compositor: Add helper to damage surface below
[profile/ivi/weston.git] / compositor / shell.c
1 /*
2  * Copyright © 2010 Intel Corporation
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and
5  * its documentation for any purpose is hereby granted without fee, provided
6  * that the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation, and that the name of the copyright holders not be used in
9  * advertising or publicity pertaining to distribution of the software
10  * without specific, written prior permission.  The copyright holders make
11  * no representations about the suitability of this software for any
12  * purpose.  It is provided "as is" without express or implied warranty.
13  *
14  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
15  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
16  * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
17  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
18  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
19  * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21  */
22
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <linux/input.h>
27
28 #include "wayland-server.h"
29 #include "compositor.h"
30
31 struct wl_shell {
32         struct wl_object object;
33         struct wlsc_shell shell;
34 };
35
36 struct wlsc_move_grab {
37         struct wl_grab grab;
38         struct wlsc_surface *surface;
39         int32_t dx, dy;
40 };
41
42 static void
43 move_grab_motion(struct wl_grab *grab,
44                    uint32_t time, int32_t x, int32_t y)
45 {
46         struct wlsc_move_grab *move = (struct wlsc_move_grab *) grab;
47         struct wlsc_surface *es = move->surface;
48
49         wlsc_surface_damage_below(es);
50         es->x = x + move->dx;
51         es->y = y + move->dy;
52         wlsc_surface_assign_output(es);
53         wlsc_surface_damage(es);
54 }
55
56 static void
57 move_grab_button(struct wl_grab *grab,
58                  uint32_t time, int32_t button, int32_t state)
59 {
60 }
61
62 static void
63 move_grab_end(struct wl_grab *grab, uint32_t time)
64 {
65         struct wlsc_surface *es;
66         struct wl_input_device *device = grab->input_device;
67         int32_t sx, sy;
68
69         es = pick_surface(grab->input_device, &sx, &sy);
70         wl_input_device_set_pointer_focus(device,
71                                           &es->surface, time,
72                                           device->x, device->y, sx, sy);
73         free(grab);
74 }
75
76 static const struct wl_grab_interface move_grab_interface = {
77         move_grab_motion,
78         move_grab_button,
79         move_grab_end
80 };
81
82 static void
83 shell_move(struct wl_client *client, struct wl_shell *shell,
84            struct wl_surface *surface,
85            struct wl_input_device *device, uint32_t time)
86 {
87         struct wlsc_input_device *wd = (struct wlsc_input_device *) device;
88         struct wlsc_surface *es = (struct wlsc_surface *) surface;
89         struct wlsc_move_grab *move;
90
91         /* FIXME: Reject if fullscreen */
92
93         move = malloc(sizeof *move);
94         if (!move) {
95                 wl_client_post_no_memory(client);
96                 return;
97         }
98
99         move->grab.interface = &move_grab_interface;
100         move->dx = es->x - wd->input_device.grab_x;
101         move->dy = es->y - wd->input_device.grab_y;
102         move->surface = es;
103
104         if (wl_input_device_update_grab(&wd->input_device,
105                                         &move->grab, surface, time) < 0)
106                 return;
107
108         wlsc_input_device_set_pointer_image(wd, WLSC_POINTER_DRAGGING);
109         wl_input_device_set_pointer_focus(device, NULL, time, 0, 0, 0, 0);
110 }
111
112 struct wlsc_resize_grab {
113         struct wl_grab grab;
114         uint32_t edges;
115         int32_t dx, dy, width, height;
116         struct wlsc_surface *surface;
117         struct wl_shell *shell;
118 };
119
120 static void
121 resize_grab_motion(struct wl_grab *grab,
122                    uint32_t time, int32_t x, int32_t y)
123 {
124         struct wlsc_resize_grab *resize = (struct wlsc_resize_grab *) grab;
125         struct wl_input_device *device = grab->input_device;
126         struct wl_surface *surface = &resize->surface->surface;
127         int32_t width, height;
128
129         if (resize->edges & WL_SHELL_RESIZE_LEFT) {
130                 width = device->grab_x - x + resize->width;
131         } else if (resize->edges & WL_SHELL_RESIZE_RIGHT) {
132                 width = x - device->grab_x + resize->width;
133         } else {
134                 width = resize->width;
135         }
136
137         if (resize->edges & WL_SHELL_RESIZE_TOP) {
138                 height = device->grab_y - y + resize->height;
139         } else if (resize->edges & WL_SHELL_RESIZE_BOTTOM) {
140                 height = y - device->grab_y + resize->height;
141         } else {
142                 height = resize->height;
143         }
144
145         wl_client_post_event(surface->client, &resize->shell->object,
146                              WL_SHELL_CONFIGURE, time, resize->edges,
147                              surface, width, height);
148 }
149
150 static void
151 resize_grab_button(struct wl_grab *grab,
152                    uint32_t time, int32_t button, int32_t state)
153 {
154 }
155
156 static void
157 resize_grab_end(struct wl_grab *grab, uint32_t time)
158 {
159         struct wlsc_surface *es;
160         struct wl_input_device *device = grab->input_device;
161         int32_t sx, sy;
162
163         es = pick_surface(grab->input_device, &sx, &sy);
164         wl_input_device_set_pointer_focus(device,
165                                           &es->surface, time,
166                                           device->x, device->y, sx, sy);
167         free(grab);
168 }
169
170 static const struct wl_grab_interface resize_grab_interface = {
171         resize_grab_motion,
172         resize_grab_button,
173         resize_grab_end
174 };
175
176 static void
177 shell_resize(struct wl_client *client, struct wl_shell *shell,
178              struct wl_surface *surface,
179              struct wl_input_device *device, uint32_t time, uint32_t edges)
180 {
181         struct wlsc_input_device *wd = (struct wlsc_input_device *) device;
182         struct wlsc_resize_grab *resize;
183         enum wlsc_pointer_type pointer = WLSC_POINTER_LEFT_PTR;
184         struct wlsc_surface *es = (struct wlsc_surface *) surface;
185
186         /* FIXME: Reject if fullscreen */
187
188         resize = malloc(sizeof *resize);
189         if (!resize) {
190                 wl_client_post_no_memory(client);
191                 return;
192         }
193
194         resize->grab.interface = &resize_grab_interface;
195         resize->edges = edges;
196         resize->dx = es->x - wd->input_device.grab_x;
197         resize->dy = es->y - wd->input_device.grab_y;
198         resize->width = es->width;
199         resize->height = es->height;
200         resize->surface = es;
201         resize->shell = shell;
202
203         if (edges == 0 || edges > 15 ||
204             (edges & 3) == 3 || (edges & 12) == 12)
205                 return;
206
207         switch (edges) {
208         case WL_SHELL_RESIZE_TOP:
209                 pointer = WLSC_POINTER_TOP;
210                 break;
211         case WL_SHELL_RESIZE_BOTTOM:
212                 pointer = WLSC_POINTER_BOTTOM;
213                 break;
214         case WL_SHELL_RESIZE_LEFT:
215                 pointer = WLSC_POINTER_LEFT;
216                 break;
217         case WL_SHELL_RESIZE_TOP_LEFT:
218                 pointer = WLSC_POINTER_TOP_LEFT;
219                 break;
220         case WL_SHELL_RESIZE_BOTTOM_LEFT:
221                 pointer = WLSC_POINTER_BOTTOM_LEFT;
222                 break;
223         case WL_SHELL_RESIZE_RIGHT:
224                 pointer = WLSC_POINTER_RIGHT;
225                 break;
226         case WL_SHELL_RESIZE_TOP_RIGHT:
227                 pointer = WLSC_POINTER_TOP_RIGHT;
228                 break;
229         case WL_SHELL_RESIZE_BOTTOM_RIGHT:
230                 pointer = WLSC_POINTER_BOTTOM_RIGHT;
231                 break;
232         }
233
234         if (wl_input_device_update_grab(&wd->input_device,
235                                         &resize->grab, surface, time) < 0)
236                 return;
237
238         wlsc_input_device_set_pointer_image(wd, pointer);
239         wl_input_device_set_pointer_focus(device, NULL, time, 0, 0, 0, 0);
240 }
241
242 static void
243 shell_set_toplevel(struct wl_client *client,
244                    struct wl_shell *wl_shell,
245                    struct wl_surface *surface)
246
247 {
248         struct wlsc_surface *es = (struct wlsc_surface *) surface;
249         struct wlsc_compositor *ec = es->compositor;
250
251         if (es->map_type == WLSC_SURFACE_MAP_FULLSCREEN) {
252                 es->x = es->saved_x;
253                 es->y = es->saved_y;
254         } else if (es->map_type == WLSC_SURFACE_MAP_UNMAPPED) {
255                 es->x = 10 + random() % 400;
256                 es->y = 10 + random() % 400;
257                 /* assign to first output */
258                 es->output = container_of(ec->output_list.next,
259                                           struct wlsc_output, link);
260         }
261
262         wlsc_surface_damage(es);
263         es->map_type = WLSC_SURFACE_MAP_TOPLEVEL;
264         es->fullscreen_output = NULL;
265 }
266
267 static void
268 shell_set_transient(struct wl_client *client,
269                     struct wl_shell *wl_shell,
270                     struct wl_surface *surface,
271                     struct wl_surface *parent,
272                     int x, int y, uint32_t flags)
273 {
274         struct wlsc_surface *es = (struct wlsc_surface *) surface;
275         struct wlsc_surface *pes = (struct wlsc_surface *) parent;
276
277         /* assign to parents output  */
278         es->output = pes->output;
279  
280         es->x = pes->x + x;
281         es->y = pes->y + y;
282
283         wlsc_surface_damage(es);
284         es->map_type = WLSC_SURFACE_MAP_TRANSIENT;
285 }
286
287 static void
288 shell_set_fullscreen(struct wl_client *client,
289                      struct wl_shell *wl_shell,
290                      struct wl_surface *surface)
291
292 {
293         struct wlsc_surface *es = (struct wlsc_surface *) surface;
294         struct wlsc_output *output;
295
296         /* FIXME: Fullscreen on first output */
297         /* FIXME: Handle output going away */
298         output = container_of(es->compositor->output_list.next,
299                               struct wlsc_output, link);
300         es->output = output;
301
302         es->saved_x = es->x;
303         es->saved_y = es->y;
304         es->x = (output->current->width - es->width) / 2;
305         es->y = (output->current->height - es->height) / 2;
306         es->fullscreen_output = output;
307         wlsc_surface_damage(es);
308         es->map_type = WLSC_SURFACE_MAP_FULLSCREEN;
309 }
310
311 static void
312 destroy_drag(struct wl_resource *resource, struct wl_client *client)
313 {
314         struct wl_drag *drag =
315                 container_of(resource, struct wl_drag, resource);
316
317         wl_list_remove(&drag->drag_focus_listener.link);
318         if (drag->grab.input_device)
319                 wl_input_device_end_grab(drag->grab.input_device,
320                                          wlsc_compositor_get_time());
321
322         free(drag);
323 }
324
325
326 static void
327 wl_drag_set_pointer_focus(struct wl_drag *drag,
328                           struct wl_surface *surface, uint32_t time,
329                           int32_t x, int32_t y, int32_t sx, int32_t sy)
330 {
331         char **p, **end;
332
333         if (drag->drag_focus == surface)
334                 return;
335
336         if (drag->drag_focus &&
337             (!surface || drag->drag_focus->client != surface->client))
338                 wl_client_post_event(drag->drag_focus->client,
339                                       &drag->drag_offer.object,
340                                       WL_DRAG_OFFER_POINTER_FOCUS,
341                                       time, NULL, 0, 0, 0, 0);
342
343         if (surface &&
344             (!drag->drag_focus ||
345              drag->drag_focus->client != surface->client)) {
346                 wl_client_post_global(surface->client,
347                                       &drag->drag_offer.object);
348
349                 end = drag->types.data + drag->types.size;
350                 for (p = drag->types.data; p < end; p++)
351                         wl_client_post_event(surface->client,
352                                               &drag->drag_offer.object,
353                                               WL_DRAG_OFFER_OFFER, *p);
354         }
355
356         if (surface) {
357                 wl_client_post_event(surface->client,
358                                      &drag->drag_offer.object,
359                                      WL_DRAG_OFFER_POINTER_FOCUS,
360                                      time, surface,
361                                      x, y, sx, sy);
362
363         }
364
365         drag->drag_focus = surface;
366         drag->pointer_focus_time = time;
367         drag->target = NULL;
368
369         wl_list_remove(&drag->drag_focus_listener.link);
370         if (surface)
371                 wl_list_insert(surface->resource.destroy_listener_list.prev,
372                                &drag->drag_focus_listener.link);
373 }
374
375 static void
376 drag_offer_accept(struct wl_client *client,
377                   struct wl_drag_offer *offer, uint32_t time, const char *type)
378 {
379         struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer);
380         char **p, **end;
381
382         /* If the client responds to drag pointer_focus or motion
383          * events after the pointer has left the surface, we just
384          * discard the accept requests.  The drag source just won't
385          * get the corresponding 'target' events and eventually the
386          * next surface/root will start sending events. */
387         if (time < drag->pointer_focus_time)
388                 return;
389
390         drag->target = client;
391         drag->type = NULL;
392         end = drag->types.data + drag->types.size;
393         for (p = drag->types.data; p < end; p++)
394                 if (type && strcmp(*p, type) == 0)
395                         drag->type = *p;
396
397         wl_client_post_event(drag->source->client, &drag->resource.object,
398                              WL_DRAG_TARGET, drag->type);
399 }
400
401 static void
402 drag_offer_receive(struct wl_client *client,
403                    struct wl_drag_offer *offer, int fd)
404 {
405         struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer);
406
407         wl_client_post_event(drag->source->client, &drag->resource.object,
408                              WL_DRAG_FINISH, fd);
409         close(fd);
410 }
411
412 static void
413 drag_offer_reject(struct wl_client *client, struct wl_drag_offer *offer)
414 {
415         struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer);
416
417         wl_client_post_event(drag->source->client, &drag->resource.object,
418                              WL_DRAG_REJECT);
419 }
420
421 static const struct wl_drag_offer_interface drag_offer_interface = {
422         drag_offer_accept,
423         drag_offer_receive,
424         drag_offer_reject
425 };
426
427 static void
428 drag_offer(struct wl_client *client, struct wl_drag *drag, const char *type)
429 {
430         char **p;
431
432         p = wl_array_add(&drag->types, sizeof *p);
433         if (p)
434                 *p = strdup(type);
435         if (!p || !*p)
436                 wl_client_post_no_memory(client);
437 }
438
439 static void
440 drag_grab_motion(struct wl_grab *grab,
441                    uint32_t time, int32_t x, int32_t y)
442 {
443         struct wl_drag *drag = container_of(grab, struct wl_drag, grab);
444         struct wlsc_surface *es;
445         int32_t sx, sy;
446
447         es = pick_surface(grab->input_device, &sx, &sy);
448         wl_drag_set_pointer_focus(drag, &es->surface, time, x, y, sx, sy);
449         if (es)
450                 wl_client_post_event(es->surface.client,
451                                      &drag->drag_offer.object,
452                                      WL_DRAG_OFFER_MOTION,
453                                      time, x, y, sx, sy);
454 }
455
456 static void
457 drag_grab_button(struct wl_grab *grab,
458                  uint32_t time, int32_t button, int32_t state)
459 {
460 }
461
462 static void
463 drag_grab_end(struct wl_grab *grab, uint32_t time)
464 {
465         struct wl_drag *drag = container_of(grab, struct wl_drag, grab);
466         struct wlsc_surface *es;
467         struct wl_input_device *device = grab->input_device;
468         int32_t sx, sy;
469
470         if (drag->target)
471                 wl_client_post_event(drag->target,
472                                      &drag->drag_offer.object,
473                                      WL_DRAG_OFFER_DROP);
474
475         wl_drag_set_pointer_focus(drag, NULL, time, 0, 0, 0, 0);
476
477         es = pick_surface(grab->input_device, &sx, &sy);
478         wl_input_device_set_pointer_focus(device,
479                                           &es->surface, time,
480                                           device->x, device->y, sx, sy);
481 }
482
483 static const struct wl_grab_interface drag_grab_interface = {
484         drag_grab_motion,
485         drag_grab_button,
486         drag_grab_end
487 };
488
489 static void
490 drag_activate(struct wl_client *client,
491               struct wl_drag *drag,
492               struct wl_surface *surface,
493               struct wl_input_device *device, uint32_t time)
494 {
495         struct wl_display *display = wl_client_get_display (client);
496         struct wlsc_surface *target;
497         int32_t sx, sy;
498
499         if (wl_input_device_update_grab(device,
500                                         &drag->grab, surface, time) < 0)
501                 return;
502
503         drag->grab.interface = &drag_grab_interface;
504
505         drag->source = surface;
506
507         drag->drag_offer.object.interface = &wl_drag_offer_interface;
508         drag->drag_offer.object.implementation =
509                 (void (**)(void)) &drag_offer_interface;
510
511         wl_display_add_object(display, &drag->drag_offer.object);
512
513         target = pick_surface(device, &sx, &sy);
514         wl_input_device_set_pointer_focus(device, NULL, time, 0, 0, 0, 0);
515         wl_drag_set_pointer_focus(drag, &target->surface, time,
516                                   device->x, device->y, sx, sy);
517 }
518
519 static void
520 drag_destroy(struct wl_client *client, struct wl_drag *drag)
521 {
522         wl_resource_destroy(&drag->resource, client,
523                             wlsc_compositor_get_time());
524 }
525
526 static const struct wl_drag_interface drag_interface = {
527         drag_offer,
528         drag_activate,
529         drag_destroy,
530 };
531
532 static void
533 drag_handle_surface_destroy(struct wl_listener *listener,
534                             struct wl_resource *resource, uint32_t time)
535 {
536         struct wl_drag *drag =
537                 container_of(listener, struct wl_drag, drag_focus_listener);
538         struct wl_surface *surface = (struct wl_surface *) resource;
539
540         if (drag->drag_focus == surface)
541                 wl_drag_set_pointer_focus(drag, NULL, time, 0, 0, 0, 0);
542 }
543
544 static void
545 shell_create_drag(struct wl_client *client,
546                   struct wl_shell *shell, uint32_t id)
547 {
548         struct wl_drag *drag;
549
550         drag = malloc(sizeof *drag);
551         if (drag == NULL) {
552                 wl_client_post_no_memory(client);
553                 return;
554         }
555
556         memset(drag, 0, sizeof *drag);
557         drag->resource.object.id = id;
558         drag->resource.object.interface = &wl_drag_interface;
559         drag->resource.object.implementation =
560                 (void (**)(void)) &drag_interface;
561
562         drag->resource.destroy = destroy_drag;
563
564         drag->drag_focus_listener.func = drag_handle_surface_destroy;
565         wl_list_init(&drag->drag_focus_listener.link);
566
567         wl_client_add_resource(client, &drag->resource);
568 }
569
570 static void
571 wlsc_selection_set_focus(struct wlsc_shell *shell,
572                          struct wl_selection *selection,
573                          struct wl_surface *surface, uint32_t time)
574 {
575         char **p, **end;
576
577         if (selection->selection_focus == surface)
578                 return;
579
580         if (selection->selection_focus != NULL)
581                 wl_client_post_event(selection->selection_focus->client,
582                                      &selection->selection_offer.object,
583                                      WL_SELECTION_OFFER_KEYBOARD_FOCUS,
584                                      NULL);
585
586         if (surface) {
587                 wl_client_post_global(surface->client,
588                                       &selection->selection_offer.object);
589
590                 end = selection->types.data + selection->types.size;
591                 for (p = selection->types.data; p < end; p++)
592                         wl_client_post_event(surface->client,
593                                              &selection->selection_offer.object,
594                                              WL_SELECTION_OFFER_OFFER, *p);
595
596                 wl_list_remove(&selection->selection_focus_listener.link);
597                 wl_list_insert(surface->resource.destroy_listener_list.prev,
598                                &selection->selection_focus_listener.link);
599
600                 wl_client_post_event(surface->client,
601                                      &selection->selection_offer.object,
602                                      WL_SELECTION_OFFER_KEYBOARD_FOCUS,
603                                      selection->input_device);
604         }
605
606         selection->selection_focus = surface;
607
608         wl_list_remove(&selection->selection_focus_listener.link);
609         if (surface)
610                 wl_list_insert(surface->resource.destroy_listener_list.prev,
611                                &selection->selection_focus_listener.link);
612 }
613
614 static void
615 selection_offer_receive(struct wl_client *client,
616                         struct wl_selection_offer *offer,
617                         const char *mime_type, int fd)
618 {
619         struct wl_selection *selection =
620                 container_of(offer, struct wl_selection, selection_offer);
621
622         wl_client_post_event(selection->client,
623                              &selection->resource.object,
624                              WL_SELECTION_SEND, mime_type, fd);
625         close(fd);
626 }
627
628 static const struct wl_selection_offer_interface selection_offer_interface = {
629         selection_offer_receive
630 };
631
632 static void
633 selection_offer(struct wl_client *client,
634                 struct wl_selection *selection, const char *type)
635 {
636         char **p;
637
638         p = wl_array_add(&selection->types, sizeof *p);
639         if (p)
640                 *p = strdup(type);
641         if (!p || !*p)
642                 wl_client_post_no_memory(client);
643 }
644
645 static void
646 selection_activate(struct wl_client *client,
647                    struct wl_selection *selection,
648                    struct wl_input_device *device, uint32_t time)
649 {
650         struct wlsc_input_device *wd = (struct wlsc_input_device *) device;
651         struct wl_display *display = wl_client_get_display (client);
652         struct wlsc_compositor *compositor =
653                 (struct wlsc_compositor *) device->compositor;
654
655         selection->input_device = device;
656
657         selection->selection_offer.object.interface =
658                 &wl_selection_offer_interface;
659         selection->selection_offer.object.implementation =
660                 (void (**)(void)) &selection_offer_interface;
661
662         wl_display_add_object(display, &selection->selection_offer.object);
663
664         if (wd->selection) {
665                 wl_client_post_event(wd->selection->client,
666                                      &wd->selection->resource.object,
667                                      WL_SELECTION_CANCELLED);
668         }
669         wd->selection = selection;
670
671         wlsc_selection_set_focus(compositor->shell,
672                                  selection, device->keyboard_focus, time);
673 }
674
675 static void
676 selection_destroy(struct wl_client *client, struct wl_selection *selection)
677 {
678         wl_resource_destroy(&selection->resource, client,
679                             wlsc_compositor_get_time());
680 }
681
682 static const struct wl_selection_interface selection_interface = {
683         selection_offer,
684         selection_activate,
685         selection_destroy
686 };
687
688 static void
689 destroy_selection(struct wl_resource *resource, struct wl_client *client)
690 {
691         struct wl_selection *selection =
692                 container_of(resource, struct wl_selection, resource);
693         struct wlsc_input_device *wd =
694                 (struct wlsc_input_device *) selection->input_device;
695         struct wlsc_compositor *compositor =
696                 (struct wlsc_compositor *) wd->input_device.compositor;
697
698         if (wd && wd->selection == selection) {
699                 wd->selection = NULL;
700                 wlsc_selection_set_focus(compositor->shell, 
701                                          selection, NULL,
702                                          wlsc_compositor_get_time());
703         }
704
705         wl_list_remove(&selection->selection_focus_listener.link);
706         free(selection);
707 }
708
709 static void
710 selection_handle_surface_destroy(struct wl_listener *listener,
711                                  struct wl_resource *resource, uint32_t time)
712 {
713 }
714
715 static void
716 shell_create_selection(struct wl_client *client,
717                        struct wl_shell *shell, uint32_t id)
718 {
719         struct wl_selection *selection;
720
721         selection = malloc(sizeof *selection);
722         if (selection == NULL) {
723                 wl_client_post_no_memory(client);
724                 return;
725         }
726
727         memset(selection, 0, sizeof *selection);
728         selection->resource.object.id = id;
729         selection->resource.object.interface = &wl_selection_interface;
730         selection->resource.object.implementation =
731                 (void (**)(void)) &selection_interface;
732
733         selection->client = client;
734         selection->resource.destroy = destroy_selection;
735         selection->selection_focus = NULL;
736
737         selection->selection_focus_listener.func =
738                 selection_handle_surface_destroy;
739         wl_list_init(&selection->selection_focus_listener.link);
740
741         wl_client_add_resource(client, &selection->resource);
742 }
743
744 const static struct wl_shell_interface shell_interface = {
745         shell_move,
746         shell_resize,
747         shell_create_drag,
748         shell_create_selection,
749         shell_set_toplevel,
750         shell_set_transient,
751         shell_set_fullscreen
752 };
753
754 static void
755 move_binding(struct wl_input_device *device, uint32_t time,
756              uint32_t key, uint32_t button, uint32_t state, void *data)
757 {
758         struct wl_shell *shell = data;
759         struct wlsc_surface *surface =
760                 (struct wlsc_surface *) device->pointer_focus;
761
762         if (surface == NULL)
763                 return;
764
765         shell_move(NULL, shell, &surface->surface, device, time);
766 }
767
768 static void
769 resize_binding(struct wl_input_device *device, uint32_t time,
770                uint32_t key, uint32_t button, uint32_t state, void *data)
771 {
772         struct wl_shell *shell = data;
773         struct wlsc_surface *surface =
774                 (struct wlsc_surface *) device->pointer_focus;
775         uint32_t edges = 0;
776         int32_t x, y;
777
778         if (surface == NULL)
779                 return;
780
781         x = device->grab_x - surface->x;
782         y = device->grab_y - surface->y;
783
784         if (x < surface->width / 3)
785                 edges |= WL_SHELL_RESIZE_LEFT;
786         else if (x < 2 * surface->width / 3)
787                 edges |= 0;
788         else
789                 edges |= WL_SHELL_RESIZE_RIGHT;
790
791         if (y < surface->height / 3)
792                 edges |= WL_SHELL_RESIZE_TOP;
793         else if (y < 2 * surface->height / 3)
794                 edges |= 0;
795         else
796                 edges |= WL_SHELL_RESIZE_BOTTOM;
797
798         shell_resize(NULL, shell, &surface->surface, device, time, edges);
799 }
800
801 static void
802 lock(struct wlsc_shell *shell)
803 {
804 }
805
806 static void
807 attach(struct wlsc_shell *shell, struct wlsc_surface *es)
808 {
809         if (es->map_type == WLSC_SURFACE_MAP_FULLSCREEN) {
810                 es->x = (es->fullscreen_output->current->width - es->width) / 2;
811                 es->y = (es->fullscreen_output->current->height - es->height) / 2;
812         }
813 }
814
815 int
816 shell_init(struct wlsc_compositor *ec);
817
818 WL_EXPORT int
819 shell_init(struct wlsc_compositor *ec)
820 {
821         struct wl_shell *shell;
822
823         shell = malloc(sizeof *shell);
824         if (shell == NULL)
825                 return -1;
826
827         shell->shell.lock = lock;
828         shell->shell.attach = attach;
829         shell->shell.set_selection_focus = wlsc_selection_set_focus;
830
831         shell->object.interface = &wl_shell_interface;
832         shell->object.implementation = (void (**)(void)) &shell_interface;
833         wl_display_add_object(ec->wl_display, &shell->object);
834         if (wl_display_add_global(ec->wl_display, &shell->object, NULL))
835                 return -1;
836
837         wlsc_compositor_add_binding(ec, 0, BTN_LEFT, MODIFIER_SUPER,
838                                     move_binding, shell);
839         wlsc_compositor_add_binding(ec, 0, BTN_MIDDLE, MODIFIER_SUPER,
840                                     resize_binding, shell);
841
842         ec->shell = &shell->shell;
843
844         return 0;
845 }