blob: fe620cb8f231bef184f1894178d09ffff479f80b [file] [log] [blame]
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001/*
Kristian Høgsberg07045392012-02-19 18:52:44 -05002 * Copyright © 2010-2012 Intel Corporation
Pekka Paalanend581a8f2012-01-27 16:25:16 +02003 * Copyright © 2011-2012 Collabora, Ltd.
Daniel Stonedf8133b2013-11-19 11:37:14 +01004 * Copyright © 2013 Raspberry Pi Foundation
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05005 *
6 * Permission to use, copy, modify, distribute, and sell this software and
7 * its documentation for any purpose is hereby granted without fee, provided
8 * that the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of the copyright holders not be used in
11 * advertising or publicity pertaining to distribution of the software
12 * without specific, written prior permission. The copyright holders make
13 * no representations about the suitability of this software for any
14 * purpose. It is provided "as is" without express or implied warranty.
15 *
16 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
17 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
18 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
20 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
21 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
22 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 */
24
Daniel Stonec228e232013-05-22 18:03:19 +030025#include "config.h"
26
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050027#include <stdlib.h>
Kristian Høgsberg75840622011-09-06 13:48:16 -040028#include <stdio.h>
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050029#include <string.h>
30#include <unistd.h>
Kristian Høgsberg07937562011-04-12 17:25:42 -040031#include <linux/input.h>
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +020032#include <assert.h>
Pekka Paalanen18027e52011-12-02 16:31:49 +020033#include <signal.h>
Pekka Paalanen460099f2012-01-20 16:48:25 +020034#include <math.h>
Kristian Høgsberg92a57db2012-05-26 13:41:06 -040035#include <sys/types.h>
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050036
Kristian Høgsberg1ef23132013-12-04 00:20:01 -080037#include "shell.h"
Kristian Høgsberg75840622011-09-06 13:48:16 -040038#include "desktop-shell-server-protocol.h"
Jonas Ådahle9d22502012-08-29 22:13:01 +020039#include "workspaces-server-protocol.h"
Pekka Paalanene955f1e2011-12-07 11:49:52 +020040#include "../shared/config-parser.h"
Rafael Antognollie2a34552013-12-03 15:35:45 -020041#include "xdg-shell-server-protocol.h"
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050042
Jonas Ådahle3cddce2012-06-13 00:01:22 +020043#define DEFAULT_NUM_WORKSPACES 1
Jonas Ådahl62fcd042012-06-13 00:01:23 +020044#define DEFAULT_WORKSPACE_CHANGE_ANIMATION_LENGTH 200
Jonas Ådahle3cddce2012-06-13 00:01:22 +020045
Giulio Camuffo1aaf3e42013-12-09 22:47:58 +010046#ifndef static_assert
47#define static_assert(cond, msg)
48#endif
49
Jonas Ådahl04769742012-06-13 00:01:24 +020050struct focus_state {
51 struct weston_seat *seat;
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -040052 struct workspace *ws;
Jonas Ådahl04769742012-06-13 00:01:24 +020053 struct weston_surface *keyboard_focus;
54 struct wl_list link;
55 struct wl_listener seat_destroy_listener;
56 struct wl_listener surface_destroy_listener;
57};
58
Kristian Høgsbergd2abb832011-11-23 10:52:40 -050059enum shell_surface_type {
Pekka Paalanen98262232011-12-01 10:42:22 +020060 SHELL_SURFACE_NONE,
Kristian Høgsbergd2abb832011-11-23 10:52:40 -050061 SHELL_SURFACE_TOPLEVEL,
Tiago Vignattifb2adba2013-06-12 15:43:21 -030062 SHELL_SURFACE_POPUP,
63 SHELL_SURFACE_XWAYLAND
Pekka Paalanen57da4a82011-11-23 16:42:16 +020064};
65
Jason Ekstrand9e9512f2014-04-16 21:12:10 -050066struct shell_client;
67
Philip Withnall648a4dd2013-11-25 18:01:44 +000068/*
69 * Surface stacking and ordering.
70 *
71 * This is handled using several linked lists of surfaces, organised into
72 * ‘layers’. The layers are ordered, and each of the surfaces in one layer are
73 * above all of the surfaces in the layer below. The set of layers is static and
74 * in the following order (top-most first):
75 * • Lock layer (only ever displayed on its own)
76 * • Cursor layer
Manuel Bachmann805d2f52014-03-05 12:21:34 +010077 * • Input panel layer
Philip Withnall648a4dd2013-11-25 18:01:44 +000078 * • Fullscreen layer
79 * • Panel layer
Philip Withnall648a4dd2013-11-25 18:01:44 +000080 * • Workspace layers
81 * • Background layer
82 *
83 * The list of layers may be manipulated to remove whole layers of surfaces from
84 * display. For example, when locking the screen, all layers except the lock
85 * layer are removed.
86 *
87 * A surface’s layer is modified on configuring the surface, in
88 * set_surface_type() (which is only called when the surface’s type change is
89 * _committed_). If a surface’s type changes (e.g. when making a window
90 * fullscreen) its layer changes too.
91 *
92 * In order to allow popup and transient surfaces to be correctly stacked above
93 * their parent surfaces, each surface tracks both its parent surface, and a
94 * linked list of its children. When a surface’s layer is updated, so are the
95 * layers of its children. Note that child surfaces are *not* the same as
96 * subsurfaces — child/parent surfaces are purely for maintaining stacking
97 * order.
98 *
99 * The children_link list of siblings of a surface (i.e. those surfaces which
100 * have the same parent) only contains weston_surfaces which have a
101 * shell_surface. Stacking is not implemented for non-shell_surface
102 * weston_surfaces. This means that the following implication does *not* hold:
103 * (shsurf->parent != NULL) ⇒ !wl_list_is_empty(shsurf->children_link)
104 */
105
Pekka Paalanen56cdea92011-11-23 16:14:12 +0200106struct shell_surface {
Jason Ekstrand651f00e2013-06-14 10:07:54 -0500107 struct wl_resource *resource;
108 struct wl_signal destroy_signal;
Jason Ekstrand9e9512f2014-04-16 21:12:10 -0500109 struct shell_client *owner;
Jonas Ådahl49d77d22015-03-18 16:20:51 +0800110 struct wl_resource *owner_resource;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200111
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500112 struct weston_surface *surface;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500113 struct weston_view *view;
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600114 int32_t last_width, last_height;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200115 struct wl_listener surface_destroy_listener;
Kristian Høgsberg160fe752014-03-11 10:19:10 -0700116 struct wl_listener resource_destroy_listener;
117
Kristian Høgsberg8150b192012-06-27 10:22:58 -0400118 struct weston_surface *parent;
Philip Withnall648a4dd2013-11-25 18:01:44 +0000119 struct wl_list children_list; /* child surfaces of this one */
120 struct wl_list children_link; /* sibling surfaces of this one */
Tiago Vignattibe143262012-04-16 17:31:41 +0300121 struct desktop_shell *shell;
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200122
Kristian Høgsbergc8f8dd82013-12-05 23:20:33 -0800123 enum shell_surface_type type;
Kristian Høgsberge7afd912012-05-02 09:47:44 -0400124 char *title, *class;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500125 int32_t saved_x, saved_y;
Rafael Antognolli3c4e3f72013-12-03 15:35:46 -0200126 int32_t saved_width, saved_height;
Alex Wu4539b082012-03-01 12:57:46 +0800127 bool saved_position_valid;
Rafael Antognolli3c4e3f72013-12-03 15:35:46 -0200128 bool saved_size_valid;
Alex Wu7bcb8bd2012-04-27 09:07:24 +0800129 bool saved_rotation_valid;
Kristian Høgsbergc85f1d42013-10-24 16:52:00 -0700130 int unresponsive, grabbed;
Kristian Høgsberg44cd1962014-02-05 21:36:04 -0800131 uint32_t resize_edges;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100132
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500133 struct {
Pekka Paalanen460099f2012-01-20 16:48:25 +0200134 struct weston_transform transform;
Kristian Høgsberg765e27b2012-01-27 13:36:13 -0500135 struct weston_matrix rotation;
Pekka Paalanen460099f2012-01-20 16:48:25 +0200136 } rotation;
137
138 struct {
Giulio Camuffo5085a752013-03-25 21:42:45 +0100139 struct wl_list grab_link;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500140 int32_t x, y;
Giulio Camuffo5085a752013-03-25 21:42:45 +0100141 struct shell_seat *shseat;
Kristian Høgsberg3730f362012-04-13 12:40:07 -0400142 uint32_t serial;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500143 } popup;
144
Alex Wu4539b082012-03-01 12:57:46 +0800145 struct {
Tiago Vignatti52e598c2012-05-07 15:23:08 +0300146 int32_t x, y;
Tiago Vignatti491bac12012-05-18 16:37:43 -0400147 uint32_t flags;
Tiago Vignatti52e598c2012-05-07 15:23:08 +0300148 } transient;
149
150 struct {
Alex Wu4539b082012-03-01 12:57:46 +0800151 enum wl_shell_surface_fullscreen_method type;
152 struct weston_transform transform; /* matrix from x, y */
153 uint32_t framerate;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500154 struct weston_view *black_view;
Alex Wu4539b082012-03-01 12:57:46 +0800155 } fullscreen;
156
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200157 struct weston_transform workspace_transform;
158
Kristian Høgsberg1cbf3262012-02-17 23:49:07 -0500159 struct weston_output *fullscreen_output;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500160 struct weston_output *output;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100161 struct wl_list link;
Kristian Høgsberga61ca062012-05-22 16:05:52 -0400162
163 const struct weston_shell_client *client;
Rafael Antognolli03b16592013-12-03 15:35:42 -0200164
Jasper St. Pierre6458ec32014-04-11 16:00:31 -0700165 struct surface_state {
Rafael Antognolli03b16592013-12-03 15:35:42 -0200166 bool maximized;
167 bool fullscreen;
Rafael Antognollied207b42013-12-03 15:35:43 -0200168 bool relative;
Emilio Pozuelo Monfort9e7c7592014-01-30 14:01:10 +0100169 bool lowered;
Jasper St. Pierre8c6aa452014-02-08 18:29:49 -0500170 } state, next_state, requested_state; /* surface states */
Rafael Antognolli03b16592013-12-03 15:35:42 -0200171 bool state_changed;
Jasper St. Pierre8c6aa452014-02-08 18:29:49 -0500172 bool state_requested;
Jasper St. Pierrefaf27a92013-12-09 17:36:28 -0500173
Kristian Høgsbergae356ae2014-04-29 16:03:54 -0700174 struct {
Jasper St. Pierreccf48fb2014-05-02 10:21:38 -0400175 int32_t x, y, width, height;
176 } geometry, next_geometry;
177 bool has_set_geometry, has_next_geometry;
Kristian Høgsbergae356ae2014-04-29 16:03:54 -0700178
Jasper St. Pierrefaf27a92013-12-09 17:36:28 -0500179 int focus_count;
Derek Foreman039e9be2015-04-14 17:09:06 -0500180
181 bool destroying;
Pekka Paalanen56cdea92011-11-23 16:14:12 +0200182};
183
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300184struct shell_grab {
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -0400185 struct weston_pointer_grab grab;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300186 struct shell_surface *shsurf;
187 struct wl_listener shsurf_destroy_listener;
188};
189
Rusty Lynch1084da52013-08-15 09:10:08 -0700190struct shell_touch_grab {
191 struct weston_touch_grab grab;
192 struct shell_surface *shsurf;
193 struct wl_listener shsurf_destroy_listener;
194 struct weston_touch *touch;
195};
196
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300197struct weston_move_grab {
198 struct shell_grab base;
Daniel Stone103db7f2012-05-08 17:17:55 +0100199 wl_fixed_t dx, dy;
Kristian Høgsbergae356ae2014-04-29 16:03:54 -0700200 int client_initiated;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500201};
202
Rusty Lynch1084da52013-08-15 09:10:08 -0700203struct weston_touch_move_grab {
204 struct shell_touch_grab base;
Kristian Høgsberg8e80a312014-01-17 15:18:10 -0800205 int active;
Rusty Lynch1084da52013-08-15 09:10:08 -0700206 wl_fixed_t dx, dy;
207};
208
Pekka Paalanen460099f2012-01-20 16:48:25 +0200209struct rotate_grab {
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300210 struct shell_grab base;
Kristian Høgsberg765e27b2012-01-27 13:36:13 -0500211 struct weston_matrix rotation;
Pekka Paalanen460099f2012-01-20 16:48:25 +0200212 struct {
John Kåre Alsaker490d02a2012-09-30 02:57:21 +0200213 float x;
214 float y;
Pekka Paalanen460099f2012-01-20 16:48:25 +0200215 } center;
216};
217
Giulio Camuffo5085a752013-03-25 21:42:45 +0100218struct shell_seat {
219 struct weston_seat *seat;
220 struct wl_listener seat_destroy_listener;
Jasper St. Pierrefaf27a92013-12-09 17:36:28 -0500221 struct weston_surface *focused_surface;
Giulio Camuffo5085a752013-03-25 21:42:45 +0100222
Jason Ekstrand024177c2014-04-21 19:42:58 -0500223 struct wl_listener caps_changed_listener;
224 struct wl_listener pointer_focus_listener;
225 struct wl_listener keyboard_focus_listener;
226
Giulio Camuffo5085a752013-03-25 21:42:45 +0100227 struct {
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -0400228 struct weston_pointer_grab grab;
Jonny Lamb76cf1fe2014-08-20 11:27:10 +0200229 struct weston_touch_grab touch_grab;
Giulio Camuffo5085a752013-03-25 21:42:45 +0100230 struct wl_list surfaces_list;
231 struct wl_client *client;
232 int32_t initial_up;
Jonny Lamb76cf1fe2014-08-20 11:27:10 +0200233 enum { POINTER, TOUCH } type;
Giulio Camuffo5085a752013-03-25 21:42:45 +0100234 } popup_grab;
235};
236
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -0800237struct shell_client {
238 struct wl_resource *resource;
239 struct wl_client *client;
240 struct desktop_shell *shell;
241 struct wl_listener destroy_listener;
242 struct wl_event_source *ping_timer;
243 uint32_t ping_serial;
244 int unresponsive;
Jonas Ådahl49d77d22015-03-18 16:20:51 +0800245 struct wl_list surface_list;
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -0800246};
247
Alex Wubd3354b2012-04-17 17:20:49 +0800248static struct desktop_shell *
249shell_surface_get_shell(struct shell_surface *shsurf);
250
Kristian Høgsberg0c369032013-02-14 21:31:44 -0500251static void
Kristian Høgsberge3148752013-05-06 23:19:49 -0400252surface_rotate(struct shell_surface *surface, struct weston_seat *seat);
Kristian Høgsberg0c369032013-02-14 21:31:44 -0500253
Pekka Paalanen79346ab2013-05-22 18:03:09 +0300254static void
255shell_fade_startup(struct desktop_shell *shell);
256
Philip Withnallbecb77e2013-11-25 18:01:30 +0000257static struct shell_seat *
258get_shell_seat(struct weston_seat *seat);
259
Jonny Lambd73c6942014-08-20 15:53:20 +0200260static void
261get_output_panel_size(struct desktop_shell *shell,
262 struct weston_output *output,
263 int *width, int *height);
Kristian Høgsbergae356ae2014-04-29 16:03:54 -0700264
Philip Withnall648a4dd2013-11-25 18:01:44 +0000265static void
266shell_surface_update_child_surface_layers(struct shell_surface *shsurf);
267
Alex Wubd3354b2012-04-17 17:20:49 +0800268static bool
Rafael Antognollie2a34552013-12-03 15:35:45 -0200269shell_surface_is_wl_shell_surface(struct shell_surface *shsurf);
270
271static bool
272shell_surface_is_xdg_surface(struct shell_surface *shsurf);
273
274static bool
275shell_surface_is_xdg_popup(struct shell_surface *shsurf);
276
277static void
278shell_surface_set_parent(struct shell_surface *shsurf,
279 struct weston_surface *parent);
280
Pekka Paalanen8274d902014-08-06 19:36:51 +0300281static int
282shell_surface_get_label(struct weston_surface *surface, char *buf, size_t len)
283{
284 struct shell_surface *shsurf;
285 const char *typestr[] = {
286 [SHELL_SURFACE_NONE] = "unidentified",
287 [SHELL_SURFACE_TOPLEVEL] = "top-level",
288 [SHELL_SURFACE_POPUP] = "popup",
289 [SHELL_SURFACE_XWAYLAND] = "Xwayland",
290 };
291 const char *t, *c;
292
293 shsurf = get_shell_surface(surface);
294 if (!shsurf)
295 return snprintf(buf, len, "unidentified window");
296
297 t = shsurf->title;
298 c = shsurf->class;
299
300 return snprintf(buf, len, "%s window%s%s%s%s%s",
301 typestr[shsurf->type],
302 t ? " '" : "", t ?: "", t ? "'" : "",
303 c ? " of " : "", c ?: "");
304}
305
Rafael Antognollie2a34552013-12-03 15:35:45 -0200306static bool
Alex Wubd3354b2012-04-17 17:20:49 +0800307shell_surface_is_top_fullscreen(struct shell_surface *shsurf)
308{
309 struct desktop_shell *shell;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500310 struct weston_view *top_fs_ev;
Alex Wubd3354b2012-04-17 17:20:49 +0800311
312 shell = shell_surface_get_shell(shsurf);
Quentin Glidicc0d79ce2013-01-29 14:16:13 +0100313
Giulio Camuffo412e6a52014-07-09 22:12:56 +0300314 if (wl_list_empty(&shell->fullscreen_layer.view_list.link))
Alex Wubd3354b2012-04-17 17:20:49 +0800315 return false;
316
Giulio Camuffo412e6a52014-07-09 22:12:56 +0300317 top_fs_ev = container_of(shell->fullscreen_layer.view_list.link.next,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500318 struct weston_view,
Giulio Camuffo412e6a52014-07-09 22:12:56 +0300319 layer_link.link);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500320 return (shsurf == get_shell_surface(top_fs_ev->surface));
Alex Wubd3354b2012-04-17 17:20:49 +0800321}
322
Kristian Høgsberg6af8eb92012-01-25 16:57:11 -0500323static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400324destroy_shell_grab_shsurf(struct wl_listener *listener, void *data)
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300325{
326 struct shell_grab *grab;
327
328 grab = container_of(listener, struct shell_grab,
329 shsurf_destroy_listener);
330
331 grab->shsurf = NULL;
332}
333
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800334struct weston_view *
Jason Ekstranda7af7042013-10-12 22:38:11 -0500335get_default_view(struct weston_surface *surface)
336{
337 struct shell_surface *shsurf;
338 struct weston_view *view;
339
340 if (!surface || wl_list_empty(&surface->views))
341 return NULL;
342
343 shsurf = get_shell_surface(surface);
344 if (shsurf)
345 return shsurf->view;
346
347 wl_list_for_each(view, &surface->views, surface_link)
348 if (weston_view_is_mapped(view))
349 return view;
350
351 return container_of(surface->views.next, struct weston_view, surface_link);
352}
353
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300354static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -0400355popup_grab_end(struct weston_pointer *pointer);
Jonny Lamb76cf1fe2014-08-20 11:27:10 +0200356static void
357touch_popup_grab_end(struct weston_touch *touch);
Kristian Høgsberg57e09072012-10-30 14:07:27 -0400358
359static void
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300360shell_grab_start(struct shell_grab *grab,
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -0400361 const struct weston_pointer_grab_interface *interface,
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300362 struct shell_surface *shsurf,
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -0400363 struct weston_pointer *pointer,
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300364 enum desktop_shell_cursor cursor)
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300365{
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300366 struct desktop_shell *shell = shsurf->shell;
367
Kristian Høgsberg57e09072012-10-30 14:07:27 -0400368 popup_grab_end(pointer);
Jonny Lamb76cf1fe2014-08-20 11:27:10 +0200369 if (pointer->seat->touch)
370 touch_popup_grab_end(pointer->seat->touch);
Kristian Høgsberg57e09072012-10-30 14:07:27 -0400371
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300372 grab->grab.interface = interface;
373 grab->shsurf = shsurf;
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400374 grab->shsurf_destroy_listener.notify = destroy_shell_grab_shsurf;
Jason Ekstrand651f00e2013-06-14 10:07:54 -0500375 wl_signal_add(&shsurf->destroy_signal,
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400376 &grab->shsurf_destroy_listener);
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300377
Kristian Høgsbergc85f1d42013-10-24 16:52:00 -0700378 shsurf->grabbed = 1;
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -0400379 weston_pointer_start_grab(pointer, &grab->grab);
Kristian Høgsbergc9974a02013-07-03 19:24:57 -0400380 if (shell->child.desktop_shell) {
381 desktop_shell_send_grab_cursor(shell->child.desktop_shell,
382 cursor);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500383 weston_pointer_set_focus(pointer,
384 get_default_view(shell->grab_surface),
Kristian Høgsbergc9974a02013-07-03 19:24:57 -0400385 wl_fixed_from_int(0),
386 wl_fixed_from_int(0));
387 }
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300388}
389
Jonny Lambd73c6942014-08-20 15:53:20 +0200390static void
391get_output_panel_size(struct desktop_shell *shell,
392 struct weston_output *output,
393 int *width,
394 int *height)
Jasper St. Pierre6458ec32014-04-11 16:00:31 -0700395{
396 struct weston_view *view;
Jonny Lambd73c6942014-08-20 15:53:20 +0200397
398 *width = 0;
399 *height = 0;
Jasper St. Pierre6458ec32014-04-11 16:00:31 -0700400
401 if (!output)
Jonny Lambd73c6942014-08-20 15:53:20 +0200402 return;
Jasper St. Pierre6458ec32014-04-11 16:00:31 -0700403
Giulio Camuffo412e6a52014-07-09 22:12:56 +0300404 wl_list_for_each(view, &shell->panel_layer.view_list.link, layer_link.link) {
Jonny Lambd73c6942014-08-20 15:53:20 +0200405 float x, y;
406
407 if (view->surface->output != output)
408 continue;
409
410 switch (shell->panel_position) {
411 case DESKTOP_SHELL_PANEL_POSITION_TOP:
412 case DESKTOP_SHELL_PANEL_POSITION_BOTTOM:
413
414 weston_view_to_global_float(view,
415 view->surface->width, 0,
416 &x, &y);
417
418 *width = (int) x;
419 *height = view->surface->height + (int) y;
420 return;
421
422 case DESKTOP_SHELL_PANEL_POSITION_LEFT:
423 case DESKTOP_SHELL_PANEL_POSITION_RIGHT:
424 weston_view_to_global_float(view,
425 0, view->surface->height,
426 &x, &y);
427
428 *width = view->surface->width + (int) x;
429 *height = (int) y;
430 return;
431
432 default:
433 /* we've already set width and height to
434 * fallback values. */
Jasper St. Pierre6458ec32014-04-11 16:00:31 -0700435 break;
436 }
437 }
438
Jonny Lambd73c6942014-08-20 15:53:20 +0200439 /* the correct view wasn't found */
440}
441
442static void
443get_output_work_area(struct desktop_shell *shell,
444 struct weston_output *output,
445 pixman_rectangle32_t *area)
446{
447 int32_t panel_width = 0, panel_height = 0;
448
449 area->x = 0;
450 area->y = 0;
451
452 get_output_panel_size(shell, output, &panel_width, &panel_height);
453
454 switch (shell->panel_position) {
455 case DESKTOP_SHELL_PANEL_POSITION_TOP:
456 default:
457 area->y = panel_height;
458 case DESKTOP_SHELL_PANEL_POSITION_BOTTOM:
459 area->width = output->width;
460 area->height = output->height - panel_height;
461 break;
462 case DESKTOP_SHELL_PANEL_POSITION_LEFT:
463 area->x = panel_width;
464 case DESKTOP_SHELL_PANEL_POSITION_RIGHT:
465 area->width = output->width - panel_width;
466 area->height = output->height;
467 break;
468 }
Jasper St. Pierre6458ec32014-04-11 16:00:31 -0700469}
470
471static void
472send_configure_for_surface(struct shell_surface *shsurf)
473{
474 int32_t width, height;
475 struct surface_state *state;
476
477 if (shsurf->state_requested)
478 state = &shsurf->requested_state;
479 else if (shsurf->state_changed)
480 state = &shsurf->next_state;
481 else
482 state = &shsurf->state;
483
484 if (state->fullscreen) {
485 width = shsurf->output->width;
486 height = shsurf->output->height;
487 } else if (state->maximized) {
488 struct desktop_shell *shell;
Jonny Lambd73c6942014-08-20 15:53:20 +0200489 pixman_rectangle32_t area;
Jasper St. Pierre6458ec32014-04-11 16:00:31 -0700490
491 shell = shell_surface_get_shell(shsurf);
Jonny Lambd73c6942014-08-20 15:53:20 +0200492 get_output_work_area(shell, shsurf->output, &area);
Jasper St. Pierre6458ec32014-04-11 16:00:31 -0700493
Jonny Lambd73c6942014-08-20 15:53:20 +0200494 width = area.width;
495 height = area.height;
Ryo Munakata79954ec2015-05-02 21:44:04 +0900496 } else if (shsurf->resize_edges) {
497 width = shsurf->geometry.width;
498 height = shsurf->geometry.height;
Jasper St. Pierre6458ec32014-04-11 16:00:31 -0700499 } else {
500 width = 0;
501 height = 0;
502 }
503
504 shsurf->client->send_configure(shsurf->surface, width, height);
505}
506
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300507static void
Jasper St. Pierre5befdda2014-05-06 08:50:47 -0400508shell_surface_state_changed(struct shell_surface *shsurf)
509{
Jasper St. Pierre6458ec32014-04-11 16:00:31 -0700510 if (shell_surface_is_xdg_surface(shsurf))
511 send_configure_for_surface(shsurf);
Jasper St. Pierre5befdda2014-05-06 08:50:47 -0400512}
513
514static void
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300515shell_grab_end(struct shell_grab *grab)
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300516{
Kristian Høgsbergc85f1d42013-10-24 16:52:00 -0700517 if (grab->shsurf) {
Kristian Høgsberg47b5dca2012-06-07 18:08:04 -0400518 wl_list_remove(&grab->shsurf_destroy_listener.link);
Kristian Høgsbergc85f1d42013-10-24 16:52:00 -0700519 grab->shsurf->grabbed = 0;
Jasper St. Pierre5befdda2014-05-06 08:50:47 -0400520
521 if (grab->shsurf->resize_edges) {
522 grab->shsurf->resize_edges = 0;
523 shell_surface_state_changed(grab->shsurf);
524 }
Kristian Høgsbergc85f1d42013-10-24 16:52:00 -0700525 }
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300526
Kristian Høgsberg9e5d7d12013-07-22 16:31:53 -0700527 weston_pointer_end_grab(grab->grab.pointer);
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300528}
529
530static void
Rusty Lynch1084da52013-08-15 09:10:08 -0700531shell_touch_grab_start(struct shell_touch_grab *grab,
532 const struct weston_touch_grab_interface *interface,
533 struct shell_surface *shsurf,
534 struct weston_touch *touch)
535{
536 struct desktop_shell *shell = shsurf->shell;
U. Artie Eoffcf5737a2014-01-17 10:08:25 -0800537
Jonny Lamb76cf1fe2014-08-20 11:27:10 +0200538 touch_popup_grab_end(touch);
Kristian Høgsberg74071e02014-04-29 15:01:16 -0700539 if (touch->seat->pointer)
540 popup_grab_end(touch->seat->pointer);
541
Rusty Lynch1084da52013-08-15 09:10:08 -0700542 grab->grab.interface = interface;
543 grab->shsurf = shsurf;
544 grab->shsurf_destroy_listener.notify = destroy_shell_grab_shsurf;
545 wl_signal_add(&shsurf->destroy_signal,
546 &grab->shsurf_destroy_listener);
547
548 grab->touch = touch;
Kristian Høgsbergc85f1d42013-10-24 16:52:00 -0700549 shsurf->grabbed = 1;
Rusty Lynch1084da52013-08-15 09:10:08 -0700550
551 weston_touch_start_grab(touch, &grab->grab);
552 if (shell->child.desktop_shell)
Derek Foreman4c93c082015-04-30 16:45:41 -0500553 weston_touch_set_focus(touch,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500554 get_default_view(shell->grab_surface));
Rusty Lynch1084da52013-08-15 09:10:08 -0700555}
556
557static void
558shell_touch_grab_end(struct shell_touch_grab *grab)
559{
Kristian Høgsbergc85f1d42013-10-24 16:52:00 -0700560 if (grab->shsurf) {
Rusty Lynch1084da52013-08-15 09:10:08 -0700561 wl_list_remove(&grab->shsurf_destroy_listener.link);
Kristian Høgsbergc85f1d42013-10-24 16:52:00 -0700562 grab->shsurf->grabbed = 0;
563 }
Rusty Lynch1084da52013-08-15 09:10:08 -0700564
565 weston_touch_end_grab(grab->touch);
566}
567
568static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500569center_on_output(struct weston_view *view,
Alex Wu4539b082012-03-01 12:57:46 +0800570 struct weston_output *output);
571
Daniel Stone496ca172012-05-30 16:31:42 +0100572static enum weston_keyboard_modifier
Tiago Vignatti0b52d482012-04-20 18:54:25 +0300573get_modifier(char *modifier)
574{
575 if (!modifier)
576 return MODIFIER_SUPER;
577
578 if (!strcmp("ctrl", modifier))
579 return MODIFIER_CTRL;
580 else if (!strcmp("alt", modifier))
581 return MODIFIER_ALT;
582 else if (!strcmp("super", modifier))
583 return MODIFIER_SUPER;
584 else
585 return MODIFIER_SUPER;
586}
587
Juan Zhaoe10d2792012-04-25 19:09:52 +0800588static enum animation_type
589get_animation_type(char *animation)
590{
U. Artie Eoffb5719102014-01-15 14:26:31 -0800591 if (!animation)
592 return ANIMATION_NONE;
593
Juan Zhaoe10d2792012-04-25 19:09:52 +0800594 if (!strcmp("zoom", animation))
595 return ANIMATION_ZOOM;
596 else if (!strcmp("fade", animation))
597 return ANIMATION_FADE;
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100598 else if (!strcmp("dim-layer", animation))
599 return ANIMATION_DIM_LAYER;
Juan Zhaoe10d2792012-04-25 19:09:52 +0800600 else
601 return ANIMATION_NONE;
602}
603
Alex Wu4539b082012-03-01 12:57:46 +0800604static void
Kristian Høgsberg14e438c2013-05-26 21:48:14 -0400605shell_configuration(struct desktop_shell *shell)
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200606{
Kristian Høgsberg673a8892013-05-23 21:40:56 -0400607 struct weston_config_section *section;
608 int duration;
Derek Foremanc7210432014-08-21 11:32:38 -0500609 char *s, *client;
Pekka Paalanen974c0942014-09-05 14:45:09 +0300610 int ret;
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200611
Kristian Høgsberg673a8892013-05-23 21:40:56 -0400612 section = weston_config_get_section(shell->compositor->config,
613 "screensaver", NULL, NULL);
614 weston_config_section_get_string(section,
615 "path", &shell->screensaver.path, NULL);
616 weston_config_section_get_int(section, "duration", &duration, 60);
Ander Conselvan de Oliveira859e8852013-02-21 18:35:21 +0200617 shell->screensaver.duration = duration * 1000;
Kristian Høgsberg673a8892013-05-23 21:40:56 -0400618
619 section = weston_config_get_section(shell->compositor->config,
620 "shell", NULL, NULL);
Pekka Paalanen974c0942014-09-05 14:45:09 +0300621 ret = asprintf(&client, "%s/%s", weston_config_get_libexec_dir(),
622 WESTON_SHELL_CLIENT);
623 if (ret < 0)
624 client = NULL;
Kristian Høgsberg673a8892013-05-23 21:40:56 -0400625 weston_config_section_get_string(section,
Derek Foremanc7210432014-08-21 11:32:38 -0500626 "client", &s, client);
627 free(client);
Emilio Pozuelo Monfort46ce7982013-11-20 13:22:29 +0100628 shell->client = s;
629 weston_config_section_get_string(section,
Kristian Høgsberg673a8892013-05-23 21:40:56 -0400630 "binding-modifier", &s, "super");
631 shell->binding_modifier = get_modifier(s);
Quentin Glidic8418c292013-06-18 09:11:03 +0200632 free(s);
Kristian Høgsbergd56ab4e2014-01-16 16:51:52 -0800633
634 weston_config_section_get_string(section,
635 "exposay-modifier", &s, "none");
636 if (strcmp(s, "none") == 0)
637 shell->exposay_modifier = 0;
638 else
639 shell->exposay_modifier = get_modifier(s);
640 free(s);
641
Kristian Høgsberg673a8892013-05-23 21:40:56 -0400642 weston_config_section_get_string(section, "animation", &s, "none");
643 shell->win_animation_type = get_animation_type(s);
Quentin Glidic8418c292013-06-18 09:11:03 +0200644 free(s);
Jonny Lambf322f8e2014-08-12 15:13:30 +0200645 weston_config_section_get_string(section, "close-animation", &s, "fade");
646 shell->win_close_animation_type = get_animation_type(s);
647 free(s);
Kristian Høgsberg724c8d92013-10-16 11:38:24 -0700648 weston_config_section_get_string(section,
649 "startup-animation", &s, "fade");
650 shell->startup_animation_type = get_animation_type(s);
651 free(s);
Kristian Høgsberg912e0a12013-10-30 08:59:55 -0700652 if (shell->startup_animation_type == ANIMATION_ZOOM)
653 shell->startup_animation_type = ANIMATION_NONE;
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100654 weston_config_section_get_string(section, "focus-animation", &s, "none");
655 shell->focus_animation_type = get_animation_type(s);
656 free(s);
Kristian Høgsberg673a8892013-05-23 21:40:56 -0400657 weston_config_section_get_uint(section, "num-workspaces",
658 &shell->workspaces.num,
659 DEFAULT_NUM_WORKSPACES);
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200660}
661
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800662struct weston_output *
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100663get_default_output(struct weston_compositor *compositor)
664{
665 return container_of(compositor->output_list.next,
666 struct weston_output, link);
667}
668
Pekka Paalanen8274d902014-08-06 19:36:51 +0300669static int
670focus_surface_get_label(struct weston_surface *surface, char *buf, size_t len)
671{
672 return snprintf(buf, len, "focus highlight effect for output %s",
673 surface->output->name);
674}
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100675
676/* no-op func for checking focus surface */
677static void
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600678focus_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100679{
680}
681
682static struct focus_surface *
683get_focus_surface(struct weston_surface *surface)
684{
685 if (surface->configure == focus_surface_configure)
686 return surface->configure_private;
687 else
688 return NULL;
689}
690
691static bool
692is_focus_surface (struct weston_surface *es)
693{
694 return (es->configure == focus_surface_configure);
695}
696
697static bool
698is_focus_view (struct weston_view *view)
699{
700 return is_focus_surface (view->surface);
701}
702
703static struct focus_surface *
704create_focus_surface(struct weston_compositor *ec,
705 struct weston_output *output)
706{
707 struct focus_surface *fsurf = NULL;
708 struct weston_surface *surface = NULL;
709
710 fsurf = malloc(sizeof *fsurf);
711 if (!fsurf)
712 return NULL;
713
714 fsurf->surface = weston_surface_create(ec);
715 surface = fsurf->surface;
716 if (surface == NULL) {
717 free(fsurf);
718 return NULL;
719 }
720
721 surface->configure = focus_surface_configure;
722 surface->output = output;
723 surface->configure_private = fsurf;
Pekka Paalanen8274d902014-08-06 19:36:51 +0300724 weston_surface_set_label_func(surface, focus_surface_get_label);
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100725
U. Artie Eoff0b23b2b2014-01-15 14:45:59 -0800726 fsurf->view = weston_view_create(surface);
727 if (fsurf->view == NULL) {
728 weston_surface_destroy(surface);
729 free(fsurf);
730 return NULL;
731 }
Emilio Pozuelo Monfortda644262013-11-19 11:37:19 +0100732 fsurf->view->output = output;
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100733
Jason Ekstrand5c11a332013-12-04 20:32:03 -0600734 weston_surface_set_size(surface, output->width, output->height);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600735 weston_view_set_position(fsurf->view, output->x, output->y);
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100736 weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1.0);
737 pixman_region32_fini(&surface->opaque);
738 pixman_region32_init_rect(&surface->opaque, output->x, output->y,
739 output->width, output->height);
740 pixman_region32_fini(&surface->input);
741 pixman_region32_init(&surface->input);
742
743 wl_list_init(&fsurf->workspace_transform.link);
744
745 return fsurf;
746}
747
748static void
749focus_surface_destroy(struct focus_surface *fsurf)
750{
751 weston_surface_destroy(fsurf->surface);
752 free(fsurf);
753}
754
755static void
756focus_animation_done(struct weston_view_animation *animation, void *data)
757{
758 struct workspace *ws = data;
759
760 ws->focus_animation = NULL;
761}
762
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200763static void
Jonas Ådahl04769742012-06-13 00:01:24 +0200764focus_state_destroy(struct focus_state *state)
765{
766 wl_list_remove(&state->seat_destroy_listener.link);
767 wl_list_remove(&state->surface_destroy_listener.link);
768 free(state);
769}
770
771static void
772focus_state_seat_destroy(struct wl_listener *listener, void *data)
773{
774 struct focus_state *state = container_of(listener,
775 struct focus_state,
776 seat_destroy_listener);
777
778 wl_list_remove(&state->link);
779 focus_state_destroy(state);
780}
781
782static void
783focus_state_surface_destroy(struct wl_listener *listener, void *data)
784{
785 struct focus_state *state = container_of(listener,
786 struct focus_state,
Kristian Høgsbergb8e0d0f2012-07-31 10:30:26 -0400787 surface_destroy_listener);
Kristian Høgsberge3778222012-07-31 17:29:30 -0400788 struct desktop_shell *shell;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500789 struct weston_surface *main_surface, *next;
790 struct weston_view *view;
Jonas Ådahl04769742012-06-13 00:01:24 +0200791
Pekka Paalanen01388e22013-04-25 13:57:44 +0300792 main_surface = weston_surface_get_main_surface(state->keyboard_focus);
793
Kristian Høgsberge3778222012-07-31 17:29:30 -0400794 next = NULL;
Giulio Camuffo412e6a52014-07-09 22:12:56 +0300795 wl_list_for_each(view,
796 &state->ws->layer.view_list.link, layer_link.link) {
Jason Ekstranda7af7042013-10-12 22:38:11 -0500797 if (view->surface == main_surface)
Kristian Høgsberge3778222012-07-31 17:29:30 -0400798 continue;
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100799 if (is_focus_view(view))
800 continue;
Kristian Høgsberge3778222012-07-31 17:29:30 -0400801
Jason Ekstranda7af7042013-10-12 22:38:11 -0500802 next = view->surface;
Kristian Høgsberge3778222012-07-31 17:29:30 -0400803 break;
804 }
805
Pekka Paalanen01388e22013-04-25 13:57:44 +0300806 /* if the focus was a sub-surface, activate its main surface */
807 if (main_surface != state->keyboard_focus)
808 next = main_surface;
809
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100810 shell = state->seat->compositor->shell_interface.shell;
Kristian Høgsberge3778222012-07-31 17:29:30 -0400811 if (next) {
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100812 state->keyboard_focus = NULL;
Emilio Pozuelo Monfort9e7c7592014-01-30 14:01:10 +0100813 activate(shell, next, state->seat, true);
Kristian Høgsberge3778222012-07-31 17:29:30 -0400814 } else {
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100815 if (shell->focus_animation_type == ANIMATION_DIM_LAYER) {
816 if (state->ws->focus_animation)
817 weston_view_animation_destroy(state->ws->focus_animation);
818
819 state->ws->focus_animation = weston_fade_run(
820 state->ws->fsurf_front->view,
821 state->ws->fsurf_front->view->alpha, 0.0, 300,
822 focus_animation_done, state->ws);
823 }
824
Kristian Høgsberge3778222012-07-31 17:29:30 -0400825 wl_list_remove(&state->link);
826 focus_state_destroy(state);
827 }
Jonas Ådahl04769742012-06-13 00:01:24 +0200828}
829
830static struct focus_state *
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400831focus_state_create(struct weston_seat *seat, struct workspace *ws)
Jonas Ådahl04769742012-06-13 00:01:24 +0200832{
Jonas Ådahl04769742012-06-13 00:01:24 +0200833 struct focus_state *state;
Jonas Ådahl04769742012-06-13 00:01:24 +0200834
835 state = malloc(sizeof *state);
836 if (state == NULL)
837 return NULL;
838
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100839 state->keyboard_focus = NULL;
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400840 state->ws = ws;
Jonas Ådahl04769742012-06-13 00:01:24 +0200841 state->seat = seat;
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400842 wl_list_insert(&ws->focus_list, &state->link);
Jonas Ådahl04769742012-06-13 00:01:24 +0200843
844 state->seat_destroy_listener.notify = focus_state_seat_destroy;
845 state->surface_destroy_listener.notify = focus_state_surface_destroy;
Kristian Høgsberg49124542013-05-06 22:27:40 -0400846 wl_signal_add(&seat->destroy_signal,
Jonas Ådahl04769742012-06-13 00:01:24 +0200847 &state->seat_destroy_listener);
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400848 wl_list_init(&state->surface_destroy_listener.link);
Jonas Ådahl04769742012-06-13 00:01:24 +0200849
850 return state;
851}
852
Jonas Ådahl8538b222012-08-29 22:13:03 +0200853static struct focus_state *
854ensure_focus_state(struct desktop_shell *shell, struct weston_seat *seat)
855{
856 struct workspace *ws = get_current_workspace(shell);
857 struct focus_state *state;
858
859 wl_list_for_each(state, &ws->focus_list, link)
860 if (state->seat == seat)
861 break;
862
863 if (&state->link == &ws->focus_list)
864 state = focus_state_create(seat, ws);
865
866 return state;
867}
868
Jonas Ådahl04769742012-06-13 00:01:24 +0200869static void
Kristian Høgsbergd500bf12014-01-22 12:25:20 -0800870focus_state_set_focus(struct focus_state *state,
871 struct weston_surface *surface)
872{
873 if (state->keyboard_focus) {
874 wl_list_remove(&state->surface_destroy_listener.link);
875 wl_list_init(&state->surface_destroy_listener.link);
876 }
877
878 state->keyboard_focus = surface;
879 if (surface)
880 wl_signal_add(&surface->destroy_signal,
881 &state->surface_destroy_listener);
882}
883
884static void
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400885restore_focus_state(struct desktop_shell *shell, struct workspace *ws)
Jonas Ådahl04769742012-06-13 00:01:24 +0200886{
887 struct focus_state *state, *next;
Kristian Høgsbergfe7aa902013-05-08 09:54:37 -0400888 struct weston_surface *surface;
Neil Roberts4237f502014-04-09 16:33:31 +0100889 struct wl_list pending_seat_list;
890 struct weston_seat *seat, *next_seat;
891
892 /* Temporarily steal the list of seats so that we can keep
893 * track of the seats we've already processed */
894 wl_list_init(&pending_seat_list);
895 wl_list_insert_list(&pending_seat_list, &shell->compositor->seat_list);
896 wl_list_init(&shell->compositor->seat_list);
Jonas Ådahl04769742012-06-13 00:01:24 +0200897
898 wl_list_for_each_safe(state, next, &ws->focus_list, link) {
Neil Roberts4237f502014-04-09 16:33:31 +0100899 wl_list_remove(&state->seat->link);
900 wl_list_insert(&shell->compositor->seat_list,
901 &state->seat->link);
902
Kristian Høgsberge61d2f42014-01-17 12:18:53 -0800903 if (state->seat->keyboard == NULL)
904 continue;
905
Kristian Høgsbergfe7aa902013-05-08 09:54:37 -0400906 surface = state->keyboard_focus;
Jonas Ådahl56899442012-08-29 22:12:59 +0200907
Kristian Høgsberge3148752013-05-06 23:19:49 -0400908 weston_keyboard_set_focus(state->seat->keyboard, surface);
Jonas Ådahl04769742012-06-13 00:01:24 +0200909 }
Neil Roberts4237f502014-04-09 16:33:31 +0100910
911 /* For any remaining seats that we don't have a focus state
912 * for we'll reset the keyboard focus to NULL */
913 wl_list_for_each_safe(seat, next_seat, &pending_seat_list, link) {
914 wl_list_insert(&shell->compositor->seat_list, &seat->link);
915
Ander Conselvan de Oliveira6e56ab42014-05-07 11:57:28 +0300916 if (seat->keyboard == NULL)
Neil Roberts4237f502014-04-09 16:33:31 +0100917 continue;
918
919 weston_keyboard_set_focus(seat->keyboard, NULL);
920 }
Jonas Ådahl04769742012-06-13 00:01:24 +0200921}
922
923static void
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200924replace_focus_state(struct desktop_shell *shell, struct workspace *ws,
925 struct weston_seat *seat)
926{
927 struct focus_state *state;
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200928
929 wl_list_for_each(state, &ws->focus_list, link) {
930 if (state->seat == seat) {
Kristian Høgsbergd500bf12014-01-22 12:25:20 -0800931 focus_state_set_focus(state, seat->keyboard->focus);
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200932 return;
933 }
934 }
935}
936
937static void
938drop_focus_state(struct desktop_shell *shell, struct workspace *ws,
939 struct weston_surface *surface)
940{
941 struct focus_state *state;
942
943 wl_list_for_each(state, &ws->focus_list, link)
944 if (state->keyboard_focus == surface)
Kristian Høgsbergd500bf12014-01-22 12:25:20 -0800945 focus_state_set_focus(state, NULL);
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200946}
947
948static void
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100949animate_focus_change(struct desktop_shell *shell, struct workspace *ws,
950 struct weston_view *from, struct weston_view *to)
951{
952 struct weston_output *output;
953 bool focus_surface_created = false;
954
955 /* FIXME: Only support dim animation using two layers */
956 if (from == to || shell->focus_animation_type != ANIMATION_DIM_LAYER)
957 return;
958
959 output = get_default_output(shell->compositor);
960 if (ws->fsurf_front == NULL && (from || to)) {
961 ws->fsurf_front = create_focus_surface(shell->compositor, output);
U. Artie Eoff0b23b2b2014-01-15 14:45:59 -0800962 if (ws->fsurf_front == NULL)
963 return;
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100964 ws->fsurf_front->view->alpha = 0.0;
U. Artie Eoff0b23b2b2014-01-15 14:45:59 -0800965
966 ws->fsurf_back = create_focus_surface(shell->compositor, output);
967 if (ws->fsurf_back == NULL) {
968 focus_surface_destroy(ws->fsurf_front);
969 return;
970 }
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100971 ws->fsurf_back->view->alpha = 0.0;
U. Artie Eoff0b23b2b2014-01-15 14:45:59 -0800972
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100973 focus_surface_created = true;
974 } else {
Giulio Camuffo412e6a52014-07-09 22:12:56 +0300975 weston_layer_entry_remove(&ws->fsurf_front->view->layer_link);
976 weston_layer_entry_remove(&ws->fsurf_back->view->layer_link);
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100977 }
978
979 if (ws->focus_animation) {
980 weston_view_animation_destroy(ws->focus_animation);
981 ws->focus_animation = NULL;
982 }
983
984 if (to)
Giulio Camuffo412e6a52014-07-09 22:12:56 +0300985 weston_layer_entry_insert(&to->layer_link,
986 &ws->fsurf_front->view->layer_link);
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100987 else if (from)
Giulio Camuffo412e6a52014-07-09 22:12:56 +0300988 weston_layer_entry_insert(&ws->layer.view_list,
989 &ws->fsurf_front->view->layer_link);
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100990
991 if (focus_surface_created) {
992 ws->focus_animation = weston_fade_run(
993 ws->fsurf_front->view,
Jonny Lamb7e7d4852014-05-22 22:41:34 +0200994 ws->fsurf_front->view->alpha, 0.4, 300,
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100995 focus_animation_done, ws);
996 } else if (from) {
Giulio Camuffo412e6a52014-07-09 22:12:56 +0300997 weston_layer_entry_insert(&from->layer_link,
998 &ws->fsurf_back->view->layer_link);
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100999 ws->focus_animation = weston_stable_fade_run(
1000 ws->fsurf_front->view, 0.0,
Jonny Lamb7e7d4852014-05-22 22:41:34 +02001001 ws->fsurf_back->view, 0.4,
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01001002 focus_animation_done, ws);
1003 } else if (to) {
Giulio Camuffo412e6a52014-07-09 22:12:56 +03001004 weston_layer_entry_insert(&ws->layer.view_list,
1005 &ws->fsurf_back->view->layer_link);
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01001006 ws->focus_animation = weston_stable_fade_run(
1007 ws->fsurf_front->view, 0.0,
Jonny Lamb7e7d4852014-05-22 22:41:34 +02001008 ws->fsurf_back->view, 0.4,
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01001009 focus_animation_done, ws);
1010 }
1011}
1012
1013static void
Jonas Ådahle3cddce2012-06-13 00:01:22 +02001014workspace_destroy(struct workspace *ws)
1015{
Jonas Ådahl04769742012-06-13 00:01:24 +02001016 struct focus_state *state, *next;
1017
1018 wl_list_for_each_safe(state, next, &ws->focus_list, link)
1019 focus_state_destroy(state);
1020
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01001021 if (ws->fsurf_front)
1022 focus_surface_destroy(ws->fsurf_front);
1023 if (ws->fsurf_back)
1024 focus_surface_destroy(ws->fsurf_back);
1025
Jonas Ådahle3cddce2012-06-13 00:01:22 +02001026 free(ws);
1027}
1028
Jonas Ådahl04769742012-06-13 00:01:24 +02001029static void
1030seat_destroyed(struct wl_listener *listener, void *data)
1031{
1032 struct weston_seat *seat = data;
1033 struct focus_state *state, *next;
1034 struct workspace *ws = container_of(listener,
1035 struct workspace,
1036 seat_destroyed_listener);
1037
1038 wl_list_for_each_safe(state, next, &ws->focus_list, link)
1039 if (state->seat == seat)
1040 wl_list_remove(&state->link);
1041}
1042
Jonas Ådahle3cddce2012-06-13 00:01:22 +02001043static struct workspace *
1044workspace_create(void)
1045{
1046 struct workspace *ws = malloc(sizeof *ws);
1047 if (ws == NULL)
1048 return NULL;
1049
1050 weston_layer_init(&ws->layer, NULL);
1051
Jonas Ådahl04769742012-06-13 00:01:24 +02001052 wl_list_init(&ws->focus_list);
1053 wl_list_init(&ws->seat_destroyed_listener.link);
1054 ws->seat_destroyed_listener.notify = seat_destroyed;
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01001055 ws->fsurf_front = NULL;
1056 ws->fsurf_back = NULL;
1057 ws->focus_animation = NULL;
Jonas Ådahl04769742012-06-13 00:01:24 +02001058
Jonas Ådahle3cddce2012-06-13 00:01:22 +02001059 return ws;
1060}
1061
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001062static int
1063workspace_is_empty(struct workspace *ws)
1064{
Giulio Camuffo412e6a52014-07-09 22:12:56 +03001065 return wl_list_empty(&ws->layer.view_list.link);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001066}
1067
Jonas Ådahle3cddce2012-06-13 00:01:22 +02001068static struct workspace *
1069get_workspace(struct desktop_shell *shell, unsigned int index)
1070{
1071 struct workspace **pws = shell->workspaces.array.data;
Philipp Brüschweiler067abf62012-09-01 16:03:05 +02001072 assert(index < shell->workspaces.num);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02001073 pws += index;
1074 return *pws;
1075}
1076
Kristian Høgsberg1ef23132013-12-04 00:20:01 -08001077struct workspace *
Jonas Ådahle3cddce2012-06-13 00:01:22 +02001078get_current_workspace(struct desktop_shell *shell)
1079{
1080 return get_workspace(shell, shell->workspaces.current);
1081}
1082
1083static void
1084activate_workspace(struct desktop_shell *shell, unsigned int index)
1085{
1086 struct workspace *ws;
1087
1088 ws = get_workspace(shell, index);
1089 wl_list_insert(&shell->panel_layer.link, &ws->layer.link);
1090
1091 shell->workspaces.current = index;
1092}
1093
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001094static unsigned int
1095get_output_height(struct weston_output *output)
1096{
1097 return abs(output->region.extents.y1 - output->region.extents.y2);
1098}
1099
1100static void
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01001101view_translate(struct workspace *ws, struct weston_view *view, double d)
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001102{
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001103 struct weston_transform *transform;
1104
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01001105 if (is_focus_view(view)) {
1106 struct focus_surface *fsurf = get_focus_surface(view->surface);
1107 transform = &fsurf->workspace_transform;
1108 } else {
1109 struct shell_surface *shsurf = get_shell_surface(view->surface);
1110 transform = &shsurf->workspace_transform;
1111 }
1112
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001113 if (wl_list_empty(&transform->link))
Jason Ekstranda7af7042013-10-12 22:38:11 -05001114 wl_list_insert(view->geometry.transformation_list.prev,
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01001115 &transform->link);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001116
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01001117 weston_matrix_init(&transform->matrix);
1118 weston_matrix_translate(&transform->matrix,
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001119 0.0, d, 0.0);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001120 weston_view_geometry_dirty(view);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001121}
1122
1123static void
1124workspace_translate_out(struct workspace *ws, double fraction)
1125{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001126 struct weston_view *view;
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001127 unsigned int height;
1128 double d;
1129
Giulio Camuffo412e6a52014-07-09 22:12:56 +03001130 wl_list_for_each(view, &ws->layer.view_list.link, layer_link.link) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001131 height = get_output_height(view->surface->output);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001132 d = height * fraction;
1133
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01001134 view_translate(ws, view, d);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001135 }
1136}
1137
1138static void
1139workspace_translate_in(struct workspace *ws, double fraction)
1140{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001141 struct weston_view *view;
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001142 unsigned int height;
1143 double d;
1144
Giulio Camuffo412e6a52014-07-09 22:12:56 +03001145 wl_list_for_each(view, &ws->layer.view_list.link, layer_link.link) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001146 height = get_output_height(view->surface->output);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001147
1148 if (fraction > 0)
1149 d = -(height - height * fraction);
1150 else
1151 d = height + height * fraction;
1152
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01001153 view_translate(ws, view, d);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001154 }
1155}
1156
1157static void
Jonas Ådahle9d22502012-08-29 22:13:01 +02001158broadcast_current_workspace_state(struct desktop_shell *shell)
1159{
Kristian Høgsberg2e3c3962013-09-11 12:00:47 -07001160 struct wl_resource *resource;
Jonas Ådahle9d22502012-08-29 22:13:01 +02001161
Kristian Høgsberg2e3c3962013-09-11 12:00:47 -07001162 wl_resource_for_each(resource, &shell->workspaces.client_list)
1163 workspace_manager_send_state(resource,
Jonas Ådahle9d22502012-08-29 22:13:01 +02001164 shell->workspaces.current,
1165 shell->workspaces.num);
1166}
1167
1168static void
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001169reverse_workspace_change_animation(struct desktop_shell *shell,
1170 unsigned int index,
1171 struct workspace *from,
1172 struct workspace *to)
1173{
1174 shell->workspaces.current = index;
1175
1176 shell->workspaces.anim_to = to;
1177 shell->workspaces.anim_from = from;
1178 shell->workspaces.anim_dir = -1 * shell->workspaces.anim_dir;
1179 shell->workspaces.anim_timestamp = 0;
1180
Scott Moreau4272e632012-08-13 09:58:41 -06001181 weston_compositor_schedule_repaint(shell->compositor);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001182}
1183
1184static void
1185workspace_deactivate_transforms(struct workspace *ws)
1186{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001187 struct weston_view *view;
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01001188 struct weston_transform *transform;
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001189
Giulio Camuffo412e6a52014-07-09 22:12:56 +03001190 wl_list_for_each(view, &ws->layer.view_list.link, layer_link.link) {
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01001191 if (is_focus_view(view)) {
1192 struct focus_surface *fsurf = get_focus_surface(view->surface);
1193 transform = &fsurf->workspace_transform;
1194 } else {
1195 struct shell_surface *shsurf = get_shell_surface(view->surface);
1196 transform = &shsurf->workspace_transform;
1197 }
1198
1199 if (!wl_list_empty(&transform->link)) {
1200 wl_list_remove(&transform->link);
1201 wl_list_init(&transform->link);
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001202 }
Jason Ekstranda7af7042013-10-12 22:38:11 -05001203 weston_view_geometry_dirty(view);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001204 }
1205}
1206
1207static void
1208finish_workspace_change_animation(struct desktop_shell *shell,
1209 struct workspace *from,
1210 struct workspace *to)
1211{
Ander Conselvan de Oliveira9c6217e2014-05-07 11:57:26 +03001212 struct weston_view *view;
1213
Scott Moreau4272e632012-08-13 09:58:41 -06001214 weston_compositor_schedule_repaint(shell->compositor);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001215
Ander Conselvan de Oliveira9c6217e2014-05-07 11:57:26 +03001216 /* Views that extend past the bottom of the output are still
1217 * visible after the workspace animation ends but before its layer
1218 * is hidden. In that case, we need to damage below those views so
1219 * that the screen is properly repainted. */
Giulio Camuffo412e6a52014-07-09 22:12:56 +03001220 wl_list_for_each(view, &from->layer.view_list.link, layer_link.link)
Ander Conselvan de Oliveira9c6217e2014-05-07 11:57:26 +03001221 weston_view_damage_below(view);
1222
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001223 wl_list_remove(&shell->workspaces.animation.link);
1224 workspace_deactivate_transforms(from);
1225 workspace_deactivate_transforms(to);
1226 shell->workspaces.anim_to = NULL;
1227
1228 wl_list_remove(&shell->workspaces.anim_from->layer.link);
1229}
1230
1231static void
1232animate_workspace_change_frame(struct weston_animation *animation,
1233 struct weston_output *output, uint32_t msecs)
1234{
1235 struct desktop_shell *shell =
1236 container_of(animation, struct desktop_shell,
1237 workspaces.animation);
1238 struct workspace *from = shell->workspaces.anim_from;
1239 struct workspace *to = shell->workspaces.anim_to;
1240 uint32_t t;
1241 double x, y;
1242
1243 if (workspace_is_empty(from) && workspace_is_empty(to)) {
1244 finish_workspace_change_animation(shell, from, to);
1245 return;
1246 }
1247
1248 if (shell->workspaces.anim_timestamp == 0) {
1249 if (shell->workspaces.anim_current == 0.0)
1250 shell->workspaces.anim_timestamp = msecs;
1251 else
1252 shell->workspaces.anim_timestamp =
1253 msecs -
1254 /* Invers of movement function 'y' below. */
1255 (asin(1.0 - shell->workspaces.anim_current) *
1256 DEFAULT_WORKSPACE_CHANGE_ANIMATION_LENGTH *
1257 M_2_PI);
1258 }
1259
1260 t = msecs - shell->workspaces.anim_timestamp;
1261
1262 /*
1263 * x = [0, π/2]
1264 * y(x) = sin(x)
1265 */
1266 x = t * (1.0/DEFAULT_WORKSPACE_CHANGE_ANIMATION_LENGTH) * M_PI_2;
1267 y = sin(x);
1268
1269 if (t < DEFAULT_WORKSPACE_CHANGE_ANIMATION_LENGTH) {
Scott Moreau4272e632012-08-13 09:58:41 -06001270 weston_compositor_schedule_repaint(shell->compositor);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001271
1272 workspace_translate_out(from, shell->workspaces.anim_dir * y);
1273 workspace_translate_in(to, shell->workspaces.anim_dir * y);
1274 shell->workspaces.anim_current = y;
1275
Scott Moreau4272e632012-08-13 09:58:41 -06001276 weston_compositor_schedule_repaint(shell->compositor);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001277 }
Jonas Ådahl04769742012-06-13 00:01:24 +02001278 else
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001279 finish_workspace_change_animation(shell, from, to);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001280}
1281
1282static void
1283animate_workspace_change(struct desktop_shell *shell,
1284 unsigned int index,
1285 struct workspace *from,
1286 struct workspace *to)
1287{
1288 struct weston_output *output;
1289
1290 int dir;
1291
1292 if (index > shell->workspaces.current)
1293 dir = -1;
1294 else
1295 dir = 1;
1296
1297 shell->workspaces.current = index;
1298
1299 shell->workspaces.anim_dir = dir;
1300 shell->workspaces.anim_from = from;
1301 shell->workspaces.anim_to = to;
1302 shell->workspaces.anim_current = 0.0;
1303 shell->workspaces.anim_timestamp = 0;
1304
1305 output = container_of(shell->compositor->output_list.next,
1306 struct weston_output, link);
1307 wl_list_insert(&output->animation_list,
1308 &shell->workspaces.animation.link);
1309
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001310 wl_list_insert(from->layer.link.prev, &to->layer.link);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001311
1312 workspace_translate_in(to, 0);
1313
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -04001314 restore_focus_state(shell, to);
Jonas Ådahl04769742012-06-13 00:01:24 +02001315
Scott Moreau4272e632012-08-13 09:58:41 -06001316 weston_compositor_schedule_repaint(shell->compositor);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001317}
1318
Jonas Ådahle3cddce2012-06-13 00:01:22 +02001319static void
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001320update_workspace(struct desktop_shell *shell, unsigned int index,
1321 struct workspace *from, struct workspace *to)
1322{
1323 shell->workspaces.current = index;
1324 wl_list_insert(&from->layer.link, &to->layer.link);
1325 wl_list_remove(&from->layer.link);
1326}
1327
1328static void
Jonas Ådahle3cddce2012-06-13 00:01:22 +02001329change_workspace(struct desktop_shell *shell, unsigned int index)
1330{
1331 struct workspace *from;
1332 struct workspace *to;
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01001333 struct focus_state *state;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02001334
1335 if (index == shell->workspaces.current)
1336 return;
1337
1338 /* Don't change workspace when there is any fullscreen surfaces. */
Giulio Camuffo412e6a52014-07-09 22:12:56 +03001339 if (!wl_list_empty(&shell->fullscreen_layer.view_list.link))
Jonas Ådahle3cddce2012-06-13 00:01:22 +02001340 return;
1341
Jonas Ådahle3cddce2012-06-13 00:01:22 +02001342 from = get_current_workspace(shell);
1343 to = get_workspace(shell, index);
1344
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001345 if (shell->workspaces.anim_from == to &&
1346 shell->workspaces.anim_to == from) {
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001347 restore_focus_state(shell, to);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001348 reverse_workspace_change_animation(shell, index, from, to);
Jonas Ådahle9d22502012-08-29 22:13:01 +02001349 broadcast_current_workspace_state(shell);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001350 return;
1351 }
Jonas Ådahle3cddce2012-06-13 00:01:22 +02001352
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001353 if (shell->workspaces.anim_to != NULL)
1354 finish_workspace_change_animation(shell,
1355 shell->workspaces.anim_from,
1356 shell->workspaces.anim_to);
1357
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001358 restore_focus_state(shell, to);
Jonas Ådahl04769742012-06-13 00:01:24 +02001359
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01001360 if (shell->focus_animation_type != ANIMATION_NONE) {
1361 wl_list_for_each(state, &from->focus_list, link)
1362 if (state->keyboard_focus)
1363 animate_focus_change(shell, from,
1364 get_default_view(state->keyboard_focus), NULL);
1365
1366 wl_list_for_each(state, &to->focus_list, link)
1367 if (state->keyboard_focus)
1368 animate_focus_change(shell, to,
1369 NULL, get_default_view(state->keyboard_focus));
1370 }
1371
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001372 if (workspace_is_empty(to) && workspace_is_empty(from))
1373 update_workspace(shell, index, from, to);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001374 else
1375 animate_workspace_change(shell, index, from, to);
Jonas Ådahle9d22502012-08-29 22:13:01 +02001376
1377 broadcast_current_workspace_state(shell);
Pekka Paalanene955f1e2011-12-07 11:49:52 +02001378}
1379
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001380static bool
1381workspace_has_only(struct workspace *ws, struct weston_surface *surface)
1382{
Giulio Camuffo412e6a52014-07-09 22:12:56 +03001383 struct wl_list *list = &ws->layer.view_list.link;
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001384 struct wl_list *e;
1385
1386 if (wl_list_empty(list))
1387 return false;
1388
1389 e = list->next;
1390
1391 if (e->next != list)
1392 return false;
1393
Giulio Camuffo412e6a52014-07-09 22:12:56 +03001394 return container_of(e, struct weston_view, layer_link.link)->surface == surface;
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001395}
1396
1397static void
Philip Withnall659163d2013-11-25 18:01:36 +00001398move_surface_to_workspace(struct desktop_shell *shell,
1399 struct shell_surface *shsurf,
1400 uint32_t workspace)
Jonas Ådahle9d22502012-08-29 22:13:01 +02001401{
1402 struct workspace *from;
1403 struct workspace *to;
1404 struct weston_seat *seat;
Pekka Paalanen01388e22013-04-25 13:57:44 +03001405 struct weston_surface *focus;
Philip Withnall659163d2013-11-25 18:01:36 +00001406 struct weston_view *view;
Jonas Ådahle9d22502012-08-29 22:13:01 +02001407
1408 if (workspace == shell->workspaces.current)
1409 return;
1410
Philip Withnall659163d2013-11-25 18:01:36 +00001411 view = get_default_view(shsurf->surface);
1412 if (!view)
1413 return;
1414
1415 assert(weston_surface_get_main_surface(view->surface) == view->surface);
1416
Philipp Brüschweiler067abf62012-09-01 16:03:05 +02001417 if (workspace >= shell->workspaces.num)
1418 workspace = shell->workspaces.num - 1;
1419
Jonas Ådahle9d22502012-08-29 22:13:01 +02001420 from = get_current_workspace(shell);
1421 to = get_workspace(shell, workspace);
1422
Giulio Camuffo412e6a52014-07-09 22:12:56 +03001423 weston_layer_entry_remove(&view->layer_link);
1424 weston_layer_entry_insert(&to->layer.view_list, &view->layer_link);
Jonas Ådahle9d22502012-08-29 22:13:01 +02001425
Philip Withnall648a4dd2013-11-25 18:01:44 +00001426 shell_surface_update_child_surface_layers(shsurf);
1427
Jason Ekstranda7af7042013-10-12 22:38:11 -05001428 drop_focus_state(shell, from, view->surface);
Pekka Paalanen01388e22013-04-25 13:57:44 +03001429 wl_list_for_each(seat, &shell->compositor->seat_list, link) {
1430 if (!seat->keyboard)
1431 continue;
1432
1433 focus = weston_surface_get_main_surface(seat->keyboard->focus);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001434 if (focus == view->surface)
Kristian Høgsberge3148752013-05-06 23:19:49 -04001435 weston_keyboard_set_focus(seat->keyboard, NULL);
Pekka Paalanen01388e22013-04-25 13:57:44 +03001436 }
Jonas Ådahle9d22502012-08-29 22:13:01 +02001437
Jason Ekstranda7af7042013-10-12 22:38:11 -05001438 weston_view_damage_below(view);
Jonas Ådahle9d22502012-08-29 22:13:01 +02001439}
1440
1441static void
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001442take_surface_to_workspace_by_seat(struct desktop_shell *shell,
Kristian Høgsberge3148752013-05-06 23:19:49 -04001443 struct weston_seat *seat,
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001444 unsigned int index)
1445{
Pekka Paalanen01388e22013-04-25 13:57:44 +03001446 struct weston_surface *surface;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001447 struct weston_view *view;
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001448 struct shell_surface *shsurf;
1449 struct workspace *from;
1450 struct workspace *to;
Jonas Ådahl8538b222012-08-29 22:13:03 +02001451 struct focus_state *state;
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001452
Pekka Paalanen01388e22013-04-25 13:57:44 +03001453 surface = weston_surface_get_main_surface(seat->keyboard->focus);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001454 view = get_default_view(surface);
1455 if (view == NULL ||
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01001456 index == shell->workspaces.current ||
1457 is_focus_view(view))
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001458 return;
1459
1460 from = get_current_workspace(shell);
1461 to = get_workspace(shell, index);
1462
Giulio Camuffo412e6a52014-07-09 22:12:56 +03001463 weston_layer_entry_remove(&view->layer_link);
1464 weston_layer_entry_insert(&to->layer.view_list, &view->layer_link);
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001465
Philip Withnall659163d2013-11-25 18:01:36 +00001466 shsurf = get_shell_surface(surface);
Philip Withnall648a4dd2013-11-25 18:01:44 +00001467 if (shsurf != NULL)
1468 shell_surface_update_child_surface_layers(shsurf);
Philip Withnall659163d2013-11-25 18:01:36 +00001469
Jonas Ådahle9d22502012-08-29 22:13:01 +02001470 replace_focus_state(shell, to, seat);
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001471 drop_focus_state(shell, from, surface);
1472
1473 if (shell->workspaces.anim_from == to &&
1474 shell->workspaces.anim_to == from) {
Jonas Ådahle9d22502012-08-29 22:13:01 +02001475 wl_list_remove(&to->layer.link);
1476 wl_list_insert(from->layer.link.prev, &to->layer.link);
1477
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001478 reverse_workspace_change_animation(shell, index, from, to);
Jonas Ådahle9d22502012-08-29 22:13:01 +02001479 broadcast_current_workspace_state(shell);
1480
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001481 return;
1482 }
1483
1484 if (shell->workspaces.anim_to != NULL)
1485 finish_workspace_change_animation(shell,
1486 shell->workspaces.anim_from,
1487 shell->workspaces.anim_to);
1488
1489 if (workspace_is_empty(from) &&
1490 workspace_has_only(to, surface))
1491 update_workspace(shell, index, from, to);
1492 else {
Philip Withnall2c3849b2013-11-25 18:01:45 +00001493 if (shsurf != NULL &&
1494 wl_list_empty(&shsurf->workspace_transform.link))
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001495 wl_list_insert(&shell->workspaces.anim_sticky_list,
1496 &shsurf->workspace_transform.link);
1497
1498 animate_workspace_change(shell, index, from, to);
1499 }
Jonas Ådahle9d22502012-08-29 22:13:01 +02001500
1501 broadcast_current_workspace_state(shell);
Jonas Ådahl8538b222012-08-29 22:13:03 +02001502
1503 state = ensure_focus_state(shell, seat);
1504 if (state != NULL)
Kristian Høgsbergd500bf12014-01-22 12:25:20 -08001505 focus_state_set_focus(state, surface);
Jonas Ådahle9d22502012-08-29 22:13:01 +02001506}
1507
1508static void
1509workspace_manager_move_surface(struct wl_client *client,
1510 struct wl_resource *resource,
1511 struct wl_resource *surface_resource,
1512 uint32_t workspace)
1513{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05001514 struct desktop_shell *shell = wl_resource_get_user_data(resource);
Jonas Ådahle9d22502012-08-29 22:13:01 +02001515 struct weston_surface *surface =
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05001516 wl_resource_get_user_data(surface_resource);
Pekka Paalanen01388e22013-04-25 13:57:44 +03001517 struct weston_surface *main_surface;
Philip Withnall659163d2013-11-25 18:01:36 +00001518 struct shell_surface *shell_surface;
Jonas Ådahle9d22502012-08-29 22:13:01 +02001519
Pekka Paalanen01388e22013-04-25 13:57:44 +03001520 main_surface = weston_surface_get_main_surface(surface);
Philip Withnall659163d2013-11-25 18:01:36 +00001521 shell_surface = get_shell_surface(main_surface);
1522 if (shell_surface == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001523 return;
Philip Withnall659163d2013-11-25 18:01:36 +00001524
1525 move_surface_to_workspace(shell, shell_surface, workspace);
Jonas Ådahle9d22502012-08-29 22:13:01 +02001526}
1527
1528static const struct workspace_manager_interface workspace_manager_implementation = {
1529 workspace_manager_move_surface,
1530};
1531
1532static void
1533unbind_resource(struct wl_resource *resource)
1534{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05001535 wl_list_remove(wl_resource_get_link(resource));
Jonas Ådahle9d22502012-08-29 22:13:01 +02001536}
1537
1538static void
1539bind_workspace_manager(struct wl_client *client,
1540 void *data, uint32_t version, uint32_t id)
1541{
1542 struct desktop_shell *shell = data;
1543 struct wl_resource *resource;
1544
Jason Ekstranda85118c2013-06-27 20:17:02 -05001545 resource = wl_resource_create(client,
1546 &workspace_manager_interface, 1, id);
Jonas Ådahle9d22502012-08-29 22:13:01 +02001547
1548 if (resource == NULL) {
1549 weston_log("couldn't add workspace manager object");
1550 return;
1551 }
1552
Jason Ekstranda85118c2013-06-27 20:17:02 -05001553 wl_resource_set_implementation(resource,
1554 &workspace_manager_implementation,
1555 shell, unbind_resource);
Jason Ekstrand651f00e2013-06-14 10:07:54 -05001556 wl_list_insert(&shell->workspaces.client_list,
1557 wl_resource_get_link(resource));
Jonas Ådahle9d22502012-08-29 22:13:01 +02001558
1559 workspace_manager_send_state(resource,
1560 shell->workspaces.current,
1561 shell->workspaces.num);
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001562}
1563
Pekka Paalanen56cdea92011-11-23 16:14:12 +02001564static void
Rusty Lynch1084da52013-08-15 09:10:08 -07001565touch_move_grab_down(struct weston_touch_grab *grab, uint32_t time,
1566 int touch_id, wl_fixed_t sx, wl_fixed_t sy)
1567{
1568}
1569
1570static void
1571touch_move_grab_up(struct weston_touch_grab *grab, uint32_t time, int touch_id)
1572{
Jonas Ådahl1c6e63e2013-10-25 23:18:04 +02001573 struct weston_touch_move_grab *move =
1574 (struct weston_touch_move_grab *) container_of(
1575 grab, struct shell_touch_grab, grab);
Neil Robertse14aa4f2013-10-03 16:43:07 +01001576
Kristian Høgsberg8e80a312014-01-17 15:18:10 -08001577 if (touch_id == 0)
1578 move->active = 0;
1579
Jonas Ådahl9484b692013-12-02 22:05:03 +01001580 if (grab->touch->num_tp == 0) {
Jonas Ådahl1c6e63e2013-10-25 23:18:04 +02001581 shell_touch_grab_end(&move->base);
1582 free(move);
1583 }
Rusty Lynch1084da52013-08-15 09:10:08 -07001584}
1585
1586static void
1587touch_move_grab_motion(struct weston_touch_grab *grab, uint32_t time,
1588 int touch_id, wl_fixed_t sx, wl_fixed_t sy)
1589{
1590 struct weston_touch_move_grab *move = (struct weston_touch_move_grab *) grab;
1591 struct shell_surface *shsurf = move->base.shsurf;
1592 struct weston_surface *es;
1593 int dx = wl_fixed_to_int(grab->touch->grab_x + move->dx);
1594 int dy = wl_fixed_to_int(grab->touch->grab_y + move->dy);
1595
Kristian Høgsberg8e80a312014-01-17 15:18:10 -08001596 if (!shsurf || !move->active)
Rusty Lynch1084da52013-08-15 09:10:08 -07001597 return;
1598
1599 es = shsurf->surface;
1600
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001601 weston_view_set_position(shsurf->view, dx, dy);
Rusty Lynch1084da52013-08-15 09:10:08 -07001602
1603 weston_compositor_schedule_repaint(es->compositor);
1604}
1605
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02001606static void
Jonas Ådahl1679f232014-04-12 09:39:51 +02001607touch_move_grab_frame(struct weston_touch_grab *grab)
1608{
1609}
1610
1611static void
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02001612touch_move_grab_cancel(struct weston_touch_grab *grab)
1613{
1614 struct weston_touch_move_grab *move =
1615 (struct weston_touch_move_grab *) container_of(
1616 grab, struct shell_touch_grab, grab);
1617
1618 shell_touch_grab_end(&move->base);
1619 free(move);
1620}
1621
Rusty Lynch1084da52013-08-15 09:10:08 -07001622static const struct weston_touch_grab_interface touch_move_grab_interface = {
1623 touch_move_grab_down,
1624 touch_move_grab_up,
1625 touch_move_grab_motion,
Jonas Ådahl1679f232014-04-12 09:39:51 +02001626 touch_move_grab_frame,
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02001627 touch_move_grab_cancel,
Rusty Lynch1084da52013-08-15 09:10:08 -07001628};
1629
1630static int
1631surface_touch_move(struct shell_surface *shsurf, struct weston_seat *seat)
1632{
1633 struct weston_touch_move_grab *move;
1634
1635 if (!shsurf)
1636 return -1;
1637
Ander Conselvan de Oliveira6d43f042014-05-07 14:22:23 +03001638 if (shsurf->state.fullscreen || shsurf->state.maximized)
Rusty Lynch1084da52013-08-15 09:10:08 -07001639 return 0;
1640
1641 move = malloc(sizeof *move);
1642 if (!move)
1643 return -1;
1644
Kristian Høgsberg8e80a312014-01-17 15:18:10 -08001645 move->active = 1;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001646 move->dx = wl_fixed_from_double(shsurf->view->geometry.x) -
Rusty Lynch1084da52013-08-15 09:10:08 -07001647 seat->touch->grab_x;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001648 move->dy = wl_fixed_from_double(shsurf->view->geometry.y) -
Rusty Lynch1084da52013-08-15 09:10:08 -07001649 seat->touch->grab_y;
1650
1651 shell_touch_grab_start(&move->base, &touch_move_grab_interface, shsurf,
1652 seat->touch);
1653
1654 return 0;
1655}
1656
1657static void
Kristian Høgsberg6848c252013-05-08 22:02:59 -04001658noop_grab_focus(struct weston_pointer_grab *grab)
Kristian Høgsberg9ddb8262012-01-04 21:30:29 -05001659{
Kristian Høgsberg9ddb8262012-01-04 21:30:29 -05001660}
1661
1662static void
Kristian Høgsbergae356ae2014-04-29 16:03:54 -07001663constrain_position(struct weston_move_grab *move, int *cx, int *cy)
1664{
1665 struct shell_surface *shsurf = move->base.shsurf;
1666 struct weston_pointer *pointer = move->base.grab.pointer;
Jonny Lambd73c6942014-08-20 15:53:20 +02001667 int x, y, panel_width, panel_height, bottom;
Kristian Høgsbergae356ae2014-04-29 16:03:54 -07001668 const int safety = 50;
1669
1670 x = wl_fixed_to_int(pointer->x + move->dx);
1671 y = wl_fixed_to_int(pointer->y + move->dy);
1672
Jonny Lambd73c6942014-08-20 15:53:20 +02001673 if (shsurf->shell->panel_position == DESKTOP_SHELL_PANEL_POSITION_TOP) {
1674 get_output_panel_size(shsurf->shell, shsurf->surface->output,
1675 &panel_width, &panel_height);
Kristian Høgsbergae356ae2014-04-29 16:03:54 -07001676
Jonny Lambd73c6942014-08-20 15:53:20 +02001677 bottom = y + shsurf->geometry.height;
1678 if (bottom - panel_height < safety)
1679 y = panel_height + safety -
1680 shsurf->geometry.height;
1681
1682 if (move->client_initiated &&
1683 y + shsurf->geometry.y < panel_height)
1684 y = panel_height - shsurf->geometry.y;
1685 }
Kristian Høgsbergae356ae2014-04-29 16:03:54 -07001686
1687 *cx = x;
1688 *cy = y;
1689}
1690
1691static void
Giulio Camuffo1959ab82013-11-14 23:42:52 +01001692move_grab_motion(struct weston_pointer_grab *grab, uint32_t time,
1693 wl_fixed_t x, wl_fixed_t y)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001694{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001695 struct weston_move_grab *move = (struct weston_move_grab *) grab;
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001696 struct weston_pointer *pointer = grab->pointer;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03001697 struct shell_surface *shsurf = move->base.shsurf;
Kristian Høgsbergae356ae2014-04-29 16:03:54 -07001698 int cx, cy;
Giulio Camuffo1959ab82013-11-14 23:42:52 +01001699
1700 weston_pointer_move(pointer, x, y);
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03001701 if (!shsurf)
1702 return;
1703
Kristian Høgsbergae356ae2014-04-29 16:03:54 -07001704 constrain_position(move, &cx, &cy);
1705
1706 weston_view_set_position(shsurf->view, cx, cy);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001707
Jason Ekstranda7af7042013-10-12 22:38:11 -05001708 weston_compositor_schedule_repaint(shsurf->surface->compositor);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001709}
1710
1711static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001712move_grab_button(struct weston_pointer_grab *grab,
Daniel Stone4dbadb12012-05-30 16:31:51 +01001713 uint32_t time, uint32_t button, uint32_t state_w)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001714{
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03001715 struct shell_grab *shell_grab = container_of(grab, struct shell_grab,
1716 grab);
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001717 struct weston_pointer *pointer = grab->pointer;
Daniel Stone4dbadb12012-05-30 16:31:51 +01001718 enum wl_pointer_button_state state = state_w;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001719
Daniel Stone4dbadb12012-05-30 16:31:51 +01001720 if (pointer->button_count == 0 &&
1721 state == WL_POINTER_BUTTON_STATE_RELEASED) {
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001722 shell_grab_end(shell_grab);
Kristian Høgsberg9ddb8262012-01-04 21:30:29 -05001723 free(grab);
1724 }
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001725}
1726
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02001727static void
1728move_grab_cancel(struct weston_pointer_grab *grab)
1729{
1730 struct shell_grab *shell_grab =
1731 container_of(grab, struct shell_grab, grab);
1732
1733 shell_grab_end(shell_grab);
1734 free(grab);
1735}
1736
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001737static const struct weston_pointer_grab_interface move_grab_interface = {
Kristian Høgsberg9ddb8262012-01-04 21:30:29 -05001738 noop_grab_focus,
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001739 move_grab_motion,
1740 move_grab_button,
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02001741 move_grab_cancel,
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001742};
1743
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001744static int
Kristian Høgsbergae356ae2014-04-29 16:03:54 -07001745surface_move(struct shell_surface *shsurf, struct weston_seat *seat,
1746 int client_initiated)
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001747{
1748 struct weston_move_grab *move;
1749
1750 if (!shsurf)
1751 return -1;
1752
Kristian Høgsberga4b620e2014-04-30 16:05:49 -07001753 if (shsurf->grabbed ||
1754 shsurf->state.fullscreen || shsurf->state.maximized)
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001755 return 0;
1756
1757 move = malloc(sizeof *move);
1758 if (!move)
1759 return -1;
1760
Jason Ekstranda7af7042013-10-12 22:38:11 -05001761 move->dx = wl_fixed_from_double(shsurf->view->geometry.x) -
Kristian Høgsberge3148752013-05-06 23:19:49 -04001762 seat->pointer->grab_x;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001763 move->dy = wl_fixed_from_double(shsurf->view->geometry.y) -
Kristian Høgsberge3148752013-05-06 23:19:49 -04001764 seat->pointer->grab_y;
Kristian Høgsbergae356ae2014-04-29 16:03:54 -07001765 move->client_initiated = client_initiated;
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001766
1767 shell_grab_start(&move->base, &move_grab_interface, shsurf,
Kristian Høgsberge3148752013-05-06 23:19:49 -04001768 seat->pointer, DESKTOP_SHELL_CURSOR_MOVE);
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001769
1770 return 0;
1771}
1772
1773static void
Rafael Antognollie2a34552013-12-03 15:35:45 -02001774common_surface_move(struct wl_resource *resource,
1775 struct wl_resource *seat_resource, uint32_t serial)
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001776{
Jason Ekstrand44a38632013-06-14 10:08:00 -05001777 struct weston_seat *seat = wl_resource_get_user_data(seat_resource);
Jason Ekstrand651f00e2013-06-14 10:07:54 -05001778 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
Giulio Camuffo61da3fc2013-04-25 13:57:45 +03001779 struct weston_surface *surface;
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001780
Kristian Høgsberge1b655d2013-08-28 23:16:20 -07001781 if (seat->pointer &&
Kristian Høgsberg70f29012014-01-09 15:43:17 -08001782 seat->pointer->focus &&
Kristian Høgsberge1b655d2013-08-28 23:16:20 -07001783 seat->pointer->button_count > 0 &&
1784 seat->pointer->grab_serial == serial) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001785 surface = weston_surface_get_main_surface(seat->pointer->focus->surface);
U. Artie Eoffcf5737a2014-01-17 10:08:25 -08001786 if ((surface == shsurf->surface) &&
Kristian Høgsbergae356ae2014-04-29 16:03:54 -07001787 (surface_move(shsurf, seat, 1) < 0))
Rusty Lynch1084da52013-08-15 09:10:08 -07001788 wl_resource_post_no_memory(resource);
Kristian Høgsberge1b655d2013-08-28 23:16:20 -07001789 } else if (seat->touch &&
Kristian Høgsberg70f29012014-01-09 15:43:17 -08001790 seat->touch->focus &&
Kristian Høgsberge1b655d2013-08-28 23:16:20 -07001791 seat->touch->grab_serial == serial) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001792 surface = weston_surface_get_main_surface(seat->touch->focus->surface);
U. Artie Eoffcf5737a2014-01-17 10:08:25 -08001793 if ((surface == shsurf->surface) &&
Rusty Lynch1084da52013-08-15 09:10:08 -07001794 (surface_touch_move(shsurf, seat) < 0))
1795 wl_resource_post_no_memory(resource);
1796 }
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001797}
1798
Rafael Antognollie2a34552013-12-03 15:35:45 -02001799static void
1800shell_surface_move(struct wl_client *client, struct wl_resource *resource,
1801 struct wl_resource *seat_resource, uint32_t serial)
1802{
1803 common_surface_move(resource, seat_resource, serial);
1804}
1805
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001806struct weston_resize_grab {
1807 struct shell_grab base;
1808 uint32_t edges;
1809 int32_t width, height;
1810};
1811
1812static void
Giulio Camuffo1959ab82013-11-14 23:42:52 +01001813resize_grab_motion(struct weston_pointer_grab *grab, uint32_t time,
1814 wl_fixed_t x, wl_fixed_t y)
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001815{
1816 struct weston_resize_grab *resize = (struct weston_resize_grab *) grab;
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001817 struct weston_pointer *pointer = grab->pointer;
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001818 struct shell_surface *shsurf = resize->base.shsurf;
1819 int32_t width, height;
1820 wl_fixed_t from_x, from_y;
1821 wl_fixed_t to_x, to_y;
1822
Giulio Camuffo1959ab82013-11-14 23:42:52 +01001823 weston_pointer_move(pointer, x, y);
1824
Kristian Høgsberge0b9d5b2014-04-30 13:45:49 -07001825 if (!shsurf)
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001826 return;
1827
Jason Ekstranda7af7042013-10-12 22:38:11 -05001828 weston_view_from_global_fixed(shsurf->view,
1829 pointer->grab_x, pointer->grab_y,
1830 &from_x, &from_y);
1831 weston_view_from_global_fixed(shsurf->view,
1832 pointer->x, pointer->y, &to_x, &to_y);
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001833
1834 width = resize->width;
1835 if (resize->edges & WL_SHELL_SURFACE_RESIZE_LEFT) {
1836 width += wl_fixed_to_int(from_x - to_x);
1837 } else if (resize->edges & WL_SHELL_SURFACE_RESIZE_RIGHT) {
1838 width += wl_fixed_to_int(to_x - from_x);
1839 }
1840
1841 height = resize->height;
1842 if (resize->edges & WL_SHELL_SURFACE_RESIZE_TOP) {
1843 height += wl_fixed_to_int(from_y - to_y);
1844 } else if (resize->edges & WL_SHELL_SURFACE_RESIZE_BOTTOM) {
1845 height += wl_fixed_to_int(to_y - from_y);
1846 }
1847
Derek Foreman70ac0ed2015-03-18 11:16:33 -05001848 if (width < 1)
1849 width = 1;
1850 if (height < 1)
1851 height = 1;
Jasper St. Pierreac985be2014-04-28 11:19:28 -04001852 shsurf->client->send_configure(shsurf->surface, width, height);
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001853}
1854
1855static void
Jasper St. Pierreac985be2014-04-28 11:19:28 -04001856send_configure(struct weston_surface *surface, int32_t width, int32_t height)
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001857{
1858 struct shell_surface *shsurf = get_shell_surface(surface);
1859
U. Artie Eoffcf5737a2014-01-17 10:08:25 -08001860 assert(shsurf);
1861
Kristian Høgsberge0b9d5b2014-04-30 13:45:49 -07001862 if (shsurf->resource)
1863 wl_shell_surface_send_configure(shsurf->resource,
Jasper St. Pierreac985be2014-04-28 11:19:28 -04001864 shsurf->resize_edges,
1865 width, height);
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001866}
1867
1868static const struct weston_shell_client shell_client = {
1869 send_configure
1870};
1871
1872static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001873resize_grab_button(struct weston_pointer_grab *grab,
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001874 uint32_t time, uint32_t button, uint32_t state_w)
1875{
1876 struct weston_resize_grab *resize = (struct weston_resize_grab *) grab;
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001877 struct weston_pointer *pointer = grab->pointer;
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001878 enum wl_pointer_button_state state = state_w;
1879
1880 if (pointer->button_count == 0 &&
1881 state == WL_POINTER_BUTTON_STATE_RELEASED) {
1882 shell_grab_end(&resize->base);
1883 free(grab);
1884 }
1885}
1886
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02001887static void
1888resize_grab_cancel(struct weston_pointer_grab *grab)
1889{
1890 struct weston_resize_grab *resize = (struct weston_resize_grab *) grab;
1891
1892 shell_grab_end(&resize->base);
1893 free(grab);
1894}
1895
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001896static const struct weston_pointer_grab_interface resize_grab_interface = {
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001897 noop_grab_focus,
1898 resize_grab_motion,
1899 resize_grab_button,
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02001900 resize_grab_cancel,
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001901};
1902
Giulio Camuffob8366642013-04-25 13:57:46 +03001903/*
1904 * Returns the bounding box of a surface and all its sub-surfaces,
1905 * in the surface coordinates system. */
1906static void
1907surface_subsurfaces_boundingbox(struct weston_surface *surface, int32_t *x,
1908 int32_t *y, int32_t *w, int32_t *h) {
1909 pixman_region32_t region;
1910 pixman_box32_t *box;
1911 struct weston_subsurface *subsurface;
1912
1913 pixman_region32_init_rect(&region, 0, 0,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001914 surface->width,
1915 surface->height);
Giulio Camuffob8366642013-04-25 13:57:46 +03001916
1917 wl_list_for_each(subsurface, &surface->subsurface_list, parent_link) {
1918 pixman_region32_union_rect(&region, &region,
1919 subsurface->position.x,
1920 subsurface->position.y,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001921 subsurface->surface->width,
1922 subsurface->surface->height);
Giulio Camuffob8366642013-04-25 13:57:46 +03001923 }
1924
1925 box = pixman_region32_extents(&region);
1926 if (x)
1927 *x = box->x1;
1928 if (y)
1929 *y = box->y1;
1930 if (w)
1931 *w = box->x2 - box->x1;
1932 if (h)
1933 *h = box->y2 - box->y1;
1934
1935 pixman_region32_fini(&region);
1936}
1937
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001938static int
1939surface_resize(struct shell_surface *shsurf,
Kristian Høgsberge3148752013-05-06 23:19:49 -04001940 struct weston_seat *seat, uint32_t edges)
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001941{
1942 struct weston_resize_grab *resize;
Ondřej Majerechae9c4fc2014-08-21 15:47:22 +02001943 const unsigned resize_topbottom =
1944 WL_SHELL_SURFACE_RESIZE_TOP | WL_SHELL_SURFACE_RESIZE_BOTTOM;
1945 const unsigned resize_leftright =
1946 WL_SHELL_SURFACE_RESIZE_LEFT | WL_SHELL_SURFACE_RESIZE_RIGHT;
1947 const unsigned resize_any = resize_topbottom | resize_leftright;
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001948
Kristian Høgsberga4b620e2014-04-30 16:05:49 -07001949 if (shsurf->grabbed ||
1950 shsurf->state.fullscreen || shsurf->state.maximized)
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001951 return 0;
1952
Ondřej Majerechae9c4fc2014-08-21 15:47:22 +02001953 /* Check for invalid edge combinations. */
1954 if (edges == WL_SHELL_SURFACE_RESIZE_NONE || edges > resize_any ||
1955 (edges & resize_topbottom) == resize_topbottom ||
1956 (edges & resize_leftright) == resize_leftright)
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001957 return 0;
1958
1959 resize = malloc(sizeof *resize);
1960 if (!resize)
1961 return -1;
1962
1963 resize->edges = edges;
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001964
Jasper St. Pierreccf48fb2014-05-02 10:21:38 -04001965 resize->width = shsurf->geometry.width;
1966 resize->height = shsurf->geometry.height;
Jasper St. Pierrebd65e502014-07-14 16:28:48 -04001967
Kristian Høgsberg44cd1962014-02-05 21:36:04 -08001968 shsurf->resize_edges = edges;
Jasper St. Pierre5befdda2014-05-06 08:50:47 -04001969 shell_surface_state_changed(shsurf);
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001970 shell_grab_start(&resize->base, &resize_grab_interface, shsurf,
Kristian Høgsberge3148752013-05-06 23:19:49 -04001971 seat->pointer, edges);
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001972
1973 return 0;
1974}
1975
1976static void
Rafael Antognollie2a34552013-12-03 15:35:45 -02001977common_surface_resize(struct wl_resource *resource,
1978 struct wl_resource *seat_resource, uint32_t serial,
1979 uint32_t edges)
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001980{
Jason Ekstrand44a38632013-06-14 10:08:00 -05001981 struct weston_seat *seat = wl_resource_get_user_data(seat_resource);
Jason Ekstrand651f00e2013-06-14 10:07:54 -05001982 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
Giulio Camuffo61da3fc2013-04-25 13:57:45 +03001983 struct weston_surface *surface;
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001984
Emilio Pozuelo Monfort5872b682014-06-18 17:48:58 +02001985 if (seat->pointer == NULL ||
1986 seat->pointer->button_count == 0 ||
Kristian Høgsberge3148752013-05-06 23:19:49 -04001987 seat->pointer->grab_serial != serial ||
Kristian Høgsberg70f29012014-01-09 15:43:17 -08001988 seat->pointer->focus == NULL)
1989 return;
1990
1991 surface = weston_surface_get_main_surface(seat->pointer->focus->surface);
1992 if (surface != shsurf->surface)
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001993 return;
1994
Kristian Høgsberge3148752013-05-06 23:19:49 -04001995 if (surface_resize(shsurf, seat, edges) < 0)
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001996 wl_resource_post_no_memory(resource);
1997}
1998
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001999static void
Rafael Antognollie2a34552013-12-03 15:35:45 -02002000shell_surface_resize(struct wl_client *client, struct wl_resource *resource,
2001 struct wl_resource *seat_resource, uint32_t serial,
2002 uint32_t edges)
2003{
2004 common_surface_resize(resource, seat_resource, serial, edges);
2005}
2006
2007static void
Kristian Høgsberg6848c252013-05-08 22:02:59 -04002008busy_cursor_grab_focus(struct weston_pointer_grab *base)
Scott Moreauc3e54eb2012-04-17 19:06:20 -06002009{
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04002010 struct shell_grab *grab = (struct shell_grab *) base;
Kristian Høgsberg6848c252013-05-08 22:02:59 -04002011 struct weston_pointer *pointer = base->pointer;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002012 struct weston_view *view;
Kristian Høgsberg6848c252013-05-08 22:02:59 -04002013 wl_fixed_t sx, sy;
2014
Jason Ekstranda7af7042013-10-12 22:38:11 -05002015 view = weston_compositor_pick_view(pointer->seat->compositor,
2016 pointer->x, pointer->y,
2017 &sx, &sy);
Scott Moreauc3e54eb2012-04-17 19:06:20 -06002018
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08002019 if (!grab->shsurf || grab->shsurf->surface != view->surface) {
2020 shell_grab_end(grab);
2021 free(grab);
2022 }
Scott Moreauc3e54eb2012-04-17 19:06:20 -06002023}
2024
2025static void
Giulio Camuffo1959ab82013-11-14 23:42:52 +01002026busy_cursor_grab_motion(struct weston_pointer_grab *grab, uint32_t time,
2027 wl_fixed_t x, wl_fixed_t y)
Scott Moreauc3e54eb2012-04-17 19:06:20 -06002028{
Giulio Camuffo1959ab82013-11-14 23:42:52 +01002029 weston_pointer_move(grab->pointer, x, y);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04002030}
Scott Moreauc3e54eb2012-04-17 19:06:20 -06002031
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04002032static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04002033busy_cursor_grab_button(struct weston_pointer_grab *base,
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04002034 uint32_t time, uint32_t button, uint32_t state)
2035{
Kristian Høgsbergbbe98392012-08-01 00:20:21 -04002036 struct shell_grab *grab = (struct shell_grab *) base;
Kristian Høgsberge122b7b2013-05-08 16:47:00 -04002037 struct shell_surface *shsurf = grab->shsurf;
Kristian Høgsberge3148752013-05-06 23:19:49 -04002038 struct weston_seat *seat = grab->grab.pointer->seat;
Kristian Høgsbergbbe98392012-08-01 00:20:21 -04002039
Kristian Høgsbergbbe98392012-08-01 00:20:21 -04002040 if (shsurf && button == BTN_LEFT && state) {
Emilio Pozuelo Monfort9e7c7592014-01-30 14:01:10 +01002041 activate(shsurf->shell, shsurf->surface, seat, true);
Kristian Høgsbergae356ae2014-04-29 16:03:54 -07002042 surface_move(shsurf, seat, 0);
Kristian Høgsberg0c369032013-02-14 21:31:44 -05002043 } else if (shsurf && button == BTN_RIGHT && state) {
Emilio Pozuelo Monfort9e7c7592014-01-30 14:01:10 +01002044 activate(shsurf->shell, shsurf->surface, seat, true);
Kristian Høgsberge3148752013-05-06 23:19:49 -04002045 surface_rotate(shsurf, seat);
Kristian Høgsbergbbe98392012-08-01 00:20:21 -04002046 }
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04002047}
2048
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02002049static void
2050busy_cursor_grab_cancel(struct weston_pointer_grab *base)
2051{
2052 struct shell_grab *grab = (struct shell_grab *) base;
2053
2054 shell_grab_end(grab);
2055 free(grab);
2056}
2057
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04002058static const struct weston_pointer_grab_interface busy_cursor_grab_interface = {
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04002059 busy_cursor_grab_focus,
2060 busy_cursor_grab_motion,
2061 busy_cursor_grab_button,
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02002062 busy_cursor_grab_cancel,
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04002063};
2064
2065static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04002066set_busy_cursor(struct shell_surface *shsurf, struct weston_pointer *pointer)
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04002067{
2068 struct shell_grab *grab;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04002069
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08002070 if (pointer->grab->interface == &busy_cursor_grab_interface)
2071 return;
2072
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04002073 grab = malloc(sizeof *grab);
2074 if (!grab)
Scott Moreauc3e54eb2012-04-17 19:06:20 -06002075 return;
2076
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03002077 shell_grab_start(grab, &busy_cursor_grab_interface, shsurf, pointer,
2078 DESKTOP_SHELL_CURSOR_BUSY);
Ander Conselvan de Oliveirae5a1aee2014-04-09 17:39:39 +03002079 /* Mark the shsurf as ungrabbed so that button binding is able
2080 * to move it. */
2081 shsurf->grabbed = 0;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04002082}
Scott Moreauc3e54eb2012-04-17 19:06:20 -06002083
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04002084static void
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08002085end_busy_cursor(struct weston_compositor *compositor, struct wl_client *client)
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04002086{
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08002087 struct shell_grab *grab;
2088 struct weston_seat *seat;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04002089
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08002090 wl_list_for_each(seat, &compositor->seat_list, link) {
2091 if (seat->pointer == NULL)
2092 continue;
2093
2094 grab = (struct shell_grab *) seat->pointer->grab;
2095 if (grab->grab.interface == &busy_cursor_grab_interface &&
2096 wl_resource_get_client(grab->shsurf->resource) == client) {
2097 shell_grab_end(grab);
2098 free(grab);
2099 }
Scott Moreauc3e54eb2012-04-17 19:06:20 -06002100 }
Scott Moreauc3e54eb2012-04-17 19:06:20 -06002101}
2102
Scott Moreau9521d5e2012-04-19 13:06:17 -06002103static void
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08002104handle_shell_client_destroy(struct wl_listener *listener, void *data);
2105
2106static int
2107xdg_ping_timeout_handler(void *data)
2108{
2109 struct shell_client *sc = data;
2110 struct weston_seat *seat;
2111 struct shell_surface *shsurf;
2112
2113 /* Client is not responding */
2114 sc->unresponsive = 1;
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08002115 wl_list_for_each(seat, &sc->shell->compositor->seat_list, link) {
2116 if (seat->pointer == NULL || seat->pointer->focus == NULL)
2117 continue;
2118 if (seat->pointer->focus->surface->resource == NULL)
2119 continue;
Michael Vetter2a18a522015-05-15 17:17:47 +02002120
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08002121 shsurf = get_shell_surface(seat->pointer->focus->surface);
2122 if (shsurf &&
2123 wl_resource_get_client(shsurf->resource) == sc->client)
2124 set_busy_cursor(shsurf, seat->pointer);
2125 }
2126
2127 return 1;
2128}
2129
2130static void
2131handle_xdg_ping(struct shell_surface *shsurf, uint32_t serial)
2132{
2133 struct weston_compositor *compositor = shsurf->shell->compositor;
Jason Ekstrand9e9512f2014-04-16 21:12:10 -05002134 struct shell_client *sc = shsurf->owner;
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08002135 struct wl_event_loop *loop;
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08002136 static const int ping_timeout = 200;
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08002137
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08002138 if (sc->unresponsive) {
2139 xdg_ping_timeout_handler(sc);
2140 return;
2141 }
2142
2143 sc->ping_serial = serial;
2144 loop = wl_display_get_event_loop(compositor->wl_display);
2145 if (sc->ping_timer == NULL)
2146 sc->ping_timer =
2147 wl_event_loop_add_timer(loop,
2148 xdg_ping_timeout_handler, sc);
2149 if (sc->ping_timer == NULL)
2150 return;
2151
2152 wl_event_source_timer_update(sc->ping_timer, ping_timeout);
2153
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08002154 if (shell_surface_is_xdg_surface(shsurf) ||
2155 shell_surface_is_xdg_popup(shsurf))
2156 xdg_shell_send_ping(sc->resource, serial);
2157 else if (shell_surface_is_wl_shell_surface(shsurf))
2158 wl_shell_surface_send_ping(shsurf->resource, serial);
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08002159}
2160
Scott Moreauff1db4a2012-04-17 19:06:18 -06002161static void
2162ping_handler(struct weston_surface *surface, uint32_t serial)
2163{
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04002164 struct shell_surface *shsurf = get_shell_surface(surface);
Scott Moreauff1db4a2012-04-17 19:06:18 -06002165
2166 if (!shsurf)
2167 return;
Jason Ekstrand651f00e2013-06-14 10:07:54 -05002168 if (!shsurf->resource)
Kristian Høgsbergca535c12012-04-21 23:20:07 -04002169 return;
Ander Conselvan de Oliveiraeac9a462012-07-16 14:15:48 +03002170 if (shsurf->surface == shsurf->shell->grab_surface)
2171 return;
2172
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08002173 handle_xdg_ping(shsurf, serial);
Scott Moreauff1db4a2012-04-17 19:06:18 -06002174}
2175
2176static void
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04002177handle_pointer_focus(struct wl_listener *listener, void *data)
2178{
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04002179 struct weston_pointer *pointer = data;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002180 struct weston_view *view = pointer->focus;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04002181 struct weston_compositor *compositor;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04002182 uint32_t serial;
2183
Jason Ekstranda7af7042013-10-12 22:38:11 -05002184 if (!view)
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04002185 return;
2186
Jason Ekstranda7af7042013-10-12 22:38:11 -05002187 compositor = view->surface->compositor;
Kristian Høgsberge11ef642014-02-11 16:35:22 -08002188 serial = wl_display_next_serial(compositor->wl_display);
2189 ping_handler(view->surface, serial);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04002190}
2191
2192static void
Jasper St. Pierrefaf27a92013-12-09 17:36:28 -05002193shell_surface_lose_keyboard_focus(struct shell_surface *shsurf)
2194{
2195 if (--shsurf->focus_count == 0)
Jasper St. Pierre973d7872014-05-06 08:44:29 -04002196 shell_surface_state_changed(shsurf);
Jasper St. Pierrefaf27a92013-12-09 17:36:28 -05002197}
2198
2199static void
2200shell_surface_gain_keyboard_focus(struct shell_surface *shsurf)
2201{
2202 if (shsurf->focus_count++ == 0)
Jasper St. Pierre973d7872014-05-06 08:44:29 -04002203 shell_surface_state_changed(shsurf);
Jasper St. Pierrefaf27a92013-12-09 17:36:28 -05002204}
2205
2206static void
2207handle_keyboard_focus(struct wl_listener *listener, void *data)
2208{
2209 struct weston_keyboard *keyboard = data;
2210 struct shell_seat *seat = get_shell_seat(keyboard->seat);
2211
2212 if (seat->focused_surface) {
2213 struct shell_surface *shsurf = get_shell_surface(seat->focused_surface);
2214 if (shsurf)
2215 shell_surface_lose_keyboard_focus(shsurf);
2216 }
2217
2218 seat->focused_surface = keyboard->focus;
2219
2220 if (seat->focused_surface) {
2221 struct shell_surface *shsurf = get_shell_surface(seat->focused_surface);
2222 if (shsurf)
2223 shell_surface_gain_keyboard_focus(shsurf);
2224 }
2225}
2226
2227static void
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08002228shell_client_pong(struct shell_client *sc, uint32_t serial)
Rafael Antognollie2a34552013-12-03 15:35:45 -02002229{
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08002230 if (sc->ping_serial != serial)
2231 return;
Rafael Antognollie2a34552013-12-03 15:35:45 -02002232
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08002233 sc->unresponsive = 0;
2234 end_busy_cursor(sc->shell->compositor, sc->client);
Rafael Antognollie2a34552013-12-03 15:35:45 -02002235
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08002236 if (sc->ping_timer) {
2237 wl_event_source_remove(sc->ping_timer);
2238 sc->ping_timer = NULL;
2239 }
2240
2241}
2242
2243static void
2244shell_surface_pong(struct wl_client *client,
2245 struct wl_resource *resource, uint32_t serial)
2246{
Jason Ekstrand9e9512f2014-04-16 21:12:10 -05002247 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
2248 struct shell_client *sc = shsurf->owner;
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08002249
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08002250 shell_client_pong(sc, serial);
Rafael Antognollie2a34552013-12-03 15:35:45 -02002251}
2252
2253static void
Giulio Camuffo62942ad2013-09-11 18:20:47 +02002254set_title(struct shell_surface *shsurf, const char *title)
2255{
2256 free(shsurf->title);
2257 shsurf->title = strdup(title);
Pekka Paalanenb5026542014-11-12 15:09:24 +02002258 shsurf->surface->timeline.force_refresh = 1;
2259}
2260
2261static void
Giulio Camuffoa8e9b412015-01-27 19:10:37 +02002262set_pid(struct shell_surface *shsurf, pid_t pid)
2263{
2264 /* We have no use for it */
2265}
2266
2267static void
Pekka Paalanenb5026542014-11-12 15:09:24 +02002268set_type(struct shell_surface *shsurf, enum shell_surface_type t)
2269{
2270 shsurf->type = t;
2271 shsurf->surface->timeline.force_refresh = 1;
Giulio Camuffo62942ad2013-09-11 18:20:47 +02002272}
2273
2274static void
Jasper St. Pierreccf48fb2014-05-02 10:21:38 -04002275set_window_geometry(struct shell_surface *shsurf,
2276 int32_t x, int32_t y, int32_t width, int32_t height)
Kristian Høgsberge5c1ae92014-04-30 16:28:41 -07002277{
Jasper St. Pierreccf48fb2014-05-02 10:21:38 -04002278 shsurf->next_geometry.x = x;
2279 shsurf->next_geometry.y = y;
2280 shsurf->next_geometry.width = width;
2281 shsurf->next_geometry.height = height;
2282 shsurf->has_next_geometry = true;
Kristian Høgsberge5c1ae92014-04-30 16:28:41 -07002283}
2284
2285static void
Kristian Høgsberge7afd912012-05-02 09:47:44 -04002286shell_surface_set_title(struct wl_client *client,
2287 struct wl_resource *resource, const char *title)
2288{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05002289 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
Kristian Høgsberge7afd912012-05-02 09:47:44 -04002290
Giulio Camuffo62942ad2013-09-11 18:20:47 +02002291 set_title(shsurf, title);
Kristian Høgsberge7afd912012-05-02 09:47:44 -04002292}
2293
2294static void
2295shell_surface_set_class(struct wl_client *client,
2296 struct wl_resource *resource, const char *class)
2297{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05002298 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
Kristian Høgsberge7afd912012-05-02 09:47:44 -04002299
2300 free(shsurf->class);
2301 shsurf->class = strdup(class);
Pekka Paalanenb5026542014-11-12 15:09:24 +02002302 shsurf->surface->timeline.force_refresh = 1;
Kristian Høgsberge7afd912012-05-02 09:47:44 -04002303}
2304
Alex Wu4539b082012-03-01 12:57:46 +08002305static void
Alexander Larssonf82b6ca2013-05-28 16:23:39 +02002306restore_output_mode(struct weston_output *output)
2307{
Derek Foreman6ae7bc92014-11-04 10:47:33 -06002308 if (output->original_mode)
2309 weston_output_mode_switch_to_native(output);
Alexander Larssonf82b6ca2013-05-28 16:23:39 +02002310}
2311
2312static void
2313restore_all_output_modes(struct weston_compositor *compositor)
2314{
2315 struct weston_output *output;
2316
2317 wl_list_for_each(output, &compositor->output_list, link)
2318 restore_output_mode(output);
2319}
2320
Philip Withnall07926d92013-11-25 18:01:40 +00002321/* The surface will be inserted into the list immediately after the link
2322 * returned by this function (i.e. will be stacked immediately above the
2323 * returned link). */
Giulio Camuffo412e6a52014-07-09 22:12:56 +03002324static struct weston_layer_entry *
Philip Withnall07926d92013-11-25 18:01:40 +00002325shell_surface_calculate_layer_link (struct shell_surface *shsurf)
2326{
2327 struct workspace *ws;
Kristian Høgsbergead52422014-01-01 13:51:52 -08002328 struct weston_view *parent;
Philip Withnall07926d92013-11-25 18:01:40 +00002329
2330 switch (shsurf->type) {
Ander Conselvan de Oliveiraef6a7e42014-04-30 14:15:14 +03002331 case SHELL_SURFACE_XWAYLAND:
2332 return &shsurf->shell->fullscreen_layer.view_list;
2333
2334 case SHELL_SURFACE_NONE:
2335 return NULL;
2336
Kristian Høgsbergead52422014-01-01 13:51:52 -08002337 case SHELL_SURFACE_POPUP:
2338 case SHELL_SURFACE_TOPLEVEL:
Emilio Pozuelo Monfort9e7c7592014-01-30 14:01:10 +01002339 if (shsurf->state.fullscreen && !shsurf->state.lowered) {
Rafael Antognolli03b16592013-12-03 15:35:42 -02002340 return &shsurf->shell->fullscreen_layer.view_list;
Rafael Antognollied207b42013-12-03 15:35:43 -02002341 } else if (shsurf->parent) {
Kristian Høgsbergd55db692014-01-01 12:26:14 -08002342 /* Move the surface to its parent layer so
2343 * that surfaces which are transient for
2344 * fullscreen surfaces don't get hidden by the
2345 * fullscreen surfaces. */
Rafael Antognollied207b42013-12-03 15:35:43 -02002346
2347 /* TODO: Handle a parent with multiple views */
2348 parent = get_default_view(shsurf->parent);
2349 if (parent)
Giulio Camuffo412e6a52014-07-09 22:12:56 +03002350 return container_of(parent->layer_link.link.prev,
2351 struct weston_layer_entry, link);
Rafael Antognollied207b42013-12-03 15:35:43 -02002352 }
Philip Withnall07926d92013-11-25 18:01:40 +00002353
Ander Conselvan de Oliveiraef6a7e42014-04-30 14:15:14 +03002354 /* Move the surface to a normal workspace layer so that surfaces
2355 * which were previously fullscreen or transient are no longer
2356 * rendered on top. */
2357 ws = get_current_workspace(shsurf->shell);
2358 return &ws->layer.view_list;
Philip Withnall07926d92013-11-25 18:01:40 +00002359 }
2360
Ander Conselvan de Oliveiraef6a7e42014-04-30 14:15:14 +03002361 assert(0 && "Unknown shell surface type");
Philip Withnall07926d92013-11-25 18:01:40 +00002362}
2363
Philip Withnall648a4dd2013-11-25 18:01:44 +00002364static void
2365shell_surface_update_child_surface_layers (struct shell_surface *shsurf)
2366{
2367 struct shell_surface *child;
Giulio Camuffo412e6a52014-07-09 22:12:56 +03002368 struct weston_layer_entry *prev;
Philip Withnall648a4dd2013-11-25 18:01:44 +00002369
2370 /* Move the child layers to the same workspace as shsurf. They will be
2371 * stacked above shsurf. */
2372 wl_list_for_each_reverse(child, &shsurf->children_list, children_link) {
Giulio Camuffo412e6a52014-07-09 22:12:56 +03002373 if (shsurf->view->layer_link.link.prev != &child->view->layer_link.link) {
Ander Conselvan de Oliveirafacc0cc2014-04-10 15:35:58 +03002374 weston_view_damage_below(child->view);
Philip Withnall648a4dd2013-11-25 18:01:44 +00002375 weston_view_geometry_dirty(child->view);
Giulio Camuffo412e6a52014-07-09 22:12:56 +03002376 prev = container_of(shsurf->view->layer_link.link.prev,
2377 struct weston_layer_entry, link);
2378 weston_layer_entry_remove(&child->view->layer_link);
2379 weston_layer_entry_insert(prev,
2380 &child->view->layer_link);
Philip Withnall648a4dd2013-11-25 18:01:44 +00002381 weston_view_geometry_dirty(child->view);
2382 weston_surface_damage(child->surface);
2383
2384 /* Recurse. We don’t expect this to recurse very far (if
2385 * at all) because that would imply we have transient
2386 * (or popup) children of transient surfaces, which
2387 * would be unusual. */
2388 shell_surface_update_child_surface_layers(child);
2389 }
2390 }
2391}
2392
Philip Withnalle1d75ae2013-11-25 18:01:41 +00002393/* Update the surface’s layer. Mark both the old and new views as having dirty
Philip Withnall648a4dd2013-11-25 18:01:44 +00002394 * geometry to ensure the changes are redrawn.
2395 *
2396 * If any child surfaces exist and are mapped, ensure they’re in the same layer
2397 * as this surface. */
Philip Withnalle1d75ae2013-11-25 18:01:41 +00002398static void
2399shell_surface_update_layer(struct shell_surface *shsurf)
2400{
Giulio Camuffo412e6a52014-07-09 22:12:56 +03002401 struct weston_layer_entry *new_layer_link;
Philip Withnalle1d75ae2013-11-25 18:01:41 +00002402
2403 new_layer_link = shell_surface_calculate_layer_link(shsurf);
2404
Ander Conselvan de Oliveiraef6a7e42014-04-30 14:15:14 +03002405 if (new_layer_link == NULL)
2406 return;
Philip Withnalle1d75ae2013-11-25 18:01:41 +00002407 if (new_layer_link == &shsurf->view->layer_link)
2408 return;
2409
2410 weston_view_geometry_dirty(shsurf->view);
Giulio Camuffo412e6a52014-07-09 22:12:56 +03002411 weston_layer_entry_remove(&shsurf->view->layer_link);
2412 weston_layer_entry_insert(new_layer_link, &shsurf->view->layer_link);
Philip Withnalle1d75ae2013-11-25 18:01:41 +00002413 weston_view_geometry_dirty(shsurf->view);
2414 weston_surface_damage(shsurf->surface);
Philip Withnall648a4dd2013-11-25 18:01:44 +00002415
2416 shell_surface_update_child_surface_layers(shsurf);
Philip Withnalle1d75ae2013-11-25 18:01:41 +00002417}
2418
Alexander Larssonf82b6ca2013-05-28 16:23:39 +02002419static void
Philip Withnalldc4332f2013-11-25 18:01:38 +00002420shell_surface_set_parent(struct shell_surface *shsurf,
2421 struct weston_surface *parent)
2422{
2423 shsurf->parent = parent;
Philip Withnall648a4dd2013-11-25 18:01:44 +00002424
2425 wl_list_remove(&shsurf->children_link);
2426 wl_list_init(&shsurf->children_link);
2427
2428 /* Insert into the parent surface’s child list. */
2429 if (parent != NULL) {
2430 struct shell_surface *parent_shsurf = get_shell_surface(parent);
2431 if (parent_shsurf != NULL)
2432 wl_list_insert(&parent_shsurf->children_list,
2433 &shsurf->children_link);
2434 }
Philip Withnalldc4332f2013-11-25 18:01:38 +00002435}
2436
2437static void
Philip Withnall352e7ed2013-11-25 18:01:35 +00002438shell_surface_set_output(struct shell_surface *shsurf,
2439 struct weston_output *output)
2440{
2441 struct weston_surface *es = shsurf->surface;
2442
2443 /* get the default output, if the client set it as NULL
2444 check whether the ouput is available */
2445 if (output)
2446 shsurf->output = output;
2447 else if (es->output)
2448 shsurf->output = es->output;
2449 else
2450 shsurf->output = get_default_output(es->compositor);
2451}
2452
2453static void
Rafael Antognolli03b16592013-12-03 15:35:42 -02002454surface_clear_next_states(struct shell_surface *shsurf)
2455{
2456 shsurf->next_state.maximized = false;
2457 shsurf->next_state.fullscreen = false;
2458
2459 if ((shsurf->next_state.maximized != shsurf->state.maximized) ||
2460 (shsurf->next_state.fullscreen != shsurf->state.fullscreen))
2461 shsurf->state_changed = true;
2462}
2463
2464static void
Philip Withnallbecb77e2013-11-25 18:01:30 +00002465set_toplevel(struct shell_surface *shsurf)
2466{
Kristian Høgsberg41fbf6f2013-12-05 22:31:25 -08002467 shell_surface_set_parent(shsurf, NULL);
2468 surface_clear_next_states(shsurf);
Pekka Paalanenb5026542014-11-12 15:09:24 +02002469 set_type(shsurf, SHELL_SURFACE_TOPLEVEL);
Philip Withnall648a4dd2013-11-25 18:01:44 +00002470
2471 /* The layer_link is updated in set_surface_type(),
2472 * called from configure. */
Philip Withnallbecb77e2013-11-25 18:01:30 +00002473}
2474
2475static void
2476shell_surface_set_toplevel(struct wl_client *client,
2477 struct wl_resource *resource)
2478{
2479 struct shell_surface *surface = wl_resource_get_user_data(resource);
2480
2481 set_toplevel(surface);
2482}
2483
2484static void
2485set_transient(struct shell_surface *shsurf,
2486 struct weston_surface *parent, int x, int y, uint32_t flags)
2487{
Philip Withnalldc4332f2013-11-25 18:01:38 +00002488 assert(parent != NULL);
2489
Kristian Høgsberg9f7e3312014-01-02 22:40:37 -08002490 shell_surface_set_parent(shsurf, parent);
2491
2492 surface_clear_next_states(shsurf);
2493
Philip Withnallbecb77e2013-11-25 18:01:30 +00002494 shsurf->transient.x = x;
2495 shsurf->transient.y = y;
2496 shsurf->transient.flags = flags;
Philip Withnalldc4332f2013-11-25 18:01:38 +00002497
Rafael Antognollied207b42013-12-03 15:35:43 -02002498 shsurf->next_state.relative = true;
Kristian Høgsberga1df7ac2013-12-31 15:01:01 -08002499 shsurf->state_changed = true;
Pekka Paalanenb5026542014-11-12 15:09:24 +02002500 set_type(shsurf, SHELL_SURFACE_TOPLEVEL);
Philip Withnall648a4dd2013-11-25 18:01:44 +00002501
2502 /* The layer_link is updated in set_surface_type(),
2503 * called from configure. */
Philip Withnallbecb77e2013-11-25 18:01:30 +00002504}
2505
2506static void
2507shell_surface_set_transient(struct wl_client *client,
2508 struct wl_resource *resource,
2509 struct wl_resource *parent_resource,
2510 int x, int y, uint32_t flags)
2511{
2512 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
2513 struct weston_surface *parent =
2514 wl_resource_get_user_data(parent_resource);
2515
2516 set_transient(shsurf, parent, x, y, flags);
2517}
2518
2519static void
2520set_fullscreen(struct shell_surface *shsurf,
2521 uint32_t method,
2522 uint32_t framerate,
2523 struct weston_output *output)
2524{
Philip Withnall352e7ed2013-11-25 18:01:35 +00002525 shell_surface_set_output(shsurf, output);
Pekka Paalanenb5026542014-11-12 15:09:24 +02002526 set_type(shsurf, SHELL_SURFACE_TOPLEVEL);
Philip Withnallbecb77e2013-11-25 18:01:30 +00002527
2528 shsurf->fullscreen_output = shsurf->output;
2529 shsurf->fullscreen.type = method;
2530 shsurf->fullscreen.framerate = framerate;
Philip Withnalldc4332f2013-11-25 18:01:38 +00002531
Jasper St. Pierre6458ec32014-04-11 16:00:31 -07002532 send_configure_for_surface(shsurf);
Philip Withnallbecb77e2013-11-25 18:01:30 +00002533}
2534
2535static void
Zhang, Xiong Y31236932013-12-13 22:10:57 +02002536weston_view_set_initial_position(struct weston_view *view,
2537 struct desktop_shell *shell);
2538
2539static void
Philip Withnallbecb77e2013-11-25 18:01:30 +00002540unset_fullscreen(struct shell_surface *shsurf)
Alex Wu4539b082012-03-01 12:57:46 +08002541{
Philip Withnallf85fe842013-11-25 18:01:37 +00002542 /* Unset the fullscreen output, driver configuration and transforms. */
Alex Wubd3354b2012-04-17 17:20:49 +08002543 if (shsurf->fullscreen.type == WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER &&
2544 shell_surface_is_top_fullscreen(shsurf)) {
Alexander Larssonf82b6ca2013-05-28 16:23:39 +02002545 restore_output_mode(shsurf->fullscreen_output);
Alex Wubd3354b2012-04-17 17:20:49 +08002546 }
Philip Withnallf85fe842013-11-25 18:01:37 +00002547
Alex Wu4539b082012-03-01 12:57:46 +08002548 shsurf->fullscreen.type = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT;
2549 shsurf->fullscreen.framerate = 0;
Philip Withnallf85fe842013-11-25 18:01:37 +00002550
Alex Wu4539b082012-03-01 12:57:46 +08002551 wl_list_remove(&shsurf->fullscreen.transform.link);
2552 wl_list_init(&shsurf->fullscreen.transform.link);
Philip Withnallf85fe842013-11-25 18:01:37 +00002553
Jason Ekstranda7af7042013-10-12 22:38:11 -05002554 if (shsurf->fullscreen.black_view)
2555 weston_surface_destroy(shsurf->fullscreen.black_view->surface);
2556 shsurf->fullscreen.black_view = NULL;
Philip Withnallf85fe842013-11-25 18:01:37 +00002557
Zhang, Xiong Y31236932013-12-13 22:10:57 +02002558 if (shsurf->saved_position_valid)
2559 weston_view_set_position(shsurf->view,
2560 shsurf->saved_x, shsurf->saved_y);
2561 else
2562 weston_view_set_initial_position(shsurf->view, shsurf->shell);
2563
Alex Wu7bcb8bd2012-04-27 09:07:24 +08002564 if (shsurf->saved_rotation_valid) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05002565 wl_list_insert(&shsurf->view->geometry.transformation_list,
Philip Withnallbecb77e2013-11-25 18:01:30 +00002566 &shsurf->rotation.transform.link);
Alex Wu7bcb8bd2012-04-27 09:07:24 +08002567 shsurf->saved_rotation_valid = false;
2568 }
Rafal Mielniczuk3e3862c2012-10-07 20:25:36 +02002569
Philip Withnalle1d75ae2013-11-25 18:01:41 +00002570 /* Layer is updated in set_surface_type(). */
Alex Wu4539b082012-03-01 12:57:46 +08002571}
2572
Rafal Mielniczukfffdcdd2013-03-11 19:26:54 +01002573static void
Philip Withnallbecb77e2013-11-25 18:01:30 +00002574shell_surface_set_fullscreen(struct wl_client *client,
2575 struct wl_resource *resource,
2576 uint32_t method,
2577 uint32_t framerate,
2578 struct wl_resource *output_resource)
2579{
2580 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
2581 struct weston_output *output;
2582
2583 if (output_resource)
2584 output = wl_resource_get_user_data(output_resource);
2585 else
2586 output = NULL;
2587
Rafael Antognolli4b99a402013-12-03 15:35:44 -02002588 shell_surface_set_parent(shsurf, NULL);
2589
Rafael Antognolli03b16592013-12-03 15:35:42 -02002590 surface_clear_next_states(shsurf);
Jasper St. Pierre8c6aa452014-02-08 18:29:49 -05002591 shsurf->next_state.fullscreen = true;
2592 shsurf->state_changed = true;
Jasper St. Pierre6458ec32014-04-11 16:00:31 -07002593 set_fullscreen(shsurf, method, framerate, output);
Philip Withnallbecb77e2013-11-25 18:01:30 +00002594}
2595
2596static void
2597set_popup(struct shell_surface *shsurf,
2598 struct weston_surface *parent,
2599 struct weston_seat *seat,
2600 uint32_t serial,
2601 int32_t x,
2602 int32_t y)
2603{
Philip Withnalldc4332f2013-11-25 18:01:38 +00002604 assert(parent != NULL);
2605
Philip Withnallbecb77e2013-11-25 18:01:30 +00002606 shsurf->popup.shseat = get_shell_seat(seat);
2607 shsurf->popup.serial = serial;
2608 shsurf->popup.x = x;
2609 shsurf->popup.y = y;
Philip Withnalldc4332f2013-11-25 18:01:38 +00002610
Pekka Paalanenb5026542014-11-12 15:09:24 +02002611 set_type(shsurf, SHELL_SURFACE_POPUP);
Philip Withnallbecb77e2013-11-25 18:01:30 +00002612}
2613
2614static void
2615shell_surface_set_popup(struct wl_client *client,
2616 struct wl_resource *resource,
2617 struct wl_resource *seat_resource,
2618 uint32_t serial,
2619 struct wl_resource *parent_resource,
2620 int32_t x, int32_t y, uint32_t flags)
2621{
2622 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
Rafael Antognolli4b99a402013-12-03 15:35:44 -02002623 struct weston_surface *parent =
2624 wl_resource_get_user_data(parent_resource);
2625
2626 shell_surface_set_parent(shsurf, parent);
Philip Withnallbecb77e2013-11-25 18:01:30 +00002627
Rafael Antognolli03b16592013-12-03 15:35:42 -02002628 surface_clear_next_states(shsurf);
Philip Withnallbecb77e2013-11-25 18:01:30 +00002629 set_popup(shsurf,
Rafael Antognolli4b99a402013-12-03 15:35:44 -02002630 parent,
Philip Withnallbecb77e2013-11-25 18:01:30 +00002631 wl_resource_get_user_data(seat_resource),
2632 serial, x, y);
2633}
2634
2635static void
Philip Withnallbecb77e2013-11-25 18:01:30 +00002636unset_maximized(struct shell_surface *shsurf)
Rafal Mielniczukfffdcdd2013-03-11 19:26:54 +01002637{
Rafal Mielniczukfffdcdd2013-03-11 19:26:54 +01002638 /* undo all maximized things here */
2639 shsurf->output = get_default_output(shsurf->surface->compositor);
Zhang, Xiong Y31236932013-12-13 22:10:57 +02002640
2641 if (shsurf->saved_position_valid)
2642 weston_view_set_position(shsurf->view,
2643 shsurf->saved_x, shsurf->saved_y);
2644 else
2645 weston_view_set_initial_position(shsurf->view, shsurf->shell);
Rafal Mielniczukfffdcdd2013-03-11 19:26:54 +01002646
2647 if (shsurf->saved_rotation_valid) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05002648 wl_list_insert(&shsurf->view->geometry.transformation_list,
2649 &shsurf->rotation.transform.link);
Rafal Mielniczukfffdcdd2013-03-11 19:26:54 +01002650 shsurf->saved_rotation_valid = false;
2651 }
2652
Philip Withnalle1d75ae2013-11-25 18:01:41 +00002653 /* Layer is updated in set_surface_type(). */
Rafal Mielniczukfffdcdd2013-03-11 19:26:54 +01002654}
2655
Philip Withnallbecb77e2013-11-25 18:01:30 +00002656static void
Manuel Bachmanndc1c3e42015-02-16 11:52:13 +01002657set_minimized(struct weston_surface *surface)
Manuel Bachmann50c87db2014-02-26 15:52:13 +01002658{
2659 struct shell_surface *shsurf;
2660 struct workspace *current_ws;
2661 struct weston_seat *seat;
2662 struct weston_surface *focus;
2663 struct weston_view *view;
2664
2665 view = get_default_view(surface);
2666 if (!view)
2667 return;
2668
2669 assert(weston_surface_get_main_surface(view->surface) == view->surface);
2670
2671 shsurf = get_shell_surface(surface);
2672 current_ws = get_current_workspace(shsurf->shell);
2673
Giulio Camuffo412e6a52014-07-09 22:12:56 +03002674 weston_layer_entry_remove(&view->layer_link);
Manuel Bachmanndc1c3e42015-02-16 11:52:13 +01002675 weston_layer_entry_insert(&shsurf->shell->minimized_layer.view_list, &view->layer_link);
Manuel Bachmann50c87db2014-02-26 15:52:13 +01002676
Manuel Bachmanndc1c3e42015-02-16 11:52:13 +01002677 drop_focus_state(shsurf->shell, current_ws, view->surface);
2678 wl_list_for_each(seat, &shsurf->shell->compositor->seat_list, link) {
2679 if (!seat->keyboard)
2680 continue;
2681 focus = weston_surface_get_main_surface(seat->keyboard->focus);
2682 if (focus == view->surface)
2683 weston_keyboard_set_focus(seat->keyboard, NULL);
Manuel Bachmann50c87db2014-02-26 15:52:13 +01002684 }
2685
2686 shell_surface_update_child_surface_layers(shsurf);
Manuel Bachmann50c87db2014-02-26 15:52:13 +01002687 weston_view_damage_below(view);
2688}
2689
2690static void
Philip Withnallbecb77e2013-11-25 18:01:30 +00002691shell_surface_set_maximized(struct wl_client *client,
2692 struct wl_resource *resource,
2693 struct wl_resource *output_resource)
2694{
2695 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
2696 struct weston_output *output;
2697
Jasper St. Pierre9aa8ce62014-04-11 16:18:54 -07002698 surface_clear_next_states(shsurf);
2699 shsurf->next_state.maximized = true;
2700 shsurf->state_changed = true;
2701
Pekka Paalanenb5026542014-11-12 15:09:24 +02002702 set_type(shsurf, SHELL_SURFACE_TOPLEVEL);
Jasper St. Pierre9aa8ce62014-04-11 16:18:54 -07002703 shell_surface_set_parent(shsurf, NULL);
2704
Philip Withnallbecb77e2013-11-25 18:01:30 +00002705 if (output_resource)
2706 output = wl_resource_get_user_data(output_resource);
2707 else
2708 output = NULL;
2709
Jasper St. Pierre9aa8ce62014-04-11 16:18:54 -07002710 shell_surface_set_output(shsurf, output);
Rafael Antognolli4b99a402013-12-03 15:35:44 -02002711
Jasper St. Pierre9aa8ce62014-04-11 16:18:54 -07002712 send_configure_for_surface(shsurf);
Philip Withnallbecb77e2013-11-25 18:01:30 +00002713}
2714
Philip Withnalle1d75ae2013-11-25 18:01:41 +00002715/* This is only ever called from set_surface_type(), so there’s no need to
2716 * update layer_links here, since they’ll be updated when we return. */
Pekka Paalanen98262232011-12-01 10:42:22 +02002717static int
Philip Withnallbecb77e2013-11-25 18:01:30 +00002718reset_surface_type(struct shell_surface *surface)
Pekka Paalanen98262232011-12-01 10:42:22 +02002719{
Rafael Antognolli03b16592013-12-03 15:35:42 -02002720 if (surface->state.fullscreen)
Philip Withnallbecb77e2013-11-25 18:01:30 +00002721 unset_fullscreen(surface);
Rafael Antognolli03b16592013-12-03 15:35:42 -02002722 if (surface->state.maximized)
Philip Withnallbecb77e2013-11-25 18:01:30 +00002723 unset_maximized(surface);
Pekka Paalanen98262232011-12-01 10:42:22 +02002724
Pekka Paalanen98262232011-12-01 10:42:22 +02002725 return 0;
2726}
2727
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05002728static void
Rafael Antognolli03b16592013-12-03 15:35:42 -02002729set_full_output(struct shell_surface *shsurf)
2730{
2731 shsurf->saved_x = shsurf->view->geometry.x;
2732 shsurf->saved_y = shsurf->view->geometry.y;
Rafael Antognolli3c4e3f72013-12-03 15:35:46 -02002733 shsurf->saved_width = shsurf->surface->width;
2734 shsurf->saved_height = shsurf->surface->height;
2735 shsurf->saved_size_valid = true;
Rafael Antognolli03b16592013-12-03 15:35:42 -02002736 shsurf->saved_position_valid = true;
2737
2738 if (!wl_list_empty(&shsurf->rotation.transform.link)) {
2739 wl_list_remove(&shsurf->rotation.transform.link);
2740 wl_list_init(&shsurf->rotation.transform.link);
2741 weston_view_geometry_dirty(shsurf->view);
2742 shsurf->saved_rotation_valid = true;
2743 }
2744}
2745
2746static void
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04002747set_surface_type(struct shell_surface *shsurf)
2748{
Kristian Høgsberg8150b192012-06-27 10:22:58 -04002749 struct weston_surface *pes = shsurf->parent;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002750 struct weston_view *pev = get_default_view(pes);
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04002751
Philip Withnallbecb77e2013-11-25 18:01:30 +00002752 reset_surface_type(shsurf);
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04002753
Rafael Antognolli03b16592013-12-03 15:35:42 -02002754 shsurf->state = shsurf->next_state;
Rafael Antognolli03b16592013-12-03 15:35:42 -02002755 shsurf->state_changed = false;
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04002756
2757 switch (shsurf->type) {
2758 case SHELL_SURFACE_TOPLEVEL:
Rafael Antognollied207b42013-12-03 15:35:43 -02002759 if (shsurf->state.maximized || shsurf->state.fullscreen) {
Rafael Antognolli03b16592013-12-03 15:35:42 -02002760 set_full_output(shsurf);
Rafael Antognollied207b42013-12-03 15:35:43 -02002761 } else if (shsurf->state.relative && pev) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05002762 weston_view_set_position(shsurf->view,
2763 pev->geometry.x + shsurf->transient.x,
2764 pev->geometry.y + shsurf->transient.y);
Rafael Antognollied207b42013-12-03 15:35:43 -02002765 }
Rafael Antognolli44a31622013-12-04 18:37:16 -02002766 break;
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04002767
Tiago Vignattifb2adba2013-06-12 15:43:21 -03002768 case SHELL_SURFACE_XWAYLAND:
Jason Ekstranda7af7042013-10-12 22:38:11 -05002769 weston_view_set_position(shsurf->view, shsurf->transient.x,
2770 shsurf->transient.y);
Tiago Vignattifb2adba2013-06-12 15:43:21 -03002771 break;
2772
Philip Withnall0f640e22013-11-25 18:01:31 +00002773 case SHELL_SURFACE_POPUP:
2774 case SHELL_SURFACE_NONE:
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04002775 default:
2776 break;
2777 }
Philip Withnalle1d75ae2013-11-25 18:01:41 +00002778
2779 /* Update the surface’s layer. */
2780 shell_surface_update_layer(shsurf);
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04002781}
2782
Tiago Vignattibe143262012-04-16 17:31:41 +03002783static struct desktop_shell *
Juan Zhao96879df2012-02-07 08:45:41 +08002784shell_surface_get_shell(struct shell_surface *shsurf)
Pekka Paalanenaf0e34c2011-12-02 10:59:17 +02002785{
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04002786 return shsurf->shell;
Juan Zhao96879df2012-02-07 08:45:41 +08002787}
2788
Pekka Paalanen8274d902014-08-06 19:36:51 +03002789static int
2790black_surface_get_label(struct weston_surface *surface, char *buf, size_t len)
2791{
2792 struct weston_surface *fs_surface = surface->configure_private;
2793 int n;
2794 int rem;
2795 int ret;
2796
2797 n = snprintf(buf, len, "black background surface for ");
2798 if (n < 0)
2799 return n;
2800
2801 rem = (int)len - n;
2802 if (rem < 0)
2803 rem = 0;
2804
2805 if (fs_surface->get_label)
2806 ret = fs_surface->get_label(fs_surface, buf + n, rem);
2807 else
2808 ret = snprintf(buf + n, rem, "<unknown>");
2809
2810 if (ret < 0)
2811 return n;
2812
2813 return n + ret;
2814}
2815
Alex Wu21858432012-04-01 20:13:08 +08002816static void
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06002817black_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy);
Alex Wu21858432012-04-01 20:13:08 +08002818
Jason Ekstranda7af7042013-10-12 22:38:11 -05002819static struct weston_view *
Alex Wu4539b082012-03-01 12:57:46 +08002820create_black_surface(struct weston_compositor *ec,
Alex Wu21858432012-04-01 20:13:08 +08002821 struct weston_surface *fs_surface,
John Kåre Alsaker490d02a2012-09-30 02:57:21 +02002822 float x, float y, int w, int h)
Alex Wu4539b082012-03-01 12:57:46 +08002823{
2824 struct weston_surface *surface = NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002825 struct weston_view *view;
Alex Wu4539b082012-03-01 12:57:46 +08002826
2827 surface = weston_surface_create(ec);
2828 if (surface == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002829 weston_log("no memory\n");
Alex Wu4539b082012-03-01 12:57:46 +08002830 return NULL;
2831 }
Jason Ekstranda7af7042013-10-12 22:38:11 -05002832 view = weston_view_create(surface);
2833 if (surface == NULL) {
2834 weston_log("no memory\n");
2835 weston_surface_destroy(surface);
2836 return NULL;
2837 }
Alex Wu4539b082012-03-01 12:57:46 +08002838
Alex Wu21858432012-04-01 20:13:08 +08002839 surface->configure = black_surface_configure;
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01002840 surface->configure_private = fs_surface;
Pekka Paalanen8274d902014-08-06 19:36:51 +03002841 weston_surface_set_label_func(surface, black_surface_get_label);
Alex Wu4539b082012-03-01 12:57:46 +08002842 weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1);
Pekka Paalanen71f6f3b2012-10-10 12:49:26 +03002843 pixman_region32_fini(&surface->opaque);
Kristian Høgsberg61f00f52012-08-03 16:31:36 -04002844 pixman_region32_init_rect(&surface->opaque, 0, 0, w, h);
Jonas Ådahl33619a42013-01-15 21:25:55 +01002845 pixman_region32_fini(&surface->input);
2846 pixman_region32_init_rect(&surface->input, 0, 0, w, h);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06002847
Jason Ekstrand6228ee22014-01-01 15:58:57 -06002848 weston_surface_set_size(surface, w, h);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06002849 weston_view_set_position(view, x, y);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002850
2851 return view;
Alex Wu4539b082012-03-01 12:57:46 +08002852}
2853
Philip Withnalled8f1a92013-11-25 18:01:43 +00002854static void
2855shell_ensure_fullscreen_black_view(struct shell_surface *shsurf)
2856{
2857 struct weston_output *output = shsurf->fullscreen_output;
2858
Rafael Antognolli03b16592013-12-03 15:35:42 -02002859 assert(shsurf->state.fullscreen);
Philip Withnalled8f1a92013-11-25 18:01:43 +00002860
2861 if (!shsurf->fullscreen.black_view)
2862 shsurf->fullscreen.black_view =
2863 create_black_surface(shsurf->surface->compositor,
2864 shsurf->surface,
2865 output->x, output->y,
2866 output->width,
2867 output->height);
2868
2869 weston_view_geometry_dirty(shsurf->fullscreen.black_view);
Giulio Camuffo412e6a52014-07-09 22:12:56 +03002870 weston_layer_entry_remove(&shsurf->fullscreen.black_view->layer_link);
2871 weston_layer_entry_insert(&shsurf->view->layer_link,
2872 &shsurf->fullscreen.black_view->layer_link);
Philip Withnalled8f1a92013-11-25 18:01:43 +00002873 weston_view_geometry_dirty(shsurf->fullscreen.black_view);
2874 weston_surface_damage(shsurf->surface);
Emilio Pozuelo Monfort9e7c7592014-01-30 14:01:10 +01002875
2876 shsurf->state.lowered = false;
Philip Withnalled8f1a92013-11-25 18:01:43 +00002877}
2878
Alex Wu4539b082012-03-01 12:57:46 +08002879/* Create black surface and append it to the associated fullscreen surface.
2880 * Handle size dismatch and positioning according to the method. */
2881static void
2882shell_configure_fullscreen(struct shell_surface *shsurf)
2883{
2884 struct weston_output *output = shsurf->fullscreen_output;
2885 struct weston_surface *surface = shsurf->surface;
2886 struct weston_matrix *matrix;
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04002887 float scale, output_aspect, surface_aspect, x, y;
Giulio Camuffob8366642013-04-25 13:57:46 +03002888 int32_t surf_x, surf_y, surf_width, surf_height;
Alex Wu4539b082012-03-01 12:57:46 +08002889
Alexander Larssonf82b6ca2013-05-28 16:23:39 +02002890 if (shsurf->fullscreen.type != WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER)
2891 restore_output_mode(output);
2892
Emilio Pozuelo Monfort9e7c7592014-01-30 14:01:10 +01002893 /* Reverse the effect of lower_fullscreen_layer() */
Giulio Camuffo412e6a52014-07-09 22:12:56 +03002894 weston_layer_entry_remove(&shsurf->view->layer_link);
2895 weston_layer_entry_insert(&shsurf->shell->fullscreen_layer.view_list, &shsurf->view->layer_link);
Emilio Pozuelo Monfort9e7c7592014-01-30 14:01:10 +01002896
Philip Withnalled8f1a92013-11-25 18:01:43 +00002897 shell_ensure_fullscreen_black_view(shsurf);
Alex Wu4539b082012-03-01 12:57:46 +08002898
Jason Ekstranda7af7042013-10-12 22:38:11 -05002899 surface_subsurfaces_boundingbox(shsurf->surface, &surf_x, &surf_y,
Giulio Camuffob8366642013-04-25 13:57:46 +03002900 &surf_width, &surf_height);
2901
Alex Wu4539b082012-03-01 12:57:46 +08002902 switch (shsurf->fullscreen.type) {
2903 case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT:
Pekka Paalanende685b82012-12-04 15:58:12 +02002904 if (surface->buffer_ref.buffer)
Jason Ekstranda7af7042013-10-12 22:38:11 -05002905 center_on_output(shsurf->view, shsurf->fullscreen_output);
Alex Wu4539b082012-03-01 12:57:46 +08002906 break;
2907 case WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE:
Rob Bradford9f3dd152013-02-12 11:53:47 +00002908 /* 1:1 mapping between surface and output dimensions */
Giulio Camuffob8366642013-04-25 13:57:46 +03002909 if (output->width == surf_width &&
2910 output->height == surf_height) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05002911 weston_view_set_position(shsurf->view,
2912 output->x - surf_x,
2913 output->y - surf_y);
Rob Bradford9f3dd152013-02-12 11:53:47 +00002914 break;
2915 }
2916
Alex Wu4539b082012-03-01 12:57:46 +08002917 matrix = &shsurf->fullscreen.transform.matrix;
2918 weston_matrix_init(matrix);
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04002919
Scott Moreau1bad5db2012-08-18 01:04:05 -06002920 output_aspect = (float) output->width /
2921 (float) output->height;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002922 /* XXX: Use surf_width and surf_height here? */
2923 surface_aspect = (float) surface->width /
2924 (float) surface->height;
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04002925 if (output_aspect < surface_aspect)
Scott Moreau1bad5db2012-08-18 01:04:05 -06002926 scale = (float) output->width /
Giulio Camuffob8366642013-04-25 13:57:46 +03002927 (float) surf_width;
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04002928 else
Scott Moreau1bad5db2012-08-18 01:04:05 -06002929 scale = (float) output->height /
Giulio Camuffob8366642013-04-25 13:57:46 +03002930 (float) surf_height;
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04002931
Alex Wu4539b082012-03-01 12:57:46 +08002932 weston_matrix_scale(matrix, scale, scale, 1);
2933 wl_list_remove(&shsurf->fullscreen.transform.link);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002934 wl_list_insert(&shsurf->view->geometry.transformation_list,
Alex Wu4539b082012-03-01 12:57:46 +08002935 &shsurf->fullscreen.transform.link);
Giulio Camuffob8366642013-04-25 13:57:46 +03002936 x = output->x + (output->width - surf_width * scale) / 2 - surf_x;
2937 y = output->y + (output->height - surf_height * scale) / 2 - surf_y;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002938 weston_view_set_position(shsurf->view, x, y);
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04002939
Alex Wu4539b082012-03-01 12:57:46 +08002940 break;
2941 case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER:
Alex Wubd3354b2012-04-17 17:20:49 +08002942 if (shell_surface_is_top_fullscreen(shsurf)) {
Quentin Glidicc0d79ce2013-01-29 14:16:13 +01002943 struct weston_mode mode = {0,
Pekka Paalanen952b6c82014-03-14 14:38:15 +02002944 surf_width * surface->buffer_viewport.buffer.scale,
2945 surf_height * surface->buffer_viewport.buffer.scale,
Alex Wubd3354b2012-04-17 17:20:49 +08002946 shsurf->fullscreen.framerate};
2947
Derek Foreman6ae7bc92014-11-04 10:47:33 -06002948 if (weston_output_mode_switch_to_temporary(output, &mode,
2949 surface->buffer_viewport.buffer.scale) == 0) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05002950 weston_view_set_position(shsurf->view,
2951 output->x - surf_x,
2952 output->y - surf_y);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06002953 shsurf->fullscreen.black_view->surface->width = output->width;
2954 shsurf->fullscreen.black_view->surface->height = output->height;
2955 weston_view_set_position(shsurf->fullscreen.black_view,
2956 output->x - surf_x,
2957 output->y - surf_y);
Alex Wubd3354b2012-04-17 17:20:49 +08002958 break;
Alexander Larssond622ed32013-05-28 16:23:40 +02002959 } else {
Alexander Larssonf82b6ca2013-05-28 16:23:39 +02002960 restore_output_mode(output);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002961 center_on_output(shsurf->view, output);
Alexander Larssond622ed32013-05-28 16:23:40 +02002962 }
Alex Wubd3354b2012-04-17 17:20:49 +08002963 }
Alex Wu4539b082012-03-01 12:57:46 +08002964 break;
2965 case WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL:
Jason Ekstranda7af7042013-10-12 22:38:11 -05002966 center_on_output(shsurf->view, output);
Alex Wu4539b082012-03-01 12:57:46 +08002967 break;
2968 default:
2969 break;
2970 }
2971}
2972
Alex Wu4539b082012-03-01 12:57:46 +08002973static void
2974shell_map_fullscreen(struct shell_surface *shsurf)
2975{
Alex Wubd3354b2012-04-17 17:20:49 +08002976 shell_configure_fullscreen(shsurf);
Alex Wu4539b082012-03-01 12:57:46 +08002977}
2978
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04002979static void
Tiago Vignattifb2adba2013-06-12 15:43:21 -03002980set_xwayland(struct shell_surface *shsurf, int x, int y, uint32_t flags)
2981{
2982 /* XXX: using the same fields for transient type */
Rafael Antognolli03b16592013-12-03 15:35:42 -02002983 surface_clear_next_states(shsurf);
Tiago Vignattifb2adba2013-06-12 15:43:21 -03002984 shsurf->transient.x = x;
2985 shsurf->transient.y = y;
2986 shsurf->transient.flags = flags;
Philip Withnalldc4332f2013-11-25 18:01:38 +00002987
2988 shell_surface_set_parent(shsurf, NULL);
2989
Pekka Paalanenb5026542014-11-12 15:09:24 +02002990 set_type(shsurf, SHELL_SURFACE_XWAYLAND);
Kristian Høgsberg8bc525c2014-01-01 22:34:49 -08002991 shsurf->state_changed = true;
Tiago Vignattifb2adba2013-06-12 15:43:21 -03002992}
2993
Kristian Høgsberg47792412014-05-04 13:47:06 -07002994static void
2995shell_interface_set_fullscreen(struct shell_surface *shsurf,
2996 uint32_t method,
2997 uint32_t framerate,
2998 struct weston_output *output)
2999{
3000 surface_clear_next_states(shsurf);
Kristian Høgsberg47792412014-05-04 13:47:06 -07003001 shsurf->next_state.fullscreen = true;
3002 shsurf->state_changed = true;
Marek Chalupae9fe4672014-10-29 13:44:44 +01003003
3004 set_fullscreen(shsurf, method, framerate, output);
Kristian Høgsberg47792412014-05-04 13:47:06 -07003005}
3006
Giulio Camuffo6b4b2412015-01-29 19:06:49 +02003007static struct weston_output *
3008get_focused_output(struct weston_compositor *compositor)
3009{
3010 struct weston_seat *seat;
3011 struct weston_output *output = NULL;
3012
3013 wl_list_for_each(seat, &compositor->seat_list, link) {
3014 /* Priority has touch focus, then pointer and
3015 * then keyboard focus. We should probably have
3016 * three for loops and check frist for touch,
3017 * then for pointer, etc. but unless somebody has some
3018 * objections, I think this is sufficient. */
3019 if (seat->touch && seat->touch->focus)
3020 output = seat->touch->focus->output;
3021 else if (seat->pointer && seat->pointer->focus)
3022 output = seat->pointer->focus->output;
3023 else if (seat->keyboard && seat->keyboard->focus)
3024 output = seat->keyboard->focus->output;
3025
3026 if (output)
3027 break;
3028 }
3029
3030 return output;
3031}
3032
3033static void
3034shell_interface_set_maximized(struct shell_surface *shsurf)
3035{
3036 struct weston_output *output;
3037
3038 surface_clear_next_states(shsurf);
3039 shsurf->next_state.maximized = true;
3040 shsurf->state_changed = true;
3041 shsurf->type = SHELL_SURFACE_TOPLEVEL;
3042
3043 if (!weston_surface_is_mapped(shsurf->surface))
3044 output = get_focused_output(shsurf->surface->compositor);
3045 else
3046 output = shsurf->surface->output;
3047
3048 shell_surface_set_output(shsurf, output);
3049 send_configure_for_surface(shsurf);
3050}
3051
Kristian Høgsbergae356ae2014-04-29 16:03:54 -07003052static int
3053shell_interface_move(struct shell_surface *shsurf, struct weston_seat *ws)
3054{
3055 return surface_move(shsurf, ws, 1);
3056}
3057
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04003058static const struct weston_pointer_grab_interface popup_grab_interface;
Giulio Camuffo5085a752013-03-25 21:42:45 +01003059
3060static void
3061destroy_shell_seat(struct wl_listener *listener, void *data)
3062{
3063 struct shell_seat *shseat =
3064 container_of(listener,
3065 struct shell_seat, seat_destroy_listener);
Jonas Ådahlc2b10112015-02-13 14:01:53 +08003066 struct shell_surface *shsurf, *next;
Giulio Camuffo5085a752013-03-25 21:42:45 +01003067
3068 if (shseat->popup_grab.grab.interface == &popup_grab_interface) {
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04003069 weston_pointer_end_grab(shseat->popup_grab.grab.pointer);
Giulio Camuffo5085a752013-03-25 21:42:45 +01003070 shseat->popup_grab.client = NULL;
3071
Jonas Ådahlc2b10112015-02-13 14:01:53 +08003072 wl_list_for_each_safe(shsurf, next,
3073 &shseat->popup_grab.surfaces_list,
3074 popup.grab_link) {
Giulio Camuffo5085a752013-03-25 21:42:45 +01003075 shsurf->popup.shseat = NULL;
Jonas Ådahlc2b10112015-02-13 14:01:53 +08003076 wl_list_init(&shsurf->popup.grab_link);
Giulio Camuffo5085a752013-03-25 21:42:45 +01003077 }
Giulio Camuffo5085a752013-03-25 21:42:45 +01003078 }
3079
3080 wl_list_remove(&shseat->seat_destroy_listener.link);
3081 free(shseat);
3082}
3083
Jason Ekstrand024177c2014-04-21 19:42:58 -05003084static void
3085shell_seat_caps_changed(struct wl_listener *listener, void *data)
3086{
3087 struct shell_seat *seat;
3088
3089 seat = container_of(listener, struct shell_seat, caps_changed_listener);
3090
3091 if (seat->seat->keyboard &&
3092 wl_list_empty(&seat->keyboard_focus_listener.link)) {
3093 wl_signal_add(&seat->seat->keyboard->focus_signal,
3094 &seat->keyboard_focus_listener);
3095 } else if (!seat->seat->keyboard) {
3096 wl_list_init(&seat->keyboard_focus_listener.link);
3097 }
3098
3099 if (seat->seat->pointer &&
3100 wl_list_empty(&seat->pointer_focus_listener.link)) {
3101 wl_signal_add(&seat->seat->pointer->focus_signal,
3102 &seat->pointer_focus_listener);
3103 } else if (!seat->seat->pointer) {
3104 wl_list_init(&seat->pointer_focus_listener.link);
3105 }
3106}
3107
Giulio Camuffo5085a752013-03-25 21:42:45 +01003108static struct shell_seat *
3109create_shell_seat(struct weston_seat *seat)
3110{
3111 struct shell_seat *shseat;
3112
3113 shseat = calloc(1, sizeof *shseat);
3114 if (!shseat) {
3115 weston_log("no memory to allocate shell seat\n");
3116 return NULL;
3117 }
3118
3119 shseat->seat = seat;
3120 wl_list_init(&shseat->popup_grab.surfaces_list);
3121
3122 shseat->seat_destroy_listener.notify = destroy_shell_seat;
3123 wl_signal_add(&seat->destroy_signal,
3124 &shseat->seat_destroy_listener);
3125
Jason Ekstrand024177c2014-04-21 19:42:58 -05003126 shseat->keyboard_focus_listener.notify = handle_keyboard_focus;
3127 wl_list_init(&shseat->keyboard_focus_listener.link);
3128
3129 shseat->pointer_focus_listener.notify = handle_pointer_focus;
3130 wl_list_init(&shseat->pointer_focus_listener.link);
3131
3132 shseat->caps_changed_listener.notify = shell_seat_caps_changed;
3133 wl_signal_add(&seat->updated_caps_signal,
3134 &shseat->caps_changed_listener);
3135 shell_seat_caps_changed(&shseat->caps_changed_listener, NULL);
3136
Giulio Camuffo5085a752013-03-25 21:42:45 +01003137 return shseat;
3138}
3139
3140static struct shell_seat *
3141get_shell_seat(struct weston_seat *seat)
3142{
3143 struct wl_listener *listener;
3144
3145 listener = wl_signal_get(&seat->destroy_signal, destroy_shell_seat);
Jason Ekstrand024177c2014-04-21 19:42:58 -05003146 assert(listener != NULL);
Giulio Camuffo5085a752013-03-25 21:42:45 +01003147
3148 return container_of(listener,
3149 struct shell_seat, seat_destroy_listener);
3150}
3151
Kristian Høgsbergb810eb52013-02-12 20:07:05 -05003152static void
Kristian Høgsberg6848c252013-05-08 22:02:59 -04003153popup_grab_focus(struct weston_pointer_grab *grab)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05003154{
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04003155 struct weston_pointer *pointer = grab->pointer;
Jason Ekstranda7af7042013-10-12 22:38:11 -05003156 struct weston_view *view;
Giulio Camuffo5085a752013-03-25 21:42:45 +01003157 struct shell_seat *shseat =
3158 container_of(grab, struct shell_seat, popup_grab.grab);
3159 struct wl_client *client = shseat->popup_grab.client;
Kristian Høgsberg6848c252013-05-08 22:02:59 -04003160 wl_fixed_t sx, sy;
3161
Jason Ekstranda7af7042013-10-12 22:38:11 -05003162 view = weston_compositor_pick_view(pointer->seat->compositor,
3163 pointer->x, pointer->y,
3164 &sx, &sy);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05003165
Jason Ekstranda7af7042013-10-12 22:38:11 -05003166 if (view && view->surface->resource &&
3167 wl_resource_get_client(view->surface->resource) == client) {
3168 weston_pointer_set_focus(pointer, view, sx, sy);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05003169 } else {
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04003170 weston_pointer_set_focus(pointer, NULL,
3171 wl_fixed_from_int(0),
3172 wl_fixed_from_int(0));
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05003173 }
3174}
3175
3176static void
Giulio Camuffo1959ab82013-11-14 23:42:52 +01003177popup_grab_motion(struct weston_pointer_grab *grab, uint32_t time,
3178 wl_fixed_t x, wl_fixed_t y)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05003179{
Kristian Høgsbergbe6403e2013-05-08 21:03:21 -04003180 struct weston_pointer *pointer = grab->pointer;
Neil Roberts96d790e2013-09-19 17:32:00 +01003181 struct wl_resource *resource;
Kristian Høgsbergbe6403e2013-05-08 21:03:21 -04003182 wl_fixed_t sx, sy;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05003183
Jonas Ådahl61917c82014-08-11 22:44:02 +02003184 if (pointer->focus) {
3185 weston_view_from_global_fixed(pointer->focus, x, y,
3186 &pointer->sx, &pointer->sy);
3187 }
3188
Giulio Camuffo1959ab82013-11-14 23:42:52 +01003189 weston_pointer_move(pointer, x, y);
3190
Neil Roberts96d790e2013-09-19 17:32:00 +01003191 wl_resource_for_each(resource, &pointer->focus_resource_list) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05003192 weston_view_from_global_fixed(pointer->focus,
3193 pointer->x, pointer->y,
3194 &sx, &sy);
Neil Roberts96d790e2013-09-19 17:32:00 +01003195 wl_pointer_send_motion(resource, time, sx, sy);
Kristian Høgsbergbe6403e2013-05-08 21:03:21 -04003196 }
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05003197}
3198
3199static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04003200popup_grab_button(struct weston_pointer_grab *grab,
Daniel Stone4dbadb12012-05-30 16:31:51 +01003201 uint32_t time, uint32_t button, uint32_t state_w)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05003202{
3203 struct wl_resource *resource;
Giulio Camuffo5085a752013-03-25 21:42:45 +01003204 struct shell_seat *shseat =
3205 container_of(grab, struct shell_seat, popup_grab.grab);
Rob Bradford880ebc72013-07-22 17:31:38 +01003206 struct wl_display *display = shseat->seat->compositor->wl_display;
Daniel Stone4dbadb12012-05-30 16:31:51 +01003207 enum wl_pointer_button_state state = state_w;
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04003208 uint32_t serial;
Neil Roberts96d790e2013-09-19 17:32:00 +01003209 struct wl_list *resource_list;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05003210
Neil Roberts96d790e2013-09-19 17:32:00 +01003211 resource_list = &grab->pointer->focus_resource_list;
3212 if (!wl_list_empty(resource_list)) {
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04003213 serial = wl_display_get_serial(display);
Neil Roberts96d790e2013-09-19 17:32:00 +01003214 wl_resource_for_each(resource, resource_list) {
3215 wl_pointer_send_button(resource, serial,
3216 time, button, state);
3217 }
Daniel Stone4dbadb12012-05-30 16:31:51 +01003218 } else if (state == WL_POINTER_BUTTON_STATE_RELEASED &&
Giulio Camuffo5085a752013-03-25 21:42:45 +01003219 (shseat->popup_grab.initial_up ||
Kristian Høgsberge3148752013-05-06 23:19:49 -04003220 time - shseat->seat->pointer->grab_time > 500)) {
Kristian Høgsberg57e09072012-10-30 14:07:27 -04003221 popup_grab_end(grab->pointer);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05003222 }
3223
Daniel Stone4dbadb12012-05-30 16:31:51 +01003224 if (state == WL_POINTER_BUTTON_STATE_RELEASED)
Giulio Camuffo5085a752013-03-25 21:42:45 +01003225 shseat->popup_grab.initial_up = 1;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05003226}
3227
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02003228static void
3229popup_grab_cancel(struct weston_pointer_grab *grab)
3230{
3231 popup_grab_end(grab->pointer);
3232}
3233
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04003234static const struct weston_pointer_grab_interface popup_grab_interface = {
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05003235 popup_grab_focus,
3236 popup_grab_motion,
3237 popup_grab_button,
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02003238 popup_grab_cancel,
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05003239};
3240
3241static void
Jonny Lamb76cf1fe2014-08-20 11:27:10 +02003242touch_popup_grab_down(struct weston_touch_grab *grab, uint32_t time,
3243 int touch_id, wl_fixed_t sx, wl_fixed_t sy)
3244{
3245 struct wl_resource *resource;
3246 struct shell_seat *shseat =
3247 container_of(grab, struct shell_seat, popup_grab.touch_grab);
3248 struct wl_display *display = shseat->seat->compositor->wl_display;
3249 uint32_t serial;
3250 struct wl_list *resource_list;
3251
3252 resource_list = &grab->touch->focus_resource_list;
3253 if (!wl_list_empty(resource_list)) {
3254 serial = wl_display_get_serial(display);
3255 wl_resource_for_each(resource, resource_list) {
3256 wl_touch_send_down(resource, serial, time,
3257 grab->touch->focus->surface->resource,
3258 touch_id, sx, sy);
3259 }
3260 }
3261}
3262
3263static void
3264touch_popup_grab_up(struct weston_touch_grab *grab, uint32_t time, int touch_id)
3265{
3266 struct wl_resource *resource;
3267 struct shell_seat *shseat =
3268 container_of(grab, struct shell_seat, popup_grab.touch_grab);
3269 struct wl_display *display = shseat->seat->compositor->wl_display;
3270 uint32_t serial;
3271 struct wl_list *resource_list;
3272
3273 resource_list = &grab->touch->focus_resource_list;
3274 if (!wl_list_empty(resource_list)) {
3275 serial = wl_display_get_serial(display);
3276 wl_resource_for_each(resource, resource_list) {
3277 wl_touch_send_up(resource, serial, time, touch_id);
3278 }
3279 }
3280}
3281
3282static void
3283touch_popup_grab_motion(struct weston_touch_grab *grab, uint32_t time,
3284 int touch_id, wl_fixed_t sx, wl_fixed_t sy)
3285{
3286 struct wl_resource *resource;
3287 struct wl_list *resource_list;
3288
3289 resource_list = &grab->touch->focus_resource_list;
3290 if (!wl_list_empty(resource_list)) {
3291 wl_resource_for_each(resource, resource_list) {
3292 wl_touch_send_motion(resource, time, touch_id, sx, sy);
3293 }
3294 }
3295}
3296
3297static void
3298touch_popup_grab_frame(struct weston_touch_grab *grab)
3299{
3300}
3301
3302static void
3303touch_popup_grab_cancel(struct weston_touch_grab *grab)
3304{
3305 touch_popup_grab_end(grab->touch);
3306}
3307
3308static const struct weston_touch_grab_interface touch_popup_grab_interface = {
3309 touch_popup_grab_down,
3310 touch_popup_grab_up,
3311 touch_popup_grab_motion,
3312 touch_popup_grab_frame,
3313 touch_popup_grab_cancel,
3314};
3315
3316static void
Rafael Antognollie2a34552013-12-03 15:35:45 -02003317shell_surface_send_popup_done(struct shell_surface *shsurf)
3318{
3319 if (shell_surface_is_wl_shell_surface(shsurf))
3320 wl_shell_surface_send_popup_done(shsurf->resource);
3321 else if (shell_surface_is_xdg_popup(shsurf))
Jasper St. Pierreecf2a0f2015-02-13 14:01:56 +08003322 xdg_popup_send_popup_done(shsurf->resource);
Rafael Antognollie2a34552013-12-03 15:35:45 -02003323}
3324
3325static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04003326popup_grab_end(struct weston_pointer *pointer)
Kristian Høgsberg57e09072012-10-30 14:07:27 -04003327{
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04003328 struct weston_pointer_grab *grab = pointer->grab;
Giulio Camuffo5085a752013-03-25 21:42:45 +01003329 struct shell_seat *shseat =
3330 container_of(grab, struct shell_seat, popup_grab.grab);
3331 struct shell_surface *shsurf;
Jonas Ådahlc2b10112015-02-13 14:01:53 +08003332 struct shell_surface *next;
Kristian Høgsberg57e09072012-10-30 14:07:27 -04003333
3334 if (pointer->grab->interface == &popup_grab_interface) {
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04003335 weston_pointer_end_grab(grab->pointer);
Giulio Camuffo5085a752013-03-25 21:42:45 +01003336 shseat->popup_grab.client = NULL;
Philipp Brüschweiler63e7be62013-04-15 21:09:54 +02003337 shseat->popup_grab.grab.interface = NULL;
3338 assert(!wl_list_empty(&shseat->popup_grab.surfaces_list));
Giulio Camuffo5085a752013-03-25 21:42:45 +01003339 /* Send the popup_done event to all the popups open */
Jonas Ådahlc2b10112015-02-13 14:01:53 +08003340 wl_list_for_each_safe(shsurf, next,
3341 &shseat->popup_grab.surfaces_list,
3342 popup.grab_link) {
Rafael Antognollie2a34552013-12-03 15:35:45 -02003343 shell_surface_send_popup_done(shsurf);
Giulio Camuffo5085a752013-03-25 21:42:45 +01003344 shsurf->popup.shseat = NULL;
Jonas Ådahlc2b10112015-02-13 14:01:53 +08003345 wl_list_init(&shsurf->popup.grab_link);
Giulio Camuffo5085a752013-03-25 21:42:45 +01003346 }
Giulio Camuffo5085a752013-03-25 21:42:45 +01003347 wl_list_init(&shseat->popup_grab.surfaces_list);
3348 }
3349}
3350
3351static void
Jonny Lamb76cf1fe2014-08-20 11:27:10 +02003352touch_popup_grab_end(struct weston_touch *touch)
3353{
3354 struct weston_touch_grab *grab = touch->grab;
3355 struct shell_seat *shseat =
3356 container_of(grab, struct shell_seat, popup_grab.touch_grab);
3357 struct shell_surface *shsurf;
Jonas Ådahlc2b10112015-02-13 14:01:53 +08003358 struct shell_surface *next;
Jonny Lamb76cf1fe2014-08-20 11:27:10 +02003359
3360 if (touch->grab->interface == &touch_popup_grab_interface) {
3361 weston_touch_end_grab(grab->touch);
3362 shseat->popup_grab.client = NULL;
3363 shseat->popup_grab.touch_grab.interface = NULL;
3364 assert(!wl_list_empty(&shseat->popup_grab.surfaces_list));
3365 /* Send the popup_done event to all the popups open */
Jonas Ådahlc2b10112015-02-13 14:01:53 +08003366 wl_list_for_each_safe(shsurf, next,
3367 &shseat->popup_grab.surfaces_list,
3368 popup.grab_link) {
Jonny Lamb76cf1fe2014-08-20 11:27:10 +02003369 shell_surface_send_popup_done(shsurf);
3370 shsurf->popup.shseat = NULL;
Jonas Ådahlc2b10112015-02-13 14:01:53 +08003371 wl_list_init(&shsurf->popup.grab_link);
Jonny Lamb76cf1fe2014-08-20 11:27:10 +02003372 }
Jonny Lamb76cf1fe2014-08-20 11:27:10 +02003373 wl_list_init(&shseat->popup_grab.surfaces_list);
3374 }
3375}
3376
Jasper St. Pierreda6ecd02015-02-27 18:35:45 +08003377static struct shell_surface *
3378get_top_popup(struct shell_seat *shseat)
3379{
3380 struct shell_surface *shsurf;
3381
3382 if (wl_list_empty(&shseat->popup_grab.surfaces_list)) {
3383 return NULL;
3384 } else {
3385 shsurf = container_of(shseat->popup_grab.surfaces_list.next,
3386 struct shell_surface,
3387 popup.grab_link);
3388 return shsurf;
3389 }
3390}
3391
3392static int
Jonas Ådahl01193ae2015-02-13 14:01:54 +08003393add_popup_grab(struct shell_surface *shsurf,
3394 struct shell_seat *shseat,
3395 int32_t type)
Giulio Camuffo5085a752013-03-25 21:42:45 +01003396{
Kristian Høgsberge3148752013-05-06 23:19:49 -04003397 struct weston_seat *seat = shseat->seat;
Jasper St. Pierreda6ecd02015-02-27 18:35:45 +08003398 struct shell_surface *parent, *top_surface;
3399
3400 parent = get_shell_surface(shsurf->parent);
3401 top_surface = get_top_popup(shseat);
3402 if (shell_surface_is_xdg_popup(shsurf) &&
Dima Ryazanov497f25d2015-04-08 11:51:57 -07003403 (!parent ||
3404 (top_surface == NULL && !shell_surface_is_xdg_surface(parent)) ||
Jasper St. Pierreda6ecd02015-02-27 18:35:45 +08003405 (top_surface != NULL && parent != top_surface))) {
Jonas Ådahlee45a552015-03-18 16:37:47 +08003406 wl_resource_post_error(shsurf->owner_resource,
3407 XDG_SHELL_ERROR_NOT_THE_TOPMOST_POPUP,
Jasper St. Pierreda6ecd02015-02-27 18:35:45 +08003408 "xdg_popup was not created on the "
3409 "topmost popup");
3410 return -1;
3411 }
Giulio Camuffo5085a752013-03-25 21:42:45 +01003412
3413 if (wl_list_empty(&shseat->popup_grab.surfaces_list)) {
Jonny Lamb76cf1fe2014-08-20 11:27:10 +02003414 shseat->popup_grab.type = type;
Jonas Ådahl01193ae2015-02-13 14:01:54 +08003415 shseat->popup_grab.client =
3416 wl_resource_get_client(shsurf->resource);
Jonny Lamb76cf1fe2014-08-20 11:27:10 +02003417
3418 if (type == POINTER) {
Jonas Ådahl01193ae2015-02-13 14:01:54 +08003419 shseat->popup_grab.grab.interface =
3420 &popup_grab_interface;
3421
3422 /* We must make sure here that this popup was opened
3423 * after a mouse press, and not just by moving around
3424 * with other popups already open. */
Jonny Lamb76cf1fe2014-08-20 11:27:10 +02003425 if (shseat->seat->pointer->button_count > 0)
3426 shseat->popup_grab.initial_up = 0;
3427 } else if (type == TOUCH) {
Jonas Ådahl01193ae2015-02-13 14:01:54 +08003428 shseat->popup_grab.touch_grab.interface =
3429 &touch_popup_grab_interface;
Jonny Lamb76cf1fe2014-08-20 11:27:10 +02003430 }
Giulio Camuffo5085a752013-03-25 21:42:45 +01003431
Jonas Ådahl01193ae2015-02-13 14:01:54 +08003432 wl_list_insert(&shseat->popup_grab.surfaces_list,
3433 &shsurf->popup.grab_link);
Jonny Lamb76cf1fe2014-08-20 11:27:10 +02003434
Jonas Ådahl01193ae2015-02-13 14:01:54 +08003435 if (type == POINTER) {
3436 weston_pointer_start_grab(seat->pointer,
3437 &shseat->popup_grab.grab);
3438 } else if (type == TOUCH) {
3439 weston_touch_start_grab(seat->touch,
3440 &shseat->popup_grab.touch_grab);
3441 }
Rob Bradforddfe31052013-06-26 19:49:11 +01003442 } else {
Jonas Ådahl01193ae2015-02-13 14:01:54 +08003443 wl_list_insert(&shseat->popup_grab.surfaces_list,
3444 &shsurf->popup.grab_link);
Giulio Camuffo5085a752013-03-25 21:42:45 +01003445 }
Jasper St. Pierreda6ecd02015-02-27 18:35:45 +08003446
3447 return 0;
Giulio Camuffo5085a752013-03-25 21:42:45 +01003448}
3449
3450static void
3451remove_popup_grab(struct shell_surface *shsurf)
3452{
3453 struct shell_seat *shseat = shsurf->popup.shseat;
3454
Jasper St. Pierreda6ecd02015-02-27 18:35:45 +08003455 if (shell_surface_is_xdg_popup(shsurf) &&
3456 get_top_popup(shseat) != shsurf) {
Jonas Ådahlee45a552015-03-18 16:37:47 +08003457 wl_resource_post_error(shsurf->owner_resource,
3458 XDG_SHELL_ERROR_NOT_THE_TOPMOST_POPUP,
Jasper St. Pierreda6ecd02015-02-27 18:35:45 +08003459 "xdg_popup was destroyed while it was "
3460 "not the topmost popup.");
3461 return;
3462 }
3463
Giulio Camuffo5085a752013-03-25 21:42:45 +01003464 wl_list_remove(&shsurf->popup.grab_link);
3465 wl_list_init(&shsurf->popup.grab_link);
3466 if (wl_list_empty(&shseat->popup_grab.surfaces_list)) {
Jonny Lamb76cf1fe2014-08-20 11:27:10 +02003467 if (shseat->popup_grab.type == POINTER) {
3468 weston_pointer_end_grab(shseat->popup_grab.grab.pointer);
3469 shseat->popup_grab.grab.interface = NULL;
3470 } else if (shseat->popup_grab.type == TOUCH) {
3471 weston_touch_end_grab(shseat->popup_grab.touch_grab.touch);
3472 shseat->popup_grab.touch_grab.interface = NULL;
3473 }
Kristian Høgsberg57e09072012-10-30 14:07:27 -04003474 }
3475}
3476
Jasper St. Pierreda6ecd02015-02-27 18:35:45 +08003477static int
Kristian Høgsberg3730f362012-04-13 12:40:07 -04003478shell_map_popup(struct shell_surface *shsurf)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05003479{
Giulio Camuffo5085a752013-03-25 21:42:45 +01003480 struct shell_seat *shseat = shsurf->popup.shseat;
Jason Ekstranda7af7042013-10-12 22:38:11 -05003481 struct weston_view *parent_view = get_default_view(shsurf->parent);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05003482
Jason Ekstranda7af7042013-10-12 22:38:11 -05003483 shsurf->surface->output = parent_view->output;
3484 shsurf->view->output = parent_view->output;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05003485
Jason Ekstranda7af7042013-10-12 22:38:11 -05003486 weston_view_set_transform_parent(shsurf->view, parent_view);
3487 weston_view_set_position(shsurf->view, shsurf->popup.x, shsurf->popup.y);
3488 weston_view_update_transform(shsurf->view);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05003489
Jonny Lambe84ab4e2014-08-06 11:50:12 +02003490 if (shseat->seat->pointer &&
3491 shseat->seat->pointer->grab_serial == shsurf->popup.serial) {
Jasper St. Pierreda6ecd02015-02-27 18:35:45 +08003492 if (add_popup_grab(shsurf, shseat, POINTER) != 0)
3493 return -1;
Jonny Lamb76cf1fe2014-08-20 11:27:10 +02003494 } else if (shseat->seat->touch &&
3495 shseat->seat->touch->grab_serial == shsurf->popup.serial) {
Jasper St. Pierreda6ecd02015-02-27 18:35:45 +08003496 if (add_popup_grab(shsurf, shseat, TOUCH) != 0)
3497 return -1;
Kristian Høgsberg3730f362012-04-13 12:40:07 -04003498 } else {
Rafael Antognollie2a34552013-12-03 15:35:45 -02003499 shell_surface_send_popup_done(shsurf);
Giulio Camuffo5085a752013-03-25 21:42:45 +01003500 shseat->popup_grab.client = NULL;
Kristian Høgsberg3730f362012-04-13 12:40:07 -04003501 }
Jasper St. Pierreda6ecd02015-02-27 18:35:45 +08003502
3503 return 0;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05003504}
3505
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003506static const struct wl_shell_surface_interface shell_surface_implementation = {
Scott Moreauff1db4a2012-04-17 19:06:18 -06003507 shell_surface_pong,
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003508 shell_surface_move,
3509 shell_surface_resize,
3510 shell_surface_set_toplevel,
3511 shell_surface_set_transient,
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05003512 shell_surface_set_fullscreen,
Juan Zhao96879df2012-02-07 08:45:41 +08003513 shell_surface_set_popup,
Kristian Høgsberge7afd912012-05-02 09:47:44 -04003514 shell_surface_set_maximized,
3515 shell_surface_set_title,
3516 shell_surface_set_class
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003517};
3518
3519static void
Tiago Vignattibc052c92012-04-19 16:18:18 +03003520destroy_shell_surface(struct shell_surface *shsurf)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003521{
Kristian Høgsberg9046d242014-01-10 00:25:30 -08003522 struct shell_surface *child, *next;
3523
Jason Ekstrand651f00e2013-06-14 10:07:54 -05003524 wl_signal_emit(&shsurf->destroy_signal, shsurf);
3525
Giulio Camuffo5085a752013-03-25 21:42:45 +01003526 if (!wl_list_empty(&shsurf->popup.grab_link)) {
3527 remove_popup_grab(shsurf);
3528 }
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05003529
Alex Wubd3354b2012-04-17 17:20:49 +08003530 if (shsurf->fullscreen.type == WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER &&
Alexander Larssonf82b6ca2013-05-28 16:23:39 +02003531 shell_surface_is_top_fullscreen(shsurf))
3532 restore_output_mode (shsurf->fullscreen_output);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003533
Jason Ekstranda7af7042013-10-12 22:38:11 -05003534 if (shsurf->fullscreen.black_view)
3535 weston_surface_destroy(shsurf->fullscreen.black_view->surface);
Alex Wuaa08e2d2012-03-05 11:01:40 +08003536
Alex Wubd3354b2012-04-17 17:20:49 +08003537 /* As destroy_resource() use wl_list_for_each_safe(),
3538 * we can always remove the listener.
3539 */
3540 wl_list_remove(&shsurf->surface_destroy_listener.link);
3541 shsurf->surface->configure = NULL;
Pekka Paalanen8274d902014-08-06 19:36:51 +03003542 weston_surface_set_label_func(shsurf->surface, NULL);
Scott Moreau976a0502013-03-07 10:15:17 -07003543 free(shsurf->title);
Alex Wubd3354b2012-04-17 17:20:49 +08003544
Jason Ekstranda7af7042013-10-12 22:38:11 -05003545 weston_view_destroy(shsurf->view);
3546
Philip Withnall648a4dd2013-11-25 18:01:44 +00003547 wl_list_remove(&shsurf->children_link);
Emilio Pozuelo Monfortadaa20c2014-01-28 13:54:16 +01003548 wl_list_for_each_safe(child, next, &shsurf->children_list, children_link)
3549 shell_surface_set_parent(child, NULL);
Philip Withnall648a4dd2013-11-25 18:01:44 +00003550
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003551 wl_list_remove(&shsurf->link);
3552 free(shsurf);
3553}
3554
3555static void
Tiago Vignattibc052c92012-04-19 16:18:18 +03003556shell_destroy_shell_surface(struct wl_resource *resource)
3557{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05003558 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
Tiago Vignattibc052c92012-04-19 16:18:18 +03003559
Bryan Caina46b9462014-04-04 17:41:24 -05003560 if (!wl_list_empty(&shsurf->popup.grab_link))
3561 remove_popup_grab(shsurf);
Jonas Ådahl49d77d22015-03-18 16:20:51 +08003562 wl_list_remove(wl_resource_get_link(shsurf->resource));
Kristian Høgsberg160fe752014-03-11 10:19:10 -07003563 shsurf->resource = NULL;
Tiago Vignattibc052c92012-04-19 16:18:18 +03003564}
3565
3566static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04003567shell_handle_surface_destroy(struct wl_listener *listener, void *data)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003568{
3569 struct shell_surface *shsurf = container_of(listener,
3570 struct shell_surface,
3571 surface_destroy_listener);
3572
Jason Ekstrand651f00e2013-06-14 10:07:54 -05003573 if (shsurf->resource)
3574 wl_resource_destroy(shsurf->resource);
Ander Conselvan de Oliveira15f9a262014-04-29 17:54:02 +03003575
3576 destroy_shell_surface(shsurf);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003577}
3578
Kristian Høgsbergd8134452012-06-21 12:49:02 -04003579static void
Derek Foreman039e9be2015-04-14 17:09:06 -05003580fade_out_done_idle_cb(void *data)
Kristian Høgsberg160fe752014-03-11 10:19:10 -07003581{
3582 struct shell_surface *shsurf = data;
3583
3584 weston_surface_destroy(shsurf->surface);
3585}
3586
3587static void
Derek Foreman039e9be2015-04-14 17:09:06 -05003588fade_out_done(struct weston_view_animation *animation, void *data)
3589{
3590 struct shell_surface *shsurf = data;
3591 struct wl_event_loop *loop;
3592
3593 loop = wl_display_get_event_loop(
3594 shsurf->surface->compositor->wl_display);
3595
3596 if (!shsurf->destroying) {
3597 wl_event_loop_add_idle(loop, fade_out_done_idle_cb, shsurf);
3598 shsurf->destroying = true;
3599 }
3600}
3601
3602static void
Kristian Høgsberg160fe752014-03-11 10:19:10 -07003603handle_resource_destroy(struct wl_listener *listener, void *data)
3604{
3605 struct shell_surface *shsurf =
3606 container_of(listener, struct shell_surface,
3607 resource_destroy_listener);
3608
Ander Conselvan de Oliveira15f9a262014-04-29 17:54:02 +03003609 if (!weston_surface_is_mapped(shsurf->surface))
3610 return;
3611
Kristian Høgsberg160fe752014-03-11 10:19:10 -07003612 shsurf->surface->ref_count++;
3613
3614 pixman_region32_fini(&shsurf->surface->pending.input);
3615 pixman_region32_init(&shsurf->surface->pending.input);
3616 pixman_region32_fini(&shsurf->surface->input);
3617 pixman_region32_init(&shsurf->surface->input);
Jonny Lambf322f8e2014-08-12 15:13:30 +02003618 if (shsurf->shell->win_close_animation_type == ANIMATION_FADE) {
3619 weston_fade_run(shsurf->view, 1.0, 0.0, 300.0,
3620 fade_out_done, shsurf);
3621 } else {
3622 weston_surface_destroy(shsurf->surface);
3623 }
Kristian Høgsberg160fe752014-03-11 10:19:10 -07003624}
3625
3626static void
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06003627shell_surface_configure(struct weston_surface *, int32_t, int32_t);
Kristian Høgsbergd8134452012-06-21 12:49:02 -04003628
Kristian Høgsberg1ef23132013-12-04 00:20:01 -08003629struct shell_surface *
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05003630get_shell_surface(struct weston_surface *surface)
Pekka Paalanenec2b32f2011-11-28 15:12:34 +02003631{
Kristian Høgsbergd8134452012-06-21 12:49:02 -04003632 if (surface->configure == shell_surface_configure)
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01003633 return surface->configure_private;
Kristian Høgsbergd8134452012-06-21 12:49:02 -04003634 else
3635 return NULL;
Pekka Paalanenec2b32f2011-11-28 15:12:34 +02003636}
3637
Rafael Antognollie2a34552013-12-03 15:35:45 -02003638static struct shell_surface *
Jason Ekstrand9e9512f2014-04-16 21:12:10 -05003639create_common_surface(struct shell_client *owner, void *shell,
3640 struct weston_surface *surface,
Rafael Antognollie2a34552013-12-03 15:35:45 -02003641 const struct weston_shell_client *client)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003642{
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003643 struct shell_surface *shsurf;
3644
Pekka Paalanen50b67472014-10-01 15:02:41 +03003645 assert(surface->configure == NULL);
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03003646
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003647 shsurf = calloc(1, sizeof *shsurf);
3648 if (!shsurf) {
Martin Minarik6d118362012-06-07 18:01:59 +02003649 weston_log("no memory to allocate shell surface\n");
Kristian Høgsberg45ba8692012-05-21 14:27:33 -04003650 return NULL;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003651 }
3652
Jason Ekstranda7af7042013-10-12 22:38:11 -05003653 shsurf->view = weston_view_create(surface);
3654 if (!shsurf->view) {
3655 weston_log("no memory to allocate shell surface\n");
3656 free(shsurf);
3657 return NULL;
3658 }
3659
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03003660 surface->configure = shell_surface_configure;
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01003661 surface->configure_private = shsurf;
Pekka Paalanen8274d902014-08-06 19:36:51 +03003662 weston_surface_set_label_func(surface, shell_surface_get_label);
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03003663
Kristian Høgsberg160fe752014-03-11 10:19:10 -07003664 shsurf->resource_destroy_listener.notify = handle_resource_destroy;
3665 wl_resource_add_destroy_listener(surface->resource,
3666 &shsurf->resource_destroy_listener);
Jason Ekstrand9e9512f2014-04-16 21:12:10 -05003667 shsurf->owner = owner;
Kristian Høgsberg160fe752014-03-11 10:19:10 -07003668
Tiago Vignattibc052c92012-04-19 16:18:18 +03003669 shsurf->shell = (struct desktop_shell *) shell;
Scott Moreauff1db4a2012-04-17 19:06:18 -06003670 shsurf->unresponsive = 0;
Alex Wu4539b082012-03-01 12:57:46 +08003671 shsurf->saved_position_valid = false;
Rafael Antognolli3c4e3f72013-12-03 15:35:46 -02003672 shsurf->saved_size_valid = false;
Alex Wu7bcb8bd2012-04-27 09:07:24 +08003673 shsurf->saved_rotation_valid = false;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003674 shsurf->surface = surface;
Alex Wu4539b082012-03-01 12:57:46 +08003675 shsurf->fullscreen.type = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT;
3676 shsurf->fullscreen.framerate = 0;
Jason Ekstranda7af7042013-10-12 22:38:11 -05003677 shsurf->fullscreen.black_view = NULL;
Alex Wu4539b082012-03-01 12:57:46 +08003678 wl_list_init(&shsurf->fullscreen.transform.link);
3679
Jasper St. Pierre9aa8ce62014-04-11 16:18:54 -07003680 shsurf->output = get_default_output(shsurf->shell->compositor);
3681
Jason Ekstrand651f00e2013-06-14 10:07:54 -05003682 wl_signal_init(&shsurf->destroy_signal);
Kristian Høgsberg27e30522012-04-11 23:18:23 -04003683 shsurf->surface_destroy_listener.notify = shell_handle_surface_destroy;
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05003684 wl_signal_add(&surface->destroy_signal,
Kristian Høgsberg27e30522012-04-11 23:18:23 -04003685 &shsurf->surface_destroy_listener);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003686
3687 /* init link so its safe to always remove it in destroy_shell_surface */
3688 wl_list_init(&shsurf->link);
Giulio Camuffo5085a752013-03-25 21:42:45 +01003689 wl_list_init(&shsurf->popup.grab_link);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003690
Pekka Paalanen460099f2012-01-20 16:48:25 +02003691 /* empty when not in use */
3692 wl_list_init(&shsurf->rotation.transform.link);
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05003693 weston_matrix_init(&shsurf->rotation.rotation);
Pekka Paalanen460099f2012-01-20 16:48:25 +02003694
Jonas Ådahl62fcd042012-06-13 00:01:23 +02003695 wl_list_init(&shsurf->workspace_transform.link);
3696
Philip Withnall648a4dd2013-11-25 18:01:44 +00003697 wl_list_init(&shsurf->children_link);
3698 wl_list_init(&shsurf->children_list);
3699 shsurf->parent = NULL;
3700
Pekka Paalanenb5026542014-11-12 15:09:24 +02003701 set_type(shsurf, SHELL_SURFACE_NONE);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003702
Kristian Høgsberga61ca062012-05-22 16:05:52 -04003703 shsurf->client = client;
3704
Kristian Høgsberg45ba8692012-05-21 14:27:33 -04003705 return shsurf;
Tiago Vignattibc052c92012-04-19 16:18:18 +03003706}
3707
Rafael Antognollie2a34552013-12-03 15:35:45 -02003708static struct shell_surface *
3709create_shell_surface(void *shell, struct weston_surface *surface,
3710 const struct weston_shell_client *client)
3711{
Jason Ekstrand9e9512f2014-04-16 21:12:10 -05003712 return create_common_surface(NULL, shell, surface, client);
Rafael Antognollie2a34552013-12-03 15:35:45 -02003713}
3714
Jason Ekstranda7af7042013-10-12 22:38:11 -05003715static struct weston_view *
3716get_primary_view(void *shell, struct shell_surface *shsurf)
3717{
3718 return shsurf->view;
3719}
3720
Tiago Vignattibc052c92012-04-19 16:18:18 +03003721static void
3722shell_get_shell_surface(struct wl_client *client,
3723 struct wl_resource *resource,
3724 uint32_t id,
3725 struct wl_resource *surface_resource)
3726{
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05003727 struct weston_surface *surface =
3728 wl_resource_get_user_data(surface_resource);
Jason Ekstrand9e9512f2014-04-16 21:12:10 -05003729 struct shell_client *sc = wl_resource_get_user_data(resource);
3730 struct desktop_shell *shell = sc->shell;
Tiago Vignattibc052c92012-04-19 16:18:18 +03003731 struct shell_surface *shsurf;
3732
Pekka Paalanen50b67472014-10-01 15:02:41 +03003733 if (weston_surface_set_role(surface, "wl_shell_surface",
3734 resource, WL_SHELL_ERROR_ROLE) < 0)
Tiago Vignattibc052c92012-04-19 16:18:18 +03003735 return;
Tiago Vignattibc052c92012-04-19 16:18:18 +03003736
Jason Ekstrand9e9512f2014-04-16 21:12:10 -05003737 shsurf = create_common_surface(sc, shell, surface, &shell_client);
Kristian Høgsberg9540ea62012-05-21 14:28:57 -04003738 if (!shsurf) {
Pekka Paalanen50b67472014-10-01 15:02:41 +03003739 wl_resource_post_no_memory(surface_resource);
Kristian Høgsberg9540ea62012-05-21 14:28:57 -04003740 return;
3741 }
Tiago Vignattibc052c92012-04-19 16:18:18 +03003742
Jason Ekstranda85118c2013-06-27 20:17:02 -05003743 shsurf->resource =
3744 wl_resource_create(client,
3745 &wl_shell_surface_interface, 1, id);
3746 wl_resource_set_implementation(shsurf->resource,
3747 &shell_surface_implementation,
3748 shsurf, shell_destroy_shell_surface);
Jonas Ådahl49d77d22015-03-18 16:20:51 +08003749 wl_list_init(wl_resource_get_link(shsurf->resource));
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003750}
3751
Rafael Antognollie2a34552013-12-03 15:35:45 -02003752static bool
3753shell_surface_is_wl_shell_surface(struct shell_surface *shsurf)
3754{
Kristian Høgsberg0b7d9952014-02-03 15:50:38 -08003755 /* A shell surface without a resource is created from xwayland
3756 * and is considered a wl_shell surface for now. */
3757
3758 return shsurf->resource == NULL ||
3759 wl_resource_instance_of(shsurf->resource,
3760 &wl_shell_surface_interface,
3761 &shell_surface_implementation);
Rafael Antognollie2a34552013-12-03 15:35:45 -02003762}
3763
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003764static const struct wl_shell_interface shell_implementation = {
Pekka Paalanen46229672011-11-29 15:49:31 +02003765 shell_get_shell_surface
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05003766};
3767
Rafael Antognollie2a34552013-12-03 15:35:45 -02003768/****************************
3769 * xdg-shell implementation */
3770
3771static void
3772xdg_surface_destroy(struct wl_client *client,
3773 struct wl_resource *resource)
3774{
3775 wl_resource_destroy(resource);
3776}
3777
3778static void
Jasper St. Pierrec815d622014-04-10 18:37:54 -07003779xdg_surface_set_parent(struct wl_client *client,
3780 struct wl_resource *resource,
3781 struct wl_resource *parent_resource)
Jasper St. Pierre63a9c332014-02-01 18:35:15 -05003782{
3783 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
Jasper St. Pierre66bc9492015-02-13 14:01:55 +08003784 struct shell_surface *parent;
Jasper St. Pierre63a9c332014-02-01 18:35:15 -05003785
Jasper St. Pierre66bc9492015-02-13 14:01:55 +08003786 if (parent_resource) {
Jasper St. Pierre63a9c332014-02-01 18:35:15 -05003787 parent = wl_resource_get_user_data(parent_resource);
Jasper St. Pierre66bc9492015-02-13 14:01:55 +08003788 shell_surface_set_parent(shsurf, parent->surface);
3789 } else {
3790 shell_surface_set_parent(shsurf, NULL);
3791 }
Jasper St. Pierre63a9c332014-02-01 18:35:15 -05003792}
3793
3794static void
Rafael Antognollie2a34552013-12-03 15:35:45 -02003795xdg_surface_set_app_id(struct wl_client *client,
3796 struct wl_resource *resource,
3797 const char *app_id)
3798{
3799 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
3800
3801 free(shsurf->class);
3802 shsurf->class = strdup(app_id);
Pekka Paalanenb5026542014-11-12 15:09:24 +02003803 shsurf->surface->timeline.force_refresh = 1;
Rafael Antognollie2a34552013-12-03 15:35:45 -02003804}
3805
3806static void
Jasper St. Pierre81ff0752014-03-13 11:04:53 -04003807xdg_surface_show_window_menu(struct wl_client *client,
3808 struct wl_resource *surface_resource,
3809 struct wl_resource *seat_resource,
3810 uint32_t serial,
3811 int32_t x,
3812 int32_t y)
3813{
3814 /* TODO */
3815}
3816
3817static void
Rafael Antognollie2a34552013-12-03 15:35:45 -02003818xdg_surface_set_title(struct wl_client *client,
3819 struct wl_resource *resource, const char *title)
3820{
3821 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
3822
3823 set_title(shsurf, title);
3824}
3825
3826static void
3827xdg_surface_move(struct wl_client *client, struct wl_resource *resource,
3828 struct wl_resource *seat_resource, uint32_t serial)
3829{
3830 common_surface_move(resource, seat_resource, serial);
3831}
3832
3833static void
3834xdg_surface_resize(struct wl_client *client, struct wl_resource *resource,
3835 struct wl_resource *seat_resource, uint32_t serial,
3836 uint32_t edges)
3837{
3838 common_surface_resize(resource, seat_resource, serial, edges);
3839}
3840
3841static void
Jasper St. Pierreab2c1082014-04-10 10:41:46 -07003842xdg_surface_ack_configure(struct wl_client *client,
3843 struct wl_resource *resource,
3844 uint32_t serial)
Rafael Antognollie2a34552013-12-03 15:35:45 -02003845{
3846 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
3847
Jasper St. Pierre8c6aa452014-02-08 18:29:49 -05003848 if (shsurf->state_requested) {
3849 shsurf->next_state = shsurf->requested_state;
3850 shsurf->state_changed = true;
3851 shsurf->state_requested = false;
Rafael Antognolli3c4e3f72013-12-03 15:35:46 -02003852 }
Rafael Antognollie2a34552013-12-03 15:35:45 -02003853}
3854
Manuel Bachmann50c87db2014-02-26 15:52:13 +01003855static void
Jasper St. Pierreccf48fb2014-05-02 10:21:38 -04003856xdg_surface_set_window_geometry(struct wl_client *client,
3857 struct wl_resource *resource,
3858 int32_t x,
3859 int32_t y,
3860 int32_t width,
3861 int32_t height)
3862{
3863 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
3864
3865 set_window_geometry(shsurf, x, y, width, height);
3866}
3867
3868static void
Jasper St. Pierreab2c1082014-04-10 10:41:46 -07003869xdg_surface_set_maximized(struct wl_client *client,
3870 struct wl_resource *resource)
3871{
3872 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
Marek Chalupabfbb64b2014-09-08 12:34:20 +02003873 struct weston_output *output;
Jasper St. Pierreab2c1082014-04-10 10:41:46 -07003874
3875 shsurf->state_requested = true;
3876 shsurf->requested_state.maximized = true;
Marek Chalupabfbb64b2014-09-08 12:34:20 +02003877
3878 if (!weston_surface_is_mapped(shsurf->surface))
3879 output = get_focused_output(shsurf->surface->compositor);
3880 else
3881 output = shsurf->surface->output;
3882
3883 shell_surface_set_output(shsurf, output);
Jasper St. Pierre9aa8ce62014-04-11 16:18:54 -07003884 send_configure_for_surface(shsurf);
Jasper St. Pierreab2c1082014-04-10 10:41:46 -07003885}
3886
3887static void
3888xdg_surface_unset_maximized(struct wl_client *client,
3889 struct wl_resource *resource)
3890{
3891 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
3892
3893 shsurf->state_requested = true;
3894 shsurf->requested_state.maximized = false;
Jasper St. Pierre6458ec32014-04-11 16:00:31 -07003895 send_configure_for_surface(shsurf);
Jasper St. Pierreab2c1082014-04-10 10:41:46 -07003896}
3897
3898static void
3899xdg_surface_set_fullscreen(struct wl_client *client,
3900 struct wl_resource *resource,
3901 struct wl_resource *output_resource)
3902{
3903 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
3904 struct weston_output *output;
3905
3906 shsurf->state_requested = true;
3907 shsurf->requested_state.fullscreen = true;
3908
3909 if (output_resource)
3910 output = wl_resource_get_user_data(output_resource);
3911 else
3912 output = NULL;
3913
Marek Chalupa052917a2014-09-02 11:35:12 +02003914 /* handle clients launching in fullscreen */
3915 if (output == NULL && !weston_surface_is_mapped(shsurf->surface)) {
3916 /* Set the output to the one that has focus currently. */
3917 assert(shsurf->surface);
3918 output = get_focused_output(shsurf->surface->compositor);
3919 }
3920
Jasper St. Pierre9aa8ce62014-04-11 16:18:54 -07003921 shell_surface_set_output(shsurf, output);
3922 shsurf->fullscreen_output = shsurf->output;
Jasper St. Pierreab2c1082014-04-10 10:41:46 -07003923
Jasper St. Pierre9aa8ce62014-04-11 16:18:54 -07003924 send_configure_for_surface(shsurf);
Jasper St. Pierreab2c1082014-04-10 10:41:46 -07003925}
3926
3927static void
3928xdg_surface_unset_fullscreen(struct wl_client *client,
3929 struct wl_resource *resource)
3930{
3931 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
3932
3933 shsurf->state_requested = true;
3934 shsurf->requested_state.fullscreen = false;
Jasper St. Pierre6458ec32014-04-11 16:00:31 -07003935 send_configure_for_surface(shsurf);
Jasper St. Pierreab2c1082014-04-10 10:41:46 -07003936}
3937
3938static void
Manuel Bachmann50c87db2014-02-26 15:52:13 +01003939xdg_surface_set_minimized(struct wl_client *client,
3940 struct wl_resource *resource)
3941{
3942 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
3943
3944 if (shsurf->type != SHELL_SURFACE_TOPLEVEL)
3945 return;
3946
3947 /* apply compositor's own minimization logic (hide) */
Manuel Bachmanndc1c3e42015-02-16 11:52:13 +01003948 set_minimized(shsurf->surface);
Manuel Bachmann50c87db2014-02-26 15:52:13 +01003949}
3950
Rafael Antognollie2a34552013-12-03 15:35:45 -02003951static const struct xdg_surface_interface xdg_surface_implementation = {
3952 xdg_surface_destroy,
Jasper St. Pierrec815d622014-04-10 18:37:54 -07003953 xdg_surface_set_parent,
Rafael Antognollie2a34552013-12-03 15:35:45 -02003954 xdg_surface_set_title,
3955 xdg_surface_set_app_id,
Jasper St. Pierre81ff0752014-03-13 11:04:53 -04003956 xdg_surface_show_window_menu,
Rafael Antognollie2a34552013-12-03 15:35:45 -02003957 xdg_surface_move,
3958 xdg_surface_resize,
Jasper St. Pierreab2c1082014-04-10 10:41:46 -07003959 xdg_surface_ack_configure,
Jasper St. Pierreccf48fb2014-05-02 10:21:38 -04003960 xdg_surface_set_window_geometry,
Jasper St. Pierreab2c1082014-04-10 10:41:46 -07003961 xdg_surface_set_maximized,
3962 xdg_surface_unset_maximized,
3963 xdg_surface_set_fullscreen,
3964 xdg_surface_unset_fullscreen,
3965 xdg_surface_set_minimized,
Rafael Antognollie2a34552013-12-03 15:35:45 -02003966};
3967
3968static void
3969xdg_send_configure(struct weston_surface *surface,
Jasper St. Pierreac985be2014-04-28 11:19:28 -04003970 int32_t width, int32_t height)
Rafael Antognollie2a34552013-12-03 15:35:45 -02003971{
3972 struct shell_surface *shsurf = get_shell_surface(surface);
Jasper St. Pierreab2c1082014-04-10 10:41:46 -07003973 uint32_t *s;
3974 struct wl_array states;
3975 uint32_t serial;
Rafael Antognollie2a34552013-12-03 15:35:45 -02003976
U. Artie Eoffcf5737a2014-01-17 10:08:25 -08003977 assert(shsurf);
3978
Jasper St. Pierreab2c1082014-04-10 10:41:46 -07003979 if (!shsurf->resource)
3980 return;
3981
3982 wl_array_init(&states);
3983 if (shsurf->requested_state.fullscreen) {
3984 s = wl_array_add(&states, sizeof *s);
3985 *s = XDG_SURFACE_STATE_FULLSCREEN;
3986 } else if (shsurf->requested_state.maximized) {
3987 s = wl_array_add(&states, sizeof *s);
3988 *s = XDG_SURFACE_STATE_MAXIMIZED;
3989 }
Jasper St. Pierre5befdda2014-05-06 08:50:47 -04003990 if (shsurf->resize_edges != 0) {
3991 s = wl_array_add(&states, sizeof *s);
3992 *s = XDG_SURFACE_STATE_RESIZING;
3993 }
Jasper St. Pierre973d7872014-05-06 08:44:29 -04003994 if (shsurf->focus_count > 0) {
3995 s = wl_array_add(&states, sizeof *s);
3996 *s = XDG_SURFACE_STATE_ACTIVATED;
3997 }
Jasper St. Pierreab2c1082014-04-10 10:41:46 -07003998
3999 serial = wl_display_next_serial(shsurf->surface->compositor->wl_display);
4000 xdg_surface_send_configure(shsurf->resource, width, height, &states, serial);
4001
4002 wl_array_release(&states);
Rafael Antognollie2a34552013-12-03 15:35:45 -02004003}
4004
4005static const struct weston_shell_client xdg_client = {
4006 xdg_send_configure
4007};
4008
4009static void
Jasper St. Pierre084aa0b2015-02-13 14:02:00 +08004010xdg_shell_destroy(struct wl_client *client,
4011 struct wl_resource *resource)
4012{
Jonas Ådahl49d77d22015-03-18 16:20:51 +08004013 struct shell_client *sc = wl_resource_get_user_data(resource);
4014 struct wl_resource *shsurf_resource;
4015 struct shell_surface *shsurf;
4016
4017 wl_resource_for_each(shsurf_resource, &sc->surface_list) {
4018 shsurf = wl_resource_get_user_data(shsurf_resource);
4019 if (shsurf->owner_resource == resource) {
4020 wl_resource_post_error(
4021 resource,
4022 XDG_SHELL_ERROR_DEFUNCT_SURFACES,
4023 "not all child surface objects destroyed");
4024 return;
4025 }
4026 }
4027
Jasper St. Pierre084aa0b2015-02-13 14:02:00 +08004028 wl_resource_destroy(resource);
4029}
4030
4031static void
Rafael Antognollie2a34552013-12-03 15:35:45 -02004032xdg_use_unstable_version(struct wl_client *client,
4033 struct wl_resource *resource,
4034 int32_t version)
4035{
4036 if (version > 1) {
4037 wl_resource_post_error(resource,
4038 1,
4039 "xdg-shell:: version not implemented yet.");
4040 return;
4041 }
4042}
4043
4044static struct shell_surface *
Jason Ekstrand9e9512f2014-04-16 21:12:10 -05004045create_xdg_surface(struct shell_client *owner, void *shell,
4046 struct weston_surface *surface,
Rafael Antognollie2a34552013-12-03 15:35:45 -02004047 const struct weston_shell_client *client)
4048{
4049 struct shell_surface *shsurf;
Rafael Antognollie2a34552013-12-03 15:35:45 -02004050
Jason Ekstrand9e9512f2014-04-16 21:12:10 -05004051 shsurf = create_common_surface(owner, shell, surface, client);
Pekka Paalanene972b272014-10-01 14:03:56 +03004052 if (!shsurf)
4053 return NULL;
4054
Pekka Paalanenb5026542014-11-12 15:09:24 +02004055 set_type(shsurf, SHELL_SURFACE_TOPLEVEL);
Rafael Antognollie2a34552013-12-03 15:35:45 -02004056
4057 return shsurf;
4058}
4059
4060static void
4061xdg_get_xdg_surface(struct wl_client *client,
4062 struct wl_resource *resource,
4063 uint32_t id,
4064 struct wl_resource *surface_resource)
4065{
4066 struct weston_surface *surface =
4067 wl_resource_get_user_data(surface_resource);
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08004068 struct shell_client *sc = wl_resource_get_user_data(resource);
4069 struct desktop_shell *shell = sc->shell;
Rafael Antognollie2a34552013-12-03 15:35:45 -02004070 struct shell_surface *shsurf;
4071
Jonas Ådahlbf48e212015-02-06 10:15:28 +08004072 shsurf = get_shell_surface(surface);
4073 if (shsurf && shell_surface_is_xdg_surface(shsurf)) {
4074 wl_resource_post_error(resource, XDG_SHELL_ERROR_ROLE,
4075 "This wl_surface is already an "
4076 "xdg_surface");
4077 return;
4078 }
4079
Pekka Paalanen50b67472014-10-01 15:02:41 +03004080 if (weston_surface_set_role(surface, "xdg_surface",
4081 resource, XDG_SHELL_ERROR_ROLE) < 0)
Rafael Antognollie2a34552013-12-03 15:35:45 -02004082 return;
Rafael Antognollie2a34552013-12-03 15:35:45 -02004083
Jason Ekstrand9e9512f2014-04-16 21:12:10 -05004084 shsurf = create_xdg_surface(sc, shell, surface, &xdg_client);
Rafael Antognollie2a34552013-12-03 15:35:45 -02004085 if (!shsurf) {
Pekka Paalanen50b67472014-10-01 15:02:41 +03004086 wl_resource_post_no_memory(surface_resource);
Rafael Antognollie2a34552013-12-03 15:35:45 -02004087 return;
4088 }
4089
4090 shsurf->resource =
4091 wl_resource_create(client,
4092 &xdg_surface_interface, 1, id);
4093 wl_resource_set_implementation(shsurf->resource,
4094 &xdg_surface_implementation,
4095 shsurf, shell_destroy_shell_surface);
Jonas Ådahl49d77d22015-03-18 16:20:51 +08004096 shsurf->owner_resource = resource;
4097 wl_list_insert(&sc->surface_list,
4098 wl_resource_get_link(shsurf->resource));
Rafael Antognollie2a34552013-12-03 15:35:45 -02004099}
4100
4101static bool
4102shell_surface_is_xdg_surface(struct shell_surface *shsurf)
4103{
Kristian Høgsberg0b7d9952014-02-03 15:50:38 -08004104 return shsurf->resource &&
4105 wl_resource_instance_of(shsurf->resource,
4106 &xdg_surface_interface,
4107 &xdg_surface_implementation);
Rafael Antognollie2a34552013-12-03 15:35:45 -02004108}
4109
4110/* xdg-popup implementation */
4111
4112static void
4113xdg_popup_destroy(struct wl_client *client,
4114 struct wl_resource *resource)
4115{
4116 wl_resource_destroy(resource);
4117}
4118
Rafael Antognollie2a34552013-12-03 15:35:45 -02004119static const struct xdg_popup_interface xdg_popup_implementation = {
4120 xdg_popup_destroy,
Rafael Antognollie2a34552013-12-03 15:35:45 -02004121};
4122
4123static void
4124xdg_popup_send_configure(struct weston_surface *surface,
Jasper St. Pierreac985be2014-04-28 11:19:28 -04004125 int32_t width, int32_t height)
Rafael Antognollie2a34552013-12-03 15:35:45 -02004126{
4127}
4128
4129static const struct weston_shell_client xdg_popup_client = {
4130 xdg_popup_send_configure
4131};
4132
4133static struct shell_surface *
Jason Ekstrand9e9512f2014-04-16 21:12:10 -05004134create_xdg_popup(struct shell_client *owner, void *shell,
4135 struct weston_surface *surface,
Rafael Antognollie2a34552013-12-03 15:35:45 -02004136 const struct weston_shell_client *client,
4137 struct weston_surface *parent,
4138 struct shell_seat *seat,
4139 uint32_t serial,
4140 int32_t x, int32_t y)
4141{
Jonas Ådahlee45a552015-03-18 16:37:47 +08004142 struct shell_surface *shsurf;
Jonas Ådahl24185e22015-02-27 18:37:41 +08004143
Jason Ekstrand9e9512f2014-04-16 21:12:10 -05004144 shsurf = create_common_surface(owner, shell, surface, client);
Pekka Paalanene972b272014-10-01 14:03:56 +03004145 if (!shsurf)
4146 return NULL;
4147
Pekka Paalanenb5026542014-11-12 15:09:24 +02004148 set_type(shsurf, SHELL_SURFACE_POPUP);
Rafael Antognollie2a34552013-12-03 15:35:45 -02004149 shsurf->popup.shseat = seat;
4150 shsurf->popup.serial = serial;
4151 shsurf->popup.x = x;
4152 shsurf->popup.y = y;
4153 shell_surface_set_parent(shsurf, parent);
4154
4155 return shsurf;
4156}
4157
4158static void
4159xdg_get_xdg_popup(struct wl_client *client,
4160 struct wl_resource *resource,
4161 uint32_t id,
4162 struct wl_resource *surface_resource,
4163 struct wl_resource *parent_resource,
4164 struct wl_resource *seat_resource,
4165 uint32_t serial,
Jasper St. Pierre14f330c2015-02-13 14:01:57 +08004166 int32_t x, int32_t y)
Rafael Antognollie2a34552013-12-03 15:35:45 -02004167{
4168 struct weston_surface *surface =
4169 wl_resource_get_user_data(surface_resource);
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08004170 struct shell_client *sc = wl_resource_get_user_data(resource);
4171 struct desktop_shell *shell = sc->shell;
Rafael Antognollie2a34552013-12-03 15:35:45 -02004172 struct shell_surface *shsurf;
Jonas Ådahlee45a552015-03-18 16:37:47 +08004173 struct shell_surface *parent_shsurf;
Rafael Antognollie2a34552013-12-03 15:35:45 -02004174 struct weston_surface *parent;
4175 struct shell_seat *seat;
4176
Jonas Ådahlbf48e212015-02-06 10:15:28 +08004177 shsurf = get_shell_surface(surface);
4178 if (shsurf && shell_surface_is_xdg_popup(shsurf)) {
4179 wl_resource_post_error(resource, XDG_SHELL_ERROR_ROLE,
4180 "This wl_surface is already an "
4181 "xdg_popup");
4182 return;
4183 }
4184
Pekka Paalanen50b67472014-10-01 15:02:41 +03004185 if (weston_surface_set_role(surface, "xdg_popup",
4186 resource, XDG_SHELL_ERROR_ROLE) < 0)
Rafael Antognollie2a34552013-12-03 15:35:45 -02004187 return;
Rafael Antognollie2a34552013-12-03 15:35:45 -02004188
4189 if (!parent_resource) {
4190 wl_resource_post_error(surface_resource,
4191 WL_DISPLAY_ERROR_INVALID_OBJECT,
4192 "xdg_shell::get_xdg_popup requires a parent shell surface");
Jasper St. Pierre666bc922014-08-07 16:43:13 -04004193 return;
Rafael Antognollie2a34552013-12-03 15:35:45 -02004194 }
4195
4196 parent = wl_resource_get_user_data(parent_resource);
4197 seat = get_shell_seat(wl_resource_get_user_data(seat_resource));;
4198
Jonas Ådahlee45a552015-03-18 16:37:47 +08004199 /* Verify that we are creating the top most popup when mapping,
4200 * as it's not until then we know whether it was mapped as most
4201 * top level or not. */
4202
4203 parent_shsurf = get_shell_surface(parent);
4204 if (!shell_surface_is_xdg_popup(parent_shsurf) &&
4205 !shell_surface_is_xdg_surface(parent_shsurf)) {
4206 wl_resource_post_error(resource,
4207 XDG_SHELL_ERROR_INVALID_POPUP_PARENT,
4208 "xdg_popup parent was invalid");
4209 return;
4210 }
4211
Jason Ekstrand9e9512f2014-04-16 21:12:10 -05004212 shsurf = create_xdg_popup(sc, shell, surface, &xdg_popup_client,
Rafael Antognollie2a34552013-12-03 15:35:45 -02004213 parent, seat, serial, x, y);
4214 if (!shsurf) {
Pekka Paalanen50b67472014-10-01 15:02:41 +03004215 wl_resource_post_no_memory(surface_resource);
Rafael Antognollie2a34552013-12-03 15:35:45 -02004216 return;
4217 }
4218
4219 shsurf->resource =
4220 wl_resource_create(client,
4221 &xdg_popup_interface, 1, id);
4222 wl_resource_set_implementation(shsurf->resource,
4223 &xdg_popup_implementation,
4224 shsurf, shell_destroy_shell_surface);
Jonas Ådahl49d77d22015-03-18 16:20:51 +08004225 shsurf->owner_resource = resource;
4226 wl_list_insert(&sc->surface_list,
4227 wl_resource_get_link(shsurf->resource));
Rafael Antognollie2a34552013-12-03 15:35:45 -02004228}
4229
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08004230static void
4231xdg_pong(struct wl_client *client,
4232 struct wl_resource *resource, uint32_t serial)
4233{
4234 struct shell_client *sc = wl_resource_get_user_data(resource);
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08004235
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08004236 shell_client_pong(sc, serial);
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08004237}
4238
Rafael Antognollie2a34552013-12-03 15:35:45 -02004239static bool
4240shell_surface_is_xdg_popup(struct shell_surface *shsurf)
4241{
4242 return wl_resource_instance_of(shsurf->resource,
4243 &xdg_popup_interface,
4244 &xdg_popup_implementation);
4245}
4246
4247static const struct xdg_shell_interface xdg_implementation = {
Jasper St. Pierre084aa0b2015-02-13 14:02:00 +08004248 xdg_shell_destroy,
Rafael Antognollie2a34552013-12-03 15:35:45 -02004249 xdg_use_unstable_version,
4250 xdg_get_xdg_surface,
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08004251 xdg_get_xdg_popup,
4252 xdg_pong
Rafael Antognollie2a34552013-12-03 15:35:45 -02004253};
4254
4255static int
4256xdg_shell_unversioned_dispatch(const void *implementation,
4257 void *_target, uint32_t opcode,
4258 const struct wl_message *message,
4259 union wl_argument *args)
4260{
4261 struct wl_resource *resource = _target;
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08004262 struct shell_client *sc = wl_resource_get_user_data(resource);
Rafael Antognollie2a34552013-12-03 15:35:45 -02004263
Jasper St. Pierre084aa0b2015-02-13 14:02:00 +08004264 if (opcode != 1 /* XDG_SHELL_USE_UNSTABLE_VERSION */) {
Rafael Antognollie2a34552013-12-03 15:35:45 -02004265 wl_resource_post_error(resource,
4266 WL_DISPLAY_ERROR_INVALID_OBJECT,
4267 "must call use_unstable_version first");
4268 return 0;
4269 }
4270
Jasper St. Pierre5ba1e1d2015-02-13 14:02:02 +08004271#define XDG_SERVER_VERSION 5
Rafael Antognollie2a34552013-12-03 15:35:45 -02004272
Kristian Høgsberg8d344a02013-12-08 22:27:11 -08004273 static_assert(XDG_SERVER_VERSION == XDG_SHELL_VERSION_CURRENT,
4274 "shell implementation doesn't match protocol version");
4275
Rafael Antognollie2a34552013-12-03 15:35:45 -02004276 if (args[0].i != XDG_SERVER_VERSION) {
4277 wl_resource_post_error(resource,
4278 WL_DISPLAY_ERROR_INVALID_OBJECT,
4279 "incompatible version, server is %d "
4280 "client wants %d",
4281 XDG_SERVER_VERSION, args[0].i);
4282 return 0;
4283 }
4284
4285 wl_resource_set_implementation(resource, &xdg_implementation,
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08004286 sc, NULL);
Rafael Antognollie2a34552013-12-03 15:35:45 -02004287
4288 return 1;
4289}
4290
4291/* end of xdg-shell implementation */
4292/***********************************/
4293
Kristian Høgsberg07937562011-04-12 17:25:42 -04004294static void
Ander Conselvan de Oliveira859e8852013-02-21 18:35:21 +02004295shell_fade(struct desktop_shell *shell, enum fade_type type);
4296
4297static int
4298screensaver_timeout(void *data)
4299{
4300 struct desktop_shell *shell = data;
4301
4302 shell_fade(shell, FADE_OUT);
4303
4304 return 1;
4305}
4306
4307static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05004308handle_screensaver_sigchld(struct weston_process *proc, int status)
Pekka Paalanen18027e52011-12-02 16:31:49 +02004309{
Ander Conselvan de Oliveira18639f82013-02-15 18:44:19 +02004310 struct desktop_shell *shell =
4311 container_of(proc, struct desktop_shell, screensaver.process);
Ander Conselvan de Oliveira18639f82013-02-15 18:44:19 +02004312
Pekka Paalanen18027e52011-12-02 16:31:49 +02004313 proc->pid = 0;
Ander Conselvan de Oliveira18639f82013-02-15 18:44:19 +02004314
4315 if (shell->locked)
Ander Conselvan de Oliveirab17537e2013-02-22 14:16:18 +02004316 weston_compositor_sleep(shell->compositor);
Pekka Paalanen18027e52011-12-02 16:31:49 +02004317}
4318
4319static void
Tiago Vignattibe143262012-04-16 17:31:41 +03004320launch_screensaver(struct desktop_shell *shell)
Pekka Paalanen77346a62011-11-30 16:26:35 +02004321{
4322 if (shell->screensaver.binding)
4323 return;
4324
Ander Conselvan de Oliveiradda9d782013-02-22 14:16:19 +02004325 if (!shell->screensaver.path) {
4326 weston_compositor_sleep(shell->compositor);
Pekka Paalanene955f1e2011-12-07 11:49:52 +02004327 return;
Ander Conselvan de Oliveiradda9d782013-02-22 14:16:19 +02004328 }
Pekka Paalanene955f1e2011-12-07 11:49:52 +02004329
Kristian Høgsberg32bed572012-03-01 17:11:36 -05004330 if (shell->screensaver.process.pid != 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02004331 weston_log("old screensaver still running\n");
Kristian Høgsberg32bed572012-03-01 17:11:36 -05004332 return;
4333 }
4334
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05004335 weston_client_launch(shell->compositor,
Pekka Paalanen18027e52011-12-02 16:31:49 +02004336 &shell->screensaver.process,
Pekka Paalanene955f1e2011-12-07 11:49:52 +02004337 shell->screensaver.path,
Pekka Paalanen18027e52011-12-02 16:31:49 +02004338 handle_screensaver_sigchld);
Pekka Paalanen77346a62011-11-30 16:26:35 +02004339}
4340
4341static void
Tiago Vignattibe143262012-04-16 17:31:41 +03004342terminate_screensaver(struct desktop_shell *shell)
Pekka Paalanen77346a62011-11-30 16:26:35 +02004343{
Pekka Paalanen18027e52011-12-02 16:31:49 +02004344 if (shell->screensaver.process.pid == 0)
4345 return;
4346
Ander Conselvan de Oliveira4e20e9b2014-04-10 14:49:35 +03004347 /* Disarm the screensaver timer, otherwise it may fire when the
4348 * compositor is not in the idle state. In that case, the screen will
4349 * be locked, but the wake_signal won't fire on user input, making the
4350 * system unresponsive. */
4351 wl_event_source_timer_update(shell->screensaver.timer, 0);
4352
Pekka Paalanen18027e52011-12-02 16:31:49 +02004353 kill(shell->screensaver.process.pid, SIGTERM);
Pekka Paalanen77346a62011-11-30 16:26:35 +02004354}
4355
4356static void
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004357configure_static_view(struct weston_view *ev, struct weston_layer *layer)
Kristian Høgsberg962342c2012-06-26 16:29:50 -04004358{
Jason Ekstranda7af7042013-10-12 22:38:11 -05004359 struct weston_view *v, *next;
Kristian Høgsberg962342c2012-06-26 16:29:50 -04004360
Giulio Camuffo412e6a52014-07-09 22:12:56 +03004361 wl_list_for_each_safe(v, next, &layer->view_list.link, layer_link.link) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05004362 if (v->output == ev->output && v != ev) {
4363 weston_view_unmap(v);
4364 v->surface->configure = NULL;
Pekka Paalanen8274d902014-08-06 19:36:51 +03004365 weston_surface_set_label_func(v->surface, NULL);
Kristian Høgsberg962342c2012-06-26 16:29:50 -04004366 }
4367 }
4368
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004369 weston_view_set_position(ev, ev->output->x, ev->output->y);
Kristian Høgsberg962342c2012-06-26 16:29:50 -04004370
Giulio Camuffo412e6a52014-07-09 22:12:56 +03004371 if (wl_list_empty(&ev->layer_link.link)) {
4372 weston_layer_entry_insert(&layer->view_list, &ev->layer_link);
Jason Ekstranda7af7042013-10-12 22:38:11 -05004373 weston_compositor_schedule_repaint(ev->surface->compositor);
Kristian Høgsberg962342c2012-06-26 16:29:50 -04004374 }
4375}
4376
Pekka Paalanen8274d902014-08-06 19:36:51 +03004377static int
4378background_get_label(struct weston_surface *surface, char *buf, size_t len)
4379{
4380 return snprintf(buf, len, "background for output %s",
4381 surface->output->name);
4382}
4383
Kristian Høgsberg962342c2012-06-26 16:29:50 -04004384static void
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004385background_configure(struct weston_surface *es, int32_t sx, int32_t sy)
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04004386{
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01004387 struct desktop_shell *shell = es->configure_private;
Jason Ekstranda7af7042013-10-12 22:38:11 -05004388 struct weston_view *view;
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04004389
Jason Ekstranda7af7042013-10-12 22:38:11 -05004390 view = container_of(es->views.next, struct weston_view, surface_link);
4391
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004392 configure_static_view(view, &shell->background_layer);
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04004393}
4394
4395static void
Kristian Høgsberg75840622011-09-06 13:48:16 -04004396desktop_shell_set_background(struct wl_client *client,
4397 struct wl_resource *resource,
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01004398 struct wl_resource *output_resource,
Kristian Høgsberg75840622011-09-06 13:48:16 -04004399 struct wl_resource *surface_resource)
4400{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05004401 struct desktop_shell *shell = wl_resource_get_user_data(resource);
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05004402 struct weston_surface *surface =
4403 wl_resource_get_user_data(surface_resource);
Jason Ekstranda7af7042013-10-12 22:38:11 -05004404 struct weston_view *view, *next;
Kristian Høgsberg75840622011-09-06 13:48:16 -04004405
Kristian Høgsberg962342c2012-06-26 16:29:50 -04004406 if (surface->configure) {
4407 wl_resource_post_error(surface_resource,
4408 WL_DISPLAY_ERROR_INVALID_OBJECT,
4409 "surface role already assigned");
4410 return;
4411 }
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01004412
Jason Ekstranda7af7042013-10-12 22:38:11 -05004413 wl_list_for_each_safe(view, next, &surface->views, surface_link)
4414 weston_view_destroy(view);
4415 view = weston_view_create(surface);
4416
Kristian Høgsberg962342c2012-06-26 16:29:50 -04004417 surface->configure = background_configure;
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01004418 surface->configure_private = shell;
Pekka Paalanen8274d902014-08-06 19:36:51 +03004419 weston_surface_set_label_func(surface, background_get_label);
Jason Ekstranda0d2dde2013-06-14 10:08:01 -05004420 surface->output = wl_resource_get_user_data(output_resource);
Jason Ekstranda7af7042013-10-12 22:38:11 -05004421 view->output = surface->output;
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04004422 desktop_shell_send_configure(resource, 0,
Kristian Høgsberg0b5cd0c2012-03-04 21:57:37 -05004423 surface_resource,
Scott Moreau1bad5db2012-08-18 01:04:05 -06004424 surface->output->width,
4425 surface->output->height);
Kristian Høgsberg75840622011-09-06 13:48:16 -04004426}
4427
Pekka Paalanen8274d902014-08-06 19:36:51 +03004428static int
4429panel_get_label(struct weston_surface *surface, char *buf, size_t len)
4430{
4431 return snprintf(buf, len, "panel for output %s",
4432 surface->output->name);
4433}
4434
Kristian Høgsberg75840622011-09-06 13:48:16 -04004435static void
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004436panel_configure(struct weston_surface *es, int32_t sx, int32_t sy)
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04004437{
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01004438 struct desktop_shell *shell = es->configure_private;
Jason Ekstranda7af7042013-10-12 22:38:11 -05004439 struct weston_view *view;
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04004440
Jason Ekstranda7af7042013-10-12 22:38:11 -05004441 view = container_of(es->views.next, struct weston_view, surface_link);
4442
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004443 configure_static_view(view, &shell->panel_layer);
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04004444}
4445
4446static void
Kristian Høgsberg75840622011-09-06 13:48:16 -04004447desktop_shell_set_panel(struct wl_client *client,
4448 struct wl_resource *resource,
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01004449 struct wl_resource *output_resource,
Kristian Høgsberg75840622011-09-06 13:48:16 -04004450 struct wl_resource *surface_resource)
4451{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05004452 struct desktop_shell *shell = wl_resource_get_user_data(resource);
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05004453 struct weston_surface *surface =
4454 wl_resource_get_user_data(surface_resource);
Jason Ekstranda7af7042013-10-12 22:38:11 -05004455 struct weston_view *view, *next;
Kristian Høgsberg75840622011-09-06 13:48:16 -04004456
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04004457 if (surface->configure) {
4458 wl_resource_post_error(surface_resource,
4459 WL_DISPLAY_ERROR_INVALID_OBJECT,
4460 "surface role already assigned");
4461 return;
4462 }
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01004463
Jason Ekstranda7af7042013-10-12 22:38:11 -05004464 wl_list_for_each_safe(view, next, &surface->views, surface_link)
4465 weston_view_destroy(view);
4466 view = weston_view_create(surface);
4467
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04004468 surface->configure = panel_configure;
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01004469 surface->configure_private = shell;
Pekka Paalanen8274d902014-08-06 19:36:51 +03004470 weston_surface_set_label_func(surface, panel_get_label);
Jason Ekstranda0d2dde2013-06-14 10:08:01 -05004471 surface->output = wl_resource_get_user_data(output_resource);
Jason Ekstranda7af7042013-10-12 22:38:11 -05004472 view->output = surface->output;
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04004473 desktop_shell_send_configure(resource, 0,
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04004474 surface_resource,
Scott Moreau1bad5db2012-08-18 01:04:05 -06004475 surface->output->width,
4476 surface->output->height);
Kristian Høgsberg75840622011-09-06 13:48:16 -04004477}
4478
Pekka Paalanen8274d902014-08-06 19:36:51 +03004479static int
4480lock_surface_get_label(struct weston_surface *surface, char *buf, size_t len)
4481{
4482 return snprintf(buf, len, "lock window");
4483}
4484
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02004485static void
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004486lock_surface_configure(struct weston_surface *surface, int32_t sx, int32_t sy)
Kristian Høgsberg730c94d2012-06-26 21:44:35 -04004487{
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01004488 struct desktop_shell *shell = surface->configure_private;
Jason Ekstranda7af7042013-10-12 22:38:11 -05004489 struct weston_view *view;
4490
4491 view = container_of(surface->views.next, struct weston_view, surface_link);
Kristian Høgsberg730c94d2012-06-26 21:44:35 -04004492
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004493 if (surface->width == 0)
Giulio Camuffo184df502013-02-21 11:29:21 +01004494 return;
4495
Jason Ekstranda7af7042013-10-12 22:38:11 -05004496 center_on_output(view, get_default_output(shell->compositor));
Kristian Høgsberg730c94d2012-06-26 21:44:35 -04004497
4498 if (!weston_surface_is_mapped(surface)) {
Giulio Camuffo412e6a52014-07-09 22:12:56 +03004499 weston_layer_entry_insert(&shell->lock_layer.view_list,
4500 &view->layer_link);
Jason Ekstranda7af7042013-10-12 22:38:11 -05004501 weston_view_update_transform(view);
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02004502 shell_fade(shell, FADE_IN);
Kristian Høgsberg730c94d2012-06-26 21:44:35 -04004503 }
4504}
4505
4506static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04004507handle_lock_surface_destroy(struct wl_listener *listener, void *data)
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05004508{
Tiago Vignattibe143262012-04-16 17:31:41 +03004509 struct desktop_shell *shell =
4510 container_of(listener, struct desktop_shell, lock_surface_listener);
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05004511
Martin Minarik6d118362012-06-07 18:01:59 +02004512 weston_log("lock surface gone\n");
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05004513 shell->lock_surface = NULL;
4514}
4515
4516static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02004517desktop_shell_set_lock_surface(struct wl_client *client,
4518 struct wl_resource *resource,
4519 struct wl_resource *surface_resource)
4520{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05004521 struct desktop_shell *shell = wl_resource_get_user_data(resource);
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05004522 struct weston_surface *surface =
4523 wl_resource_get_user_data(surface_resource);
Pekka Paalanen98262232011-12-01 10:42:22 +02004524
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02004525 shell->prepare_event_sent = false;
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +02004526
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02004527 if (!shell->locked)
4528 return;
4529
Pekka Paalanen98262232011-12-01 10:42:22 +02004530 shell->lock_surface = surface;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02004531
Kristian Høgsberg27e30522012-04-11 23:18:23 -04004532 shell->lock_surface_listener.notify = handle_lock_surface_destroy;
Jason Ekstrand651f00e2013-06-14 10:07:54 -05004533 wl_signal_add(&surface->destroy_signal,
Kristian Høgsberg27e30522012-04-11 23:18:23 -04004534 &shell->lock_surface_listener);
Pekka Paalanen57da4a82011-11-23 16:42:16 +02004535
Kristian Høgsbergaa2ee8b2013-10-30 15:49:45 -07004536 weston_view_create(surface);
Kristian Høgsberg730c94d2012-06-26 21:44:35 -04004537 surface->configure = lock_surface_configure;
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01004538 surface->configure_private = shell;
Pekka Paalanen8274d902014-08-06 19:36:51 +03004539 weston_surface_set_label_func(surface, lock_surface_get_label);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02004540}
4541
4542static void
Tiago Vignattibe143262012-04-16 17:31:41 +03004543resume_desktop(struct desktop_shell *shell)
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02004544{
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04004545 struct workspace *ws = get_current_workspace(shell);
Pekka Paalanen77346a62011-11-30 16:26:35 +02004546
Pekka Paalanen77346a62011-11-30 16:26:35 +02004547 terminate_screensaver(shell);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02004548
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05004549 wl_list_remove(&shell->lock_layer.link);
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02004550 if (shell->showing_input_panels) {
Manuel Bachmann805d2f52014-03-05 12:21:34 +01004551 wl_list_insert(&shell->compositor->cursor_layer.link,
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02004552 &shell->input_panel_layer.link);
4553 wl_list_insert(&shell->input_panel_layer.link,
Manuel Bachmann805d2f52014-03-05 12:21:34 +01004554 &shell->fullscreen_layer.link);
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02004555 } else {
Manuel Bachmann805d2f52014-03-05 12:21:34 +01004556 wl_list_insert(&shell->compositor->cursor_layer.link,
4557 &shell->fullscreen_layer.link);
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02004558 }
Manuel Bachmann805d2f52014-03-05 12:21:34 +01004559 wl_list_insert(&shell->fullscreen_layer.link,
4560 &shell->panel_layer.link);
4561 wl_list_insert(&shell->panel_layer.link,
4562 &ws->layer.link),
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02004563
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -04004564 restore_focus_state(shell, get_current_workspace(shell));
Jonas Ådahl04769742012-06-13 00:01:24 +02004565
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02004566 shell->locked = false;
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02004567 shell_fade(shell, FADE_IN);
Pekka Paalanenfc6d91a2012-02-10 15:33:10 +02004568 weston_compositor_damage_all(shell->compositor);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02004569}
4570
4571static void
4572desktop_shell_unlock(struct wl_client *client,
4573 struct wl_resource *resource)
4574{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05004575 struct desktop_shell *shell = wl_resource_get_user_data(resource);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02004576
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02004577 shell->prepare_event_sent = false;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02004578
4579 if (shell->locked)
4580 resume_desktop(shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02004581}
4582
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04004583static void
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03004584desktop_shell_set_grab_surface(struct wl_client *client,
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04004585 struct wl_resource *resource,
4586 struct wl_resource *surface_resource)
4587{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05004588 struct desktop_shell *shell = wl_resource_get_user_data(resource);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04004589
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05004590 shell->grab_surface = wl_resource_get_user_data(surface_resource);
Kristian Høgsberg48588f82013-10-24 15:51:35 -07004591 weston_view_create(shell->grab_surface);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04004592}
4593
Pekka Paalanen79346ab2013-05-22 18:03:09 +03004594static void
4595desktop_shell_desktop_ready(struct wl_client *client,
4596 struct wl_resource *resource)
4597{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05004598 struct desktop_shell *shell = wl_resource_get_user_data(resource);
Pekka Paalanen79346ab2013-05-22 18:03:09 +03004599
4600 shell_fade_startup(shell);
4601}
4602
Jonny Lamb765760d2014-08-20 15:53:19 +02004603static void
4604desktop_shell_set_panel_position(struct wl_client *client,
4605 struct wl_resource *resource,
4606 uint32_t position)
4607{
4608 struct desktop_shell *shell = wl_resource_get_user_data(resource);
4609
4610 if (position != DESKTOP_SHELL_PANEL_POSITION_TOP &&
4611 position != DESKTOP_SHELL_PANEL_POSITION_BOTTOM &&
4612 position != DESKTOP_SHELL_PANEL_POSITION_LEFT &&
4613 position != DESKTOP_SHELL_PANEL_POSITION_RIGHT) {
4614 wl_resource_post_error(resource,
4615 DESKTOP_SHELL_ERROR_INVALID_ARGUMENT,
4616 "bad position argument");
4617 return;
4618 }
4619
4620 shell->panel_position = position;
4621}
4622
Kristian Høgsberg75840622011-09-06 13:48:16 -04004623static const struct desktop_shell_interface desktop_shell_implementation = {
4624 desktop_shell_set_background,
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02004625 desktop_shell_set_panel,
4626 desktop_shell_set_lock_surface,
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04004627 desktop_shell_unlock,
Pekka Paalanen79346ab2013-05-22 18:03:09 +03004628 desktop_shell_set_grab_surface,
Jonny Lamb765760d2014-08-20 15:53:19 +02004629 desktop_shell_desktop_ready,
4630 desktop_shell_set_panel_position
Kristian Høgsberg75840622011-09-06 13:48:16 -04004631};
4632
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02004633static enum shell_surface_type
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05004634get_shell_surface_type(struct weston_surface *surface)
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02004635{
4636 struct shell_surface *shsurf;
4637
4638 shsurf = get_shell_surface(surface);
4639 if (!shsurf)
Pekka Paalanen98262232011-12-01 10:42:22 +02004640 return SHELL_SURFACE_NONE;
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02004641 return shsurf->type;
4642}
4643
Kristian Høgsberg75840622011-09-06 13:48:16 -04004644static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04004645move_binding(struct weston_seat *seat, uint32_t time, uint32_t button, void *data)
Kristian Høgsberg07937562011-04-12 17:25:42 -04004646{
Rafal Mielniczukb2917a22014-01-05 20:04:59 +01004647 struct weston_surface *focus;
Pekka Paalanen01388e22013-04-25 13:57:44 +03004648 struct weston_surface *surface;
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04004649 struct shell_surface *shsurf;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -05004650
Rafal Mielniczukb2917a22014-01-05 20:04:59 +01004651 if (seat->pointer->focus == NULL)
4652 return;
4653
4654 focus = seat->pointer->focus->surface;
4655
Pekka Paalanen01388e22013-04-25 13:57:44 +03004656 surface = weston_surface_get_main_surface(focus);
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01004657 if (surface == NULL)
4658 return;
Kristian Høgsberg07937562011-04-12 17:25:42 -04004659
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04004660 shsurf = get_shell_surface(surface);
Rafael Antognolli03b16592013-12-03 15:35:42 -02004661 if (shsurf == NULL || shsurf->state.fullscreen ||
4662 shsurf->state.maximized)
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04004663 return;
4664
Derek Foreman8aeeac82015-01-30 13:24:36 -06004665 surface_move(shsurf, seat, 0);
Kristian Høgsberg07937562011-04-12 17:25:42 -04004666}
4667
4668static void
Rafael Antognolliea997ac2013-12-03 15:35:48 -02004669maximize_binding(struct weston_seat *seat, uint32_t time, uint32_t button, void *data)
4670{
Emilio Pozuelo Monfort38b58eb2014-01-29 11:11:12 +01004671 struct weston_surface *focus = seat->keyboard->focus;
Rafael Antognolliea997ac2013-12-03 15:35:48 -02004672 struct weston_surface *surface;
4673 struct shell_surface *shsurf;
4674
4675 surface = weston_surface_get_main_surface(focus);
4676 if (surface == NULL)
4677 return;
4678
4679 shsurf = get_shell_surface(surface);
4680 if (shsurf == NULL)
4681 return;
4682
4683 if (!shell_surface_is_xdg_surface(shsurf))
4684 return;
4685
Jasper St. Pierreab2c1082014-04-10 10:41:46 -07004686 shsurf->state_requested = true;
4687 shsurf->requested_state.maximized = !shsurf->state.maximized;
Jasper St. Pierre9aa8ce62014-04-11 16:18:54 -07004688 send_configure_for_surface(shsurf);
Rafael Antognolliea997ac2013-12-03 15:35:48 -02004689}
4690
4691static void
4692fullscreen_binding(struct weston_seat *seat, uint32_t time, uint32_t button, void *data)
4693{
Emilio Pozuelo Monfort38b58eb2014-01-29 11:11:12 +01004694 struct weston_surface *focus = seat->keyboard->focus;
Rafael Antognolliea997ac2013-12-03 15:35:48 -02004695 struct weston_surface *surface;
4696 struct shell_surface *shsurf;
4697
4698 surface = weston_surface_get_main_surface(focus);
4699 if (surface == NULL)
4700 return;
4701
4702 shsurf = get_shell_surface(surface);
4703 if (shsurf == NULL)
4704 return;
4705
4706 if (!shell_surface_is_xdg_surface(shsurf))
4707 return;
4708
Jasper St. Pierreab2c1082014-04-10 10:41:46 -07004709 shsurf->state_requested = true;
4710 shsurf->requested_state.fullscreen = !shsurf->state.fullscreen;
Boyan Ding32abdbb2014-06-26 10:19:32 +08004711 shsurf->fullscreen_output = shsurf->output;
Jasper St. Pierre9aa8ce62014-04-11 16:18:54 -07004712 send_configure_for_surface(shsurf);
Rafael Antognolliea997ac2013-12-03 15:35:48 -02004713}
4714
4715static void
Neil Robertsaba0f252013-10-03 16:43:05 +01004716touch_move_binding(struct weston_seat *seat, uint32_t time, void *data)
4717{
Derek Foreman362656b2014-09-04 10:23:05 -05004718 struct weston_surface *focus;
Neil Robertsaba0f252013-10-03 16:43:05 +01004719 struct weston_surface *surface;
4720 struct shell_surface *shsurf;
4721
Derek Foreman362656b2014-09-04 10:23:05 -05004722 if (seat->touch->focus == NULL)
4723 return;
4724
4725 focus = seat->touch->focus->surface;
Neil Robertsaba0f252013-10-03 16:43:05 +01004726 surface = weston_surface_get_main_surface(focus);
4727 if (surface == NULL)
4728 return;
4729
4730 shsurf = get_shell_surface(surface);
Rafael Antognolli03b16592013-12-03 15:35:42 -02004731 if (shsurf == NULL || shsurf->state.fullscreen ||
4732 shsurf->state.maximized)
Neil Robertsaba0f252013-10-03 16:43:05 +01004733 return;
4734
Derek Foreman8aeeac82015-01-30 13:24:36 -06004735 surface_touch_move(shsurf, seat);
Neil Robertsaba0f252013-10-03 16:43:05 +01004736}
4737
4738static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04004739resize_binding(struct weston_seat *seat, uint32_t time, uint32_t button, void *data)
Kristian Høgsberg07937562011-04-12 17:25:42 -04004740{
Rafal Mielniczukb2917a22014-01-05 20:04:59 +01004741 struct weston_surface *focus;
Pekka Paalanen01388e22013-04-25 13:57:44 +03004742 struct weston_surface *surface;
Kristian Høgsberg07937562011-04-12 17:25:42 -04004743 uint32_t edges = 0;
4744 int32_t x, y;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02004745 struct shell_surface *shsurf;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -05004746
Rafal Mielniczukb2917a22014-01-05 20:04:59 +01004747 if (seat->pointer->focus == NULL)
4748 return;
4749
4750 focus = seat->pointer->focus->surface;
4751
Pekka Paalanen01388e22013-04-25 13:57:44 +03004752 surface = weston_surface_get_main_surface(focus);
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01004753 if (surface == NULL)
4754 return;
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02004755
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02004756 shsurf = get_shell_surface(surface);
Rafael Antognolli03b16592013-12-03 15:35:42 -02004757 if (shsurf == NULL || shsurf->state.fullscreen ||
4758 shsurf->state.maximized)
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02004759 return;
4760
Jason Ekstranda7af7042013-10-12 22:38:11 -05004761 weston_view_from_global(shsurf->view,
4762 wl_fixed_to_int(seat->pointer->grab_x),
4763 wl_fixed_to_int(seat->pointer->grab_y),
4764 &x, &y);
Kristian Høgsberg07937562011-04-12 17:25:42 -04004765
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004766 if (x < shsurf->surface->width / 3)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02004767 edges |= WL_SHELL_SURFACE_RESIZE_LEFT;
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004768 else if (x < 2 * shsurf->surface->width / 3)
Kristian Høgsberg07937562011-04-12 17:25:42 -04004769 edges |= 0;
4770 else
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02004771 edges |= WL_SHELL_SURFACE_RESIZE_RIGHT;
Kristian Høgsberg07937562011-04-12 17:25:42 -04004772
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004773 if (y < shsurf->surface->height / 3)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02004774 edges |= WL_SHELL_SURFACE_RESIZE_TOP;
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004775 else if (y < 2 * shsurf->surface->height / 3)
Kristian Høgsberg07937562011-04-12 17:25:42 -04004776 edges |= 0;
4777 else
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02004778 edges |= WL_SHELL_SURFACE_RESIZE_BOTTOM;
Kristian Høgsberg07937562011-04-12 17:25:42 -04004779
Derek Foreman8aeeac82015-01-30 13:24:36 -06004780 surface_resize(shsurf, seat, edges);
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04004781}
4782
4783static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04004784surface_opacity_binding(struct weston_seat *seat, uint32_t time, uint32_t axis,
Daniel Stone0c1e46e2012-05-30 16:31:59 +01004785 wl_fixed_t value, void *data)
Scott Moreaua3aa9c92012-03-22 11:01:03 -06004786{
Jonas Ådahlb0b87ba2012-09-27 18:40:42 +02004787 float step = 0.005;
Scott Moreaua3aa9c92012-03-22 11:01:03 -06004788 struct shell_surface *shsurf;
Kristian Høgsberg7ab139c2013-10-24 16:21:39 -07004789 struct weston_surface *focus = seat->pointer->focus->surface;
Pekka Paalanen01388e22013-04-25 13:57:44 +03004790 struct weston_surface *surface;
Scott Moreaua3aa9c92012-03-22 11:01:03 -06004791
Pekka Paalanen01388e22013-04-25 13:57:44 +03004792 /* XXX: broken for windows containing sub-surfaces */
4793 surface = weston_surface_get_main_surface(focus);
Scott Moreaua3aa9c92012-03-22 11:01:03 -06004794 if (surface == NULL)
4795 return;
4796
4797 shsurf = get_shell_surface(surface);
4798 if (!shsurf)
4799 return;
4800
Jason Ekstranda7af7042013-10-12 22:38:11 -05004801 shsurf->view->alpha -= wl_fixed_to_double(value) * step;
Scott Moreaua3aa9c92012-03-22 11:01:03 -06004802
Jason Ekstranda7af7042013-10-12 22:38:11 -05004803 if (shsurf->view->alpha > 1.0)
4804 shsurf->view->alpha = 1.0;
4805 if (shsurf->view->alpha < step)
4806 shsurf->view->alpha = step;
Scott Moreaua3aa9c92012-03-22 11:01:03 -06004807
Jason Ekstranda7af7042013-10-12 22:38:11 -05004808 weston_view_geometry_dirty(shsurf->view);
Scott Moreaua3aa9c92012-03-22 11:01:03 -06004809 weston_surface_damage(surface);
4810}
4811
4812static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04004813do_zoom(struct weston_seat *seat, uint32_t time, uint32_t key, uint32_t axis,
Daniel Stone0c1e46e2012-05-30 16:31:59 +01004814 wl_fixed_t value)
Scott Moreauccbf29d2012-02-22 14:21:41 -07004815{
Derek Foreman8aeeac82015-01-30 13:24:36 -06004816 struct weston_compositor *compositor = seat->compositor;
Scott Moreauccbf29d2012-02-22 14:21:41 -07004817 struct weston_output *output;
Scott Moreaue6603982012-06-11 13:07:51 -06004818 float increment;
Scott Moreauccbf29d2012-02-22 14:21:41 -07004819
Derek Foreman7ef3bed2015-01-06 14:28:13 -06004820 if (!seat->pointer) {
4821 weston_log("Zoom hotkey pressed but seat '%s' contains no pointer.\n", seat->seat_name);
4822 return;
4823 }
4824
Scott Moreauccbf29d2012-02-22 14:21:41 -07004825 wl_list_for_each(output, &compositor->output_list, link) {
4826 if (pixman_region32_contains_point(&output->region,
Daniel Stone37816df2012-05-16 18:45:18 +01004827 wl_fixed_to_double(seat->pointer->x),
4828 wl_fixed_to_double(seat->pointer->y),
Daniel Stone103db7f2012-05-08 17:17:55 +01004829 NULL)) {
Daniel Stone325fc2d2012-05-30 16:31:58 +01004830 if (key == KEY_PAGEUP)
Kristian Høgsberg9b68af02012-05-22 12:55:18 -04004831 increment = output->zoom.increment;
Daniel Stone325fc2d2012-05-30 16:31:58 +01004832 else if (key == KEY_PAGEDOWN)
Kristian Høgsberg9b68af02012-05-22 12:55:18 -04004833 increment = -output->zoom.increment;
4834 else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
Jonas Ådahlb0b87ba2012-09-27 18:40:42 +02004835 /* For every pixel zoom 20th of a step */
Daniel Stone0c1e46e2012-05-30 16:31:59 +01004836 increment = output->zoom.increment *
Jonas Ådahlb0b87ba2012-09-27 18:40:42 +02004837 -wl_fixed_to_double(value) / 20.0;
Kristian Høgsberg9b68af02012-05-22 12:55:18 -04004838 else
4839 increment = 0;
4840
Kristian Høgsberg9b68af02012-05-22 12:55:18 -04004841 output->zoom.level += increment;
Scott Moreauc6d7f602012-02-23 22:28:37 -07004842
Scott Moreaue6603982012-06-11 13:07:51 -06004843 if (output->zoom.level < 0.0)
Scott Moreau850ca422012-05-21 15:21:25 -06004844 output->zoom.level = 0.0;
Scott Moreaue6603982012-06-11 13:07:51 -06004845 else if (output->zoom.level > output->zoom.max_level)
4846 output->zoom.level = output->zoom.max_level;
Ville Syrjäläaa628d02012-11-16 11:48:47 +02004847 else if (!output->zoom.active) {
Giulio Camuffo412b0242013-11-14 23:42:51 +01004848 weston_output_activate_zoom(output);
Kristian Høgsberg79af73e2012-08-03 15:45:23 -04004849 }
Scott Moreauccbf29d2012-02-22 14:21:41 -07004850
Scott Moreaue6603982012-06-11 13:07:51 -06004851 output->zoom.spring_z.target = output->zoom.level;
Scott Moreauccbf29d2012-02-22 14:21:41 -07004852
Jason Ekstranda7af7042013-10-12 22:38:11 -05004853 weston_output_update_zoom(output);
Scott Moreauccbf29d2012-02-22 14:21:41 -07004854 }
4855 }
4856}
4857
Scott Moreauccbf29d2012-02-22 14:21:41 -07004858static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04004859zoom_axis_binding(struct weston_seat *seat, uint32_t time, uint32_t axis,
Daniel Stone0c1e46e2012-05-30 16:31:59 +01004860 wl_fixed_t value, void *data)
Daniel Stone325fc2d2012-05-30 16:31:58 +01004861{
4862 do_zoom(seat, time, 0, axis, value);
4863}
4864
4865static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04004866zoom_key_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
Daniel Stone325fc2d2012-05-30 16:31:58 +01004867 void *data)
4868{
4869 do_zoom(seat, time, key, 0, 0);
4870}
4871
4872static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04004873terminate_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
Daniel Stone325fc2d2012-05-30 16:31:58 +01004874 void *data)
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05004875{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05004876 struct weston_compositor *compositor = data;
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05004877
Daniel Stone325fc2d2012-05-30 16:31:58 +01004878 wl_display_terminate(compositor->wl_display);
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05004879}
4880
Emilio Pozuelo Monfort03251b62013-11-19 11:37:16 +01004881static void
Giulio Camuffo1959ab82013-11-14 23:42:52 +01004882rotate_grab_motion(struct weston_pointer_grab *grab, uint32_t time,
4883 wl_fixed_t x, wl_fixed_t y)
Pekka Paalanen460099f2012-01-20 16:48:25 +02004884{
4885 struct rotate_grab *rotate =
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004886 container_of(grab, struct rotate_grab, base.grab);
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04004887 struct weston_pointer *pointer = grab->pointer;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004888 struct shell_surface *shsurf = rotate->base.shsurf;
John Kåre Alsaker490d02a2012-09-30 02:57:21 +02004889 float cx, cy, dx, dy, cposx, cposy, dposx, dposy, r;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004890
Giulio Camuffo1959ab82013-11-14 23:42:52 +01004891 weston_pointer_move(pointer, x, y);
4892
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004893 if (!shsurf)
4894 return;
4895
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004896 cx = 0.5f * shsurf->surface->width;
4897 cy = 0.5f * shsurf->surface->height;
Pekka Paalanen460099f2012-01-20 16:48:25 +02004898
Daniel Stone37816df2012-05-16 18:45:18 +01004899 dx = wl_fixed_to_double(pointer->x) - rotate->center.x;
4900 dy = wl_fixed_to_double(pointer->y) - rotate->center.y;
Pekka Paalanen460099f2012-01-20 16:48:25 +02004901 r = sqrtf(dx * dx + dy * dy);
4902
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004903 wl_list_remove(&shsurf->rotation.transform.link);
Jason Ekstranda7af7042013-10-12 22:38:11 -05004904 weston_view_geometry_dirty(shsurf->view);
Pekka Paalanen460099f2012-01-20 16:48:25 +02004905
4906 if (r > 20.0f) {
Pekka Paalanen460099f2012-01-20 16:48:25 +02004907 struct weston_matrix *matrix =
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004908 &shsurf->rotation.transform.matrix;
Pekka Paalanen460099f2012-01-20 16:48:25 +02004909
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05004910 weston_matrix_init(&rotate->rotation);
Vasily Khoruzhick1bbf3722013-01-28 22:40:28 +03004911 weston_matrix_rotate_xy(&rotate->rotation, dx / r, dy / r);
Pekka Paalanen460099f2012-01-20 16:48:25 +02004912
4913 weston_matrix_init(matrix);
Pekka Paalanen7b3bd3d2012-01-30 14:16:34 +02004914 weston_matrix_translate(matrix, -cx, -cy, 0.0f);
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004915 weston_matrix_multiply(matrix, &shsurf->rotation.rotation);
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05004916 weston_matrix_multiply(matrix, &rotate->rotation);
Pekka Paalanen7b3bd3d2012-01-30 14:16:34 +02004917 weston_matrix_translate(matrix, cx, cy, 0.0f);
Pekka Paalanen460099f2012-01-20 16:48:25 +02004918
Pekka Paalanenbc0b7e72012-01-24 09:53:37 +02004919 wl_list_insert(
Jason Ekstranda7af7042013-10-12 22:38:11 -05004920 &shsurf->view->geometry.transformation_list,
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004921 &shsurf->rotation.transform.link);
Pekka Paalanen460099f2012-01-20 16:48:25 +02004922 } else {
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004923 wl_list_init(&shsurf->rotation.transform.link);
4924 weston_matrix_init(&shsurf->rotation.rotation);
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05004925 weston_matrix_init(&rotate->rotation);
Pekka Paalanen460099f2012-01-20 16:48:25 +02004926 }
Pekka Paalanenb45ac5e2012-02-09 15:58:44 +02004927
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01004928 /* We need to adjust the position of the surface
4929 * in case it was resized in a rotated state before */
Jason Ekstranda7af7042013-10-12 22:38:11 -05004930 cposx = shsurf->view->geometry.x + cx;
4931 cposy = shsurf->view->geometry.y + cy;
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01004932 dposx = rotate->center.x - cposx;
4933 dposy = rotate->center.y - cposy;
4934 if (dposx != 0.0f || dposy != 0.0f) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05004935 weston_view_set_position(shsurf->view,
4936 shsurf->view->geometry.x + dposx,
4937 shsurf->view->geometry.y + dposy);
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01004938 }
4939
Derek Foreman4b1a0a12014-09-10 15:37:33 -05004940 /* Repaint implies weston_view_update_transform(), which
Pekka Paalanenb45ac5e2012-02-09 15:58:44 +02004941 * lazily applies the damage due to rotation update.
4942 */
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004943 weston_compositor_schedule_repaint(shsurf->surface->compositor);
Pekka Paalanen460099f2012-01-20 16:48:25 +02004944}
4945
4946static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04004947rotate_grab_button(struct weston_pointer_grab *grab,
4948 uint32_t time, uint32_t button, uint32_t state_w)
Pekka Paalanen460099f2012-01-20 16:48:25 +02004949{
4950 struct rotate_grab *rotate =
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004951 container_of(grab, struct rotate_grab, base.grab);
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04004952 struct weston_pointer *pointer = grab->pointer;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004953 struct shell_surface *shsurf = rotate->base.shsurf;
Daniel Stone4dbadb12012-05-30 16:31:51 +01004954 enum wl_pointer_button_state state = state_w;
Pekka Paalanen460099f2012-01-20 16:48:25 +02004955
Daniel Stone4dbadb12012-05-30 16:31:51 +01004956 if (pointer->button_count == 0 &&
4957 state == WL_POINTER_BUTTON_STATE_RELEASED) {
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004958 if (shsurf)
4959 weston_matrix_multiply(&shsurf->rotation.rotation,
4960 &rotate->rotation);
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03004961 shell_grab_end(&rotate->base);
Pekka Paalanen460099f2012-01-20 16:48:25 +02004962 free(rotate);
4963 }
4964}
4965
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02004966static void
4967rotate_grab_cancel(struct weston_pointer_grab *grab)
4968{
4969 struct rotate_grab *rotate =
4970 container_of(grab, struct rotate_grab, base.grab);
4971
4972 shell_grab_end(&rotate->base);
4973 free(rotate);
4974}
4975
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04004976static const struct weston_pointer_grab_interface rotate_grab_interface = {
Pekka Paalanen460099f2012-01-20 16:48:25 +02004977 noop_grab_focus,
4978 rotate_grab_motion,
4979 rotate_grab_button,
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02004980 rotate_grab_cancel,
Pekka Paalanen460099f2012-01-20 16:48:25 +02004981};
4982
4983static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04004984surface_rotate(struct shell_surface *surface, struct weston_seat *seat)
Pekka Paalanen460099f2012-01-20 16:48:25 +02004985{
Pekka Paalanen460099f2012-01-20 16:48:25 +02004986 struct rotate_grab *rotate;
John Kåre Alsaker490d02a2012-09-30 02:57:21 +02004987 float dx, dy;
4988 float r;
Pekka Paalanen460099f2012-01-20 16:48:25 +02004989
Pekka Paalanen460099f2012-01-20 16:48:25 +02004990 rotate = malloc(sizeof *rotate);
4991 if (!rotate)
4992 return;
4993
Jason Ekstranda7af7042013-10-12 22:38:11 -05004994 weston_view_to_global_float(surface->view,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004995 surface->surface->width * 0.5f,
4996 surface->surface->height * 0.5f,
Jason Ekstranda7af7042013-10-12 22:38:11 -05004997 &rotate->center.x, &rotate->center.y);
Pekka Paalanen460099f2012-01-20 16:48:25 +02004998
Daniel Stone37816df2012-05-16 18:45:18 +01004999 dx = wl_fixed_to_double(seat->pointer->x) - rotate->center.x;
5000 dy = wl_fixed_to_double(seat->pointer->y) - rotate->center.y;
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05005001 r = sqrtf(dx * dx + dy * dy);
5002 if (r > 20.0f) {
5003 struct weston_matrix inverse;
5004
5005 weston_matrix_init(&inverse);
Vasily Khoruzhick1bbf3722013-01-28 22:40:28 +03005006 weston_matrix_rotate_xy(&inverse, dx / r, -dy / r);
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05005007 weston_matrix_multiply(&surface->rotation.rotation, &inverse);
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01005008
5009 weston_matrix_init(&rotate->rotation);
Vasily Khoruzhick1bbf3722013-01-28 22:40:28 +03005010 weston_matrix_rotate_xy(&rotate->rotation, dx / r, dy / r);
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05005011 } else {
5012 weston_matrix_init(&surface->rotation.rotation);
5013 weston_matrix_init(&rotate->rotation);
5014 }
5015
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03005016 shell_grab_start(&rotate->base, &rotate_grab_interface, surface,
5017 seat->pointer, DESKTOP_SHELL_CURSOR_ARROW);
Pekka Paalanen460099f2012-01-20 16:48:25 +02005018}
5019
5020static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04005021rotate_binding(struct weston_seat *seat, uint32_t time, uint32_t button,
Kristian Høgsberg0c369032013-02-14 21:31:44 -05005022 void *data)
5023{
Rafal Mielniczukb2917a22014-01-05 20:04:59 +01005024 struct weston_surface *focus;
Pekka Paalanen01388e22013-04-25 13:57:44 +03005025 struct weston_surface *base_surface;
Kristian Høgsberg0c369032013-02-14 21:31:44 -05005026 struct shell_surface *surface;
5027
Rafal Mielniczukb2917a22014-01-05 20:04:59 +01005028 if (seat->pointer->focus == NULL)
5029 return;
5030
5031 focus = seat->pointer->focus->surface;
5032
Pekka Paalanen01388e22013-04-25 13:57:44 +03005033 base_surface = weston_surface_get_main_surface(focus);
Kristian Høgsberg0c369032013-02-14 21:31:44 -05005034 if (base_surface == NULL)
5035 return;
5036
5037 surface = get_shell_surface(base_surface);
Rafael Antognolli03b16592013-12-03 15:35:42 -02005038 if (surface == NULL || surface->state.fullscreen ||
5039 surface->state.maximized)
Kristian Høgsberg0c369032013-02-14 21:31:44 -05005040 return;
5041
5042 surface_rotate(surface, seat);
5043}
5044
Emilio Pozuelo Monfort9e7c7592014-01-30 14:01:10 +01005045/* Move all fullscreen layers down to the current workspace and hide their
5046 * black views. The surfaces' state is set to both fullscreen and lowered,
5047 * and this is reversed when such a surface is re-configured, see
5048 * shell_configure_fullscreen() and shell_ensure_fullscreen_black_view().
5049 *
5050 * This should be used when implementing shell-wide overlays, such as
Philip Withnall83ffd9d2013-11-25 18:01:42 +00005051 * the alt-tab switcher, which need to de-promote fullscreen layers. */
Kristian Høgsberg1ef23132013-12-04 00:20:01 -08005052void
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04005053lower_fullscreen_layer(struct desktop_shell *shell)
5054{
5055 struct workspace *ws;
Jason Ekstranda7af7042013-10-12 22:38:11 -05005056 struct weston_view *view, *prev;
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04005057
5058 ws = get_current_workspace(shell);
Jason Ekstranda7af7042013-10-12 22:38:11 -05005059 wl_list_for_each_reverse_safe(view, prev,
Giulio Camuffo412e6a52014-07-09 22:12:56 +03005060 &shell->fullscreen_layer.view_list.link,
5061 layer_link.link) {
Emilio Pozuelo Monfort9e7c7592014-01-30 14:01:10 +01005062 struct shell_surface *shsurf = get_shell_surface(view->surface);
5063
5064 if (!shsurf)
5065 continue;
5066
5067 /* We can have a non-fullscreen popup for a fullscreen surface
5068 * in the fullscreen layer. */
5069 if (shsurf->state.fullscreen) {
5070 /* Hide the black view */
Giulio Camuffo412e6a52014-07-09 22:12:56 +03005071 weston_layer_entry_remove(&shsurf->fullscreen.black_view->layer_link);
5072 wl_list_init(&shsurf->fullscreen.black_view->layer_link.link);
Kristian Høgsbergc9915132014-05-09 16:24:07 -07005073 weston_view_damage_below(shsurf->fullscreen.black_view);
5074
Emilio Pozuelo Monfort9e7c7592014-01-30 14:01:10 +01005075 }
5076
5077 /* Lower the view to the workspace layer */
Giulio Camuffo412e6a52014-07-09 22:12:56 +03005078 weston_layer_entry_remove(&view->layer_link);
5079 weston_layer_entry_insert(&ws->layer.view_list, &view->layer_link);
Philip Withnall83ffd9d2013-11-25 18:01:42 +00005080 weston_view_damage_below(view);
5081 weston_surface_damage(view->surface);
Emilio Pozuelo Monfort9e7c7592014-01-30 14:01:10 +01005082
5083 shsurf->state.lowered = true;
Philip Withnall83ffd9d2013-11-25 18:01:42 +00005084 }
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04005085}
5086
Kristian Høgsberg1ef23132013-12-04 00:20:01 -08005087void
Tiago Vignattibe143262012-04-16 17:31:41 +03005088activate(struct desktop_shell *shell, struct weston_surface *es,
Emilio Pozuelo Monfort9e7c7592014-01-30 14:01:10 +01005089 struct weston_seat *seat, bool configure)
Kristian Høgsberg75840622011-09-06 13:48:16 -04005090{
Pekka Paalanen01388e22013-04-25 13:57:44 +03005091 struct weston_surface *main_surface;
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -04005092 struct focus_state *state;
Jonas Ådahl8538b222012-08-29 22:13:03 +02005093 struct workspace *ws;
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01005094 struct weston_surface *old_es;
Rafael Antognolli03b16592013-12-03 15:35:42 -02005095 struct shell_surface *shsurf;
Kristian Høgsberg75840622011-09-06 13:48:16 -04005096
Kristian Høgsberg6110d072014-04-29 15:15:45 -07005097 lower_fullscreen_layer(shell);
5098
Pekka Paalanen01388e22013-04-25 13:57:44 +03005099 main_surface = weston_surface_get_main_surface(es);
5100
Daniel Stone37816df2012-05-16 18:45:18 +01005101 weston_surface_activate(es, seat);
Kristian Høgsberg75840622011-09-06 13:48:16 -04005102
Jonas Ådahl8538b222012-08-29 22:13:03 +02005103 state = ensure_focus_state(shell, seat);
5104 if (state == NULL)
5105 return;
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -04005106
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01005107 old_es = state->keyboard_focus;
Kristian Høgsbergd500bf12014-01-22 12:25:20 -08005108 focus_state_set_focus(state, es);
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -04005109
Rafael Antognolli03b16592013-12-03 15:35:42 -02005110 shsurf = get_shell_surface(main_surface);
U. Artie Eoffcf5737a2014-01-17 10:08:25 -08005111 assert(shsurf);
5112
Emilio Pozuelo Monfort9e7c7592014-01-30 14:01:10 +01005113 if (shsurf->state.fullscreen && configure)
Rafael Antognolli03b16592013-12-03 15:35:42 -02005114 shell_configure_fullscreen(shsurf);
5115 else
Alexander Larssonf82b6ca2013-05-28 16:23:39 +02005116 restore_all_output_modes(shell->compositor);
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01005117
Emilio Pozuelo Monfort7908bff2014-01-30 13:49:39 +01005118 /* Update the surface’s layer. This brings it to the top of the stacking
5119 * order as appropriate. */
5120 shell_surface_update_layer(shsurf);
5121
Philip Withnall83ffd9d2013-11-25 18:01:42 +00005122 if (shell->focus_animation_type != ANIMATION_NONE) {
5123 ws = get_current_workspace(shell);
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01005124 animate_focus_change(shell, ws, get_default_view(old_es), get_default_view(es));
Philip Withnall83ffd9d2013-11-25 18:01:42 +00005125 }
Kristian Høgsberg75840622011-09-06 13:48:16 -04005126}
5127
Alex Wu21858432012-04-01 20:13:08 +08005128/* no-op func for checking black surface */
5129static void
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06005130black_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
Alex Wu21858432012-04-01 20:13:08 +08005131{
5132}
5133
Quentin Glidicc0d79ce2013-01-29 14:16:13 +01005134static bool
Alex Wu21858432012-04-01 20:13:08 +08005135is_black_surface (struct weston_surface *es, struct weston_surface **fs_surface)
5136{
5137 if (es->configure == black_surface_configure) {
5138 if (fs_surface)
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01005139 *fs_surface = (struct weston_surface *)es->configure_private;
Alex Wu21858432012-04-01 20:13:08 +08005140 return true;
5141 }
5142 return false;
5143}
5144
Kristian Høgsberg75840622011-09-06 13:48:16 -04005145static void
Neil Robertsa28c6932013-10-03 16:43:04 +01005146activate_binding(struct weston_seat *seat,
5147 struct desktop_shell *shell,
5148 struct weston_surface *focus)
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05005149{
Pekka Paalanen01388e22013-04-25 13:57:44 +03005150 struct weston_surface *main_surface;
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05005151
Alex Wu9c35e6b2012-03-05 14:13:13 +08005152 if (!focus)
5153 return;
5154
Pekka Paalanen01388e22013-04-25 13:57:44 +03005155 if (is_black_surface(focus, &main_surface))
5156 focus = main_surface;
Alex Wu4539b082012-03-01 12:57:46 +08005157
Pekka Paalanen01388e22013-04-25 13:57:44 +03005158 main_surface = weston_surface_get_main_surface(focus);
5159 if (get_shell_surface_type(main_surface) == SHELL_SURFACE_NONE)
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04005160 return;
Kristian Høgsberg85b2e4b2012-06-21 16:49:42 -04005161
Emilio Pozuelo Monfort9e7c7592014-01-30 14:01:10 +01005162 activate(shell, focus, seat, true);
Neil Robertsa28c6932013-10-03 16:43:04 +01005163}
5164
5165static void
5166click_to_activate_binding(struct weston_seat *seat, uint32_t time, uint32_t button,
5167 void *data)
5168{
5169 if (seat->pointer->grab != &seat->pointer->default_grab)
5170 return;
Kristian Høgsberg7c4f6cc2014-01-01 16:28:32 -08005171 if (seat->pointer->focus == NULL)
5172 return;
Neil Robertsa28c6932013-10-03 16:43:04 +01005173
Kristian Høgsberg7ab139c2013-10-24 16:21:39 -07005174 activate_binding(seat, data, seat->pointer->focus->surface);
Neil Robertsa28c6932013-10-03 16:43:04 +01005175}
5176
5177static void
5178touch_to_activate_binding(struct weston_seat *seat, uint32_t time, void *data)
5179{
5180 if (seat->touch->grab != &seat->touch->default_grab)
5181 return;
Kristian Høgsberg0ed67502014-01-02 23:00:11 -08005182 if (seat->touch->focus == NULL)
5183 return;
Neil Robertsa28c6932013-10-03 16:43:04 +01005184
Kristian Høgsberg7ab139c2013-10-24 16:21:39 -07005185 activate_binding(seat, data, seat->touch->focus->surface);
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05005186}
5187
5188static void
Neil Robertsb4a91702014-04-09 16:33:32 +01005189unfocus_all_seats(struct desktop_shell *shell)
5190{
5191 struct weston_seat *seat, *next;
5192
5193 wl_list_for_each_safe(seat, next, &shell->compositor->seat_list, link) {
5194 if (seat->keyboard == NULL)
5195 continue;
5196
5197 weston_keyboard_set_focus(seat->keyboard, NULL);
5198 }
5199}
5200
5201static void
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02005202lock(struct desktop_shell *shell)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04005203{
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04005204 struct workspace *ws = get_current_workspace(shell);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02005205
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02005206 if (shell->locked) {
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02005207 weston_compositor_sleep(shell->compositor);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02005208 return;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02005209 }
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02005210
5211 shell->locked = true;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02005212
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05005213 /* Hide all surfaces by removing the fullscreen, panel and
5214 * toplevel layers. This way nothing else can show or receive
5215 * input events while we are locked. */
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02005216
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05005217 wl_list_remove(&shell->panel_layer.link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05005218 wl_list_remove(&shell->fullscreen_layer.link);
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02005219 if (shell->showing_input_panels)
5220 wl_list_remove(&shell->input_panel_layer.link);
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04005221 wl_list_remove(&ws->layer.link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05005222 wl_list_insert(&shell->compositor->cursor_layer.link,
5223 &shell->lock_layer.link);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02005224
Pekka Paalanen77346a62011-11-30 16:26:35 +02005225 launch_screensaver(shell);
5226
Neil Robertsb4a91702014-04-09 16:33:32 +01005227 /* Remove the keyboard focus on all seats. This will be
5228 * restored to the workspace's saved state via
5229 * restore_focus_state when the compositor is unlocked */
5230 unfocus_all_seats(shell);
5231
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02005232 /* TODO: disable bindings that should not work while locked. */
5233
5234 /* All this must be undone in resume_desktop(). */
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02005235}
5236
5237static void
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02005238unlock(struct desktop_shell *shell)
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02005239{
Pekka Paalanend81c2162011-11-16 13:47:34 +02005240 if (!shell->locked || shell->lock_surface) {
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02005241 shell_fade(shell, FADE_IN);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02005242 return;
5243 }
5244
5245 /* If desktop-shell client has gone away, unlock immediately. */
5246 if (!shell->child.desktop_shell) {
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02005247 resume_desktop(shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02005248 return;
5249 }
5250
5251 if (shell->prepare_event_sent)
5252 return;
5253
Kristian Høgsberg0b5cd0c2012-03-04 21:57:37 -05005254 desktop_shell_send_prepare_lock_surface(shell->child.desktop_shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02005255 shell->prepare_event_sent = true;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04005256}
5257
5258static void
Jason Ekstranda7af7042013-10-12 22:38:11 -05005259shell_fade_done(struct weston_view_animation *animation, void *data)
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02005260{
5261 struct desktop_shell *shell = data;
5262
5263 shell->fade.animation = NULL;
5264
5265 switch (shell->fade.type) {
5266 case FADE_IN:
Jason Ekstranda7af7042013-10-12 22:38:11 -05005267 weston_surface_destroy(shell->fade.view->surface);
5268 shell->fade.view = NULL;
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02005269 break;
5270 case FADE_OUT:
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02005271 lock(shell);
5272 break;
Philip Withnall4a86a0a2013-11-25 18:01:32 +00005273 default:
5274 break;
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02005275 }
5276}
5277
Jason Ekstranda7af7042013-10-12 22:38:11 -05005278static struct weston_view *
Pekka Paalanen79346ab2013-05-22 18:03:09 +03005279shell_fade_create_surface(struct desktop_shell *shell)
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02005280{
5281 struct weston_compositor *compositor = shell->compositor;
5282 struct weston_surface *surface;
Jason Ekstranda7af7042013-10-12 22:38:11 -05005283 struct weston_view *view;
Pekka Paalanen79346ab2013-05-22 18:03:09 +03005284
5285 surface = weston_surface_create(compositor);
5286 if (!surface)
5287 return NULL;
5288
Jason Ekstranda7af7042013-10-12 22:38:11 -05005289 view = weston_view_create(surface);
5290 if (!view) {
5291 weston_surface_destroy(surface);
5292 return NULL;
5293 }
5294
Jason Ekstrand5c11a332013-12-04 20:32:03 -06005295 weston_surface_set_size(surface, 8192, 8192);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06005296 weston_view_set_position(view, 0, 0);
Pekka Paalanen79346ab2013-05-22 18:03:09 +03005297 weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1.0);
Giulio Camuffo412e6a52014-07-09 22:12:56 +03005298 weston_layer_entry_insert(&compositor->fade_layer.view_list,
5299 &view->layer_link);
Pekka Paalanen79346ab2013-05-22 18:03:09 +03005300 pixman_region32_init(&surface->input);
5301
Jason Ekstranda7af7042013-10-12 22:38:11 -05005302 return view;
Pekka Paalanen79346ab2013-05-22 18:03:09 +03005303}
5304
5305static void
5306shell_fade(struct desktop_shell *shell, enum fade_type type)
5307{
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02005308 float tint;
5309
5310 switch (type) {
5311 case FADE_IN:
5312 tint = 0.0;
5313 break;
5314 case FADE_OUT:
5315 tint = 1.0;
5316 break;
5317 default:
5318 weston_log("shell: invalid fade type\n");
5319 return;
5320 }
5321
5322 shell->fade.type = type;
5323
Jason Ekstranda7af7042013-10-12 22:38:11 -05005324 if (shell->fade.view == NULL) {
5325 shell->fade.view = shell_fade_create_surface(shell);
5326 if (!shell->fade.view)
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02005327 return;
5328
Jason Ekstranda7af7042013-10-12 22:38:11 -05005329 shell->fade.view->alpha = 1.0 - tint;
5330 weston_view_update_transform(shell->fade.view);
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02005331 }
5332
Kristian Høgsberg87d3b612014-01-19 21:48:10 -08005333 if (shell->fade.view->output == NULL) {
5334 /* If the black view gets a NULL output, we lost the
5335 * last output and we'll just cancel the fade. This
5336 * happens when you close the last window under the
5337 * X11 or Wayland backends. */
5338 shell->locked = false;
5339 weston_surface_destroy(shell->fade.view->surface);
5340 shell->fade.view = NULL;
5341 } else if (shell->fade.animation) {
Kristian Høgsberg5281fb12013-06-17 10:10:28 -04005342 weston_fade_update(shell->fade.animation, tint);
Kristian Høgsberg87d3b612014-01-19 21:48:10 -08005343 } else {
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02005344 shell->fade.animation =
Jason Ekstranda7af7042013-10-12 22:38:11 -05005345 weston_fade_run(shell->fade.view,
Kristian Høgsberg5281fb12013-06-17 10:10:28 -04005346 1.0 - tint, tint, 300.0,
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02005347 shell_fade_done, shell);
Kristian Høgsberg87d3b612014-01-19 21:48:10 -08005348 }
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02005349}
5350
5351static void
Pekka Paalanen79346ab2013-05-22 18:03:09 +03005352do_shell_fade_startup(void *data)
5353{
5354 struct desktop_shell *shell = data;
5355
Pekka Paalanen23ed5f22015-05-26 11:54:52 +03005356 if (shell->startup_animation_type == ANIMATION_FADE) {
Kristian Høgsberg724c8d92013-10-16 11:38:24 -07005357 shell_fade(shell, FADE_IN);
Pekka Paalanen23ed5f22015-05-26 11:54:52 +03005358 } else {
5359 weston_log("desktop shell: "
5360 "unexpected fade-in animation type %d\n",
5361 shell->startup_animation_type);
Jason Ekstranda7af7042013-10-12 22:38:11 -05005362 weston_surface_destroy(shell->fade.view->surface);
5363 shell->fade.view = NULL;
Kristian Høgsberg724c8d92013-10-16 11:38:24 -07005364 }
Pekka Paalanen79346ab2013-05-22 18:03:09 +03005365}
5366
5367static void
5368shell_fade_startup(struct desktop_shell *shell)
5369{
5370 struct wl_event_loop *loop;
5371
5372 if (!shell->fade.startup_timer)
5373 return;
5374
5375 wl_event_source_remove(shell->fade.startup_timer);
5376 shell->fade.startup_timer = NULL;
5377
5378 loop = wl_display_get_event_loop(shell->compositor->wl_display);
5379 wl_event_loop_add_idle(loop, do_shell_fade_startup, shell);
5380}
5381
5382static int
5383fade_startup_timeout(void *data)
5384{
5385 struct desktop_shell *shell = data;
5386
5387 shell_fade_startup(shell);
5388 return 0;
5389}
5390
5391static void
5392shell_fade_init(struct desktop_shell *shell)
5393{
5394 /* Make compositor output all black, and wait for the desktop-shell
5395 * client to signal it is ready, then fade in. The timer triggers a
5396 * fade-in, in case the desktop-shell client takes too long.
5397 */
5398
5399 struct wl_event_loop *loop;
5400
Jason Ekstranda7af7042013-10-12 22:38:11 -05005401 if (shell->fade.view != NULL) {
Pekka Paalanen79346ab2013-05-22 18:03:09 +03005402 weston_log("%s: warning: fade surface already exists\n",
5403 __func__);
5404 return;
5405 }
5406
Pekka Paalanen23ed5f22015-05-26 11:54:52 +03005407 if (shell->startup_animation_type == ANIMATION_NONE)
5408 return;
5409
Jason Ekstranda7af7042013-10-12 22:38:11 -05005410 shell->fade.view = shell_fade_create_surface(shell);
5411 if (!shell->fade.view)
Pekka Paalanen79346ab2013-05-22 18:03:09 +03005412 return;
5413
Jason Ekstranda7af7042013-10-12 22:38:11 -05005414 weston_view_update_transform(shell->fade.view);
5415 weston_surface_damage(shell->fade.view->surface);
Pekka Paalanen79346ab2013-05-22 18:03:09 +03005416
5417 loop = wl_display_get_event_loop(shell->compositor->wl_display);
5418 shell->fade.startup_timer =
5419 wl_event_loop_add_timer(loop, fade_startup_timeout, shell);
5420 wl_event_source_timer_update(shell->fade.startup_timer, 15000);
5421}
5422
5423static void
Ander Conselvan de Oliveiraa4575632013-02-21 18:35:23 +02005424idle_handler(struct wl_listener *listener, void *data)
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02005425{
5426 struct desktop_shell *shell =
Ander Conselvan de Oliveiraa4575632013-02-21 18:35:23 +02005427 container_of(listener, struct desktop_shell, idle_listener);
Kristian Høgsberg27d5fa82014-01-17 16:22:50 -08005428 struct weston_seat *seat;
5429
Jonny Lamb76cf1fe2014-08-20 11:27:10 +02005430 wl_list_for_each(seat, &shell->compositor->seat_list, link) {
Kristian Høgsberg27d5fa82014-01-17 16:22:50 -08005431 if (seat->pointer)
5432 popup_grab_end(seat->pointer);
Jonny Lamb76cf1fe2014-08-20 11:27:10 +02005433 if (seat->touch)
5434 touch_popup_grab_end(seat->touch);
5435 }
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02005436
5437 shell_fade(shell, FADE_OUT);
5438 /* lock() is called from shell_fade_done() */
5439}
5440
5441static void
Ander Conselvan de Oliveiraa4575632013-02-21 18:35:23 +02005442wake_handler(struct wl_listener *listener, void *data)
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02005443{
5444 struct desktop_shell *shell =
Ander Conselvan de Oliveiraa4575632013-02-21 18:35:23 +02005445 container_of(listener, struct desktop_shell, wake_listener);
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02005446
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02005447 unlock(shell);
5448}
5449
5450static void
Jason Ekstranda7af7042013-10-12 22:38:11 -05005451center_on_output(struct weston_view *view, struct weston_output *output)
Pekka Paalanen77346a62011-11-30 16:26:35 +02005452{
Giulio Camuffob8366642013-04-25 13:57:46 +03005453 int32_t surf_x, surf_y, width, height;
Ander Conselvan de Oliveira012b4c72012-11-27 17:03:42 +02005454 float x, y;
Pekka Paalanen77346a62011-11-30 16:26:35 +02005455
Jason Ekstranda7af7042013-10-12 22:38:11 -05005456 surface_subsurfaces_boundingbox(view->surface, &surf_x, &surf_y, &width, &height);
Giulio Camuffob8366642013-04-25 13:57:46 +03005457
5458 x = output->x + (output->width - width) / 2 - surf_x / 2;
5459 y = output->y + (output->height - height) / 2 - surf_y / 2;
Ander Conselvan de Oliveira012b4c72012-11-27 17:03:42 +02005460
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06005461 weston_view_set_position(view, x, y);
Pekka Paalanen77346a62011-11-30 16:26:35 +02005462}
5463
5464static void
Jason Ekstranda7af7042013-10-12 22:38:11 -05005465weston_view_set_initial_position(struct weston_view *view,
5466 struct desktop_shell *shell)
Rob Bradfordac63e5b2012-08-13 14:07:52 +01005467{
5468 struct weston_compositor *compositor = shell->compositor;
5469 int ix = 0, iy = 0;
Jonny Lambd73c6942014-08-20 15:53:20 +02005470 int32_t range_x, range_y;
5471 int32_t dx, dy, x, y;
Rob Bradfordac63e5b2012-08-13 14:07:52 +01005472 struct weston_output *output, *target_output = NULL;
5473 struct weston_seat *seat;
Jonny Lambd73c6942014-08-20 15:53:20 +02005474 pixman_rectangle32_t area;
Rob Bradfordac63e5b2012-08-13 14:07:52 +01005475
5476 /* As a heuristic place the new window on the same output as the
5477 * pointer. Falling back to the output containing 0, 0.
5478 *
5479 * TODO: Do something clever for touch too?
5480 */
5481 wl_list_for_each(seat, &compositor->seat_list, link) {
Kristian Høgsberg2bf87622013-05-07 23:17:41 -04005482 if (seat->pointer) {
Kristian Høgsberge3148752013-05-06 23:19:49 -04005483 ix = wl_fixed_to_int(seat->pointer->x);
5484 iy = wl_fixed_to_int(seat->pointer->y);
Rob Bradfordac63e5b2012-08-13 14:07:52 +01005485 break;
5486 }
5487 }
5488
5489 wl_list_for_each(output, &compositor->output_list, link) {
5490 if (pixman_region32_contains_point(&output->region, ix, iy, NULL)) {
5491 target_output = output;
5492 break;
5493 }
5494 }
5495
5496 if (!target_output) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05005497 weston_view_set_position(view, 10 + random() % 400,
5498 10 + random() % 400);
Rob Bradfordac63e5b2012-08-13 14:07:52 +01005499 return;
5500 }
5501
5502 /* Valid range within output where the surface will still be onscreen.
5503 * If this is negative it means that the surface is bigger than
5504 * output.
5505 */
Jonny Lambd73c6942014-08-20 15:53:20 +02005506 get_output_work_area(shell, target_output, &area);
5507
5508 dx = area.x;
5509 dy = area.y;
5510 range_x = area.width - view->surface->width;
5511 range_y = area.height - view->surface->height;
Rob Bradfordac63e5b2012-08-13 14:07:52 +01005512
Rob Bradford4cb88c72012-08-13 15:18:44 +01005513 if (range_x > 0)
Jonny Lambd73c6942014-08-20 15:53:20 +02005514 dx += random() % range_x;
Rob Bradford4cb88c72012-08-13 15:18:44 +01005515
5516 if (range_y > 0)
Jonny Lambd73c6942014-08-20 15:53:20 +02005517 dy += random() % range_y;
Rob Bradfordac63e5b2012-08-13 14:07:52 +01005518
5519 x = target_output->x + dx;
5520 y = target_output->y + dy;
5521
Jason Ekstranda7af7042013-10-12 22:38:11 -05005522 weston_view_set_position(view, x, y);
Rob Bradfordac63e5b2012-08-13 14:07:52 +01005523}
5524
5525static void
Jonny Lambd73c6942014-08-20 15:53:20 +02005526set_maximized_position(struct desktop_shell *shell,
5527 struct shell_surface *shsurf)
5528{
5529 int32_t surf_x, surf_y;
5530 pixman_rectangle32_t area;
Marek Chalupa8b771af2014-09-01 17:20:33 +02005531 pixman_box32_t *e;
Jonny Lambd73c6942014-08-20 15:53:20 +02005532
Jonny Lambd73c6942014-08-20 15:53:20 +02005533 get_output_work_area(shell, shsurf->output, &area);
Giulio Camuffo7a8d67d2015-01-09 20:10:45 +02005534 if (shsurf->has_set_geometry) {
5535 surf_x = shsurf->geometry.x;
5536 surf_y = shsurf->geometry.y;
5537 } else {
5538 surface_subsurfaces_boundingbox(shsurf->surface,
5539 &surf_x, &surf_y, NULL, NULL);
5540 }
Marek Chalupa8b771af2014-09-01 17:20:33 +02005541 e = pixman_region32_extents(&shsurf->output->region);
Jonny Lambd73c6942014-08-20 15:53:20 +02005542
5543 weston_view_set_position(shsurf->view,
Marek Chalupa8b771af2014-09-01 17:20:33 +02005544 e->x1 + area.x - surf_x,
5545 e->y1 + area.y - surf_y);
Jonny Lambd73c6942014-08-20 15:53:20 +02005546}
5547
5548static void
Jason Ekstranda7af7042013-10-12 22:38:11 -05005549map(struct desktop_shell *shell, struct shell_surface *shsurf,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06005550 int32_t sx, int32_t sy)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04005551{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05005552 struct weston_compositor *compositor = shell->compositor;
Daniel Stoneb2104682012-05-30 16:31:56 +01005553 struct weston_seat *seat;
Pekka Paalanen57da4a82011-11-23 16:42:16 +02005554
Pekka Paalanen77346a62011-11-30 16:26:35 +02005555 /* initial positioning, see also configure() */
Jason Ekstranda7af7042013-10-12 22:38:11 -05005556 switch (shsurf->type) {
Rafael Antognollied207b42013-12-03 15:35:43 -02005557 case SHELL_SURFACE_TOPLEVEL:
Rafael Antognolli03b16592013-12-03 15:35:42 -02005558 if (shsurf->state.fullscreen) {
5559 center_on_output(shsurf->view, shsurf->fullscreen_output);
5560 shell_map_fullscreen(shsurf);
5561 } else if (shsurf->state.maximized) {
Jonny Lambd73c6942014-08-20 15:53:20 +02005562 set_maximized_position(shell, shsurf);
Rafael Antognollied207b42013-12-03 15:35:43 -02005563 } else if (!shsurf->state.relative) {
Rafael Antognolli03b16592013-12-03 15:35:42 -02005564 weston_view_set_initial_position(shsurf->view, shell);
5565 }
Juan Zhao96879df2012-02-07 08:45:41 +08005566 break;
Tiago Vignatti0f997012012-02-10 16:17:23 +02005567 case SHELL_SURFACE_POPUP:
Jasper St. Pierreda6ecd02015-02-27 18:35:45 +08005568 if (shell_map_popup(shsurf) != 0)
5569 return;
Rob Bradforddb999382012-12-06 12:07:48 +00005570 break;
Ander Conselvan de Oliveirae9e05152012-02-15 17:02:56 +02005571 case SHELL_SURFACE_NONE:
Jason Ekstranda7af7042013-10-12 22:38:11 -05005572 weston_view_set_position(shsurf->view,
5573 shsurf->view->geometry.x + sx,
5574 shsurf->view->geometry.y + sy);
Tiago Vignatti0f997012012-02-10 16:17:23 +02005575 break;
Philip Withnall0f640e22013-11-25 18:01:31 +00005576 case SHELL_SURFACE_XWAYLAND:
Pekka Paalanen77346a62011-11-30 16:26:35 +02005577 default:
5578 ;
5579 }
Kristian Høgsberg75840622011-09-06 13:48:16 -04005580
Philip Withnalle1d75ae2013-11-25 18:01:41 +00005581 /* Surface stacking order, see also activate(). */
5582 shell_surface_update_layer(shsurf);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02005583
Jason Ekstranda7af7042013-10-12 22:38:11 -05005584 if (shsurf->type != SHELL_SURFACE_NONE) {
5585 weston_view_update_transform(shsurf->view);
Rafael Antognolli03b16592013-12-03 15:35:42 -02005586 if (shsurf->state.maximized) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05005587 shsurf->surface->output = shsurf->output;
5588 shsurf->view->output = shsurf->output;
5589 }
Ander Conselvan de Oliveirade56c312012-03-05 15:39:23 +02005590 }
Kristian Høgsberg2f88a402011-12-04 15:32:59 -05005591
Jason Ekstranda7af7042013-10-12 22:38:11 -05005592 switch (shsurf->type) {
Tiago Vignattifb2adba2013-06-12 15:43:21 -03005593 /* XXX: xwayland's using the same fields for transient type */
5594 case SHELL_SURFACE_XWAYLAND:
Tiago Vignatti99aeb1e2012-05-23 22:06:26 +03005595 if (shsurf->transient.flags ==
5596 WL_SHELL_SURFACE_TRANSIENT_INACTIVE)
5597 break;
5598 case SHELL_SURFACE_TOPLEVEL:
Rafael Antognollied207b42013-12-03 15:35:43 -02005599 if (shsurf->state.relative &&
5600 shsurf->transient.flags == WL_SHELL_SURFACE_TRANSIENT_INACTIVE)
5601 break;
Rafael Antognolliba5d2d72013-12-04 17:49:55 -02005602 if (shell->locked)
Rafael Antognollied207b42013-12-03 15:35:43 -02005603 break;
5604 wl_list_for_each(seat, &compositor->seat_list, link)
Emilio Pozuelo Monfort9e7c7592014-01-30 14:01:10 +01005605 activate(shell, shsurf->surface, seat, true);
Juan Zhao7bb92f02011-12-15 11:31:51 -05005606 break;
Philip Withnall0f640e22013-11-25 18:01:31 +00005607 case SHELL_SURFACE_POPUP:
5608 case SHELL_SURFACE_NONE:
Juan Zhao7bb92f02011-12-15 11:31:51 -05005609 default:
5610 break;
5611 }
5612
Rafael Antognolli03b16592013-12-03 15:35:42 -02005613 if (shsurf->type == SHELL_SURFACE_TOPLEVEL &&
5614 !shsurf->state.maximized && !shsurf->state.fullscreen)
Juan Zhaoe10d2792012-04-25 19:09:52 +08005615 {
5616 switch (shell->win_animation_type) {
5617 case ANIMATION_FADE:
Jason Ekstranda7af7042013-10-12 22:38:11 -05005618 weston_fade_run(shsurf->view, 0.0, 1.0, 300.0, NULL, NULL);
Juan Zhaoe10d2792012-04-25 19:09:52 +08005619 break;
5620 case ANIMATION_ZOOM:
Jason Ekstranda7af7042013-10-12 22:38:11 -05005621 weston_zoom_run(shsurf->view, 0.5, 1.0, NULL, NULL);
Juan Zhaoe10d2792012-04-25 19:09:52 +08005622 break;
Philip Withnall4a86a0a2013-11-25 18:01:32 +00005623 case ANIMATION_NONE:
Juan Zhaoe10d2792012-04-25 19:09:52 +08005624 default:
5625 break;
5626 }
5627 }
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05005628}
5629
5630static void
Tiago Vignattibe143262012-04-16 17:31:41 +03005631configure(struct desktop_shell *shell, struct weston_surface *surface,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06005632 float x, float y)
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05005633{
Pekka Paalanen77346a62011-11-30 16:26:35 +02005634 struct shell_surface *shsurf;
Jason Ekstranda7af7042013-10-12 22:38:11 -05005635 struct weston_view *view;
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05005636
Pekka Paalanen77346a62011-11-30 16:26:35 +02005637 shsurf = get_shell_surface(surface);
Pekka Paalanen77346a62011-11-30 16:26:35 +02005638
U. Artie Eoffcf5737a2014-01-17 10:08:25 -08005639 assert(shsurf);
5640
Rafael Antognolli03b16592013-12-03 15:35:42 -02005641 if (shsurf->state.fullscreen)
Alex Wu4539b082012-03-01 12:57:46 +08005642 shell_configure_fullscreen(shsurf);
Rafael Antognolli03b16592013-12-03 15:35:42 -02005643 else if (shsurf->state.maximized) {
Jonny Lambd73c6942014-08-20 15:53:20 +02005644 set_maximized_position(shell, shsurf);
Rafael Antognolli03b16592013-12-03 15:35:42 -02005645 } else {
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06005646 weston_view_set_position(shsurf->view, x, y);
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04005647 }
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05005648
Alex Wu4539b082012-03-01 12:57:46 +08005649 /* XXX: would a fullscreen surface need the same handling? */
Kristian Høgsberg6a8b5532012-02-16 23:43:59 -05005650 if (surface->output) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05005651 wl_list_for_each(view, &surface->views, surface_link)
5652 weston_view_update_transform(view);
Pekka Paalanen77346a62011-11-30 16:26:35 +02005653
Rafael Antognolli03b16592013-12-03 15:35:42 -02005654 if (shsurf->state.maximized)
Juan Zhao96879df2012-02-07 08:45:41 +08005655 surface->output = shsurf->output;
Pekka Paalanen77346a62011-11-30 16:26:35 +02005656 }
Kristian Høgsberg07937562011-04-12 17:25:42 -04005657}
5658
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03005659static void
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06005660shell_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03005661{
Ander Conselvan de Oliveira7fb9f952012-03-27 17:36:42 +03005662 struct shell_surface *shsurf = get_shell_surface(es);
U. Artie Eoffcf5737a2014-01-17 10:08:25 -08005663 struct desktop_shell *shell;
Tiago Vignatti70e5c9c2012-05-07 15:23:07 +03005664 int type_changed = 0;
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03005665
U. Artie Eoffcf5737a2014-01-17 10:08:25 -08005666 assert(shsurf);
5667
5668 shell = shsurf->shell;
5669
Kristian Høgsberg8eb0f4f2013-06-17 10:33:14 -04005670 if (!weston_surface_is_mapped(es) &&
5671 !wl_list_empty(&shsurf->popup.grab_link)) {
Giulio Camuffo5085a752013-03-25 21:42:45 +01005672 remove_popup_grab(shsurf);
5673 }
5674
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06005675 if (es->width == 0)
Giulio Camuffo184df502013-02-21 11:29:21 +01005676 return;
5677
Jasper St. Pierreccf48fb2014-05-02 10:21:38 -04005678 if (shsurf->has_next_geometry) {
5679 shsurf->geometry = shsurf->next_geometry;
5680 shsurf->has_next_geometry = false;
5681 shsurf->has_set_geometry = true;
5682 } else if (!shsurf->has_set_geometry) {
5683 surface_subsurfaces_boundingbox(shsurf->surface,
5684 &shsurf->geometry.x,
5685 &shsurf->geometry.y,
5686 &shsurf->geometry.width,
5687 &shsurf->geometry.height);
Jasper St. Pierre851799e2014-05-02 10:14:07 -04005688 }
5689
Kristian Høgsbergc8f8dd82013-12-05 23:20:33 -08005690 if (shsurf->state_changed) {
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04005691 set_surface_type(shsurf);
Kristian Høgsbergf7e23d52012-04-27 17:51:59 -04005692 type_changed = 1;
5693 }
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04005694
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03005695 if (!weston_surface_is_mapped(es)) {
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06005696 map(shell, shsurf, sx, sy);
Kristian Høgsbergf7e23d52012-04-27 17:51:59 -04005697 } else if (type_changed || sx != 0 || sy != 0 ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06005698 shsurf->last_width != es->width ||
5699 shsurf->last_height != es->height) {
John Kåre Alsaker490d02a2012-09-30 02:57:21 +02005700 float from_x, from_y;
5701 float to_x, to_y;
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03005702
Kristian Høgsberg44cd1962014-02-05 21:36:04 -08005703 if (shsurf->resize_edges) {
5704 sx = 0;
5705 sy = 0;
5706 }
5707
5708 if (shsurf->resize_edges & WL_SHELL_SURFACE_RESIZE_LEFT)
5709 sx = shsurf->last_width - es->width;
5710 if (shsurf->resize_edges & WL_SHELL_SURFACE_RESIZE_TOP)
5711 sy = shsurf->last_height - es->height;
5712
5713 shsurf->last_width = es->width;
5714 shsurf->last_height = es->height;
5715
Jason Ekstranda7af7042013-10-12 22:38:11 -05005716 weston_view_to_global_float(shsurf->view, 0, 0, &from_x, &from_y);
5717 weston_view_to_global_float(shsurf->view, sx, sy, &to_x, &to_y);
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03005718 configure(shell, es,
Jason Ekstranda7af7042013-10-12 22:38:11 -05005719 shsurf->view->geometry.x + to_x - from_x,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06005720 shsurf->view->geometry.y + to_y - from_y);
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03005721 }
5722}
5723
Pekka Paalanen2e62e4a2014-08-28 11:41:26 +03005724static bool
5725check_desktop_shell_crash_too_early(struct desktop_shell *shell)
5726{
5727 struct timespec now;
5728
5729 if (clock_gettime(CLOCK_MONOTONIC, &now) < 0)
5730 return false;
5731
5732 /*
5733 * If the shell helper client dies before the session has been
5734 * up for roughly 30 seconds, better just make Weston shut down,
5735 * because the user likely has no way to interact with the desktop
5736 * anyway.
5737 */
5738 if (now.tv_sec - shell->startup_time.tv_sec < 30) {
5739 weston_log("Error: %s apparently cannot run at all.\n",
5740 shell->client);
5741 weston_log_continue(STAMP_SPACE "Quitting...");
5742 wl_display_terminate(shell->compositor->wl_display);
5743
5744 return true;
5745 }
5746
5747 return false;
5748}
5749
Tiago Vignattib7dbbd62012-09-25 17:57:01 +03005750static void launch_desktop_shell_process(void *data);
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02005751
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04005752static void
Pekka Paalanen826dc142014-08-27 12:11:53 +03005753respawn_desktop_shell_process(struct desktop_shell *shell)
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02005754{
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02005755 uint32_t time;
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02005756
5757 /* if desktop-shell dies more than 5 times in 30 seconds, give up */
5758 time = weston_compositor_get_time();
Kristian Høgsbergf03a6162012-01-17 11:07:42 -05005759 if (time - shell->child.deathstamp > 30000) {
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02005760 shell->child.deathstamp = time;
5761 shell->child.deathcount = 0;
5762 }
5763
5764 shell->child.deathcount++;
5765 if (shell->child.deathcount > 5) {
Pekka Paalanen826dc142014-08-27 12:11:53 +03005766 weston_log("%s disconnected, giving up.\n", shell->client);
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02005767 return;
5768 }
5769
Pekka Paalanen826dc142014-08-27 12:11:53 +03005770 weston_log("%s disconnected, respawning...\n", shell->client);
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02005771 launch_desktop_shell_process(shell);
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02005772}
5773
Tiago Vignattib7dbbd62012-09-25 17:57:01 +03005774static void
Ander Conselvan de Oliveira312ea4c2013-12-20 21:07:01 +02005775desktop_shell_client_destroy(struct wl_listener *listener, void *data)
5776{
5777 struct desktop_shell *shell;
5778
5779 shell = container_of(listener, struct desktop_shell,
5780 child.client_destroy_listener);
5781
Pekka Paalanen826dc142014-08-27 12:11:53 +03005782 wl_list_remove(&shell->child.client_destroy_listener.link);
Ander Conselvan de Oliveira312ea4c2013-12-20 21:07:01 +02005783 shell->child.client = NULL;
Pekka Paalanen826dc142014-08-27 12:11:53 +03005784 /*
5785 * unbind_desktop_shell() will reset shell->child.desktop_shell
5786 * before the respawned process has a chance to create a new
5787 * desktop_shell object, because we are being called from the
5788 * wl_client destructor which destroys all wl_resources before
5789 * returning.
5790 */
5791
Pekka Paalanen2e62e4a2014-08-28 11:41:26 +03005792 if (!check_desktop_shell_crash_too_early(shell))
5793 respawn_desktop_shell_process(shell);
5794
Pekka Paalanen826dc142014-08-27 12:11:53 +03005795 shell_fade_startup(shell);
Ander Conselvan de Oliveira312ea4c2013-12-20 21:07:01 +02005796}
5797
5798static void
Tiago Vignattib7dbbd62012-09-25 17:57:01 +03005799launch_desktop_shell_process(void *data)
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02005800{
Tiago Vignattib7dbbd62012-09-25 17:57:01 +03005801 struct desktop_shell *shell = data;
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02005802
Pekka Paalanen826dc142014-08-27 12:11:53 +03005803 shell->child.client = weston_client_start(shell->compositor,
5804 shell->client);
Pekka Paalanen409ef0a2011-12-02 15:30:21 +02005805
Arnaud Vrac42631192014-08-25 20:56:46 +02005806 if (!shell->child.client) {
Emilio Pozuelo Monfort46ce7982013-11-20 13:22:29 +01005807 weston_log("not able to start %s\n", shell->client);
Arnaud Vrac42631192014-08-25 20:56:46 +02005808 return;
5809 }
Ander Conselvan de Oliveira312ea4c2013-12-20 21:07:01 +02005810
5811 shell->child.client_destroy_listener.notify =
5812 desktop_shell_client_destroy;
5813 wl_client_add_destroy_listener(shell->child.client,
5814 &shell->child.client_destroy_listener);
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02005815}
5816
5817static void
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08005818handle_shell_client_destroy(struct wl_listener *listener, void *data)
5819{
5820 struct shell_client *sc =
5821 container_of(listener, struct shell_client, destroy_listener);
5822
5823 if (sc->ping_timer)
5824 wl_event_source_remove(sc->ping_timer);
5825 free(sc);
5826}
5827
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08005828static struct shell_client *
5829shell_client_create(struct wl_client *client, struct desktop_shell *shell,
5830 const struct wl_interface *interface, uint32_t id)
Rafael Antognollie2a34552013-12-03 15:35:45 -02005831{
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08005832 struct shell_client *sc;
Rafael Antognollie2a34552013-12-03 15:35:45 -02005833
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08005834 sc = zalloc(sizeof *sc);
5835 if (sc == NULL) {
5836 wl_client_post_no_memory(client);
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08005837 return NULL;
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08005838 }
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08005839
5840 sc->resource = wl_resource_create(client, interface, 1, id);
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08005841 if (sc->resource == NULL) {
5842 free(sc);
5843 wl_client_post_no_memory(client);
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08005844 return NULL;
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08005845 }
5846
5847 sc->client = client;
5848 sc->shell = shell;
5849 sc->destroy_listener.notify = handle_shell_client_destroy;
5850 wl_client_add_destroy_listener(client, &sc->destroy_listener);
Jonas Ådahl49d77d22015-03-18 16:20:51 +08005851 wl_list_init(&sc->surface_list);
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08005852
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08005853 return sc;
5854}
5855
5856static void
5857bind_shell(struct wl_client *client, void *data, uint32_t version, uint32_t id)
5858{
5859 struct desktop_shell *shell = data;
5860 struct shell_client *sc;
5861
5862 sc = shell_client_create(client, shell, &wl_shell_interface, id);
5863 if (sc)
5864 wl_resource_set_implementation(sc->resource,
5865 &shell_implementation,
Jason Ekstrand9e9512f2014-04-16 21:12:10 -05005866 sc, NULL);
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08005867}
5868
5869static void
5870bind_xdg_shell(struct wl_client *client, void *data, uint32_t version, uint32_t id)
5871{
5872 struct desktop_shell *shell = data;
5873 struct shell_client *sc;
5874
5875 sc = shell_client_create(client, shell, &xdg_shell_interface, id);
5876 if (sc)
5877 wl_resource_set_dispatcher(sc->resource,
5878 xdg_shell_unversioned_dispatch,
5879 NULL, sc, NULL);
Rafael Antognollie2a34552013-12-03 15:35:45 -02005880}
5881
5882static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02005883unbind_desktop_shell(struct wl_resource *resource)
5884{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05005885 struct desktop_shell *shell = wl_resource_get_user_data(resource);
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05005886
5887 if (shell->locked)
5888 resume_desktop(shell);
5889
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02005890 shell->child.desktop_shell = NULL;
5891 shell->prepare_event_sent = false;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02005892}
5893
5894static void
Kristian Høgsberg75840622011-09-06 13:48:16 -04005895bind_desktop_shell(struct wl_client *client,
5896 void *data, uint32_t version, uint32_t id)
5897{
Tiago Vignattibe143262012-04-16 17:31:41 +03005898 struct desktop_shell *shell = data;
Pekka Paalanenbbe60522011-11-03 14:11:33 +02005899 struct wl_resource *resource;
Kristian Høgsberg75840622011-09-06 13:48:16 -04005900
Jason Ekstranda85118c2013-06-27 20:17:02 -05005901 resource = wl_resource_create(client, &desktop_shell_interface,
Jonny Lamb765760d2014-08-20 15:53:19 +02005902 MIN(version, 3), id);
Pekka Paalanenbbe60522011-11-03 14:11:33 +02005903
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02005904 if (client == shell->child.client) {
Jason Ekstranda85118c2013-06-27 20:17:02 -05005905 wl_resource_set_implementation(resource,
5906 &desktop_shell_implementation,
5907 shell, unbind_desktop_shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02005908 shell->child.desktop_shell = resource;
Pekka Paalanen79346ab2013-05-22 18:03:09 +03005909
5910 if (version < 2)
5911 shell_fade_startup(shell);
5912
Pekka Paalanenbbe60522011-11-03 14:11:33 +02005913 return;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02005914 }
Pekka Paalanenbbe60522011-11-03 14:11:33 +02005915
5916 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
5917 "permission to bind desktop_shell denied");
Kristian Høgsberg75840622011-09-06 13:48:16 -04005918}
5919
Pekka Paalanen8274d902014-08-06 19:36:51 +03005920static int
5921screensaver_get_label(struct weston_surface *surface, char *buf, size_t len)
5922{
5923 return snprintf(buf, len, "screensaver for output %s",
5924 surface->output->name);
5925}
5926
Pekka Paalanen6e168112011-11-24 11:34:05 +02005927static void
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06005928screensaver_configure(struct weston_surface *surface, int32_t sx, int32_t sy)
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04005929{
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01005930 struct desktop_shell *shell = surface->configure_private;
Jason Ekstranda7af7042013-10-12 22:38:11 -05005931 struct weston_view *view;
Giulio Camuffo412e6a52014-07-09 22:12:56 +03005932 struct weston_layer_entry *prev;
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04005933
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06005934 if (surface->width == 0)
Giulio Camuffo184df502013-02-21 11:29:21 +01005935 return;
5936
Pekka Paalanen3a1d07d2012-12-20 14:02:13 +02005937 /* XXX: starting weston-screensaver beforehand does not work */
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04005938 if (!shell->locked)
5939 return;
5940
Jason Ekstranda7af7042013-10-12 22:38:11 -05005941 view = container_of(surface->views.next, struct weston_view, surface_link);
5942 center_on_output(view, surface->output);
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04005943
Giulio Camuffo412e6a52014-07-09 22:12:56 +03005944 if (wl_list_empty(&view->layer_link.link)) {
5945 prev = container_of(shell->lock_layer.view_list.link.prev,
5946 struct weston_layer_entry, link);
5947 weston_layer_entry_insert(prev, &view->layer_link);
Jason Ekstranda7af7042013-10-12 22:38:11 -05005948 weston_view_update_transform(view);
Ander Conselvan de Oliveira859e8852013-02-21 18:35:21 +02005949 wl_event_source_timer_update(shell->screensaver.timer,
5950 shell->screensaver.duration);
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02005951 shell_fade(shell, FADE_IN);
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04005952 }
5953}
5954
5955static void
Pekka Paalanen6e168112011-11-24 11:34:05 +02005956screensaver_set_surface(struct wl_client *client,
5957 struct wl_resource *resource,
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04005958 struct wl_resource *surface_resource,
Pekka Paalanen6e168112011-11-24 11:34:05 +02005959 struct wl_resource *output_resource)
5960{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05005961 struct desktop_shell *shell = wl_resource_get_user_data(resource);
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05005962 struct weston_surface *surface =
5963 wl_resource_get_user_data(surface_resource);
Jason Ekstranda0d2dde2013-06-14 10:08:01 -05005964 struct weston_output *output = wl_resource_get_user_data(output_resource);
Jason Ekstranda7af7042013-10-12 22:38:11 -05005965 struct weston_view *view, *next;
5966
5967 /* Make sure we only have one view */
5968 wl_list_for_each_safe(view, next, &surface->views, surface_link)
5969 weston_view_destroy(view);
5970 weston_view_create(surface);
Pekka Paalanen6e168112011-11-24 11:34:05 +02005971
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04005972 surface->configure = screensaver_configure;
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01005973 surface->configure_private = shell;
Pekka Paalanen8274d902014-08-06 19:36:51 +03005974 weston_surface_set_label_func(surface, screensaver_get_label);
Pekka Paalanen77346a62011-11-30 16:26:35 +02005975 surface->output = output;
Pekka Paalanen6e168112011-11-24 11:34:05 +02005976}
5977
5978static const struct screensaver_interface screensaver_implementation = {
5979 screensaver_set_surface
5980};
5981
5982static void
5983unbind_screensaver(struct wl_resource *resource)
5984{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05005985 struct desktop_shell *shell = wl_resource_get_user_data(resource);
Pekka Paalanen6e168112011-11-24 11:34:05 +02005986
Pekka Paalanen77346a62011-11-30 16:26:35 +02005987 shell->screensaver.binding = NULL;
Pekka Paalanen6e168112011-11-24 11:34:05 +02005988}
5989
5990static void
5991bind_screensaver(struct wl_client *client,
5992 void *data, uint32_t version, uint32_t id)
5993{
Tiago Vignattibe143262012-04-16 17:31:41 +03005994 struct desktop_shell *shell = data;
Pekka Paalanen6e168112011-11-24 11:34:05 +02005995 struct wl_resource *resource;
5996
Jason Ekstranda85118c2013-06-27 20:17:02 -05005997 resource = wl_resource_create(client, &screensaver_interface, 1, id);
Pekka Paalanen6e168112011-11-24 11:34:05 +02005998
Pekka Paalanen77346a62011-11-30 16:26:35 +02005999 if (shell->screensaver.binding == NULL) {
Jason Ekstranda85118c2013-06-27 20:17:02 -05006000 wl_resource_set_implementation(resource,
6001 &screensaver_implementation,
6002 shell, unbind_screensaver);
Pekka Paalanen77346a62011-11-30 16:26:35 +02006003 shell->screensaver.binding = resource;
Pekka Paalanen6e168112011-11-24 11:34:05 +02006004 return;
6005 }
6006
6007 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
6008 "interface object already bound");
Pekka Paalanen6e168112011-11-24 11:34:05 +02006009}
6010
Kristian Høgsberg07045392012-02-19 18:52:44 -05006011struct switcher {
Tiago Vignattibe143262012-04-16 17:31:41 +03006012 struct desktop_shell *shell;
Kristian Høgsberg07045392012-02-19 18:52:44 -05006013 struct weston_surface *current;
6014 struct wl_listener listener;
Kristian Høgsberg29139d42013-04-18 15:25:39 -04006015 struct weston_keyboard_grab grab;
Manuel Bachmannc1ae2e82014-02-26 15:53:11 +01006016 struct wl_array minimized_array;
Kristian Høgsberg07045392012-02-19 18:52:44 -05006017};
6018
6019static void
6020switcher_next(struct switcher *switcher)
6021{
Jason Ekstranda7af7042013-10-12 22:38:11 -05006022 struct weston_view *view;
Kristian Høgsberg07045392012-02-19 18:52:44 -05006023 struct weston_surface *first = NULL, *prev = NULL, *next = NULL;
Kristian Høgsberg32e56862012-04-02 22:18:58 -04006024 struct shell_surface *shsurf;
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04006025 struct workspace *ws = get_current_workspace(switcher->shell);
Kristian Høgsberg07045392012-02-19 18:52:44 -05006026
Manuel Bachmannc1ae2e82014-02-26 15:53:11 +01006027 /* temporary re-display minimized surfaces */
6028 struct weston_view *tmp;
6029 struct weston_view **minimized;
Giulio Camuffo412e6a52014-07-09 22:12:56 +03006030 wl_list_for_each_safe(view, tmp, &switcher->shell->minimized_layer.view_list.link, layer_link.link) {
6031 weston_layer_entry_remove(&view->layer_link);
6032 weston_layer_entry_insert(&ws->layer.view_list, &view->layer_link);
Manuel Bachmannc1ae2e82014-02-26 15:53:11 +01006033 minimized = wl_array_add(&switcher->minimized_array, sizeof *minimized);
6034 *minimized = view;
6035 }
6036
Giulio Camuffo412e6a52014-07-09 22:12:56 +03006037 wl_list_for_each(view, &ws->layer.view_list.link, layer_link.link) {
Rafael Antognollied207b42013-12-03 15:35:43 -02006038 shsurf = get_shell_surface(view->surface);
Rafael Antognolli5031cbe2013-12-05 19:01:21 -02006039 if (shsurf &&
6040 shsurf->type == SHELL_SURFACE_TOPLEVEL &&
6041 shsurf->parent == NULL) {
Kristian Høgsberg07045392012-02-19 18:52:44 -05006042 if (first == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05006043 first = view->surface;
Kristian Høgsberg07045392012-02-19 18:52:44 -05006044 if (prev == switcher->current)
Jason Ekstranda7af7042013-10-12 22:38:11 -05006045 next = view->surface;
6046 prev = view->surface;
6047 view->alpha = 0.25;
6048 weston_view_geometry_dirty(view);
6049 weston_surface_damage(view->surface);
Kristian Høgsberg07045392012-02-19 18:52:44 -05006050 }
Alex Wu1659daa2012-04-01 20:13:09 +08006051
Jason Ekstranda7af7042013-10-12 22:38:11 -05006052 if (is_black_surface(view->surface, NULL)) {
6053 view->alpha = 0.25;
6054 weston_view_geometry_dirty(view);
6055 weston_surface_damage(view->surface);
Alex Wu1659daa2012-04-01 20:13:09 +08006056 }
Kristian Høgsberg07045392012-02-19 18:52:44 -05006057 }
6058
6059 if (next == NULL)
6060 next = first;
6061
Alex Wu07b26062012-03-12 16:06:01 +08006062 if (next == NULL)
6063 return;
6064
Kristian Høgsberg07045392012-02-19 18:52:44 -05006065 wl_list_remove(&switcher->listener.link);
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05006066 wl_signal_add(&next->destroy_signal, &switcher->listener);
Kristian Høgsberg07045392012-02-19 18:52:44 -05006067
6068 switcher->current = next;
Jason Ekstranda7af7042013-10-12 22:38:11 -05006069 wl_list_for_each(view, &next->views, surface_link)
6070 view->alpha = 1.0;
Alex Wu1659daa2012-04-01 20:13:09 +08006071
Kristian Høgsberg32e56862012-04-02 22:18:58 -04006072 shsurf = get_shell_surface(switcher->current);
Rafael Antognolli03b16592013-12-03 15:35:42 -02006073 if (shsurf && shsurf->state.fullscreen)
Jason Ekstranda7af7042013-10-12 22:38:11 -05006074 shsurf->fullscreen.black_view->alpha = 1.0;
Kristian Høgsberg07045392012-02-19 18:52:44 -05006075}
6076
6077static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04006078switcher_handle_surface_destroy(struct wl_listener *listener, void *data)
Kristian Høgsberg07045392012-02-19 18:52:44 -05006079{
6080 struct switcher *switcher =
6081 container_of(listener, struct switcher, listener);
6082
6083 switcher_next(switcher);
6084}
6085
6086static void
Daniel Stone351eb612012-05-31 15:27:47 -04006087switcher_destroy(struct switcher *switcher)
Kristian Høgsberg07045392012-02-19 18:52:44 -05006088{
Jason Ekstranda7af7042013-10-12 22:38:11 -05006089 struct weston_view *view;
Kristian Høgsberg29139d42013-04-18 15:25:39 -04006090 struct weston_keyboard *keyboard = switcher->grab.keyboard;
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04006091 struct workspace *ws = get_current_workspace(switcher->shell);
Kristian Høgsberg07045392012-02-19 18:52:44 -05006092
Giulio Camuffo412e6a52014-07-09 22:12:56 +03006093 wl_list_for_each(view, &ws->layer.view_list.link, layer_link.link) {
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01006094 if (is_focus_view(view))
6095 continue;
6096
Jason Ekstranda7af7042013-10-12 22:38:11 -05006097 view->alpha = 1.0;
6098 weston_surface_damage(view->surface);
Kristian Høgsberg07045392012-02-19 18:52:44 -05006099 }
6100
Alex Wu07b26062012-03-12 16:06:01 +08006101 if (switcher->current)
Daniel Stone37816df2012-05-16 18:45:18 +01006102 activate(switcher->shell, switcher->current,
Derek Foreman8aeeac82015-01-30 13:24:36 -06006103 keyboard->seat, true);
Kristian Høgsberg07045392012-02-19 18:52:44 -05006104 wl_list_remove(&switcher->listener.link);
Kristian Høgsberg29139d42013-04-18 15:25:39 -04006105 weston_keyboard_end_grab(keyboard);
6106 if (keyboard->input_method_resource)
6107 keyboard->grab = &keyboard->input_method_grab;
Manuel Bachmannc1ae2e82014-02-26 15:53:11 +01006108
6109 /* re-hide surfaces that were temporary shown during the switch */
6110 struct weston_view **minimized;
6111 wl_array_for_each(minimized, &switcher->minimized_array) {
6112 /* with the exception of the current selected */
6113 if ((*minimized)->surface != switcher->current) {
Giulio Camuffo412e6a52014-07-09 22:12:56 +03006114 weston_layer_entry_remove(&(*minimized)->layer_link);
6115 weston_layer_entry_insert(&switcher->shell->minimized_layer.view_list, &(*minimized)->layer_link);
Manuel Bachmannc1ae2e82014-02-26 15:53:11 +01006116 weston_view_damage_below(*minimized);
6117 }
6118 }
6119 wl_array_release(&switcher->minimized_array);
6120
Kristian Høgsberg07045392012-02-19 18:52:44 -05006121 free(switcher);
6122}
6123
6124static void
Kristian Høgsberg29139d42013-04-18 15:25:39 -04006125switcher_key(struct weston_keyboard_grab *grab,
Daniel Stonec9785ea2012-05-30 16:31:52 +01006126 uint32_t time, uint32_t key, uint32_t state_w)
Kristian Høgsberg07045392012-02-19 18:52:44 -05006127{
6128 struct switcher *switcher = container_of(grab, struct switcher, grab);
Daniel Stonec9785ea2012-05-30 16:31:52 +01006129 enum wl_keyboard_key_state state = state_w;
Daniel Stone351eb612012-05-31 15:27:47 -04006130
Daniel Stonec9785ea2012-05-30 16:31:52 +01006131 if (key == KEY_TAB && state == WL_KEYBOARD_KEY_STATE_PRESSED)
Daniel Stone351eb612012-05-31 15:27:47 -04006132 switcher_next(switcher);
6133}
6134
6135static void
Kristian Høgsberg29139d42013-04-18 15:25:39 -04006136switcher_modifier(struct weston_keyboard_grab *grab, uint32_t serial,
Daniel Stone351eb612012-05-31 15:27:47 -04006137 uint32_t mods_depressed, uint32_t mods_latched,
6138 uint32_t mods_locked, uint32_t group)
6139{
6140 struct switcher *switcher = container_of(grab, struct switcher, grab);
Derek Foreman8aeeac82015-01-30 13:24:36 -06006141 struct weston_seat *seat = grab->keyboard->seat;
Kristian Høgsberg07045392012-02-19 18:52:44 -05006142
Daniel Stone351eb612012-05-31 15:27:47 -04006143 if ((seat->modifier_state & switcher->shell->binding_modifier) == 0)
6144 switcher_destroy(switcher);
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04006145}
Kristian Høgsberg07045392012-02-19 18:52:44 -05006146
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02006147static void
6148switcher_cancel(struct weston_keyboard_grab *grab)
6149{
6150 struct switcher *switcher = container_of(grab, struct switcher, grab);
6151
6152 switcher_destroy(switcher);
6153}
6154
Kristian Høgsberg29139d42013-04-18 15:25:39 -04006155static const struct weston_keyboard_grab_interface switcher_grab = {
Daniel Stone351eb612012-05-31 15:27:47 -04006156 switcher_key,
6157 switcher_modifier,
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02006158 switcher_cancel,
Kristian Høgsberg07045392012-02-19 18:52:44 -05006159};
6160
6161static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04006162switcher_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
Daniel Stone325fc2d2012-05-30 16:31:58 +01006163 void *data)
Kristian Høgsberg07045392012-02-19 18:52:44 -05006164{
Tiago Vignattibe143262012-04-16 17:31:41 +03006165 struct desktop_shell *shell = data;
Kristian Høgsberg07045392012-02-19 18:52:44 -05006166 struct switcher *switcher;
6167
6168 switcher = malloc(sizeof *switcher);
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04006169 switcher->shell = shell;
Kristian Høgsberg07045392012-02-19 18:52:44 -05006170 switcher->current = NULL;
Kristian Høgsberg27e30522012-04-11 23:18:23 -04006171 switcher->listener.notify = switcher_handle_surface_destroy;
Kristian Høgsberg07045392012-02-19 18:52:44 -05006172 wl_list_init(&switcher->listener.link);
Manuel Bachmannc1ae2e82014-02-26 15:53:11 +01006173 wl_array_init(&switcher->minimized_array);
Kristian Høgsberg07045392012-02-19 18:52:44 -05006174
Alexander Larssonf82b6ca2013-05-28 16:23:39 +02006175 restore_all_output_modes(shell->compositor);
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04006176 lower_fullscreen_layer(switcher->shell);
Kristian Høgsberg07045392012-02-19 18:52:44 -05006177 switcher->grab.interface = &switcher_grab;
Kristian Høgsberg29139d42013-04-18 15:25:39 -04006178 weston_keyboard_start_grab(seat->keyboard, &switcher->grab);
6179 weston_keyboard_set_focus(seat->keyboard, NULL);
Kristian Høgsberg07045392012-02-19 18:52:44 -05006180 switcher_next(switcher);
6181}
6182
Pekka Paalanen3c647232011-12-22 13:43:43 +02006183static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04006184backlight_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
Daniel Stone325fc2d2012-05-30 16:31:58 +01006185 void *data)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02006186{
6187 struct weston_compositor *compositor = data;
6188 struct weston_output *output;
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03006189 long backlight_new = 0;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02006190
6191 /* TODO: we're limiting to simple use cases, where we assume just
6192 * control on the primary display. We'd have to extend later if we
6193 * ever get support for setting backlights on random desktop LCD
6194 * panels though */
6195 output = get_default_output(compositor);
6196 if (!output)
6197 return;
6198
6199 if (!output->set_backlight)
6200 return;
6201
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03006202 if (key == KEY_F9 || key == KEY_BRIGHTNESSDOWN)
6203 backlight_new = output->backlight_current - 25;
6204 else if (key == KEY_F10 || key == KEY_BRIGHTNESSUP)
6205 backlight_new = output->backlight_current + 25;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02006206
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03006207 if (backlight_new < 5)
6208 backlight_new = 5;
6209 if (backlight_new > 255)
6210 backlight_new = 255;
6211
6212 output->backlight_current = backlight_new;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02006213 output->set_backlight(output, output->backlight_current);
6214}
6215
Kristian Høgsbergb41c0812012-03-04 14:53:40 -05006216static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04006217force_kill_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
Daniel Stone325fc2d2012-05-30 16:31:58 +01006218 void *data)
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04006219{
Kristian Høgsbergfe7aa902013-05-08 09:54:37 -04006220 struct weston_surface *focus_surface;
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04006221 struct wl_client *client;
Tiago Vignatti1d01b012012-09-27 17:48:36 +03006222 struct desktop_shell *shell = data;
6223 struct weston_compositor *compositor = shell->compositor;
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04006224 pid_t pid;
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04006225
Philipp Brüschweiler6cef0092012-08-13 21:27:27 +02006226 focus_surface = seat->keyboard->focus;
6227 if (!focus_surface)
6228 return;
6229
Tiago Vignatti1d01b012012-09-27 17:48:36 +03006230 wl_signal_emit(&compositor->kill_signal, focus_surface);
6231
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05006232 client = wl_resource_get_client(focus_surface->resource);
Tiago Vignatti920f1972012-09-27 17:48:35 +03006233 wl_client_get_credentials(client, &pid, NULL, NULL);
6234
6235 /* Skip clients that we launched ourselves (the credentials of
6236 * the socketpair is ours) */
6237 if (pid == getpid())
6238 return;
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04006239
Daniel Stone325fc2d2012-05-30 16:31:58 +01006240 kill(pid, SIGKILL);
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04006241}
6242
6243static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04006244workspace_up_binding(struct weston_seat *seat, uint32_t time,
Jonas Ådahle3cddce2012-06-13 00:01:22 +02006245 uint32_t key, void *data)
6246{
6247 struct desktop_shell *shell = data;
6248 unsigned int new_index = shell->workspaces.current;
6249
Kristian Høgsbergce345b02012-06-25 21:35:29 -04006250 if (shell->locked)
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04006251 return;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02006252 if (new_index != 0)
6253 new_index--;
6254
6255 change_workspace(shell, new_index);
6256}
6257
6258static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04006259workspace_down_binding(struct weston_seat *seat, uint32_t time,
Jonas Ådahle3cddce2012-06-13 00:01:22 +02006260 uint32_t key, void *data)
6261{
6262 struct desktop_shell *shell = data;
6263 unsigned int new_index = shell->workspaces.current;
6264
Kristian Høgsbergce345b02012-06-25 21:35:29 -04006265 if (shell->locked)
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04006266 return;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02006267 if (new_index < shell->workspaces.num - 1)
6268 new_index++;
6269
6270 change_workspace(shell, new_index);
6271}
6272
6273static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04006274workspace_f_binding(struct weston_seat *seat, uint32_t time,
Jonas Ådahle3cddce2012-06-13 00:01:22 +02006275 uint32_t key, void *data)
6276{
6277 struct desktop_shell *shell = data;
6278 unsigned int new_index;
6279
Kristian Høgsbergce345b02012-06-25 21:35:29 -04006280 if (shell->locked)
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04006281 return;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02006282 new_index = key - KEY_F1;
6283 if (new_index >= shell->workspaces.num)
6284 new_index = shell->workspaces.num - 1;
6285
6286 change_workspace(shell, new_index);
6287}
6288
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02006289static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04006290workspace_move_surface_up_binding(struct weston_seat *seat, uint32_t time,
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02006291 uint32_t key, void *data)
6292{
6293 struct desktop_shell *shell = data;
6294 unsigned int new_index = shell->workspaces.current;
6295
6296 if (shell->locked)
6297 return;
6298
6299 if (new_index != 0)
6300 new_index--;
6301
6302 take_surface_to_workspace_by_seat(shell, seat, new_index);
6303}
6304
6305static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04006306workspace_move_surface_down_binding(struct weston_seat *seat, uint32_t time,
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02006307 uint32_t key, void *data)
6308{
6309 struct desktop_shell *shell = data;
6310 unsigned int new_index = shell->workspaces.current;
6311
6312 if (shell->locked)
6313 return;
6314
6315 if (new_index < shell->workspaces.num - 1)
6316 new_index++;
6317
6318 take_surface_to_workspace_by_seat(shell, seat, new_index);
6319}
Jonas Ådahle3cddce2012-06-13 00:01:22 +02006320
6321static void
Ander Conselvan de Oliveirac94d6222014-01-29 18:47:54 +02006322shell_reposition_view_on_output_destroy(struct weston_view *view)
6323{
6324 struct weston_output *output, *first_output;
6325 struct weston_compositor *ec = view->surface->compositor;
6326 struct shell_surface *shsurf;
6327 float x, y;
6328 int visible;
6329
6330 x = view->geometry.x;
6331 y = view->geometry.y;
6332
6333 /* At this point the destroyed output is not in the list anymore.
6334 * If the view is still visible somewhere, we leave where it is,
6335 * otherwise, move it to the first output. */
6336 visible = 0;
6337 wl_list_for_each(output, &ec->output_list, link) {
6338 if (pixman_region32_contains_point(&output->region,
6339 x, y, NULL)) {
6340 visible = 1;
6341 break;
6342 }
6343 }
6344
6345 if (!visible) {
6346 first_output = container_of(ec->output_list.next,
6347 struct weston_output, link);
6348
6349 x = first_output->x + first_output->width / 4;
6350 y = first_output->y + first_output->height / 4;
Xiong Zhang62899f52014-03-07 16:27:19 +08006351
6352 weston_view_set_position(view, x, y);
6353 } else {
6354 weston_view_geometry_dirty(view);
Ander Conselvan de Oliveirac94d6222014-01-29 18:47:54 +02006355 }
6356
Ander Conselvan de Oliveirac94d6222014-01-29 18:47:54 +02006357
6358 shsurf = get_shell_surface(view->surface);
6359
6360 if (shsurf) {
6361 shsurf->saved_position_valid = false;
6362 shsurf->next_state.maximized = false;
6363 shsurf->next_state.fullscreen = false;
6364 shsurf->state_changed = true;
6365 }
6366}
6367
Ander Conselvan de Oliveira304996d2014-04-11 13:57:15 +03006368void
6369shell_for_each_layer(struct desktop_shell *shell,
6370 shell_for_each_layer_func_t func, void *data)
Ander Conselvan de Oliveirac94d6222014-01-29 18:47:54 +02006371{
Ander Conselvan de Oliveira304996d2014-04-11 13:57:15 +03006372 struct workspace **ws;
6373
6374 func(shell, &shell->fullscreen_layer, data);
6375 func(shell, &shell->panel_layer, data);
6376 func(shell, &shell->background_layer, data);
6377 func(shell, &shell->lock_layer, data);
6378 func(shell, &shell->input_panel_layer, data);
6379
6380 wl_array_for_each(ws, &shell->workspaces.array)
6381 func(shell, &(*ws)->layer, data);
6382}
6383
6384static void
6385shell_output_destroy_move_layer(struct desktop_shell *shell,
6386 struct weston_layer *layer,
6387 void *data)
6388{
6389 struct weston_output *output = data;
Ander Conselvan de Oliveirac94d6222014-01-29 18:47:54 +02006390 struct weston_view *view;
6391
Giulio Camuffo412e6a52014-07-09 22:12:56 +03006392 wl_list_for_each(view, &layer->view_list.link, layer_link.link) {
Ander Conselvan de Oliveira304996d2014-04-11 13:57:15 +03006393 if (view->output != output)
6394 continue;
Ander Conselvan de Oliveirac94d6222014-01-29 18:47:54 +02006395
Ander Conselvan de Oliveira304996d2014-04-11 13:57:15 +03006396 shell_reposition_view_on_output_destroy(view);
Ander Conselvan de Oliveirac94d6222014-01-29 18:47:54 +02006397 }
6398}
6399
6400static void
Xiong Zhang6b481422013-10-23 13:58:32 +08006401handle_output_destroy(struct wl_listener *listener, void *data)
6402{
6403 struct shell_output *output_listener =
6404 container_of(listener, struct shell_output, destroy_listener);
Ander Conselvan de Oliveira304996d2014-04-11 13:57:15 +03006405 struct weston_output *output = output_listener->output;
6406 struct desktop_shell *shell = output_listener->shell;
Xiong Zhang6b481422013-10-23 13:58:32 +08006407
Ander Conselvan de Oliveira304996d2014-04-11 13:57:15 +03006408 shell_for_each_layer(shell, shell_output_destroy_move_layer, output);
Ander Conselvan de Oliveirac94d6222014-01-29 18:47:54 +02006409
Xiong Zhang6b481422013-10-23 13:58:32 +08006410 wl_list_remove(&output_listener->destroy_listener.link);
6411 wl_list_remove(&output_listener->link);
6412 free(output_listener);
6413}
6414
6415static void
6416create_shell_output(struct desktop_shell *shell,
6417 struct weston_output *output)
6418{
6419 struct shell_output *shell_output;
6420
6421 shell_output = zalloc(sizeof *shell_output);
6422 if (shell_output == NULL)
6423 return;
6424
6425 shell_output->output = output;
6426 shell_output->shell = shell;
6427 shell_output->destroy_listener.notify = handle_output_destroy;
6428 wl_signal_add(&output->destroy_signal,
6429 &shell_output->destroy_listener);
Kristian Høgsberga3a0e182013-10-23 23:36:04 -07006430 wl_list_insert(shell->output_list.prev, &shell_output->link);
Xiong Zhang6b481422013-10-23 13:58:32 +08006431}
6432
6433static void
6434handle_output_create(struct wl_listener *listener, void *data)
6435{
6436 struct desktop_shell *shell =
6437 container_of(listener, struct desktop_shell, output_create_listener);
6438 struct weston_output *output = (struct weston_output *)data;
6439
6440 create_shell_output(shell, output);
6441}
6442
6443static void
Ander Conselvan de Oliveira304996d2014-04-11 13:57:15 +03006444handle_output_move_layer(struct desktop_shell *shell,
6445 struct weston_layer *layer, void *data)
Ander Conselvan de Oliveiraa8a9baf2014-01-29 18:47:52 +02006446{
Ander Conselvan de Oliveira304996d2014-04-11 13:57:15 +03006447 struct weston_output *output = data;
Ander Conselvan de Oliveiraa8a9baf2014-01-29 18:47:52 +02006448 struct weston_view *view;
6449 float x, y;
6450
Giulio Camuffo412e6a52014-07-09 22:12:56 +03006451 wl_list_for_each(view, &layer->view_list.link, layer_link.link) {
Ander Conselvan de Oliveira304996d2014-04-11 13:57:15 +03006452 if (view->output != output)
6453 continue;
6454
6455 x = view->geometry.x + output->move_x;
6456 y = view->geometry.y + output->move_y;
6457 weston_view_set_position(view, x, y);
6458 }
6459}
6460
6461static void
6462handle_output_move(struct wl_listener *listener, void *data)
6463{
6464 struct desktop_shell *shell;
6465
Ander Conselvan de Oliveiraa8a9baf2014-01-29 18:47:52 +02006466 shell = container_of(listener, struct desktop_shell,
6467 output_move_listener);
Ander Conselvan de Oliveiraa8a9baf2014-01-29 18:47:52 +02006468
Ander Conselvan de Oliveira304996d2014-04-11 13:57:15 +03006469 shell_for_each_layer(shell, handle_output_move_layer, data);
Ander Conselvan de Oliveiraa8a9baf2014-01-29 18:47:52 +02006470}
6471
6472static void
Xiong Zhang6b481422013-10-23 13:58:32 +08006473setup_output_destroy_handler(struct weston_compositor *ec,
6474 struct desktop_shell *shell)
6475{
6476 struct weston_output *output;
6477
6478 wl_list_init(&shell->output_list);
6479 wl_list_for_each(output, &ec->output_list, link)
6480 create_shell_output(shell, output);
6481
6482 shell->output_create_listener.notify = handle_output_create;
6483 wl_signal_add(&ec->output_created_signal,
6484 &shell->output_create_listener);
Ander Conselvan de Oliveiraa8a9baf2014-01-29 18:47:52 +02006485
6486 shell->output_move_listener.notify = handle_output_move;
6487 wl_signal_add(&ec->output_moved_signal, &shell->output_move_listener);
Xiong Zhang6b481422013-10-23 13:58:32 +08006488}
6489
6490static void
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04006491shell_destroy(struct wl_listener *listener, void *data)
Pekka Paalanen3c647232011-12-22 13:43:43 +02006492{
Tiago Vignattibe143262012-04-16 17:31:41 +03006493 struct desktop_shell *shell =
6494 container_of(listener, struct desktop_shell, destroy_listener);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02006495 struct workspace **ws;
Xiong Zhang6b481422013-10-23 13:58:32 +08006496 struct shell_output *shell_output, *tmp;
Pekka Paalanen3c647232011-12-22 13:43:43 +02006497
Kristian Høgsberg17bccae2014-01-16 16:46:28 -08006498 /* Force state to unlocked so we don't try to fade */
6499 shell->locked = false;
Pekka Paalanen826dc142014-08-27 12:11:53 +03006500
6501 if (shell->child.client) {
6502 /* disable respawn */
6503 wl_list_remove(&shell->child.client_destroy_listener.link);
Pekka Paalanen9cf5cc82012-01-02 16:00:24 +02006504 wl_client_destroy(shell->child.client);
Pekka Paalanen826dc142014-08-27 12:11:53 +03006505 }
Pekka Paalanen9cf5cc82012-01-02 16:00:24 +02006506
Ryo Munakata76fb7ec2015-03-08 19:17:06 +09006507 wl_event_source_remove(shell->screensaver.timer);
6508
Ander Conselvan de Oliveiraa4575632013-02-21 18:35:23 +02006509 wl_list_remove(&shell->idle_listener.link);
6510 wl_list_remove(&shell->wake_listener.link);
Kristian Høgsberg677a5f52013-12-04 11:00:19 -08006511
6512 input_panel_destroy(shell);
Kristian Høgsberg88c16072012-05-16 08:04:19 -04006513
Xiong Zhang6b481422013-10-23 13:58:32 +08006514 wl_list_for_each_safe(shell_output, tmp, &shell->output_list, link) {
6515 wl_list_remove(&shell_output->destroy_listener.link);
6516 wl_list_remove(&shell_output->link);
6517 free(shell_output);
6518 }
6519
6520 wl_list_remove(&shell->output_create_listener.link);
Kristian Høgsberg6d50b0f2014-04-30 20:46:25 -07006521 wl_list_remove(&shell->output_move_listener.link);
Xiong Zhang6b481422013-10-23 13:58:32 +08006522
Jonas Ådahle3cddce2012-06-13 00:01:22 +02006523 wl_array_for_each(ws, &shell->workspaces.array)
6524 workspace_destroy(*ws);
6525 wl_array_release(&shell->workspaces.array);
6526
Pekka Paalanen3c647232011-12-22 13:43:43 +02006527 free(shell->screensaver.path);
Emilio Pozuelo Monfort46ce7982013-11-20 13:22:29 +01006528 free(shell->client);
Pekka Paalanen3c647232011-12-22 13:43:43 +02006529 free(shell);
6530}
6531
Tiago Vignatti0b52d482012-04-20 18:54:25 +03006532static void
6533shell_add_bindings(struct weston_compositor *ec, struct desktop_shell *shell)
6534{
6535 uint32_t mod;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02006536 int i, num_workspace_bindings;
Tiago Vignatti0b52d482012-04-20 18:54:25 +03006537
6538 /* fixed bindings */
Daniel Stone325fc2d2012-05-30 16:31:58 +01006539 weston_compositor_add_key_binding(ec, KEY_BACKSPACE,
6540 MODIFIER_CTRL | MODIFIER_ALT,
6541 terminate_binding, ec);
6542 weston_compositor_add_button_binding(ec, BTN_LEFT, 0,
6543 click_to_activate_binding,
6544 shell);
Kristian Høgsbergf0ce5812014-04-07 11:52:17 -07006545 weston_compositor_add_button_binding(ec, BTN_RIGHT, 0,
6546 click_to_activate_binding,
6547 shell);
Neil Robertsa28c6932013-10-03 16:43:04 +01006548 weston_compositor_add_touch_binding(ec, 0,
6549 touch_to_activate_binding,
6550 shell);
Daniel Stone325fc2d2012-05-30 16:31:58 +01006551 weston_compositor_add_axis_binding(ec, WL_POINTER_AXIS_VERTICAL_SCROLL,
6552 MODIFIER_SUPER | MODIFIER_ALT,
6553 surface_opacity_binding, NULL);
6554 weston_compositor_add_axis_binding(ec, WL_POINTER_AXIS_VERTICAL_SCROLL,
6555 MODIFIER_SUPER, zoom_axis_binding,
6556 NULL);
Tiago Vignatti0b52d482012-04-20 18:54:25 +03006557
6558 /* configurable bindings */
6559 mod = shell->binding_modifier;
Daniel Stone325fc2d2012-05-30 16:31:58 +01006560 weston_compositor_add_key_binding(ec, KEY_PAGEUP, mod,
6561 zoom_key_binding, NULL);
6562 weston_compositor_add_key_binding(ec, KEY_PAGEDOWN, mod,
6563 zoom_key_binding, NULL);
Kristian Høgsberg211b5172014-01-11 13:10:21 -08006564 weston_compositor_add_key_binding(ec, KEY_M, mod | MODIFIER_SHIFT,
6565 maximize_binding, NULL);
6566 weston_compositor_add_key_binding(ec, KEY_F, mod | MODIFIER_SHIFT,
6567 fullscreen_binding, NULL);
Daniel Stone325fc2d2012-05-30 16:31:58 +01006568 weston_compositor_add_button_binding(ec, BTN_LEFT, mod, move_binding,
6569 shell);
Neil Robertsaba0f252013-10-03 16:43:05 +01006570 weston_compositor_add_touch_binding(ec, mod, touch_move_binding, shell);
Daniel Stone325fc2d2012-05-30 16:31:58 +01006571 weston_compositor_add_button_binding(ec, BTN_MIDDLE, mod,
6572 resize_binding, shell);
Kristian Høgsberg0837fa92014-01-20 10:35:26 -08006573 weston_compositor_add_button_binding(ec, BTN_LEFT,
6574 mod | MODIFIER_SHIFT,
6575 resize_binding, shell);
Pekka Paalanen7bb65102013-05-22 18:03:04 +03006576
6577 if (ec->capabilities & WESTON_CAP_ROTATION_ANY)
6578 weston_compositor_add_button_binding(ec, BTN_RIGHT, mod,
6579 rotate_binding, NULL);
6580
Daniel Stone325fc2d2012-05-30 16:31:58 +01006581 weston_compositor_add_key_binding(ec, KEY_TAB, mod, switcher_binding,
6582 shell);
6583 weston_compositor_add_key_binding(ec, KEY_F9, mod, backlight_binding,
6584 ec);
6585 weston_compositor_add_key_binding(ec, KEY_BRIGHTNESSDOWN, 0,
6586 backlight_binding, ec);
6587 weston_compositor_add_key_binding(ec, KEY_F10, mod, backlight_binding,
6588 ec);
6589 weston_compositor_add_key_binding(ec, KEY_BRIGHTNESSUP, 0,
6590 backlight_binding, ec);
Daniel Stone325fc2d2012-05-30 16:31:58 +01006591 weston_compositor_add_key_binding(ec, KEY_K, mod,
6592 force_kill_binding, shell);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02006593 weston_compositor_add_key_binding(ec, KEY_UP, mod,
6594 workspace_up_binding, shell);
6595 weston_compositor_add_key_binding(ec, KEY_DOWN, mod,
6596 workspace_down_binding, shell);
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02006597 weston_compositor_add_key_binding(ec, KEY_UP, mod | MODIFIER_SHIFT,
6598 workspace_move_surface_up_binding,
6599 shell);
6600 weston_compositor_add_key_binding(ec, KEY_DOWN, mod | MODIFIER_SHIFT,
6601 workspace_move_surface_down_binding,
6602 shell);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02006603
Kristian Høgsbergd56ab4e2014-01-16 16:51:52 -08006604 if (shell->exposay_modifier)
6605 weston_compositor_add_modifier_binding(ec, shell->exposay_modifier,
6606 exposay_binding, shell);
Daniel Stonedf8133b2013-11-19 11:37:14 +01006607
Jonas Ådahle3cddce2012-06-13 00:01:22 +02006608 /* Add bindings for mod+F[1-6] for workspace 1 to 6. */
6609 if (shell->workspaces.num > 1) {
6610 num_workspace_bindings = shell->workspaces.num;
6611 if (num_workspace_bindings > 6)
6612 num_workspace_bindings = 6;
6613 for (i = 0; i < num_workspace_bindings; i++)
6614 weston_compositor_add_key_binding(ec, KEY_F1 + i, mod,
6615 workspace_f_binding,
6616 shell);
6617 }
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02006618
Pekka Paalanen2829f7c2015-02-19 17:02:13 +02006619 weston_install_debug_key_binding(ec, mod);
Tiago Vignatti0b52d482012-04-20 18:54:25 +03006620}
6621
Jason Ekstrand024177c2014-04-21 19:42:58 -05006622static void
6623handle_seat_created(struct wl_listener *listener, void *data)
6624{
6625 struct weston_seat *seat = data;
6626
6627 create_shell_seat(seat);
6628}
6629
Kristian Høgsberg1c562182011-05-02 22:09:20 -04006630WL_EXPORT int
Kristian Høgsbergcb4685b2013-02-20 15:37:49 -05006631module_init(struct weston_compositor *ec,
Ossama Othmana50e6e42013-05-14 09:48:26 -07006632 int *argc, char *argv[])
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05006633{
Kristian Høgsbergf4d2f232012-08-10 10:05:39 -04006634 struct weston_seat *seat;
Tiago Vignattibe143262012-04-16 17:31:41 +03006635 struct desktop_shell *shell;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02006636 struct workspace **pws;
6637 unsigned int i;
Tiago Vignattib7dbbd62012-09-25 17:57:01 +03006638 struct wl_event_loop *loop;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04006639
Peter Huttererf3d62272013-08-08 11:57:05 +10006640 shell = zalloc(sizeof *shell);
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04006641 if (shell == NULL)
6642 return -1;
6643
Kristian Høgsberg75840622011-09-06 13:48:16 -04006644 shell->compositor = ec;
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04006645
6646 shell->destroy_listener.notify = shell_destroy;
6647 wl_signal_add(&ec->destroy_signal, &shell->destroy_listener);
Ander Conselvan de Oliveiraa4575632013-02-21 18:35:23 +02006648 shell->idle_listener.notify = idle_handler;
6649 wl_signal_add(&ec->idle_signal, &shell->idle_listener);
6650 shell->wake_listener.notify = wake_handler;
6651 wl_signal_add(&ec->wake_signal, &shell->wake_listener);
Kristian Høgsberg677a5f52013-12-04 11:00:19 -08006652
Kristian Høgsberg82a1d112012-07-19 14:02:00 -04006653 ec->shell_interface.shell = shell;
Tiago Vignattibc052c92012-04-19 16:18:18 +03006654 ec->shell_interface.create_shell_surface = create_shell_surface;
Jason Ekstranda7af7042013-10-12 22:38:11 -05006655 ec->shell_interface.get_primary_view = get_primary_view;
Tiago Vignattibc052c92012-04-19 16:18:18 +03006656 ec->shell_interface.set_toplevel = set_toplevel;
Tiago Vignatti491bac12012-05-18 16:37:43 -04006657 ec->shell_interface.set_transient = set_transient;
Kristian Høgsberg47792412014-05-04 13:47:06 -07006658 ec->shell_interface.set_fullscreen = shell_interface_set_fullscreen;
Tiago Vignattifb2adba2013-06-12 15:43:21 -03006659 ec->shell_interface.set_xwayland = set_xwayland;
Kristian Høgsbergae356ae2014-04-29 16:03:54 -07006660 ec->shell_interface.move = shell_interface_move;
Kristian Høgsbergc1693f22012-05-22 16:56:23 -04006661 ec->shell_interface.resize = surface_resize;
Giulio Camuffo62942ad2013-09-11 18:20:47 +02006662 ec->shell_interface.set_title = set_title;
Jasper St. Pierreccf48fb2014-05-02 10:21:38 -04006663 ec->shell_interface.set_window_geometry = set_window_geometry;
Giulio Camuffo6b4b2412015-01-29 19:06:49 +02006664 ec->shell_interface.set_maximized = shell_interface_set_maximized;
Giulio Camuffoa8e9b412015-01-27 19:10:37 +02006665 ec->shell_interface.set_pid = set_pid;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05006666
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05006667 weston_layer_init(&shell->fullscreen_layer, &ec->cursor_layer.link);
6668 weston_layer_init(&shell->panel_layer, &shell->fullscreen_layer.link);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02006669 weston_layer_init(&shell->background_layer, &shell->panel_layer.link);
6670 weston_layer_init(&shell->lock_layer, NULL);
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02006671 weston_layer_init(&shell->input_panel_layer, NULL);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02006672
6673 wl_array_init(&shell->workspaces.array);
Jonas Ådahle9d22502012-08-29 22:13:01 +02006674 wl_list_init(&shell->workspaces.client_list);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05006675
Kristian Høgsberg677a5f52013-12-04 11:00:19 -08006676 if (input_panel_setup(shell) < 0)
6677 return -1;
6678
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04006679 shell_configuration(shell);
Pekka Paalanene955f1e2011-12-07 11:49:52 +02006680
Daniel Stonedf8133b2013-11-19 11:37:14 +01006681 shell->exposay.state_cur = EXPOSAY_LAYOUT_INACTIVE;
6682 shell->exposay.state_target = EXPOSAY_TARGET_CANCEL;
6683
Jonas Ådahle3cddce2012-06-13 00:01:22 +02006684 for (i = 0; i < shell->workspaces.num; i++) {
6685 pws = wl_array_add(&shell->workspaces.array, sizeof *pws);
6686 if (pws == NULL)
6687 return -1;
6688
6689 *pws = workspace_create();
6690 if (*pws == NULL)
6691 return -1;
6692 }
6693 activate_workspace(shell, 0);
6694
Manuel Bachmann50c87db2014-02-26 15:52:13 +01006695 weston_layer_init(&shell->minimized_layer, NULL);
6696
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02006697 wl_list_init(&shell->workspaces.anim_sticky_list);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02006698 wl_list_init(&shell->workspaces.animation.link);
6699 shell->workspaces.animation.frame = animate_workspace_change_frame;
6700
Kristian Høgsberg919cddb2013-07-08 19:03:57 -04006701 if (wl_global_create(ec->wl_display, &wl_shell_interface, 1,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04006702 shell, bind_shell) == NULL)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05006703 return -1;
6704
Rafael Antognollie2a34552013-12-03 15:35:45 -02006705 if (wl_global_create(ec->wl_display, &xdg_shell_interface, 1,
6706 shell, bind_xdg_shell) == NULL)
6707 return -1;
6708
Kristian Høgsberg919cddb2013-07-08 19:03:57 -04006709 if (wl_global_create(ec->wl_display,
Jonny Lamb765760d2014-08-20 15:53:19 +02006710 &desktop_shell_interface, 3,
Kristian Høgsberg919cddb2013-07-08 19:03:57 -04006711 shell, bind_desktop_shell) == NULL)
Kristian Høgsberg75840622011-09-06 13:48:16 -04006712 return -1;
6713
Kristian Høgsberg919cddb2013-07-08 19:03:57 -04006714 if (wl_global_create(ec->wl_display, &screensaver_interface, 1,
6715 shell, bind_screensaver) == NULL)
Pekka Paalanen6e168112011-11-24 11:34:05 +02006716 return -1;
6717
Kristian Høgsberg919cddb2013-07-08 19:03:57 -04006718 if (wl_global_create(ec->wl_display, &workspace_manager_interface, 1,
6719 shell, bind_workspace_manager) == NULL)
Jonas Ådahle9d22502012-08-29 22:13:01 +02006720 return -1;
6721
Kristian Høgsbergf03a6162012-01-17 11:07:42 -05006722 shell->child.deathstamp = weston_compositor_get_time();
Tiago Vignattib7dbbd62012-09-25 17:57:01 +03006723
Jonny Lamb765760d2014-08-20 15:53:19 +02006724 shell->panel_position = DESKTOP_SHELL_PANEL_POSITION_TOP;
6725
Xiong Zhang6b481422013-10-23 13:58:32 +08006726 setup_output_destroy_handler(ec, shell);
6727
Tiago Vignattib7dbbd62012-09-25 17:57:01 +03006728 loop = wl_display_get_event_loop(ec->wl_display);
6729 wl_event_loop_add_idle(loop, launch_desktop_shell_process, shell);
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02006730
Ander Conselvan de Oliveira859e8852013-02-21 18:35:21 +02006731 shell->screensaver.timer =
6732 wl_event_loop_add_timer(loop, screensaver_timeout, shell);
6733
Jason Ekstrand024177c2014-04-21 19:42:58 -05006734 wl_list_for_each(seat, &ec->seat_list, link)
6735 handle_seat_created(NULL, seat);
6736 shell->seat_create_listener.notify = handle_seat_created;
6737 wl_signal_add(&ec->seat_created_signal, &shell->seat_create_listener);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04006738
Giulio Camuffoc6ab3d52013-12-11 23:45:12 +01006739 screenshooter_create(ec);
6740
Tiago Vignatti0b52d482012-04-20 18:54:25 +03006741 shell_add_bindings(ec, shell);
Kristian Høgsberg07937562011-04-12 17:25:42 -04006742
Pekka Paalanen79346ab2013-05-22 18:03:09 +03006743 shell_fade_init(shell);
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02006744
Pekka Paalanen2e62e4a2014-08-28 11:41:26 +03006745 clock_gettime(CLOCK_MONOTONIC, &shell->startup_time);
6746
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05006747 return 0;
6748}