blob: 0fd5e7f9287edf4013ef0a91811f365f4f12a42b [file] [log] [blame]
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001/*
2 * Copyright © 2010 Intel Corporation
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02003 * Copyright © 2011 Collabora, Ltd.
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05004 *
5 * Permission to use, copy, modify, distribute, and sell this software and
6 * its documentation for any purpose is hereby granted without fee, provided
7 * that the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of the copyright holders not be used in
10 * advertising or publicity pertaining to distribution of the software
11 * without specific, written prior permission. The copyright holders make
12 * no representations about the suitability of this software for any
13 * purpose. It is provided "as is" without express or implied warranty.
14 *
15 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
16 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
20 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 */
23
24#include <stdlib.h>
Kristian Høgsberg75840622011-09-06 13:48:16 -040025#include <stdio.h>
Pekka Paalanen9ef3e012011-11-15 13:34:48 +020026#include <stdbool.h>
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050027#include <string.h>
28#include <unistd.h>
Kristian Høgsberg07937562011-04-12 17:25:42 -040029#include <linux/input.h>
Pekka Paalanen6cd281a2011-11-03 14:11:32 +020030#include <sys/types.h>
31#include <sys/socket.h>
32#include <fcntl.h>
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +020033#include <assert.h>
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050034
35#include "wayland-server.h"
36#include "compositor.h"
Kristian Høgsberg75840622011-09-06 13:48:16 -040037#include "desktop-shell-server-protocol.h"
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050038
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -040039struct wl_shell {
Kristian Høgsberg75840622011-09-06 13:48:16 -040040 struct wlsc_compositor *compositor;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -040041 struct wlsc_shell shell;
Kristian Høgsberg75840622011-09-06 13:48:16 -040042 struct wlsc_surface *panel;
43 struct wl_listener panel_listener;
44 struct wlsc_surface *background;
45 struct wl_listener background_listener;
Pekka Paalanen6cd281a2011-11-03 14:11:32 +020046
47 struct {
48 struct wlsc_process process;
49 struct wl_client *client;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +020050 struct wl_resource *desktop_shell;
Pekka Paalanen6cd281a2011-11-03 14:11:32 +020051 } child;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +020052
53 bool locked;
54 bool prepare_event_sent;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +020055
56 struct wl_list hidden_surface_list;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -040057};
58
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +020059struct hidden_surface {
60 struct wlsc_surface *surface;
61 struct wl_listener destroy_listener;
62 struct wl_shell *shell;
63
64 struct wl_list link;
65};
66
67static void
68hidden_surface_destroy(struct hidden_surface *hidden)
69{
70 wl_list_remove(&hidden->link);
71 wl_list_remove(&hidden->destroy_listener.link);
72 free(hidden);
73}
74
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050075struct wlsc_move_grab {
76 struct wl_grab grab;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -050077 struct wlsc_surface *surface;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050078 int32_t dx, dy;
79};
80
81static void
82move_grab_motion(struct wl_grab *grab,
83 uint32_t time, int32_t x, int32_t y)
84{
85 struct wlsc_move_grab *move = (struct wlsc_move_grab *) grab;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -050086 struct wlsc_surface *es = move->surface;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050087
Kristian Høgsberga691aee2011-06-23 21:43:50 -040088 wlsc_surface_configure(es, x + move->dx, y + move->dy,
89 es->width, es->height);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050090}
91
92static void
93move_grab_button(struct wl_grab *grab,
94 uint32_t time, int32_t button, int32_t state)
95{
96}
97
98static void
99move_grab_end(struct wl_grab *grab, uint32_t time)
100{
101 free(grab);
102}
103
104static const struct wl_grab_interface move_grab_interface = {
105 move_grab_motion,
106 move_grab_button,
107 move_grab_end
108};
109
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400110static int
111wlsc_surface_move(struct wlsc_surface *es,
112 struct wlsc_input_device *wd, uint32_t time)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500113{
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500114 struct wlsc_move_grab *move;
115
116 move = malloc(sizeof *move);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400117 if (!move)
118 return -1;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500119
120 move->grab.interface = &move_grab_interface;
121 move->dx = es->x - wd->input_device.grab_x;
122 move->dy = es->y - wd->input_device.grab_y;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -0500123 move->surface = es;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500124
125 if (wl_input_device_update_grab(&wd->input_device,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400126 &move->grab, &es->surface, time) < 0)
127 return 0;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500128
129 wlsc_input_device_set_pointer_image(wd, WLSC_POINTER_DRAGGING);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400130 wl_input_device_set_pointer_focus(&wd->input_device,
131 NULL, time, 0, 0, 0, 0);
132
133 return 0;
134}
135
136static void
137shell_move(struct wl_client *client, struct wl_resource *resource,
138 struct wl_resource *surface_resource,
139 struct wl_resource *input_resource, uint32_t time)
140{
141 struct wlsc_input_device *wd = input_resource->data;
142 struct wlsc_surface *es = surface_resource->data;
143
144 if (wlsc_surface_move(es, wd, time) < 0)
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400145 wl_resource_post_no_memory(resource);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500146}
147
148struct wlsc_resize_grab {
149 struct wl_grab grab;
150 uint32_t edges;
151 int32_t dx, dy, width, height;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -0500152 struct wlsc_surface *surface;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400153 struct wl_resource *resource;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500154};
155
156static void
157resize_grab_motion(struct wl_grab *grab,
158 uint32_t time, int32_t x, int32_t y)
159{
160 struct wlsc_resize_grab *resize = (struct wlsc_resize_grab *) grab;
161 struct wl_input_device *device = grab->input_device;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -0500162 struct wl_surface *surface = &resize->surface->surface;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500163 int32_t width, height;
164
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500165 if (resize->edges & WL_SHELL_RESIZE_LEFT) {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500166 width = device->grab_x - x + resize->width;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500167 } else if (resize->edges & WL_SHELL_RESIZE_RIGHT) {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500168 width = x - device->grab_x + resize->width;
169 } else {
170 width = resize->width;
171 }
172
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500173 if (resize->edges & WL_SHELL_RESIZE_TOP) {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500174 height = device->grab_y - y + resize->height;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500175 } else if (resize->edges & WL_SHELL_RESIZE_BOTTOM) {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500176 height = y - device->grab_y + resize->height;
177 } else {
178 height = resize->height;
179 }
180
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400181 wl_resource_post_event(resize->resource,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400182 WL_SHELL_CONFIGURE, time, resize->edges,
183 surface, width, height);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500184}
185
186static void
187resize_grab_button(struct wl_grab *grab,
188 uint32_t time, int32_t button, int32_t state)
189{
190}
191
192static void
193resize_grab_end(struct wl_grab *grab, uint32_t time)
194{
195 free(grab);
196}
197
198static const struct wl_grab_interface resize_grab_interface = {
199 resize_grab_motion,
200 resize_grab_button,
201 resize_grab_end
202};
203
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400204static int
205wlsc_surface_resize(struct wlsc_surface *es,
206 struct wlsc_input_device *wd,
207 uint32_t time, uint32_t edges,
208 struct wl_resource *resource)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500209{
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500210 struct wlsc_resize_grab *resize;
211 enum wlsc_pointer_type pointer = WLSC_POINTER_LEFT_PTR;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500212
Kristian Høgsberg0ce24572011-01-28 15:18:33 -0500213 /* FIXME: Reject if fullscreen */
214
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500215 resize = malloc(sizeof *resize);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400216 if (!resize)
217 return -1;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500218
219 resize->grab.interface = &resize_grab_interface;
220 resize->edges = edges;
221 resize->dx = es->x - wd->input_device.grab_x;
222 resize->dy = es->y - wd->input_device.grab_y;
223 resize->width = es->width;
224 resize->height = es->height;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -0500225 resize->surface = es;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400226 resize->resource = resource;
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400227
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500228 if (edges == 0 || edges > 15 ||
229 (edges & 3) == 3 || (edges & 12) == 12)
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400230 return 0;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500231
232 switch (edges) {
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500233 case WL_SHELL_RESIZE_TOP:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500234 pointer = WLSC_POINTER_TOP;
235 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500236 case WL_SHELL_RESIZE_BOTTOM:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500237 pointer = WLSC_POINTER_BOTTOM;
238 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500239 case WL_SHELL_RESIZE_LEFT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500240 pointer = WLSC_POINTER_LEFT;
241 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500242 case WL_SHELL_RESIZE_TOP_LEFT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500243 pointer = WLSC_POINTER_TOP_LEFT;
244 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500245 case WL_SHELL_RESIZE_BOTTOM_LEFT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500246 pointer = WLSC_POINTER_BOTTOM_LEFT;
247 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500248 case WL_SHELL_RESIZE_RIGHT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500249 pointer = WLSC_POINTER_RIGHT;
250 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500251 case WL_SHELL_RESIZE_TOP_RIGHT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500252 pointer = WLSC_POINTER_TOP_RIGHT;
253 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500254 case WL_SHELL_RESIZE_BOTTOM_RIGHT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500255 pointer = WLSC_POINTER_BOTTOM_RIGHT;
256 break;
257 }
258
259 if (wl_input_device_update_grab(&wd->input_device,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400260 &resize->grab, &es->surface, time) < 0)
261 return 0;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500262
263 wlsc_input_device_set_pointer_image(wd, pointer);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400264 wl_input_device_set_pointer_focus(&wd->input_device,
265 NULL, time, 0, 0, 0, 0);
266
267 return 0;
268}
269
270static void
271shell_resize(struct wl_client *client, struct wl_resource *resource,
272 struct wl_resource *surface_resource,
273 struct wl_resource *input_resource, uint32_t time, uint32_t edges)
274{
275 struct wlsc_input_device *wd = input_resource->data;
276 struct wlsc_surface *es = surface_resource->data;
277
278 /* FIXME: Reject if fullscreen */
279
280 if (wlsc_surface_resize(es, wd, time, edges, resource) < 0)
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400281 wl_resource_post_no_memory(resource);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500282}
283
284static void
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400285shell_set_toplevel(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400286 struct wl_resource *resource,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400287 struct wl_resource *surface_resource)
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400288
289{
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400290 struct wlsc_surface *es = surface_resource->data;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400291
292 if (es->map_type == WLSC_SURFACE_MAP_FULLSCREEN) {
293 es->x = es->saved_x;
294 es->y = es->saved_y;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400295 }
296
297 wlsc_surface_damage(es);
298 es->map_type = WLSC_SURFACE_MAP_TOPLEVEL;
299 es->fullscreen_output = NULL;
300}
301
302static void
303shell_set_transient(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400304 struct wl_resource *resource,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400305 struct wl_resource *surface_resource,
306 struct wl_resource *parent_resource,
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400307 int x, int y, uint32_t flags)
308{
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400309 struct wlsc_surface *es = surface_resource->data;
310 struct wlsc_surface *pes = parent_resource->data;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400311
312 /* assign to parents output */
313 es->output = pes->output;
314
315 es->x = pes->x + x;
316 es->y = pes->y + y;
317
318 wlsc_surface_damage(es);
319 es->map_type = WLSC_SURFACE_MAP_TRANSIENT;
320}
321
322static void
323shell_set_fullscreen(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400324 struct wl_resource *resource,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400325 struct wl_resource *surface_resource)
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400326
327{
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400328 struct wlsc_surface *es = surface_resource->data;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400329 struct wlsc_output *output;
330
331 /* FIXME: Fullscreen on first output */
332 /* FIXME: Handle output going away */
333 output = container_of(es->compositor->output_list.next,
334 struct wlsc_output, link);
335 es->output = output;
336
337 es->saved_x = es->x;
338 es->saved_y = es->y;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400339 es->x = (output->current->width - es->width) / 2;
340 es->y = (output->current->height - es->height) / 2;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400341 es->fullscreen_output = output;
342 wlsc_surface_damage(es);
343 es->map_type = WLSC_SURFACE_MAP_FULLSCREEN;
344}
345
346static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400347destroy_drag(struct wl_resource *resource)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500348{
349 struct wl_drag *drag =
350 container_of(resource, struct wl_drag, resource);
351
352 wl_list_remove(&drag->drag_focus_listener.link);
353 if (drag->grab.input_device)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400354 wl_input_device_end_grab(drag->grab.input_device,
355 wlsc_compositor_get_time());
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500356
357 free(drag);
358}
359
360
361static void
362wl_drag_set_pointer_focus(struct wl_drag *drag,
363 struct wl_surface *surface, uint32_t time,
364 int32_t x, int32_t y, int32_t sx, int32_t sy)
365{
366 char **p, **end;
367
368 if (drag->drag_focus == surface)
369 return;
370
371 if (drag->drag_focus &&
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400372 (!surface ||
373 drag->drag_focus->resource.client != surface->resource.client))
374 wl_resource_post_event(&drag->drag_offer.resource,
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500375 WL_DRAG_OFFER_POINTER_FOCUS,
376 time, NULL, 0, 0, 0, 0);
377
378 if (surface &&
379 (!drag->drag_focus ||
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400380 drag->drag_focus->resource.client != surface->resource.client)) {
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400381
382 drag->drag_offer.resource.client = surface->resource.client;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500383 end = drag->types.data + drag->types.size;
384 for (p = drag->types.data; p < end; p++)
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400385 wl_resource_post_event(&drag->drag_offer.resource,
386 WL_DRAG_OFFER_OFFER, *p);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500387 }
388
389 if (surface) {
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400390 wl_resource_post_event(&drag->drag_offer.resource,
391 WL_DRAG_OFFER_POINTER_FOCUS,
392 time, surface,
393 x, y, sx, sy);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500394
395 }
396
397 drag->drag_focus = surface;
398 drag->pointer_focus_time = time;
399 drag->target = NULL;
400
401 wl_list_remove(&drag->drag_focus_listener.link);
402 if (surface)
Benjamin Franzke4721a3c2011-05-06 17:13:17 +0200403 wl_list_insert(surface->resource.destroy_listener_list.prev,
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500404 &drag->drag_focus_listener.link);
405}
406
407static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400408drag_offer_accept(struct wl_client *client, struct wl_resource *resource,
409 uint32_t time, const char *type)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500410{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400411 struct wl_drag_offer *offer = resource->data;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500412 struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer);
413 char **p, **end;
414
415 /* If the client responds to drag pointer_focus or motion
416 * events after the pointer has left the surface, we just
417 * discard the accept requests. The drag source just won't
418 * get the corresponding 'target' events and eventually the
419 * next surface/root will start sending events. */
420 if (time < drag->pointer_focus_time)
421 return;
422
423 drag->target = client;
424 drag->type = NULL;
425 end = drag->types.data + drag->types.size;
426 for (p = drag->types.data; p < end; p++)
427 if (type && strcmp(*p, type) == 0)
428 drag->type = *p;
429
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400430 wl_resource_post_event(&drag->resource, WL_DRAG_TARGET, drag->type);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500431}
432
433static void
434drag_offer_receive(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400435 struct wl_resource *resource, int fd)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500436{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400437 struct wl_drag_offer *offer = resource->data;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500438 struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer);
439
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400440 wl_resource_post_event(&drag->resource, WL_DRAG_FINISH, fd);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500441 close(fd);
442}
443
444static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400445drag_offer_reject(struct wl_client *client, struct wl_resource *resource)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500446{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400447 struct wl_drag_offer *offer = resource->data;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500448 struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer);
449
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400450 wl_resource_post_event(&drag->resource, WL_DRAG_REJECT);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500451}
452
453static const struct wl_drag_offer_interface drag_offer_interface = {
454 drag_offer_accept,
455 drag_offer_receive,
456 drag_offer_reject
457};
458
459static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400460drag_offer(struct wl_client *client,
461 struct wl_resource *resource, const char *type)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500462{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400463 struct wl_drag *drag = resource->data;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500464 char **p;
465
466 p = wl_array_add(&drag->types, sizeof *p);
467 if (p)
468 *p = strdup(type);
469 if (!p || !*p)
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400470 wl_resource_post_no_memory(resource);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500471}
472
473static void
474drag_grab_motion(struct wl_grab *grab,
475 uint32_t time, int32_t x, int32_t y)
476{
477 struct wl_drag *drag = container_of(grab, struct wl_drag, grab);
478 struct wlsc_surface *es;
479 int32_t sx, sy;
480
481 es = pick_surface(grab->input_device, &sx, &sy);
482 wl_drag_set_pointer_focus(drag, &es->surface, time, x, y, sx, sy);
483 if (es)
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400484 wl_resource_post_event(&drag->drag_offer.resource,
485 WL_DRAG_OFFER_MOTION,
486 time, x, y, sx, sy);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500487}
488
489static void
490drag_grab_button(struct wl_grab *grab,
491 uint32_t time, int32_t button, int32_t state)
492{
493}
494
495static void
496drag_grab_end(struct wl_grab *grab, uint32_t time)
497{
498 struct wl_drag *drag = container_of(grab, struct wl_drag, grab);
499
500 if (drag->target)
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400501 wl_resource_post_event(&drag->drag_offer.resource,
502 WL_DRAG_OFFER_DROP);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500503
504 wl_drag_set_pointer_focus(drag, NULL, time, 0, 0, 0, 0);
505}
506
507static const struct wl_grab_interface drag_grab_interface = {
508 drag_grab_motion,
509 drag_grab_button,
510 drag_grab_end
511};
512
513static void
514drag_activate(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400515 struct wl_resource *resource,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400516 struct wl_resource *surface_resource,
517 struct wl_resource *device_resource, uint32_t time)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500518{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400519 struct wl_drag *drag = resource->data;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400520 struct wl_surface *surface = surface_resource->data;
521 struct wl_input_device *device = device_resource->data;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500522 struct wl_display *display = wl_client_get_display (client);
523 struct wlsc_surface *target;
524 int32_t sx, sy;
525
526 if (wl_input_device_update_grab(device,
527 &drag->grab, surface, time) < 0)
528 return;
529
530 drag->grab.interface = &drag_grab_interface;
531
532 drag->source = surface;
533
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400534 drag->drag_offer.resource.object.interface = &wl_drag_offer_interface;
535 drag->drag_offer.resource.object.implementation =
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500536 (void (**)(void)) &drag_offer_interface;
537
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400538 wl_display_add_global(display, &wl_drag_offer_interface, drag, NULL);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500539
540 target = pick_surface(device, &sx, &sy);
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -0500541 wl_input_device_set_pointer_focus(device, NULL, time, 0, 0, 0, 0);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500542 wl_drag_set_pointer_focus(drag, &target->surface, time,
543 device->x, device->y, sx, sy);
544}
545
546static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400547drag_destroy(struct wl_client *client, struct wl_resource *resource)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500548{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400549 wl_resource_destroy(resource, wlsc_compositor_get_time());
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500550}
551
552static const struct wl_drag_interface drag_interface = {
553 drag_offer,
554 drag_activate,
555 drag_destroy,
556};
557
558static void
559drag_handle_surface_destroy(struct wl_listener *listener,
Benjamin Franzke4721a3c2011-05-06 17:13:17 +0200560 struct wl_resource *resource, uint32_t time)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500561{
562 struct wl_drag *drag =
563 container_of(listener, struct wl_drag, drag_focus_listener);
Benjamin Franzke4721a3c2011-05-06 17:13:17 +0200564 struct wl_surface *surface = (struct wl_surface *) resource;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500565
566 if (drag->drag_focus == surface)
567 wl_drag_set_pointer_focus(drag, NULL, time, 0, 0, 0, 0);
568}
569
570static void
571shell_create_drag(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400572 struct wl_resource *resource, uint32_t id)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500573{
574 struct wl_drag *drag;
575
576 drag = malloc(sizeof *drag);
577 if (drag == NULL) {
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400578 wl_resource_post_no_memory(resource);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500579 return;
580 }
581
582 memset(drag, 0, sizeof *drag);
583 drag->resource.object.id = id;
584 drag->resource.object.interface = &wl_drag_interface;
585 drag->resource.object.implementation =
586 (void (**)(void)) &drag_interface;
587
Pekka Paalanen02ebfb12011-10-24 17:34:53 +0300588 drag->resource.data = drag;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500589 drag->resource.destroy = destroy_drag;
590
591 drag->drag_focus_listener.func = drag_handle_surface_destroy;
592 wl_list_init(&drag->drag_focus_listener.link);
593
594 wl_client_add_resource(client, &drag->resource);
595}
596
Kristian Høgsberg1c562182011-05-02 22:09:20 -0400597static void
598wlsc_selection_set_focus(struct wlsc_shell *shell,
599 struct wl_selection *selection,
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500600 struct wl_surface *surface, uint32_t time)
601{
602 char **p, **end;
603
604 if (selection->selection_focus == surface)
605 return;
606
607 if (selection->selection_focus != NULL)
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400608 wl_resource_post_event(&selection->selection_offer.resource,
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500609 WL_SELECTION_OFFER_KEYBOARD_FOCUS,
610 NULL);
611
612 if (surface) {
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500613
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400614 selection->selection_offer.resource.client = surface->resource.client;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500615 end = selection->types.data + selection->types.size;
616 for (p = selection->types.data; p < end; p++)
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400617 wl_resource_post_event(&selection->selection_offer.resource,
618 WL_SELECTION_OFFER_OFFER, *p);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500619
620 wl_list_remove(&selection->selection_focus_listener.link);
Benjamin Franzke4721a3c2011-05-06 17:13:17 +0200621 wl_list_insert(surface->resource.destroy_listener_list.prev,
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500622 &selection->selection_focus_listener.link);
623
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400624 wl_resource_post_event(&selection->selection_offer.resource,
625 WL_SELECTION_OFFER_KEYBOARD_FOCUS,
626 selection->input_device);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500627 }
628
629 selection->selection_focus = surface;
630
631 wl_list_remove(&selection->selection_focus_listener.link);
632 if (surface)
Benjamin Franzke4721a3c2011-05-06 17:13:17 +0200633 wl_list_insert(surface->resource.destroy_listener_list.prev,
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500634 &selection->selection_focus_listener.link);
635}
636
637static void
638selection_offer_receive(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400639 struct wl_resource *resource,
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500640 const char *mime_type, int fd)
641{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400642 struct wl_selection_offer *offer = resource->data;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500643 struct wl_selection *selection =
644 container_of(offer, struct wl_selection, selection_offer);
645
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400646 wl_resource_post_event(&selection->resource,
647 WL_SELECTION_SEND, mime_type, fd);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500648 close(fd);
649}
650
651static const struct wl_selection_offer_interface selection_offer_interface = {
652 selection_offer_receive
653};
654
655static void
656selection_offer(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400657 struct wl_resource *resource, const char *type)
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500658{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400659 struct wl_selection *selection = resource->data;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500660 char **p;
661
662 p = wl_array_add(&selection->types, sizeof *p);
663 if (p)
664 *p = strdup(type);
665 if (!p || !*p)
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400666 wl_resource_post_no_memory(resource);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500667}
668
669static void
670selection_activate(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400671 struct wl_resource *resource,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400672 struct wl_resource *input_resource, uint32_t time)
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500673{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400674 struct wl_selection *selection = resource->data;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400675 struct wlsc_input_device *wd = input_resource->data;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500676 struct wl_display *display = wl_client_get_display (client);
Kristian Høgsberg1c562182011-05-02 22:09:20 -0400677 struct wlsc_compositor *compositor =
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400678 (struct wlsc_compositor *) wd->input_device.compositor;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500679
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400680 selection->input_device = &wd->input_device;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500681
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400682 selection->selection_offer.resource.object.interface =
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500683 &wl_selection_offer_interface;
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400684 selection->selection_offer.resource.object.implementation =
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500685 (void (**)(void)) &selection_offer_interface;
686
Kristian Høgsbergd9551a32011-08-19 12:07:44 -0400687 wl_display_add_global(display,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400688 &wl_selection_offer_interface, selection, NULL);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500689
690 if (wd->selection) {
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400691 wl_resource_post_event(&wd->selection->resource,
692 WL_SELECTION_CANCELLED);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500693 }
694 wd->selection = selection;
695
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400696 wlsc_selection_set_focus(compositor->shell, selection,
697 wd->input_device.keyboard_focus, time);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500698}
699
700static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400701selection_destroy(struct wl_client *client, struct wl_resource *resource)
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500702{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400703 wl_resource_destroy(resource, wlsc_compositor_get_time());
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500704}
705
706static const struct wl_selection_interface selection_interface = {
707 selection_offer,
708 selection_activate,
709 selection_destroy
710};
711
712static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400713destroy_selection(struct wl_resource *resource)
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500714{
715 struct wl_selection *selection =
716 container_of(resource, struct wl_selection, resource);
717 struct wlsc_input_device *wd =
718 (struct wlsc_input_device *) selection->input_device;
Kristian Høgsberg1c562182011-05-02 22:09:20 -0400719 struct wlsc_compositor *compositor =
720 (struct wlsc_compositor *) wd->input_device.compositor;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500721
722 if (wd && wd->selection == selection) {
723 wd->selection = NULL;
Kristian Høgsberg1c562182011-05-02 22:09:20 -0400724 wlsc_selection_set_focus(compositor->shell,
725 selection, NULL,
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400726 wlsc_compositor_get_time());
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500727 }
728
729 wl_list_remove(&selection->selection_focus_listener.link);
730 free(selection);
731}
732
733static void
734selection_handle_surface_destroy(struct wl_listener *listener,
Benjamin Franzke4721a3c2011-05-06 17:13:17 +0200735 struct wl_resource *resource, uint32_t time)
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500736{
737}
738
739static void
740shell_create_selection(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400741 struct wl_resource *resource, uint32_t id)
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500742{
743 struct wl_selection *selection;
744
745 selection = malloc(sizeof *selection);
746 if (selection == NULL) {
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400747 wl_resource_post_no_memory(resource);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500748 return;
749 }
750
751 memset(selection, 0, sizeof *selection);
752 selection->resource.object.id = id;
753 selection->resource.object.interface = &wl_selection_interface;
754 selection->resource.object.implementation =
755 (void (**)(void)) &selection_interface;
756
757 selection->client = client;
758 selection->resource.destroy = destroy_selection;
759 selection->selection_focus = NULL;
760
761 selection->selection_focus_listener.func =
762 selection_handle_surface_destroy;
763 wl_list_init(&selection->selection_focus_listener.link);
764
765 wl_client_add_resource(client, &selection->resource);
766}
767
Kristian Høgsberg75840622011-09-06 13:48:16 -0400768static const struct wl_shell_interface shell_interface = {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500769 shell_move,
770 shell_resize,
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500771 shell_create_drag,
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400772 shell_create_selection,
773 shell_set_toplevel,
774 shell_set_transient,
775 shell_set_fullscreen
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500776};
777
Kristian Høgsberg07937562011-04-12 17:25:42 -0400778static void
Kristian Høgsberg75840622011-09-06 13:48:16 -0400779handle_background_surface_destroy(struct wl_listener *listener,
780 struct wl_resource *resource, uint32_t time)
781{
782 struct wl_shell *shell =
783 container_of(listener, struct wl_shell, background_listener);
784
785 fprintf(stderr, "background surface gone\n");
786 shell->background = NULL;
787}
788
789static void
790desktop_shell_set_background(struct wl_client *client,
791 struct wl_resource *resource,
792 struct wl_resource *surface_resource)
793{
794 struct wl_shell *shell = resource->data;
795 struct wlsc_surface *surface = surface_resource->data;
796 struct wlsc_output *output =
797 container_of(shell->compositor->output_list.next,
798 struct wlsc_output, link);
799
800 shell->background = surface_resource->data;
801 shell->background_listener.func = handle_background_surface_destroy;
802 wl_list_insert(&surface_resource->destroy_listener_list,
803 &shell->background_listener.link);
804
805 wl_resource_post_event(resource,
806 DESKTOP_SHELL_CONFIGURE,
807 wlsc_compositor_get_time(), 0, surface,
808 output->current->width,
809 output->current->height);
810}
811
812static void
813handle_panel_surface_destroy(struct wl_listener *listener,
814 struct wl_resource *resource, uint32_t time)
815{
816 struct wl_shell *shell =
817 container_of(listener, struct wl_shell, panel_listener);
818
819 fprintf(stderr, "panel surface gone\n");
820 shell->panel = NULL;
821}
822
823static void
824desktop_shell_set_panel(struct wl_client *client,
825 struct wl_resource *resource,
826 struct wl_resource *surface_resource)
827{
828 struct wl_shell *shell = resource->data;
829 struct wlsc_output *output =
830 container_of(shell->compositor->output_list.next,
831 struct wlsc_output, link);
832
833 shell->panel = surface_resource->data;
834
835 shell->panel_listener.func = handle_panel_surface_destroy;
836 wl_list_insert(&surface_resource->destroy_listener_list,
837 &shell->panel_listener.link);
838
839 wl_resource_post_event(resource,
840 DESKTOP_SHELL_CONFIGURE,
841 wlsc_compositor_get_time(), 0, surface_resource,
842 output->current->width,
843 output->current->height);
844}
845
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200846static void
847desktop_shell_set_lock_surface(struct wl_client *client,
848 struct wl_resource *resource,
849 struct wl_resource *surface_resource)
850{
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +0200851 struct wl_shell *shell = resource->data;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200852 struct wlsc_surface *es = surface_resource->data;
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +0200853
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200854 shell->prepare_event_sent = false;
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +0200855
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200856 if (!shell->locked)
857 return;
858
859 wl_list_remove(&es->link);
860 wl_list_insert(&shell->compositor->surface_list, &es->link);
861
862 wlsc_compositor_repick(shell->compositor);
863 wlsc_compositor_wake(shell->compositor);
864}
865
866static void
867resume_desktop(struct wl_shell *shell)
868{
869 struct hidden_surface *hidden;
870 struct hidden_surface *tmp;
871 struct wl_list *elem;
872 struct wl_list *put = &shell->compositor->surface_list;
873
874 wl_list_for_each_safe(hidden, tmp, &shell->hidden_surface_list, link) {
875 elem = &hidden->surface->link;
876 wl_list_remove(elem);
877
878 if (hidden->surface == shell->panel) {
879 wl_list_insert(&shell->compositor->surface_list, elem);
880 if (put == &shell->compositor->surface_list)
881 put = elem;
882 } else {
883 wl_list_insert(put, elem);
884 put = elem;
885 }
886
887 hidden_surface_destroy(hidden);
888 }
889
890 if (!wl_list_empty(&shell->hidden_surface_list)) {
891 fprintf(stderr,
892 "%s: Assertion failed: hidden_surface_list is not empty.\n",
893 __func__);
894 }
895
896 shell->locked = false;
897 wlsc_compositor_repick(shell->compositor);
898 wlsc_compositor_damage_all(shell->compositor);
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +0200899 wlsc_compositor_wake(shell->compositor);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200900}
901
902static void
903desktop_shell_unlock(struct wl_client *client,
904 struct wl_resource *resource)
905{
906 struct wl_shell *shell = resource->data;
907
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200908 shell->prepare_event_sent = false;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200909
910 if (shell->locked)
911 resume_desktop(shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200912}
913
Kristian Høgsberg75840622011-09-06 13:48:16 -0400914static const struct desktop_shell_interface desktop_shell_implementation = {
915 desktop_shell_set_background,
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200916 desktop_shell_set_panel,
917 desktop_shell_set_lock_surface,
918 desktop_shell_unlock
Kristian Høgsberg75840622011-09-06 13:48:16 -0400919};
920
921static void
Kristian Høgsberg07937562011-04-12 17:25:42 -0400922move_binding(struct wl_input_device *device, uint32_t time,
923 uint32_t key, uint32_t button, uint32_t state, void *data)
924{
Kristian Høgsberg75840622011-09-06 13:48:16 -0400925 struct wl_shell *shell = data;
Kristian Høgsberg07937562011-04-12 17:25:42 -0400926 struct wlsc_surface *surface =
927 (struct wlsc_surface *) device->pointer_focus;
928
Kristian Høgsberga4a42f02011-09-08 16:56:57 -0400929 if (surface == NULL ||
930 surface->map_type == WLSC_SURFACE_MAP_FULLSCREEN)
Kristian Høgsberg10f097e2011-04-13 11:52:54 -0400931 return;
Kristian Høgsberg75840622011-09-06 13:48:16 -0400932 if (surface == shell->panel)
933 return;
934 if (surface == shell->background)
935 return;
Kristian Høgsberg10f097e2011-04-13 11:52:54 -0400936
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400937 wlsc_surface_move(surface, (struct wlsc_input_device *) device, time);
Kristian Høgsberg07937562011-04-12 17:25:42 -0400938}
939
940static void
941resize_binding(struct wl_input_device *device, uint32_t time,
942 uint32_t key, uint32_t button, uint32_t state, void *data)
943{
Kristian Høgsberg75840622011-09-06 13:48:16 -0400944 struct wl_shell *shell = data;
Kristian Høgsberg07937562011-04-12 17:25:42 -0400945 struct wlsc_surface *surface =
946 (struct wlsc_surface *) device->pointer_focus;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400947 struct wl_resource *resource;
Kristian Høgsberg07937562011-04-12 17:25:42 -0400948 uint32_t edges = 0;
949 int32_t x, y;
950
Kristian Høgsberga4a42f02011-09-08 16:56:57 -0400951 if (surface == NULL ||
952 surface->map_type == WLSC_SURFACE_MAP_FULLSCREEN)
Kristian Høgsberg75840622011-09-06 13:48:16 -0400953 if (surface == shell->panel)
954 return;
955 if (surface == shell->background)
956 return;
Kristian Høgsberg10f097e2011-04-13 11:52:54 -0400957
Kristian Høgsberg07937562011-04-12 17:25:42 -0400958 x = device->grab_x - surface->x;
959 y = device->grab_y - surface->y;
960
961 if (x < surface->width / 3)
962 edges |= WL_SHELL_RESIZE_LEFT;
963 else if (x < 2 * surface->width / 3)
964 edges |= 0;
965 else
966 edges |= WL_SHELL_RESIZE_RIGHT;
967
968 if (y < surface->height / 3)
969 edges |= WL_SHELL_RESIZE_TOP;
970 else if (y < 2 * surface->height / 3)
971 edges |= 0;
972 else
973 edges |= WL_SHELL_RESIZE_BOTTOM;
974
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400975 resource = /* Find shell resource for surface client */ 0;
976
977 /* ... or use wl_shell_surface */
978
979 wlsc_surface_resize(surface, (struct wlsc_input_device *) device,
980 time, edges, resource);
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400981}
982
983static void
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200984handle_hidden_surface_destroy(struct wl_listener *listener,
985 struct wl_resource *resource, uint32_t time)
986{
987 struct hidden_surface *hidden =
988 container_of(listener, struct hidden_surface, destroy_listener);
989
990 hidden_surface_destroy(hidden);
991}
992
993static struct hidden_surface *
994hidden_surface_create(struct wl_shell *shell, struct wlsc_surface *surface)
995{
996 struct hidden_surface *hidden;
997
998 hidden = malloc(sizeof *hidden);
999 if (!hidden)
1000 return NULL;
1001
1002 hidden->surface = surface;
1003 hidden->shell = shell;
1004 hidden->destroy_listener.func = handle_hidden_surface_destroy;
1005 wl_list_insert(surface->surface.resource.destroy_listener_list.prev,
1006 &hidden->destroy_listener.link);
1007
1008 return hidden;
1009}
1010
1011static void
Kristian Høgsberg75840622011-09-06 13:48:16 -04001012activate(struct wlsc_shell *base, struct wlsc_surface *es,
1013 struct wlsc_input_device *device, uint32_t time)
1014{
1015 struct wl_shell *shell = container_of(base, struct wl_shell, shell);
1016 struct wlsc_compositor *compositor = shell->compositor;
1017
1018 wlsc_surface_activate(es, device, time);
1019
Kristian Høgsbergd6e55252011-10-11 23:41:17 -04001020 if (compositor->wxs)
1021 wlsc_xserver_surface_activate(es);
1022
Kristian Høgsberg75840622011-09-06 13:48:16 -04001023 if (es == shell->background) {
1024 wl_list_remove(&es->link);
1025 wl_list_insert(compositor->surface_list.prev, &es->link);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001026 } else if (shell->panel && !shell->locked) {
Kristian Høgsberg75840622011-09-06 13:48:16 -04001027 wl_list_remove(&shell->panel->link);
1028 wl_list_insert(&compositor->surface_list, &shell->panel->link);
1029 }
1030}
1031
1032static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001033lock(struct wlsc_shell *base)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001034{
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001035 struct wl_shell *shell = container_of(base, struct wl_shell, shell);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001036 struct wl_list *surface_list = &shell->compositor->surface_list;
1037 struct wlsc_surface *cur;
1038 struct wlsc_surface *tmp;
1039 struct hidden_surface *hidden;
1040 struct wlsc_input_device *device;
1041 uint32_t time;
1042
1043 if (shell->locked)
1044 return;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001045
1046 shell->locked = true;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001047
1048 /* Move all surfaces from compositor's list to our hidden list,
1049 * except the background. This way nothing else can show or
1050 * receive input events while we are locked. */
1051
1052 if (!wl_list_empty(&shell->hidden_surface_list)) {
1053 fprintf(stderr,
1054 "%s: Assertion failed: hidden_surface_list is not empty.\n",
1055 __func__);
1056 }
1057
1058 wl_list_for_each_safe(cur, tmp, surface_list, link) {
1059 /* skip input device sprites, cur->surface is uninitialised */
1060 if (cur->surface.resource.client == NULL)
1061 continue;
1062
1063 if (cur == shell->background)
1064 continue;
1065
1066 hidden = hidden_surface_create(shell, cur);
1067 if (!hidden)
1068 continue;
1069
1070 wl_list_insert(shell->hidden_surface_list.prev, &hidden->link);
1071 wl_list_remove(&cur->link);
1072 wl_list_init(&cur->link);
1073 }
1074
1075 /* reset pointer foci */
1076 wlsc_compositor_repick(shell->compositor);
1077
1078 /* reset keyboard foci */
1079 time = wlsc_compositor_get_time();
1080 wl_list_for_each(device, &shell->compositor->input_device_list, link) {
1081 wl_input_device_set_keyboard_focus(&device->input_device,
1082 NULL, time);
1083 }
1084
1085 /* TODO: disable bindings that should not work while locked. */
1086
1087 /* All this must be undone in resume_desktop(). */
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001088}
1089
1090static void
1091unlock(struct wlsc_shell *base)
1092{
1093 struct wl_shell *shell = container_of(base, struct wl_shell, shell);
1094
1095 if (!shell->locked) {
1096 wlsc_compositor_wake(shell->compositor);
1097 return;
1098 }
1099
1100 /* If desktop-shell client has gone away, unlock immediately. */
1101 if (!shell->child.desktop_shell) {
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001102 resume_desktop(shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001103 return;
1104 }
1105
1106 if (shell->prepare_event_sent)
1107 return;
1108
1109 wl_resource_post_event(shell->child.desktop_shell,
1110 DESKTOP_SHELL_PREPARE_LOCK_SURFACE);
1111 shell->prepare_event_sent = true;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001112}
1113
1114static void
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05001115map(struct wlsc_shell *base,
1116 struct wlsc_surface *surface, int32_t width, int32_t height)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001117{
Kristian Høgsberg75840622011-09-06 13:48:16 -04001118 struct wl_shell *shell = container_of(base, struct wl_shell, shell);
1119 struct wlsc_compositor *compositor = shell->compositor;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001120 struct hidden_surface *hidden;
Kristian Høgsberg75840622011-09-06 13:48:16 -04001121
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05001122 /* Map background at the bottom of the stack, panel on top,
1123 everything else just below panel. */
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001124 if (surface == shell->background) {
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05001125 wl_list_insert(compositor->surface_list.prev, &surface->link);
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05001126
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001127 } else if (shell->locked) {
1128 wl_list_init(&surface->link);
1129
1130 hidden = hidden_surface_create(shell, surface);
1131 if (!hidden)
1132 goto out;
1133
1134 /* panel positioning is fixed on resume */
1135 wl_list_insert(&shell->hidden_surface_list, &hidden->link);
1136 } else {
1137 if (surface == shell->panel)
1138 wl_list_insert(&compositor->surface_list,
1139 &surface->link);
1140 else
1141 wl_list_insert(&shell->panel->link, &surface->link);
1142 }
1143
1144out:
Kristian Høgsberg46770132011-11-09 12:38:53 -05001145 if (surface->map_type == WLSC_SURFACE_MAP_TOPLEVEL) {
1146 surface->x = 10 + random() % 400;
1147 surface->y = 10 + random() % 400;
1148 }
1149
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05001150 wlsc_surface_configure(surface, surface->x, surface->y, width, height);
1151}
1152
1153static void
1154configure(struct wlsc_shell *shell, struct wlsc_surface *surface,
1155 int32_t x, int32_t y, int32_t width, int32_t height)
1156{
1157 struct wlsc_mode *current;
1158
1159 if (surface->map_type == WLSC_SURFACE_MAP_FULLSCREEN) {
1160 current = surface->fullscreen_output->current;
1161 x = (current->width - surface->width) / 2;
1162 y = (current->height - surface->height) / 2;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001163 }
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05001164
1165 wlsc_surface_configure(surface, x, y, width, height);
Kristian Høgsberg07937562011-04-12 17:25:42 -04001166}
1167
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001168static void
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02001169desktop_shell_sigchld(struct wlsc_process *process, int status)
1170{
1171 struct wl_shell *shell =
1172 container_of(process, struct wl_shell, child.process);
1173
1174 shell->child.process.pid = 0;
1175 shell->child.client = NULL; /* already destroyed by wayland */
1176}
1177
1178static int
1179launch_desktop_shell_process(struct wl_shell *shell)
1180{
Kristian Høgsbergc4693c42011-11-14 14:57:17 -05001181 const char *shell_exe = LIBEXECDIR "/wayland-desktop-shell";
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02001182 struct wlsc_compositor *compositor = shell->compositor;
1183 char s[32];
1184 int sv[2], flags;
1185
1186 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) {
1187 fprintf(stderr, "socketpair failed\n");
1188 return -1;
1189 }
1190
1191 shell->child.process.pid = fork();
1192 shell->child.process.cleanup = desktop_shell_sigchld;
1193
1194 switch (shell->child.process.pid) {
1195 case 0:
1196 /* SOCK_CLOEXEC closes both ends, so we need to unset
1197 * the flag on the client fd. */
1198 flags = fcntl(sv[1], F_GETFD);
1199 if (flags != -1)
1200 fcntl(sv[1], F_SETFD, flags & ~FD_CLOEXEC);
1201
1202 snprintf(s, sizeof s, "%d", sv[1]);
1203 setenv("WAYLAND_SOCKET", s, 1);
1204 if (execl(shell_exe, shell_exe, NULL) < 0)
1205 fprintf(stderr, "%s: running '%s' failed: %m\n",
1206 __func__, shell_exe);
1207 exit(-1);
1208
1209 default:
1210 close(sv[1]);
1211 shell->child.client =
1212 wl_client_create(compositor->wl_display, sv[0]);
1213 wlsc_watch_process(&shell->child.process);
1214 break;
1215
1216 case -1:
1217 fprintf(stderr, "%s: fork failed: %m\n", __func__);
1218 return -1;
1219 }
1220 return 0;
1221}
1222
1223static void
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001224bind_shell(struct wl_client *client, void *data, uint32_t version, uint32_t id)
1225{
1226 struct wl_shell *shell = data;
1227
1228 wl_client_add_object(client, &wl_shell_interface,
1229 &shell_interface, id, shell);
1230}
1231
Kristian Høgsberg75840622011-09-06 13:48:16 -04001232static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001233unbind_desktop_shell(struct wl_resource *resource)
1234{
1235 struct wl_shell *shell = resource->data;
1236 shell->child.desktop_shell = NULL;
1237 shell->prepare_event_sent = false;
1238 free(resource);
1239}
1240
1241static void
Kristian Høgsberg75840622011-09-06 13:48:16 -04001242bind_desktop_shell(struct wl_client *client,
1243 void *data, uint32_t version, uint32_t id)
1244{
1245 struct wl_shell *shell = data;
Pekka Paalanenbbe60522011-11-03 14:11:33 +02001246 struct wl_resource *resource;
Kristian Høgsberg75840622011-09-06 13:48:16 -04001247
Pekka Paalanenbbe60522011-11-03 14:11:33 +02001248 resource = wl_client_add_object(client, &desktop_shell_interface,
1249 &desktop_shell_implementation,
1250 id, shell);
1251
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001252 if (client == shell->child.client) {
1253 resource->destroy = unbind_desktop_shell;
1254 shell->child.desktop_shell = resource;
Pekka Paalanenbbe60522011-11-03 14:11:33 +02001255 return;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001256 }
Pekka Paalanenbbe60522011-11-03 14:11:33 +02001257
1258 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
1259 "permission to bind desktop_shell denied");
1260 wl_resource_destroy(resource, 0);
Kristian Høgsberg75840622011-09-06 13:48:16 -04001261}
1262
Kristian Høgsberg6c709a32011-05-06 14:52:41 -04001263int
1264shell_init(struct wlsc_compositor *ec);
1265
Kristian Høgsberg1c562182011-05-02 22:09:20 -04001266WL_EXPORT int
1267shell_init(struct wlsc_compositor *ec)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001268{
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001269 struct wl_shell *shell;
1270
1271 shell = malloc(sizeof *shell);
1272 if (shell == NULL)
1273 return -1;
1274
Kristian Høgsbergf0d91162011-10-11 22:44:23 -04001275 memset(shell, 0, sizeof *shell);
Kristian Høgsberg75840622011-09-06 13:48:16 -04001276 shell->compositor = ec;
1277 shell->shell.activate = activate;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001278 shell->shell.lock = lock;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001279 shell->shell.unlock = unlock;
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05001280 shell->shell.map = map;
1281 shell->shell.configure = configure;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04001282 shell->shell.set_selection_focus = wlsc_selection_set_focus;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001283
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001284 wl_list_init(&shell->hidden_surface_list);
1285
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001286 if (wl_display_add_global(ec->wl_display, &wl_shell_interface,
1287 shell, bind_shell) == NULL)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001288 return -1;
1289
Kristian Høgsberg75840622011-09-06 13:48:16 -04001290 if (wl_display_add_global(ec->wl_display,
1291 &desktop_shell_interface,
1292 shell, bind_desktop_shell) == NULL)
1293 return -1;
1294
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02001295 if (launch_desktop_shell_process(shell) != 0)
1296 return -1;
1297
Kristian Høgsberg07937562011-04-12 17:25:42 -04001298 wlsc_compositor_add_binding(ec, 0, BTN_LEFT, MODIFIER_SUPER,
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001299 move_binding, shell);
Kristian Høgsberg07937562011-04-12 17:25:42 -04001300 wlsc_compositor_add_binding(ec, 0, BTN_MIDDLE, MODIFIER_SUPER,
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001301 resize_binding, shell);
1302
1303 ec->shell = &shell->shell;
Kristian Høgsberg07937562011-04-12 17:25:42 -04001304
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001305 return 0;
1306}