blob: 622aa5a84dc05e5b126ab90ffb94f9980051cf8a [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 *
Bryce Harringtonaf637c22015-06-11 12:55:55 -07006 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
Kristian Høgsberg1ef23132013-12-04 00:20:01 -080012 *
Bryce Harringtonaf637c22015-06-11 12:55:55 -070013 * The above copyright notice and this permission notice (including the next
14 * paragraph) shall be included in all copies or substantial portions of the
15 * Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
Kristian Høgsberg1ef23132013-12-04 00:20:01 -080024 */
25
26#include "config.h"
27
28#include <linux/input.h>
29
30#include "shell.h"
31
32struct exposay_surface {
33 struct desktop_shell *shell;
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +010034 struct exposay_output *eoutput;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -080035 struct weston_surface *surface;
36 struct weston_view *view;
Emilio Pozuelo Monfortf942b732014-02-10 14:23:04 +010037 struct wl_listener view_destroy_listener;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -080038 struct wl_list link;
39
40 int x;
41 int y;
42 int width;
43 int height;
44 double scale;
45
46 int row;
47 int column;
48
49 /* The animations only apply a transformation for their own lifetime,
50 * and don't have an option to indefinitely maintain the
51 * transformation in a steady state - so, we apply our own once the
52 * animation has finished. */
53 struct weston_transform transform;
54};
55
56static void exposay_set_state(struct desktop_shell *shell,
57 enum exposay_target_state state,
58 struct weston_seat *seat);
59static void exposay_check_state(struct desktop_shell *shell);
60
61static void
Emilio Pozuelo Monfortf942b732014-02-10 14:23:04 +010062exposay_surface_destroy(struct exposay_surface *esurface)
63{
64 wl_list_remove(&esurface->link);
65 wl_list_remove(&esurface->view_destroy_listener.link);
66
67 if (esurface->shell->exposay.focus_current == esurface->view)
68 esurface->shell->exposay.focus_current = NULL;
69 if (esurface->shell->exposay.focus_prev == esurface->view)
70 esurface->shell->exposay.focus_prev = NULL;
71
72 free(esurface);
73}
74
75static void
Kristian Høgsberg1ef23132013-12-04 00:20:01 -080076exposay_in_flight_inc(struct desktop_shell *shell)
77{
78 shell->exposay.in_flight++;
79}
80
81static void
82exposay_in_flight_dec(struct desktop_shell *shell)
83{
84 if (--shell->exposay.in_flight > 0)
85 return;
86
87 exposay_check_state(shell);
88}
89
90static void
91exposay_animate_in_done(struct weston_view_animation *animation, void *data)
92{
93 struct exposay_surface *esurface = data;
94
95 wl_list_insert(&esurface->view->geometry.transformation_list,
96 &esurface->transform.link);
97 weston_matrix_init(&esurface->transform.matrix);
98 weston_matrix_scale(&esurface->transform.matrix,
99 esurface->scale, esurface->scale, 1.0f);
100 weston_matrix_translate(&esurface->transform.matrix,
101 esurface->x - esurface->view->geometry.x,
102 esurface->y - esurface->view->geometry.y,
103 0);
104
105 weston_view_geometry_dirty(esurface->view);
106 weston_compositor_schedule_repaint(esurface->view->surface->compositor);
107
108 exposay_in_flight_dec(esurface->shell);
109}
110
111static void
112exposay_animate_in(struct exposay_surface *esurface)
113{
114 exposay_in_flight_inc(esurface->shell);
115
116 weston_move_scale_run(esurface->view,
117 esurface->x - esurface->view->geometry.x,
118 esurface->y - esurface->view->geometry.y,
119 1.0, esurface->scale, 0,
120 exposay_animate_in_done, esurface);
121}
122
123static void
124exposay_animate_out_done(struct weston_view_animation *animation, void *data)
125{
126 struct exposay_surface *esurface = data;
127 struct desktop_shell *shell = esurface->shell;
128
Emilio Pozuelo Monfortf942b732014-02-10 14:23:04 +0100129 exposay_surface_destroy(esurface);
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800130
131 exposay_in_flight_dec(shell);
132}
133
134static void
135exposay_animate_out(struct exposay_surface *esurface)
136{
137 exposay_in_flight_inc(esurface->shell);
138
139 /* Remove the static transformation set up by
140 * exposay_transform_in_done(). */
141 wl_list_remove(&esurface->transform.link);
142 weston_view_geometry_dirty(esurface->view);
143
144 weston_move_scale_run(esurface->view,
145 esurface->x - esurface->view->geometry.x,
146 esurface->y - esurface->view->geometry.y,
147 1.0, esurface->scale, 1,
148 exposay_animate_out_done, esurface);
149}
150
151static void
152exposay_highlight_surface(struct desktop_shell *shell,
153 struct exposay_surface *esurface)
154{
U. Artie Eoff6d6d1902014-01-15 13:42:18 -0800155 struct weston_view *view = esurface->view;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800156
Emilio Pozuelo Monforta7592012014-02-10 16:52:33 +0100157 if (shell->exposay.focus_current == view)
158 return;
159
U. Artie Eoff6d6d1902014-01-15 13:42:18 -0800160 shell->exposay.row_current = esurface->row;
161 shell->exposay.column_current = esurface->column;
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100162 shell->exposay.cur_output = esurface->eoutput;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800163
Emilio Pozuelo Monfort9e7c7592014-01-30 14:01:10 +0100164 activate(shell, view->surface, shell->exposay.seat, false);
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800165 shell->exposay.focus_current = view;
166}
167
168static int
169exposay_is_animating(struct desktop_shell *shell)
170{
171 if (shell->exposay.state_cur == EXPOSAY_LAYOUT_INACTIVE ||
172 shell->exposay.state_cur == EXPOSAY_LAYOUT_OVERVIEW)
173 return 0;
174
175 return (shell->exposay.in_flight > 0);
176}
177
178static void
179exposay_pick(struct desktop_shell *shell, int x, int y)
180{
181 struct exposay_surface *esurface;
182
183 if (exposay_is_animating(shell))
184 return;
185
186 wl_list_for_each(esurface, &shell->exposay.surface_list, link) {
187 if (x < esurface->x || x > esurface->x + esurface->width)
188 continue;
189 if (y < esurface->y || y > esurface->y + esurface->height)
190 continue;
191
192 exposay_highlight_surface(shell, esurface);
193 return;
194 }
195}
196
Emilio Pozuelo Monfortf942b732014-02-10 14:23:04 +0100197static void
198handle_view_destroy(struct wl_listener *listener, void *data)
199{
200 struct exposay_surface *esurface = container_of(listener,
201 struct exposay_surface,
202 view_destroy_listener);
203
204 exposay_surface_destroy(esurface);
205}
206
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800207/* Pretty lame layout for now; just tries to make a square. Should take
208 * aspect ratio into account really. Also needs to be notified of surface
209 * addition and removal and adjust layout/animate accordingly. */
210static enum exposay_layout_state
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100211exposay_layout(struct desktop_shell *shell, struct shell_output *shell_output)
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800212{
213 struct workspace *workspace = shell->exposay.workspace;
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100214 struct weston_output *output = shell_output->output;
215 struct exposay_output *eoutput = &shell_output->eoutput;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800216 struct weston_view *view;
Emilio Pozuelo Monforte6bbe5a2014-01-07 16:41:39 +0100217 struct exposay_surface *esurface, *highlight = NULL;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800218 int w, h;
219 int i;
220 int last_row_removed = 0;
221
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100222 eoutput->num_surfaces = 0;
Giulio Camuffo412e6a52014-07-09 22:12:56 +0300223 wl_list_for_each(view, &workspace->layer.view_list.link, layer_link.link) {
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800224 if (!get_shell_surface(view->surface))
225 continue;
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100226 if (view->output != output)
227 continue;
228 eoutput->num_surfaces++;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800229 }
230
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100231 if (eoutput->num_surfaces == 0) {
232 eoutput->grid_size = 0;
233 eoutput->hpadding_outer = 0;
234 eoutput->vpadding_outer = 0;
235 eoutput->padding_inner = 0;
236 eoutput->surface_size = 0;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800237 return EXPOSAY_LAYOUT_OVERVIEW;
238 }
239
240 /* Lay the grid out as square as possible, losing surfaces from the
241 * bottom row if required. Start with fixed padding of a 10% margin
242 * around the outside and 80px internal padding between surfaces, and
243 * maximise the area made available to surfaces after this, but only
244 * to a maximum of 1/3rd the total output size.
245 *
246 * If we can't make a square grid, add one extra row at the bottom
247 * which will have a smaller number of columns.
248 *
249 * XXX: Surely there has to be a better way to express this maths,
250 * right?!
251 */
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100252 eoutput->grid_size = floor(sqrtf(eoutput->num_surfaces));
253 if (pow(eoutput->grid_size, 2) != eoutput->num_surfaces)
254 eoutput->grid_size++;
255 last_row_removed = pow(eoutput->grid_size, 2) - eoutput->num_surfaces;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800256
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100257 eoutput->hpadding_outer = (output->width / 10);
258 eoutput->vpadding_outer = (output->height / 10);
259 eoutput->padding_inner = 80;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800260
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100261 w = output->width - (eoutput->hpadding_outer * 2);
262 w -= eoutput->padding_inner * (eoutput->grid_size - 1);
263 w /= eoutput->grid_size;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800264
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100265 h = output->height - (eoutput->vpadding_outer * 2);
266 h -= eoutput->padding_inner * (eoutput->grid_size - 1);
267 h /= eoutput->grid_size;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800268
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100269 eoutput->surface_size = (w < h) ? w : h;
270 if (eoutput->surface_size > (output->width / 2))
271 eoutput->surface_size = output->width / 2;
272 if (eoutput->surface_size > (output->height / 2))
273 eoutput->surface_size = output->height / 2;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800274
275 i = 0;
Giulio Camuffo412e6a52014-07-09 22:12:56 +0300276 wl_list_for_each(view, &workspace->layer.view_list.link, layer_link.link) {
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800277 int pad;
278
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100279 pad = eoutput->surface_size + eoutput->padding_inner;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800280
281 if (!get_shell_surface(view->surface))
282 continue;
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100283 if (view->output != output)
284 continue;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800285
286 esurface = malloc(sizeof(*esurface));
287 if (!esurface) {
288 exposay_set_state(shell, EXPOSAY_TARGET_CANCEL,
289 shell->exposay.seat);
290 break;
291 }
292
293 wl_list_insert(&shell->exposay.surface_list, &esurface->link);
294 esurface->shell = shell;
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100295 esurface->eoutput = eoutput;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800296 esurface->view = view;
297
Emilio Pozuelo Monfortf942b732014-02-10 14:23:04 +0100298 esurface->view_destroy_listener.notify = handle_view_destroy;
299 wl_signal_add(&view->destroy_signal, &esurface->view_destroy_listener);
300
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100301 esurface->row = i / eoutput->grid_size;
302 esurface->column = i % eoutput->grid_size;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800303
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100304 esurface->x = output->x + eoutput->hpadding_outer;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800305 esurface->x += pad * esurface->column;
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100306 esurface->y = output->y + eoutput->vpadding_outer;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800307 esurface->y += pad * esurface->row;
308
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100309 if (esurface->row == eoutput->grid_size - 1)
310 esurface->x += (eoutput->surface_size + eoutput->padding_inner) * last_row_removed / 2;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800311
312 if (view->surface->width > view->surface->height)
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100313 esurface->scale = eoutput->surface_size / (float) view->surface->width;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800314 else
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100315 esurface->scale = eoutput->surface_size / (float) view->surface->height;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800316 esurface->width = view->surface->width * esurface->scale;
317 esurface->height = view->surface->height * esurface->scale;
318
319 if (shell->exposay.focus_current == esurface->view)
Emilio Pozuelo Monforte6bbe5a2014-01-07 16:41:39 +0100320 highlight = esurface;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800321
322 exposay_animate_in(esurface);
323
324 i++;
325 }
326
Emilio Pozuelo Monfort5905ebc2014-05-24 02:43:04 +0200327 if (highlight) {
328 shell->exposay.focus_current = NULL;
Emilio Pozuelo Monforte6bbe5a2014-01-07 16:41:39 +0100329 exposay_highlight_surface(shell, highlight);
Emilio Pozuelo Monfort5905ebc2014-05-24 02:43:04 +0200330 }
Emilio Pozuelo Monforte6bbe5a2014-01-07 16:41:39 +0100331
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800332 weston_compositor_schedule_repaint(shell->compositor);
333
334 return EXPOSAY_LAYOUT_ANIMATE_TO_OVERVIEW;
335}
336
337static void
338exposay_focus(struct weston_pointer_grab *grab)
339{
340}
341
342static void
343exposay_motion(struct weston_pointer_grab *grab, uint32_t time,
344 wl_fixed_t x, wl_fixed_t y)
345{
346 struct desktop_shell *shell =
347 container_of(grab, struct desktop_shell, exposay.grab_ptr);
348
349 weston_pointer_move(grab->pointer, x, y);
350
351 exposay_pick(shell,
352 wl_fixed_to_int(grab->pointer->x),
353 wl_fixed_to_int(grab->pointer->y));
354}
355
356static void
357exposay_button(struct weston_pointer_grab *grab, uint32_t time, uint32_t button,
358 uint32_t state_w)
359{
360 struct desktop_shell *shell =
361 container_of(grab, struct desktop_shell, exposay.grab_ptr);
362 struct weston_seat *seat = grab->pointer->seat;
363 enum wl_pointer_button_state state = state_w;
364
365 if (button != BTN_LEFT)
366 return;
367
368 /* Store the surface we clicked on, and don't do anything if we end up
369 * releasing on a different surface. */
370 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
371 shell->exposay.clicked = shell->exposay.focus_current;
372 return;
373 }
374
375 if (shell->exposay.focus_current == shell->exposay.clicked)
376 exposay_set_state(shell, EXPOSAY_TARGET_SWITCH, seat);
377 else
378 shell->exposay.clicked = NULL;
379}
380
381static void
382exposay_pointer_grab_cancel(struct weston_pointer_grab *grab)
383{
384 struct desktop_shell *shell =
385 container_of(grab, struct desktop_shell, exposay.grab_ptr);
386
387 exposay_set_state(shell, EXPOSAY_TARGET_CANCEL, shell->exposay.seat);
388}
389
390static const struct weston_pointer_grab_interface exposay_ptr_grab = {
391 exposay_focus,
392 exposay_motion,
393 exposay_button,
394 exposay_pointer_grab_cancel,
395};
396
397static int
398exposay_maybe_move(struct desktop_shell *shell, int row, int column)
399{
400 struct exposay_surface *esurface;
401
402 wl_list_for_each(esurface, &shell->exposay.surface_list, link) {
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100403 if (esurface->eoutput != shell->exposay.cur_output ||
404 esurface->row != row || esurface->column != column)
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800405 continue;
406
407 exposay_highlight_surface(shell, esurface);
408 return 1;
409 }
410
411 return 0;
412}
413
414static void
415exposay_key(struct weston_keyboard_grab *grab, uint32_t time, uint32_t key,
416 uint32_t state_w)
417{
418 struct weston_seat *seat = grab->keyboard->seat;
419 struct desktop_shell *shell =
420 container_of(grab, struct desktop_shell, exposay.grab_kbd);
421 enum wl_keyboard_key_state state = state_w;
422
423 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
424 return;
425
426 switch (key) {
427 case KEY_ESC:
428 exposay_set_state(shell, EXPOSAY_TARGET_CANCEL, seat);
429 break;
430 case KEY_ENTER:
431 exposay_set_state(shell, EXPOSAY_TARGET_SWITCH, seat);
432 break;
433 case KEY_UP:
434 exposay_maybe_move(shell, shell->exposay.row_current - 1,
435 shell->exposay.column_current);
436 break;
437 case KEY_DOWN:
438 /* Special case for trying to move to the bottom row when it
439 * has fewer items than all the others. */
440 if (!exposay_maybe_move(shell, shell->exposay.row_current + 1,
441 shell->exposay.column_current) &&
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100442 shell->exposay.row_current < (shell->exposay.cur_output->grid_size - 1)) {
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800443 exposay_maybe_move(shell, shell->exposay.row_current + 1,
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100444 (shell->exposay.cur_output->num_surfaces %
445 shell->exposay.cur_output->grid_size) - 1);
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800446 }
447 break;
448 case KEY_LEFT:
449 exposay_maybe_move(shell, shell->exposay.row_current,
450 shell->exposay.column_current - 1);
451 break;
452 case KEY_RIGHT:
453 exposay_maybe_move(shell, shell->exposay.row_current,
454 shell->exposay.column_current + 1);
455 break;
456 case KEY_TAB:
457 /* Try to move right, then down (and to the leftmost column),
458 * then if all else fails, to the top left. */
459 if (!exposay_maybe_move(shell, shell->exposay.row_current,
460 shell->exposay.column_current + 1) &&
461 !exposay_maybe_move(shell, shell->exposay.row_current + 1, 0))
462 exposay_maybe_move(shell, 0, 0);
463 break;
464 default:
465 break;
466 }
467}
468
469static void
470exposay_modifier(struct weston_keyboard_grab *grab, uint32_t serial,
471 uint32_t mods_depressed, uint32_t mods_latched,
472 uint32_t mods_locked, uint32_t group)
473{
474 struct desktop_shell *shell =
475 container_of(grab, struct desktop_shell, exposay.grab_kbd);
476 struct weston_seat *seat = (struct weston_seat *) grab->keyboard->seat;
477
478 /* We want to know when mod has been pressed and released.
479 * FIXME: There is a problem here: if mod is pressed, then a key
480 * is pressed and released, then mod is released, we will treat that
481 * as if only mod had been pressed and released. */
482 if (seat->modifier_state) {
483 if (seat->modifier_state == shell->binding_modifier) {
484 shell->exposay.mod_pressed = true;
485 } else {
486 shell->exposay.mod_invalid = true;
487 }
488 } else {
489 if (shell->exposay.mod_pressed && !shell->exposay.mod_invalid)
490 exposay_set_state(shell, EXPOSAY_TARGET_CANCEL, seat);
491
492 shell->exposay.mod_invalid = false;
493 shell->exposay.mod_pressed = false;
494 }
495
496 return;
497}
498
499static void
500exposay_cancel(struct weston_keyboard_grab *grab)
501{
502 struct desktop_shell *shell =
503 container_of(grab, struct desktop_shell, exposay.grab_kbd);
504
505 exposay_set_state(shell, EXPOSAY_TARGET_CANCEL, shell->exposay.seat);
506}
507
508static const struct weston_keyboard_grab_interface exposay_kbd_grab = {
509 exposay_key,
510 exposay_modifier,
511 exposay_cancel,
512};
513
514/**
515 * Called when the transition from overview -> inactive has completed.
516 */
517static enum exposay_layout_state
518exposay_set_inactive(struct desktop_shell *shell)
519{
520 struct weston_seat *seat = shell->exposay.seat;
521
522 weston_keyboard_end_grab(seat->keyboard);
Derek Foreman3dd570e2015-05-22 11:47:20 -0500523 if (seat->pointer_device_count)
524 weston_pointer_end_grab(seat->pointer);
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800525 if (seat->keyboard->input_method_resource)
526 seat->keyboard->grab = &seat->keyboard->input_method_grab;
527
528 return EXPOSAY_LAYOUT_INACTIVE;
529}
530
531/**
532 * Begins the transition from overview to inactive. */
533static enum exposay_layout_state
534exposay_transition_inactive(struct desktop_shell *shell, int switch_focus)
535{
536 struct exposay_surface *esurface;
537
538 /* Call activate() before we start the animations to avoid
539 * animating back the old state and then immediately transitioning
540 * to the new. */
541 if (switch_focus && shell->exposay.focus_current)
542 activate(shell, shell->exposay.focus_current->surface,
Emilio Pozuelo Monfort9e7c7592014-01-30 14:01:10 +0100543 shell->exposay.seat, true);
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800544 else if (shell->exposay.focus_prev)
545 activate(shell, shell->exposay.focus_prev->surface,
Emilio Pozuelo Monfort9e7c7592014-01-30 14:01:10 +0100546 shell->exposay.seat, true);
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800547
548 wl_list_for_each(esurface, &shell->exposay.surface_list, link)
549 exposay_animate_out(esurface);
550 weston_compositor_schedule_repaint(shell->compositor);
551
552 return EXPOSAY_LAYOUT_ANIMATE_TO_INACTIVE;
553}
554
555static enum exposay_layout_state
556exposay_transition_active(struct desktop_shell *shell)
557{
558 struct weston_seat *seat = shell->exposay.seat;
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100559 struct shell_output *shell_output;
560 bool animate = false;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800561
562 shell->exposay.workspace = get_current_workspace(shell);
563 shell->exposay.focus_prev = get_default_view (seat->keyboard->focus);
564 shell->exposay.focus_current = get_default_view (seat->keyboard->focus);
565 shell->exposay.clicked = NULL;
566 wl_list_init(&shell->exposay.surface_list);
567
568 lower_fullscreen_layer(shell);
569 shell->exposay.grab_kbd.interface = &exposay_kbd_grab;
570 weston_keyboard_start_grab(seat->keyboard,
571 &shell->exposay.grab_kbd);
572 weston_keyboard_set_focus(seat->keyboard, NULL);
573
574 shell->exposay.grab_ptr.interface = &exposay_ptr_grab;
Derek Foreman3dd570e2015-05-22 11:47:20 -0500575 if (seat->pointer_device_count) {
576 weston_pointer_start_grab(seat->pointer,
577 &shell->exposay.grab_ptr);
578 weston_pointer_set_focus(seat->pointer, NULL,
579 seat->pointer->x,
580 seat->pointer->y);
581 }
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100582 wl_list_for_each(shell_output, &shell->output_list, link) {
583 enum exposay_layout_state state;
584
585 state = exposay_layout(shell, shell_output);
586
587 if (state == EXPOSAY_LAYOUT_ANIMATE_TO_OVERVIEW)
588 animate = true;
589 }
590
591 return animate ? EXPOSAY_LAYOUT_ANIMATE_TO_OVERVIEW
592 : EXPOSAY_LAYOUT_OVERVIEW;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800593}
594
595static void
596exposay_check_state(struct desktop_shell *shell)
597{
598 enum exposay_layout_state state_new = shell->exposay.state_cur;
599 int do_switch = 0;
600
601 /* Don't do anything whilst animations are running, just store up
602 * target state changes and only act on them when the animations have
603 * completed. */
604 if (exposay_is_animating(shell))
605 return;
606
607 switch (shell->exposay.state_target) {
608 case EXPOSAY_TARGET_OVERVIEW:
609 switch (shell->exposay.state_cur) {
610 case EXPOSAY_LAYOUT_OVERVIEW:
611 goto out;
612 case EXPOSAY_LAYOUT_ANIMATE_TO_OVERVIEW:
613 state_new = EXPOSAY_LAYOUT_OVERVIEW;
614 break;
615 default:
616 state_new = exposay_transition_active(shell);
617 break;
618 }
619 break;
620
621 case EXPOSAY_TARGET_SWITCH:
622 do_switch = 1; /* fallthrough */
623 case EXPOSAY_TARGET_CANCEL:
624 switch (shell->exposay.state_cur) {
625 case EXPOSAY_LAYOUT_INACTIVE:
626 goto out;
627 case EXPOSAY_LAYOUT_ANIMATE_TO_INACTIVE:
628 state_new = exposay_set_inactive(shell);
629 break;
630 default:
631 state_new = exposay_transition_inactive(shell, do_switch);
632 break;
633 }
634
635 break;
636 }
637
638out:
639 shell->exposay.state_cur = state_new;
640}
641
642static void
643exposay_set_state(struct desktop_shell *shell, enum exposay_target_state state,
644 struct weston_seat *seat)
645{
646 shell->exposay.state_target = state;
647 shell->exposay.seat = seat;
648 exposay_check_state(shell);
649}
650
651void
652exposay_binding(struct weston_seat *seat, enum weston_keyboard_modifier modifier,
653 void *data)
654{
655 struct desktop_shell *shell = data;
656
657 exposay_set_state(shell, EXPOSAY_TARGET_OVERVIEW, seat);
658}