shell.c 177 KB
Newer Older
1
/*
2
 * Copyright © 2010-2012 Intel Corporation
Pekka Paalanen's avatar
Pekka Paalanen committed
3
 * Copyright © 2011-2012 Collabora, Ltd.
Daniel Stone's avatar
Daniel Stone committed
4
 * Copyright © 2013 Raspberry Pi Foundation
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 *
 * Permission to use, copy, modify, distribute, and sell this software and
 * its documentation for any purpose is hereby granted without fee, provided
 * that the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of the copyright holders not be used in
 * advertising or publicity pertaining to distribution of the software
 * without specific, written prior permission.  The copyright holders make
 * no representations about the suitability of this software for any
 * purpose.  It is provided "as is" without express or implied warranty.
 *
 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

25
26
#include "config.h"

27
#include <stdlib.h>
28
#include <stdio.h>
29
30
#include <string.h>
#include <unistd.h>
31
#include <linux/input.h>
32
#include <assert.h>
33
#include <signal.h>
34
#include <math.h>
35
#include <sys/types.h>
36

37
#include "shell.h"
38
#include "desktop-shell-server-protocol.h"
39
#include "workspaces-server-protocol.h"
40
#include "../shared/config-parser.h"
41
#include "xdg-shell-server-protocol.h"
42

Jonas Ådahl's avatar
Jonas Ådahl committed
43
#define DEFAULT_NUM_WORKSPACES 1
44
#define DEFAULT_WORKSPACE_CHANGE_ANIMATION_LENGTH 200
Jonas Ådahl's avatar
Jonas Ådahl committed
45

46
47
48
49
#ifndef static_assert
#define static_assert(cond, msg)
#endif

50
51
struct focus_state {
	struct weston_seat *seat;
52
	struct workspace *ws;
53
54
55
56
57
58
	struct weston_surface *keyboard_focus;
	struct wl_list link;
	struct wl_listener seat_destroy_listener;
	struct wl_listener surface_destroy_listener;
};

59
enum shell_surface_type {
60
	SHELL_SURFACE_NONE,
61
	SHELL_SURFACE_TOPLEVEL,
62
63
	SHELL_SURFACE_POPUP,
	SHELL_SURFACE_XWAYLAND
64
65
};

66
67
struct shell_client;

68
69
70
71
72
73
74
75
76
/*
 * Surface stacking and ordering.
 *
 * This is handled using several linked lists of surfaces, organised into
 * ‘layers’. The layers are ordered, and each of the surfaces in one layer are
 * above all of the surfaces in the layer below. The set of layers is static and
 * in the following order (top-most first):
 *  • Lock layer (only ever displayed on its own)
 *  • Cursor layer
77
 *  • Input panel layer
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
 *  • Fullscreen layer
 *  • Panel layer
 *  • Workspace layers
 *  • Background layer
 *
 * The list of layers may be manipulated to remove whole layers of surfaces from
 * display. For example, when locking the screen, all layers except the lock
 * layer are removed.
 *
 * A surface’s layer is modified on configuring the surface, in
 * set_surface_type() (which is only called when the surface’s type change is
 * _committed_). If a surface’s type changes (e.g. when making a window
 * fullscreen) its layer changes too.
 *
 * In order to allow popup and transient surfaces to be correctly stacked above
 * their parent surfaces, each surface tracks both its parent surface, and a
 * linked list of its children. When a surface’s layer is updated, so are the
 * layers of its children. Note that child surfaces are *not* the same as
 * subsurfaces — child/parent surfaces are purely for maintaining stacking
 * order.
 *
 * The children_link list of siblings of a surface (i.e. those surfaces which
 * have the same parent) only contains weston_surfaces which have a
 * shell_surface. Stacking is not implemented for non-shell_surface
 * weston_surfaces. This means that the following implication does *not* hold:
 *     (shsurf->parent != NULL) ⇒ !wl_list_is_empty(shsurf->children_link)
 */

106
struct shell_surface {
107
108
	struct wl_resource *resource;
	struct wl_signal destroy_signal;
109
	struct shell_client *owner;
110
	struct wl_resource *owner_resource;
Pekka Paalanen's avatar
Pekka Paalanen committed
111

112
	struct weston_surface *surface;
113
	struct weston_view *view;
114
	int32_t last_width, last_height;
Pekka Paalanen's avatar
Pekka Paalanen committed
115
	struct wl_listener surface_destroy_listener;
116
117
	struct wl_listener resource_destroy_listener;

118
	struct weston_surface *parent;
119
120
	struct wl_list children_list;  /* child surfaces of this one */
	struct wl_list children_link;  /* sibling surfaces of this one */
121
	struct desktop_shell *shell;
122

123
	enum shell_surface_type type;
124
	char *title, *class;
125
	int32_t saved_x, saved_y;
126
	int32_t saved_width, saved_height;
127
	bool saved_position_valid;
128
	bool saved_size_valid;
129
	bool saved_rotation_valid;
130
	int unresponsive, grabbed;
131
	uint32_t resize_edges;
132

133
134
	struct {
		struct weston_transform transform;
135
		struct weston_matrix rotation;
136
137
	} rotation;

138
	struct {
Giulio Camuffo's avatar
Giulio Camuffo committed
139
		struct wl_list grab_link;
140
		int32_t x, y;
Giulio Camuffo's avatar
Giulio Camuffo committed
141
		struct shell_seat *shseat;
142
		uint32_t serial;
143
144
	} popup;

145
146
	struct {
		int32_t x, y;
147
		uint32_t flags;
148
149
	} transient;

150
151
152
153
	struct {
		enum wl_shell_surface_fullscreen_method type;
		struct weston_transform transform; /* matrix from x, y */
		uint32_t framerate;
154
		struct weston_view *black_view;
155
156
	} fullscreen;

157
158
	struct weston_transform workspace_transform;

159
	struct weston_output *fullscreen_output;
160
	struct weston_output *output;
161
	struct wl_list link;
162
163

