blob: f05fa4c569c701c4c08d561cce4dbb3450db253b [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"
Jon Cruz867d50e2015-06-15 15:37:10 -070031#include "shared/helpers.h"
Kristian Høgsberg1ef23132013-12-04 00:20:01 -080032
33struct exposay_surface {
34 struct desktop_shell *shell;
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +010035 struct exposay_output *eoutput;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -080036 struct weston_surface *surface;
37 struct weston_view *view;
Emilio Pozuelo Monfortf942b732014-02-10 14:23:04 +010038 struct wl_listener view_destroy_listener;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -080039 struct wl_list link;
40
41 int x;
42 int y;
43 int width;
44 int height;
45 double scale;
46
47 int row;
48 int column;
49
50 /* The animations only apply a transformation for their own lifetime,
51 * and don't have an option to indefinitely maintain the
52 * transformation in a steady state - so, we apply our own once the
53 * animation has finished. */
54 struct weston_transform transform;
55};
56
57static void exposay_set_state(struct desktop_shell *shell,
58 enum exposay_target_state state,
59 struct weston_seat *seat);
60static void exposay_check_state(struct desktop_shell *shell);
61
62static void
Emilio Pozuelo Monfortf942b732014-02-10 14:23:04 +010063exposay_surface_destroy(struct exposay_surface *esurface)
64{
65 wl_list_remove(&esurface->link);
66 wl_list_remove(&esurface->view_destroy_listener.link);
67
68 if (esurface->shell->exposay.focus_current == esurface->view)
69 esurface->shell->exposay.focus_current = NULL;
70 if (esurface->shell->exposay.focus_prev == esurface->view)
71 esurface->shell->exposay.focus_prev = NULL;
72
73 free(esurface);
74}
75
76static void
Kristian Høgsberg1ef23132013-12-04 00:20:01 -080077exposay_in_flight_inc(struct desktop_shell *shell)
78{
79 shell->exposay.in_flight++;
80}
81
82static void
83exposay_in_flight_dec(struct desktop_shell *shell)
84{
85 if (--shell->exposay.in_flight > 0)
86 return;
87
88 exposay_check_state(shell);
89}
90
91static void
92exposay_animate_in_done(struct weston_view_animation *animation, void *data)
93{
94 struct exposay_surface *esurface = data;
95
96 wl_list_insert(&esurface->view->geometry.transformation_list,
97 &esurface->transform.link);
98 weston_matrix_init(&esurface->transform.matrix);
99 weston_matrix_scale(&esurface->transform.matrix,
100 esurface->scale, esurface->scale, 1.0f);
101 weston_matrix_translate(&esurface->transform.matrix,
102 esurface->x - esurface->view->geometry.x,
103 esurface->y - esurface->view->geometry.y,
104 0);
105
106 weston_view_geometry_dirty(esurface->view);
107 weston_compositor_schedule_repaint(esurface->view->surface->compositor);
108
109 exposay_in_flight_dec(esurface->shell);
110}
111
112static void
113exposay_animate_in(struct exposay_surface *esurface)
114{
115 exposay_in_flight_inc(esurface->shell);
116
117 weston_move_scale_run(esurface->view,
118 esurface->x - esurface->view->geometry.x,
119 esurface->y - esurface->view->geometry.y,
120 1.0, esurface->scale, 0,
121 exposay_animate_in_done, esurface);
122}
123
124static void
125exposay_animate_out_done(struct weston_view_animation *animation, void *data)
126{
127 struct exposay_surface *esurface = data;
128 struct desktop_shell *shell = esurface->shell;
129
Emilio Pozuelo Monfortf942b732014-02-10 14:23:04 +0100130 exposay_surface_destroy(esurface);
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800131
132 exposay_in_flight_dec(shell);
133}
134
135static void
136exposay_animate_out(struct exposay_surface *esurface)
137{
138 exposay_in_flight_inc(esurface->shell);
139
140 /* Remove the static transformation set up by
141 * exposay_transform_in_done(). */
142 wl_list_remove(&esurface->transform.link);
143 weston_view_geometry_dirty(esurface->view);
144
145 weston_move_scale_run(esurface->view,
146 esurface->x - esurface->view->geometry.x,
147 esurface->y - esurface->view->geometry.y,
148 1.0, esurface->scale, 1,
149 exposay_animate_out_done, esurface);
150}
151
152static void
153exposay_highlight_surface(struct desktop_shell *shell,
154 struct exposay_surface *esurface)
155{
U. Artie Eoff6d6d1902014-01-15 13:42:18 -0800156 struct weston_view *view = esurface->view;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800157
Emilio Pozuelo Monforta7592012014-02-10 16:52:33 +0100158 if (shell->exposay.focus_current == view)
159 return;
160
U. Artie Eoff6d6d1902014-01-15 13:42:18 -0800161 shell->exposay.row_current = esurface->row;
162 shell->exposay.column_current = esurface->column;
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100163 shell->exposay.cur_output = esurface->eoutput;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800164
Jonas Ådahl4361b4e2014-10-18 18:20:16 +0200165 activate(shell, view, shell->exposay.seat,
166 WESTON_ACTIVATE_FLAG_NONE);
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800167 shell->exposay.focus_current = view;
168}
169
170static int
171exposay_is_animating(struct desktop_shell *shell)
172{
173 if (shell->exposay.state_cur == EXPOSAY_LAYOUT_INACTIVE ||
174 shell->exposay.state_cur == EXPOSAY_LAYOUT_OVERVIEW)
175 return 0;
176
177 return (shell->exposay.in_flight > 0);
178}
179
180static void
181exposay_pick(struct desktop_shell *shell, int x, int y)
182{
183 struct exposay_surface *esurface;
184
185 if (exposay_is_animating(shell))
186 return;
187
188 wl_list_for_each(esurface, &shell->exposay.surface_list, link) {
189 if (x < esurface->x || x > esurface->x + esurface->width)
190 continue;
191 if (y < esurface->y || y > esurface->y + esurface->height)
192 continue;
193
194 exposay_highlight_surface(shell, esurface);
195 return;
196 }
197}
198
Emilio Pozuelo Monfortf942b732014-02-10 14:23:04 +0100199static void
200handle_view_destroy(struct wl_listener *listener, void *data)
201{
202 struct exposay_surface *esurface = container_of(listener,
203 struct exposay_surface,
204 view_destroy_listener);
205
206 exposay_surface_destroy(esurface);
207}
208
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800209/* Pretty lame layout for now; just tries to make a square. Should take
210 * aspect ratio into account really. Also needs to be notified of surface
211 * addition and removal and adjust layout/animate accordingly. */
212static enum exposay_layout_state
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100213exposay_layout(struct desktop_shell *shell, struct shell_output *shell_output)
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800214{
215 struct workspace *workspace = shell->exposay.workspace;
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100216 struct weston_output *output = shell_output->output;
217 struct exposay_output *eoutput = &shell_output->eoutput;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800218 struct weston_view *view;
Emilio Pozuelo Monforte6bbe5a2014-01-07 16:41:39 +0100219 struct exposay_surface *esurface, *highlight = NULL;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800220 int w, h;
221 int i;
222 int last_row_removed = 0;
223
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100224 eoutput->num_surfaces = 0;
Giulio Camuffo412e6a52014-07-09 22:12:56 +0300225 wl_list_for_each(view, &workspace->layer.view_list.link, layer_link.link) {
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800226 if (!get_shell_surface(view->surface))
227 continue;
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100228 if (view->output != output)
229 continue;
230 eoutput->num_surfaces++;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800231 }
232
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100233 if (eoutput->num_surfaces == 0) {
234 eoutput->grid_size = 0;
235 eoutput->hpadding_outer = 0;
236 eoutput->vpadding_outer = 0;
237 eoutput->padding_inner = 0;
238 eoutput->surface_size = 0;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800239 return EXPOSAY_LAYOUT_OVERVIEW;
240 }
241
242 /* Lay the grid out as square as possible, losing surfaces from the
243 * bottom row if required. Start with fixed padding of a 10% margin
244 * around the outside and 80px internal padding between surfaces, and
245 * maximise the area made available to surfaces after this, but only
246 * to a maximum of 1/3rd the total output size.
247 *
248 * If we can't make a square grid, add one extra row at the bottom
249 * which will have a smaller number of columns.
250 *
251 * XXX: Surely there has to be a better way to express this maths,
252 * right?!
253 */
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100254 eoutput->grid_size = floor(sqrtf(eoutput->num_surfaces));
255 if (pow(eoutput->grid_size, 2) != eoutput->num_surfaces)
256 eoutput->grid_size++;
257 last_row_removed = pow(eoutput->grid_size, 2) - eoutput->num_surfaces;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800258
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100259 eoutput->hpadding_outer = (output->width / 10);
260 eoutput->vpadding_outer = (output->height / 10);
261 eoutput->padding_inner = 80;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800262
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100263 w = output->width - (eoutput->hpadding_outer * 2);
264 w -= eoutput->padding_inner * (eoutput->grid_size - 1);
265 w /= eoutput->grid_size;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800266
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100267 h = output->height - (eoutput->vpadding_outer * 2);
268 h -= eoutput->padding_inner * (eoutput->grid_size - 1);
269 h /= eoutput->grid_size;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800270
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100271 eoutput->surface_size = (w < h) ? w : h;
272 if (eoutput->surface_size > (output->width / 2))
273 eoutput->surface_size = output->width / 2;
274 if (eoutput->surface_size > (output->height / 2))
275 eoutput->surface_size = output->height / 2;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800276
277 i = 0;
Giulio Camuffo412e6a52014-07-09 22:12:56 +0300278 wl_list_for_each(view, &workspace->layer.view_list.link, layer_link.link) {
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800279 int pad;
280
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100281 pad = eoutput->surface_size + eoutput->padding_inner;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800282
283 if (!get_shell_surface(view->surface))
284 continue;
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100285 if (view->output != output)
286 continue;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800287
288 esurface = malloc(sizeof(*esurface));
289 if (!esurface) {
290 exposay_set_state(shell, EXPOSAY_TARGET_CANCEL,
291 shell->exposay.seat);
292 break;
293 }
294
295 wl_list_insert(&shell->exposay.surface_list, &esurface->link);
296 esurface->shell = shell;
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100297 esurface->eoutput = eoutput;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800298 esurface->view = view;
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
321 exposay_animate_in(esurface);
322
Derek Foremand8156e22015-05-26 16:21:05 -0500323 /* We want our destroy handler to be after the animation
324 * destroy handler in the list, this way when the view is
325 * destroyed, the animation can safely call the animation
326 * completion callback before we free the esurface in our
327 * destroy handler.
328 */
329 esurface->view_destroy_listener.notify = handle_view_destroy;
330 wl_signal_add(&view->destroy_signal, &esurface->view_destroy_listener);
331
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800332 i++;
333 }
334
Emilio Pozuelo Monfort5905ebc2014-05-24 02:43:04 +0200335 if (highlight) {
336 shell->exposay.focus_current = NULL;
Emilio Pozuelo Monforte6bbe5a2014-01-07 16:41:39 +0100337 exposay_highlight_surface(shell, highlight);
Emilio Pozuelo Monfort5905ebc2014-05-24 02:43:04 +0200338 }
Emilio Pozuelo Monforte6bbe5a2014-01-07 16:41:39 +0100339
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800340 weston_compositor_schedule_repaint(shell->compositor);
341
342 return EXPOSAY_LAYOUT_ANIMATE_TO_OVERVIEW;
343}
344
345static void
346exposay_focus(struct weston_pointer_grab *grab)
347{
348}
349
350static void
351exposay_motion(struct weston_pointer_grab *grab, uint32_t time,
Jonas Ådahld2510102014-10-05 21:39:14 +0200352 struct weston_pointer_motion_event *event)
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800353{
354 struct desktop_shell *shell =
355 container_of(grab, struct desktop_shell, exposay.grab_ptr);
356
Jonas Ådahld2510102014-10-05 21:39:14 +0200357 weston_pointer_move(grab->pointer, event);
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800358
359 exposay_pick(shell,
360 wl_fixed_to_int(grab->pointer->x),
361 wl_fixed_to_int(grab->pointer->y));
362}
363
364static void
365exposay_button(struct weston_pointer_grab *grab, uint32_t time, uint32_t button,
366 uint32_t state_w)
367{
368 struct desktop_shell *shell =
369 container_of(grab, struct desktop_shell, exposay.grab_ptr);
370 struct weston_seat *seat = grab->pointer->seat;
371 enum wl_pointer_button_state state = state_w;
372
373 if (button != BTN_LEFT)
374 return;
375
376 /* Store the surface we clicked on, and don't do anything if we end up
377 * releasing on a different surface. */
378 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
379 shell->exposay.clicked = shell->exposay.focus_current;
380 return;
381 }
382
383 if (shell->exposay.focus_current == shell->exposay.clicked)
384 exposay_set_state(shell, EXPOSAY_TARGET_SWITCH, seat);
385 else
386 shell->exposay.clicked = NULL;
387}
388
389static void
Jonas Ådahl0336ca02014-10-04 16:28:29 +0200390exposay_axis(struct weston_pointer_grab *grab,
Peter Hutterer89b6a492016-01-18 15:58:17 +1000391 uint32_t time, struct weston_pointer_axis_event *event)
Jonas Ådahl0336ca02014-10-04 16:28:29 +0200392{
393}
394
395static void
Peter Hutterer87743e92016-01-18 16:38:22 +1000396exposay_axis_source(struct weston_pointer_grab *grab, uint32_t source)
397{
398}
399
400static void
401exposay_frame(struct weston_pointer_grab *grab)
402{
403}
404
405static void
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800406exposay_pointer_grab_cancel(struct weston_pointer_grab *grab)
407{
408 struct desktop_shell *shell =
409 container_of(grab, struct desktop_shell, exposay.grab_ptr);
410
411 exposay_set_state(shell, EXPOSAY_TARGET_CANCEL, shell->exposay.seat);
412}
413
414static const struct weston_pointer_grab_interface exposay_ptr_grab = {
415 exposay_focus,
416 exposay_motion,
417 exposay_button,
Jonas Ådahl0336ca02014-10-04 16:28:29 +0200418 exposay_axis,
Peter Hutterer87743e92016-01-18 16:38:22 +1000419 exposay_axis_source,
420 exposay_frame,
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800421 exposay_pointer_grab_cancel,
422};
423
424static int
425exposay_maybe_move(struct desktop_shell *shell, int row, int column)
426{
427 struct exposay_surface *esurface;
428
429 wl_list_for_each(esurface, &shell->exposay.surface_list, link) {
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100430 if (esurface->eoutput != shell->exposay.cur_output ||
431 esurface->row != row || esurface->column != column)
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800432 continue;
433
434 exposay_highlight_surface(shell, esurface);
435 return 1;
436 }
437
438 return 0;
439}
440
441static void
442exposay_key(struct weston_keyboard_grab *grab, uint32_t time, uint32_t key,
443 uint32_t state_w)
444{
445 struct weston_seat *seat = grab->keyboard->seat;
446 struct desktop_shell *shell =
447 container_of(grab, struct desktop_shell, exposay.grab_kbd);
448 enum wl_keyboard_key_state state = state_w;
449
450 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
451 return;
452
453 switch (key) {
454 case KEY_ESC:
455 exposay_set_state(shell, EXPOSAY_TARGET_CANCEL, seat);
456 break;
457 case KEY_ENTER:
458 exposay_set_state(shell, EXPOSAY_TARGET_SWITCH, seat);
459 break;
460 case KEY_UP:
461 exposay_maybe_move(shell, shell->exposay.row_current - 1,
462 shell->exposay.column_current);
463 break;
464 case KEY_DOWN:
465 /* Special case for trying to move to the bottom row when it
466 * has fewer items than all the others. */
467 if (!exposay_maybe_move(shell, shell->exposay.row_current + 1,
468 shell->exposay.column_current) &&
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100469 shell->exposay.row_current < (shell->exposay.cur_output->grid_size - 1)) {
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800470 exposay_maybe_move(shell, shell->exposay.row_current + 1,
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100471 (shell->exposay.cur_output->num_surfaces %
472 shell->exposay.cur_output->grid_size) - 1);
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800473 }
474 break;
475 case KEY_LEFT:
476 exposay_maybe_move(shell, shell->exposay.row_current,
477 shell->exposay.column_current - 1);
478 break;
479 case KEY_RIGHT:
480 exposay_maybe_move(shell, shell->exposay.row_current,
481 shell->exposay.column_current + 1);
482 break;
483 case KEY_TAB:
484 /* Try to move right, then down (and to the leftmost column),
485 * then if all else fails, to the top left. */
486 if (!exposay_maybe_move(shell, shell->exposay.row_current,
487 shell->exposay.column_current + 1) &&
488 !exposay_maybe_move(shell, shell->exposay.row_current + 1, 0))
489 exposay_maybe_move(shell, 0, 0);
490 break;
491 default:
492 break;
493 }
494}
495
496static void
497exposay_modifier(struct weston_keyboard_grab *grab, uint32_t serial,
498 uint32_t mods_depressed, uint32_t mods_latched,
499 uint32_t mods_locked, uint32_t group)
500{
501 struct desktop_shell *shell =
502 container_of(grab, struct desktop_shell, exposay.grab_kbd);
503 struct weston_seat *seat = (struct weston_seat *) grab->keyboard->seat;
504
505 /* We want to know when mod has been pressed and released.
506 * FIXME: There is a problem here: if mod is pressed, then a key
507 * is pressed and released, then mod is released, we will treat that
508 * as if only mod had been pressed and released. */
509 if (seat->modifier_state) {
510 if (seat->modifier_state == shell->binding_modifier) {
511 shell->exposay.mod_pressed = true;
512 } else {
513 shell->exposay.mod_invalid = true;
514 }
515 } else {
516 if (shell->exposay.mod_pressed && !shell->exposay.mod_invalid)
517 exposay_set_state(shell, EXPOSAY_TARGET_CANCEL, seat);
518
519 shell->exposay.mod_invalid = false;
520 shell->exposay.mod_pressed = false;
521 }
522
523 return;
524}
525
526static void
527exposay_cancel(struct weston_keyboard_grab *grab)
528{
529 struct desktop_shell *shell =
530 container_of(grab, struct desktop_shell, exposay.grab_kbd);
531
532 exposay_set_state(shell, EXPOSAY_TARGET_CANCEL, shell->exposay.seat);
533}
534
535static const struct weston_keyboard_grab_interface exposay_kbd_grab = {
536 exposay_key,
537 exposay_modifier,
538 exposay_cancel,
539};
540
541/**
542 * Called when the transition from overview -> inactive has completed.
543 */
544static enum exposay_layout_state
545exposay_set_inactive(struct desktop_shell *shell)
546{
547 struct weston_seat *seat = shell->exposay.seat;
Derek Foreman1281a362015-07-31 16:55:32 -0500548 struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
549 struct weston_pointer *pointer = weston_seat_get_pointer(seat);
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800550
Derek Foreman1281a362015-07-31 16:55:32 -0500551 if (pointer)
552 weston_pointer_end_grab(pointer);
Derek Foremancee82d62015-07-15 13:00:33 -0500553
Derek Foreman1281a362015-07-31 16:55:32 -0500554 if (keyboard) {
555 weston_keyboard_end_grab(keyboard);
556 if (keyboard->input_method_resource)
557 keyboard->grab = &keyboard->input_method_grab;
Derek Foremancee82d62015-07-15 13:00:33 -0500558 }
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800559
560 return EXPOSAY_LAYOUT_INACTIVE;
561}
562
563/**
564 * Begins the transition from overview to inactive. */
565static enum exposay_layout_state
566exposay_transition_inactive(struct desktop_shell *shell, int switch_focus)
567{
568 struct exposay_surface *esurface;
569
570 /* Call activate() before we start the animations to avoid
571 * animating back the old state and then immediately transitioning
572 * to the new. */
573 if (switch_focus && shell->exposay.focus_current)
Jonas Ådahl1fa6ded2014-10-18 13:24:53 +0200574 activate(shell, shell->exposay.focus_current,
Jonas Ådahl4361b4e2014-10-18 18:20:16 +0200575 shell->exposay.seat,
576 WESTON_ACTIVATE_FLAG_CONFIGURE);
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800577 else if (shell->exposay.focus_prev)
Jonas Ådahl1fa6ded2014-10-18 13:24:53 +0200578 activate(shell, shell->exposay.focus_prev,
Jonas Ådahl4361b4e2014-10-18 18:20:16 +0200579 shell->exposay.seat,
580 WESTON_ACTIVATE_FLAG_CONFIGURE);
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800581
582 wl_list_for_each(esurface, &shell->exposay.surface_list, link)
583 exposay_animate_out(esurface);
584 weston_compositor_schedule_repaint(shell->compositor);
585
586 return EXPOSAY_LAYOUT_ANIMATE_TO_INACTIVE;
587}
588
589static enum exposay_layout_state
590exposay_transition_active(struct desktop_shell *shell)
591{
592 struct weston_seat *seat = shell->exposay.seat;
Derek Foreman1281a362015-07-31 16:55:32 -0500593 struct weston_pointer *pointer = weston_seat_get_pointer(seat);
594 struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100595 struct shell_output *shell_output;
596 bool animate = false;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800597
598 shell->exposay.workspace = get_current_workspace(shell);
Derek Foreman1281a362015-07-31 16:55:32 -0500599 shell->exposay.focus_prev = get_default_view(keyboard->focus);
600 shell->exposay.focus_current = get_default_view(keyboard->focus);
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800601 shell->exposay.clicked = NULL;
602 wl_list_init(&shell->exposay.surface_list);
603
Mario Kleiner9f4d6552015-06-21 21:25:08 +0200604 lower_fullscreen_layer(shell, NULL);
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800605 shell->exposay.grab_kbd.interface = &exposay_kbd_grab;
Derek Foreman1281a362015-07-31 16:55:32 -0500606 weston_keyboard_start_grab(keyboard,
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800607 &shell->exposay.grab_kbd);
Derek Foreman1281a362015-07-31 16:55:32 -0500608 weston_keyboard_set_focus(keyboard, NULL);
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800609
610 shell->exposay.grab_ptr.interface = &exposay_ptr_grab;
Derek Foreman1281a362015-07-31 16:55:32 -0500611 if (pointer) {
612 weston_pointer_start_grab(pointer,
Derek Foreman3dd570e2015-05-22 11:47:20 -0500613 &shell->exposay.grab_ptr);
Derek Foremanf9318d12015-05-11 15:40:11 -0500614 weston_pointer_clear_focus(pointer);
Derek Foreman3dd570e2015-05-22 11:47:20 -0500615 }
Emilio Pozuelo Monfort3b6e68e2014-02-10 13:22:32 +0100616 wl_list_for_each(shell_output, &shell->output_list, link) {
617 enum exposay_layout_state state;
618
619 state = exposay_layout(shell, shell_output);
620
621 if (state == EXPOSAY_LAYOUT_ANIMATE_TO_OVERVIEW)
622 animate = true;
623 }
624
625 return animate ? EXPOSAY_LAYOUT_ANIMATE_TO_OVERVIEW
626 : EXPOSAY_LAYOUT_OVERVIEW;
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800627}
628
629static void
630exposay_check_state(struct desktop_shell *shell)
631{
632 enum exposay_layout_state state_new = shell->exposay.state_cur;
633 int do_switch = 0;
634
635 /* Don't do anything whilst animations are running, just store up
636 * target state changes and only act on them when the animations have
637 * completed. */
638 if (exposay_is_animating(shell))
639 return;
640
641 switch (shell->exposay.state_target) {
642 case EXPOSAY_TARGET_OVERVIEW:
643 switch (shell->exposay.state_cur) {
644 case EXPOSAY_LAYOUT_OVERVIEW:
645 goto out;
646 case EXPOSAY_LAYOUT_ANIMATE_TO_OVERVIEW:
647 state_new = EXPOSAY_LAYOUT_OVERVIEW;
648 break;
649 default:
650 state_new = exposay_transition_active(shell);
651 break;
652 }
653 break;
654
655 case EXPOSAY_TARGET_SWITCH:
656 do_switch = 1; /* fallthrough */
657 case EXPOSAY_TARGET_CANCEL:
658 switch (shell->exposay.state_cur) {
659 case EXPOSAY_LAYOUT_INACTIVE:
660 goto out;
661 case EXPOSAY_LAYOUT_ANIMATE_TO_INACTIVE:
662 state_new = exposay_set_inactive(shell);
663 break;
664 default:
665 state_new = exposay_transition_inactive(shell, do_switch);
666 break;
667 }
668
669 break;
670 }
671
672out:
673 shell->exposay.state_cur = state_new;
674}
675
676static void
677exposay_set_state(struct desktop_shell *shell, enum exposay_target_state state,
678 struct weston_seat *seat)
679{
680 shell->exposay.state_target = state;
681 shell->exposay.seat = seat;
682 exposay_check_state(shell);
683}
684
685void
Derek Foreman8ae2db52015-07-15 13:00:36 -0500686exposay_binding(struct weston_keyboard *keyboard, enum weston_keyboard_modifier modifier,
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800687 void *data)
688{
689 struct desktop_shell *shell = data;
690
Derek Foreman8ae2db52015-07-15 13:00:36 -0500691 exposay_set_state(shell, EXPOSAY_TARGET_OVERVIEW, keyboard->seat);
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800692}