blob: 35723300cdd18d7b548199d3e0f7617eb4212602 [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 Paalanenf0fc70d2011-11-15 13:34:54 +020030#include <assert.h>
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050031
Pekka Paalanen50719bc2011-11-22 14:18:50 +020032#include <wayland-server.h>
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050033#include "compositor.h"
Kristian Høgsberg75840622011-09-06 13:48:16 -040034#include "desktop-shell-server-protocol.h"
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050035
Pekka Paalanen068ae942011-11-28 14:11:15 +020036struct shell_surface;
37
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -040038struct wl_shell {
Kristian Høgsberg75840622011-09-06 13:48:16 -040039 struct wlsc_compositor *compositor;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -040040 struct wlsc_shell shell;
Pekka Paalanen6cd281a2011-11-03 14:11:32 +020041
42 struct {
43 struct wlsc_process process;
44 struct wl_client *client;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +020045 struct wl_resource *desktop_shell;
Pekka Paalanen6cd281a2011-11-03 14:11:32 +020046 } child;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +020047
48 bool locked;
49 bool prepare_event_sent;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +020050
Pekka Paalanen068ae942011-11-28 14:11:15 +020051 struct shell_surface *lock_surface;
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -050052 struct wl_listener lock_surface_listener;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +020053 struct wl_list hidden_surface_list;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +010054
55 struct wl_list backgrounds;
56 struct wl_list panels;
Pekka Paalanen6e168112011-11-24 11:34:05 +020057
58 struct wl_resource *screensaver;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -040059};
60
Kristian Høgsbergd2abb832011-11-23 10:52:40 -050061enum shell_surface_type {
Pekka Paalanen98262232011-12-01 10:42:22 +020062 SHELL_SURFACE_NONE,
Kristian Høgsbergd2abb832011-11-23 10:52:40 -050063
Pekka Paalanen57da4a82011-11-23 16:42:16 +020064 SHELL_SURFACE_PANEL,
65 SHELL_SURFACE_BACKGROUND,
66 SHELL_SURFACE_LOCK,
Kristian Høgsbergd2abb832011-11-23 10:52:40 -050067
68 SHELL_SURFACE_TOPLEVEL,
69 SHELL_SURFACE_TRANSIENT,
70 SHELL_SURFACE_FULLSCREEN
Pekka Paalanen57da4a82011-11-23 16:42:16 +020071};
72
Pekka Paalanen56cdea92011-11-23 16:14:12 +020073struct shell_surface {
Pekka Paalanen9d1613e2011-11-25 12:09:16 +020074 struct wl_resource resource;
75
Benjamin Franzked0f79ab2011-11-22 12:43:52 +010076 struct wlsc_surface *surface;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +020077 struct wl_listener surface_destroy_listener;
Pekka Paalanen57da4a82011-11-23 16:42:16 +020078
Kristian Høgsbergd2abb832011-11-23 10:52:40 -050079 enum shell_surface_type type;
80 int32_t saved_x, saved_y;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +010081
82 struct wlsc_output *output;
83 struct wl_list link;
Pekka Paalanen56cdea92011-11-23 16:14:12 +020084};
85
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050086struct wlsc_move_grab {
87 struct wl_grab grab;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -050088 struct wlsc_surface *surface;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050089 int32_t dx, dy;
90};
91
Pekka Paalanen56cdea92011-11-23 16:14:12 +020092static void
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050093move_grab_motion(struct wl_grab *grab,
94 uint32_t time, int32_t x, int32_t y)
95{
96 struct wlsc_move_grab *move = (struct wlsc_move_grab *) grab;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -050097 struct wlsc_surface *es = move->surface;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050098
Kristian Høgsberga691aee2011-06-23 21:43:50 -040099 wlsc_surface_configure(es, x + move->dx, y + move->dy,
100 es->width, es->height);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500101}
102
103static void
104move_grab_button(struct wl_grab *grab,
105 uint32_t time, int32_t button, int32_t state)
106{
107}
108
109static void
110move_grab_end(struct wl_grab *grab, uint32_t time)
111{
112 free(grab);
113}
114
115static const struct wl_grab_interface move_grab_interface = {
116 move_grab_motion,
117 move_grab_button,
118 move_grab_end
119};
120
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400121static int
122wlsc_surface_move(struct wlsc_surface *es,
123 struct wlsc_input_device *wd, uint32_t time)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500124{
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500125 struct wlsc_move_grab *move;
126
127 move = malloc(sizeof *move);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400128 if (!move)
129 return -1;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500130
131 move->grab.interface = &move_grab_interface;
132 move->dx = es->x - wd->input_device.grab_x;
133 move->dy = es->y - wd->input_device.grab_y;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -0500134 move->surface = es;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500135
136 if (wl_input_device_update_grab(&wd->input_device,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400137 &move->grab, &es->surface, time) < 0)
138 return 0;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500139
140 wlsc_input_device_set_pointer_image(wd, WLSC_POINTER_DRAGGING);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400141 wl_input_device_set_pointer_focus(&wd->input_device,
142 NULL, time, 0, 0, 0, 0);
143
144 return 0;
145}
146
147static void
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200148shell_surface_move(struct wl_client *client, struct wl_resource *resource,
149 struct wl_resource *input_resource, uint32_t time)
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400150{
151 struct wlsc_input_device *wd = input_resource->data;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200152 struct shell_surface *shsurf = resource->data;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400153
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200154 if (wlsc_surface_move(shsurf->surface, wd, time) < 0)
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400155 wl_resource_post_no_memory(resource);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500156}
157
158struct wlsc_resize_grab {
159 struct wl_grab grab;
160 uint32_t edges;
161 int32_t dx, dy, width, height;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200162 struct shell_surface *shsurf;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500163};
164
165static void
166resize_grab_motion(struct wl_grab *grab,
167 uint32_t time, int32_t x, int32_t y)
168{
169 struct wlsc_resize_grab *resize = (struct wlsc_resize_grab *) grab;
170 struct wl_input_device *device = grab->input_device;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500171 int32_t width, height;
172
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200173 if (resize->edges & WL_SHELL_SURFACE_RESIZE_LEFT) {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500174 width = device->grab_x - x + resize->width;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200175 } else if (resize->edges & WL_SHELL_SURFACE_RESIZE_RIGHT) {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500176 width = x - device->grab_x + resize->width;
177 } else {
178 width = resize->width;
179 }
180
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200181 if (resize->edges & WL_SHELL_SURFACE_RESIZE_TOP) {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500182 height = device->grab_y - y + resize->height;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200183 } else if (resize->edges & WL_SHELL_SURFACE_RESIZE_BOTTOM) {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500184 height = y - device->grab_y + resize->height;
185 } else {
186 height = resize->height;
187 }
188
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200189 wl_resource_post_event(&resize->shsurf->resource,
190 WL_SHELL_SURFACE_CONFIGURE, time, resize->edges,
191 width, height);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500192}
193
194static void
195resize_grab_button(struct wl_grab *grab,
196 uint32_t time, int32_t button, int32_t state)
197{
198}
199
200static void
201resize_grab_end(struct wl_grab *grab, uint32_t time)
202{
203 free(grab);
204}
205
206static const struct wl_grab_interface resize_grab_interface = {
207 resize_grab_motion,
208 resize_grab_button,
209 resize_grab_end
210};
211
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400212static int
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200213wlsc_surface_resize(struct shell_surface *shsurf,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400214 struct wlsc_input_device *wd,
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200215 uint32_t time, uint32_t edges)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500216{
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500217 struct wlsc_resize_grab *resize;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200218 struct wlsc_surface *es = shsurf->surface;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500219 enum wlsc_pointer_type pointer = WLSC_POINTER_LEFT_PTR;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500220
Kristian Høgsberg0ce24572011-01-28 15:18:33 -0500221 /* FIXME: Reject if fullscreen */
222
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500223 resize = malloc(sizeof *resize);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400224 if (!resize)
225 return -1;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500226
227 resize->grab.interface = &resize_grab_interface;
228 resize->edges = edges;
229 resize->dx = es->x - wd->input_device.grab_x;
230 resize->dy = es->y - wd->input_device.grab_y;
231 resize->width = es->width;
232 resize->height = es->height;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200233 resize->shsurf = shsurf;
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400234
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500235 if (edges == 0 || edges > 15 ||
236 (edges & 3) == 3 || (edges & 12) == 12)
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400237 return 0;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500238
239 switch (edges) {
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200240 case WL_SHELL_SURFACE_RESIZE_TOP:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500241 pointer = WLSC_POINTER_TOP;
242 break;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200243 case WL_SHELL_SURFACE_RESIZE_BOTTOM:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500244 pointer = WLSC_POINTER_BOTTOM;
245 break;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200246 case WL_SHELL_SURFACE_RESIZE_LEFT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500247 pointer = WLSC_POINTER_LEFT;
248 break;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200249 case WL_SHELL_SURFACE_RESIZE_TOP_LEFT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500250 pointer = WLSC_POINTER_TOP_LEFT;
251 break;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200252 case WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500253 pointer = WLSC_POINTER_BOTTOM_LEFT;
254 break;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200255 case WL_SHELL_SURFACE_RESIZE_RIGHT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500256 pointer = WLSC_POINTER_RIGHT;
257 break;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200258 case WL_SHELL_SURFACE_RESIZE_TOP_RIGHT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500259 pointer = WLSC_POINTER_TOP_RIGHT;
260 break;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200261 case WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500262 pointer = WLSC_POINTER_BOTTOM_RIGHT;
263 break;
264 }
265
266 if (wl_input_device_update_grab(&wd->input_device,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400267 &resize->grab, &es->surface, time) < 0)
268 return 0;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500269
270 wlsc_input_device_set_pointer_image(wd, pointer);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400271 wl_input_device_set_pointer_focus(&wd->input_device,
272 NULL, time, 0, 0, 0, 0);
273
274 return 0;
275}
276
277static void
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200278shell_surface_resize(struct wl_client *client, struct wl_resource *resource,
279 struct wl_resource *input_resource, uint32_t time,
280 uint32_t edges)
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400281{
282 struct wlsc_input_device *wd = input_resource->data;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200283 struct shell_surface *shsurf = resource->data;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400284
285 /* FIXME: Reject if fullscreen */
286
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200287 if (wlsc_surface_resize(shsurf, wd, time, edges) < 0)
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400288 wl_resource_post_no_memory(resource);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500289}
290
Pekka Paalanen98262232011-12-01 10:42:22 +0200291static int
292reset_shell_surface_type(struct shell_surface *surface)
293{
294 switch (surface->type) {
295 case SHELL_SURFACE_FULLSCREEN:
296 surface->surface->x = surface->saved_x;
297 surface->surface->y = surface->saved_y;
298 surface->surface->fullscreen_output = NULL;
299 break;
300 case SHELL_SURFACE_PANEL:
301 case SHELL_SURFACE_BACKGROUND:
302 wl_list_remove(&surface->link);
303 wl_list_init(&surface->link);
304 break;
305 case SHELL_SURFACE_LOCK:
306 wl_resource_post_error(&surface->resource,
307 WL_DISPLAY_ERROR_INVALID_METHOD,
308 "cannot reassign lock surface type");
309 return -1;
310 case SHELL_SURFACE_NONE:
311 case SHELL_SURFACE_TOPLEVEL:
312 case SHELL_SURFACE_TRANSIENT:
313 break;
314 }
315
316 surface->type = SHELL_SURFACE_NONE;
317 return 0;
318}
319
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500320static void
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200321shell_surface_set_toplevel(struct wl_client *client,
322 struct wl_resource *resource)
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400323
324{
Pekka Paalanen98262232011-12-01 10:42:22 +0200325 struct shell_surface *surface = resource->data;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400326
Pekka Paalanen98262232011-12-01 10:42:22 +0200327 if (reset_shell_surface_type(surface))
328 return;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400329
Pekka Paalanen98262232011-12-01 10:42:22 +0200330 wlsc_surface_damage(surface->surface);
331 surface->type = SHELL_SURFACE_TOPLEVEL;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400332}
333
334static void
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200335shell_surface_set_transient(struct wl_client *client,
336 struct wl_resource *resource,
337 struct wl_resource *parent_resource,
338 int x, int y, uint32_t flags)
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400339{
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200340 struct shell_surface *shsurf = resource->data;
341 struct wlsc_surface *es = shsurf->surface;
Pekka Paalanen01e7b002011-12-08 16:42:33 +0200342 struct shell_surface *pshsurf = parent_resource->data;
343 struct wlsc_surface *pes = pshsurf->surface;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400344
Pekka Paalanen98262232011-12-01 10:42:22 +0200345 if (reset_shell_surface_type(shsurf))
346 return;
347
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400348 /* assign to parents output */
349 es->output = pes->output;
350
351 es->x = pes->x + x;
352 es->y = pes->y + y;
353
354 wlsc_surface_damage(es);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200355 shsurf->type = SHELL_SURFACE_TRANSIENT;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400356}
357
358static void
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200359shell_surface_set_fullscreen(struct wl_client *client,
360 struct wl_resource *resource)
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400361
362{
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200363 struct shell_surface *shsurf = resource->data;
364 struct wlsc_surface *es = shsurf->surface;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400365 struct wlsc_output *output;
366
Pekka Paalanen98262232011-12-01 10:42:22 +0200367 if (reset_shell_surface_type(shsurf))
368 return;
369
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400370 /* FIXME: Fullscreen on first output */
371 /* FIXME: Handle output going away */
372 output = container_of(es->compositor->output_list.next,
373 struct wlsc_output, link);
374 es->output = output;
375
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200376 shsurf->saved_x = es->x;
377 shsurf->saved_y = es->y;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400378 es->x = (output->current->width - es->width) / 2;
379 es->y = (output->current->height - es->height) / 2;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400380 es->fullscreen_output = output;
381 wlsc_surface_damage(es);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200382 shsurf->type = SHELL_SURFACE_FULLSCREEN;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400383}
384
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200385static const struct wl_shell_surface_interface shell_surface_implementation = {
386 shell_surface_move,
387 shell_surface_resize,
388 shell_surface_set_toplevel,
389 shell_surface_set_transient,
390 shell_surface_set_fullscreen
391};
392
393static void
394destroy_shell_surface(struct wl_resource *resource)
395{
396 struct shell_surface *shsurf = resource->data;
397
398 /* in case cleaning up a dead client destroys shell_surface first */
399 if (shsurf->surface)
400 wl_list_remove(&shsurf->surface_destroy_listener.link);
401
402 wl_list_remove(&shsurf->link);
403 free(shsurf);
404}
405
406static void
407shell_handle_surface_destroy(struct wl_listener *listener,
408 struct wl_resource *resource, uint32_t time)
409{
410 struct shell_surface *shsurf = container_of(listener,
411 struct shell_surface,
412 surface_destroy_listener);
413
414 shsurf->surface = NULL;
415 wl_resource_destroy(&shsurf->resource, time);
416}
417
Pekka Paalanenec2b32f2011-11-28 15:12:34 +0200418static struct shell_surface *
419get_shell_surface(struct wlsc_surface *surface)
420{
421 struct wl_list *lst = &surface->surface.resource.destroy_listener_list;
422 struct wl_listener *listener;
423
424 /* search the destroy listener list for our callback */
425 wl_list_for_each(listener, lst, link) {
426 if (listener->func == shell_handle_surface_destroy) {
427 return container_of(listener, struct shell_surface,
428 surface_destroy_listener);
429 }
430 }
431
432 return NULL;
433}
434
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200435static void
Pekka Paalanen46229672011-11-29 15:49:31 +0200436shell_get_shell_surface(struct wl_client *client,
437 struct wl_resource *resource,
438 uint32_t id,
439 struct wl_resource *surface_resource)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200440{
441 struct wlsc_surface *surface = surface_resource->data;
442 struct shell_surface *shsurf;
443
Pekka Paalanenf32f1fc2011-11-29 16:05:28 +0200444 if (get_shell_surface(surface)) {
445 wl_resource_post_error(surface_resource,
446 WL_DISPLAY_ERROR_INVALID_OBJECT,
447 "wl_shell::get_shell_surface already requested");
448 return;
449 }
450
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200451 shsurf = calloc(1, sizeof *shsurf);
452 if (!shsurf) {
453 wl_resource_post_no_memory(resource);
454 return;
455 }
456
457 shsurf->resource.destroy = destroy_shell_surface;
458 shsurf->resource.object.id = id;
459 shsurf->resource.object.interface = &wl_shell_surface_interface;
460 shsurf->resource.object.implementation =
461 (void (**)(void)) &shell_surface_implementation;
462 shsurf->resource.data = shsurf;
463
464 shsurf->surface = surface;
465 shsurf->surface_destroy_listener.func = shell_handle_surface_destroy;
466 wl_list_insert(surface->surface.resource.destroy_listener_list.prev,
467 &shsurf->surface_destroy_listener.link);
468
469 /* init link so its safe to always remove it in destroy_shell_surface */
470 wl_list_init(&shsurf->link);
471
Pekka Paalanen98262232011-12-01 10:42:22 +0200472 shsurf->type = SHELL_SURFACE_NONE;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200473
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200474 wl_client_add_resource(client, &shsurf->resource);
475}
476
477static const struct wl_shell_interface shell_implementation = {
Pekka Paalanen46229672011-11-29 15:49:31 +0200478 shell_get_shell_surface
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500479};
480
Kristian Høgsberg07937562011-04-12 17:25:42 -0400481static void
Kristian Høgsberg75840622011-09-06 13:48:16 -0400482desktop_shell_set_background(struct wl_client *client,
483 struct wl_resource *resource,
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100484 struct wl_resource *output_resource,
Kristian Høgsberg75840622011-09-06 13:48:16 -0400485 struct wl_resource *surface_resource)
486{
487 struct wl_shell *shell = resource->data;
Pekka Paalanen068ae942011-11-28 14:11:15 +0200488 struct shell_surface *shsurf = surface_resource->data;
489 struct wlsc_surface *surface = shsurf->surface;
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200490 struct shell_surface *priv;
Kristian Høgsberg75840622011-09-06 13:48:16 -0400491
Pekka Paalanen98262232011-12-01 10:42:22 +0200492 if (reset_shell_surface_type(shsurf))
493 return;
494
Benjamin Franzkef02bb642011-11-23 20:46:40 +0100495 wl_list_for_each(priv, &shell->backgrounds, link) {
496 if (priv->output == output_resource->data) {
497 priv->surface->output = NULL;
498 wl_list_remove(&priv->surface->link);
499 wl_list_remove(&priv->link);
500 break;
501 }
502 }
503
Pekka Paalanen068ae942011-11-28 14:11:15 +0200504 shsurf->type = SHELL_SURFACE_BACKGROUND;
505 shsurf->output = output_resource->data;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100506
Pekka Paalanen068ae942011-11-28 14:11:15 +0200507 wl_list_insert(&shell->backgrounds, &shsurf->link);
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100508
Pekka Paalanen068ae942011-11-28 14:11:15 +0200509 surface->x = shsurf->output->x;
510 surface->y = shsurf->output->y;
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200511
Kristian Høgsberg75840622011-09-06 13:48:16 -0400512 wl_resource_post_event(resource,
513 DESKTOP_SHELL_CONFIGURE,
Pekka Paalanen068ae942011-11-28 14:11:15 +0200514 wlsc_compositor_get_time(), 0, surface_resource,
515 shsurf->output->current->width,
516 shsurf->output->current->height);
Kristian Høgsberg75840622011-09-06 13:48:16 -0400517}
518
519static void
520desktop_shell_set_panel(struct wl_client *client,
521 struct wl_resource *resource,
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100522 struct wl_resource *output_resource,
Kristian Høgsberg75840622011-09-06 13:48:16 -0400523 struct wl_resource *surface_resource)
524{
525 struct wl_shell *shell = resource->data;
Pekka Paalanen068ae942011-11-28 14:11:15 +0200526 struct shell_surface *shsurf = surface_resource->data;
527 struct wlsc_surface *surface = shsurf->surface;
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200528 struct shell_surface *priv;
Kristian Høgsberg75840622011-09-06 13:48:16 -0400529
Pekka Paalanen98262232011-12-01 10:42:22 +0200530 if (reset_shell_surface_type(shsurf))
531 return;
532
Benjamin Franzkef02bb642011-11-23 20:46:40 +0100533 wl_list_for_each(priv, &shell->panels, link) {
534 if (priv->output == output_resource->data) {
535 priv->surface->output = NULL;
536 wl_list_remove(&priv->surface->link);
537 wl_list_remove(&priv->link);
538 break;
539 }
540 }
541
Pekka Paalanen068ae942011-11-28 14:11:15 +0200542 shsurf->type = SHELL_SURFACE_PANEL;
543 shsurf->output = output_resource->data;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100544
Pekka Paalanen068ae942011-11-28 14:11:15 +0200545 wl_list_insert(&shell->panels, &shsurf->link);
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100546
Pekka Paalanen068ae942011-11-28 14:11:15 +0200547 surface->x = shsurf->output->x;
548 surface->y = shsurf->output->y;
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200549
Kristian Høgsberg75840622011-09-06 13:48:16 -0400550 wl_resource_post_event(resource,
551 DESKTOP_SHELL_CONFIGURE,
552 wlsc_compositor_get_time(), 0, surface_resource,
Pekka Paalanen068ae942011-11-28 14:11:15 +0200553 shsurf->output->current->width,
554 shsurf->output->current->height);
Kristian Høgsberg75840622011-09-06 13:48:16 -0400555}
556
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200557static void
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500558handle_lock_surface_destroy(struct wl_listener *listener,
559 struct wl_resource *resource, uint32_t time)
560{
561 struct wl_shell *shell =
Pekka Paalanen2ca86302011-11-16 13:47:35 +0200562 container_of(listener, struct wl_shell, lock_surface_listener);
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500563
564 fprintf(stderr, "lock surface gone\n");
565 shell->lock_surface = NULL;
566}
567
568static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200569desktop_shell_set_lock_surface(struct wl_client *client,
570 struct wl_resource *resource,
571 struct wl_resource *surface_resource)
572{
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +0200573 struct wl_shell *shell = resource->data;
Pekka Paalanen98262232011-12-01 10:42:22 +0200574 struct shell_surface *surface = surface_resource->data;
575
576 if (reset_shell_surface_type(surface))
577 return;
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +0200578
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200579 shell->prepare_event_sent = false;
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +0200580
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200581 if (!shell->locked)
582 return;
583
Pekka Paalanen98262232011-12-01 10:42:22 +0200584 shell->lock_surface = surface;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200585
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500586 shell->lock_surface_listener.func = handle_lock_surface_destroy;
587 wl_list_insert(&surface_resource->destroy_listener_list,
588 &shell->lock_surface_listener.link);
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200589
Pekka Paalanen068ae942011-11-28 14:11:15 +0200590 shell->lock_surface->type = SHELL_SURFACE_LOCK;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200591}
592
593static void
594resume_desktop(struct wl_shell *shell)
595{
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500596 struct wlsc_surface *surface;
Pekka Paalanenfe340832011-11-25 16:07:52 +0200597 struct wl_list *list;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200598
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500599 wl_list_for_each(surface, &shell->hidden_surface_list, link)
600 wlsc_surface_configure(surface, surface->x, surface->y,
601 surface->width, surface->height);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200602
Pekka Paalanenfe340832011-11-25 16:07:52 +0200603 if (wl_list_empty(&shell->backgrounds)) {
604 list = &shell->compositor->surface_list;
605 } else {
606 struct shell_surface *background;
607 background = container_of(shell->backgrounds.prev,
608 struct shell_surface, link);
609 list = background->surface->link.prev;
610 }
611
612 if (!wl_list_empty(&shell->hidden_surface_list))
613 wl_list_insert_list(list, &shell->hidden_surface_list);
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500614 wl_list_init(&shell->hidden_surface_list);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200615
616 shell->locked = false;
617 wlsc_compositor_repick(shell->compositor);
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +0200618 wlsc_compositor_wake(shell->compositor);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200619}
620
621static void
622desktop_shell_unlock(struct wl_client *client,
623 struct wl_resource *resource)
624{
625 struct wl_shell *shell = resource->data;
626
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200627 shell->prepare_event_sent = false;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200628
629 if (shell->locked)
630 resume_desktop(shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200631}
632
Kristian Høgsberg75840622011-09-06 13:48:16 -0400633static const struct desktop_shell_interface desktop_shell_implementation = {
634 desktop_shell_set_background,
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200635 desktop_shell_set_panel,
636 desktop_shell_set_lock_surface,
637 desktop_shell_unlock
Kristian Høgsberg75840622011-09-06 13:48:16 -0400638};
639
Pekka Paalanen92a0dc42011-11-28 15:34:13 +0200640static enum shell_surface_type
641get_shell_surface_type(struct wlsc_surface *surface)
642{
643 struct shell_surface *shsurf;
644
645 shsurf = get_shell_surface(surface);
646 if (!shsurf)
Pekka Paalanen98262232011-12-01 10:42:22 +0200647 return SHELL_SURFACE_NONE;
Pekka Paalanen92a0dc42011-11-28 15:34:13 +0200648 return shsurf->type;
649}
650
Kristian Høgsberg75840622011-09-06 13:48:16 -0400651static void
Kristian Høgsberg07937562011-04-12 17:25:42 -0400652move_binding(struct wl_input_device *device, uint32_t time,
653 uint32_t key, uint32_t button, uint32_t state, void *data)
654{
Kristian Høgsberg07937562011-04-12 17:25:42 -0400655 struct wlsc_surface *surface =
656 (struct wlsc_surface *) device->pointer_focus;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500657
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100658 if (surface == NULL)
659 return;
Kristian Høgsberg07937562011-04-12 17:25:42 -0400660
Pekka Paalanen92a0dc42011-11-28 15:34:13 +0200661 switch (get_shell_surface_type(surface)) {
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100662 case SHELL_SURFACE_PANEL:
663 case SHELL_SURFACE_BACKGROUND:
664 case SHELL_SURFACE_FULLSCREEN:
665 return;
666 default:
667 break;
668 }
Kristian Høgsberg10f097e2011-04-13 11:52:54 -0400669
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400670 wlsc_surface_move(surface, (struct wlsc_input_device *) device, time);
Kristian Høgsberg07937562011-04-12 17:25:42 -0400671}
672
673static void
674resize_binding(struct wl_input_device *device, uint32_t time,
675 uint32_t key, uint32_t button, uint32_t state, void *data)
676{
Kristian Høgsberg07937562011-04-12 17:25:42 -0400677 struct wlsc_surface *surface =
678 (struct wlsc_surface *) device->pointer_focus;
679 uint32_t edges = 0;
680 int32_t x, y;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200681 struct shell_surface *shsurf;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500682
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100683 if (surface == NULL)
684 return;
Pekka Paalanen92a0dc42011-11-28 15:34:13 +0200685
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200686 shsurf = get_shell_surface(surface);
Pekka Paalanen92a0dc42011-11-28 15:34:13 +0200687 if (!shsurf)
688 return;
689
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200690 switch (shsurf->type) {
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100691 case SHELL_SURFACE_PANEL:
692 case SHELL_SURFACE_BACKGROUND:
693 case SHELL_SURFACE_FULLSCREEN:
694 return;
695 default:
696 break;
697 }
Kristian Høgsberg10f097e2011-04-13 11:52:54 -0400698
Kristian Høgsberg07937562011-04-12 17:25:42 -0400699 x = device->grab_x - surface->x;
700 y = device->grab_y - surface->y;
701
702 if (x < surface->width / 3)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200703 edges |= WL_SHELL_SURFACE_RESIZE_LEFT;
Kristian Høgsberg07937562011-04-12 17:25:42 -0400704 else if (x < 2 * surface->width / 3)
705 edges |= 0;
706 else
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200707 edges |= WL_SHELL_SURFACE_RESIZE_RIGHT;
Kristian Høgsberg07937562011-04-12 17:25:42 -0400708
709 if (y < surface->height / 3)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200710 edges |= WL_SHELL_SURFACE_RESIZE_TOP;
Kristian Høgsberg07937562011-04-12 17:25:42 -0400711 else if (y < 2 * surface->height / 3)
712 edges |= 0;
713 else
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200714 edges |= WL_SHELL_SURFACE_RESIZE_BOTTOM;
Kristian Høgsberg07937562011-04-12 17:25:42 -0400715
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200716 wlsc_surface_resize(shsurf, (struct wlsc_input_device *) device,
717 time, edges);
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400718}
719
720static void
Kristian Høgsberg75840622011-09-06 13:48:16 -0400721activate(struct wlsc_shell *base, struct wlsc_surface *es,
722 struct wlsc_input_device *device, uint32_t time)
723{
724 struct wl_shell *shell = container_of(base, struct wl_shell, shell);
725 struct wlsc_compositor *compositor = shell->compositor;
726
727 wlsc_surface_activate(es, device, time);
728
Kristian Høgsbergd6e55252011-10-11 23:41:17 -0400729 if (compositor->wxs)
730 wlsc_xserver_surface_activate(es);
731
Pekka Paalanen92a0dc42011-11-28 15:34:13 +0200732 switch (get_shell_surface_type(es)) {
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200733 case SHELL_SURFACE_BACKGROUND:
734 /* put background back to bottom */
Kristian Høgsberg75840622011-09-06 13:48:16 -0400735 wl_list_remove(&es->link);
736 wl_list_insert(compositor->surface_list.prev, &es->link);
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200737 break;
738 case SHELL_SURFACE_PANEL:
739 /* already put on top */
740 break;
741 default:
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100742 if (!shell->locked) {
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200743 /* bring panel back to top */
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100744 struct shell_surface *panel;
745 wl_list_for_each(panel, &shell->panels, link) {
746 wl_list_remove(&panel->surface->link);
747 wl_list_insert(&compositor->surface_list,
748 &panel->surface->link);
749 }
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200750 }
Kristian Høgsberg75840622011-09-06 13:48:16 -0400751 }
752}
753
754static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200755lock(struct wlsc_shell *base)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400756{
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200757 struct wl_shell *shell = container_of(base, struct wl_shell, shell);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200758 struct wl_list *surface_list = &shell->compositor->surface_list;
759 struct wlsc_surface *cur;
760 struct wlsc_surface *tmp;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200761 struct wlsc_input_device *device;
762 uint32_t time;
763
764 if (shell->locked)
765 return;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200766
767 shell->locked = true;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200768
769 /* Move all surfaces from compositor's list to our hidden list,
770 * except the background. This way nothing else can show or
771 * receive input events while we are locked. */
772
773 if (!wl_list_empty(&shell->hidden_surface_list)) {
774 fprintf(stderr,
775 "%s: Assertion failed: hidden_surface_list is not empty.\n",
776 __func__);
777 }
778
779 wl_list_for_each_safe(cur, tmp, surface_list, link) {
780 /* skip input device sprites, cur->surface is uninitialised */
781 if (cur->surface.resource.client == NULL)
782 continue;
783
Pekka Paalanen92a0dc42011-11-28 15:34:13 +0200784 if (get_shell_surface_type(cur) == SHELL_SURFACE_BACKGROUND)
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200785 continue;
786
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500787 cur->output = NULL;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200788 wl_list_remove(&cur->link);
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500789 wl_list_insert(shell->hidden_surface_list.prev, &cur->link);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200790 }
791
792 /* reset pointer foci */
793 wlsc_compositor_repick(shell->compositor);
794
795 /* reset keyboard foci */
796 time = wlsc_compositor_get_time();
797 wl_list_for_each(device, &shell->compositor->input_device_list, link) {
798 wl_input_device_set_keyboard_focus(&device->input_device,
799 NULL, time);
800 }
801
802 /* TODO: disable bindings that should not work while locked. */
803
804 /* All this must be undone in resume_desktop(). */
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200805}
806
807static void
808unlock(struct wlsc_shell *base)
809{
810 struct wl_shell *shell = container_of(base, struct wl_shell, shell);
811
Pekka Paalanend81c2162011-11-16 13:47:34 +0200812 if (!shell->locked || shell->lock_surface) {
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200813 wlsc_compositor_wake(shell->compositor);
814 return;
815 }
816
817 /* If desktop-shell client has gone away, unlock immediately. */
818 if (!shell->child.desktop_shell) {
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200819 resume_desktop(shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200820 return;
821 }
822
823 if (shell->prepare_event_sent)
824 return;
825
826 wl_resource_post_event(shell->child.desktop_shell,
827 DESKTOP_SHELL_PREPARE_LOCK_SURFACE);
828 shell->prepare_event_sent = true;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400829}
830
831static void
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -0500832map(struct wlsc_shell *base,
833 struct wlsc_surface *surface, int32_t width, int32_t height)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400834{
Kristian Høgsberg75840622011-09-06 13:48:16 -0400835 struct wl_shell *shell = container_of(base, struct wl_shell, shell);
836 struct wlsc_compositor *compositor = shell->compositor;
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500837 struct wl_list *list;
Pekka Paalanen92a0dc42011-11-28 15:34:13 +0200838 enum shell_surface_type surface_type;
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200839
Pekka Paalanen92a0dc42011-11-28 15:34:13 +0200840 surface_type = get_shell_surface_type(surface);
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500841
842 if (shell->locked)
843 list = &shell->hidden_surface_list;
844 else
845 list = &compositor->surface_list;
Kristian Høgsberg75840622011-09-06 13:48:16 -0400846
Pekka Paalanend3dd6e12011-11-16 13:47:33 +0200847 /* surface stacking order, see also activate() */
Pekka Paalanen92a0dc42011-11-28 15:34:13 +0200848 switch (surface_type) {
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200849 case SHELL_SURFACE_BACKGROUND:
Pekka Paalanend3dd6e12011-11-16 13:47:33 +0200850 /* background always visible, at the bottom */
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -0500851 wl_list_insert(compositor->surface_list.prev, &surface->link);
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200852 break;
853 case SHELL_SURFACE_PANEL:
Pekka Paalanend3dd6e12011-11-16 13:47:33 +0200854 /* panel always on top, hidden while locked */
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500855 wl_list_insert(list, &surface->link);
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200856 break;
857 case SHELL_SURFACE_LOCK:
Pekka Paalanend3dd6e12011-11-16 13:47:33 +0200858 /* lock surface always visible, on top */
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500859 wl_list_insert(&compositor->surface_list, &surface->link);
Pekka Paalanend3dd6e12011-11-16 13:47:33 +0200860
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500861 wlsc_compositor_repick(compositor);
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200862 wlsc_compositor_wake(compositor);
863 break;
864 default:
Pekka Paalanend3dd6e12011-11-16 13:47:33 +0200865 /* everything else just below the panel */
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100866 if (!wl_list_empty(&shell->panels)) {
867 struct shell_surface *panel =
868 container_of(shell->panels.prev,
869 struct shell_surface, link);
870 wl_list_insert(&panel->surface->link, &surface->link);
871 } else {
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200872 wl_list_insert(list, &surface->link);
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100873 }
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200874 }
875
Pekka Paalanen92a0dc42011-11-28 15:34:13 +0200876 if (surface_type == SHELL_SURFACE_TOPLEVEL) {
Kristian Høgsberg46770132011-11-09 12:38:53 -0500877 surface->x = 10 + random() % 400;
878 surface->y = 10 + random() % 400;
879 }
880
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500881 surface->width = width;
882 surface->height = height;
Pekka Paalanen92a0dc42011-11-28 15:34:13 +0200883 if (!shell->locked || surface_type == SHELL_SURFACE_LOCK)
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500884 wlsc_surface_configure(surface,
885 surface->x, surface->y, width, height);
Kristian Høgsberg2f88a402011-12-04 15:32:59 -0500886
887 if (surface_type == SHELL_SURFACE_TOPLEVEL)
888 wlsc_zoom_run(surface, 0.8, 1.0, NULL, NULL);
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -0500889}
890
891static void
892configure(struct wlsc_shell *shell, struct wlsc_surface *surface,
893 int32_t x, int32_t y, int32_t width, int32_t height)
894{
895 struct wlsc_mode *current;
896
Pekka Paalanen92a0dc42011-11-28 15:34:13 +0200897 switch (get_shell_surface_type(surface)) {
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500898 case SHELL_SURFACE_FULLSCREEN:
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -0500899 current = surface->fullscreen_output->current;
900 x = (current->width - surface->width) / 2;
901 y = (current->height - surface->height) / 2;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500902 break;
903 default:
904 break;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400905 }
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -0500906
907 wlsc_surface_configure(surface, x, y, width, height);
Kristian Høgsberg07937562011-04-12 17:25:42 -0400908}
909
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400910static void
Pekka Paalanen6cd281a2011-11-03 14:11:32 +0200911desktop_shell_sigchld(struct wlsc_process *process, int status)
912{
913 struct wl_shell *shell =
914 container_of(process, struct wl_shell, child.process);
915
916 shell->child.process.pid = 0;
917 shell->child.client = NULL; /* already destroyed by wayland */
918}
919
920static int
921launch_desktop_shell_process(struct wl_shell *shell)
922{
Kristian Høgsbergc4693c42011-11-14 14:57:17 -0500923 const char *shell_exe = LIBEXECDIR "/wayland-desktop-shell";
Pekka Paalanen6cd281a2011-11-03 14:11:32 +0200924
Pekka Paalanen409ef0a2011-12-02 15:30:21 +0200925 shell->child.client = wlsc_client_launch(shell->compositor,
926 &shell->child.process,
927 shell_exe,
928 desktop_shell_sigchld);
929
930 if (!shell->child.client)
Pekka Paalanen6cd281a2011-11-03 14:11:32 +0200931 return -1;
Pekka Paalanen6cd281a2011-11-03 14:11:32 +0200932 return 0;
933}
934
935static void
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400936bind_shell(struct wl_client *client, void *data, uint32_t version, uint32_t id)
937{
938 struct wl_shell *shell = data;
939
940 wl_client_add_object(client, &wl_shell_interface,
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200941 &shell_implementation, id, shell);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400942}
943
Kristian Høgsberg75840622011-09-06 13:48:16 -0400944static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200945unbind_desktop_shell(struct wl_resource *resource)
946{
947 struct wl_shell *shell = resource->data;
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500948
949 if (shell->locked)
950 resume_desktop(shell);
951
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200952 shell->child.desktop_shell = NULL;
953 shell->prepare_event_sent = false;
954 free(resource);
955}
956
957static void
Kristian Høgsberg75840622011-09-06 13:48:16 -0400958bind_desktop_shell(struct wl_client *client,
959 void *data, uint32_t version, uint32_t id)
960{
961 struct wl_shell *shell = data;
Pekka Paalanenbbe60522011-11-03 14:11:33 +0200962 struct wl_resource *resource;
Kristian Høgsberg75840622011-09-06 13:48:16 -0400963
Pekka Paalanenbbe60522011-11-03 14:11:33 +0200964 resource = wl_client_add_object(client, &desktop_shell_interface,
965 &desktop_shell_implementation,
966 id, shell);
967
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200968 if (client == shell->child.client) {
969 resource->destroy = unbind_desktop_shell;
970 shell->child.desktop_shell = resource;
Pekka Paalanenbbe60522011-11-03 14:11:33 +0200971 return;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200972 }
Pekka Paalanenbbe60522011-11-03 14:11:33 +0200973
974 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
975 "permission to bind desktop_shell denied");
976 wl_resource_destroy(resource, 0);
Kristian Høgsberg75840622011-09-06 13:48:16 -0400977}
978
Pekka Paalanen6e168112011-11-24 11:34:05 +0200979static void
980screensaver_set_surface(struct wl_client *client,
981 struct wl_resource *resource,
982 struct wl_resource *shell_surface_resource,
983 struct wl_resource *output_resource)
984{
985 struct wl_shell *shell = resource->data;
986 struct shell_surface *surface = shell_surface_resource->data;
987 struct wlsc_output *output = output_resource->data;
988
Pekka Paalanen98262232011-12-01 10:42:22 +0200989 if (reset_shell_surface_type(surface))
990 return;
991
Pekka Paalanen6e168112011-11-24 11:34:05 +0200992 /* TODO */
993}
994
995static const struct screensaver_interface screensaver_implementation = {
996 screensaver_set_surface
997};
998
999static void
1000unbind_screensaver(struct wl_resource *resource)
1001{
1002 struct wl_shell *shell = resource->data;
1003
1004 shell->screensaver = NULL;
1005 free(resource);
1006}
1007
1008static void
1009bind_screensaver(struct wl_client *client,
1010 void *data, uint32_t version, uint32_t id)
1011{
1012 struct wl_shell *shell = data;
1013 struct wl_resource *resource;
1014
1015 resource = wl_client_add_object(client, &screensaver_interface,
1016 &screensaver_implementation,
1017 id, shell);
1018
1019 if (shell->screensaver == NULL) {
1020 resource->destroy = unbind_screensaver;
1021 shell->screensaver = resource;
1022 return;
1023 }
1024
1025 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
1026 "interface object already bound");
1027 wl_resource_destroy(resource, 0);
1028}
1029
Kristian Høgsberg6c709a32011-05-06 14:52:41 -04001030int
1031shell_init(struct wlsc_compositor *ec);
1032
Kristian Høgsberg1c562182011-05-02 22:09:20 -04001033WL_EXPORT int
1034shell_init(struct wlsc_compositor *ec)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001035{
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001036 struct wl_shell *shell;
1037
1038 shell = malloc(sizeof *shell);
1039 if (shell == NULL)
1040 return -1;
1041
Kristian Høgsbergf0d91162011-10-11 22:44:23 -04001042 memset(shell, 0, sizeof *shell);
Kristian Høgsberg75840622011-09-06 13:48:16 -04001043 shell->compositor = ec;
1044 shell->shell.activate = activate;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001045 shell->shell.lock = lock;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001046 shell->shell.unlock = unlock;
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05001047 shell->shell.map = map;
1048 shell->shell.configure = configure;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001049
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001050 wl_list_init(&shell->hidden_surface_list);
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01001051 wl_list_init(&shell->backgrounds);
1052 wl_list_init(&shell->panels);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001053
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001054 if (wl_display_add_global(ec->wl_display, &wl_shell_interface,
1055 shell, bind_shell) == NULL)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001056 return -1;
1057
Kristian Høgsberg75840622011-09-06 13:48:16 -04001058 if (wl_display_add_global(ec->wl_display,
1059 &desktop_shell_interface,
1060 shell, bind_desktop_shell) == NULL)
1061 return -1;
1062
Pekka Paalanen6e168112011-11-24 11:34:05 +02001063 if (wl_display_add_global(ec->wl_display, &screensaver_interface,
1064 shell, bind_screensaver) == NULL)
1065 return -1;
1066
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02001067 if (launch_desktop_shell_process(shell) != 0)
1068 return -1;
1069
Kristian Høgsberg07937562011-04-12 17:25:42 -04001070 wlsc_compositor_add_binding(ec, 0, BTN_LEFT, MODIFIER_SUPER,
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001071 move_binding, shell);
Kristian Høgsberg07937562011-04-12 17:25:42 -04001072 wlsc_compositor_add_binding(ec, 0, BTN_MIDDLE, MODIFIER_SUPER,
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001073 resize_binding, shell);
1074
1075 ec->shell = &shell->shell;
Kristian Høgsberg07937562011-04-12 17:25:42 -04001076
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001077 return 0;
1078}