blob: b11a7f7940c277357bf7327ccdbb727db98ade19 [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
Jussi Kukkonen649bbce2016-07-19 14:16:27 +030028#include <stdint.h>
Kristian Høgsberg1ef23132013-12-04 00:20:01 -080029#include <linux/input.h>
30
31#include "shell.h"
Jon Cruz867d50e2015-06-15 15:37:10 -070032#include "shared/helpers.h"
Kristian Høgsberg1ef23132013-12-04 00:20:01 -080033
34struct exposay_surface {
35 struct desktop_shell *shell;
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +010036 struct exposay_output *eoutput;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -080037 struct weston_surface *surface;
38 struct weston_view *view;
Emilio Pozuelo Monfortf942b732014-02-10 14:23:04 +010039 struct wl_listener view_destroy_listener;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -080040 struct wl_list link;
41
42 int x;
43 int y;
44 int width;
45 int height;
46 double scale;
47
48 int row;
49 int column;
50
51 /* The animations only apply a transformation for their own lifetime,
52 * and don't have an option to indefinitely maintain the
53 * transformation in a steady state - so, we apply our own once the
54 * animation has finished. */
55 struct weston_transform transform;
56};
57
58static void exposay_set_state(struct desktop_shell *shell,
59 enum exposay_target_state state,
60 struct weston_seat *seat);
61static void exposay_check_state(struct desktop_shell *shell);
62
63static void
Emilio Pozuelo Monfortf942b732014-02-10 14:23:04 +010064exposay_surface_destroy(struct exposay_surface *esurface)
65{
66 wl_list_remove(&esurface->link);
67 wl_list_remove(&esurface->view_destroy_listener.link);
68
69 if (esurface->shell->exposay.focus_current == esurface->view)
70 esurface->shell->exposay.focus_current = NULL;
71 if (esurface->shell->exposay.focus_prev == esurface->view)
72 esurface->shell->exposay.focus_prev = NULL;
73
74 free(esurface);
75}
76
77static void
Kristian Høgsberg1ef23132013-12-04 00:20:01 -080078exposay_in_flight_inc(struct desktop_shell *shell)
79{
80 shell->exposay.in_flight++;
81}
82
83static void
84exposay_in_flight_dec(struct desktop_shell *shell)
85{
86 if (--shell->exposay.in_flight > 0)
87 return;
88
89 exposay_check_state(shell);
90}
91
92static void
93exposay_animate_in_done(struct weston_view_animation *animation, void *data)
94{
95 struct exposay_surface *esurface = data;
96
97 wl_list_insert(&esurface->view->geometry.transformation_list,
98 &esurface->transform.link);
99 weston_matrix_init(&esurface->transform.matrix);
100 weston_matrix_scale(&esurface->transform.matrix,
101 esurface->scale, esurface->scale, 1.0f);
102 weston_matrix_translate(&esurface->transform.matrix,
103 esurface->x - esurface->view->geometry.x,
104 esurface->y - esurface->view->geometry.y,
105 0);
106
107 weston_view_geometry_dirty(esurface->view);
108 weston_compositor_schedule_repaint(esurface->view->surface->compositor);
109
110 exposay_in_flight_dec(esurface->shell);
111}
112
113static void
114exposay_animate_in(struct exposay_surface *esurface)
115{
116 exposay_in_flight_inc(esurface->shell);
117
118 weston_move_scale_run(esurface->view,
119 esurface->x - esurface->view->geometry.x,
120 esurface->y - esurface->view->geometry.y,
121 1.0, esurface->scale, 0,
122 exposay_animate_in_done, esurface);
123}
124
125static void
126exposay_animate_out_done(struct weston_view_animation *animation, void *data)
127{
128 struct exposay_surface *esurface = data;
129 struct desktop_shell *shell = esurface->shell;
130
Emilio Pozuelo Monfortf942b732014-02-10 14:23:04 +0100131 exposay_surface_destroy(esurface);
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800132
133 exposay_in_flight_dec(shell);
134}
135
136static void
137exposay_animate_out(struct exposay_surface *esurface)
138{
139 exposay_in_flight_inc(esurface->shell);
140
141 /* Remove the static transformation set up by
142 * exposay_transform_in_done(). */
143 wl_list_remove(&esurface->transform.link);
144 weston_view_geometry_dirty(esurface->view);
145
146 weston_move_scale_run(esurface->view,
147 esurface->x - esurface->view->geometry.x,
148 esurface->y - esurface->view->geometry.y,
149 1.0, esurface->scale, 1,
150 exposay_animate_out_done, esurface);
151}
152
153static void
154exposay_highlight_surface(struct desktop_shell *shell,
155 struct exposay_surface *esurface)
156{
U. Artie Eoff6d6d1902014-01-15 13:42:18 -0800157 struct weston_view *view = esurface->view;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800158
Emilio Pozuelo Monforta7592012014-02-10 16:52:33 +0100159 if (shell->exposay.focus_current == view)
160 return;
161
U. Artie Eoff6d6d1902014-01-15 13:42:18 -0800162 shell->exposay.row_current = esurface->row;
163 shell->exposay.column_current = esurface->column;
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100164 shell->exposay.cur_output = esurface->eoutput;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800165
Jonas Ådahl4361b4e2014-10-18 18:20:16 +0200166 activate(shell, view, shell->exposay.seat,
167 WESTON_ACTIVATE_FLAG_NONE);
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800168 shell->exposay.focus_current = view;
169}
170
171static int
172exposay_is_animating(struct desktop_shell *shell)
173{
174 if (shell->exposay.state_cur == EXPOSAY_LAYOUT_INACTIVE ||
175 shell->exposay.state_cur == EXPOSAY_LAYOUT_OVERVIEW)
176 return 0;
177
178 return (shell->exposay.in_flight > 0);
179}
180
181static void
182exposay_pick(struct desktop_shell *shell, int x, int y)
183{
184 struct exposay_surface *esurface;
185
186 if (exposay_is_animating(shell))
187 return;
188
189 wl_list_for_each(esurface, &shell->exposay.surface_list, link) {
190 if (x < esurface->x || x > esurface->x + esurface->width)
191 continue;
192 if (y < esurface->y || y > esurface->y + esurface->height)
193 continue;
194
195 exposay_highlight_surface(shell, esurface);
196 return;
197 }
198}
199
Emilio Pozuelo Monfortf942b732014-02-10 14:23:04 +0100200static void
201handle_view_destroy(struct wl_listener *listener, void *data)
202{
203 struct exposay_surface *esurface = container_of(listener,
204 struct exposay_surface,
205 view_destroy_listener);
206
207 exposay_surface_destroy(esurface);
208}
209
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800210/* Pretty lame layout for now; just tries to make a square. Should take
211 * aspect ratio into account really. Also needs to be notified of surface
212 * addition and removal and adjust layout/animate accordingly. */
213static enum exposay_layout_state
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100214exposay_layout(struct desktop_shell *shell, struct shell_output *shell_output)
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800215{
216 struct workspace *workspace = shell->exposay.workspace;
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100217 struct weston_output *output = shell_output->output;
218 struct exposay_output *eoutput = &shell_output->eoutput;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800219 struct weston_view *view;
Emilio Pozuelo Monforte6bbe5a2014-01-07 16:41:39 +0100220 struct exposay_surface *esurface, *highlight = NULL;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800221 int w, h;
222 int i;
223 int last_row_removed = 0;
224
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100225 eoutput->num_surfaces = 0;
Giulio Camuffo412e6a52014-07-09 22:12:56 +0300226 wl_list_for_each(view, &workspace->layer.view_list.link, layer_link.link) {
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800227 if (!get_shell_surface(view->surface))
228 continue;
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100229 if (view->output != output)
230 continue;
231 eoutput->num_surfaces++;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800232 }
233
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100234 if (eoutput->num_surfaces == 0) {
235 eoutput->grid_size = 0;
236 eoutput->hpadding_outer = 0;
237 eoutput->vpadding_outer = 0;
238 eoutput->padding_inner = 0;
239 eoutput->surface_size = 0;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800240 return EXPOSAY_LAYOUT_OVERVIEW;
241 }
242
243 /* Lay the grid out as square as possible, losing surfaces from the
244 * bottom row if required. Start with fixed padding of a 10% margin
245 * around the outside and 80px internal padding between surfaces, and
246 * maximise the area made available to surfaces after this, but only
247 * to a maximum of 1/3rd the total output size.
248 *
249 * If we can't make a square grid, add one extra row at the bottom
250 * which will have a smaller number of columns.
251 *
252 * XXX: Surely there has to be a better way to express this maths,
253 * right?!
254 */
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100255 eoutput->grid_size = floor(sqrtf(eoutput->num_surfaces));
256 if (pow(eoutput->grid_size, 2) != eoutput->num_surfaces)
257 eoutput->grid_size++;
258 last_row_removed = pow(eoutput->grid_size, 2) - eoutput->num_surfaces;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800259
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100260 eoutput->hpadding_outer = (output->width / 10);
261 eoutput->vpadding_outer = (output->height / 10);
262 eoutput->padding_inner = 80;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800263
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100264 w = output->width - (eoutput->hpadding_outer * 2);
265 w -= eoutput->padding_inner * (eoutput->grid_size - 1);
266 w /= eoutput->grid_size;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800267
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100268 h = output->height - (eoutput->vpadding_outer * 2);
269 h -= eoutput->padding_inner * (eoutput->grid_size - 1);
270 h /= eoutput->grid_size;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800271
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100272 eoutput->surface_size = (w < h) ? w : h;
273 if (eoutput->surface_size > (output->width / 2))
274 eoutput->surface_size = output->width / 2;
275 if (eoutput->surface_size > (output->height / 2))
276 eoutput->surface_size = output->height / 2;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800277
278 i = 0;
Giulio Camuffo412e6a52014-07-09 22:12:56 +0300279 wl_list_for_each(view, &workspace->layer.view_list.link, layer_link.link) {
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800280 int pad;
281
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100282 pad = eoutput->surface_size + eoutput->padding_inner;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800283
284 if (!get_shell_surface(view->surface))
285 continue;
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100286 if (view->output != output)
287 continue;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800288
289 esurface = malloc(sizeof(*esurface));
290 if (!esurface) {
291 exposay_set_state(shell, EXPOSAY_TARGET_CANCEL,
292 shell->exposay.seat);
293 break;
294 }
295
296 wl_list_insert(&shell->exposay.surface_list, &esurface->link);
297 esurface->shell = shell;
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100298 esurface->eoutput = eoutput;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800299 esurface->view = view;
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
Derek Foremand8156e22015-05-26 16:21:05 -0500324 /* We want our destroy handler to be after the animation
325 * destroy handler in the list, this way when the view is
326 * destroyed, the animation can safely call the animation
327 * completion callback before we free the esurface in our
328 * destroy handler.
329 */
330 esurface->view_destroy_listener.notify = handle_view_destroy;
331 wl_signal_add(&view->destroy_signal, &esurface->view_destroy_listener);
332
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800333 i++;
334 }
335
Emilio Pozuelo Monfort5905ebc2014-05-24 02:43:04 +0200336 if (highlight) {
337 shell->exposay.focus_current = NULL;
Emilio Pozuelo Monforte6bbe5a2014-01-07 16:41:39 +0100338 exposay_highlight_surface(shell, highlight);
Emilio Pozuelo Monfort5905ebc2014-05-24 02:43:04 +0200339 }
Emilio Pozuelo Monforte6bbe5a2014-01-07 16:41:39 +0100340
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800341 weston_compositor_schedule_repaint(shell->compositor);
342
343 return EXPOSAY_LAYOUT_ANIMATE_TO_OVERVIEW;
344}
345
346static void
347exposay_focus(struct weston_pointer_grab *grab)
348{
349}
350
351static void
352exposay_motion(struct weston_pointer_grab *grab, uint32_t time,
Jonas Ådahld2510102014-10-05 21:39:14 +0200353 struct weston_pointer_motion_event *event)
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800354{
355 struct desktop_shell *shell =
356 container_of(grab, struct desktop_shell, exposay.grab_ptr);
357
Jonas Ådahld2510102014-10-05 21:39:14 +0200358 weston_pointer_move(grab->pointer, event);
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800359
360 exposay_pick(shell,
361 wl_fixed_to_int(grab->pointer->x),
362 wl_fixed_to_int(grab->pointer->y));
363}
364
365static void
366exposay_button(struct weston_pointer_grab *grab, uint32_t time, uint32_t button,
367 uint32_t state_w)
368{
369 struct desktop_shell *shell =
370 container_of(grab, struct desktop_shell, exposay.grab_ptr);
371 struct weston_seat *seat = grab->pointer->seat;
372 enum wl_pointer_button_state state = state_w;
373
374 if (button != BTN_LEFT)
375 return;
376
377 /* Store the surface we clicked on, and don't do anything if we end up
378 * releasing on a different surface. */
379 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
380 shell->exposay.clicked = shell->exposay.focus_current;
381 return;
382 }
383
384 if (shell->exposay.focus_current == shell->exposay.clicked)
385 exposay_set_state(shell, EXPOSAY_TARGET_SWITCH, seat);
386 else
387 shell->exposay.clicked = NULL;
388}
389
390static void
Jonas Ådahl0336ca02014-10-04 16:28:29 +0200391exposay_axis(struct weston_pointer_grab *grab,
Peter Hutterer89b6a492016-01-18 15:58:17 +1000392 uint32_t time, struct weston_pointer_axis_event *event)
Jonas Ådahl0336ca02014-10-04 16:28:29 +0200393{
394}
395
396static void
Peter Hutterer87743e92016-01-18 16:38:22 +1000397exposay_axis_source(struct weston_pointer_grab *grab, uint32_t source)
398{
399}
400
401static void
402exposay_frame(struct weston_pointer_grab *grab)
403{
404}
405
406static void
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800407exposay_pointer_grab_cancel(struct weston_pointer_grab *grab)
408{
409 struct desktop_shell *shell =
410 container_of(grab, struct desktop_shell, exposay.grab_ptr);
411
412 exposay_set_state(shell, EXPOSAY_TARGET_CANCEL, shell->exposay.seat);
413}
414
415static const struct weston_pointer_grab_interface exposay_ptr_grab = {
416 exposay_focus,
417 exposay_motion,
418 exposay_button,
Jonas Ådahl0336ca02014-10-04 16:28:29 +0200419 exposay_axis,
Peter Hutterer87743e92016-01-18 16:38:22 +1000420 exposay_axis_source,
421 exposay_frame,
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800422 exposay_pointer_grab_cancel,
423};
424
425static int
426exposay_maybe_move(struct desktop_shell *shell, int row, int column)
427{
428 struct exposay_surface *esurface;
429
430 wl_list_for_each(esurface, &shell->exposay.surface_list, link) {
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100431 if (esurface->eoutput != shell->exposay.cur_output ||
432 esurface->row != row || esurface->column != column)
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800433 continue;
434
435 exposay_highlight_surface(shell, esurface);
436 return 1;
437 }
438
439 return 0;
440}
441
442static void
443exposay_key(struct weston_keyboard_grab *grab, uint32_t time, uint32_t key,
444 uint32_t state_w)
445{
446 struct weston_seat *seat = grab->keyboard->seat;
447 struct desktop_shell *shell =
448 container_of(grab, struct desktop_shell, exposay.grab_kbd);
449 enum wl_keyboard_key_state state = state_w;
450
451 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
452 return;
453
454 switch (key) {
455 case KEY_ESC:
456 exposay_set_state(shell, EXPOSAY_TARGET_CANCEL, seat);
457 break;
458 case KEY_ENTER:
459 exposay_set_state(shell, EXPOSAY_TARGET_SWITCH, seat);
460 break;
461 case KEY_UP:
462 exposay_maybe_move(shell, shell->exposay.row_current - 1,
463 shell->exposay.column_current);
464 break;
465 case KEY_DOWN:
466 /* Special case for trying to move to the bottom row when it
467 * has fewer items than all the others. */
468 if (!exposay_maybe_move(shell, shell->exposay.row_current + 1,
469 shell->exposay.column_current) &&
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100470 shell->exposay.row_current < (shell->exposay.cur_output->grid_size - 1)) {
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800471 exposay_maybe_move(shell, shell->exposay.row_current + 1,
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100472 (shell->exposay.cur_output->num_surfaces %
473 shell->exposay.cur_output->grid_size) - 1);
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800474 }
475 break;
476 case KEY_LEFT:
477 exposay_maybe_move(shell, shell->exposay.row_current,
478 shell->exposay.column_current - 1);
479 break;
480 case KEY_RIGHT:
481 exposay_maybe_move(shell, shell->exposay.row_current,
482 shell->exposay.column_current + 1);
483 break;
484 case KEY_TAB:
485 /* Try to move right, then down (and to the leftmost column),
486 * then if all else fails, to the top left. */
487 if (!exposay_maybe_move(shell, shell->exposay.row_current,
488 shell->exposay.column_current + 1) &&
489 !exposay_maybe_move(shell, shell->exposay.row_current + 1, 0))
490 exposay_maybe_move(shell, 0, 0);
491 break;
492 default:
493 break;
494 }
495}
496
497static void
498exposay_modifier(struct weston_keyboard_grab *grab, uint32_t serial,
499 uint32_t mods_depressed, uint32_t mods_latched,
500 uint32_t mods_locked, uint32_t group)
501{
502 struct desktop_shell *shell =
503 container_of(grab, struct desktop_shell, exposay.grab_kbd);
504 struct weston_seat *seat = (struct weston_seat *) grab->keyboard->seat;
505
506 /* We want to know when mod has been pressed and released.
507 * FIXME: There is a problem here: if mod is pressed, then a key
508 * is pressed and released, then mod is released, we will treat that
509 * as if only mod had been pressed and released. */
510 if (seat->modifier_state) {
511 if (seat->modifier_state == shell->binding_modifier) {
512 shell->exposay.mod_pressed = true;
513 } else {
514 shell->exposay.mod_invalid = true;
515 }
516 } else {
517 if (shell->exposay.mod_pressed && !shell->exposay.mod_invalid)
518 exposay_set_state(shell, EXPOSAY_TARGET_CANCEL, seat);
519
520 shell->exposay.mod_invalid = false;
521 shell->exposay.mod_pressed = false;
522 }
523
524 return;
525}
526
527static void
528exposay_cancel(struct weston_keyboard_grab *grab)
529{
530 struct desktop_shell *shell =
531 container_of(grab, struct desktop_shell, exposay.grab_kbd);
532
533 exposay_set_state(shell, EXPOSAY_TARGET_CANCEL, shell->exposay.seat);
534}
535
536static const struct weston_keyboard_grab_interface exposay_kbd_grab = {
537 exposay_key,
538 exposay_modifier,
539 exposay_cancel,
540};
541
542/**
543 * Called when the transition from overview -> inactive has completed.
544 */
545static enum exposay_layout_state
546exposay_set_inactive(struct desktop_shell *shell)
547{
548 struct weston_seat *seat = shell->exposay.seat;
Derek Foreman1281a362015-07-31 16:55:32 -0500549 struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
550 struct weston_pointer *pointer = weston_seat_get_pointer(seat);
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800551
Derek Foreman1281a362015-07-31 16:55:32 -0500552 if (pointer)
553 weston_pointer_end_grab(pointer);
Derek Foremancee82d62015-07-15 13:00:33 -0500554
Derek Foreman1281a362015-07-31 16:55:32 -0500555 if (keyboard) {
556 weston_keyboard_end_grab(keyboard);
557 if (keyboard->input_method_resource)
558 keyboard->grab = &keyboard->input_method_grab;
Derek Foremancee82d62015-07-15 13:00:33 -0500559 }
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800560
561 return EXPOSAY_LAYOUT_INACTIVE;
562}
563
564/**
565 * Begins the transition from overview to inactive. */
566static enum exposay_layout_state
567exposay_transition_inactive(struct desktop_shell *shell, int switch_focus)
568{
569 struct exposay_surface *esurface;
570
571 /* Call activate() before we start the animations to avoid
572 * animating back the old state and then immediately transitioning
573 * to the new. */
574 if (switch_focus && shell->exposay.focus_current)
Jonas Ådahl1fa6ded2014-10-18 13:24:53 +0200575 activate(shell, shell->exposay.focus_current,
Jonas Ådahl4361b4e2014-10-18 18:20:16 +0200576 shell->exposay.seat,
577 WESTON_ACTIVATE_FLAG_CONFIGURE);
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800578 else if (shell->exposay.focus_prev)
Jonas Ådahl1fa6ded2014-10-18 13:24:53 +0200579 activate(shell, shell->exposay.focus_prev,
Jonas Ådahl4361b4e2014-10-18 18:20:16 +0200580 shell->exposay.seat,
581 WESTON_ACTIVATE_FLAG_CONFIGURE);
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800582
583 wl_list_for_each(esurface, &shell->exposay.surface_list, link)
584 exposay_animate_out(esurface);
585 weston_compositor_schedule_repaint(shell->compositor);
586
587 return EXPOSAY_LAYOUT_ANIMATE_TO_INACTIVE;
588}
589
590static enum exposay_layout_state
591exposay_transition_active(struct desktop_shell *shell)
592{
593 struct weston_seat *seat = shell->exposay.seat;
Derek Foreman1281a362015-07-31 16:55:32 -0500594 struct weston_pointer *pointer = weston_seat_get_pointer(seat);
595 struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100596 struct shell_output *shell_output;
597 bool animate = false;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800598
599 shell->exposay.workspace = get_current_workspace(shell);
Derek Foreman1281a362015-07-31 16:55:32 -0500600 shell->exposay.focus_prev = get_default_view(keyboard->focus);
601 shell->exposay.focus_current = get_default_view(keyboard->focus);
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800602 shell->exposay.clicked = NULL;
603 wl_list_init(&shell->exposay.surface_list);
604
Mario Kleiner9f4d6552015-06-21 21:25:08 +0200605 lower_fullscreen_layer(shell, NULL);
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800606 shell->exposay.grab_kbd.interface = &exposay_kbd_grab;
Derek Foreman1281a362015-07-31 16:55:32 -0500607 weston_keyboard_start_grab(keyboard,
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800608 &shell->exposay.grab_kbd);
Derek Foreman1281a362015-07-31 16:55:32 -0500609 weston_keyboard_set_focus(keyboard, NULL);
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800610
611 shell->exposay.grab_ptr.interface = &exposay_ptr_grab;
Derek Foreman1281a362015-07-31 16:55:32 -0500612 if (pointer) {
613 weston_pointer_start_grab(pointer,
Derek Foreman3dd570e2015-05-22 11:47:20 -0500614 &shell->exposay.grab_ptr);
Derek Foremanf9318d12015-05-11 15:40:11 -0500615 weston_pointer_clear_focus(pointer);
Derek Foreman3dd570e2015-05-22 11:47:20 -0500616 }
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100617 wl_list_for_each(shell_output, &shell->output_list, link) {
618 enum exposay_layout_state state;
619
620 state = exposay_layout(shell, shell_output);
621
622 if (state == EXPOSAY_LAYOUT_ANIMATE_TO_OVERVIEW)
623 animate = true;
624 }
625
626 return animate ? EXPOSAY_LAYOUT_ANIMATE_TO_OVERVIEW
627 : EXPOSAY_LAYOUT_OVERVIEW;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800628}
629
630static void
631exposay_check_state(struct desktop_shell *shell)
632{
633 enum exposay_layout_state state_new = shell->exposay.state_cur;
634 int do_switch = 0;
635
636 /* Don't do anything whilst animations are running, just store up
637 * target state changes and only act on them when the animations have
638 * completed. */
639 if (exposay_is_animating(shell))
640 return;
641
642 switch (shell->exposay.state_target) {
643 case EXPOSAY_TARGET_OVERVIEW:
644 switch (shell->exposay.state_cur) {
645 case EXPOSAY_LAYOUT_OVERVIEW:
646 goto out;
647 case EXPOSAY_LAYOUT_ANIMATE_TO_OVERVIEW:
648 state_new = EXPOSAY_LAYOUT_OVERVIEW;
649 break;
650 default:
651 state_new = exposay_transition_active(shell);
652 break;
653 }
654 break;
655
656 case EXPOSAY_TARGET_SWITCH:
657 do_switch = 1; /* fallthrough */
658 case EXPOSAY_TARGET_CANCEL:
659 switch (shell->exposay.state_cur) {
660 case EXPOSAY_LAYOUT_INACTIVE:
661 goto out;
662 case EXPOSAY_LAYOUT_ANIMATE_TO_INACTIVE:
663 state_new = exposay_set_inactive(shell);
664 break;
665 default:
666 state_new = exposay_transition_inactive(shell, do_switch);
667 break;
668 }
669
670 break;
671 }
672
673out:
674 shell->exposay.state_cur = state_new;
675}
676
677static void
678exposay_set_state(struct desktop_shell *shell, enum exposay_target_state state,
679 struct weston_seat *seat)
680{
681 shell->exposay.state_target = state;
682 shell->exposay.seat = seat;
683 exposay_check_state(shell);
684}
685
686void
Derek Foreman8ae2db52015-07-15 13:00:36 -0500687exposay_binding(struct weston_keyboard *keyboard, enum weston_keyboard_modifier modifier,
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800688 void *data)
689{
690 struct desktop_shell *shell = data;
691
Derek Foreman8ae2db52015-07-15 13:00:36 -0500692 exposay_set_state(shell, EXPOSAY_TARGET_OVERVIEW, keyboard->seat);
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800693}