	const struct weston_shell_client *client;
164

165
	struct surface_state {
166
167
		bool maximized;
		bool fullscreen;
168
		bool relative;
169
		bool lowered;
170
	} state, next_state, requested_state; /* surface states */
171
	bool state_changed;
172
	bool state_requested;
173

174
	struct {
175
176
177
		int32_t x, y, width, height;
	} geometry, next_geometry;
	bool has_set_geometry, has_next_geometry;
178

179
	int focus_count;
180
181

	bool destroying;
182
183
};

184
struct shell_grab {
185
	struct weston_pointer_grab grab;
186
187
188
189
	struct shell_surface *shsurf;
	struct wl_listener shsurf_destroy_listener;
};

190
191
192
193
194
195
196
struct shell_touch_grab {
	struct weston_touch_grab grab;
	struct shell_surface *shsurf;
	struct wl_listener shsurf_destroy_listener;
	struct weston_touch *touch;
};

197
198
struct weston_move_grab {
	struct shell_grab base;
199
	wl_fixed_t dx, dy;
200
	int client_initiated;
201
202
};

203
204
struct weston_touch_move_grab {
	struct shell_touch_grab base;
205
	int active;
206
207
208
	wl_fixed_t dx, dy;
};

209
struct rotate_grab {
210
	struct shell_grab base;
211
	struct weston_matrix rotation;
212
	struct {
213
214
		float x;
		float y;
215
216
217
	} center;
};

Giulio Camuffo's avatar
Giulio Camuffo committed
218
219
220
struct shell_seat {
	struct weston_seat *seat;
	struct wl_listener seat_destroy_listener;
221
	struct weston_surface *focused_surface;
Giulio Camuffo's avatar
Giulio Camuffo committed
222

223
224
225
226
	struct wl_listener caps_changed_listener;
	struct wl_listener pointer_focus_listener;
	struct wl_listener keyboard_focus_listener;

Giulio Camuffo's avatar
Giulio Camuffo committed
227
	struct {
228
		struct weston_pointer_grab grab;
229
		struct weston_touch_grab touch_grab;
Giulio Camuffo's avatar
Giulio Camuffo committed
230
231
232
		struct wl_list surfaces_list;
		struct wl_client *client;
		int32_t initial_up;
233
		enum { POINTER, TOUCH } type;
Giulio Camuffo's avatar
Giulio Camuffo committed
234
235
236
	} popup_grab;
};

237
238
239
240
241
242
243
244
struct shell_client {
	struct wl_resource *resource;
	struct wl_client *client;
	struct desktop_shell *shell;
	struct wl_listener destroy_listener;
	struct wl_event_source *ping_timer;
	uint32_t ping_serial;
	int unresponsive;
245
	struct wl_list surface_list;
246
247
};

248
249
250
static struct desktop_shell *
shell_surface_get_shell(struct shell_surface *shsurf);

251
static void
252
surface_rotate(struct shell_surface *surface, struct weston_seat *seat);
253

254
255
256
static void
shell_fade_startup(struct desktop_shell *shell);

257
258
259
static struct shell_seat *
get_shell_seat(struct weston_seat *seat);

260
261
262
263
static void
get_output_panel_size(struct desktop_shell *shell,
		      struct weston_output *output,
		      int *width, int *height);
264

265
266
267
static void
shell_surface_update_child_surface_layers(struct shell_surface *shsurf);

268
269
270
271
272
273
274
275
276
277
278
279
280
static bool
shell_surface_is_wl_shell_surface(struct shell_surface *shsurf);

static bool
shell_surface_is_xdg_surface(struct shell_surface *shsurf);

static bool
shell_surface_is_xdg_popup(struct shell_surface *shsurf);

static void
shell_surface_set_parent(struct shell_surface *shsurf,
                         struct weston_surface *parent);

