compositor: drop wl_display_add_object()
[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_configure(es, x + move->dx, y + move->dy,
50                                es->width, es->height);
51 }
52
53 static void
54 move_grab_button(struct wl_grab *grab,
55                  uint32_t time, int32_t button, int32_t state)
56 {
57 }
58
59 static void
60 move_grab_end(struct wl_grab *grab, uint32_t time)
61 {
62         struct wlsc_surface *es;
63         struct wl_input_device *device = grab->input_device;
64         int32_t sx, sy;
65
66         es = pick_surface(grab->input_device, &sx, &sy);
67         wl_input_device_set_pointer_focus(device,
68                                           &es->surface, time,
69                                           device->x, device->y, sx, sy);
70         free(grab);
71 }
72
73 static const struct wl_grab_interface move_grab_interface = {
74         move_grab_motion,
75         move_grab_button,
76         move_grab_end
77 };
78
79 static void
80 shell_move(struct wl_client *client, struct wl_resource *resource,
81            struct wl_surface *surface,
82            struct wl_input_device *device, uint32_t time)
83 {
84         struct wlsc_input_device *wd = (struct wlsc_input_device *) device;
85         struct wlsc_surface *es = (struct wlsc_surface *) surface;
86         struct wlsc_move_grab *move;
87
88         /* FIXME: Reject if fullscreen */
89
90         move = malloc(sizeof *move);
91         if (!move) {
92                 wl_client_post_no_memory(client);
93                 return;
94         }
95
96         move->grab.interface = &move_grab_interface;
97         move->dx = es->x - wd->input_device.grab_x;
98         move->dy = es->y - wd->input_device.grab_y;
99         move->surface = es;
100
101         if (wl_input_device_update_grab(&wd->input_device,
102                                         &move->grab, surface, time) < 0)
103                 return;
104
105         wlsc_input_device_set_pointer_image(wd, WLSC_POINTER_DRAGGING);
106         wl_input_device_set_pointer_focus(device, NULL, time, 0, 0, 0, 0);
107 }
108
109 struct wlsc_resize_grab {
110         struct wl_grab grab;
111         uint32_t edges;
112         int32_t dx, dy, width, height;
113         struct wlsc_surface *surface;
114         struct wl_shell *shell;
115         struct wl_resource resource;
116 };
117
118 static void
119 resize_grab_motion(struct wl_grab *grab,
120                    uint32_t time, int32_t x, int32_t y)
121 {
122         struct wlsc_resize_grab *resize = (struct wlsc_resize_grab *) grab;
123         struct wl_input_device *device = grab->input_device;
124         struct wl_surface *surface = &resize->surface->surface;
125         int32_t width, height;
126
127         if (resize->edges & WL_SHELL_RESIZE_LEFT) {
128                 width = device->grab_x - x + resize->width;
129         } else if (resize->edges & WL_SHELL_RESIZE_RIGHT) {
130                 width = x - device->grab_x + resize->width;
131         } else {
132                 width = resize->width;
133         }
134
135         if (resize->edges & WL_SHELL_RESIZE_TOP) {
136                 height = device->grab_y - y + resize->height;
137         } else if (resize->edges & WL_SHELL_RESIZE_BOTTOM) {
138                 height = y - device->grab_y + resize->height;
139         } else {
140                 height = resize->height;
141         }
142
143         wl_resource_post_event(&resize->resource,
144                                WL_SHELL_CONFIGURE, time, resize->edges,
145                                surface, width, height);
146 }
147
148 static void
149 resize_grab_button(struct wl_grab *grab,
150                    uint32_t time, int32_t button, int32_t state)
151 {
152 }
153
154 static void
155 resize_grab_end(struct wl_grab *grab, uint32_t time)
156 {
157         struct wlsc_surface *es;
158         struct wl_input_device *device = grab->input_device;
159         int32_t sx, sy;
160
161         es = pick_surface(grab->input_device, &sx, &sy);
162         wl_input_device_set_pointer_focus(device,
163                                           &es->surface, time,
164                                           device->x, device->y, sx, sy);
165         free(grab);
166 }
167
168 static const struct wl_grab_interface resize_grab_interface = {
169         resize_grab_motion,
170         resize_grab_button,
171         resize_grab_end
172 };
173
174 static void
175 shell_resize(struct wl_client *client, struct wl_resource *resource,
176              struct wl_surface *surface,
177              struct wl_input_device *device, uint32_t time, uint32_t edges)
178 {
179         struct wl_shell *shell = resource->data;
180         struct wlsc_input_device *wd = (struct wlsc_input_device *) device;
181         struct wlsc_resize_grab *resize;
182         enum wlsc_pointer_type pointer = WLSC_POINTER_LEFT_PTR;
183         struct wlsc_surface *es = (struct wlsc_surface *) surface;
184
185         /* FIXME: Reject if fullscreen */
186
187         resize = malloc(sizeof *resize);
188         if (!resize) {
189                 wl_client_post_no_memory(client);
190                 return;
191         }
192
193         resize->grab.interface = &resize_grab_interface;
194         resize->edges = edges;
195         resize->dx = es->x - wd->input_device.grab_x;
196         resize->dy = es->y - wd->input_device.grab_y;
197         resize->width = es->width;
198         resize->height = es->height;
199         resize->surface = es;
200         resize->shell = shell;
201
202         resize->resource.object = resource->object;
203         resize->resource.client = client;
204
205         if (edges == 0 || edges > 15 ||
206             (edges & 3) == 3 || (edges & 12) == 12)
207                 return;
208
209         switch (edges) {
210         case WL_SHELL_RESIZE_TOP:
211                 pointer = WLSC_POINTER_TOP;
212                 break;
213         case WL_SHELL_RESIZE_BOTTOM:
214                 pointer = WLSC_POINTER_BOTTOM;
215                 break;
216         case WL_SHELL_RESIZE_LEFT:
217                 pointer = WLSC_POINTER_LEFT;
218                 break;
219         case WL_SHELL_RESIZE_TOP_LEFT:
220                 pointer = WLSC_POINTER_TOP_LEFT;
221                 break;
222         case WL_SHELL_RESIZE_BOTTOM_LEFT:
223                 pointer = WLSC_POINTER_BOTTOM_LEFT;
224                 break;
225         case WL_SHELL_RESIZE_RIGHT:
226                 pointer = WLSC_POINTER_RIGHT;
227                 break;
228         case WL_SHELL_RESIZE_TOP_RIGHT:
229                 pointer = WLSC_POINTER_TOP_RIGHT;
230                 break;
231         case WL_SHELL_RESIZE_BOTTOM_RIGHT:
232                 pointer = WLSC_POINTER_BOTTOM_RIGHT;
233                 break;
234         }
235
236         if (wl_input_device_update_grab(&wd->input_device,
237                                         &resize->grab, surface, time) < 0)
238                 return;
239
240         wlsc_input_device_set_pointer_image(wd, pointer);
241         wl_input_device_set_pointer_focus(device, NULL, time, 0, 0, 0, 0);
242 }
243
244 static void
245 shell_set_toplevel(struct wl_client *client,
246                    struct wl_resource *resource,
247                    struct wl_surface *surface)
248
249 {
250         struct wlsc_surface *es = (struct wlsc_surface *) surface;
251         struct wlsc_compositor *ec = es->compositor;
252
253         if (es->map_type == WLSC_SURFACE_MAP_FULLSCREEN) {
254                 es->x = es->saved_x;
255                 es->y = es->saved_y;
256         } else if (es->map_type == WLSC_SURFACE_MAP_UNMAPPED) {
257                 es->x = 10 + random() % 400;
258                 es->y = 10 + random() % 400;
259                 /* assign to first output */
260                 es->output = container_of(ec->output_list.next,
261                                           struct wlsc_output, link);
262         }
263
264         wlsc_surface_damage(es);
265         es->map_type = WLSC_SURFACE_MAP_TOPLEVEL;
266         es->fullscreen_output = NULL;
267 }
268
269 static void
270 shell_set_transient(struct wl_client *client,
271                     struct wl_resource *resource,
272                     struct wl_surface *surface,
273                     struct wl_surface *parent,
274                     int x, int y, uint32_t flags)
275 {
276         struct wlsc_surface *es = (struct wlsc_surface *) surface;
277         struct wlsc_surface *pes = (struct wlsc_surface *) parent;
278
279         /* assign to parents output  */
280         es->output = pes->output;
281  
282         es->x = pes->x + x;
283         es->y = pes->y + y;
284
285         wlsc_surface_damage(es);
286         es->map_type = WLSC_SURFACE_MAP_TRANSIENT;
287 }
288
289 static void
290 shell_set_fullscreen(struct wl_client *client,
291                      struct wl_resource *resource,
292                      struct wl_surface *surface)
293
294 {
295         struct wlsc_surface *es = (struct wlsc_surface *) surface;
296         struct wlsc_output *output;
297
298         /* FIXME: Fullscreen on first output */
299         /* FIXME: Handle output going away */
300         output = container_of(es->compositor->output_list.next,
301                               struct wlsc_output, link);
302         es->output = output;
303
304         es->saved_x = es->x;
305         es->saved_y = es->y;
306         es->x = (output->current->width - es->width) / 2;
307         es->y = (output->current->height - es->height) / 2;
308         es->fullscreen_output = output;
309         wlsc_surface_damage(es);
310         es->map_type = WLSC_SURFACE_MAP_FULLSCREEN;
311 }
312
313 static void
314 destroy_drag(struct wl_resource *resource)
315 {
316         struct wl_drag *drag =
317                 container_of(resource, struct wl_drag, resource);
318
319         wl_list_remove(&drag->drag_focus_listener.link);
320         if (drag->grab.input_device)
321                 wl_input_device_end_grab(drag->grab.input_device,
322                                          wlsc_compositor_get_time());
323
324         free(drag);
325 }
326
327
328 static void
329 wl_drag_set_pointer_focus(struct wl_drag *drag,
330                           struct wl_surface *surface, uint32_t time,
331                           int32_t x, int32_t y, int32_t sx, int32_t sy)
332 {
333         char **p, **end;
334
335         if (drag->drag_focus == surface)
336                 return;
337
338         if (drag->drag_focus &&
339             (!surface ||
340              drag->drag_focus->resource.client != surface->resource.client))
341                 wl_resource_post_event(&drag->drag_offer.resource,
342                                       WL_DRAG_OFFER_POINTER_FOCUS,
343                                       time, NULL, 0, 0, 0, 0);
344
345         if (surface &&
346             (!drag->drag_focus ||
347              drag->drag_focus->resource.client != surface->resource.client)) {
348                 wl_client_post_global(surface->resource.client,
349                                       &drag->drag_offer.resource.object);
350                 
351                 drag->drag_offer.resource.client = surface->resource.client;
352                 end = drag->types.data + drag->types.size;
353                 for (p = drag->types.data; p < end; p++)
354                         wl_resource_post_event(&drag->drag_offer.resource,
355                                                WL_DRAG_OFFER_OFFER, *p);
356         }
357
358         if (surface) {
359                 wl_resource_post_event(&drag->drag_offer.resource,
360                                        WL_DRAG_OFFER_POINTER_FOCUS,
361                                        time, surface,
362                                        x, y, sx, sy);
363
364         }
365
366         drag->drag_focus = surface;
367         drag->pointer_focus_time = time;
368         drag->target = NULL;
369
370         wl_list_remove(&drag->drag_focus_listener.link);
371         if (surface)
372                 wl_list_insert(surface->resource.destroy_listener_list.prev,
373                                &drag->drag_focus_listener.link);
374 }
375
376 static void
377 drag_offer_accept(struct wl_client *client, struct wl_resource *resource,
378                   uint32_t time, const char *type)
379 {
380         struct wl_drag_offer *offer = resource->data;
381         struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer);
382         char **p, **end;
383
384         /* If the client responds to drag pointer_focus or motion
385          * events after the pointer has left the surface, we just
386          * discard the accept requests.  The drag source just won't
387          * get the corresponding 'target' events and eventually the
388          * next surface/root will start sending events. */
389         if (time < drag->pointer_focus_time)
390                 return;
391
392         drag->target = client;
393         drag->type = NULL;
394         end = drag->types.data + drag->types.size;
395         for (p = drag->types.data; p < end; p++)
396                 if (type && strcmp(*p, type) == 0)
397                         drag->type = *p;
398
399         wl_resource_post_event(&drag->resource, WL_DRAG_TARGET, drag->type);
400 }
401
402 static void
403 drag_offer_receive(struct wl_client *client,
404                    struct wl_resource *resource, int fd)
405 {
406         struct wl_drag_offer *offer = resource->data;
407         struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer);
408
409         wl_resource_post_event(&drag->resource, WL_DRAG_FINISH, fd);
410         close(fd);
411 }
412
413 static void
414 drag_offer_reject(struct wl_client *client, struct wl_resource *resource)
415 {
416         struct wl_drag_offer *offer = resource->data;
417         struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer);
418
419         wl_resource_post_event(&drag->resource, WL_DRAG_REJECT);
420 }
421
422 static const struct wl_drag_offer_interface drag_offer_interface = {
423         drag_offer_accept,
424         drag_offer_receive,
425         drag_offer_reject
426 };
427
428 static void
429 drag_offer(struct wl_client *client,
430            struct wl_resource *resource, const char *type)
431 {
432         struct wl_drag *drag = resource->data;
433         char **p;
434
435         p = wl_array_add(&drag->types, sizeof *p);
436         if (p)
437                 *p = strdup(type);
438         if (!p || !*p)
439                 wl_client_post_no_memory(client);
440 }
441
442 static void
443 drag_grab_motion(struct wl_grab *grab,
444                    uint32_t time, int32_t x, int32_t y)
445 {
446         struct wl_drag *drag = container_of(grab, struct wl_drag, grab);
447         struct wlsc_surface *es;
448         int32_t sx, sy;
449
450         es = pick_surface(grab->input_device, &sx, &sy);
451         wl_drag_set_pointer_focus(drag, &es->surface, time, x, y, sx, sy);
452         if (es)
453                 wl_resource_post_event(&drag->drag_offer.resource,
454                                        WL_DRAG_OFFER_MOTION,
455                                        time, x, y, sx, sy);
456 }
457
458 static void
459 drag_grab_button(struct wl_grab *grab,
460                  uint32_t time, int32_t button, int32_t state)
461 {
462 }
463
464 static void
465 drag_grab_end(struct wl_grab *grab, uint32_t time)
466 {
467         struct wl_drag *drag = container_of(grab, struct wl_drag, grab);
468         struct wlsc_surface *es;
469         struct wl_input_device *device = grab->input_device;
470         int32_t sx, sy;
471
472         if (drag->target)
473                 wl_resource_post_event(&drag->drag_offer.resource,
474                                        WL_DRAG_OFFER_DROP);
475
476         wl_drag_set_pointer_focus(drag, NULL, time, 0, 0, 0, 0);
477
478         es = pick_surface(grab->input_device, &sx, &sy);
479         wl_input_device_set_pointer_focus(device,
480                                           &es->surface, time,
481                                           device->x, device->y, sx, sy);
482 }
483
484 static const struct wl_grab_interface drag_grab_interface = {
485         drag_grab_motion,
486         drag_grab_button,
487         drag_grab_end
488 };
489
490 static void
491 drag_activate(struct wl_client *client,
492               struct wl_resource *resource,
493               struct wl_surface *surface,
494               struct wl_input_device *device, uint32_t time)
495 {
496         struct wl_drag *drag = resource->data;
497         struct wl_display *display = wl_client_get_display (client);
498         struct wlsc_surface *target;
499         int32_t sx, sy;
500
501         if (wl_input_device_update_grab(device,
502                                         &drag->grab, surface, time) < 0)
503                 return;
504
505         drag->grab.interface = &drag_grab_interface;
506
507         drag->source = surface;
508
509         drag->drag_offer.resource.object.interface = &wl_drag_offer_interface;
510         drag->drag_offer.resource.object.implementation =
511                 (void (**)(void)) &drag_offer_interface;
512
513         wl_display_add_global(display,
514                               &drag->drag_offer.resource.object, NULL);
515
516         target = pick_surface(device, &sx, &sy);
517         wl_input_device_set_pointer_focus(device, NULL, time, 0, 0, 0, 0);
518         wl_drag_set_pointer_focus(drag, &target->surface, time,
519                                   device->x, device->y, sx, sy);
520 }
521
522 static void
523 drag_destroy(struct wl_client *client, struct wl_resource *resource)
524 {
525         wl_resource_destroy(resource, wlsc_compositor_get_time());
526 }
527
528 static const struct wl_drag_interface drag_interface = {
529         drag_offer,
530         drag_activate,
531         drag_destroy,
532 };
533
534 static void
535 drag_handle_surface_destroy(struct wl_listener *listener,
536                             struct wl_resource *resource, uint32_t time)
537 {
538         struct wl_drag *drag =
539                 container_of(listener, struct wl_drag, drag_focus_listener);
540         struct wl_surface *surface = (struct wl_surface *) resource;
541
542         if (drag->drag_focus == surface)
543                 wl_drag_set_pointer_focus(drag, NULL, time, 0, 0, 0, 0);
544 }
545
546 static void
547 shell_create_drag(struct wl_client *client,
548                   struct wl_resource *resource, uint32_t id)
549 {
550         struct wl_drag *drag;
551
552         drag = malloc(sizeof *drag);
553         if (drag == NULL) {
554                 wl_client_post_no_memory(client);
555                 return;
556         }
557
558         memset(drag, 0, sizeof *drag);
559         drag->resource.object.id = id;
560         drag->resource.object.interface = &wl_drag_interface;
561         drag->resource.object.implementation =
562                 (void (**)(void)) &drag_interface;
563
564         drag->resource.destroy = destroy_drag;
565
566         drag->drag_focus_listener.func = drag_handle_surface_destroy;
567         wl_list_init(&drag->drag_focus_listener.link);
568
569         wl_client_add_resource(client, &drag->resource);
570 }
571
572 static void
573 wlsc_selection_set_focus(struct wlsc_shell *shell,
574                          struct wl_selection *selection,
575                          struct wl_surface *surface, uint32_t time)
576 {
577         char **p, **end;
578
579         if (selection->selection_focus == surface)
580                 return;
581
582         if (selection->selection_focus != NULL)
583                 wl_resource_post_event(&selection->selection_offer.resource,
584                                      WL_SELECTION_OFFER_KEYBOARD_FOCUS,
585                                      NULL);
586
587         if (surface) {
588                 wl_client_post_global(surface->resource.client,
589                                       &selection->selection_offer.resource.object);
590
591                 selection->selection_offer.resource.client = surface->resource.client;
592                 end = selection->types.data + selection->types.size;
593                 for (p = selection->types.data; p < end; p++)
594                         wl_resource_post_event(&selection->selection_offer.resource,
595                                                WL_SELECTION_OFFER_OFFER, *p);
596
597                 wl_list_remove(&selection->selection_focus_listener.link);
598                 wl_list_insert(surface->resource.destroy_listener_list.prev,
599                                &selection->selection_focus_listener.link);
600
601                 wl_resource_post_event(&selection->selection_offer.resource,
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_resource *resource,
617                         const char *mime_type, int fd)
618 {
619         struct wl_selection_offer *offer = resource->data;
620         struct wl_selection *selection =
621                 container_of(offer, struct wl_selection, selection_offer);
622
623         wl_resource_post_event(&selection->resource,
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_resource *resource, const char *type)
635 {
636         struct wl_selection *selection = resource->data;
637         char **p;
638
639         p = wl_array_add(&selection->types, sizeof *p);
640         if (p)
641                 *p = strdup(type);
642         if (!p || !*p)
643                 wl_client_post_no_memory(client);
644 }
645
646 static void
647 selection_activate(struct wl_client *client,
648                    struct wl_resource *resource,
649                    struct wl_input_device *device, uint32_t time)
650 {
651         struct wl_selection *selection = resource->data;
652         struct wlsc_input_device *wd = (struct wlsc_input_device *) device;
653         struct wl_display *display = wl_client_get_display (client);
654         struct wlsc_compositor *compositor =
655                 (struct wlsc_compositor *) device->compositor;
656
657         selection->input_device = device;
658
659         selection->selection_offer.resource.object.interface =
660                 &wl_selection_offer_interface;
661         selection->selection_offer.resource.object.implementation =
662                 (void (**)(void)) &selection_offer_interface;
663
664         wl_display_add_global(display,
665                               &selection->selection_offer.resource.object,
666                               NULL);
667
668         if (wd->selection) {
669                 wl_resource_post_event(&wd->selection->resource,
670                                        WL_SELECTION_CANCELLED);
671         }
672         wd->selection = selection;
673
674         wlsc_selection_set_focus(compositor->shell,
675                                  selection, device->keyboard_focus, time);
676 }
677
678 static void
679 selection_destroy(struct wl_client *client, struct wl_resource *resource)
680 {
681         wl_resource_destroy(resource, wlsc_compositor_get_time());
682 }
683
684 static const struct wl_selection_interface selection_interface = {
685         selection_offer,
686         selection_activate,
687         selection_destroy
688 };
689
690 static void
691 destroy_selection(struct wl_resource *resource)
692 {
693         struct wl_selection *selection =
694                 container_of(resource, struct wl_selection, resource);
695         struct wlsc_input_device *wd =
696                 (struct wlsc_input_device *) selection->input_device;
697         struct wlsc_compositor *compositor =
698                 (struct wlsc_compositor *) wd->input_device.compositor;
699
700         if (wd && wd->selection == selection) {
701                 wd->selection = NULL;
702                 wlsc_selection_set_focus(compositor->shell, 
703                                          selection, NULL,
704                                          wlsc_compositor_get_time());
705         }
706
707         wl_list_remove(&selection->selection_focus_listener.link);
708         free(selection);
709 }
710
711 static void
712 selection_handle_surface_destroy(struct wl_listener *listener,
713                                  struct wl_resource *resource, uint32_t time)
714 {
715 }
716
717 static void
718 shell_create_selection(struct wl_client *client,
719                        struct wl_resource *resource, uint32_t id)
720 {
721         struct wl_selection *selection;
722
723         selection = malloc(sizeof *selection);
724         if (selection == NULL) {
725                 wl_client_post_no_memory(client);
726                 return;
727         }
728
729         memset(selection, 0, sizeof *selection);
730         selection->resource.object.id = id;
731         selection->resource.object.interface = &wl_selection_interface;
732         selection->resource.object.implementation =
733                 (void (**)(void)) &selection_interface;
734
735         selection->client = client;
736         selection->resource.destroy = destroy_selection;
737         selection->selection_focus = NULL;
738
739         selection->selection_focus_listener.func =
740                 selection_handle_surface_destroy;
741         wl_list_init(&selection->selection_focus_listener.link);
742
743         wl_client_add_resource(client, &selection->resource);
744 }
745
746 const static struct wl_shell_interface shell_interface = {
747         shell_move,
748         shell_resize,
749         shell_create_drag,
750         shell_create_selection,
751         shell_set_toplevel,
752         shell_set_transient,
753         shell_set_fullscreen
754 };
755
756 static void
757 move_binding(struct wl_input_device *device, uint32_t time,
758              uint32_t key, uint32_t button, uint32_t state, void *data)
759 {
760         struct wlsc_surface *surface =
761                 (struct wlsc_surface *) device->pointer_focus;
762
763         if (surface == NULL)
764                 return;
765
766         shell_move(NULL, NULL, &surface->surface, device, time);
767 }
768
769 static void
770 resize_binding(struct wl_input_device *device, uint32_t time,
771                uint32_t key, uint32_t button, uint32_t state, void *data)
772 {
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, NULL, &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         if (wl_display_add_global(ec->wl_display, &shell->object, NULL))
834                 return -1;
835
836         wlsc_compositor_add_binding(ec, 0, BTN_LEFT, MODIFIER_SUPER,
837                                     move_binding, shell);
838         wlsc_compositor_add_binding(ec, 0, BTN_MIDDLE, MODIFIER_SUPER,
839                                     resize_binding, shell);
840
841         ec->shell = &shell->shell;
842
843         return 0;
844 }