<div dir="ltr">This is cool, but are we sure we want it?<br><br>From the "Clarifying scope and goals for weston" mail sent by Kristian [1]:<div><br>"The desktop shell in weston serves three goals: to validate wl_shell<br>
protocol, to make weston do something useful when you start it up, and<br>to provide a reference for how to implement a shell module.  The<br>desktop shell is not supposed to be a generally useful desktop<br>environment.  When we're implementing something for the weston desktop<br>
shell, we go for simplicity and protocol coverage rather than full<br>configurability or external dependencies."</div><div><br></div><div>It seems to me this Exposay is out of scope, and adds a quite big amount of code</div>
<div>to shell.c, which is already quite big and complex to understand. If anything, i think</div><div>it should go in a separate file.<br><br>[1] <a href="http://lists.freedesktop.org/archives/wayland-devel/2013-April/008659.html">http://lists.freedesktop.org/archives/wayland-devel/2013-April/008659.html</a></div>
</div><div class="gmail_extra"><br><br><div class="gmail_quote">2013/7/3 Tomeu Vizoso <span dir="ltr"><<a href="mailto:tomeu@tomeuvizoso.net" target="_blank">tomeu@tomeuvizoso.net</a>></span><br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
From: Daniel Stone <<a href="mailto:daniel@fooishbar.org">daniel@fooishbar.org</a>><br>
<br>
Exposay provides window overview functions which, when a key which<br>
produces the binding modifier is pressed on its own, scales all<br>
currently-open windows down to be shown overlaid on the desktop,<br>
providing keyboard and mouse navigation to be able to switch window<br>
focus.<br>
<br>
Signed-off-by: Daniel Stone <<a href="mailto:daniel@fooishbar.org">daniel@fooishbar.org</a>><br>
---<br>
 src/shell.c | 574 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++<br>
 1 file changed, 574 insertions(+)<br>
