blob: ca3635899acf806b4ecce73f810a50b713257cff [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
U. Artie Eoff6d6d1902014-01-15 13:42:18 -0800156 shell->exposay.row_current = esurface->row;
157 shell->exposay.column_current = esurface->column;
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100158 shell->exposay.cur_output = esurface->eoutput;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800159
160 activate(shell, view->surface, shell->exposay.seat);
161 shell->exposay.focus_current = view;
162}
163
164static int
165exposay_is_animating(struct desktop_shell *shell)
166{
167 if (shell->exposay.state_cur == EXPOSAY_LAYOUT_INACTIVE ||
168 shell->exposay.state_cur == EXPOSAY_LAYOUT_OVERVIEW)
169 return 0;
170
171 return (shell->exposay.in_flight > 0);
172}
173
174static void
175exposay_pick(struct desktop_shell *shell, int x, int y)
176{
177 struct exposay_surface *esurface;
178
179 if (exposay_is_animating(shell))
180 return;
181
182 wl_list_for_each(esurface, &shell->exposay.surface_list, link) {
183 if (x < esurface->x || x > esurface->x + esurface->width)
184 continue;
185 if (y < esurface->y || y > esurface->y + esurface->height)
186 continue;
187
188 exposay_highlight_surface(shell, esurface);
189 return;
190 }
191}
192
Emilio Pozuelo Monfortf942b732014-02-10 14:23:04 +0100193static void
194handle_view_destroy(struct wl_listener *listener, void *data)
195{
196 struct exposay_surface *esurface = container_of(listener,
197 struct exposay_surface,
198 view_destroy_listener);
199
200 exposay_surface_destroy(esurface);
201}
202
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800203/* Pretty lame layout for now; just tries to make a square. Should take
204 * aspect ratio into account really. Also needs to be notified of surface
205 * addition and removal and adjust layout/animate accordingly. */
206static enum exposay_layout_state
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100207exposay_layout(struct desktop_shell *shell, struct shell_output *shell_output)
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800208{
209 struct workspace *workspace = shell->exposay.workspace;
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100210 struct weston_output *output = shell_output->output;
211 struct exposay_output *eoutput = &shell_output->eoutput;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800212 struct weston_view *view;
Emilio Pozuelo Monforte6bbe5a2014-01-07 16:41:39 +0100213 struct exposay_surface *esurface, *highlight = NULL;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800214 int w, h;
215 int i;
216 int last_row_removed = 0;
217
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100218 eoutput->num_surfaces = 0;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800219 wl_list_for_each(view, &workspace->layer.view_list, layer_link) {
220 if (!get_shell_surface(view->surface))
221 continue;
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100222 if (view->output != output)
223 continue;
224 eoutput->num_surfaces++;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800225 }
226
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100227 if (eoutput->num_surfaces == 0) {
228 eoutput->grid_size = 0;
229 eoutput->hpadding_outer = 0;
230 eoutput->vpadding_outer = 0;
231 eoutput->padding_inner = 0;
232 eoutput->surface_size = 0;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800233 return EXPOSAY_LAYOUT_OVERVIEW;
234 }
235
236 /* Lay the grid out as square as possible, losing surfaces from the
237 * bottom row if required. Start with fixed padding of a 10% margin
238 * around the outside and 80px internal padding between surfaces, and
239 * maximise the area made available to surfaces after this, but only
240 * to a maximum of 1/3rd the total output size.
241 *
242 * If we can't make a square grid, add one extra row at the bottom
243 * which will have a smaller number of columns.
244 *
245 * XXX: Surely there has to be a better way to express this maths,
246 * right?!
247 */
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100248 eoutput->grid_size = floor(sqrtf(eoutput->num_surfaces));
249 if (pow(eoutput->grid_size, 2) != eoutput->num_surfaces)
250 eoutput->grid_size++;
251 last_row_removed = pow(eoutput->grid_size, 2) - eoutput->num_surfaces;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800252
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100253 eoutput->hpadding_outer = (output->width / 10);
254 eoutput->vpadding_outer = (output->height / 10);
255 eoutput->padding_inner = 80;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800256
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100257 w = output->width - (eoutput->hpadding_outer * 2);
258 w -= eoutput->padding_inner * (eoutput->grid_size - 1);
259 w /= eoutput->grid_size;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800260
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100261 h = output->height - (eoutput->vpadding_outer * 2);
262 h -= eoutput->padding_inner * (eoutput->grid_size - 1);
263 h /= eoutput->grid_size;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800264
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100265 eoutput->surface_size = (w < h) ? w : h;
266 if (eoutput->surface_size > (output->width / 2))
267 eoutput->surface_size = output->width / 2;
268 if (eoutput->surface_size > (output->height / 2))
269 eoutput->surface_size = output->height / 2;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800270
271 i = 0;
272 wl_list_for_each(view, &workspace->layer.view_list, layer_link) {
273 int pad;
274
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100275 pad = eoutput->surface_size + eoutput->padding_inner;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800276
277 if (!get_shell_surface(view->surface))
278 continue;
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100279 if (view->output != output)
280 continue;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800281
282 esurface = malloc(sizeof(*esurface));
283 if (!esurface) {
284 exposay_set_state(shell, EXPOSAY_TARGET_CANCEL,
285 shell->exposay.seat);
286 break;
287 }
288
289 wl_list_insert(&shell->exposay.surface_list, &esurface->link);
290 esurface->shell = shell;
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100291 esurface->eoutput = eoutput;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800292 esurface->view = view;
293
Emilio Pozuelo Monfortf942b732014-02-10 14:23:04 +0100294 esurface->view_destroy_listener.notify = handle_view_destroy;
295 wl_signal_add(&view->destroy_signal, &esurface->view_destroy_listener);
296
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100297 esurface->row = i / eoutput->grid_size;
298 esurface->column = i % eoutput->grid_size;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800299
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100300 esurface->x = output->x + eoutput->hpadding_outer;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800301 esurface->x += pad * esurface->column;
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100302 esurface->y = output->y + eoutput->vpadding_outer;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800303 esurface->y += pad * esurface->row;
304
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100305 if (esurface->row == eoutput->grid_size - 1)
306 esurface->x += (eoutput->surface_size + eoutput->padding_inner) * last_row_removed / 2;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800307
308 if (view->surface->width > view->surface->height)
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100309 esurface->scale = eoutput->surface_size / (float) view->surface->width;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800310 else
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100311 esurface->scale = eoutput->surface_size / (float) view->surface->height;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800312 esurface->width = view->surface->width * esurface->scale;
313 esurface->height = view->surface->height * esurface->scale;
314
315 if (shell->exposay.focus_current == esurface->view)
Emilio Pozuelo Monforte6bbe5a2014-01-07 16:41:39 +0100316 highlight = esurface;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800317
Emilio Pozuelo Monfort1a26f1b2014-01-07 16:41:40 +0100318 set_alpha_if_fullscreen(get_shell_surface(view->surface));
319
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800320 exposay_animate_in(esurface);
321
322 i++;
323 }
324
Emilio Pozuelo Monforte6bbe5a2014-01-07 16:41:39 +0100325 if (highlight)
326 exposay_highlight_surface(shell, highlight);
327
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800328 weston_compositor_schedule_repaint(shell->compositor);
329
330 return EXPOSAY_LAYOUT_ANIMATE_TO_OVERVIEW;
331}
332
333static void
334exposay_focus(struct weston_pointer_grab *grab)
335{
336}
337
338static void
339exposay_motion(struct weston_pointer_grab *grab, uint32_t time,
340 wl_fixed_t x, wl_fixed_t y)
341{
342 struct desktop_shell *shell =
343 container_of(grab, struct desktop_shell, exposay.grab_ptr);
344
345 weston_pointer_move(grab->pointer, x, y);
346
347 exposay_pick(shell,
348 wl_fixed_to_int(grab->pointer->x),
349 wl_fixed_to_int(grab->pointer->y));
350}
351
352static void
353exposay_button(struct weston_pointer_grab *grab, uint32_t time, uint32_t button,
354 uint32_t state_w)
355{
356 struct desktop_shell *shell =
357 container_of(grab, struct desktop_shell, exposay.grab_ptr);
358 struct weston_seat *seat = grab->pointer->seat;
359 enum wl_pointer_button_state state = state_w;
360
361 if (button != BTN_LEFT)
362 return;
363
364 /* Store the surface we clicked on, and don't do anything if we end up
365 * releasing on a different surface. */
366 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
367 shell->exposay.clicked = shell->exposay.focus_current;
368 return;
369 }
370
371 if (shell->exposay.focus_current == shell->exposay.clicked)
372 exposay_set_state(shell, EXPOSAY_TARGET_SWITCH, seat);
373 else
374 shell->exposay.clicked = NULL;
375}
376
377static void
378exposay_pointer_grab_cancel(struct weston_pointer_grab *grab)
379{
380 struct desktop_shell *shell =
381 container_of(grab, struct desktop_shell, exposay.grab_ptr);
382
383 exposay_set_state(shell, EXPOSAY_TARGET_CANCEL, shell->exposay.seat);
384}
385
386static const struct weston_pointer_grab_interface exposay_ptr_grab = {
387 exposay_focus,
388 exposay_motion,
389 exposay_button,
390 exposay_pointer_grab_cancel,
391};
392
393static int
394exposay_maybe_move(struct desktop_shell *shell, int row, int column)
395{
396 struct exposay_surface *esurface;
397
398 wl_list_for_each(esurface, &shell->exposay.surface_list, link) {
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100399 if (esurface->eoutput != shell->exposay.cur_output ||
400 esurface->row != row || esurface->column != column)
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800401 continue;
402
403 exposay_highlight_surface(shell, esurface);
404 return 1;
405 }
406
407 return 0;
408}
409
410static void
411exposay_key(struct weston_keyboard_grab *grab, uint32_t time, uint32_t key,
412 uint32_t state_w)
413{
414 struct weston_seat *seat = grab->keyboard->seat;
415 struct desktop_shell *shell =
416 container_of(grab, struct desktop_shell, exposay.grab_kbd);
417 enum wl_keyboard_key_state state = state_w;
418
419 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
420 return;
421
422 switch (key) {
423 case KEY_ESC:
424 exposay_set_state(shell, EXPOSAY_TARGET_CANCEL, seat);
425 break;
426 case KEY_ENTER:
427 exposay_set_state(shell, EXPOSAY_TARGET_SWITCH, seat);
428 break;
429 case KEY_UP:
430 exposay_maybe_move(shell, shell->exposay.row_current - 1,
431 shell->exposay.column_current);
432 break;
433 case KEY_DOWN:
434 /* Special case for trying to move to the bottom row when it
435 * has fewer items than all the others. */
436 if (!exposay_maybe_move(shell, shell->exposay.row_current + 1,
437 shell->exposay.column_current) &&
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100438 shell->exposay.row_current < (shell->exposay.cur_output->grid_size - 1)) {
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800439 exposay_maybe_move(shell, shell->exposay.row_current + 1,
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100440 (shell->exposay.cur_output->num_surfaces %
441 shell->exposay.cur_output->grid_size) - 1);
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800442 }
443 break;
444 case KEY_LEFT:
445 exposay_maybe_move(shell, shell->exposay.row_current,
446 shell->exposay.column_current - 1);
447 break;
448 case KEY_RIGHT:
449 exposay_maybe_move(shell, shell->exposay.row_current,
450 shell->exposay.column_current + 1);
451 break;
452 case KEY_TAB:
453 /* Try to move right, then down (and to the leftmost column),
454 * then if all else fails, to the top left. */
455 if (!exposay_maybe_move(shell, shell->exposay.row_current,
456 shell->exposay.column_current + 1) &&
457 !exposay_maybe_move(shell, shell->exposay.row_current + 1, 0))
458 exposay_maybe_move(shell, 0, 0);
459 break;
460 default:
461 break;
462 }
463}
464
465static void
466exposay_modifier(struct weston_keyboard_grab *grab, uint32_t serial,
467 uint32_t mods_depressed, uint32_t mods_latched,
468 uint32_t mods_locked, uint32_t group)
469{
470 struct desktop_shell *shell =
471 container_of(grab, struct desktop_shell, exposay.grab_kbd);
472 struct weston_seat *seat = (struct weston_seat *) grab->keyboard->seat;
473
474 /* We want to know when mod has been pressed and released.
475 * FIXME: There is a problem here: if mod is pressed, then a key
476 * is pressed and released, then mod is released, we will treat that
477 * as if only mod had been pressed and released. */
478 if (seat->modifier_state) {
479 if (seat->modifier_state == shell->binding_modifier) {
480 shell->exposay.mod_pressed = true;
481 } else {
482 shell->exposay.mod_invalid = true;
483 }
484 } else {
485 if (shell->exposay.mod_pressed && !shell->exposay.mod_invalid)
486 exposay_set_state(shell, EXPOSAY_TARGET_CANCEL, seat);
487
488 shell->exposay.mod_invalid = false;
489 shell->exposay.mod_pressed = false;
490 }
491
492 return;
493}
494
495static void
496exposay_cancel(struct weston_keyboard_grab *grab)
497{
498 struct desktop_shell *shell =
499 container_of(grab, struct desktop_shell, exposay.grab_kbd);
500
501 exposay_set_state(shell, EXPOSAY_TARGET_CANCEL, shell->exposay.seat);
502}
503
504static const struct weston_keyboard_grab_interface exposay_kbd_grab = {
505 exposay_key,
506 exposay_modifier,
507 exposay_cancel,
508};
509
510/**
511 * Called when the transition from overview -> inactive has completed.
512 */
513static enum exposay_layout_state
514exposay_set_inactive(struct desktop_shell *shell)
515{
516 struct weston_seat *seat = shell->exposay.seat;
517
518 weston_keyboard_end_grab(seat->keyboard);
519 weston_pointer_end_grab(seat->pointer);
520 if (seat->keyboard->input_method_resource)
521 seat->keyboard->grab = &seat->keyboard->input_method_grab;
522
523 return EXPOSAY_LAYOUT_INACTIVE;
524}
525
526/**
527 * Begins the transition from overview to inactive. */
528static enum exposay_layout_state
529exposay_transition_inactive(struct desktop_shell *shell, int switch_focus)
530{
531 struct exposay_surface *esurface;
532
533 /* Call activate() before we start the animations to avoid
534 * animating back the old state and then immediately transitioning
535 * to the new. */
536 if (switch_focus && shell->exposay.focus_current)
537 activate(shell, shell->exposay.focus_current->surface,
538 shell->exposay.seat);
539 else if (shell->exposay.focus_prev)
540 activate(shell, shell->exposay.focus_prev->surface,
541 shell->exposay.seat);
542
543 wl_list_for_each(esurface, &shell->exposay.surface_list, link)
544 exposay_animate_out(esurface);
545 weston_compositor_schedule_repaint(shell->compositor);
546
547 return EXPOSAY_LAYOUT_ANIMATE_TO_INACTIVE;
548}
549
550static enum exposay_layout_state
551exposay_transition_active(struct desktop_shell *shell)
552{
553 struct weston_seat *seat = shell->exposay.seat;
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100554 struct shell_output *shell_output;
555 bool animate = false;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800556
557 shell->exposay.workspace = get_current_workspace(shell);
558 shell->exposay.focus_prev = get_default_view (seat->keyboard->focus);
559 shell->exposay.focus_current = get_default_view (seat->keyboard->focus);
560 shell->exposay.clicked = NULL;
561 wl_list_init(&shell->exposay.surface_list);
562
563 lower_fullscreen_layer(shell);
564 shell->exposay.grab_kbd.interface = &exposay_kbd_grab;
565 weston_keyboard_start_grab(seat->keyboard,
566 &shell->exposay.grab_kbd);
567 weston_keyboard_set_focus(seat->keyboard, NULL);
568
569 shell->exposay.grab_ptr.interface = &exposay_ptr_grab;
570 weston_pointer_start_grab(seat->pointer,
571 &shell->exposay.grab_ptr);
572 weston_pointer_set_focus(seat->pointer, NULL,
573 seat->pointer->x, seat->pointer->y);
574
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100575 wl_list_for_each(shell_output, &shell->output_list, link) {
576 enum exposay_layout_state state;
577
578 state = exposay_layout(shell, shell_output);
579
580 if (state == EXPOSAY_LAYOUT_ANIMATE_TO_OVERVIEW)
581 animate = true;
582 }
583
584 return animate ? EXPOSAY_LAYOUT_ANIMATE_TO_OVERVIEW
585 : EXPOSAY_LAYOUT_OVERVIEW;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800586}
587
588static void
589exposay_check_state(struct desktop_shell *shell)
590{
591 enum exposay_layout_state state_new = shell->exposay.state_cur;
592 int do_switch = 0;
593
594 /* Don't do anything whilst animations are running, just store up
595 * target state changes and only act on them when the animations have
596 * completed. */
597 if (exposay_is_animating(shell))
598 return;
599
600 switch (shell->exposay.state_target) {
601 case EXPOSAY_TARGET_OVERVIEW:
602 switch (shell->exposay.state_cur) {
603 case EXPOSAY_LAYOUT_OVERVIEW:
604 goto out;
605 case EXPOSAY_LAYOUT_ANIMATE_TO_OVERVIEW:
606 state_new = EXPOSAY_LAYOUT_OVERVIEW;
607 break;
608 default:
609 state_new = exposay_transition_active(shell);
610 break;
611 }
612 break;
613
614 case EXPOSAY_TARGET_SWITCH:
615 do_switch = 1; /* fallthrough */
616 case EXPOSAY_TARGET_CANCEL:
617 switch (shell->exposay.state_cur) {
618 case EXPOSAY_LAYOUT_INACTIVE:
619 goto out;
620 case EXPOSAY_LAYOUT_ANIMATE_TO_INACTIVE:
621 state_new = exposay_set_inactive(shell);
622 break;
623 default:
624 state_new = exposay_transition_inactive(shell, do_switch);
625 break;
626 }
627
628 break;
629 }
630
631out:
632 shell->exposay.state_cur = state_new;
633}
634
635static void
636exposay_set_state(struct desktop_shell *shell, enum exposay_target_state state,
637 struct weston_seat *seat)
638{
639 shell->exposay.state_target = state;
640 shell->exposay.seat = seat;
641 exposay_check_state(shell);
642}
643
644void
645exposay_binding(struct weston_seat *seat, enum weston_keyboard_modifier modifier,
646 void *data)
647{
648 struct desktop_shell *shell = data;
649
650 exposay_set_state(shell, EXPOSAY_TARGET_OVERVIEW, seat);
651}