281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
static int
shell_surface_get_label(struct weston_surface *surface, char *buf, size_t len)
{
	struct shell_surface *shsurf;
	const char *typestr[] = {
		[SHELL_SURFACE_NONE] = "unidentified",
		[SHELL_SURFACE_TOPLEVEL] = "top-level",
		[SHELL_SURFACE_POPUP] = "popup",
		[SHELL_SURFACE_XWAYLAND] = "Xwayland",
	};
	const char *t, *c;

	shsurf = get_shell_surface(surface);
	if (!shsurf)
		return snprintf(buf, len, "unidentified window");

	t = shsurf->title;
	c = shsurf->class;

	return snprintf(buf, len, "%s window%s%s%s%s%s",
		typestr[shsurf->type],
		t ? " '" : "", t ?: "", t ? "'" : "",
		c ? " of " : "", c ?: "");
}

306
307
308
309
static bool
shell_surface_is_top_fullscreen(struct shell_surface *shsurf)
{
	struct desktop_shell *shell;
310
	struct weston_view *top_fs_ev;
311
312

	shell = shell_surface_get_shell(shsurf);
Quentin Glidic's avatar
Quentin Glidic committed
313

314
	if (wl_list_empty(&shell->fullscreen_layer.view_list.link))
315
316
		return false;

317
	top_fs_ev = container_of(shell->fullscreen_layer.view_list.link.next,
318
			         struct weston_view,
319
				 layer_link.link);
320
	return (shsurf == get_shell_surface(top_fs_ev->surface));
321
322
}

323
static void
Kristian Høgsberg's avatar
Kristian Høgsberg committed
324
destroy_shell_grab_shsurf(struct wl_listener *listener, void *data)
325
326
327
328
329
330
331
332
333
{
	struct shell_grab *grab;

	grab = container_of(listener, struct shell_grab,
			    shsurf_destroy_listener);

	grab->shsurf = NULL;
}

334
struct weston_view *
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
get_default_view(struct weston_surface *surface)
{
	struct shell_surface *shsurf;
	struct weston_view *view;

	if (!surface || wl_list_empty(&surface->views))
		return NULL;

	shsurf = get_shell_surface(surface);
	if (shsurf)
		return shsurf->view;

	wl_list_for_each(view, &surface->views, surface_link)
		if (weston_view_is_mapped(view))
			return view;

	return container_of(surface->views.next, struct weston_view, surface_link);
}

354
static void
355
popup_grab_end(struct weston_pointer *pointer);
356
357
static void
touch_popup_grab_end(struct weston_touch *touch);
358

359
static void
360
shell_grab_start(struct shell_grab *grab,
361
		 const struct weston_pointer_grab_interface *interface,
362
		 struct shell_surface *shsurf,
363
		 struct weston_pointer *pointer,
364
		 enum desktop_shell_cursor cursor)
365
{
366
367
	struct desktop_shell *shell = shsurf->shell;

368
	popup_grab_end(pointer);
369
370
	if (pointer->seat->touch)
		touch_popup_grab_end(pointer->seat->touch);
371

372
373
	grab->grab.interface = interface;
	grab->shsurf = shsurf;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
374
	grab->shsurf_destroy_listener.notify = destroy_shell_grab_shsurf;
375
	wl_signal_add(&shsurf->destroy_signal,
Kristian Høgsberg's avatar
Kristian Høgsberg committed
376
		      &grab->shsurf_destroy_listener);
377

378
	shsurf->grabbed = 1;
379
	weston_pointer_start_grab(pointer, &grab->grab);
380
381
382
	if (shell->child.desktop_shell) {
		desktop_shell_send_grab_cursor(shell->child.desktop_shell,
					       cursor);
383
384
		weston_pointer_set_focus(pointer,
					 get_default_view(shell->grab_surface),
385
386
387
					 wl_fixed_from_int(0),
					 wl_fixed_from_int(0));
	}
388
389
}

390
391
392
393
394
static void
get_output_panel_size(struct desktop_shell *shell,
		      struct weston_output *output,
		      int *width,
		      int *height)
395
396
{
	struct weston_view *view;
397
398
399

	*width = 0;
	*height = 0;
400
401

	if (!output)
402
		return;
403

404
	wl_list_for_each(view, &shell->panel_layer.view_list.link, layer_link.link) {
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
		float x, y;

		if (view->surface->output != output)
			continue;

		switch (shell->panel_position) {
		case DESKTOP_SHELL_PANEL_POSITION_TOP:
		case DESKTOP_SHELL_PANEL_POSITION_BOTTOM:

			weston_view_to_global_float(view,
						    view->surface->width, 0,
						    &x, &y);

			*width = (int) x;
			*height = view->surface->height + (int) y;
			return;

		case DESKTOP_SHELL_PANEL_POSITION_LEFT:
		case DESKTOP_SHELL_PANEL_POSITION_RIGHT:
			weston_view_to_global_float(view,
						    0, view->surface->height,
						    &x, &y);

			*width = view->surface->width + (int) x;
			*height = (int) y;
			return;

		default:
			/* we've already set width and height to
			 * fallback values. */
435
436
437
438
			break;
		}
	}

439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
	/* the correct view wasn't found */
}