<br>
diff --git a/src/shell.c b/src/shell.c<br>
index 80b3e8b..cadcb55 100644<br>
--- a/src/shell.c<br>
+++ b/src/shell.c<br>
@@ -1,6 +1,7 @@<br>
 /*<br>
  * Copyright © 2010-2012 Intel Corporation<br>
  * Copyright © 2011-2012 Collabora, Ltd.<br>
+ * Copyright © 2013 Raspberry Pi Foundation<br>
  *<br>
  * Permission to use, copy, modify, distribute, and sell this software and<br>
  * its documentation for any purpose is hereby granted without fee, provided<br>
@@ -57,6 +58,19 @@ enum fade_type {<br>
        FADE_OUT<br>
 };<br>
<br>
+enum exposay_target_state {<br>
+       EXPOSAY_TARGET_OVERVIEW, /* show all windows */<br>
+       EXPOSAY_TARGET_CANCEL, /* return to normal, same focus */<br>
+       EXPOSAY_TARGET_SWITCH, /* return to normal, switch focus */<br>
+};<br>
+<br>
+enum exposay_layout_state {<br>
+       EXPOSAY_LAYOUT_INACTIVE = 0, /* normal desktop */<br>
+       EXPOSAY_LAYOUT_ANIMATE_TO_INACTIVE, /* in transition to normal */<br>
+       EXPOSAY_LAYOUT_OVERVIEW, /* show all windows */<br>
+       EXPOSAY_LAYOUT_ANIMATE_TO_OVERVIEW, /* in transition to all windows */<br>
+};<br>
+<br>
 struct focus_state {<br>
        struct weston_seat *seat;<br>
        struct workspace *ws;<br>
@@ -184,6 +198,34 @@ struct desktop_shell {<br>
                struct wl_event_source *startup_timer;<br>
        } fade;<br>
<br>
+       struct exposay {<br>
+               /* XXX: Make these exposay_surfaces. */<br>
+               struct weston_surface *focus_prev;<br>
+               struct weston_surface *focus_current;<br>
+               struct weston_surface *clicked;<br>
+               struct workspace *workspace;<br>
+               struct weston_seat *seat;<br>
+               struct wl_list surface_list;<br>
+<br>
+               struct weston_keyboard_grab grab_kbd;<br>
+               struct weston_pointer_grab grab_ptr;<br>
+<br>
+                enum exposay_target_state state_target;<br>
+                enum exposay_layout_state state_cur;<br>
+               int in_flight; /* number of animations still running */<br>
+<br>
+               int num_surfaces;<br>
+               int grid_size;<br>
+               int surface_size;<br>
+<br>
+               int hpadding_outer;<br>
+               int vpadding_outer;<br>
+               int padding_inner;<br>
+<br>
+               int row_current;<br>
+               int column_current;<br>
+       } exposay;<br>
+<br>
        uint32_t binding_modifier;<br>
        enum animation_type win_animation_type;<br>
        enum animation_type focus_animation_type;<br>
@@ -4289,6 +4331,533 @@ switcher_binding(struct weston_seat *seat, uint32_t time, uint32_t key,<br>
        switcher_next(switcher);<br>
 }<br>
<br>
+struct exposay_surface {<br>
+       struct desktop_shell *shell;<br>
+       struct weston_surface *surface;<br>
+       struct wl_list link;<br>
+<br>
+       int x;<br>
+       int y;<br>
+       int width;<br>
+       int height;<br>
+       double scale;<br>
+<br>
+       int row;<br>
+       int column;<br>
+<br>
+       /* The animations only apply a transformation for their own lifetime,<br>
+        * and don't have an option to indefinitely maintain the<br>
+        * transformation in a steady state - so, we apply our own once the<br>
+        * animation has finished. */<br>
+       struct weston_transform transform;<br>
+};<br>
+<br>
+static void exposay_set_state(struct desktop_shell *shell,<br>
+                              enum exposay_target_state state,<br>
+                             struct weston_seat *seat);<br>
+static void exposay_check_state(struct desktop_shell *shell);<br>
+<br>
+static void<br>
+exposay_in_flight_inc(struct desktop_shell *shell)<br>
+{<br>
+       shell->exposay.in_flight++;<br>
+}<br>
+<br>
+static void<br>
+exposay_in_flight_dec(struct desktop_shell *shell)<br>
+{<br>
+       if (--shell->exposay.in_flight > 0)<br>
+               return;<br>
+<br>
+       exposay_check_state(shell);<br>
+}<br>
+<br>
+static void<br>
+exposay_animate_in_done(struct weston_surface_animation *animation, void *data)<br>
+{<br>
+       struct exposay_surface *esurface = data;<br>
+<br>
+       wl_list_insert(&esurface->surface->geometry.transformation_list,<br>
+                      &esurface->transform.link);<br>
+       weston_matrix_init(&esurface->transform.matrix);<br>
+       weston_matrix_scale(&esurface->transform.matrix,<br>
+                           esurface->scale, esurface->scale, 1.0f);<br>
+       weston_matrix_translate(&esurface->transform.matrix,<br>
+                               esurface->x - esurface->surface->geometry.x,<br>
+                               esurface->y - esurface->surface->geometry.y,<br>
+                               0);<br>
+<br>
+       weston_surface_geometry_dirty(esurface->surface);<br>
+       weston_compositor_schedule_repaint(esurface->surface->compositor);<br>
+<br>
+       exposay_in_flight_dec(esurface->shell);<br>
+}<br>
+<br>
+static void<br>
+exposay_animate_in(struct exposay_surface *esurface)<br>
+{<br>
+       exposay_in_flight_inc(esurface->shell);<br>
+<br>
+       weston_move_scale_run(esurface->surface,<br>
+                             esurface->x - esurface->surface->geometry.x,<br>
+                             esurface->y - esurface->surface->geometry.y,<br>
+                             1.0, esurface->scale, 0,<br>
+                             exposay_animate_in_done, esurface);<br>
+}<br>
+<br>
+static void<br>
+exposay_animate_out_done(struct weston_surface_animation *animation, void *data)<br>
+{<br>
+       struct exposay_surface *esurface = data;<br>
+       struct desktop_shell *shell = esurface->shell;<br>
+<br>
+       wl_list_remove(&esurface->link);<br>
+       free(esurface);<br>
+<br>
+       exposay_in_flight_dec(shell);<br>
+}<br>
+<br>
+static void<br>
+exposay_animate_out(struct exposay_surface *esurface)<br>
+{<br>
+       exposay_in_flight_inc(esurface->shell);<br>
+<br>
+       /* Remove the static transformation set up by<br>
+        * exposay_transform_in_done(). */<br>
+       wl_list_remove(&esurface->transform.link);<br>
+       weston_surface_geometry_dirty(esurface->surface);<br>
+<br>
+       weston_move_scale_run(esurface->surface,<br>
+                             esurface->x - esurface->surface->geometry.x,<br>
+                             esurface->y - esurface->surface->geometry.y,<br>
+                             1.0, esurface->scale, 1,<br>
+                             exposay_animate_out_done, esurface);<br>
+}<br>
+<br>
+static void<br>
+exposay_highlight_surface(struct desktop_shell *shell,<br>
+                          struct exposay_surface *esurface)<br>
+{<br>
+       struct weston_surface *ws = NULL;<br>
+<br>
+       if (esurface) {<br>
+               shell->exposay.row_current = esurface->row;<br>
+               shell->exposay.column_current = esurface->column;<br>
+               ws = esurface->surface;<br>
+       }<br>
+<br>
+       animate_focus_change(shell, shell->exposay.workspace,<br>
+                            shell->exposay.focus_current, ws);<br>
+       shell->exposay.focus_current = ws;<br>
+}<br>
+<br>
+static int<br>
+exposay_is_animating(struct desktop_shell *shell)<br>
+{<br>
+       if (shell->exposay.state_cur == EXPOSAY_LAYOUT_INACTIVE ||<br>
+           shell->exposay.state_cur == EXPOSAY_LAYOUT_OVERVIEW)<br>
+               return 0;<br>
+<br>
+       return (shell->exposay.in_flight > 0);<br>
+}<br>
+<br>
+static void<br>
+exposay_pick(struct desktop_shell *shell, int x, int y)<br>
+{<br>
+       struct exposay_surface *esurface;<br>
+<br>
+        if (exposay_is_animating(shell))<br>
+            return;<br>
+<br>
+       wl_list_for_each(esurface, &shell->exposay.surface_list, link) {<br>
+               if (x < esurface->x || x > esurface->x + esurface->width)<br>
+                       continue;<br>
+               if (y < esurface->y || y > esurface->y + esurface->height)<br>
+                       continue;<br>
+<br>
+               exposay_highlight_surface(shell, esurface);<br>
+               return;<br>
+       }<br>
+}<br>
+<br>
+/* Pretty lame layout for now; just tries to make a square.  Should take<br>
+ * aspect ratio into account really.  Also needs to be notified of surface<br>
+ * addition and removal and adjust layout/animate accordingly. */<br>
+static enum exposay_layout_state<br>
+exposay_layout(struct desktop_shell *shell)<br>
+{<br>
+       struct workspace *workspace = shell->exposay.workspace;<br>
+       struct weston_compositor *compositor = shell->compositor;<br>
+       struct weston_output *output = get_default_output(compositor);<br>
+       struct weston_surface *ws;<br>
+       struct exposay_surface *esurface;<br>
+       int w, h;<br>
+       int i;<br>
+       int last_row_removed = 0;<br>
+<br>
+       wl_list_init(&shell->exposay.surface_list);<br>
+<br>
+       shell->exposay.num_surfaces = 0;<br>
+       wl_list_for_each(ws, &workspace->layer.surface_list, layer_link) {<br>
+               if (!get_shell_surface(ws))<br>
+                       continue;<br>
+               shell->exposay.num_surfaces++;<br>
+       }<br>
+<br>
+       if (shell->exposay.num_surfaces == 0) {<br>
+               shell->exposay.grid_size = 0;<br>
+               shell->exposay.hpadding_outer = 0;<br>
+               shell->exposay.vpadding_outer = 0;<br>
+               shell->exposay.padding_inner = 0;<br>
+               shell->exposay.surface_size = 0;<br>
+               return EXPOSAY_LAYOUT_OVERVIEW;<br>
+       }<br>
+<br>
+       /* Lay the grid out as square as possible, losing surfaces from the<br>
+        * bottom row if required.  Start with fixed padding of a 10% margin<br>
+        * around the outside and 80px internal padding between surfaces, and<br>
+        * maximise the area made available to surfaces after this, but only<br>
+        * to a maximum of 1/3rd the total output size.<br>
+        *<br>
+        * If we can't make a square grid, add one extra row at the bottom<br>
+        * which will have a smaller number of columns.<br>
+        *<br>
+        * XXX: Surely there has to be a better way to express this maths,<br>
+        *      right?!<br>
+        */<br>
+       shell->exposay.grid_size = floor(sqrtf(shell->exposay.num_surfaces));<br>
+       if (pow(shell->exposay.grid_size, 2) != shell->exposay.num_surfaces)<br>
+               shell->exposay.grid_size++;<br>
+       last_row_removed = pow(shell->exposay.grid_size, 2) - shell->exposay.num_surfaces;<br>
+<br>
+       shell->exposay.hpadding_outer = (output->width / 10);<br>
+       shell->exposay.vpadding_outer = (output->height / 10);<br>
+       shell->exposay.padding_inner = 80;<br>
+<br>
+       w = output->width - (shell->exposay.hpadding_outer * 2);<br>
+       w -= shell->exposay.padding_inner * (shell->exposay.grid_size - 1);<br>
+       w /= shell->exposay.grid_size;<br>
+<br>
+       h = output->height - (shell->exposay.vpadding_outer * 2);<br>
+       h -= shell->exposay.padding_inner * (shell->exposay.grid_size - 1);<br>
+       h /= shell->exposay.grid_size;<br>
+<br>
+       shell->exposay.surface_size = (w < h) ? w : h;<br>
+       if (shell->exposay.surface_size > (output->width / 2))<br>
+               shell->exposay.surface_size = output->width / 2;<br>
+       if (shell->exposay.surface_size > (output->height / 2))<br>
+               shell->exposay.surface_size = output->height / 2;<br>
+<br>
+       i = 0;<br>
+       wl_list_for_each(ws, &workspace->layer.surface_list, layer_link) {<br>
+               int pad;<br>
+<br>
+               pad = shell->exposay.surface_size + shell->exposay.padding_inner;<br>
+<br>
+               if (!get_shell_surface(ws))<br>
+                       continue;<br>
+<br>
+               esurface = malloc(sizeof(*esurface));<br>
+               if (!esurface) {<br>
+                       exposay_set_state(shell, EXPOSAY_TARGET_CANCEL,<br>
+                                         shell->exposay.seat);<br>
+                       break;<br>
+               }<br>
+<br>
+               wl_list_insert(&shell->exposay.surface_list, &esurface->link);<br>
+               esurface->shell = shell;<br>
+               esurface->surface = ws;<br>
+<br>
+               esurface->row = i / shell->exposay.grid_size;<br>
+               esurface->column = i % shell->exposay.grid_size;<br>
+<br>
+               esurface->x = shell->exposay.hpadding_outer;<br>
+               esurface->x += pad * esurface->column;<br>
+               esurface->y = shell->exposay.vpadding_outer;<br>
+               esurface->y += pad * esurface->row;<br>
+<br>
+               if (esurface->row == shell->exposay.grid_size - 1)<br>
+                       esurface->x += (shell->exposay.surface_size + shell->exposay.padding_inner) * last_row_removed / 2;<br>
+<br>
+               if (ws->geometry.width > ws->geometry.height)<br>
+                       esurface->scale = shell->exposay.surface_size / (float) ws->geometry.width;<br>
+               else<br>
+                       esurface->scale = shell->exposay.surface_size / (float) ws->geometry.height;<br>
+               esurface->width = ws->geometry.width * esurface->scale;<br>
+               esurface->height = ws->geometry.height * esurface->scale;<br>
+<br>
+               if (shell->exposay.focus_current == esurface->surface)<br>
+                       exposay_highlight_surface(shell, esurface);<br>
+<br>
+               exposay_animate_in(esurface);<br>
+<br>
+               i++;<br>
+       }<br>
+<br>
+       weston_compositor_schedule_repaint(shell->compositor);<br>
+<br>
+       return EXPOSAY_LAYOUT_ANIMATE_TO_OVERVIEW;<br>
+}<br>
+<br>
+static void<br>
+exposay_motion(struct weston_pointer_grab *grab, uint32_t time)<br>
+{<br>
+       struct desktop_shell *shell =<br>
+               container_of(grab, struct desktop_shell, exposay.grab_ptr);<br>
+<br>
+       exposay_pick(shell,<br>
+                    wl_fixed_to_int(grab->pointer->x),<br>
+                    wl_fixed_to_int(grab->pointer->y));<br>
+}<br>
+<br>
+static void<br>
+exposay_button(struct weston_pointer_grab *grab, uint32_t time, uint32_t button,<br>
+               uint32_t state_w)<br>
+{<br>
+       struct desktop_shell *shell =<br>
+               container_of(grab, struct desktop_shell, exposay.grab_ptr);<br>
+       struct weston_seat *seat = grab->pointer->seat;<br>
+       enum wl_pointer_button_state state = state_w;<br>
+<br>
+       if (button != BTN_LEFT)<br>
+               return;<br>
+<br>
+       /* Store the surface we clicked on, and don't do anything if we end up<br>
+        * releasing on a different surface. */<br>
+       if (state == WL_POINTER_BUTTON_STATE_PRESSED) {<br>
+               shell->exposay.clicked = shell->exposay.focus_current;<br>
+               return;<br>
+       }<br>
+<br>
+       if (shell->exposay.focus_current == shell->exposay.clicked)<br>
+               exposay_set_state(shell, EXPOSAY_TARGET_SWITCH, seat);<br>
+       else<br>
+               shell->exposay.clicked = NULL;<br>
+}<br>
+<br>
+static const struct weston_pointer_grab_interface exposay_ptr_grab = {<br>
+       noop_grab_focus,<br>
+       exposay_motion,<br>
+       exposay_button,<br>
+};<br>
+<br>
+static int<br>
+exposay_maybe_move(struct desktop_shell *shell, int row, int column)<br>
+{<br>
+       struct exposay_surface *esurface;<br>
+<br>
+       wl_list_for_each(esurface, &shell->exposay.surface_list, link) {<br>
+               if (esurface->row != row || esurface->column != column)<br>
+                       continue;<br>
+<br>
+               exposay_highlight_surface(shell, esurface);<br>
+               return 1;<br>
+       }<br>
+<br>
+       return 0;<br>
+}<br>
+<br>
+static void<br>
+exposay_key(struct weston_keyboard_grab *grab, uint32_t time, uint32_t key,<br>
+            uint32_t state_w)<br>
+{<br>
+       struct weston_seat *seat = grab->keyboard->seat;<br>
+       struct desktop_shell *shell =<br>
+               container_of(grab, struct desktop_shell, exposay.grab_kbd);<br>
+       enum wl_keyboard_key_state state = state_w;<br>
+<br>
+       if (state != WL_KEYBOARD_KEY_STATE_RELEASED)<br>
+               return;<br>
+<br>
+       switch (key) {<br>
+       case KEY_ESC:<br>
+               exposay_set_state(shell, EXPOSAY_TARGET_CANCEL, seat);<br>
+               break;<br>
+       case KEY_ENTER:<br>
+               exposay_set_state(shell, EXPOSAY_TARGET_SWITCH, seat);<br>
+               break;<br>
+       case KEY_UP:<br>
+               exposay_maybe_move(shell, shell->exposay.row_current - 1,<br>
+                                  shell->exposay.column_current);<br>
+               break;<br>
+       case KEY_DOWN:<br>
+               /* Special case for trying to move to the bottom row when it<br>
+                * has fewer items than all the others. */<br>
+               if (!exposay_maybe_move(shell, shell->exposay.row_current + 1,<br>
+                                       shell->exposay.column_current) &&<br>
+                   shell->exposay.row_current < (shell->exposay.grid_size - 1)) {<br>
+                       exposay_maybe_move(shell, shell->exposay.row_current + 1,<br>
+                                          (shell->exposay.num_surfaces %<br>
+                                           shell->exposay.grid_size) - 1);<br>
+               }<br>
+               break;<br>
+       case KEY_LEFT:<br>
+               exposay_maybe_move(shell, shell->exposay.row_current,<br>
+                                  shell->exposay.column_current - 1);<br>
+               break;<br>
+       case KEY_RIGHT:<br>
+               exposay_maybe_move(shell, shell->exposay.row_current,<br>
+                                  shell->exposay.column_current + 1);<br>
+               break;<br>
+       case KEY_TAB:<br>
+               /* Try to move right, then down (and to the leftmost column),<br>
+                * then if all else fails, to the top left. */<br>
+               if (!exposay_maybe_move(shell, shell->exposay.row_current,<br>
+                                       shell->exposay.column_current + 1) &&<br>
+                   !exposay_maybe_move(shell, shell->exposay.row_current + 1, 0))<br>
+                       exposay_maybe_move(shell, 0, 0);<br>
+               break;<br>
+       default:<br>
+               break;<br>
+       }<br>
+}<br>
+<br>
+static void<br>
+exposay_modifier(struct weston_keyboard_grab *grab, uint32_t serial,<br>
+                 uint32_t mods_depressed, uint32_t mods_latched,<br>
+                 uint32_t mods_locked, uint32_t group)<br>
+{<br>
+}<br>
+<br>
+static const struct weston_keyboard_grab_interface exposay_kbd_grab = {<br>
+       exposay_key,<br>
+       exposay_modifier,<br>
+};<br>
+<br>
+/**<br>
+ * Called when the transition from overview -> inactive has completed.<br>
+ */<br>
+static enum exposay_layout_state<br>
+exposay_set_inactive(struct desktop_shell *shell)<br>
+{<br>
+       struct weston_seat *seat = shell->exposay.seat;<br>
+<br>
+       weston_keyboard_end_grab(seat->keyboard);<br>
+       weston_pointer_end_grab(seat->pointer);<br>
+       if (seat->keyboard->input_method_resource)<br>
+               seat->keyboard->grab = &seat->keyboard->input_method_grab;<br>
+<br>
+       return EXPOSAY_LAYOUT_INACTIVE;<br>
+}<br>
+<br>
+/**<br>
+ * Begins the transition from overview to inactive. */<br>
+static enum exposay_layout_state<br>
+exposay_transition_inactive(struct desktop_shell *shell, int switch_focus)<br>
+{<br>
+       struct exposay_surface *esurface;<br>
+<br>
+       /* Call activate() before we start the animations to avoid<br>
+        * animating back the old state and then immediately transitioning<br>
+        * to the new. */<br>
+       if (switch_focus && shell->exposay.focus_current)<br>
+               activate(shell, shell->exposay.focus_current,<br>
+                        shell->exposay.seat);<br>
+       else if (shell->exposay.focus_prev)<br>
+               activate(shell, shell->exposay.focus_prev,<br>
+                        shell->exposay.seat);<br>
+<br>
+       wl_list_for_each(esurface, &shell->exposay.surface_list, link)<br>
+               exposay_animate_out(esurface);<br>
+       weston_compositor_schedule_repaint(shell->compositor);<br>
+<br>
+       return EXPOSAY_LAYOUT_ANIMATE_TO_INACTIVE;<br>
+}<br>
+<br>
+static enum exposay_layout_state<br>
+exposay_transition_active(struct desktop_shell *shell)<br>
+{<br>
+       struct weston_seat *seat = shell->exposay.seat;<br>
+<br>
+       shell->exposay.workspace = get_current_workspace(shell);<br>
+       shell->exposay.focus_prev = seat->keyboard->focus;<br>
+       shell->exposay.focus_current = seat->keyboard->focus;<br>
+       shell->exposay.clicked = NULL;<br>
+       wl_list_init(&shell->exposay.surface_list);<br>
+<br>
+       lower_fullscreen_layer(shell);<br>
+       shell->exposay.grab_kbd.interface = &exposay_kbd_grab;<br>
+       weston_keyboard_start_grab(seat->keyboard,<br>
+                                  &shell->exposay.grab_kbd);<br>
+       weston_keyboard_set_focus(seat->keyboard, NULL);<br>
+<br>
+       shell->exposay.grab_ptr.interface = &exposay_ptr_grab;<br>
+       weston_pointer_start_grab(seat->pointer,<br>
+                                 &shell->exposay.grab_ptr);<br>
+       weston_pointer_set_focus(seat->pointer, NULL,<br>
+                                seat->pointer->x, seat->pointer->y);<br>
+<br>
+       return exposay_layout(shell);<br>
+}<br>
+<br>
+static void<br>
+exposay_check_state(struct desktop_shell *shell)<br>
+{<br>
+       enum exposay_layout_state state_new = shell->exposay.state_cur;<br>
+       int do_switch = 0;<br>
+<br>
+       /* Don't do anything whilst animations are running, just store up<br>
+        * target state changes and only act on them when the animations have<br>
+        * completed. */<br>
+       if (exposay_is_animating(shell))<br>
+               return;<br>
+<br>
+       switch (shell->exposay.state_target) {<br>
+       case EXPOSAY_TARGET_OVERVIEW:<br>
+               switch (shell->exposay.state_cur) {<br>
+               case EXPOSAY_LAYOUT_OVERVIEW:<br>
+                       goto out;<br>
+               case EXPOSAY_LAYOUT_ANIMATE_TO_OVERVIEW:<br>
+                       state_new = EXPOSAY_LAYOUT_OVERVIEW;<br>
+                       break;<br>
+               default:<br>
+                       state_new = exposay_transition_active(shell);<br>
+                       break;<br>
+               }<br>
+               break;<br>
+<br>
+       case EXPOSAY_TARGET_SWITCH:<br>
+               do_switch = 1; /* fallthrough */<br>
+       case EXPOSAY_TARGET_CANCEL:<br>
+               switch (shell->exposay.state_cur) {<br>
+               case EXPOSAY_LAYOUT_INACTIVE:<br>
+                       goto out;<br>
+               case EXPOSAY_LAYOUT_ANIMATE_TO_INACTIVE:<br>
+                       state_new = exposay_set_inactive(shell);<br>
+                       break;<br>
+               default:<br>
+                       state_new = exposay_transition_inactive(shell, do_switch);<br>
+                       break;<br>
+               }<br>
+<br>
+               break;<br>
+       }<br>
+<br>
+out:<br>
+       shell->exposay.state_cur = state_new;<br>
+}<br>
+<br>
+static void<br>
+exposay_set_state(struct desktop_shell *shell, enum exposay_target_state state,<br>
+                  struct weston_seat *seat)<br>
+{<br>
+       shell->exposay.state_target = state;<br>
+       shell->exposay.seat = seat;<br>
+       exposay_check_state(shell);<br>
+}<br>
+<br>
+static void<br>
+exposay_binding(struct weston_seat *seat, enum weston_keyboard_modifier modifier,<br>
+               void *data)<br>
+{<br>
+       struct desktop_shell *shell = data;<br>
+<br>
+       if (shell->exposay.state_target == EXPOSAY_TARGET_OVERVIEW)<br>
+               exposay_set_state(shell, EXPOSAY_TARGET_CANCEL, seat);<br>
+       else<br>
+               exposay_set_state(shell, EXPOSAY_TARGET_OVERVIEW, seat);<br>
+}<br>
+<br>
 static void<br>
 backlight_binding(struct weston_seat *seat, uint32_t time, uint32_t key,<br>
                  void *data)<br>
@@ -4731,6 +5300,8 @@ shell_add_bindings(struct weston_compositor *ec, struct desktop_shell *shell)<br>
                                          workspace_move_surface_down_binding,<br>
                                          shell);<br>
