blob: f8305dbe17ab4f4975bcf2c05f7af4e230d98cc5 [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
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050061struct wlsc_move_grab {
62 struct wl_grab grab;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -050063 struct wlsc_surface *surface;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050064 int32_t dx, dy;
65};
66
67static void
68move_grab_motion(struct wl_grab *grab,
69 uint32_t time, int32_t x, int32_t y)
70{
71 struct wlsc_move_grab *move = (struct wlsc_move_grab *) grab;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -050072 struct wlsc_surface *es = move->surface;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050073
Kristian Høgsberga691aee2011-06-23 21:43:50 -040074 wlsc_surface_configure(es, x + move->dx, y + move->dy,
75 es->width, es->height);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050076}
77
78static void
79move_grab_button(struct wl_grab *grab,
80 uint32_t time, int32_t button, int32_t state)
81{
82}
83
84static void
85move_grab_end(struct wl_grab *grab, uint32_t time)
86{
87 free(grab);
88}
89
90static const struct wl_grab_interface move_grab_interface = {
91 move_grab_motion,
92 move_grab_button,
93 move_grab_end
94};
95
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -040096static int
97wlsc_surface_move(struct wlsc_surface *es,
98 struct wlsc_input_device *wd, uint32_t time)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050099{
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500100 struct wlsc_move_grab *move;
101
102 move = malloc(sizeof *move);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400103 if (!move)
104 return -1;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500105
106 move->grab.interface = &move_grab_interface;
107 move->dx = es->x - wd->input_device.grab_x;
108 move->dy = es->y - wd->input_device.grab_y;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -0500109 move->surface = es;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500110
111 if (wl_input_device_update_grab(&wd->input_device,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400112 &move->grab, &es->surface, time) < 0)
113 return 0;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500114
115 wlsc_input_device_set_pointer_image(wd, WLSC_POINTER_DRAGGING);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400116 wl_input_device_set_pointer_focus(&wd->input_device,
117 NULL, time, 0, 0, 0, 0);
118
119 return 0;
120}
121
122static void
123shell_move(struct wl_client *client, struct wl_resource *resource,
124 struct wl_resource *surface_resource,
125 struct wl_resource *input_resource, uint32_t time)
126{
127 struct wlsc_input_device *wd = input_resource->data;
128 struct wlsc_surface *es = surface_resource->data;
129
130 if (wlsc_surface_move(es, wd, time) < 0)
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400131 wl_resource_post_no_memory(resource);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500132}
133
134struct wlsc_resize_grab {
135 struct wl_grab grab;
136 uint32_t edges;
137 int32_t dx, dy, width, height;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -0500138 struct wlsc_surface *surface;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400139 struct wl_resource *resource;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500140};
141
142static void
143resize_grab_motion(struct wl_grab *grab,
144 uint32_t time, int32_t x, int32_t y)
145{
146 struct wlsc_resize_grab *resize = (struct wlsc_resize_grab *) grab;
147 struct wl_input_device *device = grab->input_device;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -0500148 struct wl_surface *surface = &resize->surface->surface;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500149 int32_t width, height;
150
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500151 if (resize->edges & WL_SHELL_RESIZE_LEFT) {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500152 width = device->grab_x - x + resize->width;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500153 } else if (resize->edges & WL_SHELL_RESIZE_RIGHT) {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500154 width = x - device->grab_x + resize->width;
155 } else {
156 width = resize->width;
157 }
158
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500159 if (resize->edges & WL_SHELL_RESIZE_TOP) {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500160 height = device->grab_y - y + resize->height;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500161 } else if (resize->edges & WL_SHELL_RESIZE_BOTTOM) {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500162 height = y - device->grab_y + resize->height;
163 } else {
164 height = resize->height;
165 }
166
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400167 wl_resource_post_event(resize->resource,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400168 WL_SHELL_CONFIGURE, time, resize->edges,
169 surface, width, height);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500170}
171
172static void
173resize_grab_button(struct wl_grab *grab,
174 uint32_t time, int32_t button, int32_t state)
175{
176}
177
178static void
179resize_grab_end(struct wl_grab *grab, uint32_t time)
180{
181 free(grab);
182}
183
184static const struct wl_grab_interface resize_grab_interface = {
185 resize_grab_motion,
186 resize_grab_button,
187 resize_grab_end
188};
189
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400190static int
191wlsc_surface_resize(struct wlsc_surface *es,
192 struct wlsc_input_device *wd,
193 uint32_t time, uint32_t edges,
194 struct wl_resource *resource)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500195{
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500196 struct wlsc_resize_grab *resize;
197 enum wlsc_pointer_type pointer = WLSC_POINTER_LEFT_PTR;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500198
Kristian Høgsberg0ce24572011-01-28 15:18:33 -0500199 /* FIXME: Reject if fullscreen */
200
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500201 resize = malloc(sizeof *resize);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400202 if (!resize)
203 return -1;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500204
205 resize->grab.interface = &resize_grab_interface;
206 resize->edges = edges;
207 resize->dx = es->x - wd->input_device.grab_x;
208 resize->dy = es->y - wd->input_device.grab_y;
209 resize->width = es->width;
210 resize->height = es->height;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -0500211 resize->surface = es;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400212 resize->resource = resource;
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400213
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500214 if (edges == 0 || edges > 15 ||
215 (edges & 3) == 3 || (edges & 12) == 12)
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400216 return 0;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500217
218 switch (edges) {
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500219 case WL_SHELL_RESIZE_TOP:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500220 pointer = WLSC_POINTER_TOP;
221 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500222 case WL_SHELL_RESIZE_BOTTOM:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500223 pointer = WLSC_POINTER_BOTTOM;
224 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500225 case WL_SHELL_RESIZE_LEFT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500226 pointer = WLSC_POINTER_LEFT;
227 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500228 case WL_SHELL_RESIZE_TOP_LEFT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500229 pointer = WLSC_POINTER_TOP_LEFT;
230 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500231 case WL_SHELL_RESIZE_BOTTOM_LEFT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500232 pointer = WLSC_POINTER_BOTTOM_LEFT;
233 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500234 case WL_SHELL_RESIZE_RIGHT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500235 pointer = WLSC_POINTER_RIGHT;
236 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500237 case WL_SHELL_RESIZE_TOP_RIGHT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500238 pointer = WLSC_POINTER_TOP_RIGHT;
239 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500240 case WL_SHELL_RESIZE_BOTTOM_RIGHT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500241 pointer = WLSC_POINTER_BOTTOM_RIGHT;
242 break;
243 }
244
245 if (wl_input_device_update_grab(&wd->input_device,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400246 &resize->grab, &es->surface, time) < 0)
247 return 0;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500248
249 wlsc_input_device_set_pointer_image(wd, pointer);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400250 wl_input_device_set_pointer_focus(&wd->input_device,
251 NULL, time, 0, 0, 0, 0);
252
253 return 0;
254}
255
256static void
257shell_resize(struct wl_client *client, struct wl_resource *resource,
258 struct wl_resource *surface_resource,
259 struct wl_resource *input_resource, uint32_t time, uint32_t edges)
260{
261 struct wlsc_input_device *wd = input_resource->data;
262 struct wlsc_surface *es = surface_resource->data;
263
264 /* FIXME: Reject if fullscreen */
265
266 if (wlsc_surface_resize(es, wd, time, edges, resource) < 0)
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400267 wl_resource_post_no_memory(resource);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500268}
269
270static void
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400271shell_set_toplevel(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400272 struct wl_resource *resource,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400273 struct wl_resource *surface_resource)
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400274
275{
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400276 struct wlsc_surface *es = surface_resource->data;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400277
278 if (es->map_type == WLSC_SURFACE_MAP_FULLSCREEN) {
279 es->x = es->saved_x;
280 es->y = es->saved_y;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400281 }
282
283 wlsc_surface_damage(es);
284 es->map_type = WLSC_SURFACE_MAP_TOPLEVEL;
285 es->fullscreen_output = NULL;
286}
287
288static void
289shell_set_transient(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400290 struct wl_resource *resource,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400291 struct wl_resource *surface_resource,
292 struct wl_resource *parent_resource,
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400293 int x, int y, uint32_t flags)
294{
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400295 struct wlsc_surface *es = surface_resource->data;
296 struct wlsc_surface *pes = parent_resource->data;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400297
298 /* assign to parents output */
299 es->output = pes->output;
300
301 es->x = pes->x + x;
302 es->y = pes->y + y;
303
304 wlsc_surface_damage(es);
305 es->map_type = WLSC_SURFACE_MAP_TRANSIENT;
306}
307
308static void
309shell_set_fullscreen(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400310 struct wl_resource *resource,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400311 struct wl_resource *surface_resource)
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400312
313{
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400314 struct wlsc_surface *es = surface_resource->data;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400315 struct wlsc_output *output;
316
317 /* FIXME: Fullscreen on first output */
318 /* FIXME: Handle output going away */
319 output = container_of(es->compositor->output_list.next,
320 struct wlsc_output, link);
321 es->output = output;
322
323 es->saved_x = es->x;
324 es->saved_y = es->y;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400325 es->x = (output->current->width - es->width) / 2;
326 es->y = (output->current->height - es->height) / 2;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400327 es->fullscreen_output = output;
328 wlsc_surface_damage(es);
329 es->map_type = WLSC_SURFACE_MAP_FULLSCREEN;
330}
331
332static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400333destroy_drag(struct wl_resource *resource)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500334{
335 struct wl_drag *drag =
336 container_of(resource, struct wl_drag, resource);
337
338 wl_list_remove(&drag->drag_focus_listener.link);
339 if (drag->grab.input_device)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400340 wl_input_device_end_grab(drag->grab.input_device,
341 wlsc_compositor_get_time());
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500342
343 free(drag);
344}
345
346
347static void
348wl_drag_set_pointer_focus(struct wl_drag *drag,
349 struct wl_surface *surface, uint32_t time,
350 int32_t x, int32_t y, int32_t sx, int32_t sy)
351{
352 char **p, **end;
353
354 if (drag->drag_focus == surface)
355 return;
356
357 if (drag->drag_focus &&
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400358 (!surface ||
359 drag->drag_focus->resource.client != surface->resource.client))
360 wl_resource_post_event(&drag->drag_offer.resource,
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500361 WL_DRAG_OFFER_POINTER_FOCUS,
362 time, NULL, 0, 0, 0, 0);
363
364 if (surface &&
365 (!drag->drag_focus ||
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400366 drag->drag_focus->resource.client != surface->resource.client)) {
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400367
368 drag->drag_offer.resource.client = surface->resource.client;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500369 end = drag->types.data + drag->types.size;
370 for (p = drag->types.data; p < end; p++)
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400371 wl_resource_post_event(&drag->drag_offer.resource,
372 WL_DRAG_OFFER_OFFER, *p);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500373 }
374
375 if (surface) {
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400376 wl_resource_post_event(&drag->drag_offer.resource,
377 WL_DRAG_OFFER_POINTER_FOCUS,
378 time, surface,
379 x, y, sx, sy);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500380
381 }
382
383 drag->drag_focus = surface;
384 drag->pointer_focus_time = time;
385 drag->target = NULL;
386
387 wl_list_remove(&drag->drag_focus_listener.link);
388 if (surface)
Benjamin Franzke4721a3c2011-05-06 17:13:17 +0200389 wl_list_insert(surface->resource.destroy_listener_list.prev,
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500390 &drag->drag_focus_listener.link);
391}
392
393static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400394drag_offer_accept(struct wl_client *client, struct wl_resource *resource,
395 uint32_t time, const char *type)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500396{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400397 struct wl_drag_offer *offer = resource->data;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500398 struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer);
399 char **p, **end;
400
401 /* If the client responds to drag pointer_focus or motion
402 * events after the pointer has left the surface, we just
403 * discard the accept requests. The drag source just won't
404 * get the corresponding 'target' events and eventually the
405 * next surface/root will start sending events. */
406 if (time < drag->pointer_focus_time)
407 return;
408
409 drag->target = client;
410 drag->type = NULL;
411 end = drag->types.data + drag->types.size;
412 for (p = drag->types.data; p < end; p++)
413 if (type && strcmp(*p, type) == 0)
414 drag->type = *p;
415
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400416 wl_resource_post_event(&drag->resource, WL_DRAG_TARGET, drag->type);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500417}
418
419static void
420drag_offer_receive(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400421 struct wl_resource *resource, int fd)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500422{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400423 struct wl_drag_offer *offer = resource->data;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500424 struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer);
425
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400426 wl_resource_post_event(&drag->resource, WL_DRAG_FINISH, fd);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500427 close(fd);
428}
429
430static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400431drag_offer_reject(struct wl_client *client, struct wl_resource *resource)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500432{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400433 struct wl_drag_offer *offer = resource->data;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500434 struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer);
435
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400436 wl_resource_post_event(&drag->resource, WL_DRAG_REJECT);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500437}
438
439static const struct wl_drag_offer_interface drag_offer_interface = {
440 drag_offer_accept,
441 drag_offer_receive,
442 drag_offer_reject
443};
444
445static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400446drag_offer(struct wl_client *client,
447 struct wl_resource *resource, const char *type)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500448{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400449 struct wl_drag *drag = resource->data;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500450 char **p;
451
452 p = wl_array_add(&drag->types, sizeof *p);
453 if (p)
454 *p = strdup(type);
455 if (!p || !*p)
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400456 wl_resource_post_no_memory(resource);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500457}
458
459static void
460drag_grab_motion(struct wl_grab *grab,
461 uint32_t time, int32_t x, int32_t y)
462{
463 struct wl_drag *drag = container_of(grab, struct wl_drag, grab);
464 struct wlsc_surface *es;
465 int32_t sx, sy;
466
467 es = pick_surface(grab->input_device, &sx, &sy);
468 wl_drag_set_pointer_focus(drag, &es->surface, time, x, y, sx, sy);
469 if (es)
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400470 wl_resource_post_event(&drag->drag_offer.resource,
471 WL_DRAG_OFFER_MOTION,
472 time, x, y, sx, sy);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500473}
474
475static void
476drag_grab_button(struct wl_grab *grab,
477 uint32_t time, int32_t button, int32_t state)
478{
479}
480
481static void
482drag_grab_end(struct wl_grab *grab, uint32_t time)
483{
484 struct wl_drag *drag = container_of(grab, struct wl_drag, grab);
485
486 if (drag->target)
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400487 wl_resource_post_event(&drag->drag_offer.resource,
488 WL_DRAG_OFFER_DROP);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500489
490 wl_drag_set_pointer_focus(drag, NULL, time, 0, 0, 0, 0);
491}
492
493static const struct wl_grab_interface drag_grab_interface = {
494 drag_grab_motion,
495 drag_grab_button,
496 drag_grab_end
497};
498
499static void
500drag_activate(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400501 struct wl_resource *resource,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400502 struct wl_resource *surface_resource,
503 struct wl_resource *device_resource, uint32_t time)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500504{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400505 struct wl_drag *drag = resource->data;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400506 struct wl_surface *surface = surface_resource->data;
507 struct wl_input_device *device = device_resource->data;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500508 struct wl_display *display = wl_client_get_display (client);
509 struct wlsc_surface *target;
510 int32_t sx, sy;
511
512 if (wl_input_device_update_grab(device,
513 &drag->grab, surface, time) < 0)
514 return;
515
516 drag->grab.interface = &drag_grab_interface;
517
518 drag->source = surface;
519
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400520 drag->drag_offer.resource.object.interface = &wl_drag_offer_interface;
521 drag->drag_offer.resource.object.implementation =
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500522 (void (**)(void)) &drag_offer_interface;
523
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400524 wl_display_add_global(display, &wl_drag_offer_interface, drag, NULL);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500525
526 target = pick_surface(device, &sx, &sy);
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -0500527 wl_input_device_set_pointer_focus(device, NULL, time, 0, 0, 0, 0);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500528 wl_drag_set_pointer_focus(drag, &target->surface, time,
529 device->x, device->y, sx, sy);
530}
531
532static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400533drag_destroy(struct wl_client *client, struct wl_resource *resource)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500534{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400535 wl_resource_destroy(resource, wlsc_compositor_get_time());
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500536}
537
538static const struct wl_drag_interface drag_interface = {
539 drag_offer,
540 drag_activate,
541 drag_destroy,
542};
543
544static void
545drag_handle_surface_destroy(struct wl_listener *listener,
Benjamin Franzke4721a3c2011-05-06 17:13:17 +0200546 struct wl_resource *resource, uint32_t time)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500547{
548 struct wl_drag *drag =
549 container_of(listener, struct wl_drag, drag_focus_listener);
Benjamin Franzke4721a3c2011-05-06 17:13:17 +0200550 struct wl_surface *surface = (struct wl_surface *) resource;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500551
552 if (drag->drag_focus == surface)
553 wl_drag_set_pointer_focus(drag, NULL, time, 0, 0, 0, 0);
554}
555
556static void
557shell_create_drag(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400558 struct wl_resource *resource, uint32_t id)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500559{
560 struct wl_drag *drag;
561
562 drag = malloc(sizeof *drag);
563 if (drag == NULL) {
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400564 wl_resource_post_no_memory(resource);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500565 return;
566 }
567
568 memset(drag, 0, sizeof *drag);
569 drag->resource.object.id = id;
570 drag->resource.object.interface = &wl_drag_interface;
571 drag->resource.object.implementation =
572 (void (**)(void)) &drag_interface;
573
Pekka Paalanen02ebfb12011-10-24 17:34:53 +0300574 drag->resource.data = drag;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500575 drag->resource.destroy = destroy_drag;
576
577 drag->drag_focus_listener.func = drag_handle_surface_destroy;
578 wl_list_init(&drag->drag_focus_listener.link);
579
580 wl_client_add_resource(client, &drag->resource);
581}
582
Kristian Høgsberg1c562182011-05-02 22:09:20 -0400583static void
584wlsc_selection_set_focus(struct wlsc_shell *shell,
585 struct wl_selection *selection,
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500586 struct wl_surface *surface, uint32_t time)
587{
588 char **p, **end;
589
590 if (selection->selection_focus == surface)
591 return;
592
593 if (selection->selection_focus != NULL)
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400594 wl_resource_post_event(&selection->selection_offer.resource,
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500595 WL_SELECTION_OFFER_KEYBOARD_FOCUS,
596 NULL);
597
598 if (surface) {
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500599
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400600 selection->selection_offer.resource.client = surface->resource.client;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500601 end = selection->types.data + selection->types.size;
602 for (p = selection->types.data; p < end; p++)
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400603 wl_resource_post_event(&selection->selection_offer.resource,
604 WL_SELECTION_OFFER_OFFER, *p);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500605
606 wl_list_remove(&selection->selection_focus_listener.link);
Benjamin Franzke4721a3c2011-05-06 17:13:17 +0200607 wl_list_insert(surface->resource.destroy_listener_list.prev,
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500608 &selection->selection_focus_listener.link);
609
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400610 wl_resource_post_event(&selection->selection_offer.resource,
611 WL_SELECTION_OFFER_KEYBOARD_FOCUS,
612 selection->input_device);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500613 }
614
615 selection->selection_focus = surface;
616
617 wl_list_remove(&selection->selection_focus_listener.link);
618 if (surface)
Benjamin Franzke4721a3c2011-05-06 17:13:17 +0200619 wl_list_insert(surface->resource.destroy_listener_list.prev,
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500620 &selection->selection_focus_listener.link);
621}
622
623static void
624selection_offer_receive(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400625 struct wl_resource *resource,
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500626 const char *mime_type, int fd)
627{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400628 struct wl_selection_offer *offer = resource->data;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500629 struct wl_selection *selection =
630 container_of(offer, struct wl_selection, selection_offer);
631
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400632 wl_resource_post_event(&selection->resource,
633 WL_SELECTION_SEND, mime_type, fd);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500634 close(fd);
635}
636
637static const struct wl_selection_offer_interface selection_offer_interface = {
638 selection_offer_receive
639};
640
641static void
642selection_offer(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400643 struct wl_resource *resource, const char *type)
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500644{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400645 struct wl_selection *selection = resource->data;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500646 char **p;
647
648 p = wl_array_add(&selection->types, sizeof *p);
649 if (p)
650 *p = strdup(type);
651 if (!p || !*p)
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400652 wl_resource_post_no_memory(resource);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500653}
654
655static void
656selection_activate(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400657 struct wl_resource *resource,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400658 struct wl_resource *input_resource, uint32_t time)
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500659{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400660 struct wl_selection *selection = resource->data;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400661 struct wlsc_input_device *wd = input_resource->data;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500662 struct wl_display *display = wl_client_get_display (client);
Kristian Høgsberg1c562182011-05-02 22:09:20 -0400663 struct wlsc_compositor *compositor =
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400664 (struct wlsc_compositor *) wd->input_device.compositor;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500665
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400666 selection->input_device = &wd->input_device;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500667
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400668 selection->selection_offer.resource.object.interface =
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500669 &wl_selection_offer_interface;
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400670 selection->selection_offer.resource.object.implementation =
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500671 (void (**)(void)) &selection_offer_interface;
672
Kristian Høgsbergd9551a32011-08-19 12:07:44 -0400673 wl_display_add_global(display,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400674 &wl_selection_offer_interface, selection, NULL);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500675
676 if (wd->selection) {
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400677 wl_resource_post_event(&wd->selection->resource,
678 WL_SELECTION_CANCELLED);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500679 }
680 wd->selection = selection;
681
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400682 wlsc_selection_set_focus(compositor->shell, selection,
683 wd->input_device.keyboard_focus, time);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500684}
685
686static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400687selection_destroy(struct wl_client *client, struct wl_resource *resource)
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500688{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400689 wl_resource_destroy(resource, wlsc_compositor_get_time());
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500690}
691
692static const struct wl_selection_interface selection_interface = {
693 selection_offer,
694 selection_activate,
695 selection_destroy
696};
697
698static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400699destroy_selection(struct wl_resource *resource)
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500700{
701 struct wl_selection *selection =
702 container_of(resource, struct wl_selection, resource);
703 struct wlsc_input_device *wd =
704 (struct wlsc_input_device *) selection->input_device;
Kristian Høgsberg1c562182011-05-02 22:09:20 -0400705 struct wlsc_compositor *compositor =
706 (struct wlsc_compositor *) wd->input_device.compositor;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500707
708 if (wd && wd->selection == selection) {
709 wd->selection = NULL;
Kristian Høgsberg1c562182011-05-02 22:09:20 -0400710 wlsc_selection_set_focus(compositor->shell,
711 selection, NULL,
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400712 wlsc_compositor_get_time());
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500713 }
714
715 wl_list_remove(&selection->selection_focus_listener.link);
716 free(selection);
717}
718
719static void
720selection_handle_surface_destroy(struct wl_listener *listener,
Benjamin Franzke4721a3c2011-05-06 17:13:17 +0200721 struct wl_resource *resource, uint32_t time)
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500722{
723}
724
725static void
726shell_create_selection(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400727 struct wl_resource *resource, uint32_t id)
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500728{
729 struct wl_selection *selection;
730
731 selection = malloc(sizeof *selection);
732 if (selection == NULL) {
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400733 wl_resource_post_no_memory(resource);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500734 return;
735 }
736
737 memset(selection, 0, sizeof *selection);
738 selection->resource.object.id = id;
739 selection->resource.object.interface = &wl_selection_interface;
740 selection->resource.object.implementation =
741 (void (**)(void)) &selection_interface;
742
743 selection->client = client;
744 selection->resource.destroy = destroy_selection;
745 selection->selection_focus = NULL;
746
747 selection->selection_focus_listener.func =
748 selection_handle_surface_destroy;
749 wl_list_init(&selection->selection_focus_listener.link);
750
751 wl_client_add_resource(client, &selection->resource);
752}
753
Kristian Høgsberg75840622011-09-06 13:48:16 -0400754static const struct wl_shell_interface shell_interface = {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500755 shell_move,
756 shell_resize,
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500757 shell_create_drag,
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400758 shell_create_selection,
759 shell_set_toplevel,
760 shell_set_transient,
761 shell_set_fullscreen
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500762};
763
Kristian Høgsberg07937562011-04-12 17:25:42 -0400764static void
Kristian Høgsberg75840622011-09-06 13:48:16 -0400765handle_background_surface_destroy(struct wl_listener *listener,
766 struct wl_resource *resource, uint32_t time)
767{
768 struct wl_shell *shell =
769 container_of(listener, struct wl_shell, background_listener);
770
771 fprintf(stderr, "background surface gone\n");
772 shell->background = NULL;
773}
774
775static void
776desktop_shell_set_background(struct wl_client *client,
777 struct wl_resource *resource,
778 struct wl_resource *surface_resource)
779{
780 struct wl_shell *shell = resource->data;
781 struct wlsc_surface *surface = surface_resource->data;
782 struct wlsc_output *output =
783 container_of(shell->compositor->output_list.next,
784 struct wlsc_output, link);
785
786 shell->background = surface_resource->data;
787 shell->background_listener.func = handle_background_surface_destroy;
788 wl_list_insert(&surface_resource->destroy_listener_list,
789 &shell->background_listener.link);
790
791 wl_resource_post_event(resource,
792 DESKTOP_SHELL_CONFIGURE,
793 wlsc_compositor_get_time(), 0, surface,
794 output->current->width,
795 output->current->height);
796}
797
798static void
799handle_panel_surface_destroy(struct wl_listener *listener,
800 struct wl_resource *resource, uint32_t time)
801{
802 struct wl_shell *shell =
803 container_of(listener, struct wl_shell, panel_listener);
804
805 fprintf(stderr, "panel surface gone\n");
806 shell->panel = NULL;
807}
808
809static void
810desktop_shell_set_panel(struct wl_client *client,
811 struct wl_resource *resource,
812 struct wl_resource *surface_resource)
813{
814 struct wl_shell *shell = resource->data;
815 struct wlsc_output *output =
816 container_of(shell->compositor->output_list.next,
817 struct wlsc_output, link);
818
819 shell->panel = surface_resource->data;
820
821 shell->panel_listener.func = handle_panel_surface_destroy;
822 wl_list_insert(&surface_resource->destroy_listener_list,
823 &shell->panel_listener.link);
824
825 wl_resource_post_event(resource,
826 DESKTOP_SHELL_CONFIGURE,
827 wlsc_compositor_get_time(), 0, surface_resource,
828 output->current->width,
829 output->current->height);
830}
831
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200832static void
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500833handle_lock_surface_destroy(struct wl_listener *listener,
834 struct wl_resource *resource, uint32_t time)
835{
836 struct wl_shell *shell =
Pekka Paalanen2ca86302011-11-16 13:47:35 +0200837 container_of(listener, struct wl_shell, lock_surface_listener);
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500838
839 fprintf(stderr, "lock surface gone\n");
840 shell->lock_surface = NULL;
841}
842
843static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200844desktop_shell_set_lock_surface(struct wl_client *client,
845 struct wl_resource *resource,
846 struct wl_resource *surface_resource)
847{
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +0200848 struct wl_shell *shell = resource->data;
849
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200850 shell->prepare_event_sent = false;
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +0200851
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200852 if (!shell->locked)
853 return;
854
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500855 shell->lock_surface = surface_resource->data;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200856
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500857 shell->lock_surface_listener.func = handle_lock_surface_destroy;
858 wl_list_insert(&surface_resource->destroy_listener_list,
859 &shell->lock_surface_listener.link);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200860}
861
862static void
863resume_desktop(struct wl_shell *shell)
864{
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500865 struct wlsc_surface *surface;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200866
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500867 wl_list_for_each(surface, &shell->hidden_surface_list, link)
868 wlsc_surface_configure(surface, surface->x, surface->y,
869 surface->width, surface->height);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200870
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500871 wl_list_insert_list(shell->background->link.prev,
872 &shell->hidden_surface_list);
873 wl_list_init(&shell->hidden_surface_list);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200874
875 shell->locked = false;
876 wlsc_compositor_repick(shell->compositor);
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +0200877 wlsc_compositor_wake(shell->compositor);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200878}
879
880static void
881desktop_shell_unlock(struct wl_client *client,
882 struct wl_resource *resource)
883{
884 struct wl_shell *shell = resource->data;
885
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200886 shell->prepare_event_sent = false;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200887
888 if (shell->locked)
889 resume_desktop(shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200890}
891
Kristian Høgsberg75840622011-09-06 13:48:16 -0400892static const struct desktop_shell_interface desktop_shell_implementation = {
893 desktop_shell_set_background,
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200894 desktop_shell_set_panel,
895 desktop_shell_set_lock_surface,
896 desktop_shell_unlock
Kristian Høgsberg75840622011-09-06 13:48:16 -0400897};
898
899static void
Kristian Høgsberg07937562011-04-12 17:25:42 -0400900move_binding(struct wl_input_device *device, uint32_t time,
901 uint32_t key, uint32_t button, uint32_t state, void *data)
902{
Kristian Høgsberg75840622011-09-06 13:48:16 -0400903 struct wl_shell *shell = data;
Kristian Høgsberg07937562011-04-12 17:25:42 -0400904 struct wlsc_surface *surface =
905 (struct wlsc_surface *) device->pointer_focus;
906
Kristian Høgsberga4a42f02011-09-08 16:56:57 -0400907 if (surface == NULL ||
908 surface->map_type == WLSC_SURFACE_MAP_FULLSCREEN)
Kristian Høgsberg10f097e2011-04-13 11:52:54 -0400909 return;
Kristian Høgsberg75840622011-09-06 13:48:16 -0400910 if (surface == shell->panel)
911 return;
912 if (surface == shell->background)
913 return;
Kristian Høgsberg10f097e2011-04-13 11:52:54 -0400914
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400915 wlsc_surface_move(surface, (struct wlsc_input_device *) device, time);
Kristian Høgsberg07937562011-04-12 17:25:42 -0400916}
917
918static void
919resize_binding(struct wl_input_device *device, uint32_t time,
920 uint32_t key, uint32_t button, uint32_t state, void *data)
921{
Kristian Høgsberg75840622011-09-06 13:48:16 -0400922 struct wl_shell *shell = data;
Kristian Høgsberg07937562011-04-12 17:25:42 -0400923 struct wlsc_surface *surface =
924 (struct wlsc_surface *) device->pointer_focus;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400925 struct wl_resource *resource;
Kristian Høgsberg07937562011-04-12 17:25:42 -0400926 uint32_t edges = 0;
927 int32_t x, y;
928
Kristian Høgsberga4a42f02011-09-08 16:56:57 -0400929 if (surface == NULL ||
930 surface->map_type == WLSC_SURFACE_MAP_FULLSCREEN)
Kristian Høgsberg75840622011-09-06 13:48:16 -0400931 if (surface == shell->panel)
932 return;
933 if (surface == shell->background)
934 return;
Kristian Høgsberg10f097e2011-04-13 11:52:54 -0400935
Kristian Høgsberg07937562011-04-12 17:25:42 -0400936 x = device->grab_x - surface->x;
937 y = device->grab_y - surface->y;
938
939 if (x < surface->width / 3)
940 edges |= WL_SHELL_RESIZE_LEFT;
941 else if (x < 2 * surface->width / 3)
942 edges |= 0;
943 else
944 edges |= WL_SHELL_RESIZE_RIGHT;
945
946 if (y < surface->height / 3)
947 edges |= WL_SHELL_RESIZE_TOP;
948 else if (y < 2 * surface->height / 3)
949 edges |= 0;
950 else
951 edges |= WL_SHELL_RESIZE_BOTTOM;
952
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400953 resource = /* Find shell resource for surface client */ 0;
954
955 /* ... or use wl_shell_surface */
956
957 wlsc_surface_resize(surface, (struct wlsc_input_device *) device,
958 time, edges, resource);
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400959}
960
961static void
Kristian Høgsberg75840622011-09-06 13:48:16 -0400962activate(struct wlsc_shell *base, struct wlsc_surface *es,
963 struct wlsc_input_device *device, uint32_t time)
964{
965 struct wl_shell *shell = container_of(base, struct wl_shell, shell);
966 struct wlsc_compositor *compositor = shell->compositor;
967
968 wlsc_surface_activate(es, device, time);
969
Kristian Høgsbergd6e55252011-10-11 23:41:17 -0400970 if (compositor->wxs)
971 wlsc_xserver_surface_activate(es);
972
Kristian Høgsberg75840622011-09-06 13:48:16 -0400973 if (es == shell->background) {
974 wl_list_remove(&es->link);
975 wl_list_insert(compositor->surface_list.prev, &es->link);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200976 } else if (shell->panel && !shell->locked) {
Kristian Høgsberg75840622011-09-06 13:48:16 -0400977 wl_list_remove(&shell->panel->link);
978 wl_list_insert(&compositor->surface_list, &shell->panel->link);
979 }
980}
981
982static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200983lock(struct wlsc_shell *base)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400984{
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200985 struct wl_shell *shell = container_of(base, struct wl_shell, shell);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200986 struct wl_list *surface_list = &shell->compositor->surface_list;
987 struct wlsc_surface *cur;
988 struct wlsc_surface *tmp;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200989 struct wlsc_input_device *device;
990 uint32_t time;
991
992 if (shell->locked)
993 return;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200994
995 shell->locked = true;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200996
997 /* Move all surfaces from compositor's list to our hidden list,
998 * except the background. This way nothing else can show or
999 * receive input events while we are locked. */
1000
1001 if (!wl_list_empty(&shell->hidden_surface_list)) {
1002 fprintf(stderr,
1003 "%s: Assertion failed: hidden_surface_list is not empty.\n",
1004 __func__);
1005 }
1006
1007 wl_list_for_each_safe(cur, tmp, surface_list, link) {
1008 /* skip input device sprites, cur->surface is uninitialised */
1009 if (cur->surface.resource.client == NULL)
1010 continue;
1011
1012 if (cur == shell->background)
1013 continue;
1014
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001015 cur->output = NULL;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001016 wl_list_remove(&cur->link);
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001017 wl_list_insert(shell->hidden_surface_list.prev, &cur->link);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001018 }
1019
1020 /* reset pointer foci */
1021 wlsc_compositor_repick(shell->compositor);
1022
1023 /* reset keyboard foci */
1024 time = wlsc_compositor_get_time();
1025 wl_list_for_each(device, &shell->compositor->input_device_list, link) {
1026 wl_input_device_set_keyboard_focus(&device->input_device,
1027 NULL, time);
1028 }
1029
1030 /* TODO: disable bindings that should not work while locked. */
1031
1032 /* All this must be undone in resume_desktop(). */
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001033}
1034
1035static void
1036unlock(struct wlsc_shell *base)
1037{
1038 struct wl_shell *shell = container_of(base, struct wl_shell, shell);
1039
Pekka Paalanend81c2162011-11-16 13:47:34 +02001040 if (!shell->locked || shell->lock_surface) {
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001041 wlsc_compositor_wake(shell->compositor);
1042 return;
1043 }
1044
1045 /* If desktop-shell client has gone away, unlock immediately. */
1046 if (!shell->child.desktop_shell) {
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001047 resume_desktop(shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001048 return;
1049 }
1050
1051 if (shell->prepare_event_sent)
1052 return;
1053
1054 wl_resource_post_event(shell->child.desktop_shell,
1055 DESKTOP_SHELL_PREPARE_LOCK_SURFACE);
1056 shell->prepare_event_sent = true;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001057}
1058
1059static void
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05001060map(struct wlsc_shell *base,
1061 struct wlsc_surface *surface, int32_t width, int32_t height)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001062{
Kristian Høgsberg75840622011-09-06 13:48:16 -04001063 struct wl_shell *shell = container_of(base, struct wl_shell, shell);
1064 struct wlsc_compositor *compositor = shell->compositor;
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001065 struct wl_list *list;
1066
1067 if (shell->locked)
1068 list = &shell->hidden_surface_list;
1069 else
1070 list = &compositor->surface_list;
Kristian Høgsberg75840622011-09-06 13:48:16 -04001071
Pekka Paalanend3dd6e12011-11-16 13:47:33 +02001072 /* surface stacking order, see also activate() */
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001073 if (surface == shell->background) {
Pekka Paalanend3dd6e12011-11-16 13:47:33 +02001074 /* background always visible, at the bottom */
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05001075 wl_list_insert(compositor->surface_list.prev, &surface->link);
Pekka Paalanend3dd6e12011-11-16 13:47:33 +02001076
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001077 } else if (surface == shell->panel) {
Pekka Paalanend3dd6e12011-11-16 13:47:33 +02001078 /* panel always on top, hidden while locked */
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001079 wl_list_insert(list, &surface->link);
Pekka Paalanend3dd6e12011-11-16 13:47:33 +02001080
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001081 } else if (surface == shell->lock_surface) {
Pekka Paalanend3dd6e12011-11-16 13:47:33 +02001082 /* lock surface always visible, on top */
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001083 wl_list_insert(&compositor->surface_list, &surface->link);
Pekka Paalanend3dd6e12011-11-16 13:47:33 +02001084
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001085 wlsc_compositor_repick(compositor);
1086 wlsc_compositor_wake(compositor);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001087 } else {
Pekka Paalanend3dd6e12011-11-16 13:47:33 +02001088 /* everything else just below the panel */
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001089 wl_list_insert(&shell->panel->link, &surface->link);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001090 }
1091
Kristian Høgsberg46770132011-11-09 12:38:53 -05001092 if (surface->map_type == WLSC_SURFACE_MAP_TOPLEVEL) {
1093 surface->x = 10 + random() % 400;
1094 surface->y = 10 + random() % 400;
1095 }
1096
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001097 surface->width = width;
1098 surface->height = height;
Pekka Paalanend3dd6e12011-11-16 13:47:33 +02001099 if (!shell->locked || surface == shell->lock_surface)
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001100 wlsc_surface_configure(surface,
1101 surface->x, surface->y, width, height);
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05001102}
1103
1104static void
1105configure(struct wlsc_shell *shell, struct wlsc_surface *surface,
1106 int32_t x, int32_t y, int32_t width, int32_t height)
1107{
1108 struct wlsc_mode *current;
1109
1110 if (surface->map_type == WLSC_SURFACE_MAP_FULLSCREEN) {
1111 current = surface->fullscreen_output->current;
1112 x = (current->width - surface->width) / 2;
1113 y = (current->height - surface->height) / 2;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001114 }
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05001115
1116 wlsc_surface_configure(surface, x, y, width, height);
Kristian Høgsberg07937562011-04-12 17:25:42 -04001117}
1118
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001119static void
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02001120desktop_shell_sigchld(struct wlsc_process *process, int status)
1121{
1122 struct wl_shell *shell =
1123 container_of(process, struct wl_shell, child.process);
1124
1125 shell->child.process.pid = 0;
1126 shell->child.client = NULL; /* already destroyed by wayland */
1127}
1128
1129static int
1130launch_desktop_shell_process(struct wl_shell *shell)
1131{
Kristian Høgsbergc4693c42011-11-14 14:57:17 -05001132 const char *shell_exe = LIBEXECDIR "/wayland-desktop-shell";
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02001133 struct wlsc_compositor *compositor = shell->compositor;
1134 char s[32];
1135 int sv[2], flags;
1136
1137 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) {
1138 fprintf(stderr, "socketpair failed\n");
1139 return -1;
1140 }
1141
1142 shell->child.process.pid = fork();
1143 shell->child.process.cleanup = desktop_shell_sigchld;
1144
1145 switch (shell->child.process.pid) {
1146 case 0:
1147 /* SOCK_CLOEXEC closes both ends, so we need to unset
1148 * the flag on the client fd. */
1149 flags = fcntl(sv[1], F_GETFD);
1150 if (flags != -1)
1151 fcntl(sv[1], F_SETFD, flags & ~FD_CLOEXEC);
1152
1153 snprintf(s, sizeof s, "%d", sv[1]);
1154 setenv("WAYLAND_SOCKET", s, 1);
1155 if (execl(shell_exe, shell_exe, NULL) < 0)
1156 fprintf(stderr, "%s: running '%s' failed: %m\n",
1157 __func__, shell_exe);
1158 exit(-1);
1159
1160 default:
1161 close(sv[1]);
1162 shell->child.client =
1163 wl_client_create(compositor->wl_display, sv[0]);
1164 wlsc_watch_process(&shell->child.process);
1165 break;
1166
1167 case -1:
1168 fprintf(stderr, "%s: fork failed: %m\n", __func__);
1169 return -1;
1170 }
1171 return 0;
1172}
1173
1174static void
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001175bind_shell(struct wl_client *client, void *data, uint32_t version, uint32_t id)
1176{
1177 struct wl_shell *shell = data;
1178
1179 wl_client_add_object(client, &wl_shell_interface,
1180 &shell_interface, id, shell);
1181}
1182
Kristian Høgsberg75840622011-09-06 13:48:16 -04001183static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001184unbind_desktop_shell(struct wl_resource *resource)
1185{
1186 struct wl_shell *shell = resource->data;
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001187
1188 if (shell->locked)
1189 resume_desktop(shell);
1190
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001191 shell->child.desktop_shell = NULL;
1192 shell->prepare_event_sent = false;
1193 free(resource);
1194}
1195
1196static void
Kristian Høgsberg75840622011-09-06 13:48:16 -04001197bind_desktop_shell(struct wl_client *client,
1198 void *data, uint32_t version, uint32_t id)
1199{
1200 struct wl_shell *shell = data;
Pekka Paalanenbbe60522011-11-03 14:11:33 +02001201 struct wl_resource *resource;
Kristian Høgsberg75840622011-09-06 13:48:16 -04001202
Pekka Paalanenbbe60522011-11-03 14:11:33 +02001203 resource = wl_client_add_object(client, &desktop_shell_interface,
1204 &desktop_shell_implementation,
1205 id, shell);
1206
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001207 if (client == shell->child.client) {
1208 resource->destroy = unbind_desktop_shell;
1209 shell->child.desktop_shell = resource;
Pekka Paalanenbbe60522011-11-03 14:11:33 +02001210 return;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001211 }
Pekka Paalanenbbe60522011-11-03 14:11:33 +02001212
1213 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
1214 "permission to bind desktop_shell denied");
1215 wl_resource_destroy(resource, 0);
Kristian Høgsberg75840622011-09-06 13:48:16 -04001216}
1217
Kristian Høgsberg6c709a32011-05-06 14:52:41 -04001218int
1219shell_init(struct wlsc_compositor *ec);
1220
Kristian Høgsberg1c562182011-05-02 22:09:20 -04001221WL_EXPORT int
1222shell_init(struct wlsc_compositor *ec)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001223{
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001224 struct wl_shell *shell;
1225
1226 shell = malloc(sizeof *shell);
1227 if (shell == NULL)
1228 return -1;
1229
Kristian Høgsbergf0d91162011-10-11 22:44:23 -04001230 memset(shell, 0, sizeof *shell);
Kristian Høgsberg75840622011-09-06 13:48:16 -04001231 shell->compositor = ec;
1232 shell->shell.activate = activate;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001233 shell->shell.lock = lock;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001234 shell->shell.unlock = unlock;
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05001235 shell->shell.map = map;
1236 shell->shell.configure = configure;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04001237 shell->shell.set_selection_focus = wlsc_selection_set_focus;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001238
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001239 wl_list_init(&shell->hidden_surface_list);
1240
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001241 if (wl_display_add_global(ec->wl_display, &wl_shell_interface,
1242 shell, bind_shell) == NULL)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001243 return -1;
1244
Kristian Høgsberg75840622011-09-06 13:48:16 -04001245 if (wl_display_add_global(ec->wl_display,
1246 &desktop_shell_interface,
1247 shell, bind_desktop_shell) == NULL)
1248 return -1;
1249
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02001250 if (launch_desktop_shell_process(shell) != 0)
1251 return -1;
1252
Kristian Høgsberg07937562011-04-12 17:25:42 -04001253 wlsc_compositor_add_binding(ec, 0, BTN_LEFT, MODIFIER_SUPER,
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001254 move_binding, shell);
Kristian Høgsberg07937562011-04-12 17:25:42 -04001255 wlsc_compositor_add_binding(ec, 0, BTN_MIDDLE, MODIFIER_SUPER,
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001256 resize_binding, shell);
1257
1258 ec->shell = &shell->shell;
Kristian Høgsberg07937562011-04-12 17:25:42 -04001259
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001260 return 0;
1261}