blob: 034db55315401be44e166728ef98abe4c0764449 [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øgsberg1c562182011-05-02 22:09:20 -0400715 struct wlsc_compositor *compositor =
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400716 (struct wlsc_compositor *) wd->input_device.compositor;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500717
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400718 selection->input_device = &wd->input_device;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500719
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400720 selection->selection_offer.resource.object.interface =
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500721 &wl_selection_offer_interface;
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400722 selection->selection_offer.resource.object.implementation =
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500723 (void (**)(void)) &selection_offer_interface;
724
Kristian Høgsbergd9551a32011-08-19 12:07:44 -0400725 wl_display_add_global(display,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400726 &wl_selection_offer_interface, selection, NULL);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500727
728 if (wd->selection) {
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400729 wl_resource_post_event(&wd->selection->resource,
730 WL_SELECTION_CANCELLED);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500731 }
732 wd->selection = selection;
733
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400734 wlsc_selection_set_focus(compositor->shell, selection,
735 wd->input_device.keyboard_focus, time);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500736}
737
738static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400739selection_destroy(struct wl_client *client, struct wl_resource *resource)
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500740{
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400741 wl_resource_destroy(resource, wlsc_compositor_get_time());
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500742}
743
744static const struct wl_selection_interface selection_interface = {
745 selection_offer,
746 selection_activate,
747 selection_destroy
748};
749
750static void
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400751destroy_selection(struct wl_resource *resource)
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500752{
753 struct wl_selection *selection =
754 container_of(resource, struct wl_selection, resource);
755 struct wlsc_input_device *wd =
756 (struct wlsc_input_device *) selection->input_device;
Kristian Høgsberg1c562182011-05-02 22:09:20 -0400757 struct wlsc_compositor *compositor =
758 (struct wlsc_compositor *) wd->input_device.compositor;
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500759
760 if (wd && wd->selection == selection) {
761 wd->selection = NULL;
Kristian Høgsberg1c562182011-05-02 22:09:20 -0400762 wlsc_selection_set_focus(compositor->shell,
763 selection, NULL,
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400764 wlsc_compositor_get_time());
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500765 }
766
767 wl_list_remove(&selection->selection_focus_listener.link);
768 free(selection);
769}
770
771static void
772selection_handle_surface_destroy(struct wl_listener *listener,
Benjamin Franzke4721a3c2011-05-06 17:13:17 +0200773 struct wl_resource *resource, uint32_t time)
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500774{
775}
776
777static void
778shell_create_selection(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400779 struct wl_resource *resource, uint32_t id)
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500780{
781 struct wl_selection *selection;
782
783 selection = malloc(sizeof *selection);
784 if (selection == NULL) {
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400785 wl_resource_post_no_memory(resource);
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500786 return;
787 }
788
789 memset(selection, 0, sizeof *selection);
790 selection->resource.object.id = id;
791 selection->resource.object.interface = &wl_selection_interface;
792 selection->resource.object.implementation =
793 (void (**)(void)) &selection_interface;
794
795 selection->client = client;
796 selection->resource.destroy = destroy_selection;
797 selection->selection_focus = NULL;
798
799 selection->selection_focus_listener.func =
800 selection_handle_surface_destroy;
801 wl_list_init(&selection->selection_focus_listener.link);
802
803 wl_client_add_resource(client, &selection->resource);
804}
805
Kristian Høgsberg75840622011-09-06 13:48:16 -0400806static const struct wl_shell_interface shell_interface = {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500807 shell_move,
808 shell_resize,
Kristian Høgsbergae6c8a62011-01-18 09:08:53 -0500809 shell_create_drag,
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400810 shell_create_selection,
811 shell_set_toplevel,
812 shell_set_transient,
813 shell_set_fullscreen
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500814};
815
Kristian Høgsberg07937562011-04-12 17:25:42 -0400816static void
Kristian Høgsberg75840622011-09-06 13:48:16 -0400817handle_background_surface_destroy(struct wl_listener *listener,
818 struct wl_resource *resource, uint32_t time)
819{
820 struct wl_shell *shell =
821 container_of(listener, struct wl_shell, background_listener);
822
823 fprintf(stderr, "background surface gone\n");
824 shell->background = NULL;
825}
826
827static void
828desktop_shell_set_background(struct wl_client *client,
829 struct wl_resource *resource,
830 struct wl_resource *surface_resource)
831{
832 struct wl_shell *shell = resource->data;
833 struct wlsc_surface *surface = surface_resource->data;
834 struct wlsc_output *output =
835 container_of(shell->compositor->output_list.next,
836 struct wlsc_output, link);
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200837 struct shell_surface *priv;
Kristian Høgsberg75840622011-09-06 13:48:16 -0400838
839 shell->background = surface_resource->data;
840 shell->background_listener.func = handle_background_surface_destroy;
841 wl_list_insert(&surface_resource->destroy_listener_list,
842 &shell->background_listener.link);
843
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200844 priv = get_shell_surface(surface);
845 priv->purpose = SHELL_SURFACE_BACKGROUND;
846
Kristian Høgsberg75840622011-09-06 13:48:16 -0400847 wl_resource_post_event(resource,
848 DESKTOP_SHELL_CONFIGURE,
849 wlsc_compositor_get_time(), 0, surface,
850 output->current->width,
851 output->current->height);
852}
853
854static void
855handle_panel_surface_destroy(struct wl_listener *listener,
856 struct wl_resource *resource, uint32_t time)
857{
858 struct wl_shell *shell =
859 container_of(listener, struct wl_shell, panel_listener);
860
861 fprintf(stderr, "panel surface gone\n");
862 shell->panel = NULL;
863}
864
865static void
866desktop_shell_set_panel(struct wl_client *client,
867 struct wl_resource *resource,
868 struct wl_resource *surface_resource)
869{
870 struct wl_shell *shell = resource->data;
871 struct wlsc_output *output =
872 container_of(shell->compositor->output_list.next,
873 struct wlsc_output, link);
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200874 struct shell_surface *priv;
Kristian Høgsberg75840622011-09-06 13:48:16 -0400875
876 shell->panel = surface_resource->data;
877
878 shell->panel_listener.func = handle_panel_surface_destroy;
879 wl_list_insert(&surface_resource->destroy_listener_list,
880 &shell->panel_listener.link);
881
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200882 priv = get_shell_surface(shell->panel);
883 priv->purpose = SHELL_SURFACE_PANEL;
884
Kristian Høgsberg75840622011-09-06 13:48:16 -0400885 wl_resource_post_event(resource,
886 DESKTOP_SHELL_CONFIGURE,
887 wlsc_compositor_get_time(), 0, surface_resource,
888 output->current->width,
889 output->current->height);
890}
891
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200892static void
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500893handle_lock_surface_destroy(struct wl_listener *listener,
894 struct wl_resource *resource, uint32_t time)
895{
896 struct wl_shell *shell =
Pekka Paalanen2ca86302011-11-16 13:47:35 +0200897 container_of(listener, struct wl_shell, lock_surface_listener);
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500898
899 fprintf(stderr, "lock surface gone\n");
900 shell->lock_surface = NULL;
901}
902
903static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200904desktop_shell_set_lock_surface(struct wl_client *client,
905 struct wl_resource *resource,
906 struct wl_resource *surface_resource)
907{
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +0200908 struct wl_shell *shell = resource->data;
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200909 struct shell_surface *priv;
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +0200910
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200911 shell->prepare_event_sent = false;
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +0200912
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200913 if (!shell->locked)
914 return;
915
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500916 shell->lock_surface = surface_resource->data;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200917
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500918 shell->lock_surface_listener.func = handle_lock_surface_destroy;
919 wl_list_insert(&surface_resource->destroy_listener_list,
920 &shell->lock_surface_listener.link);
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200921
922 priv = get_shell_surface(shell->lock_surface);
923 priv->purpose = SHELL_SURFACE_LOCK;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200924}
925
926static void
927resume_desktop(struct wl_shell *shell)
928{
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500929 struct wlsc_surface *surface;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200930
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500931 wl_list_for_each(surface, &shell->hidden_surface_list, link)
932 wlsc_surface_configure(surface, surface->x, surface->y,
933 surface->width, surface->height);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200934
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500935 wl_list_insert_list(shell->background->link.prev,
936 &shell->hidden_surface_list);
937 wl_list_init(&shell->hidden_surface_list);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200938
939 shell->locked = false;
940 wlsc_compositor_repick(shell->compositor);
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +0200941 wlsc_compositor_wake(shell->compositor);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200942}
943
944static void
945desktop_shell_unlock(struct wl_client *client,
946 struct wl_resource *resource)
947{
948 struct wl_shell *shell = resource->data;
949
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200950 shell->prepare_event_sent = false;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200951
952 if (shell->locked)
953 resume_desktop(shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200954}
955
Kristian Høgsberg75840622011-09-06 13:48:16 -0400956static const struct desktop_shell_interface desktop_shell_implementation = {
957 desktop_shell_set_background,
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200958 desktop_shell_set_panel,
959 desktop_shell_set_lock_surface,
960 desktop_shell_unlock
Kristian Høgsberg75840622011-09-06 13:48:16 -0400961};
962
963static void
Kristian Høgsberg07937562011-04-12 17:25:42 -0400964move_binding(struct wl_input_device *device, uint32_t time,
965 uint32_t key, uint32_t button, uint32_t state, void *data)
966{
Kristian Høgsberg75840622011-09-06 13:48:16 -0400967 struct wl_shell *shell = data;
Kristian Høgsberg07937562011-04-12 17:25:42 -0400968 struct wlsc_surface *surface =
969 (struct wlsc_surface *) device->pointer_focus;
970
Kristian Høgsberga4a42f02011-09-08 16:56:57 -0400971 if (surface == NULL ||
972 surface->map_type == WLSC_SURFACE_MAP_FULLSCREEN)
Kristian Høgsberg10f097e2011-04-13 11:52:54 -0400973 return;
Kristian Høgsberg75840622011-09-06 13:48:16 -0400974 if (surface == shell->panel)
975 return;
976 if (surface == shell->background)
977 return;
Kristian Høgsberg10f097e2011-04-13 11:52:54 -0400978
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400979 wlsc_surface_move(surface, (struct wlsc_input_device *) device, time);
Kristian Høgsberg07937562011-04-12 17:25:42 -0400980}
981
982static void
983resize_binding(struct wl_input_device *device, uint32_t time,
984 uint32_t key, uint32_t button, uint32_t state, void *data)
985{
Kristian Høgsberg75840622011-09-06 13:48:16 -0400986 struct wl_shell *shell = data;
Kristian Høgsberg07937562011-04-12 17:25:42 -0400987 struct wlsc_surface *surface =
988 (struct wlsc_surface *) device->pointer_focus;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400989 struct wl_resource *resource;
Kristian Høgsberg07937562011-04-12 17:25:42 -0400990 uint32_t edges = 0;
991 int32_t x, y;
992
Kristian Høgsberga4a42f02011-09-08 16:56:57 -0400993 if (surface == NULL ||
994 surface->map_type == WLSC_SURFACE_MAP_FULLSCREEN)
Kristian Høgsberg75840622011-09-06 13:48:16 -0400995 if (surface == shell->panel)
996 return;
997 if (surface == shell->background)
998 return;
Kristian Høgsberg10f097e2011-04-13 11:52:54 -0400999
Kristian Høgsberg07937562011-04-12 17:25:42 -04001000 x = device->grab_x - surface->x;
1001 y = device->grab_y - surface->y;
1002
1003 if (x < surface->width / 3)
1004 edges |= WL_SHELL_RESIZE_LEFT;
1005 else if (x < 2 * surface->width / 3)
1006 edges |= 0;
1007 else
1008 edges |= WL_SHELL_RESIZE_RIGHT;
1009
1010 if (y < surface->height / 3)
1011 edges |= WL_SHELL_RESIZE_TOP;
1012 else if (y < 2 * surface->height / 3)
1013 edges |= 0;
1014 else
1015 edges |= WL_SHELL_RESIZE_BOTTOM;
1016
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001017 resource = /* Find shell resource for surface client */ 0;
1018
1019 /* ... or use wl_shell_surface */
1020
1021 wlsc_surface_resize(surface, (struct wlsc_input_device *) device,
1022 time, edges, resource);
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001023}
1024
1025static void
Kristian Høgsberg75840622011-09-06 13:48:16 -04001026activate(struct wlsc_shell *base, struct wlsc_surface *es,
1027 struct wlsc_input_device *device, uint32_t time)
1028{
1029 struct wl_shell *shell = container_of(base, struct wl_shell, shell);
1030 struct wlsc_compositor *compositor = shell->compositor;
Pekka Paalanen57da4a82011-11-23 16:42:16 +02001031 struct shell_surface *priv;
1032
1033 priv = get_shell_surface(es);
Kristian Høgsberg75840622011-09-06 13:48:16 -04001034
1035 wlsc_surface_activate(es, device, time);
1036
Kristian Høgsbergd6e55252011-10-11 23:41:17 -04001037 if (compositor->wxs)
1038 wlsc_xserver_surface_activate(es);
1039
Pekka Paalanen57da4a82011-11-23 16:42:16 +02001040 switch (priv->purpose) {
1041 case SHELL_SURFACE_BACKGROUND:
1042 /* put background back to bottom */
Kristian Høgsberg75840622011-09-06 13:48:16 -04001043 wl_list_remove(&es->link);
1044 wl_list_insert(compositor->surface_list.prev, &es->link);
Pekka Paalanen57da4a82011-11-23 16:42:16 +02001045 break;
1046 case SHELL_SURFACE_PANEL:
1047 /* already put on top */
1048 break;
1049 default:
1050 if (shell->panel && !shell->locked) {
1051 /* bring panel back to top */
1052 wl_list_remove(&shell->panel->link);
1053 wl_list_insert(&compositor->surface_list,
1054 &shell->panel->link);
1055 }
Kristian Høgsberg75840622011-09-06 13:48:16 -04001056 }
1057}
1058
1059static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001060lock(struct wlsc_shell *base)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001061{
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001062 struct wl_shell *shell = container_of(base, struct wl_shell, shell);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001063 struct wl_list *surface_list = &shell->compositor->surface_list;
1064 struct wlsc_surface *cur;
1065 struct wlsc_surface *tmp;
Pekka Paalanen57da4a82011-11-23 16:42:16 +02001066 struct shell_surface *priv;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001067 struct wlsc_input_device *device;
1068 uint32_t time;
1069
1070 if (shell->locked)
1071 return;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001072
1073 shell->locked = true;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001074
1075 /* Move all surfaces from compositor's list to our hidden list,
1076 * except the background. This way nothing else can show or
1077 * receive input events while we are locked. */
1078
1079 if (!wl_list_empty(&shell->hidden_surface_list)) {
1080 fprintf(stderr,
1081 "%s: Assertion failed: hidden_surface_list is not empty.\n",
1082 __func__);
1083 }
1084
1085 wl_list_for_each_safe(cur, tmp, surface_list, link) {
1086 /* skip input device sprites, cur->surface is uninitialised */
1087 if (cur->surface.resource.client == NULL)
1088 continue;
1089
Pekka Paalanen57da4a82011-11-23 16:42:16 +02001090 priv = get_shell_surface(cur);
1091 if (priv->purpose == SHELL_SURFACE_BACKGROUND)
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001092 continue;
1093
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001094 cur->output = NULL;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001095 wl_list_remove(&cur->link);
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001096 wl_list_insert(shell->hidden_surface_list.prev, &cur->link);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001097 }
1098
1099 /* reset pointer foci */
1100 wlsc_compositor_repick(shell->compositor);
1101
1102 /* reset keyboard foci */
1103 time = wlsc_compositor_get_time();
1104 wl_list_for_each(device, &shell->compositor->input_device_list, link) {
1105 wl_input_device_set_keyboard_focus(&device->input_device,
1106 NULL, time);
1107 }
1108
1109 /* TODO: disable bindings that should not work while locked. */
1110
1111 /* All this must be undone in resume_desktop(). */
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001112}
1113
1114static void
1115unlock(struct wlsc_shell *base)
1116{
1117 struct wl_shell *shell = container_of(base, struct wl_shell, shell);
1118
Pekka Paalanend81c2162011-11-16 13:47:34 +02001119 if (!shell->locked || shell->lock_surface) {
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001120 wlsc_compositor_wake(shell->compositor);
1121 return;
1122 }
1123
1124 /* If desktop-shell client has gone away, unlock immediately. */
1125 if (!shell->child.desktop_shell) {
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001126 resume_desktop(shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001127 return;
1128 }
1129
1130 if (shell->prepare_event_sent)
1131 return;
1132
1133 wl_resource_post_event(shell->child.desktop_shell,
1134 DESKTOP_SHELL_PREPARE_LOCK_SURFACE);
1135 shell->prepare_event_sent = true;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001136}
1137
1138static void
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05001139map(struct wlsc_shell *base,
1140 struct wlsc_surface *surface, int32_t width, int32_t height)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001141{
Kristian Høgsberg75840622011-09-06 13:48:16 -04001142 struct wl_shell *shell = container_of(base, struct wl_shell, shell);
1143 struct wlsc_compositor *compositor = shell->compositor;
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001144 struct wl_list *list;
Pekka Paalanen57da4a82011-11-23 16:42:16 +02001145 struct shell_surface *priv;
1146
1147 priv = get_shell_surface(surface);
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001148
1149 if (shell->locked)
1150 list = &shell->hidden_surface_list;
1151 else
1152 list = &compositor->surface_list;
Kristian Høgsberg75840622011-09-06 13:48:16 -04001153
Pekka Paalanend3dd6e12011-11-16 13:47:33 +02001154 /* surface stacking order, see also activate() */
Pekka Paalanen57da4a82011-11-23 16:42:16 +02001155 switch (priv->purpose) {
1156 case SHELL_SURFACE_BACKGROUND:
Pekka Paalanend3dd6e12011-11-16 13:47:33 +02001157 /* background always visible, at the bottom */
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05001158 wl_list_insert(compositor->surface_list.prev, &surface->link);
Pekka Paalanen57da4a82011-11-23 16:42:16 +02001159 break;
1160 case SHELL_SURFACE_PANEL:
Pekka Paalanend3dd6e12011-11-16 13:47:33 +02001161 /* panel always on top, hidden while locked */
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001162 wl_list_insert(list, &surface->link);
Pekka Paalanen57da4a82011-11-23 16:42:16 +02001163 break;
1164 case SHELL_SURFACE_LOCK:
Pekka Paalanend3dd6e12011-11-16 13:47:33 +02001165 /* lock surface always visible, on top */
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001166 wl_list_insert(&compositor->surface_list, &surface->link);
Pekka Paalanend3dd6e12011-11-16 13:47:33 +02001167
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001168 wlsc_compositor_repick(compositor);
Pekka Paalanen57da4a82011-11-23 16:42:16 +02001169 wlsc_compositor_wake(compositor);
1170 break;
1171 default:
Pekka Paalanend3dd6e12011-11-16 13:47:33 +02001172 /* everything else just below the panel */
Pekka Paalanen57da4a82011-11-23 16:42:16 +02001173 if (shell->panel)
1174 wl_list_insert(&shell->panel->link, &surface->link);
1175 else
1176 wl_list_insert(list, &surface->link);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001177 }
1178
Kristian Høgsberg46770132011-11-09 12:38:53 -05001179 if (surface->map_type == WLSC_SURFACE_MAP_TOPLEVEL) {
1180 surface->x = 10 + random() % 400;
1181 surface->y = 10 + random() % 400;
1182 }
1183
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001184 surface->width = width;
1185 surface->height = height;
Pekka Paalanen57da4a82011-11-23 16:42:16 +02001186 if (!shell->locked || priv->purpose == SHELL_SURFACE_LOCK)
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001187 wlsc_surface_configure(surface,
1188 surface->x, surface->y, width, height);
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05001189}
1190
1191static void
1192configure(struct wlsc_shell *shell, struct wlsc_surface *surface,
1193 int32_t x, int32_t y, int32_t width, int32_t height)
1194{
1195 struct wlsc_mode *current;
1196
1197 if (surface->map_type == WLSC_SURFACE_MAP_FULLSCREEN) {
1198 current = surface->fullscreen_output->current;
1199 x = (current->width - surface->width) / 2;
1200 y = (current->height - surface->height) / 2;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001201 }
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05001202
1203 wlsc_surface_configure(surface, x, y, width, height);
Kristian Høgsberg07937562011-04-12 17:25:42 -04001204}
1205
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001206static void
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02001207desktop_shell_sigchld(struct wlsc_process *process, int status)
1208{
1209 struct wl_shell *shell =
1210 container_of(process, struct wl_shell, child.process);
1211
1212 shell->child.process.pid = 0;
1213 shell->child.client = NULL; /* already destroyed by wayland */
1214}
1215
1216static int
1217launch_desktop_shell_process(struct wl_shell *shell)
1218{
Kristian Høgsbergc4693c42011-11-14 14:57:17 -05001219 const char *shell_exe = LIBEXECDIR "/wayland-desktop-shell";
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02001220 struct wlsc_compositor *compositor = shell->compositor;
1221 char s[32];
1222 int sv[2], flags;
1223
1224 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) {
1225 fprintf(stderr, "socketpair failed\n");
1226 return -1;
1227 }
1228
1229 shell->child.process.pid = fork();
1230 shell->child.process.cleanup = desktop_shell_sigchld;
1231
1232 switch (shell->child.process.pid) {
1233 case 0:
1234 /* SOCK_CLOEXEC closes both ends, so we need to unset
1235 * the flag on the client fd. */
1236 flags = fcntl(sv[1], F_GETFD);
1237 if (flags != -1)
1238 fcntl(sv[1], F_SETFD, flags & ~FD_CLOEXEC);
1239
1240 snprintf(s, sizeof s, "%d", sv[1]);
1241 setenv("WAYLAND_SOCKET", s, 1);
1242 if (execl(shell_exe, shell_exe, NULL) < 0)
1243 fprintf(stderr, "%s: running '%s' failed: %m\n",
1244 __func__, shell_exe);
1245 exit(-1);
1246
1247 default:
1248 close(sv[1]);
1249 shell->child.client =
1250 wl_client_create(compositor->wl_display, sv[0]);
1251 wlsc_watch_process(&shell->child.process);
1252 break;
1253
1254 case -1:
1255 fprintf(stderr, "%s: fork failed: %m\n", __func__);
1256 return -1;
1257 }
1258 return 0;
1259}
1260
1261static void
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001262bind_shell(struct wl_client *client, void *data, uint32_t version, uint32_t id)
1263{
1264 struct wl_shell *shell = data;
1265
1266 wl_client_add_object(client, &wl_shell_interface,
1267 &shell_interface, id, shell);
1268}
1269
Kristian Høgsberg75840622011-09-06 13:48:16 -04001270static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001271unbind_desktop_shell(struct wl_resource *resource)
1272{
1273 struct wl_shell *shell = resource->data;
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001274
1275 if (shell->locked)
1276 resume_desktop(shell);
1277
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001278 shell->child.desktop_shell = NULL;
1279 shell->prepare_event_sent = false;
1280 free(resource);
1281}
1282
1283static void
Kristian Høgsberg75840622011-09-06 13:48:16 -04001284bind_desktop_shell(struct wl_client *client,
1285 void *data, uint32_t version, uint32_t id)
1286{
1287 struct wl_shell *shell = data;
Pekka Paalanenbbe60522011-11-03 14:11:33 +02001288 struct wl_resource *resource;
Kristian Høgsberg75840622011-09-06 13:48:16 -04001289
Pekka Paalanenbbe60522011-11-03 14:11:33 +02001290 resource = wl_client_add_object(client, &desktop_shell_interface,
1291 &desktop_shell_implementation,
1292 id, shell);
1293
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001294 if (client == shell->child.client) {
1295 resource->destroy = unbind_desktop_shell;
1296 shell->child.desktop_shell = resource;
Pekka Paalanenbbe60522011-11-03 14:11:33 +02001297 return;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001298 }
Pekka Paalanenbbe60522011-11-03 14:11:33 +02001299
1300 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
1301 "permission to bind desktop_shell denied");
1302 wl_resource_destroy(resource, 0);
Kristian Høgsberg75840622011-09-06 13:48:16 -04001303}
1304
Kristian Høgsberg6c709a32011-05-06 14:52:41 -04001305int
1306shell_init(struct wlsc_compositor *ec);
1307
Kristian Høgsberg1c562182011-05-02 22:09:20 -04001308WL_EXPORT int
1309shell_init(struct wlsc_compositor *ec)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001310{
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001311 struct wl_shell *shell;
1312
1313 shell = malloc(sizeof *shell);
1314 if (shell == NULL)
1315 return -1;
1316
Kristian Høgsbergf0d91162011-10-11 22:44:23 -04001317 memset(shell, 0, sizeof *shell);
Kristian Høgsberg75840622011-09-06 13:48:16 -04001318 shell->compositor = ec;
1319 shell->shell.activate = activate;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001320 shell->shell.lock = lock;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001321 shell->shell.unlock = unlock;
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05001322 shell->shell.map = map;
1323 shell->shell.configure = configure;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04001324 shell->shell.set_selection_focus = wlsc_selection_set_focus;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001325
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001326 wl_list_init(&shell->hidden_surface_list);
1327
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001328 if (wl_display_add_global(ec->wl_display, &wl_shell_interface,
1329 shell, bind_shell) == NULL)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001330 return -1;
1331
Kristian Høgsberg75840622011-09-06 13:48:16 -04001332 if (wl_display_add_global(ec->wl_display,
1333 &desktop_shell_interface,
1334 shell, bind_desktop_shell) == NULL)
1335 return -1;
1336
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02001337 if (launch_desktop_shell_process(shell) != 0)
1338 return -1;
1339
Kristian Høgsberg07937562011-04-12 17:25:42 -04001340 wlsc_compositor_add_binding(ec, 0, BTN_LEFT, MODIFIER_SUPER,
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001341 move_binding, shell);
Kristian Høgsberg07937562011-04-12 17:25:42 -04001342 wlsc_compositor_add_binding(ec, 0, BTN_MIDDLE, MODIFIER_SUPER,
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04001343 resize_binding, shell);
1344
1345 ec->shell = &shell->shell;
Kristian Høgsberg07937562011-04-12 17:25:42 -04001346
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001347 return 0;
1348}