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