Implement text cursor position protocol.
[profile/ivi/weston.git] / src / shell.c
1 /*
2  * Copyright © 2010-2012 Intel Corporation
3  * Copyright © 2011-2012 Collabora, Ltd.
4  *
5  * Permission to use, copy, modify, distribute, and sell this software and
6  * its documentation for any purpose is hereby granted without fee, provided
7  * that the above copyright notice appear in all copies and that both that
8  * copyright notice and this permission notice appear in supporting
9  * documentation, and that the name of the copyright holders not be used in
10  * advertising or publicity pertaining to distribution of the software
11  * without specific, written prior permission.  The copyright holders make
12  * no representations about the suitability of this software for any
13  * purpose.  It is provided "as is" without express or implied warranty.
14  *
15  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
16  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17  * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
18  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
20  * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  */
23
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <stdbool.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <linux/input.h>
30 #include <assert.h>
31 #include <signal.h>
32 #include <math.h>
33 #include <sys/types.h>
34
35 #include <wayland-server.h>
36 #include "compositor.h"
37 #include "desktop-shell-server-protocol.h"
38 #include "../shared/config-parser.h"
39
40 enum animation_type {
41         ANIMATION_NONE,
42
43         ANIMATION_ZOOM,
44         ANIMATION_FADE
45 };
46
47 struct desktop_shell {
48         struct weston_compositor *compositor;
49
50         struct wl_listener lock_listener;
51         struct wl_listener unlock_listener;
52         struct wl_listener destroy_listener;
53
54         struct weston_layer fullscreen_layer;
55         struct weston_layer panel_layer;
56         struct weston_layer toplevel_layer;
57         struct weston_layer background_layer;
58         struct weston_layer lock_layer;
59
60         struct {
61                 struct weston_process process;
62                 struct wl_client *client;
63                 struct wl_resource *desktop_shell;
64
65                 unsigned deathcount;
66                 uint32_t deathstamp;
67         } child;
68
69         bool locked;
70         bool prepare_event_sent;
71
72         struct shell_surface *lock_surface;
73         struct wl_listener lock_surface_listener;
74
75         struct wl_list backgrounds;
76         struct wl_list panels;
77
78         struct {
79                 char *path;
80                 int duration;
81                 struct wl_resource *binding;
82                 struct wl_list surfaces;
83                 struct weston_process process;
84         } screensaver;
85
86         uint32_t binding_modifier;
87         enum animation_type win_animation_type;
88         struct weston_surface *debug_repaint_surface;
89 };
90
91 enum shell_surface_type {
92         SHELL_SURFACE_NONE,
93
94         SHELL_SURFACE_PANEL,
95         SHELL_SURFACE_BACKGROUND,
96         SHELL_SURFACE_LOCK,
97         SHELL_SURFACE_SCREENSAVER,
98
99         SHELL_SURFACE_TOPLEVEL,
100         SHELL_SURFACE_TRANSIENT,
101         SHELL_SURFACE_FULLSCREEN,
102         SHELL_SURFACE_MAXIMIZED,
103         SHELL_SURFACE_POPUP
104 };
105
106 struct ping_timer {
107         struct wl_event_source *source;
108         uint32_t serial;
109 };
110
111 struct shell_surface {
112         struct wl_resource resource;
113
114         struct weston_surface *surface;
115         struct wl_listener surface_destroy_listener;
116         struct shell_surface *parent;
117         struct desktop_shell *shell;
118
119         enum shell_surface_type type, next_type;
120         char *title, *class;
121         int32_t saved_x, saved_y;
122         bool saved_position_valid;
123         bool saved_rotation_valid;
124         int unresponsive;
125
126         struct {
127                 struct weston_transform transform;
128                 struct weston_matrix rotation;
129         } rotation;
130
131         struct {
132                 struct wl_pointer_grab grab;
133                 int32_t x, y;
134                 struct weston_transform parent_transform;
135                 int32_t initial_up;
136                 struct wl_seat *seat;
137                 uint32_t serial;
138         } popup;
139
140         struct {
141                 int32_t x, y;
142                 uint32_t flags;
143         } transient;
144
145         struct {
146                 enum wl_shell_surface_fullscreen_method type;
147                 struct weston_transform transform; /* matrix from x, y */
148                 uint32_t framerate;
149                 struct weston_surface *black_surface;
150         } fullscreen;
151
152         struct ping_timer *ping_timer;
153
154         struct {
155                 struct weston_animation current;
156                 int exists;
157                 int fading_in;
158                 uint32_t timestamp;
159         } unresponsive_animation;
160
161         struct weston_output *fullscreen_output;
162         struct weston_output *output;
163         struct wl_list link;
164
165         const struct weston_shell_client *client;
166 };
167
168 struct shell_grab {
169         struct wl_pointer_grab grab;
170         struct shell_surface *shsurf;
171         struct wl_listener shsurf_destroy_listener;
172 };
173
174 struct weston_move_grab {
175         struct shell_grab base;
176         wl_fixed_t dx, dy;
177 };
178
179 struct rotate_grab {
180         struct shell_grab base;
181         struct weston_matrix rotation;
182         struct {
183                 int32_t x;
184                 int32_t y;
185         } center;
186 };
187
188 static struct shell_surface *
189 get_shell_surface(struct weston_surface *surface);
190
191 static struct desktop_shell *
192 shell_surface_get_shell(struct shell_surface *shsurf);
193
194 static bool
195 shell_surface_is_top_fullscreen(struct shell_surface *shsurf)
196 {
197         struct desktop_shell *shell;
198         struct weston_surface *top_fs_es;
199
200         shell = shell_surface_get_shell(shsurf);
201         
202         if (wl_list_empty(&shell->fullscreen_layer.surface_list))
203                 return false;
204
205         top_fs_es = container_of(shell->fullscreen_layer.surface_list.next,
206                                  struct weston_surface, 
207                                  layer_link);
208         return (shsurf == get_shell_surface(top_fs_es));
209 }
210
211 static void
212 destroy_shell_grab_shsurf(struct wl_listener *listener, void *data)
213 {
214         struct shell_grab *grab;
215
216         grab = container_of(listener, struct shell_grab,
217                             shsurf_destroy_listener);
218
219         grab->shsurf = NULL;
220 }
221
222 static void
223 shell_grab_init(struct shell_grab *grab,
224                 const struct wl_pointer_grab_interface *interface,
225                 struct shell_surface *shsurf)
226 {
227         grab->grab.interface = interface;
228         grab->shsurf = shsurf;
229         grab->shsurf_destroy_listener.notify = destroy_shell_grab_shsurf;
230         wl_signal_add(&shsurf->resource.destroy_signal,
231                       &grab->shsurf_destroy_listener);
232
233 }
234
235 static void
236 shell_grab_finish(struct shell_grab *grab)
237 {
238         wl_list_remove(&grab->shsurf_destroy_listener.link);
239 }
240
241 static void
242 center_on_output(struct weston_surface *surface,
243                  struct weston_output *output);
244
245 static uint32_t
246 get_modifier(char *modifier)
247 {
248         if (!modifier)
249                 return MODIFIER_SUPER;
250
251         if (!strcmp("ctrl", modifier))
252                 return MODIFIER_CTRL;
253         else if (!strcmp("alt", modifier))
254                 return MODIFIER_ALT;
255         else if (!strcmp("super", modifier))
256                 return MODIFIER_SUPER;
257         else
258                 return MODIFIER_SUPER;
259 }
260
261 static enum animation_type
262 get_animation_type(char *animation)
263 {
264         if (!animation)
265                 return ANIMATION_NONE;
266
267         if (!strcmp("zoom", animation))
268                 return ANIMATION_ZOOM;
269         else if (!strcmp("fade", animation))
270                 return ANIMATION_FADE;
271         else
272                 return ANIMATION_NONE;
273 }
274
275 static void
276 shell_configuration(struct desktop_shell *shell)
277 {
278         char *config_file;
279         char *path = NULL;
280         int duration = 60;
281         char *modifier = NULL;
282         char *win_animation = NULL;
283
284         struct config_key shell_keys[] = {
285                 { "binding-modifier",   CONFIG_KEY_STRING, &modifier },
286                 { "animation",          CONFIG_KEY_STRING, &win_animation},
287         };
288
289         struct config_key saver_keys[] = {
290                 { "path",       CONFIG_KEY_STRING,  &path },
291                 { "duration",   CONFIG_KEY_INTEGER, &duration },
292         };
293
294         struct config_section cs[] = {
295                 { "shell", shell_keys, ARRAY_LENGTH(shell_keys), NULL },
296                 { "screensaver", saver_keys, ARRAY_LENGTH(saver_keys), NULL },
297         };
298
299         config_file = config_file_path("weston.ini");
300         parse_config_file(config_file, cs, ARRAY_LENGTH(cs), shell);
301         free(config_file);
302
303         shell->screensaver.path = path;
304         shell->screensaver.duration = duration;
305         shell->binding_modifier = get_modifier(modifier);
306         shell->win_animation_type = get_animation_type(win_animation);
307 }
308
309 static void
310 noop_grab_focus(struct wl_pointer_grab *grab,
311                 struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y)
312 {
313         grab->focus = NULL;
314 }
315
316 static void
317 move_grab_motion(struct wl_pointer_grab *grab,
318                  uint32_t time, wl_fixed_t x, wl_fixed_t y)
319 {
320         struct weston_move_grab *move = (struct weston_move_grab *) grab;
321         struct wl_pointer *pointer = grab->pointer;
322         struct shell_surface *shsurf = move->base.shsurf;
323         struct weston_surface *es;
324         int dx = wl_fixed_to_int(pointer->x + move->dx);
325         int dy = wl_fixed_to_int(pointer->y + move->dy);
326
327         if (!shsurf)
328                 return;
329
330         es = shsurf->surface;
331
332         weston_surface_configure(es, dx, dy,
333                                  es->geometry.width, es->geometry.height);
334 }
335
336 static void
337 move_grab_button(struct wl_pointer_grab *grab,
338                  uint32_t time, uint32_t button, uint32_t state)
339 {
340         struct shell_grab *shell_grab = container_of(grab, struct shell_grab,
341                                                     grab);
342         struct wl_pointer *pointer = grab->pointer;
343
344         if (pointer->button_count == 0 && state == 0) {
345                 shell_grab_finish(shell_grab);
346                 wl_pointer_end_grab(pointer);
347                 free(grab);
348         }
349 }
350
351 static const struct wl_pointer_grab_interface move_grab_interface = {
352         noop_grab_focus,
353         move_grab_motion,
354         move_grab_button,
355 };
356
357 static void
358 unresponsive_surface_fade(struct shell_surface *shsurf, bool reverse)
359 {
360         shsurf->unresponsive_animation.fading_in = reverse ? 0 : 1;
361
362         if(!shsurf->unresponsive_animation.exists) {
363                 wl_list_insert(&shsurf->surface->compositor->animation_list,
364                        &shsurf->unresponsive_animation.current.link);
365                 shsurf->unresponsive_animation.exists = 1;
366                 shsurf->unresponsive_animation.timestamp = weston_compositor_get_time();
367                 weston_surface_damage(shsurf->surface);
368         }
369 }
370
371 static void
372 unresponsive_fade_frame(struct weston_animation *animation,
373                 struct weston_output *output, uint32_t msecs)
374 {
375         struct shell_surface *shsurf =
376                 container_of(animation, struct shell_surface, unresponsive_animation.current);
377         struct weston_surface *surface = shsurf->surface;
378         unsigned int step = 8;
379
380         if (!surface || !shsurf)
381                 return;
382
383         if (shsurf->unresponsive_animation.fading_in) {
384                 while (step < msecs - shsurf->unresponsive_animation.timestamp) {
385                         if (surface->saturation > 1)
386                                 surface->saturation -= 5;
387                         if (surface->brightness > 200)
388                                 surface->brightness--;
389
390                         shsurf->unresponsive_animation.timestamp += step;
391                 }
392
393                 if (surface->saturation <= 1 && surface->brightness <= 200) {
394                         wl_list_remove(&shsurf->unresponsive_animation.current.link);
395                         shsurf->unresponsive_animation.exists = 0;
396                 }
397         }
398         else {
399                 while (step < msecs - shsurf->unresponsive_animation.timestamp) {
400                         if (surface->saturation < 255)
401                                 surface->saturation += 5;
402                         if (surface->brightness < 255)
403                                 surface->brightness++;
404
405                         shsurf->unresponsive_animation.timestamp += step;
406                 }
407
408                 if (surface->saturation >= 255 && surface->brightness >= 255) {
409                         surface->saturation = surface->brightness = 255;
410                         wl_list_remove(&shsurf->unresponsive_animation.current.link);
411                         shsurf->unresponsive_animation.exists = 0;
412                 }
413         }
414
415         surface->geometry.dirty = 1;
416         weston_surface_damage(surface);
417 }
418
419 static void
420 ping_timer_destroy(struct shell_surface *shsurf)
421 {
422         if (!shsurf || !shsurf->ping_timer)
423                 return;
424
425         if (shsurf->ping_timer->source)
426                 wl_event_source_remove(shsurf->ping_timer->source);
427
428         free(shsurf->ping_timer);
429         shsurf->ping_timer = NULL;
430 }
431
432 static int
433 ping_timeout_handler(void *data)
434 {
435         struct shell_surface *shsurf = data;
436
437         /* Client is not responding */
438         shsurf->unresponsive = 1;
439         unresponsive_surface_fade(shsurf, false);
440
441         return 1;
442 }
443
444 static void
445 ping_handler(struct weston_surface *surface, uint32_t serial)
446 {
447         struct shell_surface *shsurf = get_shell_surface(surface);
448         struct wl_event_loop *loop;
449         int ping_timeout = 2500;
450
451         if (!shsurf)
452                 return;
453         if (!shsurf->resource.client)
454                 return;
455
456         if (!shsurf->ping_timer) {
457                 shsurf->ping_timer = malloc(sizeof *shsurf->ping_timer);
458                 if (!shsurf->ping_timer)
459                         return;
460
461                 shsurf->ping_timer->serial = serial;
462                 loop = wl_display_get_event_loop(surface->compositor->wl_display);
463                 shsurf->ping_timer->source =
464                         wl_event_loop_add_timer(loop, ping_timeout_handler, shsurf);
465                 wl_event_source_timer_update(shsurf->ping_timer->source, ping_timeout);
466
467                 wl_shell_surface_send_ping(&shsurf->resource, serial);
468         }
469 }
470
471 static void
472 shell_surface_pong(struct wl_client *client, struct wl_resource *resource,
473                                                         uint32_t serial)
474 {
475         struct shell_surface *shsurf = resource->data;
476
477         if (shsurf->ping_timer->serial == serial) {
478                 if (shsurf->unresponsive) {
479                         /* Received pong from previously unresponsive client */
480                         unresponsive_surface_fade(shsurf, true);
481                 }
482                 shsurf->unresponsive = 0;
483                 ping_timer_destroy(shsurf);
484         }
485 }
486
487 static void
488 shell_surface_set_title(struct wl_client *client,
489                         struct wl_resource *resource, const char *title)
490 {
491         struct shell_surface *shsurf = resource->data;
492
493         free(shsurf->title);
494         shsurf->title = strdup(title);
495 }
496
497 static void
498 shell_surface_set_class(struct wl_client *client,
499                         struct wl_resource *resource, const char *class)
500 {
501         struct shell_surface *shsurf = resource->data;
502
503         free(shsurf->class);
504         shsurf->class = strdup(class);
505 }
506
507 static int
508 surface_move(struct shell_surface *shsurf, struct weston_seat *ws)
509 {
510         struct weston_move_grab *move;
511
512         if (!shsurf)
513                 return -1;
514
515         move = malloc(sizeof *move);
516         if (!move)
517                 return -1;
518
519         shell_grab_init(&move->base, &move_grab_interface, shsurf);
520
521         move->dx = wl_fixed_from_double(shsurf->surface->geometry.x) -
522                         ws->seat.pointer->grab_x;
523         move->dy = wl_fixed_from_double(shsurf->surface->geometry.y) -
524                         ws->seat.pointer->grab_y;
525
526         wl_pointer_start_grab(ws->seat.pointer, &move->base.grab);
527
528         wl_pointer_set_focus(ws->seat.pointer, NULL,
529                              wl_fixed_from_int(0),
530                              wl_fixed_from_int(0));
531
532         return 0;
533 }
534
535 static void
536 shell_surface_move(struct wl_client *client, struct wl_resource *resource,
537                    struct wl_resource *seat_resource, uint32_t serial)
538 {
539         struct weston_seat *ws = seat_resource->data;
540         struct shell_surface *shsurf = resource->data;
541
542         if (ws->seat.pointer->button_count == 0 ||
543             ws->seat.pointer->grab_serial != serial ||
544             ws->seat.pointer->focus != &shsurf->surface->surface)
545                 return;
546
547         if (surface_move(shsurf, ws) < 0)
548                 wl_resource_post_no_memory(resource);
549 }
550
551 struct weston_resize_grab {
552         struct shell_grab base;
553         uint32_t edges;
554         int32_t width, height;
555 };
556
557 static void
558 resize_grab_motion(struct wl_pointer_grab *grab,
559                    uint32_t time, wl_fixed_t x, wl_fixed_t y)
560 {
561         struct weston_resize_grab *resize = (struct weston_resize_grab *) grab;
562         struct wl_pointer *pointer = grab->pointer;
563         struct shell_surface *shsurf = resize->base.shsurf;
564         int32_t width, height;
565         wl_fixed_t from_x, from_y;
566         wl_fixed_t to_x, to_y;
567
568         if (!shsurf)
569                 return;
570
571         weston_surface_from_global_fixed(shsurf->surface,
572                                          pointer->grab_x, pointer->grab_y,
573                                          &from_x, &from_y);
574         weston_surface_from_global_fixed(shsurf->surface,
575                                          pointer->x, pointer->y, &to_x, &to_y);
576
577         width = resize->width;
578         if (resize->edges & WL_SHELL_SURFACE_RESIZE_LEFT) {
579                 width += wl_fixed_to_int(from_x - to_x);
580         } else if (resize->edges & WL_SHELL_SURFACE_RESIZE_RIGHT) {
581                 width += wl_fixed_to_int(to_x - from_x);
582         }
583
584         height = resize->height;
585         if (resize->edges & WL_SHELL_SURFACE_RESIZE_TOP) {
586                 height += wl_fixed_to_int(from_y - to_y);
587         } else if (resize->edges & WL_SHELL_SURFACE_RESIZE_BOTTOM) {
588                 height += wl_fixed_to_int(to_y - from_y);
589         }
590
591         shsurf->client->send_configure(shsurf->surface,
592                                        resize->edges, width, height);
593 }
594
595 static void
596 send_configure(struct weston_surface *surface,
597                uint32_t edges, int32_t width, int32_t height)
598 {
599         struct shell_surface *shsurf = get_shell_surface(surface);
600
601         wl_shell_surface_send_configure(&shsurf->resource,
602                                         edges, width, height);
603 }
604
605 static const struct weston_shell_client shell_client = {
606         send_configure
607 };
608
609 static void
610 resize_grab_button(struct wl_pointer_grab *grab,
611                    uint32_t time, uint32_t button, uint32_t state)
612 {
613         struct weston_resize_grab *resize = (struct weston_resize_grab *) grab;
614         struct wl_pointer *pointer = grab->pointer;
615
616         if (pointer->button_count == 0 && state == 0) {
617                 shell_grab_finish(&resize->base);
618                 wl_pointer_end_grab(pointer);
619                 free(grab);
620         }
621 }
622
623 static const struct wl_pointer_grab_interface resize_grab_interface = {
624         noop_grab_focus,
625         resize_grab_motion,
626         resize_grab_button,
627 };
628
629 static int
630 surface_resize(struct shell_surface *shsurf,
631                struct weston_seat *ws, uint32_t edges)
632 {
633         struct weston_resize_grab *resize;
634
635         if (shsurf->type == SHELL_SURFACE_FULLSCREEN)
636                 return 0;
637
638         if (edges == 0 || edges > 15 ||
639             (edges & 3) == 3 || (edges & 12) == 12)
640                 return 0;
641
642         resize = malloc(sizeof *resize);
643         if (!resize)
644                 return -1;
645
646         shell_grab_init(&resize->base, &resize_grab_interface, shsurf);
647
648         resize->edges = edges;
649         resize->width = shsurf->surface->geometry.width;
650         resize->height = shsurf->surface->geometry.height;
651
652         wl_pointer_start_grab(ws->seat.pointer, &resize->base.grab);
653
654         wl_pointer_set_focus(ws->seat.pointer, NULL,
655                              wl_fixed_from_int(0),
656                              wl_fixed_from_int(0));
657
658         return 0;
659 }
660
661 static void
662 shell_surface_resize(struct wl_client *client, struct wl_resource *resource,
663                      struct wl_resource *seat_resource, uint32_t serial,
664                      uint32_t edges)
665 {
666         struct weston_seat *ws = seat_resource->data;
667         struct shell_surface *shsurf = resource->data;
668
669         if (shsurf->type == SHELL_SURFACE_FULLSCREEN)
670                 return;
671
672         if (ws->seat.pointer->button_count == 0 ||
673             ws->seat.pointer->grab_serial != serial ||
674             ws->seat.pointer->focus != &shsurf->surface->surface)
675                 return;
676
677         if (surface_resize(shsurf, ws, edges) < 0)
678                 wl_resource_post_no_memory(resource);
679 }
680
681 static struct weston_output *
682 get_default_output(struct weston_compositor *compositor)
683 {
684         return container_of(compositor->output_list.next,
685                             struct weston_output, link);
686 }
687
688 static void
689 shell_unset_fullscreen(struct shell_surface *shsurf)
690 {
691         /* undo all fullscreen things here */
692         if (shsurf->fullscreen.type == WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER &&
693             shell_surface_is_top_fullscreen(shsurf)) {
694                 weston_output_switch_mode(shsurf->fullscreen_output,
695                                           shsurf->fullscreen_output->origin);
696         }
697         shsurf->fullscreen.type = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT;
698         shsurf->fullscreen.framerate = 0;
699         wl_list_remove(&shsurf->fullscreen.transform.link);
700         wl_list_init(&shsurf->fullscreen.transform.link);
701         if (shsurf->fullscreen.black_surface)
702                 weston_surface_destroy(shsurf->fullscreen.black_surface);
703         shsurf->fullscreen.black_surface = NULL;
704         shsurf->fullscreen_output = NULL;
705         weston_surface_set_position(shsurf->surface,
706                                     shsurf->saved_x, shsurf->saved_y);
707         if (shsurf->saved_rotation_valid) {
708                 wl_list_insert(&shsurf->surface->geometry.transformation_list,
709                                &shsurf->rotation.transform.link);
710                 shsurf->saved_rotation_valid = false;
711         }
712 }
713
714 static int
715 reset_shell_surface_type(struct shell_surface *surface)
716 {
717         switch (surface->type) {
718         case SHELL_SURFACE_FULLSCREEN:
719                 shell_unset_fullscreen(surface);
720                 break;
721         case SHELL_SURFACE_MAXIMIZED:
722                 surface->output = get_default_output(surface->surface->compositor);
723                 weston_surface_set_position(surface->surface,
724                                             surface->saved_x,
725                                             surface->saved_y);
726                 break;
727         case SHELL_SURFACE_PANEL:
728         case SHELL_SURFACE_BACKGROUND:
729                 wl_list_remove(&surface->link);
730                 wl_list_init(&surface->link);
731                 break;
732         case SHELL_SURFACE_SCREENSAVER:
733         case SHELL_SURFACE_LOCK:
734                 wl_resource_post_error(&surface->resource,
735                                        WL_DISPLAY_ERROR_INVALID_METHOD,
736                                        "cannot reassign surface type");
737                 return -1;
738         case SHELL_SURFACE_NONE:
739         case SHELL_SURFACE_TOPLEVEL:
740         case SHELL_SURFACE_TRANSIENT:
741         case SHELL_SURFACE_POPUP:
742                 break;
743         }
744
745         surface->type = SHELL_SURFACE_NONE;
746         return 0;
747 }
748
749 static void
750 set_surface_type(struct shell_surface *shsurf)
751 {
752         struct weston_surface *surface = shsurf->surface;
753         struct shell_surface *pshsurf = shsurf->parent;
754         struct weston_surface *pes;
755         struct shell_surface *priv;
756         struct desktop_shell *shell = shsurf->shell;
757
758         reset_shell_surface_type(shsurf);
759
760         shsurf->type = shsurf->next_type;
761         shsurf->next_type = SHELL_SURFACE_NONE;
762
763         switch (shsurf->type) {
764         case SHELL_SURFACE_TOPLEVEL:
765                 break;
766         case SHELL_SURFACE_TRANSIENT:
767                 pes = pshsurf->surface;
768                 weston_surface_set_position(surface,
769                                 pes->geometry.x + shsurf->transient.x,
770                                 pes->geometry.y + shsurf->transient.y);
771                 break;
772
773         case SHELL_SURFACE_MAXIMIZED:
774                 shsurf->saved_x = surface->geometry.x;
775                 shsurf->saved_y = surface->geometry.y;
776                 shsurf->saved_position_valid = true;
777                 break;
778
779         case SHELL_SURFACE_FULLSCREEN:
780                 shsurf->saved_x = surface->geometry.x;
781                 shsurf->saved_y = surface->geometry.y;
782                 shsurf->saved_position_valid = true;
783
784                 if (!wl_list_empty(&shsurf->rotation.transform.link)) {
785                         wl_list_remove(&shsurf->rotation.transform.link);
786                         wl_list_init(&shsurf->rotation.transform.link);
787                         shsurf->surface->geometry.dirty = 1;
788                         shsurf->saved_rotation_valid = true;
789                 }
790                 break;
791
792         case SHELL_SURFACE_BACKGROUND:
793                 wl_list_for_each(priv, &shell->backgrounds, link) {
794                         if (priv->output == shsurf->output) {
795                                 priv->surface->output = NULL;
796                                 wl_list_remove(&priv->surface->layer_link);
797                                 wl_list_remove(&priv->link);
798                                 break;
799                         }
800                 }
801
802                 wl_list_insert(&shell->backgrounds, &shsurf->link);
803
804                 weston_surface_set_position(surface, shsurf->output->x,
805                                             shsurf->output->y);
806                 break;
807
808         case SHELL_SURFACE_PANEL:
809                 wl_list_for_each(priv, &shell->panels, link) {
810                         if (priv->output == shsurf->output) {
811                                 priv->surface->output = NULL;
812                                 wl_list_remove(&priv->surface->layer_link);
813                                 wl_list_remove(&priv->link);
814                                 break;
815                         }
816                 }
817
818                 wl_list_insert(&shell->panels, &shsurf->link);
819
820                 weston_surface_set_position(surface, shsurf->output->x,
821                                             shsurf->output->y);
822                 break;
823
824         default:
825                 break;
826         }
827 }
828
829 static void
830 set_toplevel(struct shell_surface *shsurf)
831 {
832        shsurf->next_type = SHELL_SURFACE_TOPLEVEL;
833 }
834
835 static void
836 shell_surface_set_toplevel(struct wl_client *client,
837                            struct wl_resource *resource)
838 {
839         struct shell_surface *surface = resource->data;
840
841         set_toplevel(surface);
842 }
843
844 static void
845 set_transient(struct shell_surface *shsurf,
846               struct shell_surface *pshsurf, int x, int y, uint32_t flags)
847 {
848         /* assign to parents output */
849         shsurf->parent = pshsurf;
850         shsurf->transient.x = x;
851         shsurf->transient.y = y;
852         shsurf->transient.flags = flags;
853         shsurf->next_type = SHELL_SURFACE_TRANSIENT;
854 }
855
856 static void
857 shell_surface_set_transient(struct wl_client *client,
858                             struct wl_resource *resource,
859                             struct wl_resource *parent_resource,
860                             int x, int y, uint32_t flags)
861 {
862         struct shell_surface *shsurf = resource->data;
863         struct shell_surface *pshsurf = parent_resource->data;
864
865         set_transient(shsurf, pshsurf, x, y, flags);
866 }
867
868 static struct desktop_shell *
869 shell_surface_get_shell(struct shell_surface *shsurf)
870 {
871         return shsurf->shell;
872 }
873
874 static int
875 get_output_panel_height(struct desktop_shell *shell,
876                         struct weston_output *output)
877 {
878         struct shell_surface *priv;
879         int panel_height = 0;
880
881         if (!output)
882                 return 0;
883
884         wl_list_for_each(priv, &shell->panels, link) {
885                 if (priv->output == output) {
886                         panel_height = priv->surface->geometry.height;
887                         break;
888                 }
889         }
890         return panel_height;
891 }
892
893 static void
894 shell_surface_set_maximized(struct wl_client *client,
895                             struct wl_resource *resource,
896                             struct wl_resource *output_resource )
897 {
898         struct shell_surface *shsurf = resource->data;
899         struct weston_surface *es = shsurf->surface;
900         struct desktop_shell *shell = NULL;
901         uint32_t edges = 0, panel_height = 0;
902
903         /* get the default output, if the client set it as NULL
904            check whether the ouput is available */
905         if (output_resource)
906                 shsurf->output = output_resource->data;
907         else
908                 shsurf->output = get_default_output(es->compositor);
909
910         shell = shell_surface_get_shell(shsurf);
911         panel_height = get_output_panel_height(shell, es->output);
912         edges = WL_SHELL_SURFACE_RESIZE_TOP|WL_SHELL_SURFACE_RESIZE_LEFT;
913
914         shsurf->client->send_configure(shsurf->surface, edges,
915                                        es->output->current->width,
916                                        es->output->current->height - panel_height);
917
918         shsurf->next_type = SHELL_SURFACE_MAXIMIZED;
919 }
920
921 static void
922 black_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy);
923
924 static struct weston_surface *
925 create_black_surface(struct weston_compositor *ec,
926                      struct weston_surface *fs_surface,
927                      GLfloat x, GLfloat y, int w, int h)
928 {
929         struct weston_surface *surface = NULL;
930
931         surface = weston_surface_create(ec);
932         if (surface == NULL) {
933                 fprintf(stderr, "no memory\n");
934                 return NULL;
935         }
936
937         surface->configure = black_surface_configure;
938         surface->private = fs_surface;
939         weston_surface_configure(surface, x, y, w, h);
940         weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1);
941         return surface;
942 }
943
944 /* Create black surface and append it to the associated fullscreen surface.
945  * Handle size dismatch and positioning according to the method. */
946 static void
947 shell_configure_fullscreen(struct shell_surface *shsurf)
948 {
949         struct weston_output *output = shsurf->fullscreen_output;
950         struct weston_surface *surface = shsurf->surface;
951         struct weston_matrix *matrix;
952         float scale;
953
954         center_on_output(surface, output);
955
956         if (!shsurf->fullscreen.black_surface)
957                 shsurf->fullscreen.black_surface =
958                         create_black_surface(surface->compositor,
959                                              surface,
960                                              output->x, output->y,
961                                              output->current->width,
962                                              output->current->height);
963
964         wl_list_remove(&shsurf->fullscreen.black_surface->layer_link);
965         wl_list_insert(&surface->layer_link,
966                        &shsurf->fullscreen.black_surface->layer_link);
967         shsurf->fullscreen.black_surface->output = output;
968
969         switch (shsurf->fullscreen.type) {
970         case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT:
971                 break;
972         case WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE:
973                 matrix = &shsurf->fullscreen.transform.matrix;
974                 weston_matrix_init(matrix);
975                 scale = (float)output->current->width/(float)surface->geometry.width;
976                 weston_matrix_scale(matrix, scale, scale, 1);
977                 wl_list_remove(&shsurf->fullscreen.transform.link);
978                 wl_list_insert(surface->geometry.transformation_list.prev,
979                                &shsurf->fullscreen.transform.link);
980                 weston_surface_set_position(surface, output->x, output->y);
981                 break;
982         case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER:
983                 if (shell_surface_is_top_fullscreen(shsurf)) {
984                         struct weston_mode mode = {0, 
985                                 surface->geometry.width,
986                                 surface->geometry.height,
987                                 shsurf->fullscreen.framerate};
988
989                         if (weston_output_switch_mode(output, &mode) == 0) {
990                                 weston_surface_configure(shsurf->fullscreen.black_surface, 
991                                                          output->x, output->y,
992                                                          output->current->width,
993                                                          output->current->height);
994                                 weston_surface_set_position(surface, output->x, output->y);
995                                 break;
996                         }
997                 }
998                 break;
999         case WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL:
1000                 break;
1001         default:
1002                 break;
1003         }
1004 }
1005
1006 /* make the fullscreen and black surface at the top */
1007 static void
1008 shell_stack_fullscreen(struct shell_surface *shsurf)
1009 {
1010         struct weston_output *output = shsurf->fullscreen_output;
1011         struct weston_surface *surface = shsurf->surface;
1012         struct desktop_shell *shell = shell_surface_get_shell(shsurf);
1013
1014         wl_list_remove(&surface->layer_link);
1015         wl_list_insert(&shell->fullscreen_layer.surface_list,
1016                        &surface->layer_link);
1017         weston_surface_damage(surface);
1018
1019         if (!shsurf->fullscreen.black_surface)
1020                 shsurf->fullscreen.black_surface =
1021                         create_black_surface(surface->compositor,
1022                                              surface,
1023                                              output->x, output->y,
1024                                              output->current->width,
1025                                              output->current->height);
1026
1027         wl_list_remove(&shsurf->fullscreen.black_surface->layer_link);
1028         wl_list_insert(&surface->layer_link,
1029                        &shsurf->fullscreen.black_surface->layer_link);
1030         weston_surface_damage(shsurf->fullscreen.black_surface);
1031 }
1032
1033 static void
1034 shell_map_fullscreen(struct shell_surface *shsurf)
1035 {
1036         shell_stack_fullscreen(shsurf);
1037         shell_configure_fullscreen(shsurf);
1038 }
1039
1040 static void
1041 shell_surface_set_fullscreen(struct wl_client *client,
1042                              struct wl_resource *resource,
1043                              uint32_t method,
1044                              uint32_t framerate,
1045                              struct wl_resource *output_resource)
1046 {
1047         struct shell_surface *shsurf = resource->data;
1048         struct weston_surface *es = shsurf->surface;
1049
1050         if (output_resource)
1051                 shsurf->output = output_resource->data;
1052         else
1053                 shsurf->output = get_default_output(es->compositor);
1054
1055         shsurf->fullscreen_output = shsurf->output;
1056         shsurf->fullscreen.type = method;
1057         shsurf->fullscreen.framerate = framerate;
1058         shsurf->next_type = SHELL_SURFACE_FULLSCREEN;
1059
1060         shsurf->client->send_configure(shsurf->surface, 0,
1061                                        shsurf->output->current->width,
1062                                        shsurf->output->current->height);
1063 }
1064
1065 static void
1066 popup_grab_focus(struct wl_pointer_grab *grab,
1067                  struct wl_surface *surface,
1068                  wl_fixed_t x,
1069                  wl_fixed_t y)
1070 {
1071         struct wl_pointer *pointer = grab->pointer;
1072         struct shell_surface *priv =
1073                 container_of(grab, struct shell_surface, popup.grab);
1074         struct wl_client *client = priv->surface->surface.resource.client;
1075
1076         if (surface && surface->resource.client == client) {
1077                 wl_pointer_set_focus(pointer, surface, x, y);
1078                 grab->focus = surface;
1079         } else {
1080                 wl_pointer_set_focus(pointer, NULL,
1081                                      wl_fixed_from_int(0),
1082                                      wl_fixed_from_int(0));
1083                 grab->focus = NULL;
1084         }
1085 }
1086
1087 static void
1088 popup_grab_motion(struct wl_pointer_grab *grab,
1089                   uint32_t time, wl_fixed_t sx, wl_fixed_t sy)
1090 {
1091         struct wl_resource *resource;
1092
1093         resource = grab->pointer->focus_resource;
1094         if (resource)
1095                 wl_pointer_send_motion(resource, time, sx, sy);
1096 }
1097
1098 static void
1099 popup_grab_button(struct wl_pointer_grab *grab,
1100                   uint32_t time, uint32_t button, uint32_t state)
1101 {
1102         struct wl_resource *resource;
1103         struct shell_surface *shsurf =
1104                 container_of(grab, struct shell_surface, popup.grab);
1105         struct wl_display *display;
1106         uint32_t serial;
1107
1108         resource = grab->pointer->focus_resource;
1109         if (resource) {
1110                 display = wl_client_get_display(resource->client);
1111                 serial = wl_display_get_serial(display);
1112                 wl_pointer_send_button(resource, serial, time, button, state);
1113         } else if (state == 0 &&
1114                    (shsurf->popup.initial_up ||
1115                     time - shsurf->popup.seat->pointer->grab_time > 500)) {
1116                 wl_shell_surface_send_popup_done(&shsurf->resource);
1117                 wl_pointer_end_grab(grab->pointer);
1118                 shsurf->popup.grab.pointer = NULL;
1119         }
1120
1121         if (state == 0)
1122                 shsurf->popup.initial_up = 1;
1123 }
1124
1125 static const struct wl_pointer_grab_interface popup_grab_interface = {
1126         popup_grab_focus,
1127         popup_grab_motion,
1128         popup_grab_button,
1129 };
1130
1131 static void
1132 shell_map_popup(struct shell_surface *shsurf)
1133 {
1134         struct wl_seat *seat = shsurf->popup.seat;
1135         struct weston_surface *es = shsurf->surface;
1136         struct weston_surface *parent = shsurf->parent->surface;
1137
1138         es->output = parent->output;
1139         shsurf->popup.grab.interface = &popup_grab_interface;
1140
1141         weston_surface_update_transform(parent);
1142         if (parent->transform.enabled) {
1143                 shsurf->popup.parent_transform.matrix =
1144                         parent->transform.matrix;
1145         } else {
1146                 /* construct x, y translation matrix */
1147                 weston_matrix_init(&shsurf->popup.parent_transform.matrix);
1148                 shsurf->popup.parent_transform.matrix.d[12] =
1149                         parent->geometry.x;
1150                 shsurf->popup.parent_transform.matrix.d[13] =
1151                         parent->geometry.y;
1152         }
1153         wl_list_insert(es->geometry.transformation_list.prev,
1154                        &shsurf->popup.parent_transform.link);
1155         weston_surface_set_position(es, shsurf->popup.x, shsurf->popup.y);
1156
1157         shsurf->popup.initial_up = 0;
1158
1159         /* We don't require the grab to still be active, but if another
1160          * grab has started in the meantime, we end the popup now. */
1161         if (seat->pointer->grab_serial == shsurf->popup.serial) {
1162                 wl_pointer_start_grab(seat->pointer, &shsurf->popup.grab);
1163         } else {
1164                 wl_shell_surface_send_popup_done(&shsurf->resource);
1165         }
1166 }
1167
1168 static void
1169 shell_surface_set_popup(struct wl_client *client,
1170                         struct wl_resource *resource,
1171                         struct wl_resource *seat_resource,
1172                         uint32_t serial,
1173                         struct wl_resource *parent_resource,
1174                         int32_t x, int32_t y, uint32_t flags)
1175 {
1176         struct shell_surface *shsurf = resource->data;
1177
1178         shsurf->type = SHELL_SURFACE_POPUP;
1179         shsurf->parent = parent_resource->data;
1180         shsurf->popup.seat = seat_resource->data;
1181         shsurf->popup.serial = serial;
1182         shsurf->popup.x = x;
1183         shsurf->popup.y = y;
1184 }
1185
1186 static const struct wl_shell_surface_interface shell_surface_implementation = {
1187         shell_surface_pong,
1188         shell_surface_move,
1189         shell_surface_resize,
1190         shell_surface_set_toplevel,
1191         shell_surface_set_transient,
1192         shell_surface_set_fullscreen,
1193         shell_surface_set_popup,
1194         shell_surface_set_maximized,
1195         shell_surface_set_title,
1196         shell_surface_set_class
1197 };
1198
1199 static void
1200 destroy_shell_surface(struct shell_surface *shsurf)
1201 {
1202         if (shsurf->popup.grab.pointer)
1203                 wl_pointer_end_grab(shsurf->popup.grab.pointer);
1204
1205         if (shsurf->fullscreen.type == WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER &&
1206             shell_surface_is_top_fullscreen(shsurf)) {
1207                 weston_output_switch_mode(shsurf->fullscreen_output,
1208                                           shsurf->fullscreen_output->origin);
1209         }
1210
1211         if (shsurf->fullscreen.black_surface)
1212                 weston_surface_destroy(shsurf->fullscreen.black_surface);
1213
1214         /* As destroy_resource() use wl_list_for_each_safe(),
1215          * we can always remove the listener.
1216          */
1217         wl_list_remove(&shsurf->surface_destroy_listener.link);
1218         shsurf->surface->configure = NULL;
1219         ping_timer_destroy(shsurf);
1220
1221         if (shsurf->unresponsive_animation.exists)
1222                 wl_list_remove(&shsurf->unresponsive_animation.current.link);
1223
1224         wl_list_remove(&shsurf->link);
1225         free(shsurf);
1226 }
1227
1228 static void
1229 shell_destroy_shell_surface(struct wl_resource *resource)
1230 {
1231         struct shell_surface *shsurf = resource->data;
1232
1233         destroy_shell_surface(shsurf);
1234 }
1235
1236 static void
1237 shell_handle_surface_destroy(struct wl_listener *listener, void *data)
1238 {
1239         struct shell_surface *shsurf = container_of(listener,
1240                                                     struct shell_surface,
1241                                                     surface_destroy_listener);
1242
1243         /* tricky way to check if resource was in fact created */
1244         if (shsurf->resource.object.implementation != 0)
1245                 wl_resource_destroy(&shsurf->resource);
1246         else
1247                 destroy_shell_surface(shsurf);
1248 }
1249
1250 static struct shell_surface *
1251 get_shell_surface(struct weston_surface *surface)
1252 {
1253         struct wl_listener *listener;
1254
1255         listener = wl_signal_get(&surface->surface.resource.destroy_signal,
1256                                  shell_handle_surface_destroy);
1257         if (listener)
1258                 return container_of(listener, struct shell_surface,
1259                                     surface_destroy_listener);
1260
1261         return NULL;
1262 }
1263
1264 static void
1265 shell_surface_configure(struct weston_surface *, int32_t, int32_t);
1266
1267 static  struct shell_surface *
1268 create_shell_surface(void *shell, struct weston_surface *surface,
1269                      const struct weston_shell_client *client)
1270 {
1271         struct shell_surface *shsurf;
1272
1273         if (surface->configure) {
1274                 fprintf(stderr, "surface->configure already set\n");
1275                 return NULL;
1276         }
1277
1278         shsurf = calloc(1, sizeof *shsurf);
1279         if (!shsurf) {
1280                 fprintf(stderr, "no memory to allocate shell surface\n");
1281                 return NULL;
1282         }
1283
1284         surface->configure = shell_surface_configure;
1285         surface->compositor->shell_interface.shell = shell;
1286
1287         shsurf->shell = (struct desktop_shell *) shell;
1288         shsurf->unresponsive = 0;
1289         shsurf->unresponsive_animation.exists = 0;
1290         shsurf->unresponsive_animation.fading_in = 0;
1291         shsurf->unresponsive_animation.current.frame = unresponsive_fade_frame;
1292         shsurf->saved_position_valid = false;
1293         shsurf->saved_rotation_valid = false;
1294         shsurf->surface = surface;
1295         shsurf->fullscreen.type = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT;
1296         shsurf->fullscreen.framerate = 0;
1297         shsurf->fullscreen.black_surface = NULL;
1298         shsurf->ping_timer = NULL;
1299         wl_list_init(&shsurf->fullscreen.transform.link);
1300
1301         wl_signal_init(&shsurf->resource.destroy_signal);
1302         shsurf->surface_destroy_listener.notify = shell_handle_surface_destroy;
1303         wl_signal_add(&surface->surface.resource.destroy_signal,
1304                       &shsurf->surface_destroy_listener);
1305
1306         /* init link so its safe to always remove it in destroy_shell_surface */
1307         wl_list_init(&shsurf->link);
1308
1309         /* empty when not in use */
1310         wl_list_init(&shsurf->rotation.transform.link);
1311         weston_matrix_init(&shsurf->rotation.rotation);
1312
1313         shsurf->type = SHELL_SURFACE_NONE;
1314         shsurf->next_type = SHELL_SURFACE_NONE;
1315
1316         shsurf->client = client;
1317
1318         return shsurf;
1319 }
1320
1321 static void
1322 shell_get_shell_surface(struct wl_client *client,
1323                         struct wl_resource *resource,
1324                         uint32_t id,
1325                         struct wl_resource *surface_resource)
1326 {
1327         struct weston_surface *surface = surface_resource->data;
1328         struct desktop_shell *shell = resource->data;
1329         struct shell_surface *shsurf;
1330
1331         if (get_shell_surface(surface)) {
1332                 wl_resource_post_error(surface_resource,
1333                                        WL_DISPLAY_ERROR_INVALID_OBJECT,
1334                                        "desktop_shell::get_shell_surface already requested");
1335                 return;
1336         }
1337
1338         shsurf = create_shell_surface(shell, surface, &shell_client);
1339         if (!shsurf) {
1340                 wl_resource_post_error(surface_resource,
1341                                        WL_DISPLAY_ERROR_INVALID_OBJECT,
1342                                        "surface->configure already set");
1343                 return;
1344         }
1345
1346         shsurf->resource.destroy = shell_destroy_shell_surface;
1347         shsurf->resource.object.id = id;
1348         shsurf->resource.object.interface = &wl_shell_surface_interface;
1349         shsurf->resource.object.implementation =
1350                 (void (**)(void)) &shell_surface_implementation;
1351         shsurf->resource.data = shsurf;
1352
1353         wl_client_add_resource(client, &shsurf->resource);
1354 }
1355
1356 static const struct wl_shell_interface shell_implementation = {
1357         shell_get_shell_surface
1358 };
1359
1360 static void
1361 handle_screensaver_sigchld(struct weston_process *proc, int status)
1362 {
1363         proc->pid = 0;
1364 }
1365
1366 static void
1367 launch_screensaver(struct desktop_shell *shell)
1368 {
1369         if (shell->screensaver.binding)
1370                 return;
1371
1372         if (!shell->screensaver.path)
1373                 return;
1374
1375         if (shell->screensaver.process.pid != 0) {
1376                 fprintf(stderr, "old screensaver still running\n");
1377                 return;
1378         }
1379
1380         weston_client_launch(shell->compositor,
1381                            &shell->screensaver.process,
1382                            shell->screensaver.path,
1383                            handle_screensaver_sigchld);
1384 }
1385
1386 static void
1387 terminate_screensaver(struct desktop_shell *shell)
1388 {
1389         if (shell->screensaver.process.pid == 0)
1390                 return;
1391
1392         kill(shell->screensaver.process.pid, SIGTERM);
1393 }
1394
1395 static void
1396 show_screensaver(struct desktop_shell *shell, struct shell_surface *surface)
1397 {
1398         struct wl_list *list;
1399
1400         if (shell->lock_surface)
1401                 list = &shell->lock_surface->surface->layer_link;
1402         else
1403                 list = &shell->lock_layer.surface_list;
1404
1405         wl_list_remove(&surface->surface->layer_link);
1406         wl_list_insert(list, &surface->surface->layer_link);
1407         surface->surface->output = surface->output;
1408         weston_surface_damage(surface->surface);
1409 }
1410
1411 static void
1412 hide_screensaver(struct desktop_shell *shell, struct shell_surface *surface)
1413 {
1414         wl_list_remove(&surface->surface->layer_link);
1415         wl_list_init(&surface->surface->layer_link);
1416         surface->surface->output = NULL;
1417 }
1418
1419 static void
1420 desktop_shell_set_background(struct wl_client *client,
1421                              struct wl_resource *resource,
1422                              struct wl_resource *output_resource,
1423                              struct wl_resource *surface_resource)
1424 {
1425         struct shell_surface *shsurf = surface_resource->data;
1426
1427         shsurf->next_type = SHELL_SURFACE_BACKGROUND;
1428         shsurf->output = output_resource->data;
1429
1430         desktop_shell_send_configure(resource, 0,
1431                                      surface_resource,
1432                                      shsurf->output->current->width,
1433                                      shsurf->output->current->height);
1434 }
1435
1436 static void
1437 desktop_shell_set_panel(struct wl_client *client,
1438                         struct wl_resource *resource,
1439                         struct wl_resource *output_resource,
1440                         struct wl_resource *surface_resource)
1441 {
1442         struct shell_surface *shsurf = surface_resource->data;
1443
1444         shsurf->next_type = SHELL_SURFACE_PANEL;
1445         shsurf->output = output_resource->data;
1446
1447         desktop_shell_send_configure(resource, 0,
1448                                      surface_resource,
1449                                      shsurf->output->current->width,
1450                                      shsurf->output->current->height);
1451 }
1452
1453 static void
1454 handle_lock_surface_destroy(struct wl_listener *listener, void *data)
1455 {
1456         struct desktop_shell *shell =
1457             container_of(listener, struct desktop_shell, lock_surface_listener);
1458
1459         fprintf(stderr, "lock surface gone\n");
1460         shell->lock_surface = NULL;
1461 }
1462
1463 static void
1464 desktop_shell_set_lock_surface(struct wl_client *client,
1465                                struct wl_resource *resource,
1466                                struct wl_resource *surface_resource)
1467 {
1468         struct desktop_shell *shell = resource->data;
1469         struct shell_surface *surface = surface_resource->data;
1470
1471         shell->prepare_event_sent = false;
1472
1473         if (!shell->locked)
1474                 return;
1475
1476         shell->lock_surface = surface;
1477
1478         shell->lock_surface_listener.notify = handle_lock_surface_destroy;
1479         wl_signal_add(&surface_resource->destroy_signal,
1480                       &shell->lock_surface_listener);
1481
1482         shell->lock_surface->next_type = SHELL_SURFACE_LOCK;
1483 }
1484
1485 static void
1486 resume_desktop(struct desktop_shell *shell)
1487 {
1488         struct shell_surface *tmp;
1489
1490         wl_list_for_each(tmp, &shell->screensaver.surfaces, link)
1491                 hide_screensaver(shell, tmp);
1492
1493         terminate_screensaver(shell);
1494
1495         wl_list_remove(&shell->lock_layer.link);
1496         wl_list_insert(&shell->compositor->cursor_layer.link,
1497                        &shell->fullscreen_layer.link);
1498         wl_list_insert(&shell->fullscreen_layer.link,
1499                        &shell->panel_layer.link);
1500         wl_list_insert(&shell->panel_layer.link, &shell->toplevel_layer.link);
1501
1502         shell->locked = false;
1503         shell->compositor->idle_time = shell->compositor->option_idle_time;
1504         weston_compositor_wake(shell->compositor);
1505         weston_compositor_damage_all(shell->compositor);
1506 }
1507
1508 static void
1509 desktop_shell_unlock(struct wl_client *client,
1510                      struct wl_resource *resource)
1511 {
1512         struct desktop_shell *shell = resource->data;
1513
1514         shell->prepare_event_sent = false;
1515
1516         if (shell->locked)
1517                 resume_desktop(shell);
1518 }
1519
1520 static const struct desktop_shell_interface desktop_shell_implementation = {
1521         desktop_shell_set_background,
1522         desktop_shell_set_panel,
1523         desktop_shell_set_lock_surface,
1524         desktop_shell_unlock
1525 };
1526
1527 static enum shell_surface_type
1528 get_shell_surface_type(struct weston_surface *surface)
1529 {
1530         struct shell_surface *shsurf;
1531
1532         shsurf = get_shell_surface(surface);
1533         if (!shsurf)
1534                 return SHELL_SURFACE_NONE;
1535         return shsurf->type;
1536 }
1537
1538 static void
1539 move_binding(struct wl_seat *seat, uint32_t time,
1540              uint32_t key, uint32_t button, uint32_t axis, int32_t value,
1541              void *data)
1542 {
1543         struct weston_surface *surface =
1544                 (struct weston_surface *) seat->pointer->focus;
1545         struct shell_surface *shsurf;
1546
1547         if (surface == NULL)
1548                 return;
1549
1550         shsurf = get_shell_surface(surface);
1551         if (shsurf == NULL)
1552                 return;
1553
1554         switch (shsurf->type) {
1555                 case SHELL_SURFACE_PANEL:
1556                 case SHELL_SURFACE_BACKGROUND:
1557                 case SHELL_SURFACE_FULLSCREEN:
1558                 case SHELL_SURFACE_SCREENSAVER:
1559                         return;
1560                 default:
1561                         break;
1562         }
1563
1564         surface_move(shsurf, (struct weston_seat *) seat);
1565 }
1566
1567 static void
1568 resize_binding(struct wl_seat *seat, uint32_t time,
1569                uint32_t key, uint32_t button, uint32_t axis, int32_t value,
1570                void *data)
1571 {
1572         struct weston_surface *surface =
1573                 (struct weston_surface *) seat->pointer->focus;
1574         uint32_t edges = 0;
1575         int32_t x, y;
1576         struct shell_surface *shsurf;
1577
1578         if (surface == NULL)
1579                 return;
1580
1581         shsurf = get_shell_surface(surface);
1582         if (!shsurf)
1583                 return;
1584
1585         switch (shsurf->type) {
1586                 case SHELL_SURFACE_PANEL:
1587                 case SHELL_SURFACE_BACKGROUND:
1588                 case SHELL_SURFACE_FULLSCREEN:
1589                 case SHELL_SURFACE_SCREENSAVER:
1590                         return;
1591                 default:
1592                         break;
1593         }
1594
1595         weston_surface_from_global(surface,
1596                                    wl_fixed_to_int(seat->pointer->grab_x),
1597                                    wl_fixed_to_int(seat->pointer->grab_y),
1598                                    &x, &y);
1599
1600         if (x < surface->geometry.width / 3)
1601                 edges |= WL_SHELL_SURFACE_RESIZE_LEFT;
1602         else if (x < 2 * surface->geometry.width / 3)
1603                 edges |= 0;
1604         else
1605                 edges |= WL_SHELL_SURFACE_RESIZE_RIGHT;
1606
1607         if (y < surface->geometry.height / 3)
1608                 edges |= WL_SHELL_SURFACE_RESIZE_TOP;
1609         else if (y < 2 * surface->geometry.height / 3)
1610                 edges |= 0;
1611         else
1612                 edges |= WL_SHELL_SURFACE_RESIZE_BOTTOM;
1613
1614         surface_resize(shsurf, (struct weston_seat *) seat, edges);
1615 }
1616
1617 static void
1618 surface_opacity_binding(struct wl_seat *seat, uint32_t time,
1619                         uint32_t key, uint32_t button, uint32_t axis,
1620                         int32_t value, void *data)
1621 {
1622         float step = 0.05;
1623         struct shell_surface *shsurf;
1624         struct weston_surface *surface =
1625                 (struct weston_surface *) seat->pointer->focus;
1626
1627         if (surface == NULL)
1628                 return;
1629
1630         shsurf = get_shell_surface(surface);
1631         if (!shsurf)
1632                 return;
1633
1634         switch (shsurf->type) {
1635                 case SHELL_SURFACE_BACKGROUND:
1636                 case SHELL_SURFACE_SCREENSAVER:
1637                         return;
1638                 default:
1639                         break;
1640         }
1641
1642         surface->alpha += value * step;
1643
1644         if (surface->alpha > 1.0)
1645                 surface->alpha = 1.0;
1646         if (surface->alpha < step)
1647                 surface->alpha = step;
1648
1649         surface->geometry.dirty = 1;
1650         weston_surface_damage(surface);
1651 }
1652
1653 static void
1654 zoom_binding(struct wl_seat *seat, uint32_t time,
1655              uint32_t key, uint32_t button, uint32_t axis, int32_t value,
1656              void *data)
1657 {
1658         struct weston_seat *ws = (struct weston_seat *) seat;
1659         struct weston_compositor *compositor = ws->compositor;
1660         struct weston_output *output;
1661         float maximum_level, increment;
1662
1663         wl_list_for_each(output, &compositor->output_list, link) {
1664                 if (pixman_region32_contains_point(&output->region,
1665                                                    wl_fixed_to_double(seat->pointer->x),
1666                                                    wl_fixed_to_double(seat->pointer->y),
1667                                                    NULL)) {
1668                         if (key == KEY_PAGEUP && value)
1669                                 increment = output->zoom.increment;
1670                         else if (key == KEY_PAGEDOWN && value)
1671                                 increment = -output->zoom.increment;
1672                         else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
1673                                 increment = output->zoom.increment * value;
1674                         else
1675                                 increment = 0;
1676
1677                         output->zoom.active = 1;
1678                         output->zoom.level += increment;
1679
1680                         if (output->zoom.level <= 0.0) {
1681                                 output->zoom.active = 0;
1682                                 output->zoom.level = 0.0;
1683                         }
1684
1685                         maximum_level = 1 - output->zoom.increment;
1686
1687                         if (output->zoom.level > maximum_level)
1688                                 output->zoom.level = maximum_level;
1689
1690                         weston_output_update_zoom(output,
1691                                                   seat->pointer->x,
1692                                                   seat->pointer->y,
1693                                                   ZOOM_POINTER);
1694                 }
1695         }
1696 }
1697
1698 static void
1699 terminate_binding(struct wl_seat *seat, uint32_t time,
1700                   uint32_t key, uint32_t button, uint32_t axis, int32_t state, void *data)
1701 {
1702         struct weston_compositor *compositor = data;
1703
1704         if (state)
1705                 wl_display_terminate(compositor->wl_display);
1706 }
1707
1708 static void
1709 rotate_grab_motion(struct wl_pointer_grab *grab,
1710                    uint32_t time, wl_fixed_t x, wl_fixed_t y)
1711 {
1712         struct rotate_grab *rotate =
1713                 container_of(grab, struct rotate_grab, base.grab);
1714         struct wl_pointer *pointer = grab->pointer;
1715         struct shell_surface *shsurf = rotate->base.shsurf;
1716         struct weston_surface *surface;
1717         GLfloat cx, cy, dx, dy, cposx, cposy, dposx, dposy, r;
1718
1719         if (!shsurf)
1720                 return;
1721
1722         surface = shsurf->surface;
1723
1724         cx = 0.5f * surface->geometry.width;
1725         cy = 0.5f * surface->geometry.height;
1726
1727         dx = wl_fixed_to_double(pointer->x) - rotate->center.x;
1728         dy = wl_fixed_to_double(pointer->y) - rotate->center.y;
1729         r = sqrtf(dx * dx + dy * dy);
1730
1731         wl_list_remove(&shsurf->rotation.transform.link);
1732         shsurf->surface->geometry.dirty = 1;
1733
1734         if (r > 20.0f) {
1735                 struct weston_matrix *matrix =
1736                         &shsurf->rotation.transform.matrix;
1737
1738                 weston_matrix_init(&rotate->rotation);
1739                 rotate->rotation.d[0] = dx / r;
1740                 rotate->rotation.d[4] = -dy / r;
1741                 rotate->rotation.d[1] = -rotate->rotation.d[4];
1742                 rotate->rotation.d[5] = rotate->rotation.d[0];
1743
1744                 weston_matrix_init(matrix);
1745                 weston_matrix_translate(matrix, -cx, -cy, 0.0f);
1746                 weston_matrix_multiply(matrix, &shsurf->rotation.rotation);
1747                 weston_matrix_multiply(matrix, &rotate->rotation);
1748                 weston_matrix_translate(matrix, cx, cy, 0.0f);
1749
1750                 wl_list_insert(
1751                         &shsurf->surface->geometry.transformation_list,
1752                         &shsurf->rotation.transform.link);
1753         } else {
1754                 wl_list_init(&shsurf->rotation.transform.link);
1755                 weston_matrix_init(&shsurf->rotation.rotation);
1756                 weston_matrix_init(&rotate->rotation);
1757         }
1758
1759         /* We need to adjust the position of the surface
1760          * in case it was resized in a rotated state before */
1761         cposx = surface->geometry.x + cx;
1762         cposy = surface->geometry.y + cy;
1763         dposx = rotate->center.x - cposx;
1764         dposy = rotate->center.y - cposy;
1765         if (dposx != 0.0f || dposy != 0.0f) {
1766                 weston_surface_set_position(surface,
1767                                             surface->geometry.x + dposx,
1768                                             surface->geometry.y + dposy);
1769         }
1770
1771         /* Repaint implies weston_surface_update_transform(), which
1772          * lazily applies the damage due to rotation update.
1773          */
1774         weston_compositor_schedule_repaint(shsurf->surface->compositor);
1775 }
1776
1777 static void
1778 rotate_grab_button(struct wl_pointer_grab *grab,
1779                  uint32_t time, uint32_t button, uint32_t state)
1780 {
1781         struct rotate_grab *rotate =
1782                 container_of(grab, struct rotate_grab, base.grab);
1783         struct wl_pointer *pointer = grab->pointer;
1784         struct shell_surface *shsurf = rotate->base.shsurf;
1785
1786         if (pointer->button_count == 0 && state == 0) {
1787                 if (shsurf)
1788                         weston_matrix_multiply(&shsurf->rotation.rotation,
1789                                                &rotate->rotation);
1790                 shell_grab_finish(&rotate->base);
1791                 wl_pointer_end_grab(pointer);
1792                 free(rotate);
1793         }
1794 }
1795
1796 static const struct wl_pointer_grab_interface rotate_grab_interface = {
1797         noop_grab_focus,
1798         rotate_grab_motion,
1799         rotate_grab_button,
1800 };
1801
1802 static void
1803 rotate_binding(struct wl_seat *seat, uint32_t time,
1804                uint32_t key, uint32_t button, uint32_t axis, int32_t value,
1805                void *data)
1806 {
1807         struct weston_surface *base_surface =
1808                 (struct weston_surface *) seat->pointer->focus;
1809         struct shell_surface *surface;
1810         struct rotate_grab *rotate;
1811         GLfloat dx, dy;
1812         GLfloat r;
1813
1814         if (base_surface == NULL)
1815                 return;
1816
1817         surface = get_shell_surface(base_surface);
1818         if (!surface)
1819                 return;
1820
1821         switch (surface->type) {
1822                 case SHELL_SURFACE_PANEL:
1823                 case SHELL_SURFACE_BACKGROUND:
1824                 case SHELL_SURFACE_FULLSCREEN:
1825                 case SHELL_SURFACE_SCREENSAVER:
1826                         return;
1827                 default:
1828                         break;
1829         }
1830
1831         rotate = malloc(sizeof *rotate);
1832         if (!rotate)
1833                 return;
1834
1835         shell_grab_init(&rotate->base, &rotate_grab_interface, surface);
1836
1837         weston_surface_to_global(surface->surface,
1838                                  surface->surface->geometry.width / 2,
1839                                  surface->surface->geometry.height / 2,
1840                                  &rotate->center.x, &rotate->center.y);
1841
1842         wl_pointer_start_grab(seat->pointer, &rotate->base.grab);
1843
1844         dx = wl_fixed_to_double(seat->pointer->x) - rotate->center.x;
1845         dy = wl_fixed_to_double(seat->pointer->y) - rotate->center.y;
1846         r = sqrtf(dx * dx + dy * dy);
1847         if (r > 20.0f) {
1848                 struct weston_matrix inverse;
1849
1850                 weston_matrix_init(&inverse);
1851                 inverse.d[0] = dx / r;
1852                 inverse.d[4] = dy / r;
1853                 inverse.d[1] = -inverse.d[4];
1854                 inverse.d[5] = inverse.d[0];
1855                 weston_matrix_multiply(&surface->rotation.rotation, &inverse);
1856
1857                 weston_matrix_init(&rotate->rotation);
1858                 rotate->rotation.d[0] = dx / r;
1859                 rotate->rotation.d[4] = -dy / r;
1860                 rotate->rotation.d[1] = -rotate->rotation.d[4];
1861                 rotate->rotation.d[5] = rotate->rotation.d[0];
1862         } else {
1863                 weston_matrix_init(&surface->rotation.rotation);
1864                 weston_matrix_init(&rotate->rotation);
1865         }
1866
1867         wl_pointer_set_focus(seat->pointer, NULL,
1868                              wl_fixed_from_int(0),
1869                              wl_fixed_from_int(0));
1870 }
1871
1872 static void
1873 activate(struct desktop_shell *shell, struct weston_surface *es,
1874          struct weston_seat *seat)
1875 {
1876         struct weston_surface *surf, *prev;
1877
1878         weston_surface_activate(es, seat);
1879
1880         switch (get_shell_surface_type(es)) {
1881         case SHELL_SURFACE_BACKGROUND:
1882         case SHELL_SURFACE_PANEL:
1883         case SHELL_SURFACE_LOCK:
1884                 break;
1885
1886         case SHELL_SURFACE_SCREENSAVER:
1887                 /* always below lock surface */
1888                 if (shell->lock_surface)
1889                         weston_surface_restack(es,
1890                                                &shell->lock_surface->surface->layer_link);
1891                 break;
1892         case SHELL_SURFACE_FULLSCREEN:
1893                 /* should on top of panels */
1894                 shell_stack_fullscreen(get_shell_surface(es));
1895                 shell_configure_fullscreen(get_shell_surface(es));
1896                 break;
1897         default:
1898                 /* move the fullscreen surfaces down into the toplevel layer */
1899                 if (!wl_list_empty(&shell->fullscreen_layer.surface_list)) {
1900                         wl_list_for_each_reverse_safe(surf,
1901                                                       prev, 
1902                                                       &shell->fullscreen_layer.surface_list, 
1903                                                       layer_link)
1904                                 weston_surface_restack(surf,
1905                                                        &shell->toplevel_layer.surface_list); 
1906                 }
1907
1908                 weston_surface_restack(es,
1909                                        &shell->toplevel_layer.surface_list);
1910                 break;
1911         }
1912 }
1913
1914 /* no-op func for checking black surface */
1915 static void
1916 black_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
1917 {
1918 }
1919
1920 static bool 
1921 is_black_surface (struct weston_surface *es, struct weston_surface **fs_surface)
1922 {
1923         if (es->configure == black_surface_configure) {
1924                 if (fs_surface)
1925                         *fs_surface = (struct weston_surface *)es->private;
1926                 return true;
1927         }
1928         return false;
1929 }
1930
1931 static void
1932 click_to_activate_binding(struct wl_seat *seat,
1933                           uint32_t time, uint32_t key,
1934                           uint32_t button, uint32_t axis, int32_t state, void *data)
1935 {
1936         struct weston_seat *ws = (struct weston_seat *) seat;
1937         struct desktop_shell *shell = data;
1938         struct weston_surface *focus;
1939         struct weston_surface *upper;
1940
1941         focus = (struct weston_surface *) seat->pointer->focus;
1942         if (!focus)
1943                 return;
1944
1945         if (is_black_surface(focus, &upper))
1946                 focus = upper;
1947
1948         if (state && seat->pointer->grab == &seat->pointer->default_grab)
1949                 activate(shell, focus, ws);
1950 }
1951
1952 static void
1953 lock(struct wl_listener *listener, void *data)
1954 {
1955         struct desktop_shell *shell =
1956                 container_of(listener, struct desktop_shell, lock_listener);
1957         struct weston_seat *seat;
1958         struct shell_surface *shsurf;
1959         struct weston_output *output;
1960
1961         if (shell->locked) {
1962                 wl_list_for_each(output, &shell->compositor->output_list, link)
1963                         /* TODO: find a way to jump to other DPMS levels */
1964                         if (output->set_dpms)
1965                                 output->set_dpms(output, WESTON_DPMS_STANDBY);
1966                 return;
1967         }
1968
1969         shell->locked = true;
1970
1971         /* Hide all surfaces by removing the fullscreen, panel and
1972          * toplevel layers.  This way nothing else can show or receive
1973          * input events while we are locked. */
1974
1975         wl_list_remove(&shell->panel_layer.link);
1976         wl_list_remove(&shell->toplevel_layer.link);
1977         wl_list_remove(&shell->fullscreen_layer.link);
1978         wl_list_insert(&shell->compositor->cursor_layer.link,
1979                        &shell->lock_layer.link);
1980
1981         launch_screensaver(shell);
1982
1983         wl_list_for_each(shsurf, &shell->screensaver.surfaces, link)
1984                 show_screensaver(shell, shsurf);
1985
1986         if (!wl_list_empty(&shell->screensaver.surfaces)) {
1987                 shell->compositor->idle_time = shell->screensaver.duration;
1988                 weston_compositor_wake(shell->compositor);
1989                 shell->compositor->state = WESTON_COMPOSITOR_IDLE;
1990         }
1991
1992         /* reset pointer foci */
1993         weston_compositor_schedule_repaint(shell->compositor);
1994
1995         /* reset keyboard foci */
1996         wl_list_for_each(seat, &shell->compositor->seat_list, link) {
1997                 wl_keyboard_set_focus(seat->seat.keyboard, NULL);
1998         }
1999
2000         /* TODO: disable bindings that should not work while locked. */
2001
2002         /* All this must be undone in resume_desktop(). */
2003 }
2004
2005 static void
2006 unlock(struct wl_listener *listener, void *data)
2007 {
2008         struct desktop_shell *shell =
2009                 container_of(listener, struct desktop_shell, unlock_listener);
2010
2011         if (!shell->locked || shell->lock_surface) {
2012                 weston_compositor_wake(shell->compositor);
2013                 return;
2014         }
2015
2016         /* If desktop-shell client has gone away, unlock immediately. */
2017         if (!shell->child.desktop_shell) {
2018                 resume_desktop(shell);
2019                 return;
2020         }
2021
2022         if (shell->prepare_event_sent)
2023                 return;
2024
2025         desktop_shell_send_prepare_lock_surface(shell->child.desktop_shell);
2026         shell->prepare_event_sent = true;
2027 }
2028
2029 static void
2030 center_on_output(struct weston_surface *surface, struct weston_output *output)
2031 {
2032         struct weston_mode *mode = output->current;
2033         GLfloat x = (mode->width - surface->geometry.width) / 2;
2034         GLfloat y = (mode->height - surface->geometry.height) / 2;
2035
2036         weston_surface_set_position(surface, output->x + x, output->y + y);
2037 }
2038
2039 static void
2040 map(struct desktop_shell *shell, struct weston_surface *surface,
2041     int32_t width, int32_t height, int32_t sx, int32_t sy)
2042 {
2043         struct weston_compositor *compositor = shell->compositor;
2044         struct shell_surface *shsurf;
2045         enum shell_surface_type surface_type = SHELL_SURFACE_NONE;
2046         struct weston_surface *parent;
2047         int panel_height = 0;
2048
2049         shsurf = get_shell_surface(surface);
2050         if (shsurf)
2051                 surface_type = shsurf->type;
2052
2053         surface->geometry.width = width;
2054         surface->geometry.height = height;
2055         surface->geometry.dirty = 1;
2056
2057         /* initial positioning, see also configure() */
2058         switch (surface_type) {
2059         case SHELL_SURFACE_TOPLEVEL:
2060                 weston_surface_set_position(surface, 10 + random() % 400,
2061                                             10 + random() % 400);
2062                 break;
2063         case SHELL_SURFACE_SCREENSAVER:
2064                 center_on_output(surface, shsurf->fullscreen_output);
2065                 break;
2066         case SHELL_SURFACE_FULLSCREEN:
2067                 shell_map_fullscreen(shsurf);
2068                 break;
2069         case SHELL_SURFACE_MAXIMIZED:
2070                 /* use surface configure to set the geometry */
2071                 panel_height = get_output_panel_height(shell,surface->output);
2072                 weston_surface_set_position(surface, surface->output->x,
2073                                             surface->output->y + panel_height);
2074                 break;
2075         case SHELL_SURFACE_LOCK:
2076                 center_on_output(surface, get_default_output(compositor));
2077                 break;
2078         case SHELL_SURFACE_POPUP:
2079                 shell_map_popup(shsurf);
2080         case SHELL_SURFACE_NONE:
2081                 weston_surface_set_position(surface,
2082                                             surface->geometry.x + sx,
2083                                             surface->geometry.y + sy);
2084                 break;
2085         default:
2086                 ;
2087         }
2088
2089         /* surface stacking order, see also activate() */
2090         switch (surface_type) {
2091         case SHELL_SURFACE_BACKGROUND:
2092                 /* background always visible, at the bottom */
2093                 wl_list_insert(&shell->background_layer.surface_list,
2094                                &surface->layer_link);
2095                 break;
2096         case SHELL_SURFACE_PANEL:
2097                 /* panel always on top, hidden while locked */
2098                 wl_list_insert(&shell->panel_layer.surface_list,
2099                                &surface->layer_link);
2100                 break;
2101         case SHELL_SURFACE_LOCK:
2102                 /* lock surface always visible, on top */
2103                 wl_list_insert(&shell->lock_layer.surface_list,
2104                                &surface->layer_link);
2105                 weston_compositor_wake(compositor);
2106                 break;
2107         case SHELL_SURFACE_SCREENSAVER:
2108                 /* If locked, show it. */
2109                 if (shell->locked) {
2110                         show_screensaver(shell, shsurf);
2111                         compositor->idle_time = shell->screensaver.duration;
2112                         weston_compositor_wake(compositor);
2113                         if (!shell->lock_surface)
2114                                 compositor->state = WESTON_COMPOSITOR_IDLE;
2115                 }
2116                 break;
2117         case SHELL_SURFACE_POPUP:
2118         case SHELL_SURFACE_TRANSIENT:
2119                 parent = shsurf->parent->surface;
2120                 wl_list_insert(parent->layer_link.prev, &surface->layer_link);
2121                 break;
2122         case SHELL_SURFACE_FULLSCREEN:
2123         case SHELL_SURFACE_NONE:
2124                 break;
2125         default:
2126                 wl_list_insert(&shell->toplevel_layer.surface_list,
2127                                &surface->layer_link); 
2128                 break;
2129         }
2130
2131         if (surface_type != SHELL_SURFACE_NONE) {
2132                 weston_surface_assign_output(surface);
2133                 if (surface_type == SHELL_SURFACE_MAXIMIZED)
2134                         surface->output = shsurf->output;
2135         }
2136
2137         switch (surface_type) {
2138         case SHELL_SURFACE_TRANSIENT:
2139                 if (shsurf->transient.flags ==
2140                                 WL_SHELL_SURFACE_TRANSIENT_INACTIVE)
2141                         break;
2142         case SHELL_SURFACE_TOPLEVEL:
2143         case SHELL_SURFACE_FULLSCREEN:
2144         case SHELL_SURFACE_MAXIMIZED:
2145                 if (!shell->locked)
2146                         activate(shell, surface,
2147                                  (struct weston_seat *) compositor->seat);
2148                 break;
2149         default:
2150                 break;
2151         }
2152
2153         if (surface_type == SHELL_SURFACE_TOPLEVEL)
2154         {
2155                 switch (shell->win_animation_type) {
2156                 case ANIMATION_FADE:
2157                         weston_fade_run(surface, NULL, NULL);
2158                         break;
2159                 case ANIMATION_ZOOM:
2160                         weston_zoom_run(surface, 0.8, 1.0, NULL, NULL);
2161                         break;
2162                 default:
2163                         break;
2164                 }
2165         }
2166 }
2167
2168 static void
2169 configure(struct desktop_shell *shell, struct weston_surface *surface,
2170           GLfloat x, GLfloat y, int32_t width, int32_t height)
2171 {
2172         enum shell_surface_type surface_type = SHELL_SURFACE_NONE;
2173         struct shell_surface *shsurf;
2174
2175         shsurf = get_shell_surface(surface);
2176         if (shsurf)
2177                 surface_type = shsurf->type;
2178
2179         surface->geometry.x = x;
2180         surface->geometry.y = y;
2181         surface->geometry.width = width;
2182         surface->geometry.height = height;
2183         surface->geometry.dirty = 1;
2184
2185         switch (surface_type) {
2186         case SHELL_SURFACE_SCREENSAVER:
2187                 center_on_output(surface, shsurf->fullscreen_output);
2188                 break;
2189         case SHELL_SURFACE_FULLSCREEN:
2190                 shell_stack_fullscreen(shsurf);
2191                 shell_configure_fullscreen(shsurf);
2192                 break;
2193         case SHELL_SURFACE_MAXIMIZED:
2194                 /* setting x, y and using configure to change that geometry */
2195                 surface->geometry.x = surface->output->x;
2196                 surface->geometry.y = surface->output->y +
2197                         get_output_panel_height(shell,surface->output);
2198                 break;
2199         case SHELL_SURFACE_TOPLEVEL:
2200                 break;
2201         default:
2202                 break;
2203         }
2204
2205         /* XXX: would a fullscreen surface need the same handling? */
2206         if (surface->output) {
2207                 weston_surface_assign_output(surface);
2208
2209                 if (surface_type == SHELL_SURFACE_SCREENSAVER)
2210                         surface->output = shsurf->output;
2211                 else if (surface_type == SHELL_SURFACE_MAXIMIZED)
2212                         surface->output = shsurf->output;
2213         }
2214 }
2215
2216 static void
2217 shell_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
2218 {
2219         struct shell_surface *shsurf = get_shell_surface(es);
2220         struct desktop_shell *shell = shsurf->shell;
2221         int type_changed = 0;
2222
2223         if (shsurf->next_type != SHELL_SURFACE_NONE &&
2224             shsurf->type != shsurf->next_type) {
2225                 set_surface_type(shsurf);
2226                 type_changed = 1;
2227         }
2228
2229         if (!weston_surface_is_mapped(es)) {
2230                 map(shell, es, es->buffer->width, es->buffer->height, sx, sy);
2231         } else if (type_changed || sx != 0 || sy != 0 ||
2232                    es->geometry.width != es->buffer->width ||
2233                    es->geometry.height != es->buffer->height) {
2234                 GLfloat from_x, from_y;
2235                 GLfloat to_x, to_y;
2236
2237                 weston_surface_to_global_float(es, 0, 0, &from_x, &from_y);
2238                 weston_surface_to_global_float(es, sx, sy, &to_x, &to_y);
2239                 configure(shell, es,
2240                           es->geometry.x + to_x - from_x,
2241                           es->geometry.y + to_y - from_y,
2242                           es->buffer->width, es->buffer->height);
2243         }
2244 }
2245
2246 static int launch_desktop_shell_process(struct desktop_shell *shell);
2247
2248 static void
2249 desktop_shell_sigchld(struct weston_process *process, int status)
2250 {
2251         uint32_t time;
2252         struct desktop_shell *shell =
2253                 container_of(process, struct desktop_shell, child.process);
2254
2255         shell->child.process.pid = 0;
2256         shell->child.client = NULL; /* already destroyed by wayland */
2257
2258         /* if desktop-shell dies more than 5 times in 30 seconds, give up */
2259         time = weston_compositor_get_time();
2260         if (time - shell->child.deathstamp > 30000) {
2261                 shell->child.deathstamp = time;
2262                 shell->child.deathcount = 0;
2263         }
2264
2265         shell->child.deathcount++;
2266         if (shell->child.deathcount > 5) {
2267                 fprintf(stderr, "weston-desktop-shell died, giving up.\n");
2268                 return;
2269         }
2270
2271         fprintf(stderr, "weston-desktop-shell died, respawning...\n");
2272         launch_desktop_shell_process(shell);
2273 }
2274
2275 static int
2276 launch_desktop_shell_process(struct desktop_shell *shell)
2277 {
2278         const char *shell_exe = LIBEXECDIR "/weston-desktop-shell";
2279
2280         shell->child.client = weston_client_launch(shell->compositor,
2281                                                  &shell->child.process,
2282                                                  shell_exe,
2283                                                  desktop_shell_sigchld);
2284
2285         if (!shell->child.client)
2286                 return -1;
2287         return 0;
2288 }
2289
2290 static void
2291 bind_shell(struct wl_client *client, void *data, uint32_t version, uint32_t id)
2292 {
2293         struct desktop_shell *shell = data;
2294
2295         wl_client_add_object(client, &wl_shell_interface,
2296                              &shell_implementation, id, shell);
2297 }
2298
2299 static void
2300 unbind_desktop_shell(struct wl_resource *resource)
2301 {
2302         struct desktop_shell *shell = resource->data;
2303
2304         if (shell->locked)
2305                 resume_desktop(shell);
2306
2307         shell->child.desktop_shell = NULL;
2308         shell->prepare_event_sent = false;
2309         free(resource);
2310 }
2311
2312 static void
2313 bind_desktop_shell(struct wl_client *client,
2314                    void *data, uint32_t version, uint32_t id)
2315 {
2316         struct desktop_shell *shell = data;
2317         struct wl_resource *resource;
2318
2319         resource = wl_client_add_object(client, &desktop_shell_interface,
2320                                         &desktop_shell_implementation,
2321                                         id, shell);
2322
2323         if (client == shell->child.client) {
2324                 resource->destroy = unbind_desktop_shell;
2325                 shell->child.desktop_shell = resource;
2326                 return;
2327         }
2328
2329         wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
2330                                "permission to bind desktop_shell denied");
2331         wl_resource_destroy(resource);
2332 }
2333
2334 static void
2335 screensaver_set_surface(struct wl_client *client,
2336                         struct wl_resource *resource,
2337                         struct wl_resource *shell_surface_resource,
2338                         struct wl_resource *output_resource)
2339 {
2340         struct desktop_shell *shell = resource->data;
2341         struct shell_surface *surface = shell_surface_resource->data;
2342         struct weston_output *output = output_resource->data;
2343
2344         surface->next_type = SHELL_SURFACE_SCREENSAVER;
2345
2346         surface->fullscreen_output = output;
2347         surface->output = output;
2348         wl_list_insert(shell->screensaver.surfaces.prev, &surface->link);
2349 }
2350
2351 static const struct screensaver_interface screensaver_implementation = {
2352         screensaver_set_surface
2353 };
2354
2355 static void
2356 unbind_screensaver(struct wl_resource *resource)
2357 {
2358         struct desktop_shell *shell = resource->data;
2359
2360         shell->screensaver.binding = NULL;
2361         free(resource);
2362 }
2363
2364 static void
2365 bind_screensaver(struct wl_client *client,
2366                  void *data, uint32_t version, uint32_t id)
2367 {
2368         struct desktop_shell *shell = data;
2369         struct wl_resource *resource;
2370
2371         resource = wl_client_add_object(client, &screensaver_interface,
2372                                         &screensaver_implementation,
2373                                         id, shell);
2374
2375         if (shell->screensaver.binding == NULL) {
2376                 resource->destroy = unbind_screensaver;
2377                 shell->screensaver.binding = resource;
2378                 return;
2379         }
2380
2381         wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
2382                                "interface object already bound");
2383         wl_resource_destroy(resource);
2384 }
2385
2386 struct switcher {
2387         struct desktop_shell *shell;
2388         struct weston_surface *current;
2389         struct wl_listener listener;
2390         struct wl_keyboard_grab grab;
2391 };
2392
2393 static void
2394 switcher_next(struct switcher *switcher)
2395 {
2396         struct weston_compositor *compositor = switcher->shell->compositor;
2397         struct weston_surface *surface;
2398         struct weston_surface *first = NULL, *prev = NULL, *next = NULL;
2399         struct shell_surface *shsurf;
2400
2401         wl_list_for_each(surface, &compositor->surface_list, link) {
2402                 switch (get_shell_surface_type(surface)) {
2403                 case SHELL_SURFACE_TOPLEVEL:
2404                 case SHELL_SURFACE_FULLSCREEN:
2405                 case SHELL_SURFACE_MAXIMIZED:
2406                         if (first == NULL)
2407                                 first = surface;
2408                         if (prev == switcher->current)
2409                                 next = surface;
2410                         prev = surface;
2411                         surface->alpha = 0.25;
2412                         surface->geometry.dirty = 1;
2413                         weston_surface_damage(surface);
2414                         break;
2415                 default:
2416                         break;
2417                 }
2418
2419                 if (is_black_surface(surface, NULL)) {
2420                         surface->alpha = 0.25;
2421                         surface->geometry.dirty = 1;
2422                         weston_surface_damage(surface);
2423                 }
2424         }
2425
2426         if (next == NULL)
2427                 next = first;
2428
2429         if (next == NULL)
2430                 return;
2431
2432         wl_list_remove(&switcher->listener.link);
2433         wl_signal_add(&next->surface.resource.destroy_signal,
2434                       &switcher->listener);
2435
2436         switcher->current = next;
2437         next->alpha = 1.0;
2438
2439         shsurf = get_shell_surface(switcher->current);
2440         if (shsurf && shsurf->type ==SHELL_SURFACE_FULLSCREEN)
2441                 shsurf->fullscreen.black_surface->alpha = 1.0;
2442 }
2443
2444 static void
2445 switcher_handle_surface_destroy(struct wl_listener *listener, void *data)
2446 {
2447         struct switcher *switcher =
2448                 container_of(listener, struct switcher, listener);
2449
2450         switcher_next(switcher);
2451 }
2452
2453 static void
2454 switcher_destroy(struct switcher *switcher, uint32_t time)
2455 {
2456         struct weston_compositor *compositor = switcher->shell->compositor;
2457         struct weston_surface *surface;
2458         struct wl_keyboard *keyboard = switcher->grab.keyboard;
2459
2460         wl_list_for_each(surface, &compositor->surface_list, link) {
2461                 surface->alpha = 1.0;
2462                 weston_surface_damage(surface);
2463         }
2464
2465         if (switcher->current)
2466                 activate(switcher->shell, switcher->current,
2467                          (struct weston_seat *) keyboard->seat);
2468         wl_list_remove(&switcher->listener.link);
2469         wl_keyboard_end_grab(keyboard);
2470         free(switcher);
2471 }
2472
2473 static void
2474 switcher_key(struct wl_keyboard_grab *grab,
2475              uint32_t time, uint32_t key, uint32_t state)
2476 {
2477         struct switcher *switcher = container_of(grab, struct switcher, grab);
2478         struct weston_seat *seat = (struct weston_seat *) grab->keyboard->seat;
2479
2480         if ((seat->modifier_state & switcher->shell->binding_modifier) == 0) {
2481                 switcher_destroy(switcher, time);
2482         } else if (key == KEY_TAB && state) {
2483                 switcher_next(switcher);
2484         }
2485 }
2486
2487 static const struct wl_keyboard_grab_interface switcher_grab = {
2488         switcher_key
2489 };
2490
2491 static void
2492 switcher_binding(struct wl_seat *seat, uint32_t time,
2493                  uint32_t key, uint32_t button, uint32_t axis,
2494                  int32_t value, void *data)
2495 {
2496         struct desktop_shell *shell = data;
2497         struct switcher *switcher;
2498
2499         switcher = malloc(sizeof *switcher);
2500         switcher->shell = shell;
2501         switcher->current = NULL;
2502         switcher->listener.notify = switcher_handle_surface_destroy;
2503         wl_list_init(&switcher->listener.link);
2504
2505         switcher->grab.interface = &switcher_grab;
2506         wl_keyboard_start_grab(seat->keyboard, &switcher->grab);
2507         wl_keyboard_set_focus(seat->keyboard, NULL);
2508         switcher_next(switcher);
2509 }
2510
2511 static void
2512 backlight_binding(struct wl_seat *seat, uint32_t time,
2513                   uint32_t key, uint32_t button, uint32_t axis, int32_t state, void *data)
2514 {
2515         struct weston_compositor *compositor = data;
2516         struct weston_output *output;
2517         long backlight_new = 0;
2518
2519         /* TODO: we're limiting to simple use cases, where we assume just
2520          * control on the primary display. We'd have to extend later if we
2521          * ever get support for setting backlights on random desktop LCD
2522          * panels though */
2523         output = get_default_output(compositor);
2524         if (!output)
2525                 return;
2526
2527         if (!output->set_backlight)
2528                 return;
2529
2530         if (key == KEY_F9 || key == KEY_BRIGHTNESSDOWN)
2531                 backlight_new = output->backlight_current - 25;
2532         else if (key == KEY_F10 || key == KEY_BRIGHTNESSUP)
2533                 backlight_new = output->backlight_current + 25;
2534
2535         if (backlight_new < 5)
2536                 backlight_new = 5;
2537         if (backlight_new > 255)
2538                 backlight_new = 255;
2539
2540         output->backlight_current = backlight_new;
2541         output->set_backlight(output, output->backlight_current);
2542 }
2543
2544 static void
2545 debug_repaint_binding(struct wl_seat *seat, uint32_t time,
2546                       uint32_t key, uint32_t button, uint32_t axis,
2547                       int32_t value, void *data)
2548 {
2549         struct desktop_shell *shell = data;
2550         struct weston_compositor *compositor = shell->compositor;
2551         struct weston_surface *surface;
2552
2553         if (shell->debug_repaint_surface) {
2554                 weston_surface_destroy(shell->debug_repaint_surface);
2555                 shell->debug_repaint_surface = NULL;
2556         } else {
2557                 surface = weston_surface_create(compositor);
2558                 weston_surface_set_color(surface, 1.0, 0.0, 0.0, 0.2);
2559                 weston_surface_configure(surface, 0, 0, 8192, 8192);
2560                 wl_list_insert(&compositor->fade_layer.surface_list,
2561                                &surface->layer_link);
2562                 weston_surface_assign_output(surface);
2563                 pixman_region32_init(&surface->input);
2564
2565                 /* Here's the dirty little trick that makes the
2566                  * repaint debugging work: we force an
2567                  * update_transform first to update dependent state
2568                  * and clear the geometry.dirty bit.  Then we clear
2569                  * the surface damage so it only gets repainted
2570                  * piecewise as we repaint other things.  */
2571
2572                 weston_surface_update_transform(surface);
2573                 pixman_region32_fini(&surface->damage);
2574                 pixman_region32_init(&surface->damage);
2575                 shell->debug_repaint_surface = surface;
2576         }
2577 }
2578
2579 static void
2580 force_kill_binding(struct wl_seat *seat, uint32_t time,
2581                    uint32_t key, uint32_t button, uint32_t axis,
2582                    int32_t value, void *data)
2583 {
2584         struct wl_client *client;
2585         pid_t pid;
2586         uid_t uid;
2587         gid_t gid;
2588
2589         if (value == 1) {
2590                 client = seat->keyboard->focus->resource.client;
2591                 wl_client_get_credentials(client, &pid, &uid, &gid);
2592
2593                 kill(pid, SIGKILL);
2594         }
2595 }
2596
2597 static void
2598 shell_destroy(struct wl_listener *listener, void *data)
2599 {
2600         struct desktop_shell *shell =
2601                 container_of(listener, struct desktop_shell, destroy_listener);
2602
2603         if (shell->child.client)
2604                 wl_client_destroy(shell->child.client);
2605
2606         wl_list_remove(&shell->lock_listener.link);
2607         wl_list_remove(&shell->unlock_listener.link);
2608
2609         free(shell->screensaver.path);
2610         free(shell);
2611 }
2612
2613 static void
2614 shell_add_bindings(struct weston_compositor *ec, struct desktop_shell *shell)
2615 {
2616         uint32_t mod;
2617
2618         /* fixed bindings */
2619         weston_compositor_add_binding(ec, KEY_BACKSPACE, 0, 0,
2620                                       MODIFIER_CTRL | MODIFIER_ALT,
2621                                       terminate_binding, ec);
2622         weston_compositor_add_binding(ec, 0, BTN_LEFT, 0, 0,
2623                                       click_to_activate_binding, shell);
2624         weston_compositor_add_binding(ec, 0, 0,
2625                                       WL_POINTER_AXIS_VERTICAL_SCROLL,
2626                                       MODIFIER_SUPER | MODIFIER_ALT,
2627                                       surface_opacity_binding, NULL);
2628         weston_compositor_add_binding(ec, 0, 0,
2629                                       WL_POINTER_AXIS_VERTICAL_SCROLL,
2630                                       MODIFIER_SUPER, zoom_binding, NULL);
2631
2632         /* configurable bindings */
2633         mod = shell->binding_modifier;
2634         weston_compositor_add_binding(ec, KEY_PAGEUP, 0, 0, mod,
2635                                       zoom_binding, NULL);
2636         weston_compositor_add_binding(ec, KEY_PAGEDOWN, 0, 0, mod,
2637                                       zoom_binding, NULL);
2638         weston_compositor_add_binding(ec, 0, BTN_LEFT, 0, mod,
2639                                       move_binding, shell);
2640         weston_compositor_add_binding(ec, 0, BTN_MIDDLE, 0, mod,
2641                                       resize_binding, shell);
2642         weston_compositor_add_binding(ec, 0, BTN_RIGHT, 0, mod,
2643                                       rotate_binding, NULL);
2644         weston_compositor_add_binding(ec, KEY_TAB, 0, 0, mod,
2645                                       switcher_binding, shell);
2646         weston_compositor_add_binding(ec, KEY_F9, 0, 0, mod,
2647                                       backlight_binding, ec);
2648         weston_compositor_add_binding(ec, KEY_BRIGHTNESSDOWN, 0, 0, 0,
2649                                       backlight_binding, ec);
2650         weston_compositor_add_binding(ec, KEY_F10, 0, 0, mod,
2651                                       backlight_binding, ec);
2652         weston_compositor_add_binding(ec, KEY_BRIGHTNESSUP, 0, 0, 0,
2653                                       backlight_binding, ec);
2654         weston_compositor_add_binding(ec, KEY_SPACE, 0, 0, mod,
2655                                       debug_repaint_binding, shell);
2656         weston_compositor_add_binding(ec, KEY_K, 0, 0, mod,
2657                                       force_kill_binding, shell);
2658 }
2659
2660 int
2661 shell_init(struct weston_compositor *ec);
2662
2663 WL_EXPORT int
2664 shell_init(struct weston_compositor *ec)
2665 {
2666         struct desktop_shell *shell;
2667
2668         shell = malloc(sizeof *shell);
2669         if (shell == NULL)
2670                 return -1;
2671
2672         memset(shell, 0, sizeof *shell);
2673         shell->compositor = ec;
2674
2675         shell->destroy_listener.notify = shell_destroy;
2676         wl_signal_add(&ec->destroy_signal, &shell->destroy_listener);
2677         shell->lock_listener.notify = lock;
2678         wl_signal_add(&ec->lock_signal, &shell->lock_listener);
2679         shell->unlock_listener.notify = unlock;
2680         wl_signal_add(&ec->unlock_signal, &shell->unlock_listener);
2681         ec->ping_handler = ping_handler;
2682         ec->shell_interface.create_shell_surface = create_shell_surface;
2683         ec->shell_interface.set_toplevel = set_toplevel;
2684         ec->shell_interface.set_transient = set_transient;
2685         ec->shell_interface.move = surface_move;
2686         ec->shell_interface.resize = surface_resize;
2687
2688         wl_list_init(&shell->backgrounds);
2689         wl_list_init(&shell->panels);
2690         wl_list_init(&shell->screensaver.surfaces);
2691
2692         weston_layer_init(&shell->fullscreen_layer, &ec->cursor_layer.link);
2693         weston_layer_init(&shell->panel_layer, &shell->fullscreen_layer.link);
2694         weston_layer_init(&shell->toplevel_layer, &shell->panel_layer.link);
2695         weston_layer_init(&shell->background_layer,
2696                           &shell->toplevel_layer.link);
2697         wl_list_init(&shell->lock_layer.surface_list);
2698
2699         shell_configuration(shell);
2700
2701         if (wl_display_add_global(ec->wl_display, &wl_shell_interface,
2702                                   shell, bind_shell) == NULL)
2703                 return -1;
2704
2705         if (wl_display_add_global(ec->wl_display,
2706                                   &desktop_shell_interface,
2707                                   shell, bind_desktop_shell) == NULL)
2708                 return -1;
2709
2710         if (wl_display_add_global(ec->wl_display, &screensaver_interface,
2711                                   shell, bind_screensaver) == NULL)
2712                 return -1;
2713
2714         shell->child.deathstamp = weston_compositor_get_time();
2715         if (launch_desktop_shell_process(shell) != 0)
2716                 return -1;
2717
2718         shell_add_bindings(ec, shell);
2719
2720         return 0;
2721 }