static void
get_output_work_area(struct desktop_shell *shell,
		     struct weston_output *output,
		     pixman_rectangle32_t *area)
{
	int32_t panel_width = 0, panel_height = 0;

	area->x = 0;
	area->y = 0;

	get_output_panel_size(shell, output, &panel_width, &panel_height);

	switch (shell->panel_position) {
	case DESKTOP_SHELL_PANEL_POSITION_TOP:
	default:
		area->y = panel_height;
	case DESKTOP_SHELL_PANEL_POSITION_BOTTOM:
		area->width = output->width;
		area->height = output->height - panel_height;
		break;
	case DESKTOP_SHELL_PANEL_POSITION_LEFT:
		area->x = panel_width;
	case DESKTOP_SHELL_PANEL_POSITION_RIGHT:
		area->width = output->width - panel_width;
		area->height = output->height;
		break;
	}
469
470
}

471
static void
472
send_configure_for_surface(struct shell_surface *shsurf)
473
{
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
	int32_t width, height;
	struct surface_state *state;

	if (shsurf->state_requested)
		state = &shsurf->requested_state;
	else if (shsurf->state_changed)
		state = &shsurf->next_state;
	else
		state = &shsurf->state;

	if (state->fullscreen) {
		width = shsurf->output->width;
		height = shsurf->output->height;
	} else if (state->maximized) {
		struct desktop_shell *shell;
489
		pixman_rectangle32_t area;
490
491

		shell = shell_surface_get_shell(shsurf);
492
		get_output_work_area(shell, shsurf->output, &area);
493

494
495
		width = area.width;
		height = area.height;
496
497
498
	} else if (shsurf->resize_edges) {
		width = shsurf->geometry.width;
		height = shsurf->geometry.height;
499
500
501
	} else {
		width = 0;
		height = 0;
502
	}
503
504
505
506
507
508
509
510
511

	shsurf->client->send_configure(shsurf->surface, width, height);
}

static void
shell_surface_state_changed(struct shell_surface *shsurf)
{
	if (shell_surface_is_xdg_surface(shsurf))
		send_configure_for_surface(shsurf);
512
513
}

514
static void
515
shell_grab_end(struct shell_grab *grab)
516
{
517
	if (grab->shsurf) {
518
		wl_list_remove(&grab->shsurf_destroy_listener.link);
519
		grab->shsurf->grabbed = 0;
520
521
522
523
524

		if (grab->shsurf->resize_edges) {
			grab->shsurf->resize_edges = 0;
			shell_surface_state_changed(grab->shsurf);
		}
525
	}
526

527
	weston_pointer_end_grab(grab->grab.pointer);
528
529
}

530
531
532
533
534
535
536
static void
shell_touch_grab_start(struct shell_touch_grab *grab,
		       const struct weston_touch_grab_interface *interface,
		       struct shell_surface *shsurf,
		       struct weston_touch *touch)
{
	struct desktop_shell *shell = shsurf->shell;
537

538
	touch_popup_grab_end(touch);
539
540
541
	if (touch->seat->pointer)
		popup_grab_end(touch->seat->pointer);

542
543
544
545
546
547
548
	grab->grab.interface = interface;
	grab->shsurf = shsurf;
	grab->shsurf_destroy_listener.notify = destroy_shell_grab_shsurf;
	wl_signal_add(&shsurf->destroy_signal,
		      &grab->shsurf_destroy_listener);

	grab->touch = touch;
549
	shsurf->grabbed = 1;
550
551
552

	weston_touch_start_grab(touch, &grab->grab);
	if (shell->child.desktop_shell)
553
		weston_touch_set_focus(touch,
554
				       get_default_view(shell->grab_surface));
555
556
557
558
559
}

static void
shell_touch_grab_end(struct shell_touch_grab *grab)
{
560
	if (grab->shsurf) {
561
		wl_list_remove(&grab->shsurf_destroy_listener.link);
562
563
		grab->shsurf->grabbed = 0;
	}
564
565
566
567

	weston_touch_end_grab(grab->touch);
}

568
static void
569
center_on_output(struct weston_view *view,
570
571
		 struct weston_output *output);

572
static enum weston_keyboard_modifier
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
get_modifier(char *modifier)
{
	if (!modifier)
		return MODIFIER_SUPER;

	if (!strcmp("ctrl", modifier))
		return MODIFIER_CTRL;
	else if (!strcmp("alt", modifier))
		return MODIFIER_ALT;
	else if (!strcmp("super", modifier))
		return MODIFIER_SUPER;
	else
		return MODIFIER_SUPER;
}

588
589
590
static enum animation_type
get_animation_type(char *animation)
{
591
592
593
	if (!animation)
		return ANIMATION_NONE;

594
595
596
597
	if (!strcmp("zoom", animation))
		return ANIMATION_ZOOM;
	else if (!strcmp("fade", animation))
		return ANIMATION_FADE;
598
599
	else if (!strcmp("dim-layer", animation))
		return ANIMATION_DIM_LAYER;
600
601
602
603
	else
		return ANIMATION_NONE;
}

