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