blob: b7e32c9a9c07113ca4984a7d3e2b7b4bf513e779 [file] [log] [blame]
Kristian Høgsberg1ef23132013-12-04 00:20:01 -08001/*
2 * Copyright © 2010-2012 Intel Corporation
3 * Copyright © 2011-2012 Collabora, Ltd.
4 * Copyright © 2013 Raspberry Pi Foundation
5 *
6 * Permission to use, copy, modify, distribute, and sell this software and
7 * its documentation for any purpose is hereby granted without fee, provided
8 * that the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of the copyright holders not be used in
11 * advertising or publicity pertaining to distribution of the software
12 * without specific, written prior permission. The copyright holders make
13 * no representations about the suitability of this software for any
14 * purpose. It is provided "as is" without express or implied warranty.
15 *
16 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
17 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
18 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
20 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
21 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
22 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 */
24
25#include "config.h"
26
27#include <linux/input.h>
28
29#include "shell.h"
30
31struct exposay_surface {
32 struct desktop_shell *shell;
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +010033 struct exposay_output *eoutput;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -080034 struct weston_surface *surface;
35 struct weston_view *view;
36 struct wl_list link;
37
38 int x;
39 int y;
40 int width;
41 int height;
42 double scale;
43
44 int row;
45 int column;
46
47 /* The animations only apply a transformation for their own lifetime,
48 * and don't have an option to indefinitely maintain the
49 * transformation in a steady state - so, we apply our own once the
50 * animation has finished. */
51 struct weston_transform transform;
52};
53
54static void exposay_set_state(struct desktop_shell *shell,
55 enum exposay_target_state state,
56 struct weston_seat *seat);
57static void exposay_check_state(struct desktop_shell *shell);
58
59static void
60exposay_in_flight_inc(struct desktop_shell *shell)
61{
62 shell->exposay.in_flight++;
63}
64
65static void
66exposay_in_flight_dec(struct desktop_shell *shell)
67{
68 if (--shell->exposay.in_flight > 0)
69 return;
70
71 exposay_check_state(shell);
72}
73
74static void
75exposay_animate_in_done(struct weston_view_animation *animation, void *data)
76{
77 struct exposay_surface *esurface = data;
78
79 wl_list_insert(&esurface->view->geometry.transformation_list,
80 &esurface->transform.link);
81 weston_matrix_init(&esurface->transform.matrix);
82 weston_matrix_scale(&esurface->transform.matrix,
83 esurface->scale, esurface->scale, 1.0f);
84 weston_matrix_translate(&esurface->transform.matrix,
85 esurface->x - esurface->view->geometry.x,
86 esurface->y - esurface->view->geometry.y,
87 0);
88
89 weston_view_geometry_dirty(esurface->view);
90 weston_compositor_schedule_repaint(esurface->view->surface->compositor);
91
92 exposay_in_flight_dec(esurface->shell);
93}
94
95static void
96exposay_animate_in(struct exposay_surface *esurface)
97{
98 exposay_in_flight_inc(esurface->shell);
99
100 weston_move_scale_run(esurface->view,
101 esurface->x - esurface->view->geometry.x,
102 esurface->y - esurface->view->geometry.y,
103 1.0, esurface->scale, 0,
104 exposay_animate_in_done, esurface);
105}
106
107static void
108exposay_animate_out_done(struct weston_view_animation *animation, void *data)
109{
110 struct exposay_surface *esurface = data;
111 struct desktop_shell *shell = esurface->shell;
112
113 wl_list_remove(&esurface->link);
114 free(esurface);
115
116 exposay_in_flight_dec(shell);
117}
118
119static void
120exposay_animate_out(struct exposay_surface *esurface)
121{
122 exposay_in_flight_inc(esurface->shell);
123
124 /* Remove the static transformation set up by
125 * exposay_transform_in_done(). */
126 wl_list_remove(&esurface->transform.link);
127 weston_view_geometry_dirty(esurface->view);
128
129 weston_move_scale_run(esurface->view,
130 esurface->x - esurface->view->geometry.x,
131 esurface->y - esurface->view->geometry.y,
132 1.0, esurface->scale, 1,
133 exposay_animate_out_done, esurface);
134}
135
136static void
137exposay_highlight_surface(struct desktop_shell *shell,
138 struct exposay_surface *esurface)
139{
U. Artie Eoff6d6d1902014-01-15 13:42:18 -0800140 struct weston_view *view = esurface->view;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800141
U. Artie Eoff6d6d1902014-01-15 13:42:18 -0800142 shell->exposay.row_current = esurface->row;
143 shell->exposay.column_current = esurface->column;
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100144 shell->exposay.cur_output = esurface->eoutput;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800145
146 activate(shell, view->surface, shell->exposay.seat);
147 shell->exposay.focus_current = view;
148}
149
150static int
151exposay_is_animating(struct desktop_shell *shell)
152{
153 if (shell->exposay.state_cur == EXPOSAY_LAYOUT_INACTIVE ||
154 shell->exposay.state_cur == EXPOSAY_LAYOUT_OVERVIEW)
155 return 0;
156
157 return (shell->exposay.in_flight > 0);
158}
159
160static void
161exposay_pick(struct desktop_shell *shell, int x, int y)
162{
163 struct exposay_surface *esurface;
164
165 if (exposay_is_animating(shell))
166 return;
167
168 wl_list_for_each(esurface, &shell->exposay.surface_list, link) {
169 if (x < esurface->x || x > esurface->x + esurface->width)
170 continue;
171 if (y < esurface->y || y > esurface->y + esurface->height)
172 continue;
173
174 exposay_highlight_surface(shell, esurface);
175 return;
176 }
177}
178
179/* Pretty lame layout for now; just tries to make a square. Should take
180 * aspect ratio into account really. Also needs to be notified of surface
181 * addition and removal and adjust layout/animate accordingly. */
182static enum exposay_layout_state
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100183exposay_layout(struct desktop_shell *shell, struct shell_output *shell_output)
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800184{
185 struct workspace *workspace = shell->exposay.workspace;
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100186 struct weston_output *output = shell_output->output;
187 struct exposay_output *eoutput = &shell_output->eoutput;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800188 struct weston_view *view;
Emilio Pozuelo Monforte6bbe5a2014-01-07 16:41:39 +0100189 struct exposay_surface *esurface, *highlight = NULL;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800190 int w, h;
191 int i;
192 int last_row_removed = 0;
193
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100194 eoutput->num_surfaces = 0;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800195 wl_list_for_each(view, &workspace->layer.view_list, layer_link) {
196 if (!get_shell_surface(view->surface))
197 continue;
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100198 if (view->output != output)
199 continue;
200 eoutput->num_surfaces++;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800201 }
202
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100203 if (eoutput->num_surfaces == 0) {
204 eoutput->grid_size = 0;
205 eoutput->hpadding_outer = 0;
206 eoutput->vpadding_outer = 0;
207 eoutput->padding_inner = 0;
208 eoutput->surface_size = 0;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800209 return EXPOSAY_LAYOUT_OVERVIEW;
210 }
211
212 /* Lay the grid out as square as possible, losing surfaces from the
213 * bottom row if required. Start with fixed padding of a 10% margin
214 * around the outside and 80px internal padding between surfaces, and
215 * maximise the area made available to surfaces after this, but only
216 * to a maximum of 1/3rd the total output size.
217 *
218 * If we can't make a square grid, add one extra row at the bottom
219 * which will have a smaller number of columns.
220 *
221 * XXX: Surely there has to be a better way to express this maths,
222 * right?!
223 */
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100224 eoutput->grid_size = floor(sqrtf(eoutput->num_surfaces));
225 if (pow(eoutput->grid_size, 2) != eoutput->num_surfaces)
226 eoutput->grid_size++;
227 last_row_removed = pow(eoutput->grid_size, 2) - eoutput->num_surfaces;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800228
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100229 eoutput->hpadding_outer = (output->width / 10);
230 eoutput->vpadding_outer = (output->height / 10);
231 eoutput->padding_inner = 80;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800232
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100233 w = output->width - (eoutput->hpadding_outer * 2);
234 w -= eoutput->padding_inner * (eoutput->grid_size - 1);
235 w /= eoutput->grid_size;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800236
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100237 h = output->height - (eoutput->vpadding_outer * 2);
238 h -= eoutput->padding_inner * (eoutput->grid_size - 1);
239 h /= eoutput->grid_size;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800240
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100241 eoutput->surface_size = (w < h) ? w : h;
242 if (eoutput->surface_size > (output->width / 2))
243 eoutput->surface_size = output->width / 2;
244 if (eoutput->surface_size > (output->height / 2))
245 eoutput->surface_size = output->height / 2;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800246
247 i = 0;
248 wl_list_for_each(view, &workspace->layer.view_list, layer_link) {
249 int pad;
250
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100251 pad = eoutput->surface_size + eoutput->padding_inner;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800252
253 if (!get_shell_surface(view->surface))
254 continue;
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100255 if (view->output != output)
256 continue;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800257
258 esurface = malloc(sizeof(*esurface));
259 if (!esurface) {
260 exposay_set_state(shell, EXPOSAY_TARGET_CANCEL,
261 shell->exposay.seat);
262 break;
263 }
264
265 wl_list_insert(&shell->exposay.surface_list, &esurface->link);
266 esurface->shell = shell;
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100267 esurface->eoutput = eoutput;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800268 esurface->view = view;
269
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100270 esurface->row = i / eoutput->grid_size;
271 esurface->column = i % eoutput->grid_size;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800272
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100273 esurface->x = output->x + eoutput->hpadding_outer;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800274 esurface->x += pad * esurface->column;
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100275 esurface->y = output->y + eoutput->vpadding_outer;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800276 esurface->y += pad * esurface->row;
277
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100278 if (esurface->row == eoutput->grid_size - 1)
279 esurface->x += (eoutput->surface_size + eoutput->padding_inner) * last_row_removed / 2;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800280
281 if (view->surface->width > view->surface->height)
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100282 esurface->scale = eoutput->surface_size / (float) view->surface->width;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800283 else
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100284 esurface->scale = eoutput->surface_size / (float) view->surface->height;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800285 esurface->width = view->surface->width * esurface->scale;
286 esurface->height = view->surface->height * esurface->scale;
287
288 if (shell->exposay.focus_current == esurface->view)
Emilio Pozuelo Monforte6bbe5a2014-01-07 16:41:39 +0100289 highlight = esurface;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800290
Emilio Pozuelo Monfort1a26f1b2014-01-07 16:41:40 +0100291 set_alpha_if_fullscreen(get_shell_surface(view->surface));
292
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800293 exposay_animate_in(esurface);
294
295 i++;
296 }
297
Emilio Pozuelo Monforte6bbe5a2014-01-07 16:41:39 +0100298 if (highlight)
299 exposay_highlight_surface(shell, highlight);
300
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800301 weston_compositor_schedule_repaint(shell->compositor);
302
303 return EXPOSAY_LAYOUT_ANIMATE_TO_OVERVIEW;
304}
305
306static void
307exposay_focus(struct weston_pointer_grab *grab)
308{
309}
310
311static void
312exposay_motion(struct weston_pointer_grab *grab, uint32_t time,
313 wl_fixed_t x, wl_fixed_t y)
314{
315 struct desktop_shell *shell =
316 container_of(grab, struct desktop_shell, exposay.grab_ptr);
317
318 weston_pointer_move(grab->pointer, x, y);
319
320 exposay_pick(shell,
321 wl_fixed_to_int(grab->pointer->x),
322 wl_fixed_to_int(grab->pointer->y));
323}
324
325static void
326exposay_button(struct weston_pointer_grab *grab, uint32_t time, uint32_t button,
327 uint32_t state_w)
328{
329 struct desktop_shell *shell =
330 container_of(grab, struct desktop_shell, exposay.grab_ptr);
331 struct weston_seat *seat = grab->pointer->seat;
332 enum wl_pointer_button_state state = state_w;
333
334 if (button != BTN_LEFT)
335 return;
336
337 /* Store the surface we clicked on, and don't do anything if we end up
338 * releasing on a different surface. */
339 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
340 shell->exposay.clicked = shell->exposay.focus_current;
341 return;
342 }
343
344 if (shell->exposay.focus_current == shell->exposay.clicked)
345 exposay_set_state(shell, EXPOSAY_TARGET_SWITCH, seat);
346 else
347 shell->exposay.clicked = NULL;
348}
349
350static void
351exposay_pointer_grab_cancel(struct weston_pointer_grab *grab)
352{
353 struct desktop_shell *shell =
354 container_of(grab, struct desktop_shell, exposay.grab_ptr);
355
356 exposay_set_state(shell, EXPOSAY_TARGET_CANCEL, shell->exposay.seat);
357}
358
359static const struct weston_pointer_grab_interface exposay_ptr_grab = {
360 exposay_focus,
361 exposay_motion,
362 exposay_button,
363 exposay_pointer_grab_cancel,
364};
365
366static int
367exposay_maybe_move(struct desktop_shell *shell, int row, int column)
368{
369 struct exposay_surface *esurface;
370
371 wl_list_for_each(esurface, &shell->exposay.surface_list, link) {
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100372 if (esurface->eoutput != shell->exposay.cur_output ||
373 esurface->row != row || esurface->column != column)
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800374 continue;
375
376 exposay_highlight_surface(shell, esurface);
377 return 1;
378 }
379
380 return 0;
381}
382
383static void
384exposay_key(struct weston_keyboard_grab *grab, uint32_t time, uint32_t key,
385 uint32_t state_w)
386{
387 struct weston_seat *seat = grab->keyboard->seat;
388 struct desktop_shell *shell =
389 container_of(grab, struct desktop_shell, exposay.grab_kbd);
390 enum wl_keyboard_key_state state = state_w;
391
392 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
393 return;
394
395 switch (key) {
396 case KEY_ESC:
397 exposay_set_state(shell, EXPOSAY_TARGET_CANCEL, seat);
398 break;
399 case KEY_ENTER:
400 exposay_set_state(shell, EXPOSAY_TARGET_SWITCH, seat);
401 break;
402 case KEY_UP:
403 exposay_maybe_move(shell, shell->exposay.row_current - 1,
404 shell->exposay.column_current);
405 break;
406 case KEY_DOWN:
407 /* Special case for trying to move to the bottom row when it
408 * has fewer items than all the others. */
409 if (!exposay_maybe_move(shell, shell->exposay.row_current + 1,
410 shell->exposay.column_current) &&
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100411 shell->exposay.row_current < (shell->exposay.cur_output->grid_size - 1)) {
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800412 exposay_maybe_move(shell, shell->exposay.row_current + 1,
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100413 (shell->exposay.cur_output->num_surfaces %
414 shell->exposay.cur_output->grid_size) - 1);
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800415 }
416 break;
417 case KEY_LEFT:
418 exposay_maybe_move(shell, shell->exposay.row_current,
419 shell->exposay.column_current - 1);
420 break;
421 case KEY_RIGHT:
422 exposay_maybe_move(shell, shell->exposay.row_current,
423 shell->exposay.column_current + 1);
424 break;
425 case KEY_TAB:
426 /* Try to move right, then down (and to the leftmost column),
427 * then if all else fails, to the top left. */
428 if (!exposay_maybe_move(shell, shell->exposay.row_current,
429 shell->exposay.column_current + 1) &&
430 !exposay_maybe_move(shell, shell->exposay.row_current + 1, 0))
431 exposay_maybe_move(shell, 0, 0);
432 break;
433 default:
434 break;
435 }
436}
437
438static void
439exposay_modifier(struct weston_keyboard_grab *grab, uint32_t serial,
440 uint32_t mods_depressed, uint32_t mods_latched,
441 uint32_t mods_locked, uint32_t group)
442{
443 struct desktop_shell *shell =
444 container_of(grab, struct desktop_shell, exposay.grab_kbd);
445 struct weston_seat *seat = (struct weston_seat *) grab->keyboard->seat;
446
447 /* We want to know when mod has been pressed and released.
448 * FIXME: There is a problem here: if mod is pressed, then a key
449 * is pressed and released, then mod is released, we will treat that
450 * as if only mod had been pressed and released. */
451 if (seat->modifier_state) {
452 if (seat->modifier_state == shell->binding_modifier) {
453 shell->exposay.mod_pressed = true;
454 } else {
455 shell->exposay.mod_invalid = true;
456 }
457 } else {
458 if (shell->exposay.mod_pressed && !shell->exposay.mod_invalid)
459 exposay_set_state(shell, EXPOSAY_TARGET_CANCEL, seat);
460
461 shell->exposay.mod_invalid = false;
462 shell->exposay.mod_pressed = false;
463 }
464
465 return;
466}
467
468static void
469exposay_cancel(struct weston_keyboard_grab *grab)
470{
471 struct desktop_shell *shell =
472 container_of(grab, struct desktop_shell, exposay.grab_kbd);
473
474 exposay_set_state(shell, EXPOSAY_TARGET_CANCEL, shell->exposay.seat);
475}
476
477static const struct weston_keyboard_grab_interface exposay_kbd_grab = {
478 exposay_key,
479 exposay_modifier,
480 exposay_cancel,
481};
482
483/**
484 * Called when the transition from overview -> inactive has completed.
485 */
486static enum exposay_layout_state
487exposay_set_inactive(struct desktop_shell *shell)
488{
489 struct weston_seat *seat = shell->exposay.seat;
490
491 weston_keyboard_end_grab(seat->keyboard);
492 weston_pointer_end_grab(seat->pointer);
493 if (seat->keyboard->input_method_resource)
494 seat->keyboard->grab = &seat->keyboard->input_method_grab;
495
496 return EXPOSAY_LAYOUT_INACTIVE;
497}
498
499/**
500 * Begins the transition from overview to inactive. */
501static enum exposay_layout_state
502exposay_transition_inactive(struct desktop_shell *shell, int switch_focus)
503{
504 struct exposay_surface *esurface;
505
506 /* Call activate() before we start the animations to avoid
507 * animating back the old state and then immediately transitioning
508 * to the new. */
509 if (switch_focus && shell->exposay.focus_current)
510 activate(shell, shell->exposay.focus_current->surface,
511 shell->exposay.seat);
512 else if (shell->exposay.focus_prev)
513 activate(shell, shell->exposay.focus_prev->surface,
514 shell->exposay.seat);
515
516 wl_list_for_each(esurface, &shell->exposay.surface_list, link)
517 exposay_animate_out(esurface);
518 weston_compositor_schedule_repaint(shell->compositor);
519
520 return EXPOSAY_LAYOUT_ANIMATE_TO_INACTIVE;
521}
522
523static enum exposay_layout_state
524exposay_transition_active(struct desktop_shell *shell)
525{
526 struct weston_seat *seat = shell->exposay.seat;
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100527 struct shell_output *shell_output;
528 bool animate = false;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800529
530 shell->exposay.workspace = get_current_workspace(shell);
531 shell->exposay.focus_prev = get_default_view (seat->keyboard->focus);
532 shell->exposay.focus_current = get_default_view (seat->keyboard->focus);
533 shell->exposay.clicked = NULL;
534 wl_list_init(&shell->exposay.surface_list);
535
536 lower_fullscreen_layer(shell);
537 shell->exposay.grab_kbd.interface = &exposay_kbd_grab;
538 weston_keyboard_start_grab(seat->keyboard,
539 &shell->exposay.grab_kbd);
540 weston_keyboard_set_focus(seat->keyboard, NULL);
541
542 shell->exposay.grab_ptr.interface = &exposay_ptr_grab;
543 weston_pointer_start_grab(seat->pointer,
544 &shell->exposay.grab_ptr);
545 weston_pointer_set_focus(seat->pointer, NULL,
546 seat->pointer->x, seat->pointer->y);
547
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100548 wl_list_for_each(shell_output, &shell->output_list, link) {
549 enum exposay_layout_state state;
550
551 state = exposay_layout(shell, shell_output);
552
553 if (state == EXPOSAY_LAYOUT_ANIMATE_TO_OVERVIEW)
554 animate = true;
555 }
556
557 return animate ? EXPOSAY_LAYOUT_ANIMATE_TO_OVERVIEW
558 : EXPOSAY_LAYOUT_OVERVIEW;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800559}
560
561static void
562exposay_check_state(struct desktop_shell *shell)
563{
564 enum exposay_layout_state state_new = shell->exposay.state_cur;
565 int do_switch = 0;
566
567 /* Don't do anything whilst animations are running, just store up
568 * target state changes and only act on them when the animations have
569 * completed. */
570 if (exposay_is_animating(shell))
571 return;
572
573 switch (shell->exposay.state_target) {
574 case EXPOSAY_TARGET_OVERVIEW:
575 switch (shell->exposay.state_cur) {
576 case EXPOSAY_LAYOUT_OVERVIEW:
577 goto out;
578 case EXPOSAY_LAYOUT_ANIMATE_TO_OVERVIEW:
579 state_new = EXPOSAY_LAYOUT_OVERVIEW;
580 break;
581 default:
582 state_new = exposay_transition_active(shell);
583 break;
584 }
585 break;
586
587 case EXPOSAY_TARGET_SWITCH:
588 do_switch = 1; /* fallthrough */
589 case EXPOSAY_TARGET_CANCEL:
590 switch (shell->exposay.state_cur) {
591 case EXPOSAY_LAYOUT_INACTIVE:
592 goto out;
593 case EXPOSAY_LAYOUT_ANIMATE_TO_INACTIVE:
594 state_new = exposay_set_inactive(shell);
595 break;
596 default:
597 state_new = exposay_transition_inactive(shell, do_switch);
598 break;
599 }
600
601 break;
602 }
603
604out:
605 shell->exposay.state_cur = state_new;
606}
607
608static void
609exposay_set_state(struct desktop_shell *shell, enum exposay_target_state state,
610 struct weston_seat *seat)
611{
612 shell->exposay.state_target = state;
613 shell->exposay.seat = seat;
614 exposay_check_state(shell);
615}
616
617void
618exposay_binding(struct weston_seat *seat, enum weston_keyboard_modifier modifier,
619 void *data)
620{
621 struct desktop_shell *shell = data;
622
623 exposay_set_state(shell, EXPOSAY_TARGET_OVERVIEW, seat);
624}