604
static void
605
shell_configuration(struct desktop_shell *shell)
606
{
607
608
	struct weston_config_section *section;
	int duration;
609
	char *s, *client;
Pekka Paalanen's avatar
Pekka Paalanen committed
610
	int ret;
611
612
613
614
615
616

	section = weston_config_get_section(shell->compositor->config,
					    "screensaver", NULL, NULL);
	weston_config_section_get_string(section,
					 "path", &shell->screensaver.path, NULL);
	weston_config_section_get_int(section, "duration", &duration, 60);
617
	shell->screensaver.duration = duration * 1000;
618
619
620

	section = weston_config_get_section(shell->compositor->config,
					    "shell", NULL, NULL);
Pekka Paalanen's avatar
Pekka Paalanen committed
621
622
623
624
	ret = asprintf(&client, "%s/%s", weston_config_get_libexec_dir(),
		       WESTON_SHELL_CLIENT);
	if (ret < 0)
		client = NULL;
625
	weston_config_section_get_string(section,
626
627
					 "client", &s, client);
	free(client);
628
	shell->client = s;
629
630
631
	weston_config_section_get_string(section,
					 "binding-modifier", &s, "super");
	shell->binding_modifier = get_modifier(s);
Quentin Glidic's avatar
Quentin Glidic committed
632
	free(s);
633
634
635
636
637
638
639
640
641

	weston_config_section_get_string(section,
					 "exposay-modifier", &s, "none");
	if (strcmp(s, "none") == 0)
		shell->exposay_modifier = 0;
	else
		shell->exposay_modifier = get_modifier(s);
	free(s);

642
643
	weston_config_section_get_string(section, "animation", &s, "none");
	shell->win_animation_type = get_animation_type(s);
Quentin Glidic's avatar
Quentin Glidic committed
644
	free(s);
645
646
647
	weston_config_section_get_string(section, "close-animation", &s, "fade");
	shell->win_close_animation_type = get_animation_type(s);
	free(s);
648
649
650
651
	weston_config_section_get_string(section,
					 "startup-animation", &s, "fade");
	shell->startup_animation_type = get_animation_type(s);
	free(s);
652
653
	if (shell->startup_animation_type == ANIMATION_ZOOM)
		shell->startup_animation_type = ANIMATION_NONE;
654
655
656
	weston_config_section_get_string(section, "focus-animation", &s, "none");
	shell->focus_animation_type = get_animation_type(s);
	free(s);
657
658
659
	weston_config_section_get_uint(section, "num-workspaces",
				       &shell->workspaces.num,
				       DEFAULT_NUM_WORKSPACES);
Jonas Ådahl's avatar
Jonas Ådahl committed
660
661
}

662
struct weston_output *
663
664
665
666
667
668
get_default_output(struct weston_compositor *compositor)
{
	return container_of(compositor->output_list.next,
			    struct weston_output, link);
}

669
670
671
672
673
674
static int
focus_surface_get_label(struct weston_surface *surface, char *buf, size_t len)
{
	return snprintf(buf, len, "focus highlight effect for output %s",
			surface->output->name);
}
675
676
677

/* no-op func for checking focus surface */
static void
678
focus_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
{
}

static struct focus_surface *
get_focus_surface(struct weston_surface *surface)
{
	if (surface->configure == focus_surface_configure)
		return surface->configure_private;
	else
		return NULL;
}

static bool
is_focus_surface (struct weston_surface *es)
{
	return (es->configure == focus_surface_configure);
}

static bool
is_focus_view (struct weston_view *view)
{
	return is_focus_surface (view->surface);
}

static struct focus_surface *
create_focus_surface(struct weston_compositor *ec,
		     struct weston_output *output)
{
	struct focus_surface *fsurf = NULL;
	struct weston_surface *surface = NULL;

	fsurf = malloc(sizeof *fsurf);
	if (!fsurf)
		return NULL;

	fsurf->surface = weston_surface_create(ec);
	surface = fsurf->surface;
	if (surface == NULL) {
		free(fsurf);
		return NULL;
	}

	surface->configure = focus_surface_configure;
	surface->output = output;
	surface->configure_private = fsurf;
724
	weston_surface_set_label_func(surface, focus_surface_get_label);
725

726
727
728
729
730
731
	fsurf->view = weston_view_create(surface);
	if (fsurf->view == NULL) {
		weston_surface_destroy(surface);
		free(fsurf);
		return NULL;
	}
732
	fsurf->view->output = output;
733

734
	weston_surface_set_size(surface, output->width, output->height);
735
	weston_view_set_position(fsurf->view, output->x, output->y);
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
	weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1.0);
	pixman_region32_fini(&surface->opaque);
	pixman_region32_init_rect(&surface->opaque, output->x, output->y,
				  output->width, output->height);
	pixman_region32_fini(&surface->input);
	pixman_region32_init(&surface->input);

	wl_list_init(&fsurf->workspace_transform.link);

	return fsurf;
}

