blob: c25ada21f2a86ea62350dc442aed3191a859b995 [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>
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050033
34#include "wayland-server.h"
35#include "compositor.h"
Kristian Høgsberg75840622011-09-06 13:48:16 -040036#include "desktop-shell-server-protocol.h"
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050037
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -040038struct wl_shell {
Kristian Høgsberg75840622011-09-06 13:48:16 -040039 struct wlsc_compositor *compositor;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -040040 struct wlsc_shell shell;
Kristian Høgsberg75840622011-09-06 13:48:16 -040041 struct wlsc_surface *panel;
42 struct wl_listener panel_listener;
43 struct wlsc_surface *background;
44 struct wl_listener background_listener;
Pekka Paalanen6cd281a2011-11-03 14:11:32 +020045
46 struct {
47 struct wlsc_process process;
48 struct wl_client *client;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +020049 struct wl_resource *desktop_shell;
Pekka Paalanen6cd281a2011-11-03 14:11:32 +020050 } child;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +020051
52 bool locked;
53 bool prepare_event_sent;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -040054};
55
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050056struct wlsc_move_grab {
57 struct wl_grab grab;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -050058 struct wlsc_surface *surface;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050059 int32_t dx, dy;
60};
61
62static void
63move_grab_motion(struct wl_grab *grab,
64 uint32_t time, int32_t x, int32_t y)
65{
66 struct wlsc_move_grab *move = (struct wlsc_move_grab *) grab;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -050067 struct wlsc_surface *es = move->surface;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050068
Kristian Høgsberga691aee2011-06-23 21:43:50 -040069 wlsc_surface_configure(es, x + move->dx, y + move->dy,
70 es->width, es->height);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050071}
72
73static void
74move_grab_button(struct wl_grab *grab,
75 uint32_t time, int32_t button, int32_t state)
76{
77}
78
79static void
80move_grab_end(struct wl_grab *grab, uint32_t time)
81{
82 free(grab);
83}
84
85static const struct wl_grab_interface move_grab_interface = {
86 move_grab_motion,
87 move_grab_button,
88 move_grab_end
89};
90
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -040091static int
92wlsc_surface_move(struct wlsc_surface *es,
93 struct wlsc_input_device *wd, uint32_t time)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050094{
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050095 struct wlsc_move_grab *move;
96
97 move = malloc(sizeof *move);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -040098 if (!move)
99 return -1;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500100
101 move->grab.interface = &move_grab_interface;
102 move->dx = es->x - wd->input_device.grab_x;
103 move->dy = es->y - wd->input_device.grab_y;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -0500104 move->surface = es;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500105
106 if (wl_input_device_update_grab(&wd->input_device,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400107 &move->grab, &es->surface, time) < 0)
108 return 0;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500109
110 wlsc_input_device_set_pointer_image(wd, WLSC_POINTER_DRAGGING);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400111 wl_input_device_set_pointer_focus(&wd->input_device,
112 NULL, time, 0, 0, 0, 0);
113
114 return 0;
115}
116
117static void
118shell_move(struct wl_client *client, struct wl_resource *resource,
119 struct wl_resource *surface_resource,
120 struct wl_resource *input_resource, uint32_t time)
121{
122 struct wlsc_input_device *wd = input_resource->data;
123 struct wlsc_surface *es = surface_resource->data;
124
125 if (wlsc_surface_move(es, wd, time) < 0)
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400126 wl_resource_post_no_memory(resource);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500127}
128
129struct wlsc_resize_grab {
130 struct wl_grab grab;
131 uint32_t edges;
132 int32_t dx, dy, width, height;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -0500133 struct wlsc_surface *surface;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400134 struct wl_resource *resource;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500135};
136
137static void
138resize_grab_motion(struct wl_grab *grab,
139 uint32_t time, int32_t x, int32_t y)
140{
141 struct wlsc_resize_grab *resize = (struct wlsc_resize_grab *) grab;
142 struct wl_input_device *device = grab->input_device;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -0500143 struct wl_surface *surface = &resize->surface->surface;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500144 int32_t width, height;
145
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500146 if (resize->edges & WL_SHELL_RESIZE_LEFT) {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500147 width = device->grab_x - x + resize->width;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500148 } else if (resize->edges & WL_SHELL_RESIZE_RIGHT) {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500149 width = x - device->grab_x + resize->width;
150 } else {
151 width = resize->width;
152 }
153
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500154 if (resize->edges & WL_SHELL_RESIZE_TOP) {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500155 height = device->grab_y - y + resize->height;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500156 } else if (resize->edges & WL_SHELL_RESIZE_BOTTOM) {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500157 height = y - device->grab_y + resize->height;
158 } else {
159 height = resize->height;
160 }
161
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400162 wl_resource_post_event(resize->resource,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400163 WL_SHELL_CONFIGURE, time, resize->edges,
164 surface, width, height);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500165}
166
167static void
168resize_grab_button(struct wl_grab *grab,
169 uint32_t time, int32_t button, int32_t state)
170{
171}
172
173static void
174resize_grab_end(struct wl_grab *grab, uint32_t time)
175{
176 free(grab);
177}
178
179static const struct wl_grab_interface resize_grab_interface = {
180 resize_grab_motion,
181 resize_grab_button,
182 resize_grab_end
183};
184
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400185static int
186wlsc_surface_resize(struct wlsc_surface *es,
187 struct wlsc_input_device *wd,
188 uint32_t time, uint32_t edges,
189 struct wl_resource *resource)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500190{
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500191 struct wlsc_resize_grab *resize;
192 enum wlsc_pointer_type pointer = WLSC_POINTER_LEFT_PTR;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500193
Kristian Høgsberg0ce24572011-01-28 15:18:33 -0500194 /* FIXME: Reject if fullscreen */
195
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500196 resize = malloc(sizeof *resize);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400197 if (!resize)
198 return -1;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500199
200 resize->grab.interface = &resize_grab_interface;
201 resize->edges = edges;
202 resize->dx = es->x - wd->input_device.grab_x;
203 resize->dy = es->y - wd->input_device.grab_y;
204 resize->width = es->width;
205 resize->height = es->height;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -0500206 resize->surface = es;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400207 resize->resource = resource;
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400208
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500209 if (edges == 0 || edges > 15 ||
210 (edges & 3) == 3 || (edges & 12) == 12)
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400211 return 0;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500212
213 switch (edges) {
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500214 case WL_SHELL_RESIZE_TOP:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500215 pointer = WLSC_POINTER_TOP;
216 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500217 case WL_SHELL_RESIZE_BOTTOM:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500218 pointer = WLSC_POINTER_BOTTOM;
219 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500220 case WL_SHELL_RESIZE_LEFT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500221 pointer = WLSC_POINTER_LEFT;
222 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500223 case WL_SHELL_RESIZE_TOP_LEFT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500224 pointer = WLSC_POINTER_TOP_LEFT;
225 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500226 case WL_SHELL_RESIZE_BOTTOM_LEFT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500227 pointer = WLSC_POINTER_BOTTOM_LEFT;
228 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500229 case WL_SHELL_RESIZE_RIGHT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500230 pointer = WLSC_POINTER_RIGHT;
231 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500232 case WL_SHELL_RESIZE_TOP_RIGHT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500233 pointer = WLSC_POINTER_TOP_RIGHT;
234 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500235 case WL_SHELL_RESIZE_BOTTOM_RIGHT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500236 pointer = WLSC_POINTER_BOTTOM_RIGHT;
237 break;
238 }
239
240 if (wl_input_device_update_grab(&wd->input_device,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400241 &resize->grab, &es->surface, time) < 0)
242 return 0;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500243
244 wlsc_input_device_set_pointer_image(wd, pointer);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400245 wl_input_device_set_pointer_focus(&wd->input_device,
246 NULL, time, 0, 0, 0, 0);
247
248 return 0;
249}
250
251static void
252shell_resize(struct wl_client *client, struct wl_resource *resource,
253 struct wl_resource *surface_resource,
254 struct wl_resource *input_resource, uint32_t time, uint32_t edges)
255{
256 struct wlsc_input_device *wd = input_resource->data;
257 struct wlsc_surface *es = surface_resource->data;
258
259 /* FIXME: Reject if fullscreen */
260
261 if (wlsc_surface_resize(es, wd, time, edges, resource) < 0)
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400262 wl_resource_post_no_memory(resource);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500263}
264
265static void
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400266shell_set_toplevel(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400267 struct wl_resource *resource,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400268 struct wl_resource *surface_resource)
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400269
270{
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400271 struct wlsc_surface *es = surface_resource->data;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400272
273 if (es->map_type == WLSC_SURFACE_MAP_FULLSCREEN) {
274 es->x = es->saved_x;
275 es->y = es->saved_y;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400276 }
277
278 wlsc_surface_damage(es);
279 es->map_type = WLSC_SURFACE_MAP_TOPLEVEL;
280 es->fullscreen_output = NULL;
281}
282
283static void
284shell_set_transient(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400285 struct wl_resource *resource,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400286 struct wl_resource *surface_resource,
287 struct wl_resource *parent_resource,
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400288 int x, int y, uint32_t flags)
289{
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400290 struct wlsc_surface *es = surface_resource->data;
291 struct wlsc_surface *pes = parent_resource->data;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400292
293 /* assign to parents output */
294 es->output = pes->output;
295
296 es->x = pes->x + x;
297 es->y = pes->y + y;
298
299 wlsc_surface_damage(es);
300 es->map_type = WLSC_SURFACE_MAP_TRANSIENT;
301}
302
303static void
304shell_set_fullscreen(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400305 struct wl_resource *resource,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400306 struct wl_resource *surface_resource)
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400307
308{
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400309 struct wlsc_surface *es = surface_resource->data;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400310 struct wlsc_output *output;
311
312 /* FIXME: Fullscreen on first output */
313 /* FIXME: Handle output going away */
314 output = container_of(es->compositor->output_list.next,
315 struct wlsc_output, link);
316 es->output = output;
317
318 es->saved_x = es->x;
319 es->saved_y = es->y;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400320 es->x = (output->current->width - es->width) / 2;
321 es->y = (output->current->height - es->height) / 2;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400322 es->fullscreen_output = output;
323 wlsc_surface_damage(es);
324 es->map_type = WLSC_SURFACE_MAP_FULLSCREEN;
325}
326
327static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400328destroy_drag(struct wl_resource *resource)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500329{
330 struct wl_drag *drag =
331 container_of(resource, struct wl_drag, resource);
332
333 wl_list_remove(&drag->drag_focus_listener.link);
334 if (drag->grab.input_device)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400335 wl_input_device_end_grab(drag->grab.input_device,
336 wlsc_compositor_get_time());
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500337
338 free(drag);
339}
340
341
342static void
343wl_drag_set_pointer_focus(struct wl_drag *drag,
344 struct wl_surface *surface, uint32_t time,
345 int32_t x, int32_t y, int32_t sx, int32_t sy)
346{
347 char **p, **end;
348
349 if (drag->drag_focus == surface)
350 return;
351
352 if (drag->drag_focus &&
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400353 (!surface ||
354 drag->drag_focus->resource.client != surface->resource.client))
355 wl_resource_post_event(&drag->drag_offer.resource,
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500356 WL_DRAG_OFFER_POINTER_FOCUS,
357 time, NULL, 0, 0, 0, 0);
358
359 if (surface &&
360 (!drag->drag_focus ||
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400361 drag->drag_focus->resource.client != surface->resource.client)) {
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400362
363 drag->drag_offer.resource.client = surface->resource.client;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500364 end = drag->types.data + drag->types.size;
365 for (p = drag->types.data; p < end; p++)
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400366 wl_resource_post_event(&drag->drag_offer.resource,
367 WL_DRAG_OFFER_OFFER, *p);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500368 }
369
370 if (surface) {
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400371 wl_resource_post_event(&drag->drag_offer.resource,
372 WL_DRAG_OFFER_POINTER_FOCUS,
373 time, surface,
374 x, y, sx, sy);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500375
376 }
377
378 drag->drag_focus = surface;
379 drag->pointer_focus_time = time;
380 drag->target = NULL;
381
382 wl_list_remove(&drag->drag_focus_listener.link);
383 if (surface)
Benjamin Franzke4721a3c2011-05-06 17:13:17 +0200384 wl_list_insert(surface->resource.destroy_listener_list.prev,
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500385 &drag->drag_focus_listener.link);
386}
387
388static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400389drag_offer_accept(struct wl_client *client, struct wl_resource *resource,
390 uint32_t time, const char *type)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500391{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400392 struct wl_drag_offer *offer = resource->data;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500393 struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer);
394 char **p, **end;
395
396 /* If the client responds to drag pointer_focus or motion
397 * events after the pointer has left the surface, we just
398 * discard the accept requests. The drag source just won't
399 * get the corresponding 'target' events and eventually the
400 * next surface/root will start sending events. */
401 if (time < drag->pointer_focus_time)
402 return;
403
404 drag->target = client;
405 drag->type = NULL;
406 end = drag->types.data + drag->types.size;
407 for (p = drag->types.data; p < end; p++)
408 if (type && strcmp(*p, type) == 0)
409 drag->type = *p;
410
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400411 wl_resource_post_event(&drag->resource, WL_DRAG_TARGET, drag->type);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500412}
413
414static void
415drag_offer_receive(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400416 struct wl_resource *resource, int fd)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500417{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400418 struct wl_drag_offer *offer = resource->data;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500419 struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer);
420
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400421 wl_resource_post_event(&drag->resource, WL_DRAG_FINISH, fd);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500422 close(fd);
423}
424
425static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400426drag_offer_reject(struct wl_client *client, struct wl_resource *resource)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500427{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400428 struct wl_drag_offer *offer = resource->data;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500429 struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer);
430
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400431 wl_resource_post_event(&drag->resource, WL_DRAG_REJECT);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500432}
433
434static const struct wl_drag_offer_interface drag_offer_interface = {
435 drag_offer_accept,
436 drag_offer_receive,
437 drag_offer_reject
438};
439
440static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400441drag_offer(struct wl_client *client,
442 struct wl_resource *resource, const char *type)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500443{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400444 struct wl_drag *drag = resource->data;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500445 char **p;
446
447 p = wl_array_add(&drag->types, sizeof *p);
448 if (p)
449 *p = strdup(type);
450 if (!p || !*p)
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400451 wl_resource_post_no_memory(resource);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500452}
453
454static void
455drag_grab_motion(struct wl_grab *grab,
456 uint32_t time, int32_t x, int32_t y)
457{
458 struct wl_drag *drag = container_of(grab, struct wl_drag, grab);
459 struct wlsc_surface *es;
460 int32_t sx, sy;
461
462 es = pick_surface(grab->input_device, &sx, &sy);
463 wl_drag_set_pointer_focus(drag, &es->surface, time, x, y, sx, sy);
464 if (es)
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400465 wl_resource_post_event(&drag->drag_offer.resource,
466 WL_DRAG_OFFER_MOTION,
467 time, x, y, sx, sy);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500468}
469
470static void
471drag_grab_button(struct wl_grab *grab,
472 uint32_t time, int32_t button, int32_t state)
473{
474}
475
476static void
477drag_grab_end(struct wl_grab *grab, uint32_t time)
478{
479 struct wl_drag *drag = container_of(grab, struct wl_drag, grab);
480
481 if (drag->target)
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400482 wl_resource_post_event(&drag->drag_offer.resource,
483 WL_DRAG_OFFER_DROP);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500484
485 wl_drag_set_pointer_focus(drag, NULL, time, 0, 0, 0, 0);
486}
487
488static const struct wl_grab_interface drag_grab_interface = {
489 drag_grab_motion,
490 drag_grab_button,
491 drag_grab_end
492};
493
494static void
495drag_activate(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400496 struct wl_resource *resource,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400497 struct wl_resource *surface_resource,
498 struct wl_resource *device_resource, uint32_t time)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500499{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400500 struct wl_drag *drag = resource->data;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400501 struct wl_surface *surface = surface_resource->data;
502 struct wl_input_device *device = device_resource->data;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500503 struct wl_display *display = wl_client_get_display (client);
504 struct wlsc_surface *target;
505 int32_t sx, sy;
506
507 if (wl_input_device_update_grab(device,
508 &drag->grab, surface, time) < 0)
509 return;
510
511 drag->grab.interface = &drag_grab_interface;
512
513 drag->source = surface;
514
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400515 drag->drag_offer.resource.object.interface = &wl_drag_offer_interface;
516 drag->drag_offer.resource.object.implementation =
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500517 (void (**)(void)) &drag_offer_interface;
518
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400519 wl_display_add_global(display, &wl_drag_offer_interface, drag, NULL);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500520
521 target = pick_surface(device, &sx, &sy);
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -0500522 wl_input_device_set_pointer_focus(device, NULL, time, 0, 0, 0, 0);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500523 wl_drag_set_pointer_focus(drag, &target->surface, time,
524 device->x, device->y, sx, sy);
525}
526
527static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400528drag_destroy(struct wl_client *client, struct wl_resource *resource)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500529{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400530 wl_resource_destroy(resource, wlsc_compositor_get_time());
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500531}
532
533static const struct wl_drag_interface drag_interface = {
534 drag_offer,
535 drag_activate,
536 drag_destroy,
537};
538
539static void
540drag_handle_surface_destroy(struct wl_listener *listener,
Benjamin Franzke4721a3c2011-05-06 17:13:17 +0200541 struct wl_resource *resource, uint32_t time)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500542{
543 struct wl_drag *drag =
544 container_of(listener, struct wl_drag, drag_focus_listener);
Benjamin Franzke4721a3c2011-05-06 17:13:17 +0200545 struct wl_surface *surface = (struct wl_surface *) resource;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500546
547 if (drag->drag_focus == surface)
548 wl_drag_set_pointer_focus(drag, NULL, time, 0, 0, 0, 0);
549}
550
551static void
552shell_create_drag(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400553 struct wl_resource *resource, uint32_t id)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500554{
555 struct wl_drag *drag;
556
557 drag = malloc(sizeof *drag);
558 if (drag == NULL) {
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400559 wl_resource_post_no_memory(resource);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500560 return;
561 }
562
563 memset(drag, 0, sizeof *drag);
564 drag->resource.object.id = id;
565 drag->resource.object.interface = &wl_drag_interface;
566 drag->resource.object.implementation =
567 (void (**)(void)) &drag_interface;
568
Pekka Paalanen02ebfb12011-10-24 17:34:53 +0300569 drag->resource.data = drag;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500570 drag->resource.destroy = destroy_drag;
571
572 drag->drag_focus_listener.func = drag_handle_surface_destroy;
573 wl_list_init(&drag->drag_focus_listener.link);
574
575 wl_client_add_resource(client, &drag->resource);
576}
577
Kristian Høgsberg1c562182011-05-02 22:09:20 -0400578static void
579wlsc_selection_set_focus(struct wlsc_shell *shell,
580 struct wl_selection *selection,
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500581 struct wl_surface *surface, uint32_t time)
582{
583 char **p, **end;
584
585 if (selection->selection_focus == surface)
586 return;
587
588 if (selection->selection_focus != NULL)
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400589 wl_resource_post_event(&selection->selection_offer.resource,
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500590 WL_SELECTION_OFFER_KEYBOARD_FOCUS,
591 NULL);
592
593 if (surface) {
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500594
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400595 selection->selection_offer.resource.client = surface->resource.client;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500596 end = selection->types.data + selection->types.size;
597 for (p = selection->types.data; p < end; p++)
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400598 wl_resource_post_event(&selection->selection_offer.resource,
599 WL_SELECTION_OFFER_OFFER, *p);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500600
601 wl_list_remove(&selection->selection_focus_listener.link);
Benjamin Franzke4721a3c2011-05-06 17:13:17 +0200602 wl_list_insert(surface->resource.destroy_listener_list.prev,
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500603 &selection->selection_focus_listener.link);
604
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400605 wl_resource_post_event(&selection->selection_offer.resource,
606 WL_SELECTION_OFFER_KEYBOARD_FOCUS,
607 selection->input_device);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500608 }
609
610 selection->selection_focus = surface;
611
612 wl_list_remove(&selection->selection_focus_listener.link);
613 if (surface)
Benjamin Franzke4721a3c2011-05-06 17:13:17 +0200614 wl_list_insert(surface->resource.destroy_listener_list.prev,
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500615 &selection->selection_focus_listener.link);
616}
617
618static void
619selection_offer_receive(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400620 struct wl_resource *resource,
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500621 const char *mime_type, int fd)
622{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400623 struct wl_selection_offer *offer = resource->data;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500624 struct wl_selection *selection =
625 container_of(offer, struct wl_selection, selection_offer);
626
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400627 wl_resource_post_event(&selection->resource,
628 WL_SELECTION_SEND, mime_type, fd);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500629 close(fd);
630}
631
632static const struct wl_selection_offer_interface selection_offer_interface = {
633 selection_offer_receive
634};
635
636static void
637selection_offer(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400638 struct wl_resource *resource, const char *type)
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500639{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400640 struct wl_selection *selection = resource->data;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500641 char **p;
642
643 p = wl_array_add(&selection->types, sizeof *p);
644 if (p)
645 *p = strdup(type);
646 if (!p || !*p)
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400647 wl_resource_post_no_memory(resource);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500648}
649
650static void
651selection_activate(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400652 struct wl_resource *resource,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400653 struct wl_resource *input_resource, uint32_t time)
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500654{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400655 struct wl_selection *selection = resource->data;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400656 struct wlsc_input_device *wd = input_resource->data;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500657 struct wl_display *display = wl_client_get_display (client);
Kristian Høgsberg1c562182011-05-02 22:09:20 -0400658 struct wlsc_compositor *compositor =
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400659 (struct wlsc_compositor *) wd->input_device.compositor;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500660
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400661 selection->input_device = &wd->input_device;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500662
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400663 selection->selection_offer.resource.object.interface =
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500664 &wl_selection_offer_interface;
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400665 selection->selection_offer.resource.object.implementation =
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500666 (void (**)(void)) &selection_offer_interface;
667
Kristian Høgsbergd9551a32011-08-19 12:07:44 -0400668 wl_display_add_global(display,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400669 &wl_selection_offer_interface, selection, NULL);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500670
671 if (wd->selection) {
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400672 wl_resource_post_event(&wd->selection->resource,
673 WL_SELECTION_CANCELLED);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500674 }
675 wd->selection = selection;
676
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400677 wlsc_selection_set_focus(compositor->shell, selection,
678 wd->input_device.keyboard_focus, time);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500679}
680
681static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400682selection_destroy(struct wl_client *client, struct wl_resource *resource)
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500683{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400684 wl_resource_destroy(resource, wlsc_compositor_get_time());
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500685}
686
687static const struct wl_selection_interface selection_interface = {
688 selection_offer,
689 selection_activate,
690 selection_destroy
691};
692
693static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400694destroy_selection(struct wl_resource *resource)
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500695{
696 struct wl_selection *selection =
697 container_of(resource, struct wl_selection, resource);
698 struct wlsc_input_device *wd =
699 (struct wlsc_input_device *) selection->input_device;
Kristian Høgsberg1c562182011-05-02 22:09:20 -0400700 struct wlsc_compositor *compositor =
701 (struct wlsc_compositor *) wd->input_device.compositor;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500702
703 if (wd && wd->selection == selection) {
704 wd->selection = NULL;
Kristian Høgsberg1c562182011-05-02 22:09:20 -0400705 wlsc_selection_set_focus(compositor->shell,
706 selection, NULL,
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400707 wlsc_compositor_get_time());
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500708 }
709
710 wl_list_remove(&selection->selection_focus_listener.link);
711 free(selection);
712}
713
714static void
715selection_handle_surface_destroy(struct wl_listener *listener,
Benjamin Franzke4721a3c2011-05-06 17:13:17 +0200716 struct wl_resource *resource, uint32_t time)
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500717{
718}
719
720static void
721shell_create_selection(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400722 struct wl_resource *resource, uint32_t id)
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500723{
724 struct wl_selection *selection;
725
726 selection = malloc(sizeof *selection);
727 if (selection == NULL) {
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400728 wl_resource_post_no_memory(resource);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500729 return;
730 }
731
732 memset(selection, 0, sizeof *selection);
733 selection->resource.object.id = id;
734 selection->resource.object.interface = &wl_selection_interface;
735 selection->resource.object.implementation =
736 (void (**)(void)) &selection_interface;
737
738 selection->client = client;
739 selection->resource.destroy = destroy_selection;
740 selection->selection_focus = NULL;
741
742 selection->selection_focus_listener.func =
743 selection_handle_surface_destroy;
744 wl_list_init(&selection->selection_focus_listener.link);
745
746 wl_client_add_resource(client, &selection->resource);
747}
748
Kristian Høgsberg75840622011-09-06 13:48:16 -0400749static const struct wl_shell_interface shell_interface = {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500750 shell_move,
751 shell_resize,
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500752 shell_create_drag,
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400753 shell_create_selection,
754 shell_set_toplevel,
755 shell_set_transient,
756 shell_set_fullscreen
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500757};
758
Kristian Høgsberg07937562011-04-12 17:25:42 -0400759static void
Kristian Høgsberg75840622011-09-06 13:48:16 -0400760handle_background_surface_destroy(struct wl_listener *listener,
761 struct wl_resource *resource, uint32_t time)
762{
763 struct wl_shell *shell =
764 container_of(listener, struct wl_shell, background_listener);
765
766 fprintf(stderr, "background surface gone\n");
767 shell->background = NULL;
768}
769
770static void
771desktop_shell_set_background(struct wl_client *client,
772 struct wl_resource *resource,
773 struct wl_resource *surface_resource)
774{
775 struct wl_shell *shell = resource->data;
776 struct wlsc_surface *surface = surface_resource->data;
777 struct wlsc_output *output =
778 container_of(shell->compositor->output_list.next,
779 struct wlsc_output, link);
780
781 shell->background = surface_resource->data;
782 shell->background_listener.func = handle_background_surface_destroy;
783 wl_list_insert(&surface_resource->destroy_listener_list,
784 &shell->background_listener.link);
785
786 wl_resource_post_event(resource,
787 DESKTOP_SHELL_CONFIGURE,
788 wlsc_compositor_get_time(), 0, surface,
789 output->current->width,
790 output->current->height);
791}
792
793static void
794handle_panel_surface_destroy(struct wl_listener *listener,
795 struct wl_resource *resource, uint32_t time)
796{
797 struct wl_shell *shell =
798 container_of(listener, struct wl_shell, panel_listener);
799
800 fprintf(stderr, "panel surface gone\n");
801 shell->panel = NULL;
802}
803
804static void
805desktop_shell_set_panel(struct wl_client *client,
806 struct wl_resource *resource,
807 struct wl_resource *surface_resource)
808{
809 struct wl_shell *shell = resource->data;
810 struct wlsc_output *output =
811 container_of(shell->compositor->output_list.next,
812 struct wlsc_output, link);
813
814 shell->panel = surface_resource->data;
815
816 shell->panel_listener.func = handle_panel_surface_destroy;
817 wl_list_insert(&surface_resource->destroy_listener_list,
818 &shell->panel_listener.link);
819
820 wl_resource_post_event(resource,
821 DESKTOP_SHELL_CONFIGURE,
822 wlsc_compositor_get_time(), 0, surface_resource,
823 output->current->width,
824 output->current->height);
825}
826
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200827static void
828desktop_shell_set_lock_surface(struct wl_client *client,
829 struct wl_resource *resource,
830 struct wl_resource *surface_resource)
831{
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +0200832 struct wl_shell *shell = resource->data;
833
834 /* TODO: put the lock surface always on top modal until unlocked */
835
836 wlsc_compositor_wake(shell->compositor);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200837}
838
839static void
840desktop_shell_unlock(struct wl_client *client,
841 struct wl_resource *resource)
842{
843 struct wl_shell *shell = resource->data;
844
845 shell->locked = false;
846 shell->prepare_event_sent = false;
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +0200847 wlsc_compositor_wake(shell->compositor);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200848}
849
Kristian Høgsberg75840622011-09-06 13:48:16 -0400850static const struct desktop_shell_interface desktop_shell_implementation = {
851 desktop_shell_set_background,
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200852 desktop_shell_set_panel,
853 desktop_shell_set_lock_surface,
854 desktop_shell_unlock
Kristian Høgsberg75840622011-09-06 13:48:16 -0400855};
856
857static void
Kristian Høgsberg07937562011-04-12 17:25:42 -0400858move_binding(struct wl_input_device *device, uint32_t time,
859 uint32_t key, uint32_t button, uint32_t state, void *data)
860{
Kristian Høgsberg75840622011-09-06 13:48:16 -0400861 struct wl_shell *shell = data;
Kristian Høgsberg07937562011-04-12 17:25:42 -0400862 struct wlsc_surface *surface =
863 (struct wlsc_surface *) device->pointer_focus;
864
Kristian Høgsberga4a42f02011-09-08 16:56:57 -0400865 if (surface == NULL ||
866 surface->map_type == WLSC_SURFACE_MAP_FULLSCREEN)
Kristian Høgsberg10f097e2011-04-13 11:52:54 -0400867 return;
Kristian Høgsberg75840622011-09-06 13:48:16 -0400868 if (surface == shell->panel)
869 return;
870 if (surface == shell->background)
871 return;
Kristian Høgsberg10f097e2011-04-13 11:52:54 -0400872
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400873 wlsc_surface_move(surface, (struct wlsc_input_device *) device, time);
Kristian Høgsberg07937562011-04-12 17:25:42 -0400874}
875
876static void
877resize_binding(struct wl_input_device *device, uint32_t time,
878 uint32_t key, uint32_t button, uint32_t state, void *data)
879{
Kristian Høgsberg75840622011-09-06 13:48:16 -0400880 struct wl_shell *shell = data;
Kristian Høgsberg07937562011-04-12 17:25:42 -0400881 struct wlsc_surface *surface =
882 (struct wlsc_surface *) device->pointer_focus;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400883 struct wl_resource *resource;
Kristian Høgsberg07937562011-04-12 17:25:42 -0400884 uint32_t edges = 0;
885 int32_t x, y;
886
Kristian Høgsberga4a42f02011-09-08 16:56:57 -0400887 if (surface == NULL ||
888 surface->map_type == WLSC_SURFACE_MAP_FULLSCREEN)
Kristian Høgsberg75840622011-09-06 13:48:16 -0400889 if (surface == shell->panel)
890 return;
891 if (surface == shell->background)
892 return;
Kristian Høgsberg10f097e2011-04-13 11:52:54 -0400893
Kristian Høgsberg07937562011-04-12 17:25:42 -0400894 x = device->grab_x - surface->x;
895 y = device->grab_y - surface->y;
896
897 if (x < surface->width / 3)
898 edges |= WL_SHELL_RESIZE_LEFT;
899 else if (x < 2 * surface->width / 3)
900 edges |= 0;
901 else
902 edges |= WL_SHELL_RESIZE_RIGHT;
903
904 if (y < surface->height / 3)
905 edges |= WL_SHELL_RESIZE_TOP;
906 else if (y < 2 * surface->height / 3)
907 edges |= 0;
908 else
909 edges |= WL_SHELL_RESIZE_BOTTOM;
910
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400911 resource = /* Find shell resource for surface client */ 0;
912
913 /* ... or use wl_shell_surface */
914
915 wlsc_surface_resize(surface, (struct wlsc_input_device *) device,
916 time, edges, resource);
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400917}
918
919static void
Kristian Høgsberg75840622011-09-06 13:48:16 -0400920activate(struct wlsc_shell *base, struct wlsc_surface *es,
921 struct wlsc_input_device *device, uint32_t time)
922{
923 struct wl_shell *shell = container_of(base, struct wl_shell, shell);
924 struct wlsc_compositor *compositor = shell->compositor;
925
926 wlsc_surface_activate(es, device, time);
927
Kristian Høgsbergd6e55252011-10-11 23:41:17 -0400928 if (compositor->wxs)
929 wlsc_xserver_surface_activate(es);
930
Kristian Høgsberg75840622011-09-06 13:48:16 -0400931 if (es == shell->background) {
932 wl_list_remove(&es->link);
933 wl_list_insert(compositor->surface_list.prev, &es->link);
934 } else if (shell->panel) {
935 wl_list_remove(&shell->panel->link);
936 wl_list_insert(&compositor->surface_list, &shell->panel->link);
937 }
938}
939
940static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200941lock(struct wlsc_shell *base)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400942{
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200943 struct wl_shell *shell = container_of(base, struct wl_shell, shell);
944
945 shell->locked = true;
946}
947
948static void
949unlock(struct wlsc_shell *base)
950{
951 struct wl_shell *shell = container_of(base, struct wl_shell, shell);
952
953 if (!shell->locked) {
954 wlsc_compositor_wake(shell->compositor);
955 return;
956 }
957
958 /* If desktop-shell client has gone away, unlock immediately. */
959 if (!shell->child.desktop_shell) {
960 shell->locked = false;
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +0200961 wlsc_compositor_wake(shell->compositor);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200962 return;
963 }
964
965 if (shell->prepare_event_sent)
966 return;
967
968 wl_resource_post_event(shell->child.desktop_shell,
969 DESKTOP_SHELL_PREPARE_LOCK_SURFACE);
970 shell->prepare_event_sent = true;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400971}
972
973static void
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -0500974map(struct wlsc_shell *base,
975 struct wlsc_surface *surface, int32_t width, int32_t height)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400976{
Kristian Høgsberg75840622011-09-06 13:48:16 -0400977 struct wl_shell *shell = container_of(base, struct wl_shell, shell);
978 struct wlsc_compositor *compositor = shell->compositor;
979
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -0500980 /* Map background at the bottom of the stack, panel on top,
981 everything else just below panel. */
982 if (surface == shell->background)
983 wl_list_insert(compositor->surface_list.prev, &surface->link);
984 else if (surface == shell->panel)
985 wl_list_insert(&compositor->surface_list, &surface->link);
986 else
987 wl_list_insert(&shell->panel->link, &surface->link);
988
Kristian Høgsberg46770132011-11-09 12:38:53 -0500989 if (surface->map_type == WLSC_SURFACE_MAP_TOPLEVEL) {
990 surface->x = 10 + random() % 400;
991 surface->y = 10 + random() % 400;
992 }
993
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -0500994 wlsc_surface_configure(surface, surface->x, surface->y, width, height);
995}
996
997static void
998configure(struct wlsc_shell *shell, struct wlsc_surface *surface,
999 int32_t x, int32_t y, int32_t width, int32_t height)
1000{
1001 struct wlsc_mode *current;
1002
1003 if (surface->map_type == WLSC_SURFACE_MAP_FULLSCREEN) {
1004 current = surface->fullscreen_output->current;
1005 x = (current->width - surface->width) / 2;
1006 y = (current->height - surface->height) / 2;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001007 }
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05001008
1009 wlsc_surface_configure(surface, x, y, width, height);
Kristian Høgsberg07937562011-04-12 17:25:42 -04001010}
1011
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001012static void
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02001013desktop_shell_sigchld(struct wlsc_process *process, int status)
1014{
1015 struct wl_shell *shell =
1016 container_of(process, struct wl_shell, child.process);
1017
1018 shell->child.process.pid = 0;
1019 shell->child.client = NULL; /* already destroyed by wayland */
1020}
1021
1022static int
1023launch_desktop_shell_process(struct wl_shell *shell)
1024{
Kristian Høgsbergc4693c42011-11-14 14:57:17 -05001025 const char *shell_exe = LIBEXECDIR "/wayland-desktop-shell";
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02001026 struct wlsc_compositor *compositor = shell->compositor;
1027 char s[32];
1028 int sv[2], flags;
1029
1030 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) {
1031 fprintf(stderr, "socketpair failed\n");
1032 return -1;
1033 }
1034
1035 shell->child.process.pid = fork();
1036 shell->child.process.cleanup = desktop_shell_sigchld;
1037
1038 switch (shell->child.process.pid) {
1039 case 0:
1040 /* SOCK_CLOEXEC closes both ends, so we need to unset
1041 * the flag on the client fd. */
1042 flags = fcntl(sv[1], F_GETFD);
1043 if (flags != -1)
1044 fcntl(sv[1], F_SETFD, flags & ~FD_CLOEXEC);
1045
1046 snprintf(s, sizeof s, "%d", sv[1]);
1047 setenv("WAYLAND_SOCKET", s, 1);
1048 if (execl(shell_exe, shell_exe, NULL) < 0)
1049 fprintf(stderr, "%s: running '%s' failed: %m\n",
1050 __func__, shell_exe);
1051 exit(-1);
1052
1053 default:
1054 close(sv[1]);
1055 shell->child.client =
1056 wl_client_create(compositor->wl_display, sv[0]);
1057 wlsc_watch_process(&shell->child.process);
1058 break;
1059
1060 case -1:
1061 fprintf(stderr, "%s: fork failed: %m\n", __func__);
1062 return -1;
1063 }
1064 return 0;
1065}
1066
1067static void
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001068bind_shell(struct wl_client *client, void *data, uint32_t version, uint32_t id)
1069{
1070 struct wl_shell *shell = data;
1071
1072 wl_client_add_object(client, &wl_shell_interface,
1073 &shell_interface, id, shell);
1074}
1075
Kristian Høgsberg75840622011-09-06 13:48:16 -04001076static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001077unbind_desktop_shell(struct wl_resource *resource)
1078{
1079 struct wl_shell *shell = resource->data;
1080 shell->child.desktop_shell = NULL;
1081 shell->prepare_event_sent = false;
1082 free(resource);
1083}
1084
1085static void
Kristian Høgsberg75840622011-09-06 13:48:16 -04001086bind_desktop_shell(struct wl_client *client,
1087 void *data, uint32_t version, uint32_t id)
1088{
1089 struct wl_shell *shell = data;
Pekka Paalanenbbe60522011-11-03 14:11:33 +02001090 struct wl_resource *resource;
Kristian Høgsberg75840622011-09-06 13:48:16 -04001091
Pekka Paalanenbbe60522011-11-03 14:11:33 +02001092 resource = wl_client_add_object(client, &desktop_shell_interface,
1093 &desktop_shell_implementation,
1094 id, shell);
1095
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001096 if (client == shell->child.client) {
1097 resource->destroy = unbind_desktop_shell;
1098 shell->child.desktop_shell = resource;
Pekka Paalanenbbe60522011-11-03 14:11:33 +02001099 return;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001100 }
Pekka Paalanenbbe60522011-11-03 14:11:33 +02001101
1102 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
1103 "permission to bind desktop_shell denied");
1104 wl_resource_destroy(resource, 0);
Kristian Høgsberg75840622011-09-06 13:48:16 -04001105}
1106
Kristian Høgsberg6c709a32011-05-06 14:52:41 -04001107int
1108shell_init(struct wlsc_compositor *ec);
1109
Kristian Høgsberg1c562182011-05-02 22:09:20 -04001110WL_EXPORT int
1111shell_init(struct wlsc_compositor *ec)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001112{
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001113 struct wl_shell *shell;
1114
1115 shell = malloc(sizeof *shell);
1116 if (shell == NULL)
1117 return -1;
1118
Kristian Høgsbergf0d91162011-10-11 22:44:23 -04001119 memset(shell, 0, sizeof *shell);
Kristian Høgsberg75840622011-09-06 13:48:16 -04001120 shell->compositor = ec;
1121 shell->shell.activate = activate;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001122 shell->shell.lock = lock;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001123 shell->shell.unlock = unlock;
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05001124 shell->shell.map = map;
1125 shell->shell.configure = configure;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04001126 shell->shell.set_selection_focus = wlsc_selection_set_focus;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001127
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001128 if (wl_display_add_global(ec->wl_display, &wl_shell_interface,
1129 shell, bind_shell) == NULL)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001130 return -1;
1131
Kristian Høgsberg75840622011-09-06 13:48:16 -04001132 if (wl_display_add_global(ec->wl_display,
1133 &desktop_shell_interface,
1134 shell, bind_desktop_shell) == NULL)
1135 return -1;
1136
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02001137 if (launch_desktop_shell_process(shell) != 0)
1138 return -1;
1139
Kristian Høgsberg07937562011-04-12 17:25:42 -04001140 wlsc_compositor_add_binding(ec, 0, BTN_LEFT, MODIFIER_SUPER,
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001141 move_binding, shell);
Kristian Høgsberg07937562011-04-12 17:25:42 -04001142 wlsc_compositor_add_binding(ec, 0, BTN_MIDDLE, MODIFIER_SUPER,
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001143 resize_binding, shell);
1144
1145 ec->shell = &shell->shell;
Kristian Høgsberg07937562011-04-12 17:25:42 -04001146
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001147 return 0;
1148}