blob: 11907b333bdc8000cfe45fec82b10ea53bba883d [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 {
Pekka Paalanen9d1613e2011-11-25 12:09:16 +020073 struct wl_resource resource;
74
Benjamin Franzked0f79ab2011-11-22 12:43:52 +010075 struct wlsc_surface *surface;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +020076 struct wl_listener surface_destroy_listener;
Pekka Paalanen57da4a82011-11-23 16:42:16 +020077
Kristian Høgsbergd2abb832011-11-23 10:52:40 -050078 enum shell_surface_type type;
79 int32_t saved_x, saved_y;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +010080
81 struct wlsc_output *output;
82 struct wl_list link;
Pekka Paalanen56cdea92011-11-23 16:14:12 +020083};
84
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050085struct wlsc_move_grab {
86 struct wl_grab grab;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -050087 struct wlsc_surface *surface;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050088 int32_t dx, dy;
89};
90
Pekka Paalanen56cdea92011-11-23 16:14:12 +020091static struct shell_surface *
92get_shell_surface(struct wlsc_surface *surface)
93{
Pekka Paalanen9d1613e2011-11-25 12:09:16 +020094 return surface->shell_priv;
Pekka Paalanen56cdea92011-11-23 16:14:12 +020095}
96
97static void
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050098move_grab_motion(struct wl_grab *grab,
99 uint32_t time, int32_t x, int32_t y)
100{
101 struct wlsc_move_grab *move = (struct wlsc_move_grab *) grab;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -0500102 struct wlsc_surface *es = move->surface;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500103
Kristian Høgsberga691aee2011-06-23 21:43:50 -0400104 wlsc_surface_configure(es, x + move->dx, y + move->dy,
105 es->width, es->height);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500106}
107
108static void
109move_grab_button(struct wl_grab *grab,
110 uint32_t time, int32_t button, int32_t state)
111{
112}
113
114static void
115move_grab_end(struct wl_grab *grab, uint32_t time)
116{
117 free(grab);
118}
119
120static const struct wl_grab_interface move_grab_interface = {
121 move_grab_motion,
122 move_grab_button,
123 move_grab_end
124};
125
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400126static int
127wlsc_surface_move(struct wlsc_surface *es,
128 struct wlsc_input_device *wd, uint32_t time)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500129{
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500130 struct wlsc_move_grab *move;
131
132 move = malloc(sizeof *move);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400133 if (!move)
134 return -1;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500135
136 move->grab.interface = &move_grab_interface;
137 move->dx = es->x - wd->input_device.grab_x;
138 move->dy = es->y - wd->input_device.grab_y;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -0500139 move->surface = es;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500140
141 if (wl_input_device_update_grab(&wd->input_device,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400142 &move->grab, &es->surface, time) < 0)
143 return 0;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500144
145 wlsc_input_device_set_pointer_image(wd, WLSC_POINTER_DRAGGING);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400146 wl_input_device_set_pointer_focus(&wd->input_device,
147 NULL, time, 0, 0, 0, 0);
148
149 return 0;
150}
151
152static void
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200153shell_surface_move(struct wl_client *client, struct wl_resource *resource,
154 struct wl_resource *input_resource, uint32_t time)
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400155{
156 struct wlsc_input_device *wd = input_resource->data;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200157 struct shell_surface *shsurf = resource->data;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400158
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200159 if (wlsc_surface_move(shsurf->surface, wd, time) < 0)
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400160 wl_resource_post_no_memory(resource);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500161}
162
163struct wlsc_resize_grab {
164 struct wl_grab grab;
165 uint32_t edges;
166 int32_t dx, dy, width, height;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200167 struct shell_surface *shsurf;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500168};
169
170static void
171resize_grab_motion(struct wl_grab *grab,
172 uint32_t time, int32_t x, int32_t y)
173{
174 struct wlsc_resize_grab *resize = (struct wlsc_resize_grab *) grab;
175 struct wl_input_device *device = grab->input_device;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500176 int32_t width, height;
177
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200178 if (resize->edges & WL_SHELL_SURFACE_RESIZE_LEFT) {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500179 width = device->grab_x - x + resize->width;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200180 } else if (resize->edges & WL_SHELL_SURFACE_RESIZE_RIGHT) {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500181 width = x - device->grab_x + resize->width;
182 } else {
183 width = resize->width;
184 }
185
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200186 if (resize->edges & WL_SHELL_SURFACE_RESIZE_TOP) {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500187 height = device->grab_y - y + resize->height;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200188 } else if (resize->edges & WL_SHELL_SURFACE_RESIZE_BOTTOM) {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500189 height = y - device->grab_y + resize->height;
190 } else {
191 height = resize->height;
192 }
193
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200194 wl_resource_post_event(&resize->shsurf->resource,
195 WL_SHELL_SURFACE_CONFIGURE, time, resize->edges,
196 width, height);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500197}
198
199static void
200resize_grab_button(struct wl_grab *grab,
201 uint32_t time, int32_t button, int32_t state)
202{
203}
204
205static void
206resize_grab_end(struct wl_grab *grab, uint32_t time)
207{
208 free(grab);
209}
210
211static const struct wl_grab_interface resize_grab_interface = {
212 resize_grab_motion,
213 resize_grab_button,
214 resize_grab_end
215};
216
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400217static int
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200218wlsc_surface_resize(struct shell_surface *shsurf,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400219 struct wlsc_input_device *wd,
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200220 uint32_t time, uint32_t edges)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500221{
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500222 struct wlsc_resize_grab *resize;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200223 struct wlsc_surface *es = shsurf->surface;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500224 enum wlsc_pointer_type pointer = WLSC_POINTER_LEFT_PTR;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500225
Kristian Høgsberg0ce24572011-01-28 15:18:33 -0500226 /* FIXME: Reject if fullscreen */
227
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500228 resize = malloc(sizeof *resize);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400229 if (!resize)
230 return -1;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500231
232 resize->grab.interface = &resize_grab_interface;
233 resize->edges = edges;
234 resize->dx = es->x - wd->input_device.grab_x;
235 resize->dy = es->y - wd->input_device.grab_y;
236 resize->width = es->width;
237 resize->height = es->height;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200238 resize->shsurf = shsurf;
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400239
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500240 if (edges == 0 || edges > 15 ||
241 (edges & 3) == 3 || (edges & 12) == 12)
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400242 return 0;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500243
244 switch (edges) {
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200245 case WL_SHELL_SURFACE_RESIZE_TOP:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500246 pointer = WLSC_POINTER_TOP;
247 break;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200248 case WL_SHELL_SURFACE_RESIZE_BOTTOM:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500249 pointer = WLSC_POINTER_BOTTOM;
250 break;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200251 case WL_SHELL_SURFACE_RESIZE_LEFT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500252 pointer = WLSC_POINTER_LEFT;
253 break;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200254 case WL_SHELL_SURFACE_RESIZE_TOP_LEFT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500255 pointer = WLSC_POINTER_TOP_LEFT;
256 break;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200257 case WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500258 pointer = WLSC_POINTER_BOTTOM_LEFT;
259 break;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200260 case WL_SHELL_SURFACE_RESIZE_RIGHT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500261 pointer = WLSC_POINTER_RIGHT;
262 break;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200263 case WL_SHELL_SURFACE_RESIZE_TOP_RIGHT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500264 pointer = WLSC_POINTER_TOP_RIGHT;
265 break;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200266 case WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500267 pointer = WLSC_POINTER_BOTTOM_RIGHT;
268 break;
269 }
270
271 if (wl_input_device_update_grab(&wd->input_device,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400272 &resize->grab, &es->surface, time) < 0)
273 return 0;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500274
275 wlsc_input_device_set_pointer_image(wd, pointer);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400276 wl_input_device_set_pointer_focus(&wd->input_device,
277 NULL, time, 0, 0, 0, 0);
278
279 return 0;
280}
281
282static void
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200283shell_surface_resize(struct wl_client *client, struct wl_resource *resource,
284 struct wl_resource *input_resource, uint32_t time,
285 uint32_t edges)
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400286{
287 struct wlsc_input_device *wd = input_resource->data;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200288 struct shell_surface *shsurf = resource->data;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400289
290 /* FIXME: Reject if fullscreen */
291
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200292 if (wlsc_surface_resize(shsurf, wd, time, edges) < 0)
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400293 wl_resource_post_no_memory(resource);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500294}
295
296static void
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200297shell_surface_set_toplevel(struct wl_client *client,
298 struct wl_resource *resource)
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400299
300{
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200301 struct shell_surface *shsurf = resource->data;
302 struct wlsc_surface *es = shsurf->surface;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400303
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200304 if (shsurf->type == SHELL_SURFACE_FULLSCREEN) {
305 es->x = shsurf->saved_x;
306 es->y = shsurf->saved_y;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400307 }
308
309 wlsc_surface_damage(es);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200310 shsurf->type = SHELL_SURFACE_TOPLEVEL;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400311 es->fullscreen_output = NULL;
312}
313
314static void
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200315shell_surface_set_transient(struct wl_client *client,
316 struct wl_resource *resource,
317 struct wl_resource *parent_resource,
318 int x, int y, uint32_t flags)
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400319{
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200320 struct shell_surface *shsurf = resource->data;
321 struct wlsc_surface *es = shsurf->surface;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400322 struct wlsc_surface *pes = parent_resource->data;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400323
324 /* assign to parents output */
325 es->output = pes->output;
326
327 es->x = pes->x + x;
328 es->y = pes->y + y;
329
330 wlsc_surface_damage(es);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200331 shsurf->type = SHELL_SURFACE_TRANSIENT;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400332}
333
334static void
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200335shell_surface_set_fullscreen(struct wl_client *client,
336 struct wl_resource *resource)
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400337
338{
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200339 struct shell_surface *shsurf = resource->data;
340 struct wlsc_surface *es = shsurf->surface;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400341 struct wlsc_output *output;
342
343 /* FIXME: Fullscreen on first output */
344 /* FIXME: Handle output going away */
345 output = container_of(es->compositor->output_list.next,
346 struct wlsc_output, link);
347 es->output = output;
348
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200349 shsurf->saved_x = es->x;
350 shsurf->saved_y = es->y;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400351 es->x = (output->current->width - es->width) / 2;
352 es->y = (output->current->height - es->height) / 2;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400353 es->fullscreen_output = output;
354 wlsc_surface_damage(es);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200355 shsurf->type = SHELL_SURFACE_FULLSCREEN;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400356}
357
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200358static const struct wl_shell_surface_interface shell_surface_implementation = {
359 shell_surface_move,
360 shell_surface_resize,
361 shell_surface_set_toplevel,
362 shell_surface_set_transient,
363 shell_surface_set_fullscreen
364};
365
366static void
367destroy_shell_surface(struct wl_resource *resource)
368{
369 struct shell_surface *shsurf = resource->data;
370
371 /* in case cleaning up a dead client destroys shell_surface first */
372 if (shsurf->surface)
373 wl_list_remove(&shsurf->surface_destroy_listener.link);
374
375 wl_list_remove(&shsurf->link);
376 free(shsurf);
377}
378
379static void
380shell_handle_surface_destroy(struct wl_listener *listener,
381 struct wl_resource *resource, uint32_t time)
382{
383 struct shell_surface *shsurf = container_of(listener,
384 struct shell_surface,
385 surface_destroy_listener);
386
387 shsurf->surface = NULL;
388 wl_resource_destroy(&shsurf->resource, time);
389}
390
391static void
392shell_create_shell_surface(struct wl_client *client,
393 struct wl_resource *resource,
394 uint32_t id,
395 struct wl_resource *surface_resource)
396{
397 struct wlsc_surface *surface = surface_resource->data;
398 struct shell_surface *shsurf;
399
400 shsurf = calloc(1, sizeof *shsurf);
401 if (!shsurf) {
402 wl_resource_post_no_memory(resource);
403 return;
404 }
405
406 shsurf->resource.destroy = destroy_shell_surface;
407 shsurf->resource.object.id = id;
408 shsurf->resource.object.interface = &wl_shell_surface_interface;
409 shsurf->resource.object.implementation =
410 (void (**)(void)) &shell_surface_implementation;
411 shsurf->resource.data = shsurf;
412
413 shsurf->surface = surface;
414 shsurf->surface_destroy_listener.func = shell_handle_surface_destroy;
415 wl_list_insert(surface->surface.resource.destroy_listener_list.prev,
416 &shsurf->surface_destroy_listener.link);
417
418 /* init link so its safe to always remove it in destroy_shell_surface */
419 wl_list_init(&shsurf->link);
420
421 shsurf->type = SHELL_SURFACE_NORMAL;
422
423 surface->shell_priv = shsurf;
424
425 wl_client_add_resource(client, &shsurf->resource);
426}
427
428static const struct wl_shell_interface shell_implementation = {
429 shell_create_shell_surface
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500430};
431
Kristian Høgsberg07937562011-04-12 17:25:42 -0400432static void
Kristian Høgsberg75840622011-09-06 13:48:16 -0400433desktop_shell_set_background(struct wl_client *client,
434 struct wl_resource *resource,
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100435 struct wl_resource *output_resource,
Kristian Høgsberg75840622011-09-06 13:48:16 -0400436 struct wl_resource *surface_resource)
437{
438 struct wl_shell *shell = resource->data;
439 struct wlsc_surface *surface = surface_resource->data;
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200440 struct shell_surface *priv;
Kristian Høgsberg75840622011-09-06 13:48:16 -0400441
Benjamin Franzkef02bb642011-11-23 20:46:40 +0100442 wl_list_for_each(priv, &shell->backgrounds, link) {
443 if (priv->output == output_resource->data) {
444 priv->surface->output = NULL;
445 wl_list_remove(&priv->surface->link);
446 wl_list_remove(&priv->link);
447 break;
448 }
449 }
450
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200451 priv = get_shell_surface(surface);
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500452 priv->type = SHELL_SURFACE_BACKGROUND;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100453 priv->output = output_resource->data;
454
455 wl_list_insert(&shell->backgrounds, &priv->link);
456
457 surface->x = priv->output->x;
458 surface->y = priv->output->y;
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200459
Kristian Høgsberg75840622011-09-06 13:48:16 -0400460 wl_resource_post_event(resource,
461 DESKTOP_SHELL_CONFIGURE,
462 wlsc_compositor_get_time(), 0, surface,
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100463 priv->output->current->width,
464 priv->output->current->height);
Kristian Høgsberg75840622011-09-06 13:48:16 -0400465}
466
467static void
468desktop_shell_set_panel(struct wl_client *client,
469 struct wl_resource *resource,
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100470 struct wl_resource *output_resource,
Kristian Høgsberg75840622011-09-06 13:48:16 -0400471 struct wl_resource *surface_resource)
472{
473 struct wl_shell *shell = resource->data;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100474 struct wlsc_surface *surface = surface_resource->data;
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200475 struct shell_surface *priv;
Kristian Høgsberg75840622011-09-06 13:48:16 -0400476
Benjamin Franzkef02bb642011-11-23 20:46:40 +0100477 wl_list_for_each(priv, &shell->panels, link) {
478 if (priv->output == output_resource->data) {
479 priv->surface->output = NULL;
480 wl_list_remove(&priv->surface->link);
481 wl_list_remove(&priv->link);
482 break;
483 }
484 }
485
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100486 priv = get_shell_surface(surface);
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500487 priv->type = SHELL_SURFACE_PANEL;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100488 priv->output = output_resource->data;
489
490 wl_list_insert(&shell->panels, &priv->link);
491
492 surface->x = priv->output->x;
493 surface->y = priv->output->y;
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200494
Kristian Høgsberg75840622011-09-06 13:48:16 -0400495 wl_resource_post_event(resource,
496 DESKTOP_SHELL_CONFIGURE,
497 wlsc_compositor_get_time(), 0, surface_resource,
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100498 priv->output->current->width,
499 priv->output->current->height);
Kristian Høgsberg75840622011-09-06 13:48:16 -0400500}
501
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200502static void
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500503handle_lock_surface_destroy(struct wl_listener *listener,
504 struct wl_resource *resource, uint32_t time)
505{
506 struct wl_shell *shell =
Pekka Paalanen2ca86302011-11-16 13:47:35 +0200507 container_of(listener, struct wl_shell, lock_surface_listener);
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500508
509 fprintf(stderr, "lock surface gone\n");
510 shell->lock_surface = NULL;
511}
512
513static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200514desktop_shell_set_lock_surface(struct wl_client *client,
515 struct wl_resource *resource,
516 struct wl_resource *surface_resource)
517{
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +0200518 struct wl_shell *shell = resource->data;
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200519 struct shell_surface *priv;
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +0200520
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200521 shell->prepare_event_sent = false;
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +0200522
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200523 if (!shell->locked)
524 return;
525
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500526 shell->lock_surface = surface_resource->data;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200527
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500528 shell->lock_surface_listener.func = handle_lock_surface_destroy;
529 wl_list_insert(&surface_resource->destroy_listener_list,
530 &shell->lock_surface_listener.link);
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200531
532 priv = get_shell_surface(shell->lock_surface);
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500533 priv->type = SHELL_SURFACE_LOCK;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200534}
535
536static void
537resume_desktop(struct wl_shell *shell)
538{
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500539 struct wlsc_surface *surface;
Pekka Paalanenfe340832011-11-25 16:07:52 +0200540 struct wl_list *list;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200541
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500542 wl_list_for_each(surface, &shell->hidden_surface_list, link)
543 wlsc_surface_configure(surface, surface->x, surface->y,
544 surface->width, surface->height);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200545
Pekka Paalanenfe340832011-11-25 16:07:52 +0200546 if (wl_list_empty(&shell->backgrounds)) {
547 list = &shell->compositor->surface_list;
548 } else {
549 struct shell_surface *background;
550 background = container_of(shell->backgrounds.prev,
551 struct shell_surface, link);
552 list = background->surface->link.prev;
553 }
554
555 if (!wl_list_empty(&shell->hidden_surface_list))
556 wl_list_insert_list(list, &shell->hidden_surface_list);
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500557 wl_list_init(&shell->hidden_surface_list);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200558
559 shell->locked = false;
560 wlsc_compositor_repick(shell->compositor);
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +0200561 wlsc_compositor_wake(shell->compositor);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200562}
563
564static void
565desktop_shell_unlock(struct wl_client *client,
566 struct wl_resource *resource)
567{
568 struct wl_shell *shell = resource->data;
569
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200570 shell->prepare_event_sent = false;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200571
572 if (shell->locked)
573 resume_desktop(shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200574}
575
Kristian Høgsberg75840622011-09-06 13:48:16 -0400576static const struct desktop_shell_interface desktop_shell_implementation = {
577 desktop_shell_set_background,
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200578 desktop_shell_set_panel,
579 desktop_shell_set_lock_surface,
580 desktop_shell_unlock
Kristian Høgsberg75840622011-09-06 13:48:16 -0400581};
582
583static void
Kristian Høgsberg07937562011-04-12 17:25:42 -0400584move_binding(struct wl_input_device *device, uint32_t time,
585 uint32_t key, uint32_t button, uint32_t state, void *data)
586{
Kristian Høgsberg07937562011-04-12 17:25:42 -0400587 struct wlsc_surface *surface =
588 (struct wlsc_surface *) device->pointer_focus;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200589 struct shell_surface *shsurf;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500590
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100591 if (surface == NULL)
592 return;
Kristian Høgsberg07937562011-04-12 17:25:42 -0400593
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200594 shsurf = get_shell_surface(surface);
595 switch (shsurf->type) {
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100596 case SHELL_SURFACE_PANEL:
597 case SHELL_SURFACE_BACKGROUND:
598 case SHELL_SURFACE_FULLSCREEN:
599 return;
600 default:
601 break;
602 }
Kristian Høgsberg10f097e2011-04-13 11:52:54 -0400603
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400604 wlsc_surface_move(surface, (struct wlsc_input_device *) device, time);
Kristian Høgsberg07937562011-04-12 17:25:42 -0400605}
606
607static void
608resize_binding(struct wl_input_device *device, uint32_t time,
609 uint32_t key, uint32_t button, uint32_t state, void *data)
610{
Kristian Høgsberg07937562011-04-12 17:25:42 -0400611 struct wlsc_surface *surface =
612 (struct wlsc_surface *) device->pointer_focus;
613 uint32_t edges = 0;
614 int32_t x, y;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200615 struct shell_surface *shsurf;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500616
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100617 if (surface == NULL)
618 return;
619
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200620 shsurf = get_shell_surface(surface);
621 switch (shsurf->type) {
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100622 case SHELL_SURFACE_PANEL:
623 case SHELL_SURFACE_BACKGROUND:
624 case SHELL_SURFACE_FULLSCREEN:
625 return;
626 default:
627 break;
628 }
Kristian Høgsberg10f097e2011-04-13 11:52:54 -0400629
Kristian Høgsberg07937562011-04-12 17:25:42 -0400630 x = device->grab_x - surface->x;
631 y = device->grab_y - surface->y;
632
633 if (x < surface->width / 3)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200634 edges |= WL_SHELL_SURFACE_RESIZE_LEFT;
Kristian Høgsberg07937562011-04-12 17:25:42 -0400635 else if (x < 2 * surface->width / 3)
636 edges |= 0;
637 else
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200638 edges |= WL_SHELL_SURFACE_RESIZE_RIGHT;
Kristian Høgsberg07937562011-04-12 17:25:42 -0400639
640 if (y < surface->height / 3)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200641 edges |= WL_SHELL_SURFACE_RESIZE_TOP;
Kristian Høgsberg07937562011-04-12 17:25:42 -0400642 else if (y < 2 * surface->height / 3)
643 edges |= 0;
644 else
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200645 edges |= WL_SHELL_SURFACE_RESIZE_BOTTOM;
Kristian Høgsberg07937562011-04-12 17:25:42 -0400646
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200647 wlsc_surface_resize(shsurf, (struct wlsc_input_device *) device,
648 time, edges);
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400649}
650
651static void
Kristian Høgsberg75840622011-09-06 13:48:16 -0400652activate(struct wlsc_shell *base, struct wlsc_surface *es,
653 struct wlsc_input_device *device, uint32_t time)
654{
655 struct wl_shell *shell = container_of(base, struct wl_shell, shell);
656 struct wlsc_compositor *compositor = shell->compositor;
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200657 struct shell_surface *priv;
658
659 priv = get_shell_surface(es);
Kristian Høgsberg75840622011-09-06 13:48:16 -0400660
661 wlsc_surface_activate(es, device, time);
662
Kristian Høgsbergd6e55252011-10-11 23:41:17 -0400663 if (compositor->wxs)
664 wlsc_xserver_surface_activate(es);
665
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500666 switch (priv->type) {
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200667 case SHELL_SURFACE_BACKGROUND:
668 /* put background back to bottom */
Kristian Høgsberg75840622011-09-06 13:48:16 -0400669 wl_list_remove(&es->link);
670 wl_list_insert(compositor->surface_list.prev, &es->link);
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200671 break;
672 case SHELL_SURFACE_PANEL:
673 /* already put on top */
674 break;
675 default:
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100676 if (!shell->locked) {
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200677 /* bring panel back to top */
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100678 struct shell_surface *panel;
679 wl_list_for_each(panel, &shell->panels, link) {
680 wl_list_remove(&panel->surface->link);
681 wl_list_insert(&compositor->surface_list,
682 &panel->surface->link);
683 }
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200684 }
Kristian Høgsberg75840622011-09-06 13:48:16 -0400685 }
686}
687
688static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200689lock(struct wlsc_shell *base)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400690{
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200691 struct wl_shell *shell = container_of(base, struct wl_shell, shell);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200692 struct wl_list *surface_list = &shell->compositor->surface_list;
693 struct wlsc_surface *cur;
694 struct wlsc_surface *tmp;
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200695 struct shell_surface *priv;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200696 struct wlsc_input_device *device;
697 uint32_t time;
698
699 if (shell->locked)
700 return;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200701
702 shell->locked = true;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200703
704 /* Move all surfaces from compositor's list to our hidden list,
705 * except the background. This way nothing else can show or
706 * receive input events while we are locked. */
707
708 if (!wl_list_empty(&shell->hidden_surface_list)) {
709 fprintf(stderr,
710 "%s: Assertion failed: hidden_surface_list is not empty.\n",
711 __func__);
712 }
713
714 wl_list_for_each_safe(cur, tmp, surface_list, link) {
715 /* skip input device sprites, cur->surface is uninitialised */
716 if (cur->surface.resource.client == NULL)
717 continue;
718
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200719 priv = get_shell_surface(cur);
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500720 if (priv->type == SHELL_SURFACE_BACKGROUND)
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200721 continue;
722
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500723 cur->output = NULL;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200724 wl_list_remove(&cur->link);
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500725 wl_list_insert(shell->hidden_surface_list.prev, &cur->link);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200726 }
727
728 /* reset pointer foci */
729 wlsc_compositor_repick(shell->compositor);
730
731 /* reset keyboard foci */
732 time = wlsc_compositor_get_time();
733 wl_list_for_each(device, &shell->compositor->input_device_list, link) {
734 wl_input_device_set_keyboard_focus(&device->input_device,
735 NULL, time);
736 }
737
738 /* TODO: disable bindings that should not work while locked. */
739
740 /* All this must be undone in resume_desktop(). */
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200741}
742
743static void
744unlock(struct wlsc_shell *base)
745{
746 struct wl_shell *shell = container_of(base, struct wl_shell, shell);
747
Pekka Paalanend81c2162011-11-16 13:47:34 +0200748 if (!shell->locked || shell->lock_surface) {
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200749 wlsc_compositor_wake(shell->compositor);
750 return;
751 }
752
753 /* If desktop-shell client has gone away, unlock immediately. */
754 if (!shell->child.desktop_shell) {
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200755 resume_desktop(shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200756 return;
757 }
758
759 if (shell->prepare_event_sent)
760 return;
761
762 wl_resource_post_event(shell->child.desktop_shell,
763 DESKTOP_SHELL_PREPARE_LOCK_SURFACE);
764 shell->prepare_event_sent = true;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400765}
766
767static void
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -0500768map(struct wlsc_shell *base,
769 struct wlsc_surface *surface, int32_t width, int32_t height)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400770{
Kristian Høgsberg75840622011-09-06 13:48:16 -0400771 struct wl_shell *shell = container_of(base, struct wl_shell, shell);
772 struct wlsc_compositor *compositor = shell->compositor;
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500773 struct wl_list *list;
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200774 struct shell_surface *priv;
775
776 priv = get_shell_surface(surface);
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500777
778 if (shell->locked)
779 list = &shell->hidden_surface_list;
780 else
781 list = &compositor->surface_list;
Kristian Høgsberg75840622011-09-06 13:48:16 -0400782
Pekka Paalanend3dd6e12011-11-16 13:47:33 +0200783 /* surface stacking order, see also activate() */
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500784 switch (priv->type) {
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200785 case SHELL_SURFACE_BACKGROUND:
Pekka Paalanend3dd6e12011-11-16 13:47:33 +0200786 /* background always visible, at the bottom */
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -0500787 wl_list_insert(compositor->surface_list.prev, &surface->link);
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200788 break;
789 case SHELL_SURFACE_PANEL:
Pekka Paalanend3dd6e12011-11-16 13:47:33 +0200790 /* panel always on top, hidden while locked */
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500791 wl_list_insert(list, &surface->link);
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200792 break;
793 case SHELL_SURFACE_LOCK:
Pekka Paalanend3dd6e12011-11-16 13:47:33 +0200794 /* lock surface always visible, on top */
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500795 wl_list_insert(&compositor->surface_list, &surface->link);
Pekka Paalanend3dd6e12011-11-16 13:47:33 +0200796
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500797 wlsc_compositor_repick(compositor);
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200798 wlsc_compositor_wake(compositor);
799 break;
800 default:
Pekka Paalanend3dd6e12011-11-16 13:47:33 +0200801 /* everything else just below the panel */
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100802 if (!wl_list_empty(&shell->panels)) {
803 struct shell_surface *panel =
804 container_of(shell->panels.prev,
805 struct shell_surface, link);
806 wl_list_insert(&panel->surface->link, &surface->link);
807 } else {
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200808 wl_list_insert(list, &surface->link);
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100809 }
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200810 }
811
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500812 if (priv->type == SHELL_SURFACE_TOPLEVEL) {
Kristian Høgsberg46770132011-11-09 12:38:53 -0500813 surface->x = 10 + random() % 400;
814 surface->y = 10 + random() % 400;
815 }
816
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500817 surface->width = width;
818 surface->height = height;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500819 if (!shell->locked || priv->type == SHELL_SURFACE_LOCK)
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500820 wlsc_surface_configure(surface,
821 surface->x, surface->y, width, height);
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -0500822}
823
824static void
825configure(struct wlsc_shell *shell, struct wlsc_surface *surface,
826 int32_t x, int32_t y, int32_t width, int32_t height)
827{
828 struct wlsc_mode *current;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500829 struct shell_surface *priv;
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -0500830
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500831 priv = get_shell_surface(surface);
832 switch (priv->type) {
833 case SHELL_SURFACE_FULLSCREEN:
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -0500834 current = surface->fullscreen_output->current;
835 x = (current->width - surface->width) / 2;
836 y = (current->height - surface->height) / 2;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500837 break;
838 default:
839 break;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400840 }
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -0500841
842 wlsc_surface_configure(surface, x, y, width, height);
Kristian Høgsberg07937562011-04-12 17:25:42 -0400843}
844
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400845static void
Pekka Paalanen6cd281a2011-11-03 14:11:32 +0200846desktop_shell_sigchld(struct wlsc_process *process, int status)
847{
848 struct wl_shell *shell =
849 container_of(process, struct wl_shell, child.process);
850
851 shell->child.process.pid = 0;
852 shell->child.client = NULL; /* already destroyed by wayland */
853}
854
855static int
856launch_desktop_shell_process(struct wl_shell *shell)
857{
Kristian Høgsbergc4693c42011-11-14 14:57:17 -0500858 const char *shell_exe = LIBEXECDIR "/wayland-desktop-shell";
Pekka Paalanen6cd281a2011-11-03 14:11:32 +0200859 struct wlsc_compositor *compositor = shell->compositor;
860 char s[32];
861 int sv[2], flags;
862
863 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) {
864 fprintf(stderr, "socketpair failed\n");
865 return -1;
866 }
867
868 shell->child.process.pid = fork();
869 shell->child.process.cleanup = desktop_shell_sigchld;
870
871 switch (shell->child.process.pid) {
872 case 0:
873 /* SOCK_CLOEXEC closes both ends, so we need to unset
874 * the flag on the client fd. */
875 flags = fcntl(sv[1], F_GETFD);
876 if (flags != -1)
877 fcntl(sv[1], F_SETFD, flags & ~FD_CLOEXEC);
878
879 snprintf(s, sizeof s, "%d", sv[1]);
880 setenv("WAYLAND_SOCKET", s, 1);
881 if (execl(shell_exe, shell_exe, NULL) < 0)
882 fprintf(stderr, "%s: running '%s' failed: %m\n",
883 __func__, shell_exe);
884 exit(-1);
885
886 default:
887 close(sv[1]);
888 shell->child.client =
889 wl_client_create(compositor->wl_display, sv[0]);
890 wlsc_watch_process(&shell->child.process);
891 break;
892
893 case -1:
894 fprintf(stderr, "%s: fork failed: %m\n", __func__);
895 return -1;
896 }
897 return 0;
898}
899
900static void
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400901bind_shell(struct wl_client *client, void *data, uint32_t version, uint32_t id)
902{
903 struct wl_shell *shell = data;
904
905 wl_client_add_object(client, &wl_shell_interface,
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200906 &shell_implementation, id, shell);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400907}
908
Kristian Høgsberg75840622011-09-06 13:48:16 -0400909static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200910unbind_desktop_shell(struct wl_resource *resource)
911{
912 struct wl_shell *shell = resource->data;
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500913
914 if (shell->locked)
915 resume_desktop(shell);
916
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200917 shell->child.desktop_shell = NULL;
918 shell->prepare_event_sent = false;
919 free(resource);
920}
921
922static void
Kristian Høgsberg75840622011-09-06 13:48:16 -0400923bind_desktop_shell(struct wl_client *client,
924 void *data, uint32_t version, uint32_t id)
925{
926 struct wl_shell *shell = data;
Pekka Paalanenbbe60522011-11-03 14:11:33 +0200927 struct wl_resource *resource;
Kristian Høgsberg75840622011-09-06 13:48:16 -0400928
Pekka Paalanenbbe60522011-11-03 14:11:33 +0200929 resource = wl_client_add_object(client, &desktop_shell_interface,
930 &desktop_shell_implementation,
931 id, shell);
932
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200933 if (client == shell->child.client) {
934 resource->destroy = unbind_desktop_shell;
935 shell->child.desktop_shell = resource;
Pekka Paalanenbbe60522011-11-03 14:11:33 +0200936 return;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200937 }
Pekka Paalanenbbe60522011-11-03 14:11:33 +0200938
939 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
940 "permission to bind desktop_shell denied");
941 wl_resource_destroy(resource, 0);
Kristian Høgsberg75840622011-09-06 13:48:16 -0400942}
943
Kristian Høgsberg6c709a32011-05-06 14:52:41 -0400944int
945shell_init(struct wlsc_compositor *ec);
946
Kristian Høgsberg1c562182011-05-02 22:09:20 -0400947WL_EXPORT int
948shell_init(struct wlsc_compositor *ec)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500949{
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400950 struct wl_shell *shell;
951
952 shell = malloc(sizeof *shell);
953 if (shell == NULL)
954 return -1;
955
Kristian Høgsbergf0d91162011-10-11 22:44:23 -0400956 memset(shell, 0, sizeof *shell);
Kristian Høgsberg75840622011-09-06 13:48:16 -0400957 shell->compositor = ec;
958 shell->shell.activate = activate;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400959 shell->shell.lock = lock;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200960 shell->shell.unlock = unlock;
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -0500961 shell->shell.map = map;
962 shell->shell.configure = configure;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500963
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200964 wl_list_init(&shell->hidden_surface_list);
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100965 wl_list_init(&shell->backgrounds);
966 wl_list_init(&shell->panels);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200967
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400968 if (wl_display_add_global(ec->wl_display, &wl_shell_interface,
969 shell, bind_shell) == NULL)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500970 return -1;
971
Kristian Høgsberg75840622011-09-06 13:48:16 -0400972 if (wl_display_add_global(ec->wl_display,
973 &desktop_shell_interface,
974 shell, bind_desktop_shell) == NULL)
975 return -1;
976
Pekka Paalanen6cd281a2011-11-03 14:11:32 +0200977 if (launch_desktop_shell_process(shell) != 0)
978 return -1;
979
Kristian Høgsberg07937562011-04-12 17:25:42 -0400980 wlsc_compositor_add_binding(ec, 0, BTN_LEFT, MODIFIER_SUPER,
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400981 move_binding, shell);
Kristian Høgsberg07937562011-04-12 17:25:42 -0400982 wlsc_compositor_add_binding(ec, 0, BTN_MIDDLE, MODIFIER_SUPER,
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400983 resize_binding, shell);
984
985 ec->shell = &shell->shell;
Kristian Høgsberg07937562011-04-12 17:25:42 -0400986
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500987 return 0;
988}