static void
focus_surface_destroy(struct focus_surface *fsurf)
{
	weston_surface_destroy(fsurf->surface);
	free(fsurf);
}

static void
focus_animation_done(struct weston_view_animation *animation, void *data)
{
	struct workspace *ws = data;

	ws->focus_animation = NULL;
}

763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
static void
focus_state_destroy(struct focus_state *state)
{
	wl_list_remove(&state->seat_destroy_listener.link);
	wl_list_remove(&state->surface_destroy_listener.link);
	free(state);
}

static void
focus_state_seat_destroy(struct wl_listener *listener, void *data)
{
	struct focus_state *state = container_of(listener,
						 struct focus_state,
						 seat_destroy_listener);

	wl_list_remove(&state->link);
	focus_state_destroy(state);
}

static void
focus_state_surface_destroy(struct wl_listener *listener, void *data)
{
	struct focus_state *state = container_of(listener,
						 struct focus_state,
787
						 surface_destroy_listener);
788
	struct desktop_shell *shell;
789
790
	struct weston_surface *main_surface, *next;
	struct weston_view *view;
791

792
793
	main_surface = weston_surface_get_main_surface(state->keyboard_focus);

794
	next = NULL;
795
796
	wl_list_for_each(view,
			 &state->ws->layer.view_list.link, layer_link.link) {
797
		if (view->surface == main_surface)
798
			continue;
799
800
		if (is_focus_view(view))
			continue;
801

802
		next = view->surface;
803
804
805
		break;
	}

806
807
808
809
	/* if the focus was a sub-surface, activate its main surface */
	if (main_surface != state->keyboard_focus)
		next = main_surface;

810
	shell = state->seat->compositor->shell_interface.shell;
811
	if (next) {
812
		state->keyboard_focus = NULL;
813
		activate(shell, next, state->seat, true);
814
	} else {
815
816
817
818
819
820
821
822
823
824
		if (shell->focus_animation_type == ANIMATION_DIM_LAYER) {
			if (state->ws->focus_animation)
				weston_view_animation_destroy(state->ws->focus_animation);

			state->ws->focus_animation = weston_fade_run(
				state->ws->fsurf_front->view,
				state->ws->fsurf_front->view->alpha, 0.0, 300,
				focus_animation_done, state->ws);
		}

825
826
827
		wl_list_remove(&state->link);
		focus_state_destroy(state);
	}
828
829
830
}

static struct focus_state *
831
focus_state_create(struct weston_seat *seat, struct workspace *ws)
832
833
834
835
836
837
838
{
	struct focus_state *state;

	state = malloc(sizeof *state);
	if (state == NULL)
		return NULL;

839
	state->keyboard_focus = NULL;
840
	state->ws = ws;
841
	state->seat = seat;
842
	wl_list_insert(&ws->focus_list, &state->link);
843
844
845

	state->seat_destroy_listener.notify = focus_state_seat_destroy;
	state->surface_destroy_listener.notify = focus_state_surface_destroy;
846
	wl_signal_add(&seat->destroy_signal,
847
		      &state->seat_destroy_listener);
848
	wl_list_init(&state->surface_destroy_listener.link);
849
850
851
852

	return state;
}

853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
static struct focus_state *
ensure_focus_state(struct desktop_shell *shell, struct weston_seat *seat)
{
	struct workspace *ws = get_current_workspace(shell);
	struct focus_state *state;

	wl_list_for_each(state, &ws->focus_list, link)
		if (state->seat == seat)
			break;

	if (&state->link == &ws->focus_list)
		state = focus_state_create(seat, ws);

	return state;
}

869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
static void
focus_state_set_focus(struct focus_state *state,
		      struct weston_surface *surface)
{
	if (state->keyboard_focus) {
		wl_list_remove(&state->surface_destroy_listener.link);
		wl_list_init(&state->surface_destroy_listener.link);
	}

	state->keyboard_focus = surface;
	if (surface)
		wl_signal_add(&surface->destroy_signal,
			      &state->surface_destroy_listener);
}

884
static void
885
restore_focus_state(struct desktop_shell *shell, struct workspace *ws)
886
887
{
	struct focus_state *state, *next;
888
	struct weston_surface *surface;
889
890
891
892
893
894
895
896
	struct wl_list pending_seat_list;
	struct weston_seat *seat, *next_seat;

	/* Temporarily steal the list of seats so that we can keep
	 * track of the seats we've already processed */
	wl_list_init(&pending_seat_list);
	wl_list_insert_list(&pending_seat_list, &shell->compositor->seat_list);
	wl_list_init(&shell->compositor->seat_list);
897
898

	wl_list_for_each_safe(state, next, &ws->focus_list, link) {
899
900
901
902
		wl_list_remove(&state->seat->link);
		wl_list_insert(&shell->compositor->seat_list,
			       &state->seat->link);

903
904
905
		if (state->seat->keyboard == NULL)
			continue;

906
		surface = state->keyboard_focus;
907

908
		weston_keyboard_set_focus(state->seat->keyboard, surface);
909
	}
910
911
912
913
914
915

	/* For any remaining seats that we don't have a focus state
	 * for we'll reset the keyboard focus to NULL */
	wl_list_for_each_safe(seat, next_seat, &pending_seat_list, link) {
		wl_list_insert(&shell->compositor->seat_list, &seat->link);

916
		if (seat->keyboard == NULL)
917
918
919
920
			continue;

		weston_keyboard_set_focus(seat->keyboard, NULL);
	}
921
922
}

