blob: edef868bda44cf5ada660cb51d147b8cf6050599 [file] [log] [blame]
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001/*
2 * Copyright © 2010 Intel Corporation
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02003 * Copyright © 2011 Collabora, Ltd.
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05004 *
5 * Permission to use, copy, modify, distribute, and sell this software and
6 * its documentation for any purpose is hereby granted without fee, provided
7 * that the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of the copyright holders not be used in
10 * advertising or publicity pertaining to distribution of the software
11 * without specific, written prior permission. The copyright holders make
12 * no representations about the suitability of this software for any
13 * purpose. It is provided "as is" without express or implied warranty.
14 *
15 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
16 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
20 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 */
23
24#include <stdlib.h>
Kristian Høgsberg75840622011-09-06 13:48:16 -040025#include <stdio.h>
Pekka Paalanen9ef3e012011-11-15 13:34:48 +020026#include <stdbool.h>
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050027#include <string.h>
28#include <unistd.h>
Kristian Høgsberg07937562011-04-12 17:25:42 -040029#include <linux/input.h>
Pekka Paalanen6cd281a2011-11-03 14:11:32 +020030#include <sys/types.h>
31#include <sys/socket.h>
32#include <fcntl.h>
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +020033#include <assert.h>
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050034
Pekka Paalanen50719bc2011-11-22 14:18:50 +020035#include <wayland-server.h>
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050036#include "compositor.h"
Kristian Høgsberg75840622011-09-06 13:48:16 -040037#include "desktop-shell-server-protocol.h"
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050038
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -040039struct wl_shell {
Kristian Høgsberg75840622011-09-06 13:48:16 -040040 struct wlsc_compositor *compositor;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -040041 struct wlsc_shell shell;
Kristian Høgsberg75840622011-09-06 13:48:16 -040042 struct wlsc_surface *panel;
43 struct wl_listener panel_listener;
44 struct wlsc_surface *background;
45 struct wl_listener background_listener;
Pekka Paalanen6cd281a2011-11-03 14:11:32 +020046
47 struct {
48 struct wlsc_process process;
49 struct wl_client *client;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +020050 struct wl_resource *desktop_shell;
Pekka Paalanen6cd281a2011-11-03 14:11:32 +020051 } child;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +020052
53 bool locked;
54 bool prepare_event_sent;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +020055
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -050056 struct wlsc_surface *lock_surface;
57 struct wl_listener lock_surface_listener;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +020058 struct wl_list hidden_surface_list;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -040059};
60
Pekka Paalanen56cdea92011-11-23 16:14:12 +020061struct shell_surface {
62 struct wl_listener destroy_listener;
63};
64
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050065struct wlsc_move_grab {
66 struct wl_grab grab;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -050067 struct wlsc_surface *surface;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050068 int32_t dx, dy;
69};
70
71static void
Pekka Paalanen56cdea92011-11-23 16:14:12 +020072destroy_shell_surface(struct shell_surface *priv)
73{
74 wl_list_remove(&priv->destroy_listener.link);
75 free(priv);
76}
77
78static void
79handle_shell_surface_destroy(struct wl_listener *listener,
80 struct wl_resource *resource, uint32_t time)
81{
82 struct shell_surface *priv =
83 container_of(listener, struct shell_surface, destroy_listener);
84 destroy_shell_surface(priv);
85}
86
87static struct shell_surface *
88get_shell_surface(struct wlsc_surface *surface)
89{
90 struct shell_surface *priv;
91
92 if (surface->shell_priv)
93 return surface->shell_priv;
94
95 priv = calloc(1, sizeof *priv);
96 if (!priv)
97 return NULL;
98
99 priv->destroy_listener.func = handle_shell_surface_destroy;
100 wl_list_insert(surface->surface.resource.destroy_listener_list.prev,
101 &priv->destroy_listener.link);
102
103 surface->shell_priv = priv;
104
105 return priv;
106}
107
108static void
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500109move_grab_motion(struct wl_grab *grab,
110 uint32_t time, int32_t x, int32_t y)
111{
112 struct wlsc_move_grab *move = (struct wlsc_move_grab *) grab;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -0500113 struct wlsc_surface *es = move->surface;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500114
Kristian Høgsberga691aee2011-06-23 21:43:50 -0400115 wlsc_surface_configure(es, x + move->dx, y + move->dy,
116 es->width, es->height);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500117}
118
119static void
120move_grab_button(struct wl_grab *grab,
121 uint32_t time, int32_t button, int32_t state)
122{
123}
124
125static void
126move_grab_end(struct wl_grab *grab, uint32_t time)
127{
128 free(grab);
129}
130
131static const struct wl_grab_interface move_grab_interface = {
132 move_grab_motion,
133 move_grab_button,
134 move_grab_end
135};
136
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400137static int
138wlsc_surface_move(struct wlsc_surface *es,
139 struct wlsc_input_device *wd, uint32_t time)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500140{
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500141 struct wlsc_move_grab *move;
142
143 move = malloc(sizeof *move);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400144 if (!move)
145 return -1;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500146
147 move->grab.interface = &move_grab_interface;
148 move->dx = es->x - wd->input_device.grab_x;
149 move->dy = es->y - wd->input_device.grab_y;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -0500150 move->surface = es;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500151
152 if (wl_input_device_update_grab(&wd->input_device,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400153 &move->grab, &es->surface, time) < 0)
154 return 0;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500155
156 wlsc_input_device_set_pointer_image(wd, WLSC_POINTER_DRAGGING);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400157 wl_input_device_set_pointer_focus(&wd->input_device,
158 NULL, time, 0, 0, 0, 0);
159
160 return 0;
161}
162
163static void
164shell_move(struct wl_client *client, struct wl_resource *resource,
165 struct wl_resource *surface_resource,
166 struct wl_resource *input_resource, uint32_t time)
167{
168 struct wlsc_input_device *wd = input_resource->data;
169 struct wlsc_surface *es = surface_resource->data;
170
171 if (wlsc_surface_move(es, wd, time) < 0)
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400172 wl_resource_post_no_memory(resource);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500173}
174
175struct wlsc_resize_grab {
176 struct wl_grab grab;
177 uint32_t edges;
178 int32_t dx, dy, width, height;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -0500179 struct wlsc_surface *surface;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400180 struct wl_resource *resource;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500181};
182
183static void
184resize_grab_motion(struct wl_grab *grab,
185 uint32_t time, int32_t x, int32_t y)
186{
187 struct wlsc_resize_grab *resize = (struct wlsc_resize_grab *) grab;
188 struct wl_input_device *device = grab->input_device;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -0500189 struct wl_surface *surface = &resize->surface->surface;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500190 int32_t width, height;
191
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500192 if (resize->edges & WL_SHELL_RESIZE_LEFT) {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500193 width = device->grab_x - x + resize->width;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500194 } else if (resize->edges & WL_SHELL_RESIZE_RIGHT) {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500195 width = x - device->grab_x + resize->width;
196 } else {
197 width = resize->width;
198 }
199
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500200 if (resize->edges & WL_SHELL_RESIZE_TOP) {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500201 height = device->grab_y - y + resize->height;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500202 } else if (resize->edges & WL_SHELL_RESIZE_BOTTOM) {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500203 height = y - device->grab_y + resize->height;
204 } else {
205 height = resize->height;
206 }
207
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400208 wl_resource_post_event(resize->resource,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400209 WL_SHELL_CONFIGURE, time, resize->edges,
210 surface, width, height);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500211}
212
213static void
214resize_grab_button(struct wl_grab *grab,
215 uint32_t time, int32_t button, int32_t state)
216{
217}
218
219static void
220resize_grab_end(struct wl_grab *grab, uint32_t time)
221{
222 free(grab);
223}
224
225static const struct wl_grab_interface resize_grab_interface = {
226 resize_grab_motion,
227 resize_grab_button,
228 resize_grab_end
229};
230
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400231static int
232wlsc_surface_resize(struct wlsc_surface *es,
233 struct wlsc_input_device *wd,
234 uint32_t time, uint32_t edges,
235 struct wl_resource *resource)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500236{
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500237 struct wlsc_resize_grab *resize;
238 enum wlsc_pointer_type pointer = WLSC_POINTER_LEFT_PTR;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500239
Kristian Høgsberg0ce24572011-01-28 15:18:33 -0500240 /* FIXME: Reject if fullscreen */
241
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500242 resize = malloc(sizeof *resize);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400243 if (!resize)
244 return -1;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500245
246 resize->grab.interface = &resize_grab_interface;
247 resize->edges = edges;
248 resize->dx = es->x - wd->input_device.grab_x;
249 resize->dy = es->y - wd->input_device.grab_y;
250 resize->width = es->width;
251 resize->height = es->height;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -0500252 resize->surface = es;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400253 resize->resource = resource;
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400254
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500255 if (edges == 0 || edges > 15 ||
256 (edges & 3) == 3 || (edges & 12) == 12)
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400257 return 0;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500258
259 switch (edges) {
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500260 case WL_SHELL_RESIZE_TOP:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500261 pointer = WLSC_POINTER_TOP;
262 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500263 case WL_SHELL_RESIZE_BOTTOM:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500264 pointer = WLSC_POINTER_BOTTOM;
265 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500266 case WL_SHELL_RESIZE_LEFT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500267 pointer = WLSC_POINTER_LEFT;
268 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500269 case WL_SHELL_RESIZE_TOP_LEFT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500270 pointer = WLSC_POINTER_TOP_LEFT;
271 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500272 case WL_SHELL_RESIZE_BOTTOM_LEFT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500273 pointer = WLSC_POINTER_BOTTOM_LEFT;
274 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500275 case WL_SHELL_RESIZE_RIGHT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500276 pointer = WLSC_POINTER_RIGHT;
277 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500278 case WL_SHELL_RESIZE_TOP_RIGHT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500279 pointer = WLSC_POINTER_TOP_RIGHT;
280 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500281 case WL_SHELL_RESIZE_BOTTOM_RIGHT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500282 pointer = WLSC_POINTER_BOTTOM_RIGHT;
283 break;
284 }
285
286 if (wl_input_device_update_grab(&wd->input_device,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400287 &resize->grab, &es->surface, time) < 0)
288 return 0;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500289
290 wlsc_input_device_set_pointer_image(wd, pointer);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400291 wl_input_device_set_pointer_focus(&wd->input_device,
292 NULL, time, 0, 0, 0, 0);
293
294 return 0;
295}
296
297static void
298shell_resize(struct wl_client *client, struct wl_resource *resource,
299 struct wl_resource *surface_resource,
300 struct wl_resource *input_resource, uint32_t time, uint32_t edges)
301{
302 struct wlsc_input_device *wd = input_resource->data;
303 struct wlsc_surface *es = surface_resource->data;
304
305 /* FIXME: Reject if fullscreen */
306
307 if (wlsc_surface_resize(es, wd, time, edges, resource) < 0)
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400308 wl_resource_post_no_memory(resource);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500309}
310
311static void
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400312shell_set_toplevel(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400313 struct wl_resource *resource,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400314 struct wl_resource *surface_resource)
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400315
316{
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400317 struct wlsc_surface *es = surface_resource->data;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400318
319 if (es->map_type == WLSC_SURFACE_MAP_FULLSCREEN) {
320 es->x = es->saved_x;
321 es->y = es->saved_y;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400322 }
323
324 wlsc_surface_damage(es);
325 es->map_type = WLSC_SURFACE_MAP_TOPLEVEL;
326 es->fullscreen_output = NULL;
327}
328
329static void
330shell_set_transient(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400331 struct wl_resource *resource,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400332 struct wl_resource *surface_resource,
333 struct wl_resource *parent_resource,
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400334 int x, int y, uint32_t flags)
335{
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400336 struct wlsc_surface *es = surface_resource->data;
337 struct wlsc_surface *pes = parent_resource->data;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400338
339 /* assign to parents output */
340 es->output = pes->output;
341
342 es->x = pes->x + x;
343 es->y = pes->y + y;
344
345 wlsc_surface_damage(es);
346 es->map_type = WLSC_SURFACE_MAP_TRANSIENT;
347}
348
349static void
350shell_set_fullscreen(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400351 struct wl_resource *resource,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400352 struct wl_resource *surface_resource)
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400353
354{
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400355 struct wlsc_surface *es = surface_resource->data;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400356 struct wlsc_output *output;
357
358 /* FIXME: Fullscreen on first output */
359 /* FIXME: Handle output going away */
360 output = container_of(es->compositor->output_list.next,
361 struct wlsc_output, link);
362 es->output = output;
363
364 es->saved_x = es->x;
365 es->saved_y = es->y;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400366 es->x = (output->current->width - es->width) / 2;
367 es->y = (output->current->height - es->height) / 2;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400368 es->fullscreen_output = output;
369 wlsc_surface_damage(es);
370 es->map_type = WLSC_SURFACE_MAP_FULLSCREEN;
371}
372
373static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400374destroy_drag(struct wl_resource *resource)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500375{
376 struct wl_drag *drag =
377 container_of(resource, struct wl_drag, resource);
378
379 wl_list_remove(&drag->drag_focus_listener.link);
380 if (drag->grab.input_device)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400381 wl_input_device_end_grab(drag->grab.input_device,
382 wlsc_compositor_get_time());
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500383
384 free(drag);
385}
386
387
388static void
389wl_drag_set_pointer_focus(struct wl_drag *drag,
390 struct wl_surface *surface, uint32_t time,
391 int32_t x, int32_t y, int32_t sx, int32_t sy)
392{
393 char **p, **end;
394
395 if (drag->drag_focus == surface)
396 return;
397
398 if (drag->drag_focus &&
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400399 (!surface ||
400 drag->drag_focus->resource.client != surface->resource.client))
401 wl_resource_post_event(&drag->drag_offer.resource,
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500402 WL_DRAG_OFFER_POINTER_FOCUS,
403 time, NULL, 0, 0, 0, 0);
404
405 if (surface &&
406 (!drag->drag_focus ||
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400407 drag->drag_focus->resource.client != surface->resource.client)) {
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400408
409 drag->drag_offer.resource.client = surface->resource.client;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500410 end = drag->types.data + drag->types.size;
411 for (p = drag->types.data; p < end; p++)
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400412 wl_resource_post_event(&drag->drag_offer.resource,
413 WL_DRAG_OFFER_OFFER, *p);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500414 }
415
416 if (surface) {
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400417 wl_resource_post_event(&drag->drag_offer.resource,
418 WL_DRAG_OFFER_POINTER_FOCUS,
419 time, surface,
420 x, y, sx, sy);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500421
422 }
423
424 drag->drag_focus = surface;
425 drag->pointer_focus_time = time;
426 drag->target = NULL;
427
428 wl_list_remove(&drag->drag_focus_listener.link);
429 if (surface)
Benjamin Franzke4721a3c2011-05-06 17:13:17 +0200430 wl_list_insert(surface->resource.destroy_listener_list.prev,
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500431 &drag->drag_focus_listener.link);
432}
433
434static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400435drag_offer_accept(struct wl_client *client, struct wl_resource *resource,
436 uint32_t time, const char *type)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500437{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400438 struct wl_drag_offer *offer = resource->data;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500439 struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer);
440 char **p, **end;
441
442 /* If the client responds to drag pointer_focus or motion
443 * events after the pointer has left the surface, we just
444 * discard the accept requests. The drag source just won't
445 * get the corresponding 'target' events and eventually the
446 * next surface/root will start sending events. */
447 if (time < drag->pointer_focus_time)
448 return;
449
450 drag->target = client;
451 drag->type = NULL;
452 end = drag->types.data + drag->types.size;
453 for (p = drag->types.data; p < end; p++)
454 if (type && strcmp(*p, type) == 0)
455 drag->type = *p;
456
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400457 wl_resource_post_event(&drag->resource, WL_DRAG_TARGET, drag->type);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500458}
459
460static void
461drag_offer_receive(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400462 struct wl_resource *resource, int fd)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500463{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400464 struct wl_drag_offer *offer = resource->data;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500465 struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer);
466
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400467 wl_resource_post_event(&drag->resource, WL_DRAG_FINISH, fd);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500468 close(fd);
469}
470
471static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400472drag_offer_reject(struct wl_client *client, struct wl_resource *resource)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500473{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400474 struct wl_drag_offer *offer = resource->data;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500475 struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer);
476
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400477 wl_resource_post_event(&drag->resource, WL_DRAG_REJECT);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500478}
479
480static const struct wl_drag_offer_interface drag_offer_interface = {
481 drag_offer_accept,
482 drag_offer_receive,
483 drag_offer_reject
484};
485
486static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400487drag_offer(struct wl_client *client,
488 struct wl_resource *resource, const char *type)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500489{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400490 struct wl_drag *drag = resource->data;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500491 char **p;
492
493 p = wl_array_add(&drag->types, sizeof *p);
494 if (p)
495 *p = strdup(type);
496 if (!p || !*p)
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400497 wl_resource_post_no_memory(resource);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500498}
499
500static void
501drag_grab_motion(struct wl_grab *grab,
502 uint32_t time, int32_t x, int32_t y)
503{
504 struct wl_drag *drag = container_of(grab, struct wl_drag, grab);
505 struct wlsc_surface *es;
506 int32_t sx, sy;
507
508 es = pick_surface(grab->input_device, &sx, &sy);
509 wl_drag_set_pointer_focus(drag, &es->surface, time, x, y, sx, sy);
510 if (es)
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400511 wl_resource_post_event(&drag->drag_offer.resource,
512 WL_DRAG_OFFER_MOTION,
513 time, x, y, sx, sy);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500514}
515
516static void
517drag_grab_button(struct wl_grab *grab,
518 uint32_t time, int32_t button, int32_t state)
519{
520}
521
522static void
523drag_grab_end(struct wl_grab *grab, uint32_t time)
524{
525 struct wl_drag *drag = container_of(grab, struct wl_drag, grab);
526
527 if (drag->target)
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400528 wl_resource_post_event(&drag->drag_offer.resource,
529 WL_DRAG_OFFER_DROP);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500530
531 wl_drag_set_pointer_focus(drag, NULL, time, 0, 0, 0, 0);
532}
533
534static const struct wl_grab_interface drag_grab_interface = {
535 drag_grab_motion,
536 drag_grab_button,
537 drag_grab_end
538};
539
540static void
541drag_activate(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400542 struct wl_resource *resource,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400543 struct wl_resource *surface_resource,
544 struct wl_resource *device_resource, uint32_t time)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500545{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400546 struct wl_drag *drag = resource->data;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400547 struct wl_surface *surface = surface_resource->data;
548 struct wl_input_device *device = device_resource->data;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500549 struct wl_display *display = wl_client_get_display (client);
550 struct wlsc_surface *target;
551 int32_t sx, sy;
552
553 if (wl_input_device_update_grab(device,
554 &drag->grab, surface, time) < 0)
555 return;
556
557 drag->grab.interface = &drag_grab_interface;
558
559 drag->source = surface;
560
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400561 drag->drag_offer.resource.object.interface = &wl_drag_offer_interface;
562 drag->drag_offer.resource.object.implementation =
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500563 (void (**)(void)) &drag_offer_interface;
564
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400565 wl_display_add_global(display, &wl_drag_offer_interface, drag, NULL);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500566
567 target = pick_surface(device, &sx, &sy);
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -0500568 wl_input_device_set_pointer_focus(device, NULL, time, 0, 0, 0, 0);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500569 wl_drag_set_pointer_focus(drag, &target->surface, time,
570 device->x, device->y, sx, sy);
571}
572
573static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400574drag_destroy(struct wl_client *client, struct wl_resource *resource)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500575{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400576 wl_resource_destroy(resource, wlsc_compositor_get_time());
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500577}
578
579static const struct wl_drag_interface drag_interface = {
580 drag_offer,
581 drag_activate,
582 drag_destroy,
583};
584
585static void
586drag_handle_surface_destroy(struct wl_listener *listener,
Benjamin Franzke4721a3c2011-05-06 17:13:17 +0200587 struct wl_resource *resource, uint32_t time)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500588{
589 struct wl_drag *drag =
590 container_of(listener, struct wl_drag, drag_focus_listener);
Benjamin Franzke4721a3c2011-05-06 17:13:17 +0200591 struct wl_surface *surface = (struct wl_surface *) resource;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500592
593 if (drag->drag_focus == surface)
594 wl_drag_set_pointer_focus(drag, NULL, time, 0, 0, 0, 0);
595}
596
597static void
598shell_create_drag(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400599 struct wl_resource *resource, uint32_t id)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500600{
601 struct wl_drag *drag;
602
603 drag = malloc(sizeof *drag);
604 if (drag == NULL) {
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400605 wl_resource_post_no_memory(resource);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500606 return;
607 }
608
609 memset(drag, 0, sizeof *drag);
610 drag->resource.object.id = id;
611 drag->resource.object.interface = &wl_drag_interface;
612 drag->resource.object.implementation =
613 (void (**)(void)) &drag_interface;
614
Pekka Paalanen02ebfb12011-10-24 17:34:53 +0300615 drag->resource.data = drag;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500616 drag->resource.destroy = destroy_drag;
617
618 drag->drag_focus_listener.func = drag_handle_surface_destroy;
619 wl_list_init(&drag->drag_focus_listener.link);
620
621 wl_client_add_resource(client, &drag->resource);
622}
623
Kristian Høgsberg1c562182011-05-02 22:09:20 -0400624static void
625wlsc_selection_set_focus(struct wlsc_shell *shell,
626 struct wl_selection *selection,
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500627 struct wl_surface *surface, uint32_t time)
628{
629 char **p, **end;
630
631 if (selection->selection_focus == surface)
632 return;
633
634 if (selection->selection_focus != NULL)
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400635 wl_resource_post_event(&selection->selection_offer.resource,
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500636 WL_SELECTION_OFFER_KEYBOARD_FOCUS,
637 NULL);
638
639 if (surface) {
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500640
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400641 selection->selection_offer.resource.client = surface->resource.client;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500642 end = selection->types.data + selection->types.size;
643 for (p = selection->types.data; p < end; p++)
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400644 wl_resource_post_event(&selection->selection_offer.resource,
645 WL_SELECTION_OFFER_OFFER, *p);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500646
647 wl_list_remove(&selection->selection_focus_listener.link);
Benjamin Franzke4721a3c2011-05-06 17:13:17 +0200648 wl_list_insert(surface->resource.destroy_listener_list.prev,
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500649 &selection->selection_focus_listener.link);
650
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400651 wl_resource_post_event(&selection->selection_offer.resource,
652 WL_SELECTION_OFFER_KEYBOARD_FOCUS,
653 selection->input_device);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500654 }
655
656 selection->selection_focus = surface;
657
658 wl_list_remove(&selection->selection_focus_listener.link);
659 if (surface)
Benjamin Franzke4721a3c2011-05-06 17:13:17 +0200660 wl_list_insert(surface->resource.destroy_listener_list.prev,
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500661 &selection->selection_focus_listener.link);
662}
663
664static void
665selection_offer_receive(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400666 struct wl_resource *resource,
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500667 const char *mime_type, int fd)
668{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400669 struct wl_selection_offer *offer = resource->data;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500670 struct wl_selection *selection =
671 container_of(offer, struct wl_selection, selection_offer);
672
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400673 wl_resource_post_event(&selection->resource,
674 WL_SELECTION_SEND, mime_type, fd);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500675 close(fd);
676}
677
678static const struct wl_selection_offer_interface selection_offer_interface = {
679 selection_offer_receive
680};
681
682static void
683selection_offer(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400684 struct wl_resource *resource, const char *type)
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500685{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400686 struct wl_selection *selection = resource->data;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500687 char **p;
688
689 p = wl_array_add(&selection->types, sizeof *p);
690 if (p)
691 *p = strdup(type);
692 if (!p || !*p)
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400693 wl_resource_post_no_memory(resource);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500694}
695
696static void
697selection_activate(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400698 struct wl_resource *resource,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400699 struct wl_resource *input_resource, uint32_t time)
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500700{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400701 struct wl_selection *selection = resource->data;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400702 struct wlsc_input_device *wd = input_resource->data;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500703 struct wl_display *display = wl_client_get_display (client);
Kristian Høgsberg1c562182011-05-02 22:09:20 -0400704 struct wlsc_compositor *compositor =
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400705 (struct wlsc_compositor *) wd->input_device.compositor;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500706
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400707 selection->input_device = &wd->input_device;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500708
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400709 selection->selection_offer.resource.object.interface =
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500710 &wl_selection_offer_interface;
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400711 selection->selection_offer.resource.object.implementation =
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500712 (void (**)(void)) &selection_offer_interface;
713
Kristian Høgsbergd9551a32011-08-19 12:07:44 -0400714 wl_display_add_global(display,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400715 &wl_selection_offer_interface, selection, NULL);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500716
717 if (wd->selection) {
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400718 wl_resource_post_event(&wd->selection->resource,
719 WL_SELECTION_CANCELLED);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500720 }
721 wd->selection = selection;
722
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400723 wlsc_selection_set_focus(compositor->shell, selection,
724 wd->input_device.keyboard_focus, time);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500725}
726
727static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400728selection_destroy(struct wl_client *client, struct wl_resource *resource)
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500729{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400730 wl_resource_destroy(resource, wlsc_compositor_get_time());
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500731}
732
733static const struct wl_selection_interface selection_interface = {
734 selection_offer,
735 selection_activate,
736 selection_destroy
737};
738
739static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400740destroy_selection(struct wl_resource *resource)
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500741{
742 struct wl_selection *selection =
743 container_of(resource, struct wl_selection, resource);
744 struct wlsc_input_device *wd =
745 (struct wlsc_input_device *) selection->input_device;
Kristian Høgsberg1c562182011-05-02 22:09:20 -0400746 struct wlsc_compositor *compositor =
747 (struct wlsc_compositor *) wd->input_device.compositor;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500748
749 if (wd && wd->selection == selection) {
750 wd->selection = NULL;
Kristian Høgsberg1c562182011-05-02 22:09:20 -0400751 wlsc_selection_set_focus(compositor->shell,
752 selection, NULL,
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400753 wlsc_compositor_get_time());
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500754 }
755
756 wl_list_remove(&selection->selection_focus_listener.link);
757 free(selection);
758}
759
760static void
761selection_handle_surface_destroy(struct wl_listener *listener,
Benjamin Franzke4721a3c2011-05-06 17:13:17 +0200762 struct wl_resource *resource, uint32_t time)
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500763{
764}
765
766static void
767shell_create_selection(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400768 struct wl_resource *resource, uint32_t id)
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500769{
770 struct wl_selection *selection;
771
772 selection = malloc(sizeof *selection);
773 if (selection == NULL) {
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400774 wl_resource_post_no_memory(resource);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500775 return;
776 }
777
778 memset(selection, 0, sizeof *selection);
779 selection->resource.object.id = id;
780 selection->resource.object.interface = &wl_selection_interface;
781 selection->resource.object.implementation =
782 (void (**)(void)) &selection_interface;
783
784 selection->client = client;
785 selection->resource.destroy = destroy_selection;
786 selection->selection_focus = NULL;
787
788 selection->selection_focus_listener.func =
789 selection_handle_surface_destroy;
790 wl_list_init(&selection->selection_focus_listener.link);
791
792 wl_client_add_resource(client, &selection->resource);
793}
794
Kristian Høgsberg75840622011-09-06 13:48:16 -0400795static const struct wl_shell_interface shell_interface = {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500796 shell_move,
797 shell_resize,
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500798 shell_create_drag,
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400799 shell_create_selection,
800 shell_set_toplevel,
801 shell_set_transient,
802 shell_set_fullscreen
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500803};
804
Kristian Høgsberg07937562011-04-12 17:25:42 -0400805static void
Kristian Høgsberg75840622011-09-06 13:48:16 -0400806handle_background_surface_destroy(struct wl_listener *listener,
807 struct wl_resource *resource, uint32_t time)
808{
809 struct wl_shell *shell =
810 container_of(listener, struct wl_shell, background_listener);
811
812 fprintf(stderr, "background surface gone\n");
813 shell->background = NULL;
814}
815
816static void
817desktop_shell_set_background(struct wl_client *client,
818 struct wl_resource *resource,
819 struct wl_resource *surface_resource)
820{
821 struct wl_shell *shell = resource->data;
822 struct wlsc_surface *surface = surface_resource->data;
823 struct wlsc_output *output =
824 container_of(shell->compositor->output_list.next,
825 struct wlsc_output, link);
826
827 shell->background = surface_resource->data;
828 shell->background_listener.func = handle_background_surface_destroy;
829 wl_list_insert(&surface_resource->destroy_listener_list,
830 &shell->background_listener.link);
831
832 wl_resource_post_event(resource,
833 DESKTOP_SHELL_CONFIGURE,
834 wlsc_compositor_get_time(), 0, surface,
835 output->current->width,
836 output->current->height);
837}
838
839static void
840handle_panel_surface_destroy(struct wl_listener *listener,
841 struct wl_resource *resource, uint32_t time)
842{
843 struct wl_shell *shell =
844 container_of(listener, struct wl_shell, panel_listener);
845
846 fprintf(stderr, "panel surface gone\n");
847 shell->panel = NULL;
848}
849
850static void
851desktop_shell_set_panel(struct wl_client *client,
852 struct wl_resource *resource,
853 struct wl_resource *surface_resource)
854{
855 struct wl_shell *shell = resource->data;
856 struct wlsc_output *output =
857 container_of(shell->compositor->output_list.next,
858 struct wlsc_output, link);
859
860 shell->panel = surface_resource->data;
861
862 shell->panel_listener.func = handle_panel_surface_destroy;
863 wl_list_insert(&surface_resource->destroy_listener_list,
864 &shell->panel_listener.link);
865
866 wl_resource_post_event(resource,
867 DESKTOP_SHELL_CONFIGURE,
868 wlsc_compositor_get_time(), 0, surface_resource,
869 output->current->width,
870 output->current->height);
871}
872
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200873static void
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500874handle_lock_surface_destroy(struct wl_listener *listener,
875 struct wl_resource *resource, uint32_t time)
876{
877 struct wl_shell *shell =
Pekka Paalanen2ca86302011-11-16 13:47:35 +0200878 container_of(listener, struct wl_shell, lock_surface_listener);
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500879
880 fprintf(stderr, "lock surface gone\n");
881 shell->lock_surface = NULL;
882}
883
884static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200885desktop_shell_set_lock_surface(struct wl_client *client,
886 struct wl_resource *resource,
887 struct wl_resource *surface_resource)
888{
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +0200889 struct wl_shell *shell = resource->data;
890
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200891 shell->prepare_event_sent = false;
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +0200892
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200893 if (!shell->locked)
894 return;
895
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500896 shell->lock_surface = surface_resource->data;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200897
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500898 shell->lock_surface_listener.func = handle_lock_surface_destroy;
899 wl_list_insert(&surface_resource->destroy_listener_list,
900 &shell->lock_surface_listener.link);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200901}
902
903static void
904resume_desktop(struct wl_shell *shell)
905{
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500906 struct wlsc_surface *surface;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200907
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500908 wl_list_for_each(surface, &shell->hidden_surface_list, link)
909 wlsc_surface_configure(surface, surface->x, surface->y,
910 surface->width, surface->height);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200911
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500912 wl_list_insert_list(shell->background->link.prev,
913 &shell->hidden_surface_list);
914 wl_list_init(&shell->hidden_surface_list);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200915
916 shell->locked = false;
917 wlsc_compositor_repick(shell->compositor);
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +0200918 wlsc_compositor_wake(shell->compositor);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200919}
920
921static void
922desktop_shell_unlock(struct wl_client *client,
923 struct wl_resource *resource)
924{
925 struct wl_shell *shell = resource->data;
926
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200927 shell->prepare_event_sent = false;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200928
929 if (shell->locked)
930 resume_desktop(shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200931}
932
Kristian Høgsberg75840622011-09-06 13:48:16 -0400933static const struct desktop_shell_interface desktop_shell_implementation = {
934 desktop_shell_set_background,
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200935 desktop_shell_set_panel,
936 desktop_shell_set_lock_surface,
937 desktop_shell_unlock
Kristian Høgsberg75840622011-09-06 13:48:16 -0400938};
939
940static void
Kristian Høgsberg07937562011-04-12 17:25:42 -0400941move_binding(struct wl_input_device *device, uint32_t time,
942 uint32_t key, uint32_t button, uint32_t state, void *data)
943{
Kristian Høgsberg75840622011-09-06 13:48:16 -0400944 struct wl_shell *shell = data;
Kristian Høgsberg07937562011-04-12 17:25:42 -0400945 struct wlsc_surface *surface =
946 (struct wlsc_surface *) device->pointer_focus;
947
Kristian Høgsberga4a42f02011-09-08 16:56:57 -0400948 if (surface == NULL ||
949 surface->map_type == WLSC_SURFACE_MAP_FULLSCREEN)
Kristian Høgsberg10f097e2011-04-13 11:52:54 -0400950 return;
Kristian Høgsberg75840622011-09-06 13:48:16 -0400951 if (surface == shell->panel)
952 return;
953 if (surface == shell->background)
954 return;
Kristian Høgsberg10f097e2011-04-13 11:52:54 -0400955
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400956 wlsc_surface_move(surface, (struct wlsc_input_device *) device, time);
Kristian Høgsberg07937562011-04-12 17:25:42 -0400957}
958
959static void
960resize_binding(struct wl_input_device *device, uint32_t time,
961 uint32_t key, uint32_t button, uint32_t state, void *data)
962{
Kristian Høgsberg75840622011-09-06 13:48:16 -0400963 struct wl_shell *shell = data;
Kristian Høgsberg07937562011-04-12 17:25:42 -0400964 struct wlsc_surface *surface =
965 (struct wlsc_surface *) device->pointer_focus;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400966 struct wl_resource *resource;
Kristian Høgsberg07937562011-04-12 17:25:42 -0400967 uint32_t edges = 0;
968 int32_t x, y;
969
Kristian Høgsberga4a42f02011-09-08 16:56:57 -0400970 if (surface == NULL ||
971 surface->map_type == WLSC_SURFACE_MAP_FULLSCREEN)
Kristian Høgsberg75840622011-09-06 13:48:16 -0400972 if (surface == shell->panel)
973 return;
974 if (surface == shell->background)
975 return;
Kristian Høgsberg10f097e2011-04-13 11:52:54 -0400976
Kristian Høgsberg07937562011-04-12 17:25:42 -0400977 x = device->grab_x - surface->x;
978 y = device->grab_y - surface->y;
979
980 if (x < surface->width / 3)
981 edges |= WL_SHELL_RESIZE_LEFT;
982 else if (x < 2 * surface->width / 3)
983 edges |= 0;
984 else
985 edges |= WL_SHELL_RESIZE_RIGHT;
986
987 if (y < surface->height / 3)
988 edges |= WL_SHELL_RESIZE_TOP;
989 else if (y < 2 * surface->height / 3)
990 edges |= 0;
991 else
992 edges |= WL_SHELL_RESIZE_BOTTOM;
993
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400994 resource = /* Find shell resource for surface client */ 0;
995
996 /* ... or use wl_shell_surface */
997
998 wlsc_surface_resize(surface, (struct wlsc_input_device *) device,
999 time, edges, resource);
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001000}
1001
1002static void
Kristian Høgsberg75840622011-09-06 13:48:16 -04001003activate(struct wlsc_shell *base, struct wlsc_surface *es,
1004 struct wlsc_input_device *device, uint32_t time)
1005{
1006 struct wl_shell *shell = container_of(base, struct wl_shell, shell);
1007 struct wlsc_compositor *compositor = shell->compositor;
1008
1009 wlsc_surface_activate(es, device, time);
1010
Kristian Høgsbergd6e55252011-10-11 23:41:17 -04001011 if (compositor->wxs)
1012 wlsc_xserver_surface_activate(es);
1013
Kristian Høgsberg75840622011-09-06 13:48:16 -04001014 if (es == shell->background) {
1015 wl_list_remove(&es->link);
1016 wl_list_insert(compositor->surface_list.prev, &es->link);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001017 } else if (shell->panel && !shell->locked) {
Kristian Høgsberg75840622011-09-06 13:48:16 -04001018 wl_list_remove(&shell->panel->link);
1019 wl_list_insert(&compositor->surface_list, &shell->panel->link);
1020 }
1021}
1022
1023static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001024lock(struct wlsc_shell *base)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001025{
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001026 struct wl_shell *shell = container_of(base, struct wl_shell, shell);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001027 struct wl_list *surface_list = &shell->compositor->surface_list;
1028 struct wlsc_surface *cur;
1029 struct wlsc_surface *tmp;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001030 struct wlsc_input_device *device;
1031 uint32_t time;
1032
1033 if (shell->locked)
1034 return;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001035
1036 shell->locked = true;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001037
1038 /* Move all surfaces from compositor's list to our hidden list,
1039 * except the background. This way nothing else can show or
1040 * receive input events while we are locked. */
1041
1042 if (!wl_list_empty(&shell->hidden_surface_list)) {
1043 fprintf(stderr,
1044 "%s: Assertion failed: hidden_surface_list is not empty.\n",
1045 __func__);
1046 }
1047
1048 wl_list_for_each_safe(cur, tmp, surface_list, link) {
1049 /* skip input device sprites, cur->surface is uninitialised */
1050 if (cur->surface.resource.client == NULL)
1051 continue;
1052
1053 if (cur == shell->background)
1054 continue;
1055
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001056 cur->output = NULL;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001057 wl_list_remove(&cur->link);
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001058 wl_list_insert(shell->hidden_surface_list.prev, &cur->link);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001059 }
1060
1061 /* reset pointer foci */
1062 wlsc_compositor_repick(shell->compositor);
1063
1064 /* reset keyboard foci */
1065 time = wlsc_compositor_get_time();
1066 wl_list_for_each(device, &shell->compositor->input_device_list, link) {
1067 wl_input_device_set_keyboard_focus(&device->input_device,
1068 NULL, time);
1069 }
1070
1071 /* TODO: disable bindings that should not work while locked. */
1072
1073 /* All this must be undone in resume_desktop(). */
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001074}
1075
1076static void
1077unlock(struct wlsc_shell *base)
1078{
1079 struct wl_shell *shell = container_of(base, struct wl_shell, shell);
1080
Pekka Paalanend81c2162011-11-16 13:47:34 +02001081 if (!shell->locked || shell->lock_surface) {
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001082 wlsc_compositor_wake(shell->compositor);
1083 return;
1084 }
1085
1086 /* If desktop-shell client has gone away, unlock immediately. */
1087 if (!shell->child.desktop_shell) {
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001088 resume_desktop(shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001089 return;
1090 }
1091
1092 if (shell->prepare_event_sent)
1093 return;
1094
1095 wl_resource_post_event(shell->child.desktop_shell,
1096 DESKTOP_SHELL_PREPARE_LOCK_SURFACE);
1097 shell->prepare_event_sent = true;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001098}
1099
1100static void
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05001101map(struct wlsc_shell *base,
1102 struct wlsc_surface *surface, int32_t width, int32_t height)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001103{
Kristian Høgsberg75840622011-09-06 13:48:16 -04001104 struct wl_shell *shell = container_of(base, struct wl_shell, shell);
1105 struct wlsc_compositor *compositor = shell->compositor;
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001106 struct wl_list *list;
1107
1108 if (shell->locked)
1109 list = &shell->hidden_surface_list;
1110 else
1111 list = &compositor->surface_list;
Kristian Høgsberg75840622011-09-06 13:48:16 -04001112
Pekka Paalanend3dd6e12011-11-16 13:47:33 +02001113 /* surface stacking order, see also activate() */
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001114 if (surface == shell->background) {
Pekka Paalanend3dd6e12011-11-16 13:47:33 +02001115 /* background always visible, at the bottom */
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05001116 wl_list_insert(compositor->surface_list.prev, &surface->link);
Pekka Paalanend3dd6e12011-11-16 13:47:33 +02001117
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001118 } else if (surface == shell->panel) {
Pekka Paalanend3dd6e12011-11-16 13:47:33 +02001119 /* panel always on top, hidden while locked */
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001120 wl_list_insert(list, &surface->link);
Pekka Paalanend3dd6e12011-11-16 13:47:33 +02001121
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001122 } else if (surface == shell->lock_surface) {
Pekka Paalanend3dd6e12011-11-16 13:47:33 +02001123 /* lock surface always visible, on top */
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001124 wl_list_insert(&compositor->surface_list, &surface->link);
Pekka Paalanend3dd6e12011-11-16 13:47:33 +02001125
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001126 wlsc_compositor_repick(compositor);
1127 wlsc_compositor_wake(compositor);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001128 } else {
Pekka Paalanend3dd6e12011-11-16 13:47:33 +02001129 /* everything else just below the panel */
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001130 wl_list_insert(&shell->panel->link, &surface->link);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001131 }
1132
Kristian Høgsberg46770132011-11-09 12:38:53 -05001133 if (surface->map_type == WLSC_SURFACE_MAP_TOPLEVEL) {
1134 surface->x = 10 + random() % 400;
1135 surface->y = 10 + random() % 400;
1136 }
1137
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001138 surface->width = width;
1139 surface->height = height;
Pekka Paalanend3dd6e12011-11-16 13:47:33 +02001140 if (!shell->locked || surface == shell->lock_surface)
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001141 wlsc_surface_configure(surface,
1142 surface->x, surface->y, width, height);
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05001143}
1144
1145static void
1146configure(struct wlsc_shell *shell, struct wlsc_surface *surface,
1147 int32_t x, int32_t y, int32_t width, int32_t height)
1148{
1149 struct wlsc_mode *current;
1150
1151 if (surface->map_type == WLSC_SURFACE_MAP_FULLSCREEN) {
1152 current = surface->fullscreen_output->current;
1153 x = (current->width - surface->width) / 2;
1154 y = (current->height - surface->height) / 2;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001155 }
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05001156
1157 wlsc_surface_configure(surface, x, y, width, height);
Kristian Høgsberg07937562011-04-12 17:25:42 -04001158}
1159
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001160static void
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02001161desktop_shell_sigchld(struct wlsc_process *process, int status)
1162{
1163 struct wl_shell *shell =
1164 container_of(process, struct wl_shell, child.process);
1165
1166 shell->child.process.pid = 0;
1167 shell->child.client = NULL; /* already destroyed by wayland */
1168}
1169
1170static int
1171launch_desktop_shell_process(struct wl_shell *shell)
1172{
Kristian Høgsbergc4693c42011-11-14 14:57:17 -05001173 const char *shell_exe = LIBEXECDIR "/wayland-desktop-shell";
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02001174 struct wlsc_compositor *compositor = shell->compositor;
1175 char s[32];
1176 int sv[2], flags;
1177
1178 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) {
1179 fprintf(stderr, "socketpair failed\n");
1180 return -1;
1181 }
1182
1183 shell->child.process.pid = fork();
1184 shell->child.process.cleanup = desktop_shell_sigchld;
1185
1186 switch (shell->child.process.pid) {
1187 case 0:
1188 /* SOCK_CLOEXEC closes both ends, so we need to unset
1189 * the flag on the client fd. */
1190 flags = fcntl(sv[1], F_GETFD);
1191 if (flags != -1)
1192 fcntl(sv[1], F_SETFD, flags & ~FD_CLOEXEC);
1193
1194 snprintf(s, sizeof s, "%d", sv[1]);
1195 setenv("WAYLAND_SOCKET", s, 1);
1196 if (execl(shell_exe, shell_exe, NULL) < 0)
1197 fprintf(stderr, "%s: running '%s' failed: %m\n",
1198 __func__, shell_exe);
1199 exit(-1);
1200
1201 default:
1202 close(sv[1]);
1203 shell->child.client =
1204 wl_client_create(compositor->wl_display, sv[0]);
1205 wlsc_watch_process(&shell->child.process);
1206 break;
1207
1208 case -1:
1209 fprintf(stderr, "%s: fork failed: %m\n", __func__);
1210 return -1;
1211 }
1212 return 0;
1213}
1214
1215static void
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001216bind_shell(struct wl_client *client, void *data, uint32_t version, uint32_t id)
1217{
1218 struct wl_shell *shell = data;
1219
1220 wl_client_add_object(client, &wl_shell_interface,
1221 &shell_interface, id, shell);
1222}
1223
Kristian Høgsberg75840622011-09-06 13:48:16 -04001224static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001225unbind_desktop_shell(struct wl_resource *resource)
1226{
1227 struct wl_shell *shell = resource->data;
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001228
1229 if (shell->locked)
1230 resume_desktop(shell);
1231
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001232 shell->child.desktop_shell = NULL;
1233 shell->prepare_event_sent = false;
1234 free(resource);
1235}
1236
1237static void
Kristian Høgsberg75840622011-09-06 13:48:16 -04001238bind_desktop_shell(struct wl_client *client,
1239 void *data, uint32_t version, uint32_t id)
1240{
1241 struct wl_shell *shell = data;
Pekka Paalanenbbe60522011-11-03 14:11:33 +02001242 struct wl_resource *resource;
Kristian Høgsberg75840622011-09-06 13:48:16 -04001243
Pekka Paalanenbbe60522011-11-03 14:11:33 +02001244 resource = wl_client_add_object(client, &desktop_shell_interface,
1245 &desktop_shell_implementation,
1246 id, shell);
1247
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001248 if (client == shell->child.client) {
1249 resource->destroy = unbind_desktop_shell;
1250 shell->child.desktop_shell = resource;
Pekka Paalanenbbe60522011-11-03 14:11:33 +02001251 return;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001252 }
Pekka Paalanenbbe60522011-11-03 14:11:33 +02001253
1254 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
1255 "permission to bind desktop_shell denied");
1256 wl_resource_destroy(resource, 0);
Kristian Høgsberg75840622011-09-06 13:48:16 -04001257}
1258
Kristian Høgsberg6c709a32011-05-06 14:52:41 -04001259int
1260shell_init(struct wlsc_compositor *ec);
1261
Kristian Høgsberg1c562182011-05-02 22:09:20 -04001262WL_EXPORT int
1263shell_init(struct wlsc_compositor *ec)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001264{
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001265 struct wl_shell *shell;
1266
1267 shell = malloc(sizeof *shell);
1268 if (shell == NULL)
1269 return -1;
1270
Kristian Høgsbergf0d91162011-10-11 22:44:23 -04001271 memset(shell, 0, sizeof *shell);
Kristian Høgsberg75840622011-09-06 13:48:16 -04001272 shell->compositor = ec;
1273 shell->shell.activate = activate;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001274 shell->shell.lock = lock;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001275 shell->shell.unlock = unlock;
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05001276 shell->shell.map = map;
1277 shell->shell.configure = configure;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04001278 shell->shell.set_selection_focus = wlsc_selection_set_focus;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001279
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001280 wl_list_init(&shell->hidden_surface_list);
1281
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001282 if (wl_display_add_global(ec->wl_display, &wl_shell_interface,
1283 shell, bind_shell) == NULL)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001284 return -1;
1285
Kristian Høgsberg75840622011-09-06 13:48:16 -04001286 if (wl_display_add_global(ec->wl_display,
1287 &desktop_shell_interface,
1288 shell, bind_desktop_shell) == NULL)
1289 return -1;
1290
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02001291 if (launch_desktop_shell_process(shell) != 0)
1292 return -1;
1293
Kristian Høgsberg07937562011-04-12 17:25:42 -04001294 wlsc_compositor_add_binding(ec, 0, BTN_LEFT, MODIFIER_SUPER,
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001295 move_binding, shell);
Kristian Høgsberg07937562011-04-12 17:25:42 -04001296 wlsc_compositor_add_binding(ec, 0, BTN_MIDDLE, MODIFIER_SUPER,
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001297 resize_binding, shell);
1298
1299 ec->shell = &shell->shell;
Kristian Høgsberg07937562011-04-12 17:25:42 -04001300
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001301 return 0;
1302}