blob: c44ebcad316e9d8b03db817e46c08e166832e830 [file] [log] [blame]
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001/*
2 * Copyright © 2010 Intel Corporation
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and
5 * its documentation for any purpose is hereby granted without fee, provided
6 * that the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of the copyright holders not be used in
9 * advertising or publicity pertaining to distribution of the software
10 * without specific, written prior permission. The copyright holders make
11 * no representations about the suitability of this software for any
12 * purpose. It is provided "as is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
15 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
17 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
18 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
19 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 */
22
23#include <stdlib.h>
Kristian Høgsberg75840622011-09-06 13:48:16 -040024#include <stdio.h>
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050025#include <string.h>
26#include <unistd.h>
Kristian Høgsberg07937562011-04-12 17:25:42 -040027#include <linux/input.h>
Pekka Paalanen6cd281a2011-11-03 14:11:32 +020028#include <sys/types.h>
29#include <sys/socket.h>
30#include <fcntl.h>
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050031
32#include "wayland-server.h"
33#include "compositor.h"
Kristian Høgsberg75840622011-09-06 13:48:16 -040034#include "desktop-shell-server-protocol.h"
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050035
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -040036struct wl_shell {
Kristian Høgsberg75840622011-09-06 13:48:16 -040037 struct wlsc_compositor *compositor;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -040038 struct wlsc_shell shell;
Kristian Høgsberg75840622011-09-06 13:48:16 -040039 struct wlsc_surface *panel;
40 struct wl_listener panel_listener;
41 struct wlsc_surface *background;
42 struct wl_listener background_listener;
Pekka Paalanen6cd281a2011-11-03 14:11:32 +020043
44 struct {
45 struct wlsc_process process;
46 struct wl_client *client;
47 } child;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -040048};
49
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050050struct wlsc_move_grab {
51 struct wl_grab grab;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -050052 struct wlsc_surface *surface;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050053 int32_t dx, dy;
54};
55
56static void
57move_grab_motion(struct wl_grab *grab,
58 uint32_t time, int32_t x, int32_t y)
59{
60 struct wlsc_move_grab *move = (struct wlsc_move_grab *) grab;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -050061 struct wlsc_surface *es = move->surface;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050062
Kristian Høgsberga691aee2011-06-23 21:43:50 -040063 wlsc_surface_configure(es, x + move->dx, y + move->dy,
64 es->width, es->height);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050065}
66
67static void
68move_grab_button(struct wl_grab *grab,
69 uint32_t time, int32_t button, int32_t state)
70{
71}
72
73static void
74move_grab_end(struct wl_grab *grab, uint32_t time)
75{
76 free(grab);
77}
78
79static const struct wl_grab_interface move_grab_interface = {
80 move_grab_motion,
81 move_grab_button,
82 move_grab_end
83};
84
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -040085static int
86wlsc_surface_move(struct wlsc_surface *es,
87 struct wlsc_input_device *wd, uint32_t time)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050088{
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050089 struct wlsc_move_grab *move;
90
91 move = malloc(sizeof *move);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -040092 if (!move)
93 return -1;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050094
95 move->grab.interface = &move_grab_interface;
96 move->dx = es->x - wd->input_device.grab_x;
97 move->dy = es->y - wd->input_device.grab_y;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -050098 move->surface = es;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050099
100 if (wl_input_device_update_grab(&wd->input_device,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400101 &move->grab, &es->surface, time) < 0)
102 return 0;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500103
104 wlsc_input_device_set_pointer_image(wd, WLSC_POINTER_DRAGGING);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400105 wl_input_device_set_pointer_focus(&wd->input_device,
106 NULL, time, 0, 0, 0, 0);
107
108 return 0;
109}
110
111static void
112shell_move(struct wl_client *client, struct wl_resource *resource,
113 struct wl_resource *surface_resource,
114 struct wl_resource *input_resource, uint32_t time)
115{
116 struct wlsc_input_device *wd = input_resource->data;
117 struct wlsc_surface *es = surface_resource->data;
118
119 if (wlsc_surface_move(es, wd, time) < 0)
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400120 wl_resource_post_no_memory(resource);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500121}
122
123struct wlsc_resize_grab {
124 struct wl_grab grab;
125 uint32_t edges;
126 int32_t dx, dy, width, height;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -0500127 struct wlsc_surface *surface;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400128 struct wl_resource *resource;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500129};
130
131static void
132resize_grab_motion(struct wl_grab *grab,
133 uint32_t time, int32_t x, int32_t y)
134{
135 struct wlsc_resize_grab *resize = (struct wlsc_resize_grab *) grab;
136 struct wl_input_device *device = grab->input_device;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -0500137 struct wl_surface *surface = &resize->surface->surface;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500138 int32_t width, height;
139
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500140 if (resize->edges & WL_SHELL_RESIZE_LEFT) {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500141 width = device->grab_x - x + resize->width;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500142 } else if (resize->edges & WL_SHELL_RESIZE_RIGHT) {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500143 width = x - device->grab_x + resize->width;
144 } else {
145 width = resize->width;
146 }
147
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500148 if (resize->edges & WL_SHELL_RESIZE_TOP) {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500149 height = device->grab_y - y + resize->height;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500150 } else if (resize->edges & WL_SHELL_RESIZE_BOTTOM) {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500151 height = y - device->grab_y + resize->height;
152 } else {
153 height = resize->height;
154 }
155
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400156 wl_resource_post_event(resize->resource,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400157 WL_SHELL_CONFIGURE, time, resize->edges,
158 surface, width, height);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500159}
160
161static void
162resize_grab_button(struct wl_grab *grab,
163 uint32_t time, int32_t button, int32_t state)
164{
165}
166
167static void
168resize_grab_end(struct wl_grab *grab, uint32_t time)
169{
170 free(grab);
171}
172
173static const struct wl_grab_interface resize_grab_interface = {
174 resize_grab_motion,
175 resize_grab_button,
176 resize_grab_end
177};
178
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400179static int
180wlsc_surface_resize(struct wlsc_surface *es,
181 struct wlsc_input_device *wd,
182 uint32_t time, uint32_t edges,
183 struct wl_resource *resource)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500184{
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500185 struct wlsc_resize_grab *resize;
186 enum wlsc_pointer_type pointer = WLSC_POINTER_LEFT_PTR;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500187
Kristian Høgsberg0ce24572011-01-28 15:18:33 -0500188 /* FIXME: Reject if fullscreen */
189
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500190 resize = malloc(sizeof *resize);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400191 if (!resize)
192 return -1;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500193
194 resize->grab.interface = &resize_grab_interface;
195 resize->edges = edges;
196 resize->dx = es->x - wd->input_device.grab_x;
197 resize->dy = es->y - wd->input_device.grab_y;
198 resize->width = es->width;
199 resize->height = es->height;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -0500200 resize->surface = es;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400201 resize->resource = resource;
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400202
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500203 if (edges == 0 || edges > 15 ||
204 (edges & 3) == 3 || (edges & 12) == 12)
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400205 return 0;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500206
207 switch (edges) {
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500208 case WL_SHELL_RESIZE_TOP:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500209 pointer = WLSC_POINTER_TOP;
210 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500211 case WL_SHELL_RESIZE_BOTTOM:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500212 pointer = WLSC_POINTER_BOTTOM;
213 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500214 case WL_SHELL_RESIZE_LEFT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500215 pointer = WLSC_POINTER_LEFT;
216 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500217 case WL_SHELL_RESIZE_TOP_LEFT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500218 pointer = WLSC_POINTER_TOP_LEFT;
219 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500220 case WL_SHELL_RESIZE_BOTTOM_LEFT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500221 pointer = WLSC_POINTER_BOTTOM_LEFT;
222 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500223 case WL_SHELL_RESIZE_RIGHT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500224 pointer = WLSC_POINTER_RIGHT;
225 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500226 case WL_SHELL_RESIZE_TOP_RIGHT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500227 pointer = WLSC_POINTER_TOP_RIGHT;
228 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500229 case WL_SHELL_RESIZE_BOTTOM_RIGHT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500230 pointer = WLSC_POINTER_BOTTOM_RIGHT;
231 break;
232 }
233
234 if (wl_input_device_update_grab(&wd->input_device,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400235 &resize->grab, &es->surface, time) < 0)
236 return 0;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500237
238 wlsc_input_device_set_pointer_image(wd, pointer);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400239 wl_input_device_set_pointer_focus(&wd->input_device,
240 NULL, time, 0, 0, 0, 0);
241
242 return 0;
243}
244
245static void
246shell_resize(struct wl_client *client, struct wl_resource *resource,
247 struct wl_resource *surface_resource,
248 struct wl_resource *input_resource, uint32_t time, uint32_t edges)
249{
250 struct wlsc_input_device *wd = input_resource->data;
251 struct wlsc_surface *es = surface_resource->data;
252
253 /* FIXME: Reject if fullscreen */
254
255 if (wlsc_surface_resize(es, wd, time, edges, resource) < 0)
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400256 wl_resource_post_no_memory(resource);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500257}
258
259static void
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400260shell_set_toplevel(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400261 struct wl_resource *resource,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400262 struct wl_resource *surface_resource)
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400263
264{
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400265 struct wlsc_surface *es = surface_resource->data;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400266
267 if (es->map_type == WLSC_SURFACE_MAP_FULLSCREEN) {
268 es->x = es->saved_x;
269 es->y = es->saved_y;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400270 }
271
272 wlsc_surface_damage(es);
273 es->map_type = WLSC_SURFACE_MAP_TOPLEVEL;
274 es->fullscreen_output = NULL;
275}
276
277static void
278shell_set_transient(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400279 struct wl_resource *resource,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400280 struct wl_resource *surface_resource,
281 struct wl_resource *parent_resource,
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400282 int x, int y, uint32_t flags)
283{
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400284 struct wlsc_surface *es = surface_resource->data;
285 struct wlsc_surface *pes = parent_resource->data;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400286
287 /* assign to parents output */
288 es->output = pes->output;
289
290 es->x = pes->x + x;
291 es->y = pes->y + y;
292
293 wlsc_surface_damage(es);
294 es->map_type = WLSC_SURFACE_MAP_TRANSIENT;
295}
296
297static void
298shell_set_fullscreen(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400299 struct wl_resource *resource,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400300 struct wl_resource *surface_resource)
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400301
302{
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400303 struct wlsc_surface *es = surface_resource->data;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400304 struct wlsc_output *output;
305
306 /* FIXME: Fullscreen on first output */
307 /* FIXME: Handle output going away */
308 output = container_of(es->compositor->output_list.next,
309 struct wlsc_output, link);
310 es->output = output;
311
312 es->saved_x = es->x;
313 es->saved_y = es->y;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400314 es->x = (output->current->width - es->width) / 2;
315 es->y = (output->current->height - es->height) / 2;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400316 es->fullscreen_output = output;
317 wlsc_surface_damage(es);
318 es->map_type = WLSC_SURFACE_MAP_FULLSCREEN;
319}
320
321static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400322destroy_drag(struct wl_resource *resource)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500323{
324 struct wl_drag *drag =
325 container_of(resource, struct wl_drag, resource);
326
327 wl_list_remove(&drag->drag_focus_listener.link);
328 if (drag->grab.input_device)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400329 wl_input_device_end_grab(drag->grab.input_device,
330 wlsc_compositor_get_time());
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500331
332 free(drag);
333}
334
335
336static void
337wl_drag_set_pointer_focus(struct wl_drag *drag,
338 struct wl_surface *surface, uint32_t time,
339 int32_t x, int32_t y, int32_t sx, int32_t sy)
340{
341 char **p, **end;
342
343 if (drag->drag_focus == surface)
344 return;
345
346 if (drag->drag_focus &&
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400347 (!surface ||
348 drag->drag_focus->resource.client != surface->resource.client))
349 wl_resource_post_event(&drag->drag_offer.resource,
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500350 WL_DRAG_OFFER_POINTER_FOCUS,
351 time, NULL, 0, 0, 0, 0);
352
353 if (surface &&
354 (!drag->drag_focus ||
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400355 drag->drag_focus->resource.client != surface->resource.client)) {
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400356
357 drag->drag_offer.resource.client = surface->resource.client;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500358 end = drag->types.data + drag->types.size;
359 for (p = drag->types.data; p < end; p++)
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400360 wl_resource_post_event(&drag->drag_offer.resource,
361 WL_DRAG_OFFER_OFFER, *p);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500362 }
363
364 if (surface) {
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400365 wl_resource_post_event(&drag->drag_offer.resource,
366 WL_DRAG_OFFER_POINTER_FOCUS,
367 time, surface,
368 x, y, sx, sy);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500369
370 }
371
372 drag->drag_focus = surface;
373 drag->pointer_focus_time = time;
374 drag->target = NULL;
375
376 wl_list_remove(&drag->drag_focus_listener.link);
377 if (surface)
Benjamin Franzke4721a3c2011-05-06 17:13:17 +0200378 wl_list_insert(surface->resource.destroy_listener_list.prev,
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500379 &drag->drag_focus_listener.link);
380}
381
382static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400383drag_offer_accept(struct wl_client *client, struct wl_resource *resource,
384 uint32_t time, const char *type)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500385{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400386 struct wl_drag_offer *offer = resource->data;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500387 struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer);
388 char **p, **end;
389
390 /* If the client responds to drag pointer_focus or motion
391 * events after the pointer has left the surface, we just
392 * discard the accept requests. The drag source just won't
393 * get the corresponding 'target' events and eventually the
394 * next surface/root will start sending events. */
395 if (time < drag->pointer_focus_time)
396 return;
397
398 drag->target = client;
399 drag->type = NULL;
400 end = drag->types.data + drag->types.size;
401 for (p = drag->types.data; p < end; p++)
402 if (type && strcmp(*p, type) == 0)
403 drag->type = *p;
404
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400405 wl_resource_post_event(&drag->resource, WL_DRAG_TARGET, drag->type);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500406}
407
408static void
409drag_offer_receive(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400410 struct wl_resource *resource, int fd)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500411{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400412 struct wl_drag_offer *offer = resource->data;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500413 struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer);
414
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400415 wl_resource_post_event(&drag->resource, WL_DRAG_FINISH, fd);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500416 close(fd);
417}
418
419static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400420drag_offer_reject(struct wl_client *client, struct wl_resource *resource)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500421{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400422 struct wl_drag_offer *offer = resource->data;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500423 struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer);
424
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400425 wl_resource_post_event(&drag->resource, WL_DRAG_REJECT);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500426}
427
428static const struct wl_drag_offer_interface drag_offer_interface = {
429 drag_offer_accept,
430 drag_offer_receive,
431 drag_offer_reject
432};
433
434static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400435drag_offer(struct wl_client *client,
436 struct wl_resource *resource, const char *type)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500437{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400438 struct wl_drag *drag = resource->data;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500439 char **p;
440
441 p = wl_array_add(&drag->types, sizeof *p);
442 if (p)
443 *p = strdup(type);
444 if (!p || !*p)
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400445 wl_resource_post_no_memory(resource);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500446}
447
448static void
449drag_grab_motion(struct wl_grab *grab,
450 uint32_t time, int32_t x, int32_t y)
451{
452 struct wl_drag *drag = container_of(grab, struct wl_drag, grab);
453 struct wlsc_surface *es;
454 int32_t sx, sy;
455
456 es = pick_surface(grab->input_device, &sx, &sy);
457 wl_drag_set_pointer_focus(drag, &es->surface, time, x, y, sx, sy);
458 if (es)
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400459 wl_resource_post_event(&drag->drag_offer.resource,
460 WL_DRAG_OFFER_MOTION,
461 time, x, y, sx, sy);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500462}
463
464static void
465drag_grab_button(struct wl_grab *grab,
466 uint32_t time, int32_t button, int32_t state)
467{
468}
469
470static void
471drag_grab_end(struct wl_grab *grab, uint32_t time)
472{
473 struct wl_drag *drag = container_of(grab, struct wl_drag, grab);
474
475 if (drag->target)
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400476 wl_resource_post_event(&drag->drag_offer.resource,
477 WL_DRAG_OFFER_DROP);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500478
479 wl_drag_set_pointer_focus(drag, NULL, time, 0, 0, 0, 0);
480}
481
482static const struct wl_grab_interface drag_grab_interface = {
483 drag_grab_motion,
484 drag_grab_button,
485 drag_grab_end
486};
487
488static void
489drag_activate(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400490 struct wl_resource *resource,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400491 struct wl_resource *surface_resource,
492 struct wl_resource *device_resource, uint32_t time)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500493{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400494 struct wl_drag *drag = resource->data;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400495 struct wl_surface *surface = surface_resource->data;
496 struct wl_input_device *device = device_resource->data;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500497 struct wl_display *display = wl_client_get_display (client);
498 struct wlsc_surface *target;
499 int32_t sx, sy;
500
501 if (wl_input_device_update_grab(device,
502 &drag->grab, surface, time) < 0)
503 return;
504
505 drag->grab.interface = &drag_grab_interface;
506
507 drag->source = surface;
508
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400509 drag->drag_offer.resource.object.interface = &wl_drag_offer_interface;
510 drag->drag_offer.resource.object.implementation =
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500511 (void (**)(void)) &drag_offer_interface;
512
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400513 wl_display_add_global(display, &wl_drag_offer_interface, drag, NULL);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500514
515 target = pick_surface(device, &sx, &sy);
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -0500516 wl_input_device_set_pointer_focus(device, NULL, time, 0, 0, 0, 0);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500517 wl_drag_set_pointer_focus(drag, &target->surface, time,
518 device->x, device->y, sx, sy);
519}
520
521static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400522drag_destroy(struct wl_client *client, struct wl_resource *resource)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500523{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400524 wl_resource_destroy(resource, wlsc_compositor_get_time());
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500525}
526
527static const struct wl_drag_interface drag_interface = {
528 drag_offer,
529 drag_activate,
530 drag_destroy,
531};
532
533static void
534drag_handle_surface_destroy(struct wl_listener *listener,
Benjamin Franzke4721a3c2011-05-06 17:13:17 +0200535 struct wl_resource *resource, uint32_t time)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500536{
537 struct wl_drag *drag =
538 container_of(listener, struct wl_drag, drag_focus_listener);
Benjamin Franzke4721a3c2011-05-06 17:13:17 +0200539 struct wl_surface *surface = (struct wl_surface *) resource;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500540
541 if (drag->drag_focus == surface)
542 wl_drag_set_pointer_focus(drag, NULL, time, 0, 0, 0, 0);
543}
544
545static void
546shell_create_drag(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400547 struct wl_resource *resource, uint32_t id)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500548{
549 struct wl_drag *drag;
550
551 drag = malloc(sizeof *drag);
552 if (drag == NULL) {
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400553 wl_resource_post_no_memory(resource);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500554 return;
555 }
556
557 memset(drag, 0, sizeof *drag);
558 drag->resource.object.id = id;
559 drag->resource.object.interface = &wl_drag_interface;
560 drag->resource.object.implementation =
561 (void (**)(void)) &drag_interface;
562
Pekka Paalanen02ebfb12011-10-24 17:34:53 +0300563 drag->resource.data = drag;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500564 drag->resource.destroy = destroy_drag;
565
566 drag->drag_focus_listener.func = drag_handle_surface_destroy;
567 wl_list_init(&drag->drag_focus_listener.link);
568
569 wl_client_add_resource(client, &drag->resource);
570}
571
Kristian Høgsberg1c562182011-05-02 22:09:20 -0400572static void
573wlsc_selection_set_focus(struct wlsc_shell *shell,
574 struct wl_selection *selection,
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500575 struct wl_surface *surface, uint32_t time)
576{
577 char **p, **end;
578
579 if (selection->selection_focus == surface)
580 return;
581
582 if (selection->selection_focus != NULL)
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400583 wl_resource_post_event(&selection->selection_offer.resource,
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500584 WL_SELECTION_OFFER_KEYBOARD_FOCUS,
585 NULL);
586
587 if (surface) {
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500588
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400589 selection->selection_offer.resource.client = surface->resource.client;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500590 end = selection->types.data + selection->types.size;
591 for (p = selection->types.data; p < end; p++)
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400592 wl_resource_post_event(&selection->selection_offer.resource,
593 WL_SELECTION_OFFER_OFFER, *p);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500594
595 wl_list_remove(&selection->selection_focus_listener.link);
Benjamin Franzke4721a3c2011-05-06 17:13:17 +0200596 wl_list_insert(surface->resource.destroy_listener_list.prev,
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500597 &selection->selection_focus_listener.link);
598
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400599 wl_resource_post_event(&selection->selection_offer.resource,
600 WL_SELECTION_OFFER_KEYBOARD_FOCUS,
601 selection->input_device);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500602 }
603
604 selection->selection_focus = surface;
605
606 wl_list_remove(&selection->selection_focus_listener.link);
607 if (surface)
Benjamin Franzke4721a3c2011-05-06 17:13:17 +0200608 wl_list_insert(surface->resource.destroy_listener_list.prev,
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500609 &selection->selection_focus_listener.link);
610}
611
612static void
613selection_offer_receive(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400614 struct wl_resource *resource,
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500615 const char *mime_type, int fd)
616{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400617 struct wl_selection_offer *offer = resource->data;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500618 struct wl_selection *selection =
619 container_of(offer, struct wl_selection, selection_offer);
620
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400621 wl_resource_post_event(&selection->resource,
622 WL_SELECTION_SEND, mime_type, fd);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500623 close(fd);
624}
625
626static const struct wl_selection_offer_interface selection_offer_interface = {
627 selection_offer_receive
628};
629
630static void
631selection_offer(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400632 struct wl_resource *resource, const char *type)
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500633{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400634 struct wl_selection *selection = resource->data;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500635 char **p;
636
637 p = wl_array_add(&selection->types, sizeof *p);
638 if (p)
639 *p = strdup(type);
640 if (!p || !*p)
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400641 wl_resource_post_no_memory(resource);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500642}
643
644static void
645selection_activate(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400646 struct wl_resource *resource,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400647 struct wl_resource *input_resource, uint32_t time)
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500648{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400649 struct wl_selection *selection = resource->data;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400650 struct wlsc_input_device *wd = input_resource->data;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500651 struct wl_display *display = wl_client_get_display (client);
Kristian Høgsberg1c562182011-05-02 22:09:20 -0400652 struct wlsc_compositor *compositor =
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400653 (struct wlsc_compositor *) wd->input_device.compositor;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500654
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400655 selection->input_device = &wd->input_device;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500656
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400657 selection->selection_offer.resource.object.interface =
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500658 &wl_selection_offer_interface;
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400659 selection->selection_offer.resource.object.implementation =
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500660 (void (**)(void)) &selection_offer_interface;
661
Kristian Høgsbergd9551a32011-08-19 12:07:44 -0400662 wl_display_add_global(display,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400663 &wl_selection_offer_interface, selection, NULL);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500664
665 if (wd->selection) {
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400666 wl_resource_post_event(&wd->selection->resource,
667 WL_SELECTION_CANCELLED);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500668 }
669 wd->selection = selection;
670
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400671 wlsc_selection_set_focus(compositor->shell, selection,
672 wd->input_device.keyboard_focus, time);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500673}
674
675static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400676selection_destroy(struct wl_client *client, struct wl_resource *resource)
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500677{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400678 wl_resource_destroy(resource, wlsc_compositor_get_time());
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500679}
680
681static const struct wl_selection_interface selection_interface = {
682 selection_offer,
683 selection_activate,
684 selection_destroy
685};
686
687static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400688destroy_selection(struct wl_resource *resource)
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500689{
690 struct wl_selection *selection =
691 container_of(resource, struct wl_selection, resource);
692 struct wlsc_input_device *wd =
693 (struct wlsc_input_device *) selection->input_device;
Kristian Høgsberg1c562182011-05-02 22:09:20 -0400694 struct wlsc_compositor *compositor =
695 (struct wlsc_compositor *) wd->input_device.compositor;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500696
697 if (wd && wd->selection == selection) {
698 wd->selection = NULL;
Kristian Høgsberg1c562182011-05-02 22:09:20 -0400699 wlsc_selection_set_focus(compositor->shell,
700 selection, NULL,
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400701 wlsc_compositor_get_time());
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500702 }
703
704 wl_list_remove(&selection->selection_focus_listener.link);
705 free(selection);
706}
707
708static void
709selection_handle_surface_destroy(struct wl_listener *listener,
Benjamin Franzke4721a3c2011-05-06 17:13:17 +0200710 struct wl_resource *resource, uint32_t time)
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500711{
712}
713
714static void
715shell_create_selection(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400716 struct wl_resource *resource, uint32_t id)
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500717{
718 struct wl_selection *selection;
719
720 selection = malloc(sizeof *selection);
721 if (selection == NULL) {
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400722 wl_resource_post_no_memory(resource);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500723 return;
724 }
725
726 memset(selection, 0, sizeof *selection);
727 selection->resource.object.id = id;
728 selection->resource.object.interface = &wl_selection_interface;
729 selection->resource.object.implementation =
730 (void (**)(void)) &selection_interface;
731
732 selection->client = client;
733 selection->resource.destroy = destroy_selection;
734 selection->selection_focus = NULL;
735
736 selection->selection_focus_listener.func =
737 selection_handle_surface_destroy;
738 wl_list_init(&selection->selection_focus_listener.link);
739
740 wl_client_add_resource(client, &selection->resource);
741}
742
Kristian Høgsberg75840622011-09-06 13:48:16 -0400743static const struct wl_shell_interface shell_interface = {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500744 shell_move,
745 shell_resize,
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500746 shell_create_drag,
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400747 shell_create_selection,
748 shell_set_toplevel,
749 shell_set_transient,
750 shell_set_fullscreen
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500751};
752
Kristian Høgsberg07937562011-04-12 17:25:42 -0400753static void
Kristian Høgsberg75840622011-09-06 13:48:16 -0400754handle_background_surface_destroy(struct wl_listener *listener,
755 struct wl_resource *resource, uint32_t time)
756{
757 struct wl_shell *shell =
758 container_of(listener, struct wl_shell, background_listener);
759
760 fprintf(stderr, "background surface gone\n");
761 shell->background = NULL;
762}
763
764static void
765desktop_shell_set_background(struct wl_client *client,
766 struct wl_resource *resource,
767 struct wl_resource *surface_resource)
768{
769 struct wl_shell *shell = resource->data;
770 struct wlsc_surface *surface = surface_resource->data;
771 struct wlsc_output *output =
772 container_of(shell->compositor->output_list.next,
773 struct wlsc_output, link);
774
775 shell->background = surface_resource->data;
776 shell->background_listener.func = handle_background_surface_destroy;
777 wl_list_insert(&surface_resource->destroy_listener_list,
778 &shell->background_listener.link);
779
780 wl_resource_post_event(resource,
781 DESKTOP_SHELL_CONFIGURE,
782 wlsc_compositor_get_time(), 0, surface,
783 output->current->width,
784 output->current->height);
785}
786
787static void
788handle_panel_surface_destroy(struct wl_listener *listener,
789 struct wl_resource *resource, uint32_t time)
790{
791 struct wl_shell *shell =
792 container_of(listener, struct wl_shell, panel_listener);
793
794 fprintf(stderr, "panel surface gone\n");
795 shell->panel = NULL;
796}
797
798static void
799desktop_shell_set_panel(struct wl_client *client,
800 struct wl_resource *resource,
801 struct wl_resource *surface_resource)
802{
803 struct wl_shell *shell = resource->data;
804 struct wlsc_output *output =
805 container_of(shell->compositor->output_list.next,
806 struct wlsc_output, link);
807
808 shell->panel = surface_resource->data;
809
810 shell->panel_listener.func = handle_panel_surface_destroy;
811 wl_list_insert(&surface_resource->destroy_listener_list,
812 &shell->panel_listener.link);
813
814 wl_resource_post_event(resource,
815 DESKTOP_SHELL_CONFIGURE,
816 wlsc_compositor_get_time(), 0, surface_resource,
817 output->current->width,
818 output->current->height);
819}
820
821static const struct desktop_shell_interface desktop_shell_implementation = {
822 desktop_shell_set_background,
823 desktop_shell_set_panel
824};
825
826static void
Kristian Høgsberg07937562011-04-12 17:25:42 -0400827move_binding(struct wl_input_device *device, uint32_t time,
828 uint32_t key, uint32_t button, uint32_t state, void *data)
829{
Kristian Høgsberg75840622011-09-06 13:48:16 -0400830 struct wl_shell *shell = data;
Kristian Høgsberg07937562011-04-12 17:25:42 -0400831 struct wlsc_surface *surface =
832 (struct wlsc_surface *) device->pointer_focus;
833
Kristian Høgsberga4a42f02011-09-08 16:56:57 -0400834 if (surface == NULL ||
835 surface->map_type == WLSC_SURFACE_MAP_FULLSCREEN)
Kristian Høgsberg10f097e2011-04-13 11:52:54 -0400836 return;
Kristian Høgsberg75840622011-09-06 13:48:16 -0400837 if (surface == shell->panel)
838 return;
839 if (surface == shell->background)
840 return;
Kristian Høgsberg10f097e2011-04-13 11:52:54 -0400841
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400842 wlsc_surface_move(surface, (struct wlsc_input_device *) device, time);
Kristian Høgsberg07937562011-04-12 17:25:42 -0400843}
844
845static void
846resize_binding(struct wl_input_device *device, uint32_t time,
847 uint32_t key, uint32_t button, uint32_t state, void *data)
848{
Kristian Høgsberg75840622011-09-06 13:48:16 -0400849 struct wl_shell *shell = data;
Kristian Høgsberg07937562011-04-12 17:25:42 -0400850 struct wlsc_surface *surface =
851 (struct wlsc_surface *) device->pointer_focus;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400852 struct wl_resource *resource;
Kristian Høgsberg07937562011-04-12 17:25:42 -0400853 uint32_t edges = 0;
854 int32_t x, y;
855
Kristian Høgsberga4a42f02011-09-08 16:56:57 -0400856 if (surface == NULL ||
857 surface->map_type == WLSC_SURFACE_MAP_FULLSCREEN)
Kristian Høgsberg75840622011-09-06 13:48:16 -0400858 if (surface == shell->panel)
859 return;
860 if (surface == shell->background)
861 return;
Kristian Høgsberg10f097e2011-04-13 11:52:54 -0400862
Kristian Høgsberg07937562011-04-12 17:25:42 -0400863 x = device->grab_x - surface->x;
864 y = device->grab_y - surface->y;
865
866 if (x < surface->width / 3)
867 edges |= WL_SHELL_RESIZE_LEFT;
868 else if (x < 2 * surface->width / 3)
869 edges |= 0;
870 else
871 edges |= WL_SHELL_RESIZE_RIGHT;
872
873 if (y < surface->height / 3)
874 edges |= WL_SHELL_RESIZE_TOP;
875 else if (y < 2 * surface->height / 3)
876 edges |= 0;
877 else
878 edges |= WL_SHELL_RESIZE_BOTTOM;
879
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400880 resource = /* Find shell resource for surface client */ 0;
881
882 /* ... or use wl_shell_surface */
883
884 wlsc_surface_resize(surface, (struct wlsc_input_device *) device,
885 time, edges, resource);
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400886}
887
888static void
Kristian Høgsberg75840622011-09-06 13:48:16 -0400889activate(struct wlsc_shell *base, struct wlsc_surface *es,
890 struct wlsc_input_device *device, uint32_t time)
891{
892 struct wl_shell *shell = container_of(base, struct wl_shell, shell);
893 struct wlsc_compositor *compositor = shell->compositor;
894
895 wlsc_surface_activate(es, device, time);
896
Kristian Høgsbergd6e55252011-10-11 23:41:17 -0400897 if (compositor->wxs)
898 wlsc_xserver_surface_activate(es);
899
Kristian Høgsberg75840622011-09-06 13:48:16 -0400900 if (es == shell->background) {
901 wl_list_remove(&es->link);
902 wl_list_insert(compositor->surface_list.prev, &es->link);
903 } else if (shell->panel) {
904 wl_list_remove(&shell->panel->link);
905 wl_list_insert(&compositor->surface_list, &shell->panel->link);
906 }
907}
908
909static void
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400910lock(struct wlsc_shell *shell)
911{
912}
913
914static void
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -0500915map(struct wlsc_shell *base,
916 struct wlsc_surface *surface, int32_t width, int32_t height)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400917{
Kristian Høgsberg75840622011-09-06 13:48:16 -0400918 struct wl_shell *shell = container_of(base, struct wl_shell, shell);
919 struct wlsc_compositor *compositor = shell->compositor;
920
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -0500921 /* Map background at the bottom of the stack, panel on top,
922 everything else just below panel. */
923 if (surface == shell->background)
924 wl_list_insert(compositor->surface_list.prev, &surface->link);
925 else if (surface == shell->panel)
926 wl_list_insert(&compositor->surface_list, &surface->link);
927 else
928 wl_list_insert(&shell->panel->link, &surface->link);
929
Kristian Høgsberg46770132011-11-09 12:38:53 -0500930 if (surface->map_type == WLSC_SURFACE_MAP_TOPLEVEL) {
931 surface->x = 10 + random() % 400;
932 surface->y = 10 + random() % 400;
933 }
934
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -0500935 wlsc_surface_configure(surface, surface->x, surface->y, width, height);
936}
937
938static void
939configure(struct wlsc_shell *shell, struct wlsc_surface *surface,
940 int32_t x, int32_t y, int32_t width, int32_t height)
941{
942 struct wlsc_mode *current;
943
944 if (surface->map_type == WLSC_SURFACE_MAP_FULLSCREEN) {
945 current = surface->fullscreen_output->current;
946 x = (current->width - surface->width) / 2;
947 y = (current->height - surface->height) / 2;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400948 }
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -0500949
950 wlsc_surface_configure(surface, x, y, width, height);
Kristian Høgsberg07937562011-04-12 17:25:42 -0400951}
952
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400953static void
Pekka Paalanen6cd281a2011-11-03 14:11:32 +0200954desktop_shell_sigchld(struct wlsc_process *process, int status)
955{
956 struct wl_shell *shell =
957 container_of(process, struct wl_shell, child.process);
958
959 shell->child.process.pid = 0;
960 shell->child.client = NULL; /* already destroyed by wayland */
961}
962
963static int
964launch_desktop_shell_process(struct wl_shell *shell)
965{
966 const char *shell_exe = "./clients/desktop-shell";
967 struct wlsc_compositor *compositor = shell->compositor;
968 char s[32];
969 int sv[2], flags;
970
971 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) {
972 fprintf(stderr, "socketpair failed\n");
973 return -1;
974 }
975
976 shell->child.process.pid = fork();
977 shell->child.process.cleanup = desktop_shell_sigchld;
978
979 switch (shell->child.process.pid) {
980 case 0:
981 /* SOCK_CLOEXEC closes both ends, so we need to unset
982 * the flag on the client fd. */
983 flags = fcntl(sv[1], F_GETFD);
984 if (flags != -1)
985 fcntl(sv[1], F_SETFD, flags & ~FD_CLOEXEC);
986
987 snprintf(s, sizeof s, "%d", sv[1]);
988 setenv("WAYLAND_SOCKET", s, 1);
989 if (execl(shell_exe, shell_exe, NULL) < 0)
990 fprintf(stderr, "%s: running '%s' failed: %m\n",
991 __func__, shell_exe);
992 exit(-1);
993
994 default:
995 close(sv[1]);
996 shell->child.client =
997 wl_client_create(compositor->wl_display, sv[0]);
998 wlsc_watch_process(&shell->child.process);
999 break;
1000
1001 case -1:
1002 fprintf(stderr, "%s: fork failed: %m\n", __func__);
1003 return -1;
1004 }
1005 return 0;
1006}
1007
1008static void
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001009bind_shell(struct wl_client *client, void *data, uint32_t version, uint32_t id)
1010{
1011 struct wl_shell *shell = data;
1012
1013 wl_client_add_object(client, &wl_shell_interface,
1014 &shell_interface, id, shell);
1015}
1016
Kristian Høgsberg75840622011-09-06 13:48:16 -04001017static void
1018bind_desktop_shell(struct wl_client *client,
1019 void *data, uint32_t version, uint32_t id)
1020{
1021 struct wl_shell *shell = data;
Pekka Paalanenbbe60522011-11-03 14:11:33 +02001022 struct wl_resource *resource;
Kristian Høgsberg75840622011-09-06 13:48:16 -04001023
Pekka Paalanenbbe60522011-11-03 14:11:33 +02001024 resource = wl_client_add_object(client, &desktop_shell_interface,
1025 &desktop_shell_implementation,
1026 id, shell);
1027
1028 if (client == shell->child.client)
1029 return;
1030
1031 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
1032 "permission to bind desktop_shell denied");
1033 wl_resource_destroy(resource, 0);
Kristian Høgsberg75840622011-09-06 13:48:16 -04001034}
1035
Kristian Høgsberg6c709a32011-05-06 14:52:41 -04001036int
1037shell_init(struct wlsc_compositor *ec);
1038
Kristian Høgsberg1c562182011-05-02 22:09:20 -04001039WL_EXPORT int
1040shell_init(struct wlsc_compositor *ec)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001041{
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001042 struct wl_shell *shell;
1043
1044 shell = malloc(sizeof *shell);
1045 if (shell == NULL)
1046 return -1;
1047
Kristian Høgsbergf0d91162011-10-11 22:44:23 -04001048 memset(shell, 0, sizeof *shell);
Kristian Høgsberg75840622011-09-06 13:48:16 -04001049 shell->compositor = ec;
1050 shell->shell.activate = activate;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001051 shell->shell.lock = lock;
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05001052 shell->shell.map = map;
1053 shell->shell.configure = configure;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04001054 shell->shell.set_selection_focus = wlsc_selection_set_focus;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001055
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001056 if (wl_display_add_global(ec->wl_display, &wl_shell_interface,
1057 shell, bind_shell) == NULL)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001058 return -1;
1059
Kristian Høgsberg75840622011-09-06 13:48:16 -04001060 if (wl_display_add_global(ec->wl_display,
1061 &desktop_shell_interface,
1062 shell, bind_desktop_shell) == NULL)
1063 return -1;
1064
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02001065 if (launch_desktop_shell_process(shell) != 0)
1066 return -1;
1067
Kristian Høgsberg07937562011-04-12 17:25:42 -04001068 wlsc_compositor_add_binding(ec, 0, BTN_LEFT, MODIFIER_SUPER,
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001069 move_binding, shell);
Kristian Høgsberg07937562011-04-12 17:25:42 -04001070 wlsc_compositor_add_binding(ec, 0, BTN_MIDDLE, MODIFIER_SUPER,
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001071 resize_binding, shell);
1072
1073 ec->shell = &shell->shell;
Kristian Høgsberg07937562011-04-12 17:25:42 -04001074
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001075 return 0;
1076}