923
924
925
926
927
928
929
930
static void
replace_focus_state(struct desktop_shell *shell, struct workspace *ws,
		    struct weston_seat *seat)
{
	struct focus_state *state;

	wl_list_for_each(state, &ws->focus_list, link) {
		if (state->seat == seat) {
931
			focus_state_set_focus(state, seat->keyboard->focus);
932
933
934
935
936
937
938
939
940
941
942
943
944
			return;
		}
	}
}

static void
drop_focus_state(struct desktop_shell *shell, struct workspace *ws,
		 struct weston_surface *surface)
{
	struct focus_state *state;

	wl_list_for_each(state, &ws->focus_list, link)
		if (state->keyboard_focus == surface)
945
			focus_state_set_focus(state, NULL);
946
947
}

948
949
950
951
952
953
954
955
956
957
958
959
960
961
static void
animate_focus_change(struct desktop_shell *shell, struct workspace *ws,
		     struct weston_view *from, struct weston_view *to)
{
	struct weston_output *output;
	bool focus_surface_created = false;

	/* FIXME: Only support dim animation using two layers */
	if (from == to || shell->focus_animation_type != ANIMATION_DIM_LAYER)
		return;

	output = get_default_output(shell->compositor);
	if (ws->fsurf_front == NULL && (from || to)) {
		ws->fsurf_front = create_focus_surface(shell->compositor, output);
962
963
		if (ws->fsurf_front == NULL)
			return;
964
		ws->fsurf_front->view->alpha = 0.0;
965
966
967
968
969
970

		ws->fsurf_back = create_focus_surface(shell->compositor, output);
		if (ws->fsurf_back == NULL) {
			focus_surface_destroy(ws->fsurf_front);
			return;
		}
971
		ws->fsurf_back->view->alpha = 0.0;
972

973
974
		focus_surface_created = true;
	} else {
975
976
		weston_layer_entry_remove(&ws->fsurf_front->view->layer_link);
		weston_layer_entry_remove(&ws->fsurf_back->view->layer_link);
977
978
979
980
981
982
983
984
	}

	if (ws->focus_animation) {
		weston_view_animation_destroy(ws->focus_animation);
		ws->focus_animation = NULL;
	}

	if (to)
985
986
		weston_layer_entry_insert(&to->layer_link,
					  &ws->fsurf_front->view->layer_link);
987
	else if (from)
988
989
		weston_layer_entry_insert(&ws->layer.view_list,
					  &ws->fsurf_front->view->layer_link);
990
991
992
993

	if (focus_surface_created) {
		ws->focus_animation = weston_fade_run(
			ws->fsurf_front->view,
994
			ws->fsurf_front->view->alpha, 0.4, 300,
995
996
			focus_animation_done, ws);
	} else if (from) {
997
998
		weston_layer_entry_insert(&from->layer_link,
					  &ws->fsurf_back->view->layer_link);
999
1000
		ws->focus_animation = weston_stable_fade_run(
			ws->fsurf_front->view, 0.0,
1001
			ws->fsurf_back->view, 0.4,
1002
1003
			focus_animation_done, ws);
	} else if (to) {
1004
1005
		weston_layer_entry_insert(&ws->layer.view_list,
					  &ws->fsurf_back->view->layer_link);
1006
1007
		ws->focus_animation = weston_stable_fade_run(
			ws->fsurf_front->view, 0.0,
1008
			ws->fsurf_back->view, 0.4,
1009
1010
1011
1012
			focus_animation_done, ws);
	}
}

Jonas Ådahl's avatar
Jonas Ådahl committed
1013
1014
1015
static void
workspace_destroy(struct workspace *ws)
{
1016
1017
1018
1019
1020
	struct focus_state *state, *next;

	wl_list_for_each_safe(state, next, &ws->focus_list, link)
		focus_state_destroy(state);

1021
1022
1023
1024
1025
	if (ws->fsurf_front)
		focus_surface_destroy(ws->fsurf_front);
	if (ws->fsurf_back)
		focus_surface_destroy(ws->fsurf_back);

Jonas Ådahl's avatar
Jonas Ådahl committed
1026
1027
1028
	free(ws);
}

1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
static void
seat_destroyed(struct wl_listener *listener, void *data)
{
	struct weston_seat *seat = data;
	struct focus_state *state, *next;
	struct workspace *ws = container_of(listener,
					    struct workspace,
					    seat_destroyed_listener);

	wl_list_for_each_safe(state, next, &ws->focus_list, link)
		if (state->seat == seat)
			wl_list_remove(&state->link);
}

