251d17a7dda691ac552a6ab68347df2223d3f5d6
[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_object(display, &drag->drag_offer.resource.object);
514
515         target = pick_surface(device, &sx, &sy);
516         wl_input_device_set_pointer_focus(device, NULL, time, 0, 0, 0, 0);
517         wl_drag_set_pointer_focus(drag, &target->surface, time,
518                                   device->x, device->y, sx, sy);
519 }
520
521 static void
522 drag_destroy(struct wl_client *client, struct wl_resource *resource)
523 {
524         wl_resource_destroy(resource, wlsc_compositor_get_time());
525 }
526
527 static const struct wl_drag_interface drag_interface = {
528         drag_offer,
529         drag_activate,
530         drag_destroy,
531 };
532
533 static void
534 drag_handle_surface_destroy(struct wl_listener *listener,
535                             struct wl_resource *resource, uint32_t time)
536 {
537         struct wl_drag *drag =
538                 container_of(listener, struct wl_drag, drag_focus_listener);
539         struct wl_surface *surface = (struct wl_surface *) resource;
540
541         if (drag->drag_focus == surface)
542                 wl_drag_set_pointer_focus(drag, NULL, time, 0, 0, 0, 0);
543 }
544
545 static void
546 shell_create_drag(struct wl_client *client,
547                   struct wl_resource *resource, uint32_t id)
548 {
549         struct wl_drag *drag;
550
551         drag = malloc(sizeof *drag);
552         if (drag == NULL) {
553                 wl_client_post_no_memory(client);
554                 return;
555         }
556
557         memset(drag, 0, sizeof *drag);
558         drag->resource.object.id = id;
559         drag->resource.object.interface = &wl_drag_interface;
560         drag->resource.object.implementation =
561                 (void (**)(void)) &drag_interface;
562
563         drag->resource.destroy = destroy_drag;
564
565         drag->drag_focus_listener.func = drag_handle_surface_destroy;
566         wl_list_init(&drag->drag_focus_listener.link);
567
568         wl_client_add_resource(client, &drag->resource);
569 }
570
571 static void
572 wlsc_selection_set_focus(struct wlsc_shell *shell,
573                          struct wl_selection *selection,
574                          struct wl_surface *surface, uint32_t time)
575 {
576         char **p, **end;
577
578         if (selection->selection_focus == surface)
579                 return;
580
581         if (selection->selection_focus != NULL)
582                 wl_resource_post_event(&selection->selection_offer.resource,
583                                      WL_SELECTION_OFFER_KEYBOARD_FOCUS,
584                                      NULL);
585
586         if (surface) {
587                 wl_client_post_global(surface->resource.client,
588                                       &selection->selection_offer.resource.object);
589
590                 selection->selection_offer.resource.client = surface->resource.client;
591                 end = selection->types.data + selection->types.size;
592                 for (p = selection->types.data; p < end; p++)
593                         wl_resource_post_event(&selection->selection_offer.resource,
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_resource_post_event(&selection->selection_offer.resource,
601                                        WL_SELECTION_OFFER_KEYBOARD_FOCUS,
602                                        selection->input_device);
603         }
604
605         selection->selection_focus = surface;
606
607         wl_list_remove(&selection->selection_focus_listener.link);
608         if (surface)
609                 wl_list_insert(surface->resource.destroy_listener_list.prev,
610                                &selection->selection_focus_listener.link);
611 }
612
613 static void
614 selection_offer_receive(struct wl_client *client,
615                         struct wl_resource *resource,
616                         const char *mime_type, int fd)
617 {
618         struct wl_selection_offer *offer = resource->data;
619         struct wl_selection *selection =
620                 container_of(offer, struct wl_selection, selection_offer);
621
622         wl_resource_post_event(&selection->resource,
623                                WL_SELECTION_SEND, mime_type, fd);
624         close(fd);
625 }
626
627 static const struct wl_selection_offer_interface selection_offer_interface = {
628         selection_offer_receive
629 };
630
631 static void
632 selection_offer(struct wl_client *client,
633                 struct wl_resource *resource, const char *type)
634 {
635         struct wl_selection *selection = resource->data;
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_resource *resource,
648                    struct wl_input_device *device, uint32_t time)
649 {
650         struct wl_selection *selection = resource->data;
651         struct wlsc_input_device *wd = (struct wlsc_input_device *) device;
652         struct wl_display *display = wl_client_get_display (client);
653         struct wlsc_compositor *compositor =
654                 (struct wlsc_compositor *) device->compositor;
655
656         selection->input_device = device;
657
658         selection->selection_offer.resource.object.interface =
659                 &wl_selection_offer_interface;
660         selection->selection_offer.resource.object.implementation =
661                 (void (**)(void)) &selection_offer_interface;
662
663         wl_display_add_object(display,
664                               &selection->selection_offer.resource.object);
665
666         if (wd->selection) {
667                 wl_resource_post_event(&wd->selection->resource,
668                                        WL_SELECTION_CANCELLED);
669         }
670         wd->selection = selection;
671
672         wlsc_selection_set_focus(compositor->shell,
673                                  selection, device->keyboard_focus, time);
674 }
675
676 static void
677 selection_destroy(struct wl_client *client, struct wl_resource *resource)
678 {
679         wl_resource_destroy(resource, 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)
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_resource *resource, 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 wlsc_surface *surface =
759                 (struct wlsc_surface *) device->pointer_focus;
760
761         if (surface == NULL)
762                 return;
763
764         shell_move(NULL, NULL, &surface->surface, device, time);
765 }
766
767 static void
768 resize_binding(struct wl_input_device *device, uint32_t time,
769                uint32_t key, uint32_t button, uint32_t state, void *data)
770 {
771         struct wlsc_surface *surface =
772                 (struct wlsc_surface *) device->pointer_focus;
773         uint32_t edges = 0;
774         int32_t x, y;
775
776         if (surface == NULL)
777                 return;
778
779         x = device->grab_x - surface->x;
780         y = device->grab_y - surface->y;
781
782         if (x < surface->width / 3)
783                 edges |= WL_SHELL_RESIZE_LEFT;
784         else if (x < 2 * surface->width / 3)
785                 edges |= 0;
786         else
787                 edges |= WL_SHELL_RESIZE_RIGHT;
788
789         if (y < surface->height / 3)
790                 edges |= WL_SHELL_RESIZE_TOP;
791         else if (y < 2 * surface->height / 3)
792                 edges |= 0;
793         else
794                 edges |= WL_SHELL_RESIZE_BOTTOM;
795
796         shell_resize(NULL, NULL, &surface->surface, device, time, edges);
797 }
798
799 static void
800 lock(struct wlsc_shell *shell)
801 {
802 }
803
804 static void
805 attach(struct wlsc_shell *shell, struct wlsc_surface *es)
806 {
807         if (es->map_type == WLSC_SURFACE_MAP_FULLSCREEN) {
808                 es->x = (es->fullscreen_output->current->width - es->width) / 2;
809                 es->y = (es->fullscreen_output->current->height - es->height) / 2;
810         }
811 }
812
813 int
814 shell_init(struct wlsc_compositor *ec);
815
816 WL_EXPORT int
817 shell_init(struct wlsc_compositor *ec)
818 {
819         struct wl_shell *shell;
820
821         shell = malloc(sizeof *shell);
822         if (shell == NULL)
823                 return -1;
824
825         shell->shell.lock = lock;
826         shell->shell.attach = attach;
827         shell->shell.set_selection_focus = wlsc_selection_set_focus;
828
829         shell->object.interface = &wl_shell_interface;
830         shell->object.implementation = (void (**)(void)) &shell_interface;
831         wl_display_add_object(ec->wl_display, &shell->object);
832         if (wl_display_add_global(ec->wl_display, &shell->object, NULL))
833                 return -1;
834
835         wlsc_compositor_add_binding(ec, 0, BTN_LEFT, MODIFIER_SUPER,
836                                     move_binding, shell);
837         wlsc_compositor_add_binding(ec, 0, BTN_MIDDLE, MODIFIER_SUPER,
838                                     resize_binding, shell);
839
840         ec->shell = &shell->shell;
841
842         return 0;
843 }