<br>
+       weston_compositor_add_modifier_binding(ec, mod, exposay_binding, shell);<br>
+<br>
        /* Add bindings for mod+F[1-6] for workspace 1 to 6. */<br>
        if (shell->workspaces.num > 1) {<br>
                num_workspace_bindings = shell->workspaces.num;<br>
@@ -4802,6 +5373,9 @@ module_init(struct weston_compositor *ec,<br>
<br>
        shell_configuration(shell);<br>
<br>
+       shell->exposay.state_cur = EXPOSAY_LAYOUT_INACTIVE;<br>
+       shell->exposay.state_target = EXPOSAY_TARGET_CANCEL;<br>
+<br>
        for (i = 0; i < shell->workspaces.num; i++) {<br>
                pws = wl_array_add(&shell->workspaces.array, sizeof *pws);<br>
                if (pws == NULL)<br>
<span class="HOEnZb"><font color="#888888">--<br>
1.8.3.1<br>
<br>
_______________________________________________<br>
wayland-devel mailing list<br>
<a href="mailto:wayland-devel@lists.freedesktop.org">wayland-devel@lists.freedesktop.org</a><br>
<a href="http://lists.freedesktop.org/mailman/listinfo/wayland-devel" target="_blank">http://lists.freedesktop.org/mailman/listinfo/wayland-devel</a><br>
</font></span></blockquote></div><br></div>