blob: 9c649e770e3f670039b10857bdca849066461392 [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;
Emilio Pozuelo Monfortf942b732014-02-10 14:23:04 +010036 struct wl_listener view_destroy_listener;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -080037 struct wl_list link;
38
39 int x;
40 int y;
41 int width;
42 int height;
43 double scale;
44
45 int row;
46 int column;
47
48 /* The animations only apply a transformation for their own lifetime,
49 * and don't have an option to indefinitely maintain the
50 * transformation in a steady state - so, we apply our own once the
51 * animation has finished. */
52 struct weston_transform transform;
53};
54
55static void exposay_set_state(struct desktop_shell *shell,
56 enum exposay_target_state state,
57 struct weston_seat *seat);
58static void exposay_check_state(struct desktop_shell *shell);
59
60static void
Emilio Pozuelo Monfortf942b732014-02-10 14:23:04 +010061exposay_surface_destroy(struct exposay_surface *esurface)
62{
63 wl_list_remove(&esurface->link);
64 wl_list_remove(&esurface->view_destroy_listener.link);
65
66 if (esurface->shell->exposay.focus_current == esurface->view)
67 esurface->shell->exposay.focus_current = NULL;
68 if (esurface->shell->exposay.focus_prev == esurface->view)
69 esurface->shell->exposay.focus_prev = NULL;
70
71 free(esurface);
72}
73
74static void
Kristian Høgsberg1ef23132013-12-04 00:20:01 -080075exposay_in_flight_inc(struct desktop_shell *shell)
76{
77 shell->exposay.in_flight++;
78}
79
80static void
81exposay_in_flight_dec(struct desktop_shell *shell)
82{
83 if (--shell->exposay.in_flight > 0)
84 return;
85
86 exposay_check_state(shell);
87}
88
89static void
90exposay_animate_in_done(struct weston_view_animation *animation, void *data)
91{
92 struct exposay_surface *esurface = data;
93
94 wl_list_insert(&esurface->view->geometry.transformation_list,
95 &esurface->transform.link);
96 weston_matrix_init(&esurface->transform.matrix);
97 weston_matrix_scale(&esurface->transform.matrix,
98 esurface->scale, esurface->scale, 1.0f);
99 weston_matrix_translate(&esurface->transform.matrix,
100 esurface->x - esurface->view->geometry.x,
101 esurface->y - esurface->view->geometry.y,
102 0);
103
104 weston_view_geometry_dirty(esurface->view);
105 weston_compositor_schedule_repaint(esurface->view->surface->compositor);
106
107 exposay_in_flight_dec(esurface->shell);
108}
109
110static void
111exposay_animate_in(struct exposay_surface *esurface)
112{
113 exposay_in_flight_inc(esurface->shell);
114
115 weston_move_scale_run(esurface->view,
116 esurface->x - esurface->view->geometry.x,
117 esurface->y - esurface->view->geometry.y,
118 1.0, esurface->scale, 0,
119 exposay_animate_in_done, esurface);
120}
121
122static void
123exposay_animate_out_done(struct weston_view_animation *animation, void *data)
124{
125 struct exposay_surface *esurface = data;
126 struct desktop_shell *shell = esurface->shell;
127
Emilio Pozuelo Monfortf942b732014-02-10 14:23:04 +0100128 exposay_surface_destroy(esurface);
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800129
130 exposay_in_flight_dec(shell);
131}
132
133static void
134exposay_animate_out(struct exposay_surface *esurface)
135{
136 exposay_in_flight_inc(esurface->shell);
137
138 /* Remove the static transformation set up by
139 * exposay_transform_in_done(). */
140 wl_list_remove(&esurface->transform.link);
141 weston_view_geometry_dirty(esurface->view);
142
143 weston_move_scale_run(esurface->view,
144 esurface->x - esurface->view->geometry.x,
145 esurface->y - esurface->view->geometry.y,
146 1.0, esurface->scale, 1,
147 exposay_animate_out_done, esurface);
148}
149
150static void
151exposay_highlight_surface(struct desktop_shell *shell,
152 struct exposay_surface *esurface)
153{
U. Artie Eoff6d6d1902014-01-15 13:42:18 -0800154 struct weston_view *view = esurface->view;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800155
Emilio Pozuelo Monforta7592012014-02-10 16:52:33 +0100156 if (shell->exposay.focus_current == view)
157 return;
158
U. Artie Eoff6d6d1902014-01-15 13:42:18 -0800159 shell->exposay.row_current = esurface->row;
160 shell->exposay.column_current = esurface->column;
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100161 shell->exposay.cur_output = esurface->eoutput;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800162
163 activate(shell, view->surface, shell->exposay.seat);
164 shell->exposay.focus_current = view;
165}
166
167static int
168exposay_is_animating(struct desktop_shell *shell)
169{
170 if (shell->exposay.state_cur == EXPOSAY_LAYOUT_INACTIVE ||
171 shell->exposay.state_cur == EXPOSAY_LAYOUT_OVERVIEW)
172 return 0;
173
174 return (shell->exposay.in_flight > 0);
175}
176
177static void
178exposay_pick(struct desktop_shell *shell, int x, int y)
179{
180 struct exposay_surface *esurface;
181
182 if (exposay_is_animating(shell))
183 return;
184
185 wl_list_for_each(esurface, &shell->exposay.surface_list, link) {
186 if (x < esurface->x || x > esurface->x + esurface->width)
187 continue;
188 if (y < esurface->y || y > esurface->y + esurface->height)
189 continue;
190
191 exposay_highlight_surface(shell, esurface);
192 return;
193 }
194}
195
Emilio Pozuelo Monfortf942b732014-02-10 14:23:04 +0100196static void
197handle_view_destroy(struct wl_listener *listener, void *data)
198{
199 struct exposay_surface *esurface = container_of(listener,
200 struct exposay_surface,
201 view_destroy_listener);
202
203 exposay_surface_destroy(esurface);
204}
205
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800206/* Pretty lame layout for now; just tries to make a square. Should take
207 * aspect ratio into account really. Also needs to be notified of surface
208 * addition and removal and adjust layout/animate accordingly. */
209static enum exposay_layout_state
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100210exposay_layout(struct desktop_shell *shell, struct shell_output *shell_output)
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800211{
212 struct workspace *workspace = shell->exposay.workspace;
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100213 struct weston_output *output = shell_output->output;
214 struct exposay_output *eoutput = &shell_output->eoutput;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800215 struct weston_view *view;
Emilio Pozuelo Monforte6bbe5a2014-01-07 16:41:39 +0100216 struct exposay_surface *esurface, *highlight = NULL;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800217 int w, h;
218 int i;
219 int last_row_removed = 0;
220
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100221 eoutput->num_surfaces = 0;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800222 wl_list_for_each(view, &workspace->layer.view_list, layer_link) {
223 if (!get_shell_surface(view->surface))
224 continue;
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100225 if (view->output != output)
226 continue;
227 eoutput->num_surfaces++;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800228 }
229
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100230 if (eoutput->num_surfaces == 0) {
231 eoutput->grid_size = 0;
232 eoutput->hpadding_outer = 0;
233 eoutput->vpadding_outer = 0;
234 eoutput->padding_inner = 0;
235 eoutput->surface_size = 0;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800236 return EXPOSAY_LAYOUT_OVERVIEW;
237 }
238
239 /* Lay the grid out as square as possible, losing surfaces from the
240 * bottom row if required. Start with fixed padding of a 10% margin
241 * around the outside and 80px internal padding between surfaces, and
242 * maximise the area made available to surfaces after this, but only
243 * to a maximum of 1/3rd the total output size.
244 *
245 * If we can't make a square grid, add one extra row at the bottom
246 * which will have a smaller number of columns.
247 *
248 * XXX: Surely there has to be a better way to express this maths,
249 * right?!
250 */
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100251 eoutput->grid_size = floor(sqrtf(eoutput->num_surfaces));
252 if (pow(eoutput->grid_size, 2) != eoutput->num_surfaces)
253 eoutput->grid_size++;
254 last_row_removed = pow(eoutput->grid_size, 2) - eoutput->num_surfaces;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800255
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100256 eoutput->hpadding_outer = (output->width / 10);
257 eoutput->vpadding_outer = (output->height / 10);
258 eoutput->padding_inner = 80;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800259
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100260 w = output->width - (eoutput->hpadding_outer * 2);
261 w -= eoutput->padding_inner * (eoutput->grid_size - 1);
262 w /= eoutput->grid_size;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800263
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100264 h = output->height - (eoutput->vpadding_outer * 2);
265 h -= eoutput->padding_inner * (eoutput->grid_size - 1);
266 h /= eoutput->grid_size;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800267
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100268 eoutput->surface_size = (w < h) ? w : h;
269 if (eoutput->surface_size > (output->width / 2))
270 eoutput->surface_size = output->width / 2;
271 if (eoutput->surface_size > (output->height / 2))
272 eoutput->surface_size = output->height / 2;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800273
274 i = 0;
275 wl_list_for_each(view, &workspace->layer.view_list, layer_link) {
276 int pad;
277
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100278 pad = eoutput->surface_size + eoutput->padding_inner;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800279
280 if (!get_shell_surface(view->surface))
281 continue;
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100282 if (view->output != output)
283 continue;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800284
285 esurface = malloc(sizeof(*esurface));
286 if (!esurface) {
287 exposay_set_state(shell, EXPOSAY_TARGET_CANCEL,
288 shell->exposay.seat);
289 break;
290 }
291
292 wl_list_insert(&shell->exposay.surface_list, &esurface->link);
293 esurface->shell = shell;
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100294 esurface->eoutput = eoutput;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800295 esurface->view = view;
296
Emilio Pozuelo Monfortf942b732014-02-10 14:23:04 +0100297 esurface->view_destroy_listener.notify = handle_view_destroy;
298 wl_signal_add(&view->destroy_signal, &esurface->view_destroy_listener);
299
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100300 esurface->row = i / eoutput->grid_size;
301 esurface->column = i % eoutput->grid_size;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800302
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100303 esurface->x = output->x + eoutput->hpadding_outer;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800304 esurface->x += pad * esurface->column;
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100305 esurface->y = output->y + eoutput->vpadding_outer;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800306 esurface->y += pad * esurface->row;
307
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100308 if (esurface->row == eoutput->grid_size - 1)
309 esurface->x += (eoutput->surface_size + eoutput->padding_inner) * last_row_removed / 2;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800310
311 if (view->surface->width > view->surface->height)
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100312 esurface->scale = eoutput->surface_size / (float) view->surface->width;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800313 else
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100314 esurface->scale = eoutput->surface_size / (float) view->surface->height;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800315 esurface->width = view->surface->width * esurface->scale;
316 esurface->height = view->surface->height * esurface->scale;
317
318 if (shell->exposay.focus_current == esurface->view)
Emilio Pozuelo Monforte6bbe5a2014-01-07 16:41:39 +0100319 highlight = esurface;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800320
Emilio Pozuelo Monfort1a26f1b2014-01-07 16:41:40 +0100321 set_alpha_if_fullscreen(get_shell_surface(view->surface));
322
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800323 exposay_animate_in(esurface);
324
325 i++;
326 }
327
Emilio Pozuelo Monforte6bbe5a2014-01-07 16:41:39 +0100328 if (highlight)
329 exposay_highlight_surface(shell, highlight);
330
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800331 weston_compositor_schedule_repaint(shell->compositor);
332
333 return EXPOSAY_LAYOUT_ANIMATE_TO_OVERVIEW;
334}
335
336static void
337exposay_focus(struct weston_pointer_grab *grab)
338{
339}
340
341static void
342exposay_motion(struct weston_pointer_grab *grab, uint32_t time,
343 wl_fixed_t x, wl_fixed_t y)
344{
345 struct desktop_shell *shell =
346 container_of(grab, struct desktop_shell, exposay.grab_ptr);
347
348 weston_pointer_move(grab->pointer, x, y);
349
350 exposay_pick(shell,
351 wl_fixed_to_int(grab->pointer->x),
352 wl_fixed_to_int(grab->pointer->y));
353}
354
355static void
356exposay_button(struct weston_pointer_grab *grab, uint32_t time, uint32_t button,
357 uint32_t state_w)
358{
359 struct desktop_shell *shell =
360 container_of(grab, struct desktop_shell, exposay.grab_ptr);
361 struct weston_seat *seat = grab->pointer->seat;
362 enum wl_pointer_button_state state = state_w;
363
364 if (button != BTN_LEFT)
365 return;
366
367 /* Store the surface we clicked on, and don't do anything if we end up
368 * releasing on a different surface. */
369 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
370 shell->exposay.clicked = shell->exposay.focus_current;
371 return;
372 }
373
374 if (shell->exposay.focus_current == shell->exposay.clicked)
375 exposay_set_state(shell, EXPOSAY_TARGET_SWITCH, seat);
376 else
377 shell->exposay.clicked = NULL;
378}
379
380static void
381exposay_pointer_grab_cancel(struct weston_pointer_grab *grab)
382{
383 struct desktop_shell *shell =
384 container_of(grab, struct desktop_shell, exposay.grab_ptr);
385
386 exposay_set_state(shell, EXPOSAY_TARGET_CANCEL, shell->exposay.seat);
387}
388
389static const struct weston_pointer_grab_interface exposay_ptr_grab = {
390 exposay_focus,
391 exposay_motion,
392 exposay_button,
393 exposay_pointer_grab_cancel,
394};
395
396static int
397exposay_maybe_move(struct desktop_shell *shell, int row, int column)
398{
399 struct exposay_surface *esurface;
400
401 wl_list_for_each(esurface, &shell->exposay.surface_list, link) {
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100402 if (esurface->eoutput != shell->exposay.cur_output ||
403 esurface->row != row || esurface->column != column)
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800404 continue;
405
406 exposay_highlight_surface(shell, esurface);
407 return 1;
408 }
409
410 return 0;
411}
412
413static void
414exposay_key(struct weston_keyboard_grab *grab, uint32_t time, uint32_t key,
415 uint32_t state_w)
416{
417 struct weston_seat *seat = grab->keyboard->seat;
418 struct desktop_shell *shell =
419 container_of(grab, struct desktop_shell, exposay.grab_kbd);
420 enum wl_keyboard_key_state state = state_w;
421
422 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
423 return;
424
425 switch (key) {
426 case KEY_ESC:
427 exposay_set_state(shell, EXPOSAY_TARGET_CANCEL, seat);
428 break;
429 case KEY_ENTER:
430 exposay_set_state(shell, EXPOSAY_TARGET_SWITCH, seat);
431 break;
432 case KEY_UP:
433 exposay_maybe_move(shell, shell->exposay.row_current - 1,
434 shell->exposay.column_current);
435 break;
436 case KEY_DOWN:
437 /* Special case for trying to move to the bottom row when it
438 * has fewer items than all the others. */
439 if (!exposay_maybe_move(shell, shell->exposay.row_current + 1,
440 shell->exposay.column_current) &&
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100441 shell->exposay.row_current < (shell->exposay.cur_output->grid_size - 1)) {
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800442 exposay_maybe_move(shell, shell->exposay.row_current + 1,
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100443 (shell->exposay.cur_output->num_surfaces %
444 shell->exposay.cur_output->grid_size) - 1);
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800445 }
446 break;
447 case KEY_LEFT:
448 exposay_maybe_move(shell, shell->exposay.row_current,
449 shell->exposay.column_current - 1);
450 break;
451 case KEY_RIGHT:
452 exposay_maybe_move(shell, shell->exposay.row_current,
453 shell->exposay.column_current + 1);
454 break;
455 case KEY_TAB:
456 /* Try to move right, then down (and to the leftmost column),
457 * then if all else fails, to the top left. */
458 if (!exposay_maybe_move(shell, shell->exposay.row_current,
459 shell->exposay.column_current + 1) &&
460 !exposay_maybe_move(shell, shell->exposay.row_current + 1, 0))
461 exposay_maybe_move(shell, 0, 0);
462 break;
463 default:
464 break;
465 }
466}
467
468static void
469exposay_modifier(struct weston_keyboard_grab *grab, uint32_t serial,
470 uint32_t mods_depressed, uint32_t mods_latched,
471 uint32_t mods_locked, uint32_t group)
472{
473 struct desktop_shell *shell =
474 container_of(grab, struct desktop_shell, exposay.grab_kbd);
475 struct weston_seat *seat = (struct weston_seat *) grab->keyboard->seat;
476
477 /* We want to know when mod has been pressed and released.
478 * FIXME: There is a problem here: if mod is pressed, then a key
479 * is pressed and released, then mod is released, we will treat that
480 * as if only mod had been pressed and released. */
481 if (seat->modifier_state) {
482 if (seat->modifier_state == shell->binding_modifier) {
483 shell->exposay.mod_pressed = true;
484 } else {
485 shell->exposay.mod_invalid = true;
486 }
487 } else {
488 if (shell->exposay.mod_pressed && !shell->exposay.mod_invalid)
489 exposay_set_state(shell, EXPOSAY_TARGET_CANCEL, seat);
490
491 shell->exposay.mod_invalid = false;
492 shell->exposay.mod_pressed = false;
493 }
494
495 return;
496}
497
498static void
499exposay_cancel(struct weston_keyboard_grab *grab)
500{
501 struct desktop_shell *shell =
502 container_of(grab, struct desktop_shell, exposay.grab_kbd);
503
504 exposay_set_state(shell, EXPOSAY_TARGET_CANCEL, shell->exposay.seat);
505}
506
507static const struct weston_keyboard_grab_interface exposay_kbd_grab = {
508 exposay_key,
509 exposay_modifier,
510 exposay_cancel,
511};
512
513/**
514 * Called when the transition from overview -> inactive has completed.
515 */
516static enum exposay_layout_state
517exposay_set_inactive(struct desktop_shell *shell)
518{
519 struct weston_seat *seat = shell->exposay.seat;
520
521 weston_keyboard_end_grab(seat->keyboard);
522 weston_pointer_end_grab(seat->pointer);
523 if (seat->keyboard->input_method_resource)
524 seat->keyboard->grab = &seat->keyboard->input_method_grab;
525
526 return EXPOSAY_LAYOUT_INACTIVE;
527}
528
529/**
530 * Begins the transition from overview to inactive. */
531static enum exposay_layout_state
532exposay_transition_inactive(struct desktop_shell *shell, int switch_focus)
533{
534 struct exposay_surface *esurface;
535
536 /* Call activate() before we start the animations to avoid
537 * animating back the old state and then immediately transitioning
538 * to the new. */
539 if (switch_focus && shell->exposay.focus_current)
540 activate(shell, shell->exposay.focus_current->surface,
541 shell->exposay.seat);
542 else if (shell->exposay.focus_prev)
543 activate(shell, shell->exposay.focus_prev->surface,
544 shell->exposay.seat);
545
546 wl_list_for_each(esurface, &shell->exposay.surface_list, link)
547 exposay_animate_out(esurface);
548 weston_compositor_schedule_repaint(shell->compositor);
549
550 return EXPOSAY_LAYOUT_ANIMATE_TO_INACTIVE;
551}
552
553static enum exposay_layout_state
554exposay_transition_active(struct desktop_shell *shell)
555{
556 struct weston_seat *seat = shell->exposay.seat;
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100557 struct shell_output *shell_output;
558 bool animate = false;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800559
560 shell->exposay.workspace = get_current_workspace(shell);
561 shell->exposay.focus_prev = get_default_view (seat->keyboard->focus);
562 shell->exposay.focus_current = get_default_view (seat->keyboard->focus);
563 shell->exposay.clicked = NULL;
564 wl_list_init(&shell->exposay.surface_list);
565
566 lower_fullscreen_layer(shell);
567 shell->exposay.grab_kbd.interface = &exposay_kbd_grab;
568 weston_keyboard_start_grab(seat->keyboard,
569 &shell->exposay.grab_kbd);
570 weston_keyboard_set_focus(seat->keyboard, NULL);
571
572 shell->exposay.grab_ptr.interface = &exposay_ptr_grab;
573 weston_pointer_start_grab(seat->pointer,
574 &shell->exposay.grab_ptr);
575 weston_pointer_set_focus(seat->pointer, NULL,
576 seat->pointer->x, seat->pointer->y);
577
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100578 wl_list_for_each(shell_output, &shell->output_list, link) {
579 enum exposay_layout_state state;
580
581 state = exposay_layout(shell, shell_output);
582
583 if (state == EXPOSAY_LAYOUT_ANIMATE_TO_OVERVIEW)
584 animate = true;
585 }
586
587 return animate ? EXPOSAY_LAYOUT_ANIMATE_TO_OVERVIEW
588 : EXPOSAY_LAYOUT_OVERVIEW;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800589}
590
591static void
592exposay_check_state(struct desktop_shell *shell)
593{
594 enum exposay_layout_state state_new = shell->exposay.state_cur;
595 int do_switch = 0;
596
597 /* Don't do anything whilst animations are running, just store up
598 * target state changes and only act on them when the animations have
599 * completed. */
600 if (exposay_is_animating(shell))
601 return;
602
603 switch (shell->exposay.state_target) {
604 case EXPOSAY_TARGET_OVERVIEW:
605 switch (shell->exposay.state_cur) {
606 case EXPOSAY_LAYOUT_OVERVIEW:
607 goto out;
608 case EXPOSAY_LAYOUT_ANIMATE_TO_OVERVIEW:
609 state_new = EXPOSAY_LAYOUT_OVERVIEW;
610 break;
611 default:
612 state_new = exposay_transition_active(shell);
613 break;
614 }
615 break;
616
617 case EXPOSAY_TARGET_SWITCH:
618 do_switch = 1; /* fallthrough */
619 case EXPOSAY_TARGET_CANCEL:
620 switch (shell->exposay.state_cur) {
621 case EXPOSAY_LAYOUT_INACTIVE:
622 goto out;
623 case EXPOSAY_LAYOUT_ANIMATE_TO_INACTIVE:
624 state_new = exposay_set_inactive(shell);
625 break;
626 default:
627 state_new = exposay_transition_inactive(shell, do_switch);
628 break;
629 }
630
631 break;
632 }
633
634out:
635 shell->exposay.state_cur = state_new;
636}
637
638static void
639exposay_set_state(struct desktop_shell *shell, enum exposay_target_state state,
640 struct weston_seat *seat)
641{
642 shell->exposay.state_target = state;
643 shell->exposay.seat = seat;
644 exposay_check_state(shell);
645}
646
647void
648exposay_binding(struct weston_seat *seat, enum weston_keyboard_modifier modifier,
649 void *data)
650{
651 struct desktop_shell *shell = data;
652
653 exposay_set_state(shell, EXPOSAY_TARGET_OVERVIEW, seat);
654}