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