blob: 62edef9bc9a65c0d81426dc82510e67c3edc7883 [file] [log] [blame]
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001/*
2 * Copyright © 2010 Intel Corporation
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02003 * Copyright © 2011 Collabora, Ltd.
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05004 *
5 * Permission to use, copy, modify, distribute, and sell this software and
6 * its documentation for any purpose is hereby granted without fee, provided
7 * that the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of the copyright holders not be used in
10 * advertising or publicity pertaining to distribution of the software
11 * without specific, written prior permission. The copyright holders make
12 * no representations about the suitability of this software for any
13 * purpose. It is provided "as is" without express or implied warranty.
14 *
15 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
16 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
20 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 */
23
24#include <stdlib.h>
Kristian Høgsberg75840622011-09-06 13:48:16 -040025#include <stdio.h>
Pekka Paalanen9ef3e012011-11-15 13:34:48 +020026#include <stdbool.h>
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050027#include <string.h>
28#include <unistd.h>
Kristian Høgsberg07937562011-04-12 17:25:42 -040029#include <linux/input.h>
Pekka Paalanen6cd281a2011-11-03 14:11:32 +020030#include <sys/types.h>
31#include <sys/socket.h>
32#include <fcntl.h>
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +020033#include <assert.h>
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050034
Pekka Paalanen50719bc2011-11-22 14:18:50 +020035#include <wayland-server.h>
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050036#include "compositor.h"
Kristian Høgsberg75840622011-09-06 13:48:16 -040037#include "desktop-shell-server-protocol.h"
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050038
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -040039struct wl_shell {
Kristian Høgsberg75840622011-09-06 13:48:16 -040040 struct wlsc_compositor *compositor;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -040041 struct wlsc_shell shell;
Kristian Høgsberg75840622011-09-06 13:48:16 -040042 struct wlsc_surface *panel;
43 struct wl_listener panel_listener;
44 struct wlsc_surface *background;
45 struct wl_listener background_listener;
Pekka Paalanen6cd281a2011-11-03 14:11:32 +020046
47 struct {
48 struct wlsc_process process;
49 struct wl_client *client;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +020050 struct wl_resource *desktop_shell;
Pekka Paalanen6cd281a2011-11-03 14:11:32 +020051 } child;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +020052
53 bool locked;
54 bool prepare_event_sent;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +020055
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -050056 struct wlsc_surface *lock_surface;
57 struct wl_listener lock_surface_listener;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +020058 struct wl_list hidden_surface_list;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -040059};
60
Pekka Paalanen57da4a82011-11-23 16:42:16 +020061enum shell_surface_purpose {
62 SHELL_SURFACE_NORMAL,
63 SHELL_SURFACE_PANEL,
64 SHELL_SURFACE_BACKGROUND,
65 SHELL_SURFACE_LOCK,
66};
67
Pekka Paalanen56cdea92011-11-23 16:14:12 +020068struct shell_surface {
69 struct wl_listener destroy_listener;
Pekka Paalanen57da4a82011-11-23 16:42:16 +020070
71 enum shell_surface_purpose purpose;
Pekka Paalanen56cdea92011-11-23 16:14:12 +020072};
73
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050074struct wlsc_move_grab {
75 struct wl_grab grab;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -050076 struct wlsc_surface *surface;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050077 int32_t dx, dy;
78};
79
80static void
Pekka Paalanen56cdea92011-11-23 16:14:12 +020081destroy_shell_surface(struct shell_surface *priv)
82{
83 wl_list_remove(&priv->destroy_listener.link);
84 free(priv);
85}
86
87static void
88handle_shell_surface_destroy(struct wl_listener *listener,
89 struct wl_resource *resource, uint32_t time)
90{
91 struct shell_surface *priv =
92 container_of(listener, struct shell_surface, destroy_listener);
93 destroy_shell_surface(priv);
94}
95
96static struct shell_surface *
97get_shell_surface(struct wlsc_surface *surface)
98{
99 struct shell_surface *priv;
100
101 if (surface->shell_priv)
102 return surface->shell_priv;
103
104 priv = calloc(1, sizeof *priv);
105 if (!priv)
106 return NULL;
107
108 priv->destroy_listener.func = handle_shell_surface_destroy;
109 wl_list_insert(surface->surface.resource.destroy_listener_list.prev,
110 &priv->destroy_listener.link);
111
112 surface->shell_priv = priv;
113
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200114 priv->purpose = SHELL_SURFACE_NORMAL;
115
Pekka Paalanen56cdea92011-11-23 16:14:12 +0200116 return priv;
117}
118
119static void
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500120move_grab_motion(struct wl_grab *grab,
121 uint32_t time, int32_t x, int32_t y)
122{
123 struct wlsc_move_grab *move = (struct wlsc_move_grab *) grab;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -0500124 struct wlsc_surface *es = move->surface;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500125
Kristian Høgsberga691aee2011-06-23 21:43:50 -0400126 wlsc_surface_configure(es, x + move->dx, y + move->dy,
127 es->width, es->height);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500128}
129
130static void
131move_grab_button(struct wl_grab *grab,
132 uint32_t time, int32_t button, int32_t state)
133{
134}
135
136static void
137move_grab_end(struct wl_grab *grab, uint32_t time)
138{
139 free(grab);
140}
141
142static const struct wl_grab_interface move_grab_interface = {
143 move_grab_motion,
144 move_grab_button,
145 move_grab_end
146};
147
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400148static int
149wlsc_surface_move(struct wlsc_surface *es,
150 struct wlsc_input_device *wd, uint32_t time)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500151{
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500152 struct wlsc_move_grab *move;
153
154 move = malloc(sizeof *move);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400155 if (!move)
156 return -1;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500157
158 move->grab.interface = &move_grab_interface;
159 move->dx = es->x - wd->input_device.grab_x;
160 move->dy = es->y - wd->input_device.grab_y;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -0500161 move->surface = es;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500162
163 if (wl_input_device_update_grab(&wd->input_device,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400164 &move->grab, &es->surface, time) < 0)
165 return 0;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500166
167 wlsc_input_device_set_pointer_image(wd, WLSC_POINTER_DRAGGING);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400168 wl_input_device_set_pointer_focus(&wd->input_device,
169 NULL, time, 0, 0, 0, 0);
170
171 return 0;
172}
173
174static void
175shell_move(struct wl_client *client, struct wl_resource *resource,
176 struct wl_resource *surface_resource,
177 struct wl_resource *input_resource, uint32_t time)
178{
179 struct wlsc_input_device *wd = input_resource->data;
180 struct wlsc_surface *es = surface_resource->data;
181
182 if (wlsc_surface_move(es, wd, time) < 0)
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400183 wl_resource_post_no_memory(resource);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500184}
185
186struct wlsc_resize_grab {
187 struct wl_grab grab;
188 uint32_t edges;
189 int32_t dx, dy, width, height;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -0500190 struct wlsc_surface *surface;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400191 struct wl_resource *resource;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500192};
193
194static void
195resize_grab_motion(struct wl_grab *grab,
196 uint32_t time, int32_t x, int32_t y)
197{
198 struct wlsc_resize_grab *resize = (struct wlsc_resize_grab *) grab;
199 struct wl_input_device *device = grab->input_device;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -0500200 struct wl_surface *surface = &resize->surface->surface;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500201 int32_t width, height;
202
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500203 if (resize->edges & WL_SHELL_RESIZE_LEFT) {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500204 width = device->grab_x - x + resize->width;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500205 } else if (resize->edges & WL_SHELL_RESIZE_RIGHT) {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500206 width = x - device->grab_x + resize->width;
207 } else {
208 width = resize->width;
209 }
210
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500211 if (resize->edges & WL_SHELL_RESIZE_TOP) {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500212 height = device->grab_y - y + resize->height;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500213 } else if (resize->edges & WL_SHELL_RESIZE_BOTTOM) {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500214 height = y - device->grab_y + resize->height;
215 } else {
216 height = resize->height;
217 }
218
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400219 wl_resource_post_event(resize->resource,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400220 WL_SHELL_CONFIGURE, time, resize->edges,
221 surface, width, height);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500222}
223
224static void
225resize_grab_button(struct wl_grab *grab,
226 uint32_t time, int32_t button, int32_t state)
227{
228}
229
230static void
231resize_grab_end(struct wl_grab *grab, uint32_t time)
232{
233 free(grab);
234}
235
236static const struct wl_grab_interface resize_grab_interface = {
237 resize_grab_motion,
238 resize_grab_button,
239 resize_grab_end
240};
241
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400242static int
243wlsc_surface_resize(struct wlsc_surface *es,
244 struct wlsc_input_device *wd,
245 uint32_t time, uint32_t edges,
246 struct wl_resource *resource)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500247{
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500248 struct wlsc_resize_grab *resize;
249 enum wlsc_pointer_type pointer = WLSC_POINTER_LEFT_PTR;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500250
Kristian Høgsberg0ce24572011-01-28 15:18:33 -0500251 /* FIXME: Reject if fullscreen */
252
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500253 resize = malloc(sizeof *resize);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400254 if (!resize)
255 return -1;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500256
257 resize->grab.interface = &resize_grab_interface;
258 resize->edges = edges;
259 resize->dx = es->x - wd->input_device.grab_x;
260 resize->dy = es->y - wd->input_device.grab_y;
261 resize->width = es->width;
262 resize->height = es->height;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -0500263 resize->surface = es;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400264 resize->resource = resource;
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400265
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500266 if (edges == 0 || edges > 15 ||
267 (edges & 3) == 3 || (edges & 12) == 12)
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400268 return 0;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500269
270 switch (edges) {
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500271 case WL_SHELL_RESIZE_TOP:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500272 pointer = WLSC_POINTER_TOP;
273 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500274 case WL_SHELL_RESIZE_BOTTOM:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500275 pointer = WLSC_POINTER_BOTTOM;
276 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500277 case WL_SHELL_RESIZE_LEFT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500278 pointer = WLSC_POINTER_LEFT;
279 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500280 case WL_SHELL_RESIZE_TOP_LEFT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500281 pointer = WLSC_POINTER_TOP_LEFT;
282 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500283 case WL_SHELL_RESIZE_BOTTOM_LEFT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500284 pointer = WLSC_POINTER_BOTTOM_LEFT;
285 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500286 case WL_SHELL_RESIZE_RIGHT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500287 pointer = WLSC_POINTER_RIGHT;
288 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500289 case WL_SHELL_RESIZE_TOP_RIGHT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500290 pointer = WLSC_POINTER_TOP_RIGHT;
291 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500292 case WL_SHELL_RESIZE_BOTTOM_RIGHT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500293 pointer = WLSC_POINTER_BOTTOM_RIGHT;
294 break;
295 }
296
297 if (wl_input_device_update_grab(&wd->input_device,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400298 &resize->grab, &es->surface, time) < 0)
299 return 0;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500300
301 wlsc_input_device_set_pointer_image(wd, pointer);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400302 wl_input_device_set_pointer_focus(&wd->input_device,
303 NULL, time, 0, 0, 0, 0);
304
305 return 0;
306}
307
308static void
309shell_resize(struct wl_client *client, struct wl_resource *resource,
310 struct wl_resource *surface_resource,
311 struct wl_resource *input_resource, uint32_t time, uint32_t edges)
312{
313 struct wlsc_input_device *wd = input_resource->data;
314 struct wlsc_surface *es = surface_resource->data;
315
316 /* FIXME: Reject if fullscreen */
317
318 if (wlsc_surface_resize(es, wd, time, edges, resource) < 0)
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400319 wl_resource_post_no_memory(resource);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500320}
321
322static void
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400323shell_set_toplevel(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
330 if (es->map_type == WLSC_SURFACE_MAP_FULLSCREEN) {
331 es->x = es->saved_x;
332 es->y = es->saved_y;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400333 }
334
335 wlsc_surface_damage(es);
336 es->map_type = WLSC_SURFACE_MAP_TOPLEVEL;
337 es->fullscreen_output = NULL;
338}
339
340static void
341shell_set_transient(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400342 struct wl_resource *resource,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400343 struct wl_resource *surface_resource,
344 struct wl_resource *parent_resource,
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400345 int x, int y, uint32_t flags)
346{
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400347 struct wlsc_surface *es = surface_resource->data;
348 struct wlsc_surface *pes = parent_resource->data;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400349
350 /* assign to parents output */
351 es->output = pes->output;
352
353 es->x = pes->x + x;
354 es->y = pes->y + y;
355
356 wlsc_surface_damage(es);
357 es->map_type = WLSC_SURFACE_MAP_TRANSIENT;
358}
359
360static void
361shell_set_fullscreen(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400362 struct wl_resource *resource,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400363 struct wl_resource *surface_resource)
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400364
365{
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400366 struct wlsc_surface *es = surface_resource->data;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400367 struct wlsc_output *output;
368
369 /* FIXME: Fullscreen on first output */
370 /* FIXME: Handle output going away */
371 output = container_of(es->compositor->output_list.next,
372 struct wlsc_output, link);
373 es->output = output;
374
375 es->saved_x = es->x;
376 es->saved_y = es->y;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400377 es->x = (output->current->width - es->width) / 2;
378 es->y = (output->current->height - es->height) / 2;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400379 es->fullscreen_output = output;
380 wlsc_surface_damage(es);
381 es->map_type = WLSC_SURFACE_MAP_FULLSCREEN;
382}
383
384static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400385destroy_drag(struct wl_resource *resource)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500386{
387 struct wl_drag *drag =
388 container_of(resource, struct wl_drag, resource);
389
390 wl_list_remove(&drag->drag_focus_listener.link);
391 if (drag->grab.input_device)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400392 wl_input_device_end_grab(drag->grab.input_device,
393 wlsc_compositor_get_time());
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500394
395 free(drag);
396}
397
398
399static void
400wl_drag_set_pointer_focus(struct wl_drag *drag,
401 struct wl_surface *surface, uint32_t time,
402 int32_t x, int32_t y, int32_t sx, int32_t sy)
403{
404 char **p, **end;
405
406 if (drag->drag_focus == surface)
407 return;
408
409 if (drag->drag_focus &&
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400410 (!surface ||
411 drag->drag_focus->resource.client != surface->resource.client))
412 wl_resource_post_event(&drag->drag_offer.resource,
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500413 WL_DRAG_OFFER_POINTER_FOCUS,
414 time, NULL, 0, 0, 0, 0);
415
416 if (surface &&
417 (!drag->drag_focus ||
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400418 drag->drag_focus->resource.client != surface->resource.client)) {
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400419
420 drag->drag_offer.resource.client = surface->resource.client;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500421 end = drag->types.data + drag->types.size;
422 for (p = drag->types.data; p < end; p++)
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400423 wl_resource_post_event(&drag->drag_offer.resource,
424 WL_DRAG_OFFER_OFFER, *p);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500425 }
426
427 if (surface) {
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400428 wl_resource_post_event(&drag->drag_offer.resource,
429 WL_DRAG_OFFER_POINTER_FOCUS,
430 time, surface,
431 x, y, sx, sy);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500432
433 }
434
435 drag->drag_focus = surface;
436 drag->pointer_focus_time = time;
437 drag->target = NULL;
438
439 wl_list_remove(&drag->drag_focus_listener.link);
440 if (surface)
Benjamin Franzke4721a3c2011-05-06 17:13:17 +0200441 wl_list_insert(surface->resource.destroy_listener_list.prev,
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500442 &drag->drag_focus_listener.link);
443}
444
445static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400446drag_offer_accept(struct wl_client *client, struct wl_resource *resource,
447 uint32_t time, const char *type)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500448{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400449 struct wl_drag_offer *offer = resource->data;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500450 struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer);
451 char **p, **end;
452
453 /* If the client responds to drag pointer_focus or motion
454 * events after the pointer has left the surface, we just
455 * discard the accept requests. The drag source just won't
456 * get the corresponding 'target' events and eventually the
457 * next surface/root will start sending events. */
458 if (time < drag->pointer_focus_time)
459 return;
460
461 drag->target = client;
462 drag->type = NULL;
463 end = drag->types.data + drag->types.size;
464 for (p = drag->types.data; p < end; p++)
465 if (type && strcmp(*p, type) == 0)
466 drag->type = *p;
467
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400468 wl_resource_post_event(&drag->resource, WL_DRAG_TARGET, drag->type);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500469}
470
471static void
472drag_offer_receive(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400473 struct wl_resource *resource, int fd)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500474{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400475 struct wl_drag_offer *offer = resource->data;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500476 struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer);
477
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400478 wl_resource_post_event(&drag->resource, WL_DRAG_FINISH, fd);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500479 close(fd);
480}
481
482static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400483drag_offer_reject(struct wl_client *client, struct wl_resource *resource)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500484{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400485 struct wl_drag_offer *offer = resource->data;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500486 struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer);
487
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400488 wl_resource_post_event(&drag->resource, WL_DRAG_REJECT);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500489}
490
491static const struct wl_drag_offer_interface drag_offer_interface = {
492 drag_offer_accept,
493 drag_offer_receive,
494 drag_offer_reject
495};
496
497static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400498drag_offer(struct wl_client *client,
499 struct wl_resource *resource, const char *type)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500500{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400501 struct wl_drag *drag = resource->data;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500502 char **p;
503
504 p = wl_array_add(&drag->types, sizeof *p);
505 if (p)
506 *p = strdup(type);
507 if (!p || !*p)
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400508 wl_resource_post_no_memory(resource);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500509}
510
511static void
512drag_grab_motion(struct wl_grab *grab,
513 uint32_t time, int32_t x, int32_t y)
514{
515 struct wl_drag *drag = container_of(grab, struct wl_drag, grab);
516 struct wlsc_surface *es;
517 int32_t sx, sy;
518
519 es = pick_surface(grab->input_device, &sx, &sy);
520 wl_drag_set_pointer_focus(drag, &es->surface, time, x, y, sx, sy);
521 if (es)
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400522 wl_resource_post_event(&drag->drag_offer.resource,
523 WL_DRAG_OFFER_MOTION,
524 time, x, y, sx, sy);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500525}
526
527static void
528drag_grab_button(struct wl_grab *grab,
529 uint32_t time, int32_t button, int32_t state)
530{
531}
532
533static void
534drag_grab_end(struct wl_grab *grab, uint32_t time)
535{
536 struct wl_drag *drag = container_of(grab, struct wl_drag, grab);
537
538 if (drag->target)
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400539 wl_resource_post_event(&drag->drag_offer.resource,
540 WL_DRAG_OFFER_DROP);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500541
542 wl_drag_set_pointer_focus(drag, NULL, time, 0, 0, 0, 0);
543}
544
545static const struct wl_grab_interface drag_grab_interface = {
546 drag_grab_motion,
547 drag_grab_button,
548 drag_grab_end
549};
550
551static void
552drag_activate(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400553 struct wl_resource *resource,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400554 struct wl_resource *surface_resource,
555 struct wl_resource *device_resource, uint32_t time)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500556{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400557 struct wl_drag *drag = resource->data;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400558 struct wl_surface *surface = surface_resource->data;
559 struct wl_input_device *device = device_resource->data;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500560 struct wl_display *display = wl_client_get_display (client);
561 struct wlsc_surface *target;
562 int32_t sx, sy;
563
564 if (wl_input_device_update_grab(device,
565 &drag->grab, surface, time) < 0)
566 return;
567
568 drag->grab.interface = &drag_grab_interface;
569
570 drag->source = surface;
571
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400572 drag->drag_offer.resource.object.interface = &wl_drag_offer_interface;
573 drag->drag_offer.resource.object.implementation =
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500574 (void (**)(void)) &drag_offer_interface;
575
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400576 wl_display_add_global(display, &wl_drag_offer_interface, drag, NULL);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500577
578 target = pick_surface(device, &sx, &sy);
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -0500579 wl_input_device_set_pointer_focus(device, NULL, time, 0, 0, 0, 0);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500580 wl_drag_set_pointer_focus(drag, &target->surface, time,
581 device->x, device->y, sx, sy);
582}
583
584static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400585drag_destroy(struct wl_client *client, struct wl_resource *resource)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500586{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400587 wl_resource_destroy(resource, wlsc_compositor_get_time());
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500588}
589
590static const struct wl_drag_interface drag_interface = {
591 drag_offer,
592 drag_activate,
593 drag_destroy,
594};
595
596static void
597drag_handle_surface_destroy(struct wl_listener *listener,
Benjamin Franzke4721a3c2011-05-06 17:13:17 +0200598 struct wl_resource *resource, uint32_t time)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500599{
600 struct wl_drag *drag =
601 container_of(listener, struct wl_drag, drag_focus_listener);
Benjamin Franzke4721a3c2011-05-06 17:13:17 +0200602 struct wl_surface *surface = (struct wl_surface *) resource;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500603
604 if (drag->drag_focus == surface)
605 wl_drag_set_pointer_focus(drag, NULL, time, 0, 0, 0, 0);
606}
607
608static void
609shell_create_drag(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400610 struct wl_resource *resource, uint32_t id)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500611{
612 struct wl_drag *drag;
613
614 drag = malloc(sizeof *drag);
615 if (drag == NULL) {
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400616 wl_resource_post_no_memory(resource);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500617 return;
618 }
619
620 memset(drag, 0, sizeof *drag);
621 drag->resource.object.id = id;
622 drag->resource.object.interface = &wl_drag_interface;
623 drag->resource.object.implementation =
624 (void (**)(void)) &drag_interface;
625
Pekka Paalanen02ebfb12011-10-24 17:34:53 +0300626 drag->resource.data = drag;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500627 drag->resource.destroy = destroy_drag;
628
629 drag->drag_focus_listener.func = drag_handle_surface_destroy;
630 wl_list_init(&drag->drag_focus_listener.link);
631
632 wl_client_add_resource(client, &drag->resource);
633}
634
Kristian Høgsberg1c562182011-05-02 22:09:20 -0400635static void
636wlsc_selection_set_focus(struct wlsc_shell *shell,
637 struct wl_selection *selection,
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500638 struct wl_surface *surface, uint32_t time)
639{
640 char **p, **end;
641
642 if (selection->selection_focus == surface)
643 return;
644
645 if (selection->selection_focus != NULL)
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400646 wl_resource_post_event(&selection->selection_offer.resource,
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500647 WL_SELECTION_OFFER_KEYBOARD_FOCUS,
648 NULL);
649
650 if (surface) {
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500651
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400652 selection->selection_offer.resource.client = surface->resource.client;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500653 end = selection->types.data + selection->types.size;
654 for (p = selection->types.data; p < end; p++)
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400655 wl_resource_post_event(&selection->selection_offer.resource,
656 WL_SELECTION_OFFER_OFFER, *p);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500657
658 wl_list_remove(&selection->selection_focus_listener.link);
Benjamin Franzke4721a3c2011-05-06 17:13:17 +0200659 wl_list_insert(surface->resource.destroy_listener_list.prev,
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500660 &selection->selection_focus_listener.link);
661
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400662 wl_resource_post_event(&selection->selection_offer.resource,
663 WL_SELECTION_OFFER_KEYBOARD_FOCUS,
664 selection->input_device);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500665 }
666
667 selection->selection_focus = surface;
668
669 wl_list_remove(&selection->selection_focus_listener.link);
670 if (surface)
Benjamin Franzke4721a3c2011-05-06 17:13:17 +0200671 wl_list_insert(surface->resource.destroy_listener_list.prev,
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500672 &selection->selection_focus_listener.link);
673}
674
675static void
676selection_offer_receive(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400677 struct wl_resource *resource,
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500678 const char *mime_type, int fd)
679{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400680 struct wl_selection_offer *offer = resource->data;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500681 struct wl_selection *selection =
682 container_of(offer, struct wl_selection, selection_offer);
683
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400684 wl_resource_post_event(&selection->resource,
685 WL_SELECTION_SEND, mime_type, fd);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500686 close(fd);
687}
688
689static const struct wl_selection_offer_interface selection_offer_interface = {
690 selection_offer_receive
691};
692
693static void
694selection_offer(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400695 struct wl_resource *resource, const char *type)
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500696{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400697 struct wl_selection *selection = resource->data;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500698 char **p;
699
700 p = wl_array_add(&selection->types, sizeof *p);
701 if (p)
702 *p = strdup(type);
703 if (!p || !*p)
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400704 wl_resource_post_no_memory(resource);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500705}
706
707static void
708selection_activate(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400709 struct wl_resource *resource,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400710 struct wl_resource *input_resource, uint32_t time)
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500711{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400712 struct wl_selection *selection = resource->data;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400713 struct wlsc_input_device *wd = input_resource->data;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500714 struct wl_display *display = wl_client_get_display (client);
Kristian Høgsberga8873122011-11-23 10:39:34 -0500715 struct wlsc_compositor *compositor = wd->compositor;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500716
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400717 selection->input_device = &wd->input_device;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500718
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400719 selection->selection_offer.resource.object.interface =
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500720 &wl_selection_offer_interface;
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400721 selection->selection_offer.resource.object.implementation =
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500722 (void (**)(void)) &selection_offer_interface;
723
Kristian Høgsbergd9551a32011-08-19 12:07:44 -0400724 wl_display_add_global(display,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400725 &wl_selection_offer_interface, selection, NULL);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500726
727 if (wd->selection) {
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400728 wl_resource_post_event(&wd->selection->resource,
729 WL_SELECTION_CANCELLED);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500730 }
731 wd->selection = selection;
732
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400733 wlsc_selection_set_focus(compositor->shell, selection,
734 wd->input_device.keyboard_focus, time);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500735}
736
737static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400738selection_destroy(struct wl_client *client, struct wl_resource *resource)
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500739{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400740 wl_resource_destroy(resource, wlsc_compositor_get_time());
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500741}
742
743static const struct wl_selection_interface selection_interface = {
744 selection_offer,
745 selection_activate,
746 selection_destroy
747};
748
749static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400750destroy_selection(struct wl_resource *resource)
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500751{
752 struct wl_selection *selection =
753 container_of(resource, struct wl_selection, resource);
754 struct wlsc_input_device *wd =
755 (struct wlsc_input_device *) selection->input_device;
Kristian Høgsberga8873122011-11-23 10:39:34 -0500756 struct wlsc_compositor *compositor = wd->compositor;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500757
758 if (wd && wd->selection == selection) {
759 wd->selection = NULL;
Kristian Høgsberg1c562182011-05-02 22:09:20 -0400760 wlsc_selection_set_focus(compositor->shell,
761 selection, NULL,
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400762 wlsc_compositor_get_time());
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500763 }
764
765 wl_list_remove(&selection->selection_focus_listener.link);
766 free(selection);
767}
768
769static void
770selection_handle_surface_destroy(struct wl_listener *listener,
Benjamin Franzke4721a3c2011-05-06 17:13:17 +0200771 struct wl_resource *resource, uint32_t time)
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500772{
773}
774
775static void
776shell_create_selection(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400777 struct wl_resource *resource, uint32_t id)
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500778{
779 struct wl_selection *selection;
780
781 selection = malloc(sizeof *selection);
782 if (selection == NULL) {
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400783 wl_resource_post_no_memory(resource);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500784 return;
785 }
786
787 memset(selection, 0, sizeof *selection);
788 selection->resource.object.id = id;
789 selection->resource.object.interface = &wl_selection_interface;
790 selection->resource.object.implementation =
791 (void (**)(void)) &selection_interface;
792
793 selection->client = client;
794 selection->resource.destroy = destroy_selection;
795 selection->selection_focus = NULL;
796
797 selection->selection_focus_listener.func =
798 selection_handle_surface_destroy;
799 wl_list_init(&selection->selection_focus_listener.link);
800
801 wl_client_add_resource(client, &selection->resource);
802}
803
Kristian Høgsberg75840622011-09-06 13:48:16 -0400804static const struct wl_shell_interface shell_interface = {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500805 shell_move,
806 shell_resize,
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500807 shell_create_drag,
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400808 shell_create_selection,
809 shell_set_toplevel,
810 shell_set_transient,
811 shell_set_fullscreen
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500812};
813
Kristian Høgsberg07937562011-04-12 17:25:42 -0400814static void
Kristian Høgsberg75840622011-09-06 13:48:16 -0400815handle_background_surface_destroy(struct wl_listener *listener,
816 struct wl_resource *resource, uint32_t time)
817{
818 struct wl_shell *shell =
819 container_of(listener, struct wl_shell, background_listener);
820
821 fprintf(stderr, "background surface gone\n");
822 shell->background = NULL;
823}
824
825static void
826desktop_shell_set_background(struct wl_client *client,
827 struct wl_resource *resource,
828 struct wl_resource *surface_resource)
829{
830 struct wl_shell *shell = resource->data;
831 struct wlsc_surface *surface = surface_resource->data;
832 struct wlsc_output *output =
833 container_of(shell->compositor->output_list.next,
834 struct wlsc_output, link);
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200835 struct shell_surface *priv;
Kristian Høgsberg75840622011-09-06 13:48:16 -0400836
837 shell->background = surface_resource->data;
838 shell->background_listener.func = handle_background_surface_destroy;
839 wl_list_insert(&surface_resource->destroy_listener_list,
840 &shell->background_listener.link);
841
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200842 priv = get_shell_surface(surface);
843 priv->purpose = SHELL_SURFACE_BACKGROUND;
844
Kristian Høgsberg75840622011-09-06 13:48:16 -0400845 wl_resource_post_event(resource,
846 DESKTOP_SHELL_CONFIGURE,
847 wlsc_compositor_get_time(), 0, surface,
848 output->current->width,
849 output->current->height);
850}
851
852static void
853handle_panel_surface_destroy(struct wl_listener *listener,
854 struct wl_resource *resource, uint32_t time)
855{
856 struct wl_shell *shell =
857 container_of(listener, struct wl_shell, panel_listener);
858
859 fprintf(stderr, "panel surface gone\n");
860 shell->panel = NULL;
861}
862
863static void
864desktop_shell_set_panel(struct wl_client *client,
865 struct wl_resource *resource,
866 struct wl_resource *surface_resource)
867{
868 struct wl_shell *shell = resource->data;
869 struct wlsc_output *output =
870 container_of(shell->compositor->output_list.next,
871 struct wlsc_output, link);
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200872 struct shell_surface *priv;
Kristian Høgsberg75840622011-09-06 13:48:16 -0400873
874 shell->panel = surface_resource->data;
875
876 shell->panel_listener.func = handle_panel_surface_destroy;
877 wl_list_insert(&surface_resource->destroy_listener_list,
878 &shell->panel_listener.link);
879
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200880 priv = get_shell_surface(shell->panel);
881 priv->purpose = SHELL_SURFACE_PANEL;
882
Kristian Høgsberg75840622011-09-06 13:48:16 -0400883 wl_resource_post_event(resource,
884 DESKTOP_SHELL_CONFIGURE,
885 wlsc_compositor_get_time(), 0, surface_resource,
886 output->current->width,
887 output->current->height);
888}
889
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200890static void
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500891handle_lock_surface_destroy(struct wl_listener *listener,
892 struct wl_resource *resource, uint32_t time)
893{
894 struct wl_shell *shell =
Pekka Paalanen2ca86302011-11-16 13:47:35 +0200895 container_of(listener, struct wl_shell, lock_surface_listener);
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500896
897 fprintf(stderr, "lock surface gone\n");
898 shell->lock_surface = NULL;
899}
900
901static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200902desktop_shell_set_lock_surface(struct wl_client *client,
903 struct wl_resource *resource,
904 struct wl_resource *surface_resource)
905{
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +0200906 struct wl_shell *shell = resource->data;
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200907 struct shell_surface *priv;
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +0200908
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200909 shell->prepare_event_sent = false;
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +0200910
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200911 if (!shell->locked)
912 return;
913
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500914 shell->lock_surface = surface_resource->data;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200915
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500916 shell->lock_surface_listener.func = handle_lock_surface_destroy;
917 wl_list_insert(&surface_resource->destroy_listener_list,
918 &shell->lock_surface_listener.link);
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200919
920 priv = get_shell_surface(shell->lock_surface);
921 priv->purpose = SHELL_SURFACE_LOCK;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200922}
923
924static void
925resume_desktop(struct wl_shell *shell)
926{
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500927 struct wlsc_surface *surface;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200928
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500929 wl_list_for_each(surface, &shell->hidden_surface_list, link)
930 wlsc_surface_configure(surface, surface->x, surface->y,
931 surface->width, surface->height);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200932
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500933 wl_list_insert_list(shell->background->link.prev,
934 &shell->hidden_surface_list);
935 wl_list_init(&shell->hidden_surface_list);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200936
937 shell->locked = false;
938 wlsc_compositor_repick(shell->compositor);
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +0200939 wlsc_compositor_wake(shell->compositor);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200940}
941
942static void
943desktop_shell_unlock(struct wl_client *client,
944 struct wl_resource *resource)
945{
946 struct wl_shell *shell = resource->data;
947
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200948 shell->prepare_event_sent = false;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200949
950 if (shell->locked)
951 resume_desktop(shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200952}
953
Kristian Høgsberg75840622011-09-06 13:48:16 -0400954static const struct desktop_shell_interface desktop_shell_implementation = {
955 desktop_shell_set_background,
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200956 desktop_shell_set_panel,
957 desktop_shell_set_lock_surface,
958 desktop_shell_unlock
Kristian Høgsberg75840622011-09-06 13:48:16 -0400959};
960
961static void
Kristian Høgsberg07937562011-04-12 17:25:42 -0400962move_binding(struct wl_input_device *device, uint32_t time,
963 uint32_t key, uint32_t button, uint32_t state, void *data)
964{
Kristian Høgsberg75840622011-09-06 13:48:16 -0400965 struct wl_shell *shell = data;
Kristian Høgsberg07937562011-04-12 17:25:42 -0400966 struct wlsc_surface *surface =
967 (struct wlsc_surface *) device->pointer_focus;
968
Kristian Høgsberga4a42f02011-09-08 16:56:57 -0400969 if (surface == NULL ||
970 surface->map_type == WLSC_SURFACE_MAP_FULLSCREEN)
Kristian Høgsberg10f097e2011-04-13 11:52:54 -0400971 return;
Kristian Høgsberg75840622011-09-06 13:48:16 -0400972 if (surface == shell->panel)
973 return;
974 if (surface == shell->background)
975 return;
Kristian Høgsberg10f097e2011-04-13 11:52:54 -0400976
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400977 wlsc_surface_move(surface, (struct wlsc_input_device *) device, time);
Kristian Høgsberg07937562011-04-12 17:25:42 -0400978}
979
980static void
981resize_binding(struct wl_input_device *device, uint32_t time,
982 uint32_t key, uint32_t button, uint32_t state, void *data)
983{
Kristian Høgsberg75840622011-09-06 13:48:16 -0400984 struct wl_shell *shell = data;
Kristian Høgsberg07937562011-04-12 17:25:42 -0400985 struct wlsc_surface *surface =
986 (struct wlsc_surface *) device->pointer_focus;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400987 struct wl_resource *resource;
Kristian Høgsberg07937562011-04-12 17:25:42 -0400988 uint32_t edges = 0;
989 int32_t x, y;
990
Kristian Høgsberga4a42f02011-09-08 16:56:57 -0400991 if (surface == NULL ||
992 surface->map_type == WLSC_SURFACE_MAP_FULLSCREEN)
Kristian Høgsberg75840622011-09-06 13:48:16 -0400993 if (surface == shell->panel)
994 return;
995 if (surface == shell->background)
996 return;
Kristian Høgsberg10f097e2011-04-13 11:52:54 -0400997
Kristian Høgsberg07937562011-04-12 17:25:42 -0400998 x = device->grab_x - surface->x;
999 y = device->grab_y - surface->y;
1000
1001 if (x < surface->width / 3)
1002 edges |= WL_SHELL_RESIZE_LEFT;
1003 else if (x < 2 * surface->width / 3)
1004 edges |= 0;
1005 else
1006 edges |= WL_SHELL_RESIZE_RIGHT;
1007
1008 if (y < surface->height / 3)
1009 edges |= WL_SHELL_RESIZE_TOP;
1010 else if (y < 2 * surface->height / 3)
1011 edges |= 0;
1012 else
1013 edges |= WL_SHELL_RESIZE_BOTTOM;
1014
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001015 resource = /* Find shell resource for surface client */ 0;
1016
1017 /* ... or use wl_shell_surface */
1018
1019 wlsc_surface_resize(surface, (struct wlsc_input_device *) device,
1020 time, edges, resource);
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001021}
1022
1023static void
Kristian Høgsberg75840622011-09-06 13:48:16 -04001024activate(struct wlsc_shell *base, struct wlsc_surface *es,
1025 struct wlsc_input_device *device, uint32_t time)
1026{
1027 struct wl_shell *shell = container_of(base, struct wl_shell, shell);
1028 struct wlsc_compositor *compositor = shell->compositor;
Pekka Paalanen57da4a82011-11-23 16:42:16 +02001029 struct shell_surface *priv;
1030
1031 priv = get_shell_surface(es);
Kristian Høgsberg75840622011-09-06 13:48:16 -04001032
1033 wlsc_surface_activate(es, device, time);
1034
Kristian Høgsbergd6e55252011-10-11 23:41:17 -04001035 if (compositor->wxs)
1036 wlsc_xserver_surface_activate(es);
1037
Pekka Paalanen57da4a82011-11-23 16:42:16 +02001038 switch (priv->purpose) {
1039 case SHELL_SURFACE_BACKGROUND:
1040 /* put background back to bottom */
Kristian Høgsberg75840622011-09-06 13:48:16 -04001041 wl_list_remove(&es->link);
1042 wl_list_insert(compositor->surface_list.prev, &es->link);
Pekka Paalanen57da4a82011-11-23 16:42:16 +02001043 break;
1044 case SHELL_SURFACE_PANEL:
1045 /* already put on top */
1046 break;
1047 default:
1048 if (shell->panel && !shell->locked) {
1049 /* bring panel back to top */
1050 wl_list_remove(&shell->panel->link);
1051 wl_list_insert(&compositor->surface_list,
1052 &shell->panel->link);
1053 }
Kristian Høgsberg75840622011-09-06 13:48:16 -04001054 }
1055}
1056
1057static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001058lock(struct wlsc_shell *base)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001059{
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001060 struct wl_shell *shell = container_of(base, struct wl_shell, shell);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001061 struct wl_list *surface_list = &shell->compositor->surface_list;
1062 struct wlsc_surface *cur;
1063 struct wlsc_surface *tmp;
Pekka Paalanen57da4a82011-11-23 16:42:16 +02001064 struct shell_surface *priv;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001065 struct wlsc_input_device *device;
1066 uint32_t time;
1067
1068 if (shell->locked)
1069 return;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001070
1071 shell->locked = true;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001072
1073 /* Move all surfaces from compositor's list to our hidden list,
1074 * except the background. This way nothing else can show or
1075 * receive input events while we are locked. */
1076
1077 if (!wl_list_empty(&shell->hidden_surface_list)) {
1078 fprintf(stderr,
1079 "%s: Assertion failed: hidden_surface_list is not empty.\n",
1080 __func__);
1081 }
1082
1083 wl_list_for_each_safe(cur, tmp, surface_list, link) {
1084 /* skip input device sprites, cur->surface is uninitialised */
1085 if (cur->surface.resource.client == NULL)
1086 continue;
1087
Pekka Paalanen57da4a82011-11-23 16:42:16 +02001088 priv = get_shell_surface(cur);
1089 if (priv->purpose == SHELL_SURFACE_BACKGROUND)
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001090 continue;
1091
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001092 cur->output = NULL;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001093 wl_list_remove(&cur->link);
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001094 wl_list_insert(shell->hidden_surface_list.prev, &cur->link);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001095 }
1096
1097 /* reset pointer foci */
1098 wlsc_compositor_repick(shell->compositor);
1099
1100 /* reset keyboard foci */
1101 time = wlsc_compositor_get_time();
1102 wl_list_for_each(device, &shell->compositor->input_device_list, link) {
1103 wl_input_device_set_keyboard_focus(&device->input_device,
1104 NULL, time);
1105 }
1106
1107 /* TODO: disable bindings that should not work while locked. */
1108
1109 /* All this must be undone in resume_desktop(). */
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001110}
1111
1112static void
1113unlock(struct wlsc_shell *base)
1114{
1115 struct wl_shell *shell = container_of(base, struct wl_shell, shell);
1116
Pekka Paalanend81c2162011-11-16 13:47:34 +02001117 if (!shell->locked || shell->lock_surface) {
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001118 wlsc_compositor_wake(shell->compositor);
1119 return;
1120 }
1121
1122 /* If desktop-shell client has gone away, unlock immediately. */
1123 if (!shell->child.desktop_shell) {
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001124 resume_desktop(shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001125 return;
1126 }
1127
1128 if (shell->prepare_event_sent)
1129 return;
1130
1131 wl_resource_post_event(shell->child.desktop_shell,
1132 DESKTOP_SHELL_PREPARE_LOCK_SURFACE);
1133 shell->prepare_event_sent = true;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001134}
1135
1136static void
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05001137map(struct wlsc_shell *base,
1138 struct wlsc_surface *surface, int32_t width, int32_t height)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001139{
Kristian Høgsberg75840622011-09-06 13:48:16 -04001140 struct wl_shell *shell = container_of(base, struct wl_shell, shell);
1141 struct wlsc_compositor *compositor = shell->compositor;
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001142 struct wl_list *list;
Pekka Paalanen57da4a82011-11-23 16:42:16 +02001143 struct shell_surface *priv;
1144
1145 priv = get_shell_surface(surface);
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001146
1147 if (shell->locked)
1148 list = &shell->hidden_surface_list;
1149 else
1150 list = &compositor->surface_list;
Kristian Høgsberg75840622011-09-06 13:48:16 -04001151
Pekka Paalanend3dd6e12011-11-16 13:47:33 +02001152 /* surface stacking order, see also activate() */
Pekka Paalanen57da4a82011-11-23 16:42:16 +02001153 switch (priv->purpose) {
1154 case SHELL_SURFACE_BACKGROUND:
Pekka Paalanend3dd6e12011-11-16 13:47:33 +02001155 /* background always visible, at the bottom */
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05001156 wl_list_insert(compositor->surface_list.prev, &surface->link);
Pekka Paalanen57da4a82011-11-23 16:42:16 +02001157 break;
1158 case SHELL_SURFACE_PANEL:
Pekka Paalanend3dd6e12011-11-16 13:47:33 +02001159 /* panel always on top, hidden while locked */
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001160 wl_list_insert(list, &surface->link);
Pekka Paalanen57da4a82011-11-23 16:42:16 +02001161 break;
1162 case SHELL_SURFACE_LOCK:
Pekka Paalanend3dd6e12011-11-16 13:47:33 +02001163 /* lock surface always visible, on top */
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001164 wl_list_insert(&compositor->surface_list, &surface->link);
Pekka Paalanend3dd6e12011-11-16 13:47:33 +02001165
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001166 wlsc_compositor_repick(compositor);
Pekka Paalanen57da4a82011-11-23 16:42:16 +02001167 wlsc_compositor_wake(compositor);
1168 break;
1169 default:
Pekka Paalanend3dd6e12011-11-16 13:47:33 +02001170 /* everything else just below the panel */
Pekka Paalanen57da4a82011-11-23 16:42:16 +02001171 if (shell->panel)
1172 wl_list_insert(&shell->panel->link, &surface->link);
1173 else
1174 wl_list_insert(list, &surface->link);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001175 }
1176
Kristian Høgsberg46770132011-11-09 12:38:53 -05001177 if (surface->map_type == WLSC_SURFACE_MAP_TOPLEVEL) {
1178 surface->x = 10 + random() % 400;
1179 surface->y = 10 + random() % 400;
1180 }
1181
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001182 surface->width = width;
1183 surface->height = height;
Pekka Paalanen57da4a82011-11-23 16:42:16 +02001184 if (!shell->locked || priv->purpose == SHELL_SURFACE_LOCK)
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001185 wlsc_surface_configure(surface,
1186 surface->x, surface->y, width, height);
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05001187}
1188
1189static void
1190configure(struct wlsc_shell *shell, struct wlsc_surface *surface,
1191 int32_t x, int32_t y, int32_t width, int32_t height)
1192{
1193 struct wlsc_mode *current;
1194
1195 if (surface->map_type == WLSC_SURFACE_MAP_FULLSCREEN) {
1196 current = surface->fullscreen_output->current;
1197 x = (current->width - surface->width) / 2;
1198 y = (current->height - surface->height) / 2;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001199 }
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05001200
1201 wlsc_surface_configure(surface, x, y, width, height);
Kristian Høgsberg07937562011-04-12 17:25:42 -04001202}
1203
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001204static void
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02001205desktop_shell_sigchld(struct wlsc_process *process, int status)
1206{
1207 struct wl_shell *shell =
1208 container_of(process, struct wl_shell, child.process);
1209
1210 shell->child.process.pid = 0;
1211 shell->child.client = NULL; /* already destroyed by wayland */
1212}
1213
1214static int
1215launch_desktop_shell_process(struct wl_shell *shell)
1216{
Kristian Høgsbergc4693c42011-11-14 14:57:17 -05001217 const char *shell_exe = LIBEXECDIR "/wayland-desktop-shell";
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02001218 struct wlsc_compositor *compositor = shell->compositor;
1219 char s[32];
1220 int sv[2], flags;
1221
1222 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) {
1223 fprintf(stderr, "socketpair failed\n");
1224 return -1;
1225 }
1226
1227 shell->child.process.pid = fork();
1228 shell->child.process.cleanup = desktop_shell_sigchld;
1229
1230 switch (shell->child.process.pid) {
1231 case 0:
1232 /* SOCK_CLOEXEC closes both ends, so we need to unset
1233 * the flag on the client fd. */
1234 flags = fcntl(sv[1], F_GETFD);
1235 if (flags != -1)
1236 fcntl(sv[1], F_SETFD, flags & ~FD_CLOEXEC);
1237
1238 snprintf(s, sizeof s, "%d", sv[1]);
1239 setenv("WAYLAND_SOCKET", s, 1);
1240 if (execl(shell_exe, shell_exe, NULL) < 0)
1241 fprintf(stderr, "%s: running '%s' failed: %m\n",
1242 __func__, shell_exe);
1243 exit(-1);
1244
1245 default:
1246 close(sv[1]);
1247 shell->child.client =
1248 wl_client_create(compositor->wl_display, sv[0]);
1249 wlsc_watch_process(&shell->child.process);
1250 break;
1251
1252 case -1:
1253 fprintf(stderr, "%s: fork failed: %m\n", __func__);
1254 return -1;
1255 }
1256 return 0;
1257}
1258
1259static void
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001260bind_shell(struct wl_client *client, void *data, uint32_t version, uint32_t id)
1261{
1262 struct wl_shell *shell = data;
1263
1264 wl_client_add_object(client, &wl_shell_interface,
1265 &shell_interface, id, shell);
1266}
1267
Kristian Høgsberg75840622011-09-06 13:48:16 -04001268static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001269unbind_desktop_shell(struct wl_resource *resource)
1270{
1271 struct wl_shell *shell = resource->data;
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001272
1273 if (shell->locked)
1274 resume_desktop(shell);
1275
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001276 shell->child.desktop_shell = NULL;
1277 shell->prepare_event_sent = false;
1278 free(resource);
1279}
1280
1281static void
Kristian Høgsberg75840622011-09-06 13:48:16 -04001282bind_desktop_shell(struct wl_client *client,
1283 void *data, uint32_t version, uint32_t id)
1284{
1285 struct wl_shell *shell = data;
Pekka Paalanenbbe60522011-11-03 14:11:33 +02001286 struct wl_resource *resource;
Kristian Høgsberg75840622011-09-06 13:48:16 -04001287
Pekka Paalanenbbe60522011-11-03 14:11:33 +02001288 resource = wl_client_add_object(client, &desktop_shell_interface,
1289 &desktop_shell_implementation,
1290 id, shell);
1291
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001292 if (client == shell->child.client) {
1293 resource->destroy = unbind_desktop_shell;
1294 shell->child.desktop_shell = resource;
Pekka Paalanenbbe60522011-11-03 14:11:33 +02001295 return;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001296 }
Pekka Paalanenbbe60522011-11-03 14:11:33 +02001297
1298 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
1299 "permission to bind desktop_shell denied");
1300 wl_resource_destroy(resource, 0);
Kristian Høgsberg75840622011-09-06 13:48:16 -04001301}
1302
Kristian Høgsberg6c709a32011-05-06 14:52:41 -04001303int
1304shell_init(struct wlsc_compositor *ec);
1305
Kristian Høgsberg1c562182011-05-02 22:09:20 -04001306WL_EXPORT int
1307shell_init(struct wlsc_compositor *ec)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001308{
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001309 struct wl_shell *shell;
1310
1311 shell = malloc(sizeof *shell);
1312 if (shell == NULL)
1313 return -1;
1314
Kristian Høgsbergf0d91162011-10-11 22:44:23 -04001315 memset(shell, 0, sizeof *shell);
Kristian Høgsberg75840622011-09-06 13:48:16 -04001316 shell->compositor = ec;
1317 shell->shell.activate = activate;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001318 shell->shell.lock = lock;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001319 shell->shell.unlock = unlock;
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05001320 shell->shell.map = map;
1321 shell->shell.configure = configure;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04001322 shell->shell.set_selection_focus = wlsc_selection_set_focus;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001323
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001324 wl_list_init(&shell->hidden_surface_list);
1325
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001326 if (wl_display_add_global(ec->wl_display, &wl_shell_interface,
1327 shell, bind_shell) == NULL)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001328 return -1;
1329
Kristian Høgsberg75840622011-09-06 13:48:16 -04001330 if (wl_display_add_global(ec->wl_display,
1331 &desktop_shell_interface,
1332 shell, bind_desktop_shell) == NULL)
1333 return -1;
1334
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02001335 if (launch_desktop_shell_process(shell) != 0)
1336 return -1;
1337
Kristian Høgsberg07937562011-04-12 17:25:42 -04001338 wlsc_compositor_add_binding(ec, 0, BTN_LEFT, MODIFIER_SUPER,
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001339 move_binding, shell);
Kristian Høgsberg07937562011-04-12 17:25:42 -04001340 wlsc_compositor_add_binding(ec, 0, BTN_MIDDLE, MODIFIER_SUPER,
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001341 resize_binding, shell);
1342
1343 ec->shell = &shell->shell;
Kristian Høgsberg07937562011-04-12 17:25:42 -04001344
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001345 return 0;
1346}