Jonas Ådahl's avatar
Jonas Ådahl committed
1043
1044
1045
1046
1047
1048
1049
1050
1051
static struct workspace *
workspace_create(void)
{
	struct workspace *ws = malloc(sizeof *ws);
	if (ws == NULL)
		return NULL;

	weston_layer_init(&ws->layer, NULL);

1052
1053
1054
	wl_list_init(&ws->focus_list);
	wl_list_init(&ws->seat_destroyed_listener.link);
	ws->seat_destroyed_listener.notify = seat_destroyed;
1055
1056
1057
	ws->fsurf_front = NULL;
	ws->fsurf_back = NULL;
	ws->focus_animation = NULL;
1058

Jonas Ådahl's avatar
Jonas Ådahl committed
1059
1060
1061
	return ws;
}

1062
1063
1064
static int
workspace_is_empty(struct workspace *ws)
{
1065
	return wl_list_empty(&ws->layer.view_list.link);
1066
1067
}

Jonas Ådahl's avatar
Jonas Ådahl committed
1068
1069
1070
1071
static struct workspace *
get_workspace(struct desktop_shell *shell, unsigned int index)
{
	struct workspace **pws = shell->workspaces.array.data;
1072
	assert(index < shell->workspaces.num);
Jonas Ådahl's avatar
Jonas Ådahl committed
1073
1074
1075
1076
	pws += index;
	return *pws;
}

1077
struct workspace *
Jonas Ådahl's avatar
Jonas Ådahl committed
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
get_current_workspace(struct desktop_shell *shell)
{
	return get_workspace(shell, shell->workspaces.current);
}

static void
activate_workspace(struct desktop_shell *shell, unsigned int index)
{
	struct workspace *ws;

	ws = get_workspace(shell, index);
	wl_list_insert(&shell->panel_layer.link, &ws->layer.link);

	shell->workspaces.current = index;
}

1094
1095
1096
1097
1098
1099
1100
static unsigned int
get_output_height(struct weston_output *output)
{
	return abs(output->region.extents.y1 - output->region.extents.y2);
}

static void
1101
view_translate(struct workspace *ws, struct weston_view *view, double d)
1102
1103
1104
{
	struct weston_transform *transform;

1105
1106
1107
1108
1109
1110
1111
1112
	if (is_focus_view(view)) {
		struct focus_surface *fsurf = get_focus_surface(view->surface);
		transform = &fsurf->workspace_transform;
	} else {
		struct shell_surface *shsurf = get_shell_surface(view->surface);
		transform = &shsurf->workspace_transform;
	}

1113
	if (wl_list_empty(&transform->link))
1114
		wl_list_insert(view->geometry.transformation_list.prev,
1115
			       &transform->link);
1116

1117
1118
	weston_matrix_init(&transform->matrix);
	weston_matrix_translate(&transform->matrix,
1119
				0.0, d, 0.0);
1120
	weston_view_geometry_dirty(view);
1121
1122
1123
1124
1125
}

static void
workspace_translate_out(struct workspace *ws, double fraction)
{
1126
	struct weston_view *view;
1127
1128
1129
	unsigned int height;
	double d;

1130
	wl_list_for_each(view, &ws->layer.view_list.link, layer_link.link) {
1131
		height = get_output_height(view->surface->output);
1132
1133
		d = height * fraction;

1134
		view_translate(ws, view, d);
1135
1136
1137
1138
1139
1140
	}
}

static void
workspace_translate_in(struct workspace *ws, double fraction)
{
1141
	struct weston_view *view;
1142
1143
1144
	unsigned int height;
	double d;

1145
	wl_list_for_each(view, &ws->layer.view_list.link, layer_link.link) {
1146
		height = get_output_height(view->surface->output);
1147
1148
1149
1150
1151
1152

		if (fraction > 0)
			d = -(height - height * fraction);
		else
			d = height + height * fraction;

1153
		view_translate(ws, view, d);
1154
1155
1156
	}
}

1157
1158
1159
static void
broadcast_current_workspace_state(struct desktop_shell *shell)
{
1160
	struct wl_resource *resource;
1161

1162
1163
	wl_resource_for_each(resource, &shell->workspaces.client_list)
		workspace_manager_send_state(resource,
1164
1165
1166
1167
					     shell->workspaces.current,
					     shell->workspaces.num);
}

1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
static void
reverse_workspace_change_animation(struct desktop_shell *shell,
				   unsigned int index,
				   struct workspace *from,
				   struct workspace *to)
{
	shell->workspaces.current = index;

	shell->workspaces.anim_to = to;
	shell->workspaces.anim_from = from;
	shell->workspaces.anim_dir = -1 * shell->workspaces.anim_dir;
	shell->workspaces.anim_timestamp = 0;

1181
	weston_compositor_schedule_repaint(shell->compositor);
1182
1183
1184
1185
1186
}

static void
workspace_deactivate_transforms(struct workspace *ws)
{
1187
	struct weston_view *view;