blob: ffa21b43d5a456f87320ec5b5cc2c241dd15f70b [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
Pekka Paalanen068ae942011-11-28 14:11:15 +020039struct shell_surface;
40
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -040041struct wl_shell {
Kristian Høgsberg75840622011-09-06 13:48:16 -040042 struct wlsc_compositor *compositor;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -040043 struct wlsc_shell shell;
Pekka Paalanen6cd281a2011-11-03 14:11:32 +020044
45 struct {
46 struct wlsc_process process;
47 struct wl_client *client;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +020048 struct wl_resource *desktop_shell;
Pekka Paalanen6cd281a2011-11-03 14:11:32 +020049 } child;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +020050
51 bool locked;
52 bool prepare_event_sent;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +020053
Pekka Paalanen068ae942011-11-28 14:11:15 +020054 struct shell_surface *lock_surface;
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -050055 struct wl_listener lock_surface_listener;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +020056 struct wl_list hidden_surface_list;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +010057
58 struct wl_list backgrounds;
59 struct wl_list panels;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -040060};
61
Kristian Høgsbergd2abb832011-11-23 10:52:40 -050062enum shell_surface_type {
Pekka Paalanen57da4a82011-11-23 16:42:16 +020063 SHELL_SURFACE_NORMAL,
Kristian Høgsbergd2abb832011-11-23 10:52:40 -050064
Pekka Paalanen57da4a82011-11-23 16:42:16 +020065 SHELL_SURFACE_PANEL,
66 SHELL_SURFACE_BACKGROUND,
67 SHELL_SURFACE_LOCK,
Kristian Høgsbergd2abb832011-11-23 10:52:40 -050068
69 SHELL_SURFACE_TOPLEVEL,
70 SHELL_SURFACE_TRANSIENT,
71 SHELL_SURFACE_FULLSCREEN
Pekka Paalanen57da4a82011-11-23 16:42:16 +020072};
73
Pekka Paalanen56cdea92011-11-23 16:14:12 +020074struct shell_surface {
Pekka Paalanen9d1613e2011-11-25 12:09:16 +020075 struct wl_resource resource;
76
Benjamin Franzked0f79ab2011-11-22 12:43:52 +010077 struct wlsc_surface *surface;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +020078 struct wl_listener surface_destroy_listener;
Pekka Paalanen57da4a82011-11-23 16:42:16 +020079
Kristian Høgsbergd2abb832011-11-23 10:52:40 -050080 enum shell_surface_type type;
81 int32_t saved_x, saved_y;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +010082
83 struct wlsc_output *output;
84 struct wl_list link;
Pekka Paalanen56cdea92011-11-23 16:14:12 +020085};
86
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050087struct wlsc_move_grab {
88 struct wl_grab grab;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -050089 struct wlsc_surface *surface;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050090 int32_t dx, dy;
91};
92
Pekka Paalanen56cdea92011-11-23 16:14:12 +020093static struct shell_surface *
94get_shell_surface(struct wlsc_surface *surface)
95{
Pekka Paalanen9d1613e2011-11-25 12:09:16 +020096 return surface->shell_priv;
Pekka Paalanen56cdea92011-11-23 16:14:12 +020097}
98
99static void
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500100move_grab_motion(struct wl_grab *grab,
101 uint32_t time, int32_t x, int32_t y)
102{
103 struct wlsc_move_grab *move = (struct wlsc_move_grab *) grab;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -0500104 struct wlsc_surface *es = move->surface;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500105
Kristian Høgsberga691aee2011-06-23 21:43:50 -0400106 wlsc_surface_configure(es, x + move->dx, y + move->dy,
107 es->width, es->height);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500108}
109
110static void
111move_grab_button(struct wl_grab *grab,
112 uint32_t time, int32_t button, int32_t state)
113{
114}
115
116static void
117move_grab_end(struct wl_grab *grab, uint32_t time)
118{
119 free(grab);
120}
121
122static const struct wl_grab_interface move_grab_interface = {
123 move_grab_motion,
124 move_grab_button,
125 move_grab_end
126};
127
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400128static int
129wlsc_surface_move(struct wlsc_surface *es,
130 struct wlsc_input_device *wd, uint32_t time)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500131{
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500132 struct wlsc_move_grab *move;
133
134 move = malloc(sizeof *move);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400135 if (!move)
136 return -1;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500137
138 move->grab.interface = &move_grab_interface;
139 move->dx = es->x - wd->input_device.grab_x;
140 move->dy = es->y - wd->input_device.grab_y;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -0500141 move->surface = es;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500142
143 if (wl_input_device_update_grab(&wd->input_device,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400144 &move->grab, &es->surface, time) < 0)
145 return 0;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500146
147 wlsc_input_device_set_pointer_image(wd, WLSC_POINTER_DRAGGING);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400148 wl_input_device_set_pointer_focus(&wd->input_device,
149 NULL, time, 0, 0, 0, 0);
150
151 return 0;
152}
153
154static void
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200155shell_surface_move(struct wl_client *client, struct wl_resource *resource,
156 struct wl_resource *input_resource, uint32_t time)
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400157{
158 struct wlsc_input_device *wd = input_resource->data;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200159 struct shell_surface *shsurf = resource->data;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400160
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200161 if (wlsc_surface_move(shsurf->surface, wd, time) < 0)
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400162 wl_resource_post_no_memory(resource);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500163}
164
165struct wlsc_resize_grab {
166 struct wl_grab grab;
167 uint32_t edges;
168 int32_t dx, dy, width, height;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200169 struct shell_surface *shsurf;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500170};
171
172static void
173resize_grab_motion(struct wl_grab *grab,
174 uint32_t time, int32_t x, int32_t y)
175{
176 struct wlsc_resize_grab *resize = (struct wlsc_resize_grab *) grab;
177 struct wl_input_device *device = grab->input_device;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500178 int32_t width, height;
179
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200180 if (resize->edges & WL_SHELL_SURFACE_RESIZE_LEFT) {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500181 width = device->grab_x - x + resize->width;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200182 } else if (resize->edges & WL_SHELL_SURFACE_RESIZE_RIGHT) {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500183 width = x - device->grab_x + resize->width;
184 } else {
185 width = resize->width;
186 }
187
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200188 if (resize->edges & WL_SHELL_SURFACE_RESIZE_TOP) {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500189 height = device->grab_y - y + resize->height;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200190 } else if (resize->edges & WL_SHELL_SURFACE_RESIZE_BOTTOM) {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500191 height = y - device->grab_y + resize->height;
192 } else {
193 height = resize->height;
194 }
195
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200196 wl_resource_post_event(&resize->shsurf->resource,
197 WL_SHELL_SURFACE_CONFIGURE, time, resize->edges,
198 width, height);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500199}
200
201static void
202resize_grab_button(struct wl_grab *grab,
203 uint32_t time, int32_t button, int32_t state)
204{
205}
206
207static void
208resize_grab_end(struct wl_grab *grab, uint32_t time)
209{
210 free(grab);
211}
212
213static const struct wl_grab_interface resize_grab_interface = {
214 resize_grab_motion,
215 resize_grab_button,
216 resize_grab_end
217};
218
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400219static int
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200220wlsc_surface_resize(struct shell_surface *shsurf,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400221 struct wlsc_input_device *wd,
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200222 uint32_t time, uint32_t edges)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500223{
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500224 struct wlsc_resize_grab *resize;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200225 struct wlsc_surface *es = shsurf->surface;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500226 enum wlsc_pointer_type pointer = WLSC_POINTER_LEFT_PTR;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500227
Kristian Høgsberg0ce24572011-01-28 15:18:33 -0500228 /* FIXME: Reject if fullscreen */
229
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500230 resize = malloc(sizeof *resize);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400231 if (!resize)
232 return -1;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500233
234 resize->grab.interface = &resize_grab_interface;
235 resize->edges = edges;
236 resize->dx = es->x - wd->input_device.grab_x;
237 resize->dy = es->y - wd->input_device.grab_y;
238 resize->width = es->width;
239 resize->height = es->height;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200240 resize->shsurf = shsurf;
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400241
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500242 if (edges == 0 || edges > 15 ||
243 (edges & 3) == 3 || (edges & 12) == 12)
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400244 return 0;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500245
246 switch (edges) {
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200247 case WL_SHELL_SURFACE_RESIZE_TOP:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500248 pointer = WLSC_POINTER_TOP;
249 break;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200250 case WL_SHELL_SURFACE_RESIZE_BOTTOM:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500251 pointer = WLSC_POINTER_BOTTOM;
252 break;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200253 case WL_SHELL_SURFACE_RESIZE_LEFT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500254 pointer = WLSC_POINTER_LEFT;
255 break;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200256 case WL_SHELL_SURFACE_RESIZE_TOP_LEFT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500257 pointer = WLSC_POINTER_TOP_LEFT;
258 break;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200259 case WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500260 pointer = WLSC_POINTER_BOTTOM_LEFT;
261 break;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200262 case WL_SHELL_SURFACE_RESIZE_RIGHT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500263 pointer = WLSC_POINTER_RIGHT;
264 break;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200265 case WL_SHELL_SURFACE_RESIZE_TOP_RIGHT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500266 pointer = WLSC_POINTER_TOP_RIGHT;
267 break;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200268 case WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500269 pointer = WLSC_POINTER_BOTTOM_RIGHT;
270 break;
271 }
272
273 if (wl_input_device_update_grab(&wd->input_device,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400274 &resize->grab, &es->surface, time) < 0)
275 return 0;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500276
277 wlsc_input_device_set_pointer_image(wd, pointer);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400278 wl_input_device_set_pointer_focus(&wd->input_device,
279 NULL, time, 0, 0, 0, 0);
280
281 return 0;
282}
283
284static void
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200285shell_surface_resize(struct wl_client *client, struct wl_resource *resource,
286 struct wl_resource *input_resource, uint32_t time,
287 uint32_t edges)
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400288{
289 struct wlsc_input_device *wd = input_resource->data;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200290 struct shell_surface *shsurf = resource->data;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400291
292 /* FIXME: Reject if fullscreen */
293
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200294 if (wlsc_surface_resize(shsurf, wd, time, edges) < 0)
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400295 wl_resource_post_no_memory(resource);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500296}
297
298static void
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200299shell_surface_set_toplevel(struct wl_client *client,
300 struct wl_resource *resource)
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400301
302{
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200303 struct shell_surface *shsurf = resource->data;
304 struct wlsc_surface *es = shsurf->surface;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400305
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200306 if (shsurf->type == SHELL_SURFACE_FULLSCREEN) {
307 es->x = shsurf->saved_x;
308 es->y = shsurf->saved_y;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400309 }
310
311 wlsc_surface_damage(es);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200312 shsurf->type = SHELL_SURFACE_TOPLEVEL;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400313 es->fullscreen_output = NULL;
314}
315
316static void
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200317shell_surface_set_transient(struct wl_client *client,
318 struct wl_resource *resource,
319 struct wl_resource *parent_resource,
320 int x, int y, uint32_t flags)
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400321{
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200322 struct shell_surface *shsurf = resource->data;
323 struct wlsc_surface *es = shsurf->surface;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400324 struct wlsc_surface *pes = parent_resource->data;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400325
326 /* assign to parents output */
327 es->output = pes->output;
328
329 es->x = pes->x + x;
330 es->y = pes->y + y;
331
332 wlsc_surface_damage(es);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200333 shsurf->type = SHELL_SURFACE_TRANSIENT;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400334}
335
336static void
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200337shell_surface_set_fullscreen(struct wl_client *client,
338 struct wl_resource *resource)
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400339
340{
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200341 struct shell_surface *shsurf = resource->data;
342 struct wlsc_surface *es = shsurf->surface;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400343 struct wlsc_output *output;
344
345 /* FIXME: Fullscreen on first output */
346 /* FIXME: Handle output going away */
347 output = container_of(es->compositor->output_list.next,
348 struct wlsc_output, link);
349 es->output = output;
350
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200351 shsurf->saved_x = es->x;
352 shsurf->saved_y = es->y;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400353 es->x = (output->current->width - es->width) / 2;
354 es->y = (output->current->height - es->height) / 2;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400355 es->fullscreen_output = output;
356 wlsc_surface_damage(es);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200357 shsurf->type = SHELL_SURFACE_FULLSCREEN;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400358}
359
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200360static const struct wl_shell_surface_interface shell_surface_implementation = {
361 shell_surface_move,
362 shell_surface_resize,
363 shell_surface_set_toplevel,
364 shell_surface_set_transient,
365 shell_surface_set_fullscreen
366};
367
368static void
369destroy_shell_surface(struct wl_resource *resource)
370{
371 struct shell_surface *shsurf = resource->data;
372
373 /* in case cleaning up a dead client destroys shell_surface first */
374 if (shsurf->surface)
375 wl_list_remove(&shsurf->surface_destroy_listener.link);
376
377 wl_list_remove(&shsurf->link);
378 free(shsurf);
379}
380
381static void
382shell_handle_surface_destroy(struct wl_listener *listener,
383 struct wl_resource *resource, uint32_t time)
384{
385 struct shell_surface *shsurf = container_of(listener,
386 struct shell_surface,
387 surface_destroy_listener);
388
389 shsurf->surface = NULL;
390 wl_resource_destroy(&shsurf->resource, time);
391}
392
393static void
394shell_create_shell_surface(struct wl_client *client,
395 struct wl_resource *resource,
396 uint32_t id,
397 struct wl_resource *surface_resource)
398{
399 struct wlsc_surface *surface = surface_resource->data;
400 struct shell_surface *shsurf;
401
402 shsurf = calloc(1, sizeof *shsurf);
403 if (!shsurf) {
404 wl_resource_post_no_memory(resource);
405 return;
406 }
407
408 shsurf->resource.destroy = destroy_shell_surface;
409 shsurf->resource.object.id = id;
410 shsurf->resource.object.interface = &wl_shell_surface_interface;
411 shsurf->resource.object.implementation =
412 (void (**)(void)) &shell_surface_implementation;
413 shsurf->resource.data = shsurf;
414
415 shsurf->surface = surface;
416 shsurf->surface_destroy_listener.func = shell_handle_surface_destroy;
417 wl_list_insert(surface->surface.resource.destroy_listener_list.prev,
418 &shsurf->surface_destroy_listener.link);
419
420 /* init link so its safe to always remove it in destroy_shell_surface */
421 wl_list_init(&shsurf->link);
422
423 shsurf->type = SHELL_SURFACE_NORMAL;
424
425 surface->shell_priv = shsurf;
426
427 wl_client_add_resource(client, &shsurf->resource);
428}
429
430static const struct wl_shell_interface shell_implementation = {
431 shell_create_shell_surface
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500432};
433
Kristian Høgsberg07937562011-04-12 17:25:42 -0400434static void
Kristian Høgsberg75840622011-09-06 13:48:16 -0400435desktop_shell_set_background(struct wl_client *client,
436 struct wl_resource *resource,
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100437 struct wl_resource *output_resource,
Kristian Høgsberg75840622011-09-06 13:48:16 -0400438 struct wl_resource *surface_resource)
439{
440 struct wl_shell *shell = resource->data;
Pekka Paalanen068ae942011-11-28 14:11:15 +0200441 struct shell_surface *shsurf = surface_resource->data;
442 struct wlsc_surface *surface = shsurf->surface;
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200443 struct shell_surface *priv;
Kristian Høgsberg75840622011-09-06 13:48:16 -0400444
Benjamin Franzkef02bb642011-11-23 20:46:40 +0100445 wl_list_for_each(priv, &shell->backgrounds, link) {
446 if (priv->output == output_resource->data) {
447 priv->surface->output = NULL;
448 wl_list_remove(&priv->surface->link);
449 wl_list_remove(&priv->link);
450 break;
451 }
452 }
453
Pekka Paalanen068ae942011-11-28 14:11:15 +0200454 shsurf->type = SHELL_SURFACE_BACKGROUND;
455 shsurf->output = output_resource->data;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100456
Pekka Paalanen068ae942011-11-28 14:11:15 +0200457 wl_list_insert(&shell->backgrounds, &shsurf->link);
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100458
Pekka Paalanen068ae942011-11-28 14:11:15 +0200459 surface->x = shsurf->output->x;
460 surface->y = shsurf->output->y;
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200461
Kristian Høgsberg75840622011-09-06 13:48:16 -0400462 wl_resource_post_event(resource,
463 DESKTOP_SHELL_CONFIGURE,
Pekka Paalanen068ae942011-11-28 14:11:15 +0200464 wlsc_compositor_get_time(), 0, surface_resource,
465 shsurf->output->current->width,
466 shsurf->output->current->height);
Kristian Høgsberg75840622011-09-06 13:48:16 -0400467}
468
469static void
470desktop_shell_set_panel(struct wl_client *client,
471 struct wl_resource *resource,
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100472 struct wl_resource *output_resource,
Kristian Høgsberg75840622011-09-06 13:48:16 -0400473 struct wl_resource *surface_resource)
474{
475 struct wl_shell *shell = resource->data;
Pekka Paalanen068ae942011-11-28 14:11:15 +0200476 struct shell_surface *shsurf = surface_resource->data;
477 struct wlsc_surface *surface = shsurf->surface;
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200478 struct shell_surface *priv;
Kristian Høgsberg75840622011-09-06 13:48:16 -0400479
Benjamin Franzkef02bb642011-11-23 20:46:40 +0100480 wl_list_for_each(priv, &shell->panels, link) {
481 if (priv->output == output_resource->data) {
482 priv->surface->output = NULL;
483 wl_list_remove(&priv->surface->link);
484 wl_list_remove(&priv->link);
485 break;
486 }
487 }
488
Pekka Paalanen068ae942011-11-28 14:11:15 +0200489 shsurf->type = SHELL_SURFACE_PANEL;
490 shsurf->output = output_resource->data;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100491
Pekka Paalanen068ae942011-11-28 14:11:15 +0200492 wl_list_insert(&shell->panels, &shsurf->link);
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100493
Pekka Paalanen068ae942011-11-28 14:11:15 +0200494 surface->x = shsurf->output->x;
495 surface->y = shsurf->output->y;
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200496
Kristian Høgsberg75840622011-09-06 13:48:16 -0400497 wl_resource_post_event(resource,
498 DESKTOP_SHELL_CONFIGURE,
499 wlsc_compositor_get_time(), 0, surface_resource,
Pekka Paalanen068ae942011-11-28 14:11:15 +0200500 shsurf->output->current->width,
501 shsurf->output->current->height);
Kristian Høgsberg75840622011-09-06 13:48:16 -0400502}
503
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200504static void
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500505handle_lock_surface_destroy(struct wl_listener *listener,
506 struct wl_resource *resource, uint32_t time)
507{
508 struct wl_shell *shell =
Pekka Paalanen2ca86302011-11-16 13:47:35 +0200509 container_of(listener, struct wl_shell, lock_surface_listener);
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500510
511 fprintf(stderr, "lock surface gone\n");
512 shell->lock_surface = NULL;
513}
514
515static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200516desktop_shell_set_lock_surface(struct wl_client *client,
517 struct wl_resource *resource,
518 struct wl_resource *surface_resource)
519{
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +0200520 struct wl_shell *shell = resource->data;
521
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200522 shell->prepare_event_sent = false;
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +0200523
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200524 if (!shell->locked)
525 return;
526
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500527 shell->lock_surface = surface_resource->data;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200528
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500529 shell->lock_surface_listener.func = handle_lock_surface_destroy;
530 wl_list_insert(&surface_resource->destroy_listener_list,
531 &shell->lock_surface_listener.link);
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200532
Pekka Paalanen068ae942011-11-28 14:11:15 +0200533 shell->lock_surface->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}