Replace fprintf() by weston_log()
[profile/ivi/weston.git] / src / shell.c
index fa165e2..73af751 100644 (file)
 #include <assert.h>
 #include <signal.h>
 #include <math.h>
+#include <sys/types.h>
 
 #include <wayland-server.h>
 #include "compositor.h"
 #include "desktop-shell-server-protocol.h"
 #include "../shared/config-parser.h"
+#include "log.h"
 
-struct shell_surface;
+enum animation_type {
+       ANIMATION_NONE,
 
-struct wl_shell {
+       ANIMATION_ZOOM,
+       ANIMATION_FADE
+};
+
+struct desktop_shell {
        struct weston_compositor *compositor;
-       struct weston_shell shell;
+
+       struct wl_listener lock_listener;
+       struct wl_listener unlock_listener;
+       struct wl_listener destroy_listener;
+
+       struct weston_layer fullscreen_layer;
+       struct weston_layer panel_layer;
+       struct weston_layer toplevel_layer;
+       struct weston_layer background_layer;
+       struct weston_layer lock_layer;
+
+       struct wl_listener pointer_focus_listener;
+       struct weston_surface *busy_surface;
 
        struct {
                struct weston_process process;
@@ -56,7 +75,6 @@ struct wl_shell {
 
        struct shell_surface *lock_surface;
        struct wl_listener lock_surface_listener;
-       struct wl_list hidden_surface_list;
 
        struct wl_list backgrounds;
        struct wl_list panels;
@@ -68,6 +86,10 @@ struct wl_shell {
                struct wl_list surfaces;
                struct weston_process process;
        } screensaver;
+
+       uint32_t binding_modifier;
+       enum animation_type win_animation_type;
+       struct weston_surface *debug_repaint_surface;
 };
 
 enum shell_surface_type {
@@ -85,15 +107,25 @@ enum shell_surface_type {
        SHELL_SURFACE_POPUP
 };
 
+struct ping_timer {
+       struct wl_event_source *source;
+       uint32_t serial;
+};
+
 struct shell_surface {
        struct wl_resource resource;
 
        struct weston_surface *surface;
        struct wl_listener surface_destroy_listener;
        struct shell_surface *parent;
+       struct desktop_shell *shell;
 
-       enum shell_surface_type type;
+       enum shell_surface_type type, next_type;
+       char *title, *class;
        int32_t saved_x, saved_y;
+       bool saved_position_valid;
+       bool saved_rotation_valid;
+       int unresponsive;
 
        struct {
                struct weston_transform transform;
@@ -102,39 +134,155 @@ struct shell_surface {
 
        struct {
                struct wl_pointer_grab grab;
-               uint32_t time;
                int32_t x, y;
                struct weston_transform parent_transform;
                int32_t initial_up;
+               struct wl_seat *seat;
+               uint32_t serial;
        } popup;
 
+       struct {
+               int32_t x, y;
+               uint32_t flags;
+       } transient;
+
+       struct {
+               enum wl_shell_surface_fullscreen_method type;
+               struct weston_transform transform; /* matrix from x, y */
+               uint32_t framerate;
+               struct weston_surface *black_surface;
+       } fullscreen;
+
+       struct ping_timer *ping_timer;
+
        struct weston_output *fullscreen_output;
        struct weston_output *output;
        struct wl_list link;
+
+       const struct weston_shell_client *client;
 };
 
-struct weston_move_grab {
+struct shell_grab {
        struct wl_pointer_grab grab;
-       struct weston_surface *surface;
-       int32_t dx, dy;
+       struct shell_surface *shsurf;
+       struct wl_listener shsurf_destroy_listener;
+};
+
+struct weston_move_grab {
+       struct shell_grab base;
+       wl_fixed_t dx, dy;
 };
 
 struct rotate_grab {
-       struct wl_pointer_grab grab;
-       struct shell_surface *surface;
+       struct shell_grab base;
        struct weston_matrix rotation;
        struct {
-               int32_t x;
-               int32_t y;
+               GLfloat x;
+               GLfloat y;
        } center;
 };
 
+static struct shell_surface *
+get_shell_surface(struct weston_surface *surface);
+
+static struct desktop_shell *
+shell_surface_get_shell(struct shell_surface *shsurf);
+
+static bool
+shell_surface_is_top_fullscreen(struct shell_surface *shsurf)
+{
+       struct desktop_shell *shell;
+       struct weston_surface *top_fs_es;
+
+       shell = shell_surface_get_shell(shsurf);
+       
+       if (wl_list_empty(&shell->fullscreen_layer.surface_list))
+               return false;
+
+       top_fs_es = container_of(shell->fullscreen_layer.surface_list.next,
+                                struct weston_surface, 
+                                layer_link);
+       return (shsurf == get_shell_surface(top_fs_es));
+}
+
+static void
+destroy_shell_grab_shsurf(struct wl_listener *listener, void *data)
+{
+       struct shell_grab *grab;
+
+       grab = container_of(listener, struct shell_grab,
+                           shsurf_destroy_listener);
+
+       grab->shsurf = NULL;
+}
+
+static void
+shell_grab_init(struct shell_grab *grab,
+               const struct wl_pointer_grab_interface *interface,
+               struct shell_surface *shsurf)
+{
+       grab->grab.interface = interface;
+       grab->shsurf = shsurf;
+       grab->shsurf_destroy_listener.notify = destroy_shell_grab_shsurf;
+       wl_signal_add(&shsurf->resource.destroy_signal,
+                     &grab->shsurf_destroy_listener);
+
+}
+
 static void
-shell_configuration(struct wl_shell *shell)
+shell_grab_finish(struct shell_grab *grab)
+{
+       if (grab->shsurf)
+               wl_list_remove(&grab->shsurf_destroy_listener.link);
+}
+
+static void
+center_on_output(struct weston_surface *surface,
+                struct weston_output *output);
+
+static enum weston_keyboard_modifier
+get_modifier(char *modifier)
+{
+       if (!modifier)
+               return MODIFIER_SUPER;
+
+       if (!strcmp("ctrl", modifier))
+               return MODIFIER_CTRL;
+       else if (!strcmp("alt", modifier))
+               return MODIFIER_ALT;
+       else if (!strcmp("super", modifier))
+               return MODIFIER_SUPER;
+       else
+               return MODIFIER_SUPER;
+}
+
+static enum animation_type
+get_animation_type(char *animation)
+{
+       if (!animation)
+               return ANIMATION_NONE;
+
+       if (!strcmp("zoom", animation))
+               return ANIMATION_ZOOM;
+       else if (!strcmp("fade", animation))
+               return ANIMATION_FADE;
+       else
+               return ANIMATION_NONE;
+}
+
+static void
+shell_configuration(struct desktop_shell *shell)
 {
        char *config_file;
        char *path = NULL;
        int duration = 60;
+       char *modifier = NULL;
+       char *win_animation = NULL;
+
+       struct config_key shell_keys[] = {
+               { "binding-modifier",   CONFIG_KEY_STRING, &modifier },
+               { "animation",          CONFIG_KEY_STRING, &win_animation},
+       };
 
        struct config_key saver_keys[] = {
                { "path",       CONFIG_KEY_STRING,  &path },
@@ -142,46 +290,60 @@ shell_configuration(struct wl_shell *shell)
        };
 
        struct config_section cs[] = {
+               { "shell", shell_keys, ARRAY_LENGTH(shell_keys), NULL },
                { "screensaver", saver_keys, ARRAY_LENGTH(saver_keys), NULL },
        };
 
-       config_file = config_file_path("weston-desktop-shell.ini");
+       config_file = config_file_path("weston.ini");
        parse_config_file(config_file, cs, ARRAY_LENGTH(cs), shell);
        free(config_file);
 
        shell->screensaver.path = path;
        shell->screensaver.duration = duration;
+       shell->binding_modifier = get_modifier(modifier);
+       shell->win_animation_type = get_animation_type(win_animation);
 }
 
 static void
-noop_grab_focus(struct wl_pointer_grab *grab, uint32_t time,
-               struct wl_surface *surface, int32_t x, int32_t y)
+noop_grab_focus(struct wl_pointer_grab *grab,
+               struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y)
 {
        grab->focus = NULL;
 }
 
 static void
 move_grab_motion(struct wl_pointer_grab *grab,
-                uint32_t time, int32_t x, int32_t y)
+                uint32_t time, wl_fixed_t x, wl_fixed_t y)
 {
        struct weston_move_grab *move = (struct weston_move_grab *) grab;
-       struct wl_input_device *device = grab->input_device;
-       struct weston_surface *es = move->surface;
+       struct wl_pointer *pointer = grab->pointer;
+       struct shell_surface *shsurf = move->base.shsurf;
+       struct weston_surface *es;
+       int dx = wl_fixed_to_int(pointer->x + move->dx);
+       int dy = wl_fixed_to_int(pointer->y + move->dy);
+
+       if (!shsurf)
+               return;
 
-       weston_surface_configure(es,
-                                device->x + move->dx,
-                                device->y + move->dy,
+       es = shsurf->surface;
+
+       weston_surface_configure(es, dx, dy,
                                 es->geometry.width, es->geometry.height);
 }
 
 static void
 move_grab_button(struct wl_pointer_grab *grab,
-                uint32_t time, int32_t button, int32_t state)
+                uint32_t time, uint32_t button, uint32_t state_w)
 {
-       struct wl_input_device *device = grab->input_device;
+       struct shell_grab *shell_grab = container_of(grab, struct shell_grab,
+                                                   grab);
+       struct wl_pointer *pointer = grab->pointer;
+       enum wl_pointer_button_state state = state_w;
 
-       if (device->button_count == 0 && state == 0) {
-               wl_input_device_end_pointer_grab(device, time);
+       if (pointer->button_count == 0 &&
+           state == WL_POINTER_BUTTON_STATE_RELEASED) {
+               shell_grab_finish(shell_grab);
+               wl_pointer_end_grab(pointer);
                free(grab);
        }
 }
@@ -192,96 +354,314 @@ static const struct wl_pointer_grab_interface move_grab_interface = {
        move_grab_button,
 };
 
+static void
+busy_cursor_grab_focus(struct wl_pointer_grab *base,
+                      struct wl_surface *surface, int32_t x, int32_t y)
+{
+       struct shell_grab *grab = (struct shell_grab *) base;
+       struct wl_pointer *pointer = base->pointer;
+
+       if (grab->grab.focus != surface) {
+               shell_grab_finish(grab);
+               wl_pointer_end_grab(pointer);
+               free(grab);
+       }
+}
+
+static void
+busy_cursor_grab_motion(struct wl_pointer_grab *grab,
+                       uint32_t time, int32_t x, int32_t y)
+{
+}
+
+static void
+busy_cursor_grab_button(struct wl_pointer_grab *grab,
+                       uint32_t time, uint32_t button, uint32_t state)
+{
+}
+
+static const struct wl_pointer_grab_interface busy_cursor_grab_interface = {
+       busy_cursor_grab_focus,
+       busy_cursor_grab_motion,
+       busy_cursor_grab_button,
+};
+
+static void
+set_busy_cursor(struct shell_surface *shsurf, struct wl_pointer *pointer)
+{
+       struct shell_grab *grab;
+       struct desktop_shell *shell = shsurf->shell;
+       struct weston_seat *seat = (struct weston_seat *) pointer->seat;
+       struct weston_surface *sprite;
+
+       grab = malloc(sizeof *grab);
+       if (!grab)
+               return;
+
+       shell_grab_init(grab, &busy_cursor_grab_interface, shsurf);
+       grab->grab.focus = &shsurf->surface->surface;
+       wl_pointer_start_grab(pointer, &grab->grab);
+       wl_pointer_set_focus(pointer, &shell->busy_surface->surface, 0, 0);
+
+       sprite = (struct weston_surface *) seat->sprite;
+       shell->busy_surface->output = sprite->output;
+}
+
+static void
+end_busy_cursor(struct shell_surface *shsurf, struct wl_pointer *pointer)
+{
+       struct shell_grab *grab = (struct shell_grab *) pointer->grab;
+
+       if (grab->grab.interface == &busy_cursor_grab_interface) {
+               shell_grab_finish(grab);
+               wl_pointer_end_grab(pointer);
+               free(grab);
+       }
+}
+
+static void
+ping_timer_destroy(struct shell_surface *shsurf)
+{
+       if (!shsurf || !shsurf->ping_timer)
+               return;
+
+       if (shsurf->ping_timer->source)
+               wl_event_source_remove(shsurf->ping_timer->source);
+
+       free(shsurf->ping_timer);
+       shsurf->ping_timer = NULL;
+}
+
 static int
-weston_surface_move(struct weston_surface *es,
-                   struct weston_input_device *wd, uint32_t time)
+ping_timeout_handler(void *data)
+{
+       struct shell_surface *shsurf = data;
+       struct weston_seat *seat;
+
+       /* Client is not responding */
+       shsurf->unresponsive = 1;
+
+       wl_list_for_each(seat, &shsurf->surface->compositor->seat_list, link)
+               if (seat->seat.pointer->focus == &shsurf->surface->surface)
+                       set_busy_cursor(shsurf, seat->seat.pointer);
+
+       return 1;
+}
+
+static void
+ping_handler(struct weston_surface *surface, uint32_t serial)
+{
+       struct shell_surface *shsurf = get_shell_surface(surface);
+       struct wl_event_loop *loop;
+       int ping_timeout = 200;
+
+       if (!shsurf)
+               return;
+       if (!shsurf->resource.client)
+               return;
+
+       if (!shsurf->ping_timer) {
+               shsurf->ping_timer = malloc(sizeof *shsurf->ping_timer);
+               if (!shsurf->ping_timer)
+                       return;
+
+               shsurf->ping_timer->serial = serial;
+               loop = wl_display_get_event_loop(surface->compositor->wl_display);
+               shsurf->ping_timer->source =
+                       wl_event_loop_add_timer(loop, ping_timeout_handler, shsurf);
+               wl_event_source_timer_update(shsurf->ping_timer->source, ping_timeout);
+
+               wl_shell_surface_send_ping(&shsurf->resource, serial);
+       }
+}
+
+static void
+handle_pointer_focus(struct wl_listener *listener, void *data)
+{
+       struct wl_pointer *pointer = data;
+       struct weston_surface *surface =
+               (struct weston_surface *) pointer->focus;
+       struct weston_compositor *compositor;
+       struct shell_surface *shsurf;
+       uint32_t serial;
+
+       if (!surface)
+               return;
+
+       compositor = surface->compositor;
+       shsurf = get_shell_surface(surface);
+
+       if (shsurf && shsurf->unresponsive) {
+               set_busy_cursor(shsurf, pointer);
+       } else {
+               serial = wl_display_next_serial(compositor->wl_display);
+               ping_handler(surface, serial);
+       }
+}
+
+static void
+shell_surface_pong(struct wl_client *client, struct wl_resource *resource,
+                                                       uint32_t serial)
+{
+       struct shell_surface *shsurf = resource->data;
+       struct desktop_shell *shell = shsurf->shell;
+       struct weston_seat *seat;
+       struct weston_compositor *ec = shsurf->surface->compositor;
+       struct wl_pointer *pointer;
+       int was_unresponsive;
+
+       if (shsurf->ping_timer->serial == serial) {
+               was_unresponsive = shsurf->unresponsive;
+               shsurf->unresponsive = 0;
+               if (was_unresponsive) {
+                       /* Received pong from previously unresponsive client */
+                       wl_list_for_each(seat, &ec->seat_list, link) {
+                               pointer = seat->seat.pointer;
+                               if (pointer->focus ==
+                                   &shell->busy_surface->surface &&
+                                   pointer->current ==
+                                   &shsurf->surface->surface)
+                                       end_busy_cursor(shsurf, pointer);
+                       }
+               }
+               ping_timer_destroy(shsurf);
+       }
+}
+
+static void
+shell_surface_set_title(struct wl_client *client,
+                       struct wl_resource *resource, const char *title)
+{
+       struct shell_surface *shsurf = resource->data;
+
+       free(shsurf->title);
+       shsurf->title = strdup(title);
+}
+
+static void
+shell_surface_set_class(struct wl_client *client,
+                       struct wl_resource *resource, const char *class)
+{
+       struct shell_surface *shsurf = resource->data;
+
+       free(shsurf->class);
+       shsurf->class = strdup(class);
+}
+
+static int
+surface_move(struct shell_surface *shsurf, struct weston_seat *ws)
 {
        struct weston_move_grab *move;
 
+       if (!shsurf)
+               return -1;
+
        move = malloc(sizeof *move);
        if (!move)
                return -1;
 
-       move->grab.interface = &move_grab_interface;
-       move->dx = es->geometry.x - wd->input_device.grab_x;
-       move->dy = es->geometry.y - wd->input_device.grab_y;
-       move->surface = es;
+       shell_grab_init(&move->base, &move_grab_interface, shsurf);
 
-       wl_input_device_start_pointer_grab(&wd->input_device, &move->grab, time);
+       move->dx = wl_fixed_from_double(shsurf->surface->geometry.x) -
+                       ws->seat.pointer->grab_x;
+       move->dy = wl_fixed_from_double(shsurf->surface->geometry.y) -
+                       ws->seat.pointer->grab_y;
 
-       wl_input_device_set_pointer_focus(&wd->input_device, NULL, time, 0, 0);
+       wl_pointer_start_grab(ws->seat.pointer, &move->base.grab);
+
+       wl_pointer_set_focus(ws->seat.pointer, NULL,
+                            wl_fixed_from_int(0),
+                            wl_fixed_from_int(0));
 
        return 0;
 }
 
 static void
 shell_surface_move(struct wl_client *client, struct wl_resource *resource,
-                  struct wl_resource *input_resource, uint32_t time)
+                  struct wl_resource *seat_resource, uint32_t serial)
 {
-       struct weston_input_device *wd = input_resource->data;
+       struct weston_seat *ws = seat_resource->data;
        struct shell_surface *shsurf = resource->data;
 
-       if (wd->input_device.button_count == 0 ||
-           wd->input_device.grab_time != time ||
-           wd->input_device.pointer_focus != &shsurf->surface->surface)
+       if (ws->seat.pointer->button_count == 0 ||
+           ws->seat.pointer->grab_serial != serial ||
+           ws->seat.pointer->focus != &shsurf->surface->surface)
                return;
 
-       if (weston_surface_move(shsurf->surface, wd, time) < 0)
+       if (surface_move(shsurf, ws) < 0)
                wl_resource_post_no_memory(resource);
 }
 
 struct weston_resize_grab {
-       struct wl_pointer_grab grab;
+       struct shell_grab base;
        uint32_t edges;
        int32_t width, height;
-       struct shell_surface *shsurf;
 };
 
 static void
 resize_grab_motion(struct wl_pointer_grab *grab,
-                  uint32_t time, int32_t x, int32_t y)
+                  uint32_t time, wl_fixed_t x, wl_fixed_t y)
 {
        struct weston_resize_grab *resize = (struct weston_resize_grab *) grab;
-       struct wl_input_device *device = grab->input_device;
+       struct wl_pointer *pointer = grab->pointer;
+       struct shell_surface *shsurf = resize->base.shsurf;
        int32_t width, height;
-       int32_t from_x, from_y;
-       int32_t to_x, to_y;
+       wl_fixed_t from_x, from_y;
+       wl_fixed_t to_x, to_y;
+
+       if (!shsurf)
+               return;
 
-       weston_surface_from_global(resize->shsurf->surface,
-                                  device->grab_x, device->grab_y,
-                                  &from_x, &from_y);
-       weston_surface_from_global(resize->shsurf->surface,
-                                  device->x, device->y, &to_x, &to_y);
+       weston_surface_from_global_fixed(shsurf->surface,
+                                        pointer->grab_x, pointer->grab_y,
+                                        &from_x, &from_y);
+       weston_surface_from_global_fixed(shsurf->surface,
+                                        pointer->x, pointer->y, &to_x, &to_y);
 
+       width = resize->width;
        if (resize->edges & WL_SHELL_SURFACE_RESIZE_LEFT) {
-               width = resize->width + from_x - to_x;
+               width += wl_fixed_to_int(from_x - to_x);
        } else if (resize->edges & WL_SHELL_SURFACE_RESIZE_RIGHT) {
-               width = resize->width + to_x - from_x;
-       } else {
-               width = resize->width;
+               width += wl_fixed_to_int(to_x - from_x);
        }
 
+       height = resize->height;
        if (resize->edges & WL_SHELL_SURFACE_RESIZE_TOP) {
-               height = resize->height + from_y - to_y;
+               height += wl_fixed_to_int(from_y - to_y);
        } else if (resize->edges & WL_SHELL_SURFACE_RESIZE_BOTTOM) {
-               height = resize->height + to_y - from_y;
-       } else {
-               height = resize->height;
+               height += wl_fixed_to_int(to_y - from_y);
        }
 
-       wl_resource_post_event(&resize->shsurf->resource,
-                              WL_SHELL_SURFACE_CONFIGURE, time, resize->edges,
-                              width, height);
+       shsurf->client->send_configure(shsurf->surface,
+                                      resize->edges, width, height);
 }
 
 static void
+send_configure(struct weston_surface *surface,
+              uint32_t edges, int32_t width, int32_t height)
+{
+       struct shell_surface *shsurf = get_shell_surface(surface);
+
+       wl_shell_surface_send_configure(&shsurf->resource,
+                                       edges, width, height);
+}
+
+static const struct weston_shell_client shell_client = {
+       send_configure
+};
+
+static void
 resize_grab_button(struct wl_pointer_grab *grab,
-                  uint32_t time, int32_t button, int32_t state)
+                  uint32_t time, uint32_t button, uint32_t state_w)
 {
-       struct wl_input_device *device = grab->input_device;
+       struct weston_resize_grab *resize = (struct weston_resize_grab *) grab;
+       struct wl_pointer *pointer = grab->pointer;
+       enum wl_pointer_button_state state = state_w;
 
-       if (device->button_count == 0 && state == 0) {
-               wl_input_device_end_pointer_grab(device, time);
+       if (pointer->button_count == 0 &&
+           state == WL_POINTER_BUTTON_STATE_RELEASED) {
+               shell_grab_finish(&resize->base);
+               wl_pointer_end_grab(pointer);
                free(grab);
        }
 }
@@ -293,13 +673,13 @@ static const struct wl_pointer_grab_interface resize_grab_interface = {
 };
 
 static int
-weston_surface_resize(struct shell_surface *shsurf,
-                   struct weston_input_device *wd,
-                   uint32_t time, uint32_t edges)
+surface_resize(struct shell_surface *shsurf,
+              struct weston_seat *ws, uint32_t edges)
 {
        struct weston_resize_grab *resize;
 
-       /* FIXME: Reject if fullscreen */
+       if (shsurf->type == SHELL_SURFACE_FULLSCREEN)
+               return 0;
 
        if (edges == 0 || edges > 15 ||
            (edges & 3) == 3 || (edges & 12) == 12)
@@ -309,35 +689,38 @@ weston_surface_resize(struct shell_surface *shsurf,
        if (!resize)
                return -1;
 
-       resize->grab.interface = &resize_grab_interface;
+       shell_grab_init(&resize->base, &resize_grab_interface, shsurf);
+
        resize->edges = edges;
        resize->width = shsurf->surface->geometry.width;
        resize->height = shsurf->surface->geometry.height;
-       resize->shsurf = shsurf;
 
-       wl_input_device_start_pointer_grab(&wd->input_device, &resize->grab, time);
+       wl_pointer_start_grab(ws->seat.pointer, &resize->base.grab);
 
-       wl_input_device_set_pointer_focus(&wd->input_device, NULL, time, 0, 0);
+       wl_pointer_set_focus(ws->seat.pointer, NULL,
+                            wl_fixed_from_int(0),
+                            wl_fixed_from_int(0));
 
        return 0;
 }
 
 static void
 shell_surface_resize(struct wl_client *client, struct wl_resource *resource,
-                    struct wl_resource *input_resource, uint32_t time,
+                    struct wl_resource *seat_resource, uint32_t serial,
                     uint32_t edges)
 {
-       struct weston_input_device *wd = input_resource->data;
+       struct weston_seat *ws = seat_resource->data;
        struct shell_surface *shsurf = resource->data;
 
-       /* FIXME: Reject if fullscreen */
+       if (shsurf->type == SHELL_SURFACE_FULLSCREEN)
+               return;
 
-       if (wd->input_device.button_count == 0 ||
-           wd->input_device.grab_time != time ||
-           wd->input_device.pointer_focus != &shsurf->surface->surface)
+       if (ws->seat.pointer->button_count == 0 ||
+           ws->seat.pointer->grab_serial != serial ||
+           ws->seat.pointer->focus != &shsurf->surface->surface)
                return;
 
-       if (weston_surface_resize(shsurf, wd, time, edges) < 0)
+       if (surface_resize(shsurf, ws, edges) < 0)
                wl_resource_post_no_memory(resource);
 }
 
@@ -348,15 +731,38 @@ get_default_output(struct weston_compositor *compositor)
                            struct weston_output, link);
 }
 
+static void
+shell_unset_fullscreen(struct shell_surface *shsurf)
+{
+       /* undo all fullscreen things here */
+       if (shsurf->fullscreen.type == WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER &&
+           shell_surface_is_top_fullscreen(shsurf)) {
+               weston_output_switch_mode(shsurf->fullscreen_output,
+                                         shsurf->fullscreen_output->origin);
+       }
+       shsurf->fullscreen.type = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT;
+       shsurf->fullscreen.framerate = 0;
+       wl_list_remove(&shsurf->fullscreen.transform.link);
+       wl_list_init(&shsurf->fullscreen.transform.link);
+       if (shsurf->fullscreen.black_surface)
+               weston_surface_destroy(shsurf->fullscreen.black_surface);
+       shsurf->fullscreen.black_surface = NULL;
+       shsurf->fullscreen_output = NULL;
+       weston_surface_set_position(shsurf->surface,
+                                   shsurf->saved_x, shsurf->saved_y);
+       if (shsurf->saved_rotation_valid) {
+               wl_list_insert(&shsurf->surface->geometry.transformation_list,
+                              &shsurf->rotation.transform.link);
+               shsurf->saved_rotation_valid = false;
+       }
+}
+
 static int
 reset_shell_surface_type(struct shell_surface *surface)
 {
        switch (surface->type) {
        case SHELL_SURFACE_FULLSCREEN:
-               weston_surface_set_position(surface->surface,
-                                           surface->saved_x,
-                                           surface->saved_y);
-               surface->fullscreen_output = NULL;
+               shell_unset_fullscreen(surface);
                break;
        case SHELL_SURFACE_MAXIMIZED:
                surface->output = get_default_output(surface->surface->compositor);
@@ -387,16 +793,110 @@ reset_shell_surface_type(struct shell_surface *surface)
 }
 
 static void
+set_surface_type(struct shell_surface *shsurf)
+{
+       struct weston_surface *surface = shsurf->surface;
+       struct shell_surface *pshsurf = shsurf->parent;
+       struct weston_surface *pes;
+       struct shell_surface *priv;
+       struct desktop_shell *shell = shsurf->shell;
+
+       reset_shell_surface_type(shsurf);
+
+       shsurf->type = shsurf->next_type;
+       shsurf->next_type = SHELL_SURFACE_NONE;
+
+       switch (shsurf->type) {
+       case SHELL_SURFACE_TOPLEVEL:
+               break;
+       case SHELL_SURFACE_TRANSIENT:
+               pes = pshsurf->surface;
+               weston_surface_set_position(surface,
+                               pes->geometry.x + shsurf->transient.x,
+                               pes->geometry.y + shsurf->transient.y);
+               break;
+
+       case SHELL_SURFACE_MAXIMIZED:
+               shsurf->saved_x = surface->geometry.x;
+               shsurf->saved_y = surface->geometry.y;
+               shsurf->saved_position_valid = true;
+               break;
+
+       case SHELL_SURFACE_FULLSCREEN:
+               shsurf->saved_x = surface->geometry.x;
+               shsurf->saved_y = surface->geometry.y;
+               shsurf->saved_position_valid = true;
+
+               if (!wl_list_empty(&shsurf->rotation.transform.link)) {
+                       wl_list_remove(&shsurf->rotation.transform.link);
+                       wl_list_init(&shsurf->rotation.transform.link);
+                       shsurf->surface->geometry.dirty = 1;
+                       shsurf->saved_rotation_valid = true;
+               }
+               break;
+
+       case SHELL_SURFACE_BACKGROUND:
+               wl_list_for_each(priv, &shell->backgrounds, link) {
+                       if (priv->output == shsurf->output) {
+                               priv->surface->output = NULL;
+                               wl_list_remove(&priv->surface->layer_link);
+                               wl_list_remove(&priv->link);
+                               break;
+                       }
+               }
+
+               wl_list_insert(&shell->backgrounds, &shsurf->link);
+
+               weston_surface_set_position(surface, shsurf->output->x,
+                                           shsurf->output->y);
+               break;
+
+       case SHELL_SURFACE_PANEL:
+               wl_list_for_each(priv, &shell->panels, link) {
+                       if (priv->output == shsurf->output) {
+                               priv->surface->output = NULL;
+                               wl_list_remove(&priv->surface->layer_link);
+                               wl_list_remove(&priv->link);
+                               break;
+                       }
+               }
+
+               wl_list_insert(&shell->panels, &shsurf->link);
+
+               weston_surface_set_position(surface, shsurf->output->x,
+                                           shsurf->output->y);
+               break;
+
+       default:
+               break;
+       }
+}
+
+static void
+set_toplevel(struct shell_surface *shsurf)
+{
+       shsurf->next_type = SHELL_SURFACE_TOPLEVEL;
+}
+
+static void
 shell_surface_set_toplevel(struct wl_client *client,
                           struct wl_resource *resource)
-
 {
        struct shell_surface *surface = resource->data;
 
-       if (reset_shell_surface_type(surface))
-               return;
+       set_toplevel(surface);
+}
 
-       surface->type = SHELL_SURFACE_TOPLEVEL;
+static void
+set_transient(struct shell_surface *shsurf,
+             struct shell_surface *pshsurf, int x, int y, uint32_t flags)
+{
+       /* assign to parents output */
+       shsurf->parent = pshsurf;
+       shsurf->transient.x = x;
+       shsurf->transient.y = y;
+       shsurf->transient.flags = flags;
+       shsurf->next_type = SHELL_SURFACE_TRANSIENT;
 }
 
 static void
@@ -406,32 +906,20 @@ shell_surface_set_transient(struct wl_client *client,
                            int x, int y, uint32_t flags)
 {
        struct shell_surface *shsurf = resource->data;
-       struct weston_surface *es = shsurf->surface;
        struct shell_surface *pshsurf = parent_resource->data;
-       struct weston_surface *pes = pshsurf->surface;
 
-       if (reset_shell_surface_type(shsurf))
-               return;
-
-       /* assign to parents output  */
-       es->output = pes->output;
-       weston_surface_set_position(es, pes->geometry.x + x,
-                                       pes->geometry.y + y);
-
-       shsurf->type = SHELL_SURFACE_TRANSIENT;
+       set_transient(shsurf, pshsurf, x, y, flags);
 }
 
-static struct wl_shell *
+static struct desktop_shell *
 shell_surface_get_shell(struct shell_surface *shsurf)
 {
-       struct weston_surface *es = shsurf->surface;
-       struct weston_shell *shell = es->compositor->shell;
-
-       return (struct wl_shell *)container_of(shell, struct wl_shell, shell);
+       return shsurf->shell;
 }
 
 static int
-get_output_panel_height(struct wl_shell *wlshell,struct weston_output *output)
+get_output_panel_height(struct desktop_shell *shell,
+                       struct weston_output *output)
 {
        struct shell_surface *priv;
        int panel_height = 0;
@@ -439,7 +927,7 @@ get_output_panel_height(struct wl_shell *wlshell,struct weston_output *output)
        if (!output)
                return 0;
 
-       wl_list_for_each(priv, &wlshell->panels, link) {
+       wl_list_for_each(priv, &shell->panels, link) {
                if (priv->output == output) {
                        panel_height = priv->surface->geometry.height;
                        break;
@@ -455,7 +943,7 @@ shell_surface_set_maximized(struct wl_client *client,
 {
        struct shell_surface *shsurf = resource->data;
        struct weston_surface *es = shsurf->surface;
-       struct wl_shell *wlshell = NULL;
+       struct desktop_shell *shell = NULL;
        uint32_t edges = 0, panel_height = 0;
 
        /* get the default output, if the client set it as NULL
@@ -465,22 +953,134 @@ shell_surface_set_maximized(struct wl_client *client,
        else
                shsurf->output = get_default_output(es->compositor);
 
-       if (reset_shell_surface_type(shsurf))
-               return;
+       shell = shell_surface_get_shell(shsurf);
+       panel_height = get_output_panel_height(shell, es->output);
+       edges = WL_SHELL_SURFACE_RESIZE_TOP|WL_SHELL_SURFACE_RESIZE_LEFT;
 
-       shsurf->saved_x = es->geometry.x;
-       shsurf->saved_y = es->geometry.y;
+       shsurf->client->send_configure(shsurf->surface, edges,
+                                      es->output->current->width,
+                                      es->output->current->height - panel_height);
 
-       wlshell = shell_surface_get_shell(shsurf);
-       panel_height = get_output_panel_height(wlshell, es->output);
-       edges = WL_SHELL_SURFACE_RESIZE_TOP|WL_SHELL_SURFACE_RESIZE_LEFT;
-       wl_resource_post_event(&shsurf->resource,
-                              WL_SHELL_SURFACE_CONFIGURE,
-                              weston_compositor_get_time(), edges,
-                              es->output->current->width,
-                              es->output->current->height - panel_height);
+       shsurf->next_type = SHELL_SURFACE_MAXIMIZED;
+}
 
-       shsurf->type = SHELL_SURFACE_MAXIMIZED;
+static void
+black_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy);
+
+static struct weston_surface *
+create_black_surface(struct weston_compositor *ec,
+                    struct weston_surface *fs_surface,
+                    GLfloat x, GLfloat y, int w, int h)
+{
+       struct weston_surface *surface = NULL;
+
+       surface = weston_surface_create(ec);
+       if (surface == NULL) {
+               weston_log("no memory\n");
+               return NULL;
+       }
+
+       surface->configure = black_surface_configure;
+       surface->private = fs_surface;
+       weston_surface_configure(surface, x, y, w, h);
+       weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1);
+       return surface;
+}
+
+/* Create black surface and append it to the associated fullscreen surface.
+ * Handle size dismatch and positioning according to the method. */
+static void
+shell_configure_fullscreen(struct shell_surface *shsurf)
+{
+       struct weston_output *output = shsurf->fullscreen_output;
+       struct weston_surface *surface = shsurf->surface;
+       struct weston_matrix *matrix;
+       float scale;
+
+       center_on_output(surface, output);
+
+       if (!shsurf->fullscreen.black_surface)
+               shsurf->fullscreen.black_surface =
+                       create_black_surface(surface->compositor,
+                                            surface,
+                                            output->x, output->y,
+                                            output->current->width,
+                                            output->current->height);
+
+       wl_list_remove(&shsurf->fullscreen.black_surface->layer_link);
+       wl_list_insert(&surface->layer_link,
+                      &shsurf->fullscreen.black_surface->layer_link);
+       shsurf->fullscreen.black_surface->output = output;
+
+       switch (shsurf->fullscreen.type) {
+       case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT:
+               break;
+       case WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE:
+               matrix = &shsurf->fullscreen.transform.matrix;
+               weston_matrix_init(matrix);
+               scale = (float)output->current->width/(float)surface->geometry.width;
+               weston_matrix_scale(matrix, scale, scale, 1);
+               wl_list_remove(&shsurf->fullscreen.transform.link);
+               wl_list_insert(surface->geometry.transformation_list.prev,
+                              &shsurf->fullscreen.transform.link);
+               weston_surface_set_position(surface, output->x, output->y);
+               break;
+       case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER:
+               if (shell_surface_is_top_fullscreen(shsurf)) {
+                       struct weston_mode mode = {0, 
+                               surface->geometry.width,
+                               surface->geometry.height,
+                               shsurf->fullscreen.framerate};
+
+                       if (weston_output_switch_mode(output, &mode) == 0) {
+                               weston_surface_configure(shsurf->fullscreen.black_surface, 
+                                                        output->x, output->y,
+                                                        output->current->width,
+                                                        output->current->height);
+                               weston_surface_set_position(surface, output->x, output->y);
+                               break;
+                       }
+               }
+               break;
+       case WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL:
+               break;
+       default:
+               break;
+       }
+}
+
+/* make the fullscreen and black surface at the top */
+static void
+shell_stack_fullscreen(struct shell_surface *shsurf)
+{
+       struct weston_output *output = shsurf->fullscreen_output;
+       struct weston_surface *surface = shsurf->surface;
+       struct desktop_shell *shell = shell_surface_get_shell(shsurf);
+
+       wl_list_remove(&surface->layer_link);
+       wl_list_insert(&shell->fullscreen_layer.surface_list,
+                      &surface->layer_link);
+       weston_surface_damage(surface);
+
+       if (!shsurf->fullscreen.black_surface)
+               shsurf->fullscreen.black_surface =
+                       create_black_surface(surface->compositor,
+                                            surface,
+                                            output->x, output->y,
+                                            output->current->width,
+                                            output->current->height);
+
+       wl_list_remove(&shsurf->fullscreen.black_surface->layer_link);
+       wl_list_insert(&surface->layer_link,
+                      &shsurf->fullscreen.black_surface->layer_link);
+       weston_surface_damage(shsurf->fullscreen.black_surface);
+}
+
+static void
+shell_map_fullscreen(struct shell_surface *shsurf)
+{
+       shell_stack_fullscreen(shsurf);
+       shell_configure_fullscreen(shsurf);
 }
 
 static void
@@ -492,80 +1092,80 @@ shell_surface_set_fullscreen(struct wl_client *client,
 {
        struct shell_surface *shsurf = resource->data;
        struct weston_surface *es = shsurf->surface;
-       struct weston_output *output;
 
-       if (reset_shell_surface_type(shsurf))
-               return;
-
-       /* FIXME: Fullscreen on first output */
-       /* FIXME: Handle output going away */
-       output = get_default_output(es->compositor);
-       es->output = output;
+       if (output_resource)
+               shsurf->output = output_resource->data;
+       else
+               shsurf->output = get_default_output(es->compositor);
 
-       shsurf->saved_x = es->geometry.x;
-       shsurf->saved_y = es->geometry.y;
-       shsurf->fullscreen_output = output;
-       shsurf->type = SHELL_SURFACE_FULLSCREEN;
+       shsurf->fullscreen_output = shsurf->output;
+       shsurf->fullscreen.type = method;
+       shsurf->fullscreen.framerate = framerate;
+       shsurf->next_type = SHELL_SURFACE_FULLSCREEN;
 
-       wl_resource_post_event(resource,
-                              WL_SHELL_SURFACE_CONFIGURE,
-                              weston_compositor_get_time(), 0,
-                              es->output->current->width,
-                              es->output->current->height);
+       shsurf->client->send_configure(shsurf->surface, 0,
+                                      shsurf->output->current->width,
+                                      shsurf->output->current->height);
 }
 
 static void
-popup_grab_focus(struct wl_pointer_grab *grab, uint32_t time,
-                struct wl_surface *surface, int32_t x, int32_t y)
+popup_grab_focus(struct wl_pointer_grab *grab,
+                struct wl_surface *surface,
+                wl_fixed_t x,
+                wl_fixed_t y)
 {
-       struct wl_input_device *device = grab->input_device;
+       struct wl_pointer *pointer = grab->pointer;
        struct shell_surface *priv =
                container_of(grab, struct shell_surface, popup.grab);
        struct wl_client *client = priv->surface->surface.resource.client;
 
        if (surface && surface->resource.client == client) {
-               wl_input_device_set_pointer_focus(device, surface, time, x, y);
+               wl_pointer_set_focus(pointer, surface, x, y);
                grab->focus = surface;
        } else {
-               wl_input_device_set_pointer_focus(device, NULL, time, 0, 0);
+               wl_pointer_set_focus(pointer, NULL,
+                                    wl_fixed_from_int(0),
+                                    wl_fixed_from_int(0));
                grab->focus = NULL;
        }
 }
 
 static void
 popup_grab_motion(struct wl_pointer_grab *grab,
-                 uint32_t time, int32_t sx, int32_t sy)
+                 uint32_t time, wl_fixed_t sx, wl_fixed_t sy)
 {
        struct wl_resource *resource;
 
-       resource = grab->input_device->pointer_focus_resource;
+       resource = grab->pointer->focus_resource;
        if (resource)
-               wl_resource_post_event(resource, WL_INPUT_DEVICE_MOTION,
-                                      time, sx, sy);
+               wl_pointer_send_motion(resource, time, sx, sy);
 }
 
 static void
 popup_grab_button(struct wl_pointer_grab *grab,
-                 uint32_t time, int32_t button, int32_t state)
+                 uint32_t time, uint32_t button, uint32_t state_w)
 {
        struct wl_resource *resource;
        struct shell_surface *shsurf =
                container_of(grab, struct shell_surface, popup.grab);
+       struct wl_display *display;
+       enum wl_pointer_button_state state = state_w;
+       uint32_t serial;
 
-       resource = grab->input_device->pointer_focus_resource;
+       resource = grab->pointer->focus_resource;
        if (resource) {
-               wl_resource_post_event(resource, WL_INPUT_DEVICE_BUTTON,
-                                      time, button, state);
-       } else if (state == 0 &&
+               display = wl_client_get_display(resource->client);
+               serial = wl_display_get_serial(display);
+               wl_pointer_send_button(resource, serial, time, button, state);
+       } else if (state == WL_POINTER_BUTTON_STATE_RELEASED &&
                   (shsurf->popup.initial_up ||
-                   time - shsurf->popup.time > 500)) {
-               wl_resource_post_event(&shsurf->resource,
-                                      WL_SHELL_SURFACE_POPUP_DONE);
-               wl_input_device_end_pointer_grab(grab->input_device, time);
-               shsurf->popup.grab.input_device = NULL;
+                   time - shsurf->popup.seat->pointer->grab_time > 500)) {
+               wl_shell_surface_send_popup_done(&shsurf->resource);
+               wl_pointer_end_grab(grab->pointer);
+               shsurf->popup.grab.pointer = NULL;
        }
 
-       if (state == 0)
+       if (state == WL_POINTER_BUTTON_STATE_RELEASED)
                shsurf->popup.initial_up = 1;
 }
 
@@ -576,16 +1176,14 @@ static const struct wl_pointer_grab_interface popup_grab_interface = {
 };
 
 static void
-shell_map_popup(struct shell_surface *shsurf, uint32_t time)
+shell_map_popup(struct shell_surface *shsurf)
 {
-       struct wl_input_device *device;
+       struct wl_seat *seat = shsurf->popup.seat;
        struct weston_surface *es = shsurf->surface;
        struct weston_surface *parent = shsurf->parent->surface;
 
        es->output = parent->output;
-
        shsurf->popup.grab.interface = &popup_grab_interface;
-       device = es->compositor->input_device;
 
        weston_surface_update_transform(parent);
        if (parent->transform.enabled) {
@@ -603,19 +1201,22 @@ shell_map_popup(struct shell_surface *shsurf, uint32_t time)
                       &shsurf->popup.parent_transform.link);
        weston_surface_set_position(es, shsurf->popup.x, shsurf->popup.y);
 
-       shsurf->popup.grab.input_device = device;
-       shsurf->popup.time = device->grab_time;
        shsurf->popup.initial_up = 0;
 
-       wl_input_device_start_pointer_grab(shsurf->popup.grab.input_device,
-                                  &shsurf->popup.grab, shsurf->popup.time);
+       /* We don't require the grab to still be active, but if another
+        * grab has started in the meantime, we end the popup now. */
+       if (seat->pointer->grab_serial == shsurf->popup.serial) {
+               wl_pointer_start_grab(seat->pointer, &shsurf->popup.grab);
+       } else {
+               wl_shell_surface_send_popup_done(&shsurf->resource);
+       }
 }
 
 static void
 shell_surface_set_popup(struct wl_client *client,
                        struct wl_resource *resource,
-                       struct wl_resource *input_device_resource,
-                       uint32_t time,
+                       struct wl_resource *seat_resource,
+                       uint32_t serial,
                        struct wl_resource *parent_resource,
                        int32_t x, int32_t y, uint32_t flags)
 {
@@ -623,63 +1224,141 @@ shell_surface_set_popup(struct wl_client *client,
 
        shsurf->type = SHELL_SURFACE_POPUP;
        shsurf->parent = parent_resource->data;
+       shsurf->popup.seat = seat_resource->data;
+       shsurf->popup.serial = serial;
        shsurf->popup.x = x;
        shsurf->popup.y = y;
 }
 
 static const struct wl_shell_surface_interface shell_surface_implementation = {
+       shell_surface_pong,
        shell_surface_move,
        shell_surface_resize,
        shell_surface_set_toplevel,
        shell_surface_set_transient,
        shell_surface_set_fullscreen,
        shell_surface_set_popup,
-       shell_surface_set_maximized
+       shell_surface_set_maximized,
+       shell_surface_set_title,
+       shell_surface_set_class
 };
 
 static void
-destroy_shell_surface(struct wl_resource *resource)
+destroy_shell_surface(struct shell_surface *shsurf)
 {
-       struct shell_surface *shsurf = resource->data;
+       if (shsurf->popup.grab.pointer)
+               wl_pointer_end_grab(shsurf->popup.grab.pointer);
+
+       if (shsurf->fullscreen.type == WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER &&
+           shell_surface_is_top_fullscreen(shsurf)) {
+               weston_output_switch_mode(shsurf->fullscreen_output,
+                                         shsurf->fullscreen_output->origin);
+       }
 
-       if (shsurf->popup.grab.input_device)
-               wl_input_device_end_pointer_grab(shsurf->popup.grab.input_device, 0);
+       if (shsurf->fullscreen.black_surface)
+               weston_surface_destroy(shsurf->fullscreen.black_surface);
 
-       /* in case cleaning up a dead client destroys shell_surface first */
-       if (shsurf->surface)
-               wl_list_remove(&shsurf->surface_destroy_listener.link);
+       /* As destroy_resource() use wl_list_for_each_safe(),
+        * we can always remove the listener.
+        */
+       wl_list_remove(&shsurf->surface_destroy_listener.link);
+       shsurf->surface->configure = NULL;
+       ping_timer_destroy(shsurf);
 
        wl_list_remove(&shsurf->link);
        free(shsurf);
 }
 
 static void
-shell_handle_surface_destroy(struct wl_listener *listener,
-                            struct wl_resource *resource, uint32_t time)
+shell_destroy_shell_surface(struct wl_resource *resource)
+{
+       struct shell_surface *shsurf = resource->data;
+
+       destroy_shell_surface(shsurf);
+}
+
+static void
+shell_handle_surface_destroy(struct wl_listener *listener, void *data)
 {
        struct shell_surface *shsurf = container_of(listener,
                                                    struct shell_surface,
                                                    surface_destroy_listener);
 
-       shsurf->surface = NULL;
-       wl_resource_destroy(&shsurf->resource, time);
+       if (shsurf->resource.client) {
+               wl_resource_destroy(&shsurf->resource);
+       } else {
+               wl_signal_emit(&shsurf->resource.destroy_signal,
+                              &shsurf->resource);
+               destroy_shell_surface(shsurf);
+       }
 }
 
 static struct shell_surface *
 get_shell_surface(struct weston_surface *surface)
 {
-       struct wl_list *lst = &surface->surface.resource.destroy_listener_list;
        struct wl_listener *listener;
 
-       /* search the destroy listener list for our callback */
-       wl_list_for_each(listener, lst, link) {
-               if (listener->func == shell_handle_surface_destroy) {
-                       return container_of(listener, struct shell_surface,
-                                           surface_destroy_listener);
-               }
+       listener = wl_signal_get(&surface->surface.resource.destroy_signal,
+                                shell_handle_surface_destroy);
+       if (listener)
+               return container_of(listener, struct shell_surface,
+                                   surface_destroy_listener);
+
+       return NULL;
+}
+
+static void
+shell_surface_configure(struct weston_surface *, int32_t, int32_t);
+
+static         struct shell_surface *
+create_shell_surface(void *shell, struct weston_surface *surface,
+                    const struct weston_shell_client *client)
+{
+       struct shell_surface *shsurf;
+
+       if (surface->configure) {
+               weston_log("surface->configure already set\n");
+               return NULL;
+       }
+
+       shsurf = calloc(1, sizeof *shsurf);
+       if (!shsurf) {
+               weston_log("no memory to allocate shell surface\n");
+               return NULL;
        }
 
-       return NULL;
+       surface->configure = shell_surface_configure;
+       surface->compositor->shell_interface.shell = shell;
+
+       shsurf->shell = (struct desktop_shell *) shell;
+       shsurf->unresponsive = 0;
+       shsurf->saved_position_valid = false;
+       shsurf->saved_rotation_valid = false;
+       shsurf->surface = surface;
+       shsurf->fullscreen.type = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT;
+       shsurf->fullscreen.framerate = 0;
+       shsurf->fullscreen.black_surface = NULL;
+       shsurf->ping_timer = NULL;
+       wl_list_init(&shsurf->fullscreen.transform.link);
+
+       wl_signal_init(&shsurf->resource.destroy_signal);
+       shsurf->surface_destroy_listener.notify = shell_handle_surface_destroy;
+       wl_signal_add(&surface->surface.resource.destroy_signal,
+                     &shsurf->surface_destroy_listener);
+
+       /* init link so its safe to always remove it in destroy_shell_surface */
+       wl_list_init(&shsurf->link);
+
+       /* empty when not in use */
+       wl_list_init(&shsurf->rotation.transform.link);
+       weston_matrix_init(&shsurf->rotation.rotation);
+
+       shsurf->type = SHELL_SURFACE_NONE;
+       shsurf->next_type = SHELL_SURFACE_NONE;
+
+       shsurf->client = client;
+
+       return shsurf;
 }
 
 static void
@@ -689,42 +1368,31 @@ shell_get_shell_surface(struct wl_client *client,
                        struct wl_resource *surface_resource)
 {
        struct weston_surface *surface = surface_resource->data;
+       struct desktop_shell *shell = resource->data;
        struct shell_surface *shsurf;
 
        if (get_shell_surface(surface)) {
                wl_resource_post_error(surface_resource,
-                       WL_DISPLAY_ERROR_INVALID_OBJECT,
-                       "wl_shell::get_shell_surface already requested");
+                                      WL_DISPLAY_ERROR_INVALID_OBJECT,
+                                      "desktop_shell::get_shell_surface already requested");
                return;
        }
 
-       shsurf = calloc(1, sizeof *shsurf);
+       shsurf = create_shell_surface(shell, surface, &shell_client);
        if (!shsurf) {
-               wl_resource_post_no_memory(resource);
+               wl_resource_post_error(surface_resource,
+                                      WL_DISPLAY_ERROR_INVALID_OBJECT,
+                                      "surface->configure already set");
                return;
        }
 
-       shsurf->resource.destroy = destroy_shell_surface;
+       shsurf->resource.destroy = shell_destroy_shell_surface;
        shsurf->resource.object.id = id;
        shsurf->resource.object.interface = &wl_shell_surface_interface;
        shsurf->resource.object.implementation =
                (void (**)(void)) &shell_surface_implementation;
        shsurf->resource.data = shsurf;
 
-       shsurf->surface = surface;
-       shsurf->surface_destroy_listener.func = shell_handle_surface_destroy;
-       wl_list_insert(surface->surface.resource.destroy_listener_list.prev,
-                      &shsurf->surface_destroy_listener.link);
-
-       /* init link so its safe to always remove it in destroy_shell_surface */
-       wl_list_init(&shsurf->link);
-
-       /* empty when not in use */
-       wl_list_init(&shsurf->rotation.transform.link);
-       weston_matrix_init(&shsurf->rotation.rotation);
-
-       shsurf->type = SHELL_SURFACE_NONE;
-
        wl_client_add_resource(client, &shsurf->resource);
 }
 
@@ -739,7 +1407,7 @@ handle_screensaver_sigchld(struct weston_process *proc, int status)
 }
 
 static void
-launch_screensaver(struct wl_shell *shell)
+launch_screensaver(struct desktop_shell *shell)
 {
        if (shell->screensaver.binding)
                return;
@@ -747,6 +1415,11 @@ launch_screensaver(struct wl_shell *shell)
        if (!shell->screensaver.path)
                return;
 
+       if (shell->screensaver.process.pid != 0) {
+               weston_log("old screensaver still running\n");
+               return;
+       }
+
        weston_client_launch(shell->compositor,
                           &shell->screensaver.process,
                           shell->screensaver.path,
@@ -754,7 +1427,7 @@ launch_screensaver(struct wl_shell *shell)
 }
 
 static void
-terminate_screensaver(struct wl_shell *shell)
+terminate_screensaver(struct desktop_shell *shell)
 {
        if (shell->screensaver.process.pid == 0)
                return;
@@ -763,26 +1436,26 @@ terminate_screensaver(struct wl_shell *shell)
 }
 
 static void
-show_screensaver(struct wl_shell *shell, struct shell_surface *surface)
+show_screensaver(struct desktop_shell *shell, struct shell_surface *surface)
 {
        struct wl_list *list;
 
        if (shell->lock_surface)
-               list = &shell->lock_surface->surface->link;
+               list = &shell->lock_surface->surface->layer_link;
        else
-               list = &shell->compositor->surface_list;
+               list = &shell->lock_layer.surface_list;
 
-       wl_list_remove(&surface->surface->link);
-       wl_list_insert(list, &surface->surface->link);
+       wl_list_remove(&surface->surface->layer_link);
+       wl_list_insert(list, &surface->surface->layer_link);
        surface->surface->output = surface->output;
        weston_surface_damage(surface->surface);
 }
 
 static void
-hide_screensaver(struct wl_shell *shell, struct shell_surface *surface)
+hide_screensaver(struct desktop_shell *shell, struct shell_surface *surface)
 {
-       wl_list_remove(&surface->surface->link);
-       wl_list_init(&surface->surface->link);
+       wl_list_remove(&surface->surface->layer_link);
+       wl_list_init(&surface->surface->layer_link);
        surface->surface->output = NULL;
 }
 
@@ -792,36 +1465,15 @@ desktop_shell_set_background(struct wl_client *client,
                             struct wl_resource *output_resource,
                             struct wl_resource *surface_resource)
 {
-       struct wl_shell *shell = resource->data;
        struct shell_surface *shsurf = surface_resource->data;
-       struct weston_surface *surface = shsurf->surface;
-       struct shell_surface *priv;
-
-       if (reset_shell_surface_type(shsurf))
-               return;
-
-       wl_list_for_each(priv, &shell->backgrounds, link) {
-               if (priv->output == output_resource->data) {
-                       priv->surface->output = NULL;
-                       wl_list_remove(&priv->surface->link);
-                       wl_list_remove(&priv->link);
-                       break;
-               }
-       }
 
-       shsurf->type = SHELL_SURFACE_BACKGROUND;
+       shsurf->next_type = SHELL_SURFACE_BACKGROUND;
        shsurf->output = output_resource->data;
 
-       wl_list_insert(&shell->backgrounds, &shsurf->link);
-
-       weston_surface_set_position(surface, shsurf->output->x,
-                                   shsurf->output->y);
-
-       wl_resource_post_event(resource,
-                              DESKTOP_SHELL_CONFIGURE,
-                              weston_compositor_get_time(), 0, surface_resource,
-                              shsurf->output->current->width,
-                              shsurf->output->current->height);
+       desktop_shell_send_configure(resource, 0,
+                                    surface_resource,
+                                    shsurf->output->current->width,
+                                    shsurf->output->current->height);
 }
 
 static void
@@ -830,46 +1482,24 @@ desktop_shell_set_panel(struct wl_client *client,
                        struct wl_resource *output_resource,
                        struct wl_resource *surface_resource)
 {
-       struct wl_shell *shell = resource->data;
        struct shell_surface *shsurf = surface_resource->data;
-       struct weston_surface *surface = shsurf->surface;
-       struct shell_surface *priv;
-
-       if (reset_shell_surface_type(shsurf))
-               return;
 
-       wl_list_for_each(priv, &shell->panels, link) {
-               if (priv->output == output_resource->data) {
-                       priv->surface->output = NULL;
-                       wl_list_remove(&priv->surface->link);
-                       wl_list_remove(&priv->link);
-                       break;
-               }
-       }
-
-       shsurf->type = SHELL_SURFACE_PANEL;
+       shsurf->next_type = SHELL_SURFACE_PANEL;
        shsurf->output = output_resource->data;
 
-       wl_list_insert(&shell->panels, &shsurf->link);
-
-       weston_surface_set_position(surface, shsurf->output->x,
-                                   shsurf->output->y);
-
-       wl_resource_post_event(resource,
-                              DESKTOP_SHELL_CONFIGURE,
-                              weston_compositor_get_time(), 0, surface_resource,
-                              shsurf->output->current->width,
-                              shsurf->output->current->height);
+       desktop_shell_send_configure(resource, 0,
+                                    surface_resource,
+                                    shsurf->output->current->width,
+                                    shsurf->output->current->height);
 }
 
 static void
-handle_lock_surface_destroy(struct wl_listener *listener,
-                           struct wl_resource *resource, uint32_t time)
+handle_lock_surface_destroy(struct wl_listener *listener, void *data)
 {
-       struct wl_shell *shell =
-               container_of(listener, struct wl_shell, lock_surface_listener);
+       struct desktop_shell *shell =
+           container_of(listener, struct desktop_shell, lock_surface_listener);
 
-       fprintf(stderr, "lock surface gone\n");
+       weston_log("lock surface gone\n");
        shell->lock_surface = NULL;
 }
 
@@ -878,12 +1508,9 @@ desktop_shell_set_lock_surface(struct wl_client *client,
                               struct wl_resource *resource,
                               struct wl_resource *surface_resource)
 {
-       struct wl_shell *shell = resource->data;
+       struct desktop_shell *shell = resource->data;
        struct shell_surface *surface = surface_resource->data;
 
-       if (reset_shell_surface_type(surface))
-               return;
-
        shell->prepare_event_sent = false;
 
        if (!shell->locked)
@@ -891,18 +1518,16 @@ desktop_shell_set_lock_surface(struct wl_client *client,
 
        shell->lock_surface = surface;
 
-       shell->lock_surface_listener.func = handle_lock_surface_destroy;
-       wl_list_insert(&surface_resource->destroy_listener_list,
-                      &shell->lock_surface_listener.link);
+       shell->lock_surface_listener.notify = handle_lock_surface_destroy;
+       wl_signal_add(&surface_resource->destroy_signal,
+                     &shell->lock_surface_listener);
 
-       shell->lock_surface->type = SHELL_SURFACE_LOCK;
+       shell->lock_surface->next_type = SHELL_SURFACE_LOCK;
 }
 
 static void
-resume_desktop(struct wl_shell *shell)
+resume_desktop(struct desktop_shell *shell)
 {
-       struct weston_surface *surface;
-       struct wl_list *list;
        struct shell_surface *tmp;
 
        wl_list_for_each(tmp, &shell->screensaver.surfaces, link)
@@ -910,24 +1535,14 @@ resume_desktop(struct wl_shell *shell)
 
        terminate_screensaver(shell);
 
-       wl_list_for_each(surface, &shell->hidden_surface_list, link)
-               weston_surface_assign_output(surface);
-
-       if (wl_list_empty(&shell->backgrounds)) {
-               list = &shell->compositor->surface_list;
-       } else {
-               struct shell_surface *background;
-               background = container_of(shell->backgrounds.prev,
-                                         struct shell_surface, link);
-               list = background->surface->link.prev;
-       }
-
-       if (!wl_list_empty(&shell->hidden_surface_list))
-               wl_list_insert_list(list, &shell->hidden_surface_list);
-       wl_list_init(&shell->hidden_surface_list);
+       wl_list_remove(&shell->lock_layer.link);
+       wl_list_insert(&shell->compositor->cursor_layer.link,
+                      &shell->fullscreen_layer.link);
+       wl_list_insert(&shell->fullscreen_layer.link,
+                      &shell->panel_layer.link);
+       wl_list_insert(&shell->panel_layer.link, &shell->toplevel_layer.link);
 
        shell->locked = false;
-       weston_compositor_repick(shell->compositor);
        shell->compositor->idle_time = shell->compositor->option_idle_time;
        weston_compositor_wake(shell->compositor);
        weston_compositor_damage_all(shell->compositor);
@@ -937,7 +1552,7 @@ static void
 desktop_shell_unlock(struct wl_client *client,
                     struct wl_resource *resource)
 {
-       struct wl_shell *shell = resource->data;
+       struct desktop_shell *shell = resource->data;
 
        shell->prepare_event_sent = false;
 
@@ -945,11 +1560,22 @@ desktop_shell_unlock(struct wl_client *client,
                resume_desktop(shell);
 }
 
+static void
+desktop_shell_set_busy_surface(struct wl_client *client,
+                              struct wl_resource *resource,
+                              struct wl_resource *surface_resource)
+{
+       struct desktop_shell *shell = resource->data;
+
+       shell->busy_surface = surface_resource->data;
+}
+
 static const struct desktop_shell_interface desktop_shell_implementation = {
        desktop_shell_set_background,
        desktop_shell_set_panel,
        desktop_shell_set_lock_surface,
-       desktop_shell_unlock
+       desktop_shell_unlock,
+       desktop_shell_set_busy_surface
 };
 
 static enum shell_surface_type
@@ -964,16 +1590,20 @@ get_shell_surface_type(struct weston_surface *surface)
 }
 
 static void
-move_binding(struct wl_input_device *device, uint32_t time,
-            uint32_t key, uint32_t button, uint32_t state, void *data)
+move_binding(struct wl_seat *seat, uint32_t time, uint32_t button, void *data)
 {
        struct weston_surface *surface =
-               (struct weston_surface *) device->pointer_focus;
+               (struct weston_surface *) seat->pointer->focus;
+       struct shell_surface *shsurf;
 
        if (surface == NULL)
                return;
 
-       switch (get_shell_surface_type(surface)) {
+       shsurf = get_shell_surface(surface);
+       if (shsurf == NULL)
+               return;
+
+       switch (shsurf->type) {
                case SHELL_SURFACE_PANEL:
                case SHELL_SURFACE_BACKGROUND:
                case SHELL_SURFACE_FULLSCREEN:
@@ -983,15 +1613,14 @@ move_binding(struct wl_input_device *device, uint32_t time,
                        break;
        }
 
-       weston_surface_move(surface, (struct weston_input_device *) device, time);
+       surface_move(shsurf, (struct weston_seat *) seat);
 }
 
 static void
-resize_binding(struct wl_input_device *device, uint32_t time,
-              uint32_t key, uint32_t button, uint32_t state, void *data)
+resize_binding(struct wl_seat *seat, uint32_t time, uint32_t button, void *data)
 {
        struct weston_surface *surface =
-               (struct weston_surface *) device->pointer_focus;
+               (struct weston_surface *) seat->pointer->focus;
        uint32_t edges = 0;
        int32_t x, y;
        struct shell_surface *shsurf;
@@ -1014,7 +1643,9 @@ resize_binding(struct wl_input_device *device, uint32_t time,
        }
 
        weston_surface_from_global(surface,
-                                  device->grab_x, device->grab_y, &x, &y);
+                                  wl_fixed_to_int(seat->pointer->grab_x),
+                                  wl_fixed_to_int(seat->pointer->grab_y),
+                                  &x, &y);
 
        if (x < surface->geometry.width / 3)
                edges |= WL_SHELL_SURFACE_RESIZE_LEFT;
@@ -1030,43 +1661,141 @@ resize_binding(struct wl_input_device *device, uint32_t time,
        else
                edges |= WL_SHELL_SURFACE_RESIZE_BOTTOM;
 
-       weston_surface_resize(shsurf, (struct weston_input_device *) device,
-                           time, edges);
+       surface_resize(shsurf, (struct weston_seat *) seat, edges);
+}
+
+static void
+surface_opacity_binding(struct wl_seat *seat, uint32_t time, uint32_t axis,
+                       wl_fixed_t value, void *data)
+{
+       float step = 0.05;
+       struct shell_surface *shsurf;
+       struct weston_surface *surface =
+               (struct weston_surface *) seat->pointer->focus;
+
+       if (surface == NULL)
+               return;
+
+       shsurf = get_shell_surface(surface);
+       if (!shsurf)
+               return;
+
+       switch (shsurf->type) {
+               case SHELL_SURFACE_BACKGROUND:
+               case SHELL_SURFACE_SCREENSAVER:
+                       return;
+               default:
+                       break;
+       }
+
+       surface->alpha += wl_fixed_to_double(value) * step;
+
+       if (surface->alpha > 1.0)
+               surface->alpha = 1.0;
+       if (surface->alpha < step)
+               surface->alpha = step;
+
+       surface->geometry.dirty = 1;
+       weston_surface_damage(surface);
+}
+
+static void
+do_zoom(struct wl_seat *seat, uint32_t time, uint32_t key, uint32_t axis,
+       wl_fixed_t value)
+{
+       struct weston_seat *ws = (struct weston_seat *) seat;
+       struct weston_compositor *compositor = ws->compositor;
+       struct weston_output *output;
+       float maximum_level, increment;
+
+       wl_list_for_each(output, &compositor->output_list, link) {
+               if (pixman_region32_contains_point(&output->region,
+                                                  wl_fixed_to_double(seat->pointer->x),
+                                                  wl_fixed_to_double(seat->pointer->y),
+                                                  NULL)) {
+                       if (key == KEY_PAGEUP)
+                               increment = output->zoom.increment;
+                       else if (key == KEY_PAGEDOWN)
+                               increment = -output->zoom.increment;
+                       else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
+                               increment = output->zoom.increment *
+                                           wl_fixed_to_double(value);
+                       else
+                               increment = 0;
+
+                       output->zoom.active = 1;
+                       output->zoom.level += increment;
+
+                       if (output->zoom.level <= 0.0) {
+                               output->zoom.active = 0;
+                               output->zoom.level = 0.0;
+                       }
+
+                       maximum_level = 1 - output->zoom.increment;
+
+                       if (output->zoom.level > maximum_level)
+                               output->zoom.level = maximum_level;
+
+                       weston_output_update_zoom(output,
+                                                 seat->pointer->x,
+                                                 seat->pointer->y,
+                                                 ZOOM_POINTER);
+               }
+       }
+}
+
+static void
+zoom_axis_binding(struct wl_seat *seat, uint32_t time, uint32_t axis,
+                 wl_fixed_t value, void *data)
+{
+       do_zoom(seat, time, 0, axis, value);
+}
+
+static void
+zoom_key_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
+                void *data)
+{
+       do_zoom(seat, time, key, 0, 0);
 }
 
 static void
-terminate_binding(struct wl_input_device *device, uint32_t time,
-                 uint32_t key, uint32_t button, uint32_t state, void *data)
+terminate_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
+                 void *data)
 {
        struct weston_compositor *compositor = data;
 
-       if (state)
-               wl_display_terminate(compositor->wl_display);
+       wl_display_terminate(compositor->wl_display);
 }
 
 static void
 rotate_grab_motion(struct wl_pointer_grab *grab,
-                uint32_t time, int32_t x, int32_t y)
+                  uint32_t time, wl_fixed_t x, wl_fixed_t y)
 {
        struct rotate_grab *rotate =
-               container_of(grab, struct rotate_grab, grab);
-       struct wl_input_device *device = grab->input_device;
-       struct shell_surface *surface = rotate->surface;
-       GLfloat cx = 0.5f * surface->surface->geometry.width;
-       GLfloat cy = 0.5f * surface->surface->geometry.height;
-       GLfloat dx, dy;
-       GLfloat r;
+               container_of(grab, struct rotate_grab, base.grab);
+       struct wl_pointer *pointer = grab->pointer;
+       struct shell_surface *shsurf = rotate->base.shsurf;
+       struct weston_surface *surface;
+       GLfloat cx, cy, dx, dy, cposx, cposy, dposx, dposy, r;
+
+       if (!shsurf)
+               return;
+
+       surface = shsurf->surface;
+
+       cx = 0.5f * surface->geometry.width;
+       cy = 0.5f * surface->geometry.height;
 
-       dx = device->x - rotate->center.x;
-       dy = device->y - rotate->center.y;
+       dx = wl_fixed_to_double(pointer->x) - rotate->center.x;
+       dy = wl_fixed_to_double(pointer->y) - rotate->center.y;
        r = sqrtf(dx * dx + dy * dy);
 
-       wl_list_remove(&surface->rotation.transform.link);
-       surface->surface->geometry.dirty = 1;
+       wl_list_remove(&shsurf->rotation.transform.link);
+       shsurf->surface->geometry.dirty = 1;
 
        if (r > 20.0f) {
                struct weston_matrix *matrix =
-                       &surface->rotation.transform.matrix;
+                       &shsurf->rotation.transform.matrix;
 
                weston_matrix_init(&rotate->rotation);
                rotate->rotation.d[0] = dx / r;
@@ -1076,38 +1805,54 @@ rotate_grab_motion(struct wl_pointer_grab *grab,
 
                weston_matrix_init(matrix);
                weston_matrix_translate(matrix, -cx, -cy, 0.0f);
-               weston_matrix_multiply(matrix, &surface->rotation.rotation);
+               weston_matrix_multiply(matrix, &shsurf->rotation.rotation);
                weston_matrix_multiply(matrix, &rotate->rotation);
                weston_matrix_translate(matrix, cx, cy, 0.0f);
 
                wl_list_insert(
-                       &surface->surface->geometry.transformation_list,
-                       &surface->rotation.transform.link);
+                       &shsurf->surface->geometry.transformation_list,
+                       &shsurf->rotation.transform.link);
        } else {
-               wl_list_init(&surface->rotation.transform.link);
-               weston_matrix_init(&surface->rotation.rotation);
+               wl_list_init(&shsurf->rotation.transform.link);
+               weston_matrix_init(&shsurf->rotation.rotation);
                weston_matrix_init(&rotate->rotation);
        }
 
+       /* We need to adjust the position of the surface
+        * in case it was resized in a rotated state before */
+       cposx = surface->geometry.x + cx;
+       cposy = surface->geometry.y + cy;
+       dposx = rotate->center.x - cposx;
+       dposy = rotate->center.y - cposy;
+       if (dposx != 0.0f || dposy != 0.0f) {
+               weston_surface_set_position(surface,
+                                           surface->geometry.x + dposx,
+                                           surface->geometry.y + dposy);
+       }
+
        /* Repaint implies weston_surface_update_transform(), which
         * lazily applies the damage due to rotation update.
         */
-       weston_compositor_schedule_repaint(surface->surface->compositor);
+       weston_compositor_schedule_repaint(shsurf->surface->compositor);
 }
 
 static void
 rotate_grab_button(struct wl_pointer_grab *grab,
-                uint32_t time, int32_t button, int32_t state)
+                uint32_t time, uint32_t button, uint32_t state_w)
 {
        struct rotate_grab *rotate =
-               container_of(grab, struct rotate_grab, grab);
-       struct wl_input_device *device = grab->input_device;
-       struct shell_surface *surface = rotate->surface;
-
-       if (device->button_count == 0 && state == 0) {
-               weston_matrix_multiply(&surface->rotation.rotation,
-                                      &rotate->rotation);
-               wl_input_device_end_pointer_grab(device, time);
+               container_of(grab, struct rotate_grab, base.grab);
+       struct wl_pointer *pointer = grab->pointer;
+       struct shell_surface *shsurf = rotate->base.shsurf;
+       enum wl_pointer_button_state state = state_w;
+
+       if (pointer->button_count == 0 &&
+           state == WL_POINTER_BUTTON_STATE_RELEASED) {
+               if (shsurf)
+                       weston_matrix_multiply(&shsurf->rotation.rotation,
+                                              &rotate->rotation);
+               shell_grab_finish(&rotate->base);
+               wl_pointer_end_grab(pointer);
                free(rotate);
        }
 }
@@ -1119,11 +1864,11 @@ static const struct wl_pointer_grab_interface rotate_grab_interface = {
 };
 
 static void
-rotate_binding(struct wl_input_device *device, uint32_t time,
-              uint32_t key, uint32_t button, uint32_t state, void *data)
+rotate_binding(struct wl_seat *seat, uint32_t time, uint32_t button,
+              void *data)
 {
        struct weston_surface *base_surface =
-               (struct weston_surface *) device->pointer_focus;
+               (struct weston_surface *) seat->pointer->focus;
        struct shell_surface *surface;
        struct rotate_grab *rotate;
        GLfloat dx, dy;
@@ -1150,18 +1895,17 @@ rotate_binding(struct wl_input_device *device, uint32_t time,
        if (!rotate)
                return;
 
-       rotate->grab.interface = &rotate_grab_interface;
-       rotate->surface = surface;
+       shell_grab_init(&rotate->base, &rotate_grab_interface, surface);
 
-       weston_surface_to_global(surface->surface,
-                                surface->surface->geometry.width / 2,
-                                surface->surface->geometry.height / 2,
-                                &rotate->center.x, &rotate->center.y);
+       weston_surface_to_global_float(surface->surface,
+                                      surface->surface->geometry.width / 2,
+                                      surface->surface->geometry.height / 2,
+                                      &rotate->center.x, &rotate->center.y);
 
-       wl_input_device_start_pointer_grab(device, &rotate->grab, time);
+       wl_pointer_start_grab(seat->pointer, &rotate->base.grab);
 
-       dx = device->x - rotate->center.x;
-       dy = device->y - rotate->center.y;
+       dx = wl_fixed_to_double(seat->pointer->x) - rotate->center.x;
+       dy = wl_fixed_to_double(seat->pointer->y) - rotate->center.y;
        r = sqrtf(dx * dx + dy * dy);
        if (r > 20.0f) {
                struct weston_matrix inverse;
@@ -1172,110 +1916,129 @@ rotate_binding(struct wl_input_device *device, uint32_t time,
                inverse.d[1] = -inverse.d[4];
                inverse.d[5] = inverse.d[0];
                weston_matrix_multiply(&surface->rotation.rotation, &inverse);
+
+               weston_matrix_init(&rotate->rotation);
+               rotate->rotation.d[0] = dx / r;
+               rotate->rotation.d[4] = -dy / r;
+               rotate->rotation.d[1] = -rotate->rotation.d[4];
+               rotate->rotation.d[5] = rotate->rotation.d[0];
        } else {
                weston_matrix_init(&surface->rotation.rotation);
                weston_matrix_init(&rotate->rotation);
        }
 
-       wl_input_device_set_pointer_focus(device, NULL, time, 0, 0);
+       wl_pointer_set_focus(seat->pointer, NULL,
+                            wl_fixed_from_int(0),
+                            wl_fixed_from_int(0));
 }
 
 static void
-activate(struct weston_shell *base, struct weston_surface *es,
-        struct weston_input_device *device, uint32_t time)
+activate(struct desktop_shell *shell, struct weston_surface *es,
+        struct weston_seat *seat)
 {
-       struct wl_shell *shell = container_of(base, struct wl_shell, shell);
-       struct weston_compositor *compositor = shell->compositor;
-       struct wl_list *list;
+       struct weston_surface *surf, *prev;
 
-       weston_surface_activate(es, device, time);
-
-       if (compositor->wxs)
-               weston_xserver_surface_activate(es);
+       weston_surface_activate(es, seat);
 
        switch (get_shell_surface_type(es)) {
        case SHELL_SURFACE_BACKGROUND:
-               /* put background back to bottom */
-               wl_list_remove(&es->link);
-               wl_list_insert(compositor->surface_list.prev, &es->link);
-               break;
        case SHELL_SURFACE_PANEL:
-               /* already put on top */
+       case SHELL_SURFACE_LOCK:
                break;
+
        case SHELL_SURFACE_SCREENSAVER:
                /* always below lock surface */
-               if (shell->lock_surface) {
-                       wl_list_remove(&es->link);
-                       wl_list_insert(&shell->lock_surface->surface->link,
-                                      &es->link);
-               }
+               if (shell->lock_surface)
+                       weston_surface_restack(es,
+                                              &shell->lock_surface->surface->layer_link);
+               break;
+       case SHELL_SURFACE_FULLSCREEN:
+               /* should on top of panels */
+               shell_stack_fullscreen(get_shell_surface(es));
+               shell_configure_fullscreen(get_shell_surface(es));
                break;
        default:
-               if (!shell->locked) {
-                       list = weston_compositor_top(compositor);
-
-                       /* bring panel back to top */
-                       struct shell_surface *panel;
-                       wl_list_for_each(panel, &shell->panels, link) {
-                               wl_list_remove(&panel->surface->link);
-                               wl_list_insert(list, &panel->surface->link);
-                       }
+               /* move the fullscreen surfaces down into the toplevel layer */
+               if (!wl_list_empty(&shell->fullscreen_layer.surface_list)) {
+                       wl_list_for_each_reverse_safe(surf,
+                                                     prev, 
+                                                     &shell->fullscreen_layer.surface_list, 
+                                                     layer_link)
+                               weston_surface_restack(surf,
+                                                      &shell->toplevel_layer.surface_list); 
                }
+
+               weston_surface_restack(es,
+                                      &shell->toplevel_layer.surface_list);
+               break;
        }
 }
 
+/* no-op func for checking black surface */
 static void
-click_to_activate_binding(struct wl_input_device *device,
-                         uint32_t time, uint32_t key,
-                         uint32_t button, uint32_t state, void *data)
+black_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
 {
-       struct weston_input_device *wd = (struct weston_input_device *) device;
-       struct weston_compositor *compositor = data;
-       struct weston_surface *focus;
+}
 
-       focus = (struct weston_surface *) device->pointer_focus;
-       if (state && focus && device->pointer_grab == &device->default_pointer_grab)
-               activate(compositor->shell, focus, wd, time);
+static bool 
+is_black_surface (struct weston_surface *es, struct weston_surface **fs_surface)
+{
+       if (es->configure == black_surface_configure) {
+               if (fs_surface)
+                       *fs_surface = (struct weston_surface *)es->private;
+               return true;
+       }
+       return false;
 }
 
 static void
-lock(struct weston_shell *base)
+click_to_activate_binding(struct wl_seat *seat, uint32_t time, uint32_t button,
+                         void *data)
 {
-       struct wl_shell *shell = container_of(base, struct wl_shell, shell);
-       struct wl_list *surface_list = &shell->compositor->surface_list;
-       struct weston_surface *cur;
-       struct weston_surface *tmp;
-       struct weston_input_device *device;
-       struct shell_surface *shsurf;
-       uint32_t time;
+       struct weston_seat *ws = (struct weston_seat *) seat;
+       struct desktop_shell *shell = data;
+       struct weston_surface *focus;
+       struct weston_surface *upper;
 
-       if (shell->locked)
+       focus = (struct weston_surface *) seat->pointer->focus;
+       if (!focus)
                return;
 
-       shell->locked = true;
+       if (is_black_surface(focus, &upper))
+               focus = upper;
+
+       if (seat->pointer->grab == &seat->pointer->default_grab)
+               activate(shell, focus, ws);
+}
 
-       /* Move all surfaces from compositor's list to our hidden list,
-        * except the background. This way nothing else can show or
-        * receive input events while we are locked. */
+static void
+lock(struct wl_listener *listener, void *data)
+{
+       struct desktop_shell *shell =
+               container_of(listener, struct desktop_shell, lock_listener);
+       struct weston_seat *seat;
+       struct shell_surface *shsurf;
+       struct weston_output *output;
 
-       if (!wl_list_empty(&shell->hidden_surface_list)) {
-               fprintf(stderr,
-               "%s: Assertion failed: hidden_surface_list is not empty.\n",
-                                                               __func__);
+       if (shell->locked) {
+               wl_list_for_each(output, &shell->compositor->output_list, link)
+                       /* TODO: find a way to jump to other DPMS levels */
+                       if (output->set_dpms)
+                               output->set_dpms(output, WESTON_DPMS_STANDBY);
+               return;
        }
 
-       wl_list_for_each_safe(cur, tmp, surface_list, link) {
-               /* skip input device sprites, cur->surface is uninitialised */
-               if (cur->surface.resource.client == NULL)
-                       continue;
+       shell->locked = true;
 
-               if (get_shell_surface_type(cur) == SHELL_SURFACE_BACKGROUND)
-                       continue;
+       /* Hide all surfaces by removing the fullscreen, panel and
+        * toplevel layers.  This way nothing else can show or receive
+        * input events while we are locked. */
 
-               cur->output = NULL;
-               wl_list_remove(&cur->link);
-               wl_list_insert(shell->hidden_surface_list.prev, &cur->link);
-       }
+       wl_list_remove(&shell->panel_layer.link);
+       wl_list_remove(&shell->toplevel_layer.link);
+       wl_list_remove(&shell->fullscreen_layer.link);
+       wl_list_insert(&shell->compositor->cursor_layer.link,
+                      &shell->lock_layer.link);
 
        launch_screensaver(shell);
 
@@ -1289,13 +2052,11 @@ lock(struct weston_shell *base)
        }
 
        /* reset pointer foci */
-       weston_compositor_repick(shell->compositor);
+       weston_compositor_schedule_repaint(shell->compositor);
 
        /* reset keyboard foci */
-       time = weston_compositor_get_time();
-       wl_list_for_each(device, &shell->compositor->input_device_list, link) {
-               wl_input_device_set_keyboard_focus(&device->input_device,
-                                                  NULL, time);
+       wl_list_for_each(seat, &shell->compositor->seat_list, link) {
+               wl_keyboard_set_focus(seat->seat.keyboard, NULL);
        }
 
        /* TODO: disable bindings that should not work while locked. */
@@ -1304,9 +2065,10 @@ lock(struct weston_shell *base)
 }
 
 static void
-unlock(struct weston_shell *base)
+unlock(struct wl_listener *listener, void *data)
 {
-       struct wl_shell *shell = container_of(base, struct wl_shell, shell);
+       struct desktop_shell *shell =
+               container_of(listener, struct desktop_shell, unlock_listener);
 
        if (!shell->locked || shell->lock_surface) {
                weston_compositor_wake(shell->compositor);
@@ -1322,8 +2084,7 @@ unlock(struct weston_shell *base)
        if (shell->prepare_event_sent)
                return;
 
-       wl_resource_post_event(shell->child.desktop_shell,
-                              DESKTOP_SHELL_PREPARE_LOCK_SURFACE);
+       desktop_shell_send_prepare_lock_surface(shell->child.desktop_shell);
        shell->prepare_event_sent = true;
 }
 
@@ -1338,35 +2099,24 @@ center_on_output(struct weston_surface *surface, struct weston_output *output)
 }
 
 static void
-map(struct weston_shell *base, struct weston_surface *surface,
+map(struct desktop_shell *shell, struct weston_surface *surface,
     int32_t width, int32_t height, int32_t sx, int32_t sy)
 {
-       struct wl_shell *shell = container_of(base, struct wl_shell, shell);
        struct weston_compositor *compositor = shell->compositor;
-       struct wl_list *list;
        struct shell_surface *shsurf;
        enum shell_surface_type surface_type = SHELL_SURFACE_NONE;
-       int do_configure;
+       struct weston_surface *parent;
+       struct weston_seat *seat;
        int panel_height = 0;
 
        shsurf = get_shell_surface(surface);
        if (shsurf)
                surface_type = shsurf->type;
 
-       if (shell->locked) {
-               list = &shell->hidden_surface_list;
-               do_configure = 0;
-       } else {
-               list = weston_compositor_top(compositor);
-               do_configure = 1;
-       }
-
        surface->geometry.width = width;
        surface->geometry.height = height;
        surface->geometry.dirty = 1;
 
-       weston_compositor_update_drag_surfaces(compositor);
-
        /* initial positioning, see also configure() */
        switch (surface_type) {
        case SHELL_SURFACE_TOPLEVEL:
@@ -1374,11 +2124,13 @@ map(struct weston_shell *base, struct weston_surface *surface,
                                            10 + random() % 400);
                break;
        case SHELL_SURFACE_SCREENSAVER:
-       case SHELL_SURFACE_FULLSCREEN:
                center_on_output(surface, shsurf->fullscreen_output);
                break;
+       case SHELL_SURFACE_FULLSCREEN:
+               shell_map_fullscreen(shsurf);
+               break;
        case SHELL_SURFACE_MAXIMIZED:
-               /*use surface configure to set the geometry*/
+               /* use surface configure to set the geometry */
                panel_height = get_output_panel_height(shell,surface->output);
                weston_surface_set_position(surface, surface->output->x,
                                            surface->output->y + panel_height);
@@ -1387,7 +2139,7 @@ map(struct weston_shell *base, struct weston_surface *surface,
                center_on_output(surface, get_default_output(compositor));
                break;
        case SHELL_SURFACE_POPUP:
-               shell_map_popup(shsurf, shsurf->popup.time);
+               shell_map_popup(shsurf);
        case SHELL_SURFACE_NONE:
                weston_surface_set_position(surface,
                                            surface->geometry.x + sx,
@@ -1401,19 +2153,19 @@ map(struct weston_shell *base, struct weston_surface *surface,
        switch (surface_type) {
        case SHELL_SURFACE_BACKGROUND:
                /* background always visible, at the bottom */
-               wl_list_insert(compositor->surface_list.prev, &surface->link);
-               do_configure = 1;
+               wl_list_insert(&shell->background_layer.surface_list,
+                              &surface->layer_link);
                break;
        case SHELL_SURFACE_PANEL:
                /* panel always on top, hidden while locked */
-               wl_list_insert(list, &surface->link);
+               wl_list_insert(&shell->panel_layer.surface_list,
+                              &surface->layer_link);
                break;
        case SHELL_SURFACE_LOCK:
                /* lock surface always visible, on top */
-               wl_list_insert(&compositor->surface_list, &surface->link);
-
+               wl_list_insert(&shell->lock_layer.surface_list,
+                              &surface->layer_link);
                weston_compositor_wake(compositor);
-               do_configure = 1;
                break;
        case SHELL_SURFACE_SCREENSAVER:
                /* If locked, show it. */
@@ -1424,53 +2176,63 @@ map(struct weston_shell *base, struct weston_surface *surface,
                        if (!shell->lock_surface)
                                compositor->state = WESTON_COMPOSITOR_IDLE;
                }
-               do_configure = 0;
                break;
+       case SHELL_SURFACE_POPUP:
+       case SHELL_SURFACE_TRANSIENT:
+               parent = shsurf->parent->surface;
+               wl_list_insert(parent->layer_link.prev, &surface->layer_link);
+               break;
+       case SHELL_SURFACE_FULLSCREEN:
        case SHELL_SURFACE_NONE:
                break;
        default:
-               /* everything else just below the panel */
-               if (!wl_list_empty(&shell->panels)) {
-                       struct shell_surface *panel =
-                               container_of(shell->panels.prev,
-                                            struct shell_surface, link);
-                       wl_list_insert(&panel->surface->link, &surface->link);
-               } else {
-                       wl_list_insert(list, &surface->link);
-               }
+               wl_list_insert(&shell->toplevel_layer.surface_list,
+                              &surface->layer_link); 
+               break;
        }
 
-       if (do_configure) {
+       if (surface_type != SHELL_SURFACE_NONE) {
                weston_surface_assign_output(surface);
-               weston_compositor_repick(compositor);
                if (surface_type == SHELL_SURFACE_MAXIMIZED)
                        surface->output = shsurf->output;
        }
 
        switch (surface_type) {
-       case SHELL_SURFACE_TOPLEVEL:
        case SHELL_SURFACE_TRANSIENT:
+               if (shsurf->transient.flags ==
+                               WL_SHELL_SURFACE_TRANSIENT_INACTIVE)
+                       break;
+       case SHELL_SURFACE_TOPLEVEL:
        case SHELL_SURFACE_FULLSCREEN:
        case SHELL_SURFACE_MAXIMIZED:
-               if (!shell->locked)
-                       activate(base, surface,
-                                (struct weston_input_device *)
-                                       compositor->input_device,
-                                weston_compositor_get_time());
+               if (!shell->locked) {
+                       wl_list_for_each(seat, &compositor->seat_list, link)
+                               activate(shell, surface, seat);
+               }
                break;
        default:
                break;
        }
 
        if (surface_type == SHELL_SURFACE_TOPLEVEL)
-               weston_zoom_run(surface, 0.8, 1.0, NULL, NULL);
+       {
+               switch (shell->win_animation_type) {
+               case ANIMATION_FADE:
+                       weston_fade_run(surface, NULL, NULL);
+                       break;
+               case ANIMATION_ZOOM:
+                       weston_zoom_run(surface, 0.8, 1.0, NULL, NULL);
+                       break;
+               default:
+                       break;
+               }
+       }
 }
 
 static void
-configure(struct weston_shell *base, struct weston_surface *surface,
+configure(struct desktop_shell *shell, struct weston_surface *surface,
          GLfloat x, GLfloat y, int32_t width, int32_t height)
 {
-       struct wl_shell *shell = container_of(base, struct wl_shell, shell);
        enum shell_surface_type surface_type = SHELL_SURFACE_NONE;
        struct shell_surface *shsurf;
 
@@ -1486,20 +2248,25 @@ configure(struct weston_shell *base, struct weston_surface *surface,
 
        switch (surface_type) {
        case SHELL_SURFACE_SCREENSAVER:
-       case SHELL_SURFACE_FULLSCREEN:
                center_on_output(surface, shsurf->fullscreen_output);
                break;
+       case SHELL_SURFACE_FULLSCREEN:
+               shell_stack_fullscreen(shsurf);
+               shell_configure_fullscreen(shsurf);
+               break;
        case SHELL_SURFACE_MAXIMIZED:
-               /*setting x, y and using configure to change that geometry*/
+               /* setting x, y and using configure to change that geometry */
                surface->geometry.x = surface->output->x;
                surface->geometry.y = surface->output->y +
                        get_output_panel_height(shell,surface->output);
                break;
+       case SHELL_SURFACE_TOPLEVEL:
+               break;
        default:
                break;
        }
 
-       /*  XXX: would a fullscreen surface need the same handling? */
+       /* XXX: would a fullscreen surface need the same handling? */
        if (surface->output) {
                weston_surface_assign_output(surface);
 
@@ -1510,14 +2277,44 @@ configure(struct weston_shell *base, struct weston_surface *surface,
        }
 }
 
-static int launch_desktop_shell_process(struct wl_shell *shell);
+static void
+shell_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
+{
+       struct shell_surface *shsurf = get_shell_surface(es);
+       struct desktop_shell *shell = shsurf->shell;
+       int type_changed = 0;
+
+       if (shsurf->next_type != SHELL_SURFACE_NONE &&
+           shsurf->type != shsurf->next_type) {
+               set_surface_type(shsurf);
+               type_changed = 1;
+       }
+
+       if (!weston_surface_is_mapped(es)) {
+               map(shell, es, es->buffer->width, es->buffer->height, sx, sy);
+       } else if (type_changed || sx != 0 || sy != 0 ||
+                  es->geometry.width != es->buffer->width ||
+                  es->geometry.height != es->buffer->height) {
+               GLfloat from_x, from_y;
+               GLfloat to_x, to_y;
+
+               weston_surface_to_global_float(es, 0, 0, &from_x, &from_y);
+               weston_surface_to_global_float(es, sx, sy, &to_x, &to_y);
+               configure(shell, es,
+                         es->geometry.x + to_x - from_x,
+                         es->geometry.y + to_y - from_y,
+                         es->buffer->width, es->buffer->height);
+       }
+}
+
+static int launch_desktop_shell_process(struct desktop_shell *shell);
 
 static void
 desktop_shell_sigchld(struct weston_process *process, int status)
 {
        uint32_t time;
-       struct wl_shell *shell =
-               container_of(process, struct wl_shell, child.process);
+       struct desktop_shell *shell =
+               container_of(process, struct desktop_shell, child.process);
 
        shell->child.process.pid = 0;
        shell->child.client = NULL; /* already destroyed by wayland */
@@ -1531,16 +2328,16 @@ desktop_shell_sigchld(struct weston_process *process, int status)
 
        shell->child.deathcount++;
        if (shell->child.deathcount > 5) {
-               fprintf(stderr, "weston-desktop-shell died, giving up.\n");
+               weston_log("weston-desktop-shell died, giving up.\n");
                return;
        }
 
-       fprintf(stderr, "weston-desktop-shell died, respawning...\n");
+       weston_log("weston-desktop-shell died, respawning...\n");
        launch_desktop_shell_process(shell);
 }
 
 static int
-launch_desktop_shell_process(struct wl_shell *shell)
+launch_desktop_shell_process(struct desktop_shell *shell)
 {
        const char *shell_exe = LIBEXECDIR "/weston-desktop-shell";
 
@@ -1557,7 +2354,7 @@ launch_desktop_shell_process(struct wl_shell *shell)
 static void
 bind_shell(struct wl_client *client, void *data, uint32_t version, uint32_t id)
 {
-       struct wl_shell *shell = data;
+       struct desktop_shell *shell = data;
 
        wl_client_add_object(client, &wl_shell_interface,
                             &shell_implementation, id, shell);
@@ -1566,7 +2363,7 @@ bind_shell(struct wl_client *client, void *data, uint32_t version, uint32_t id)
 static void
 unbind_desktop_shell(struct wl_resource *resource)
 {
-       struct wl_shell *shell = resource->data;
+       struct desktop_shell *shell = resource->data;
 
        if (shell->locked)
                resume_desktop(shell);
@@ -1580,7 +2377,7 @@ static void
 bind_desktop_shell(struct wl_client *client,
                   void *data, uint32_t version, uint32_t id)
 {
-       struct wl_shell *shell = data;
+       struct desktop_shell *shell = data;
        struct wl_resource *resource;
 
        resource = wl_client_add_object(client, &desktop_shell_interface,
@@ -1595,7 +2392,7 @@ bind_desktop_shell(struct wl_client *client,
 
        wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
                               "permission to bind desktop_shell denied");
-       wl_resource_destroy(resource, 0);
+       wl_resource_destroy(resource);
 }
 
 static void
@@ -1604,14 +2401,11 @@ screensaver_set_surface(struct wl_client *client,
                        struct wl_resource *shell_surface_resource,
                        struct wl_resource *output_resource)
 {
-       struct wl_shell *shell = resource->data;
+       struct desktop_shell *shell = resource->data;
        struct shell_surface *surface = shell_surface_resource->data;
        struct weston_output *output = output_resource->data;
 
-       if (reset_shell_surface_type(surface))
-               return;
-
-       surface->type = SHELL_SURFACE_SCREENSAVER;
+       surface->next_type = SHELL_SURFACE_SCREENSAVER;
 
        surface->fullscreen_output = output;
        surface->output = output;
@@ -1625,7 +2419,7 @@ static const struct screensaver_interface screensaver_implementation = {
 static void
 unbind_screensaver(struct wl_resource *resource)
 {
-       struct wl_shell *shell = resource->data;
+       struct desktop_shell *shell = resource->data;
 
        shell->screensaver.binding = NULL;
        free(resource);
@@ -1635,7 +2429,7 @@ static void
 bind_screensaver(struct wl_client *client,
                 void *data, uint32_t version, uint32_t id)
 {
-       struct wl_shell *shell = data;
+       struct desktop_shell *shell = data;
        struct wl_resource *resource;
 
        resource = wl_client_add_object(client, &screensaver_interface,
@@ -1650,11 +2444,11 @@ bind_screensaver(struct wl_client *client,
 
        wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
                               "interface object already bound");
-       wl_resource_destroy(resource, 0);
+       wl_resource_destroy(resource);
 }
 
 struct switcher {
-       struct weston_compositor *compositor;
+       struct desktop_shell *shell;
        struct weston_surface *current;
        struct wl_listener listener;
        struct wl_keyboard_grab grab;
@@ -1663,15 +2457,12 @@ struct switcher {
 static void
 switcher_next(struct switcher *switcher)
 {
-       struct weston_compositor *compositor = switcher->compositor;
+       struct weston_compositor *compositor = switcher->shell->compositor;
        struct weston_surface *surface;
        struct weston_surface *first = NULL, *prev = NULL, *next = NULL;
+       struct shell_surface *shsurf;
 
        wl_list_for_each(surface, &compositor->surface_list, link) {
-               /* Workaround for cursor surfaces. */
-               if (surface->surface.resource.destroy_listener_list.next == NULL)
-                       continue;
-
                switch (get_shell_surface_type(surface)) {
                case SHELL_SURFACE_TOPLEVEL:
                case SHELL_SURFACE_FULLSCREEN:
@@ -1681,28 +2472,41 @@ switcher_next(struct switcher *switcher)
                        if (prev == switcher->current)
                                next = surface;
                        prev = surface;
-                       surface->alpha = 64;
+                       surface->alpha = 0.25;
+                       surface->geometry.dirty = 1;
                        weston_surface_damage(surface);
                        break;
                default:
                        break;
                }
+
+               if (is_black_surface(surface, NULL)) {
+                       surface->alpha = 0.25;
+                       surface->geometry.dirty = 1;
+                       weston_surface_damage(surface);
+               }
        }
 
        if (next == NULL)
                next = first;
 
+       if (next == NULL)
+               return;
+
        wl_list_remove(&switcher->listener.link);
-       wl_list_insert(next->surface.resource.destroy_listener_list.prev,
-                      &switcher->listener.link);
+       wl_signal_add(&next->surface.resource.destroy_signal,
+                     &switcher->listener);
 
        switcher->current = next;
-       next->alpha = 255;
+       next->alpha = 1.0;
+
+       shsurf = get_shell_surface(switcher->current);
+       if (shsurf && shsurf->type ==SHELL_SURFACE_FULLSCREEN)
+               shsurf->fullscreen.black_surface->alpha = 1.0;
 }
 
 static void
-switcher_handle_surface_destroy(struct wl_listener *listener,
-                               struct wl_resource *resource, uint32_t time)
+switcher_handle_surface_destroy(struct wl_listener *listener, void *data)
 {
        struct switcher *switcher =
                container_of(listener, struct switcher, listener);
@@ -1711,81 +2515,224 @@ switcher_handle_surface_destroy(struct wl_listener *listener,
 }
 
 static void
-switcher_destroy(struct switcher *switcher, uint32_t time)
+switcher_destroy(struct switcher *switcher)
 {
-       struct weston_compositor *compositor = switcher->compositor;
+       struct weston_compositor *compositor = switcher->shell->compositor;
        struct weston_surface *surface;
-       struct weston_input_device *device =
-               (struct weston_input_device *) switcher->grab.input_device;
+       struct wl_keyboard *keyboard = switcher->grab.keyboard;
 
        wl_list_for_each(surface, &compositor->surface_list, link) {
-               surface->alpha = 255;
+               surface->alpha = 1.0;
                weston_surface_damage(surface);
        }
 
-       activate(compositor->shell, switcher->current, device, time);
+       if (switcher->current)
+               activate(switcher->shell, switcher->current,
+                        (struct weston_seat *) keyboard->seat);
        wl_list_remove(&switcher->listener.link);
-       wl_input_device_end_keyboard_grab(&device->input_device, time);
+       wl_keyboard_end_grab(keyboard);
        free(switcher);
 }
 
 static void
 switcher_key(struct wl_keyboard_grab *grab,
-            uint32_t time, uint32_t key, int32_t state)
+            uint32_t time, uint32_t key, uint32_t state_w)
 {
        struct switcher *switcher = container_of(grab, struct switcher, grab);
-       struct weston_input_device *device =
-               (struct weston_input_device *) grab->input_device;
+       enum wl_keyboard_key_state state = state_w;
 
-       if ((device->modifier_state & MODIFIER_SUPER) == 0) {
-               switcher_destroy(switcher, time);
-       } else if (key == KEY_TAB && state) {
+       if (key == KEY_TAB && state == WL_KEYBOARD_KEY_STATE_PRESSED)
                switcher_next(switcher);
-       }
-};
+}
+
+static void
+switcher_modifier(struct wl_keyboard_grab *grab, uint32_t serial,
+                 uint32_t mods_depressed, uint32_t mods_latched,
+                 uint32_t mods_locked, uint32_t group)
+{
+       struct switcher *switcher = container_of(grab, struct switcher, grab);
+       struct weston_seat *seat = (struct weston_seat *) grab->keyboard->seat;
+
+       if ((seat->modifier_state & switcher->shell->binding_modifier) == 0)
+               switcher_destroy(switcher);
+}
 
 static const struct wl_keyboard_grab_interface switcher_grab = {
-       switcher_key
+       switcher_key,
+       switcher_modifier,
 };
 
 static void
-switcher_binding(struct wl_input_device *device, uint32_t time,
-                uint32_t key, uint32_t button,
-                uint32_t state, void *data)
+switcher_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
+                void *data)
 {
-       struct weston_compositor *compositor = data;
+       struct desktop_shell *shell = data;
        struct switcher *switcher;
 
        switcher = malloc(sizeof *switcher);
-       switcher->compositor = compositor;
+       switcher->shell = shell;
        switcher->current = NULL;
-       switcher->listener.func = switcher_handle_surface_destroy;
+       switcher->listener.notify = switcher_handle_surface_destroy;
        wl_list_init(&switcher->listener.link);
 
        switcher->grab.interface = &switcher_grab;
-       wl_input_device_start_keyboard_grab(device, &switcher->grab, time);
+       wl_keyboard_start_grab(seat->keyboard, &switcher->grab);
+       wl_keyboard_set_focus(seat->keyboard, NULL);
        switcher_next(switcher);
 }
 
 static void
-shell_destroy(struct weston_shell *base)
+backlight_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
+                 void *data)
+{
+       struct weston_compositor *compositor = data;
+       struct weston_output *output;
+       long backlight_new = 0;
+
+       /* TODO: we're limiting to simple use cases, where we assume just
+        * control on the primary display. We'd have to extend later if we
+        * ever get support for setting backlights on random desktop LCD
+        * panels though */
+       output = get_default_output(compositor);
+       if (!output)
+               return;
+
+       if (!output->set_backlight)
+               return;
+
+       if (key == KEY_F9 || key == KEY_BRIGHTNESSDOWN)
+               backlight_new = output->backlight_current - 25;
+       else if (key == KEY_F10 || key == KEY_BRIGHTNESSUP)
+               backlight_new = output->backlight_current + 25;
+
+       if (backlight_new < 5)
+               backlight_new = 5;
+       if (backlight_new > 255)
+               backlight_new = 255;
+
+       output->backlight_current = backlight_new;
+       output->set_backlight(output, output->backlight_current);
+}
+
+static void
+debug_repaint_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
+                     void *data)
+{
+       struct desktop_shell *shell = data;
+       struct weston_compositor *compositor = shell->compositor;
+       struct weston_surface *surface;
+
+       if (shell->debug_repaint_surface) {
+               weston_surface_destroy(shell->debug_repaint_surface);
+               shell->debug_repaint_surface = NULL;
+       } else {
+               surface = weston_surface_create(compositor);
+               weston_surface_set_color(surface, 1.0, 0.0, 0.0, 0.2);
+               weston_surface_configure(surface, 0, 0, 8192, 8192);
+               wl_list_insert(&compositor->fade_layer.surface_list,
+                              &surface->layer_link);
+               weston_surface_assign_output(surface);
+               pixman_region32_init(&surface->input);
+
+               /* Here's the dirty little trick that makes the
+                * repaint debugging work: we force an
+                * update_transform first to update dependent state
+                * and clear the geometry.dirty bit.  Then we clear
+                * the surface damage so it only gets repainted
+                * piecewise as we repaint other things.  */
+
+               weston_surface_update_transform(surface);
+               pixman_region32_fini(&surface->damage);
+               pixman_region32_init(&surface->damage);
+               shell->debug_repaint_surface = surface;
+       }
+}
+
+static void
+force_kill_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
+                  void *data)
+{
+       struct wl_client *client;
+       pid_t pid;
+       uid_t uid;
+       gid_t gid;
+
+       client = seat->keyboard->focus->resource.client;
+       wl_client_get_credentials(client, &pid, &uid, &gid);
+
+       kill(pid, SIGKILL);
+}
+
+static void
+shell_destroy(struct wl_listener *listener, void *data)
 {
-       struct wl_shell *shell = container_of(base, struct wl_shell, shell);
+       struct desktop_shell *shell =
+               container_of(listener, struct desktop_shell, destroy_listener);
 
        if (shell->child.client)
                wl_client_destroy(shell->child.client);
 
+       wl_list_remove(&shell->lock_listener.link);
+       wl_list_remove(&shell->unlock_listener.link);
+
        free(shell->screensaver.path);
        free(shell);
 }
 
+static void
+shell_add_bindings(struct weston_compositor *ec, struct desktop_shell *shell)
+{
+       uint32_t mod;
+
+       /* fixed bindings */
+       weston_compositor_add_key_binding(ec, KEY_BACKSPACE,
+                                         MODIFIER_CTRL | MODIFIER_ALT,
+                                         terminate_binding, ec);
+       weston_compositor_add_button_binding(ec, BTN_LEFT, 0,
+                                            click_to_activate_binding,
+                                            shell);
+       weston_compositor_add_axis_binding(ec, WL_POINTER_AXIS_VERTICAL_SCROLL,
+                                          MODIFIER_SUPER | MODIFIER_ALT,
+                                          surface_opacity_binding, NULL);
+       weston_compositor_add_axis_binding(ec, WL_POINTER_AXIS_VERTICAL_SCROLL,
+                                          MODIFIER_SUPER, zoom_axis_binding,
+                                          NULL);
+
+       /* configurable bindings */
+       mod = shell->binding_modifier;
+       weston_compositor_add_key_binding(ec, KEY_PAGEUP, mod,
+                                         zoom_key_binding, NULL);
+       weston_compositor_add_key_binding(ec, KEY_PAGEDOWN, mod,
+                                         zoom_key_binding, NULL);
+       weston_compositor_add_button_binding(ec, BTN_LEFT, mod, move_binding,
+                                            shell);
+       weston_compositor_add_button_binding(ec, BTN_MIDDLE, mod,
+                                            resize_binding, shell);
+       weston_compositor_add_button_binding(ec, BTN_RIGHT, mod,
+                                            rotate_binding, NULL);
+       weston_compositor_add_key_binding(ec, KEY_TAB, mod, switcher_binding,
+                                         shell);
+       weston_compositor_add_key_binding(ec, KEY_F9, mod, backlight_binding,
+                                         ec);
+       weston_compositor_add_key_binding(ec, KEY_BRIGHTNESSDOWN, 0,
+                                         backlight_binding, ec);
+       weston_compositor_add_key_binding(ec, KEY_F10, mod, backlight_binding,
+                                         ec);
+       weston_compositor_add_key_binding(ec, KEY_BRIGHTNESSUP, 0,
+                                         backlight_binding, ec);
+       weston_compositor_add_key_binding(ec, KEY_SPACE, mod,
+                                         debug_repaint_binding, shell);
+       weston_compositor_add_key_binding(ec, KEY_K, mod,
+                                         force_kill_binding, shell);
+}
+
 int
 shell_init(struct weston_compositor *ec);
 
 WL_EXPORT int
 shell_init(struct weston_compositor *ec)
 {
-       struct wl_shell *shell;
+       struct desktop_shell *shell;
 
        shell = malloc(sizeof *shell);
        if (shell == NULL)
@@ -1793,17 +2740,31 @@ shell_init(struct weston_compositor *ec)
 
        memset(shell, 0, sizeof *shell);
        shell->compositor = ec;
-       shell->shell.lock = lock;
-       shell->shell.unlock = unlock;
-       shell->shell.map = map;
-       shell->shell.configure = configure;
-       shell->shell.destroy = shell_destroy;
 
-       wl_list_init(&shell->hidden_surface_list);
+       shell->destroy_listener.notify = shell_destroy;
+       wl_signal_add(&ec->destroy_signal, &shell->destroy_listener);
+       shell->lock_listener.notify = lock;
+       wl_signal_add(&ec->lock_signal, &shell->lock_listener);
+       shell->unlock_listener.notify = unlock;
+       wl_signal_add(&ec->unlock_signal, &shell->unlock_listener);
+       ec->ping_handler = ping_handler;
+       ec->shell_interface.create_shell_surface = create_shell_surface;
+       ec->shell_interface.set_toplevel = set_toplevel;
+       ec->shell_interface.set_transient = set_transient;
+       ec->shell_interface.move = surface_move;
+       ec->shell_interface.resize = surface_resize;
+
        wl_list_init(&shell->backgrounds);
        wl_list_init(&shell->panels);
        wl_list_init(&shell->screensaver.surfaces);
 
+       weston_layer_init(&shell->fullscreen_layer, &ec->cursor_layer.link);
+       weston_layer_init(&shell->panel_layer, &shell->fullscreen_layer.link);
+       weston_layer_init(&shell->toplevel_layer, &shell->panel_layer.link);
+       weston_layer_init(&shell->background_layer,
+                         &shell->toplevel_layer.link);
+       wl_list_init(&shell->lock_layer.surface_list);
+
        shell_configuration(shell);
 
        if (wl_display_add_global(ec->wl_display, &wl_shell_interface,
@@ -1823,23 +2784,12 @@ shell_init(struct weston_compositor *ec)
        if (launch_desktop_shell_process(shell) != 0)
                return -1;
 
-       weston_compositor_add_binding(ec, 0, BTN_LEFT, MODIFIER_SUPER,
-                                   move_binding, shell);
-       weston_compositor_add_binding(ec, 0, BTN_MIDDLE, MODIFIER_SUPER,
-                                   resize_binding, shell);
-       weston_compositor_add_binding(ec, KEY_BACKSPACE, 0,
-                                   MODIFIER_CTRL | MODIFIER_ALT,
-                                   terminate_binding, ec);
-       weston_compositor_add_binding(ec, 0, BTN_LEFT, 0,
-                                   click_to_activate_binding, ec);
-       weston_compositor_add_binding(ec, 0, BTN_LEFT,
-                                     MODIFIER_SUPER | MODIFIER_ALT,
-                                     rotate_binding, NULL);
-
-       weston_compositor_add_binding(ec, KEY_TAB, 0, MODIFIER_SUPER,
-                                     switcher_binding, ec);
-
-       ec->shell = &shell->shell;
+       shell->pointer_focus_listener.notify = handle_pointer_focus;
+       if (ec->seat->seat.pointer)
+               wl_signal_add(&ec->seat->seat.pointer->focus_signal,
+                             &shell->pointer_focus_listener);
+
+       shell_add_bindings(ec, shell);
 
        return 0;
 }