blob: c6865064b9c4d02109ae172156ea88358b9e1c75 [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
Philip Withnall648a4dd2013-11-25 18:01:44 +000066/*
67 * Surface stacking and ordering.
68 *
69 * This is handled using several linked lists of surfaces, organised into
70 * ‘layers’. The layers are ordered, and each of the surfaces in one layer are
71 * above all of the surfaces in the layer below. The set of layers is static and
72 * in the following order (top-most first):
73 * • Lock layer (only ever displayed on its own)
74 * • Cursor layer
75 * • Fullscreen layer
76 * • Panel layer
77 * • Input panel layer
78 * • Workspace layers
79 * • Background layer
80 *
81 * The list of layers may be manipulated to remove whole layers of surfaces from
82 * display. For example, when locking the screen, all layers except the lock
83 * layer are removed.
84 *
85 * A surface’s layer is modified on configuring the surface, in
86 * set_surface_type() (which is only called when the surface’s type change is
87 * _committed_). If a surface’s type changes (e.g. when making a window
88 * fullscreen) its layer changes too.
89 *
90 * In order to allow popup and transient surfaces to be correctly stacked above
91 * their parent surfaces, each surface tracks both its parent surface, and a
92 * linked list of its children. When a surface’s layer is updated, so are the
93 * layers of its children. Note that child surfaces are *not* the same as
94 * subsurfaces — child/parent surfaces are purely for maintaining stacking
95 * order.
96 *
97 * The children_link list of siblings of a surface (i.e. those surfaces which
98 * have the same parent) only contains weston_surfaces which have a
99 * shell_surface. Stacking is not implemented for non-shell_surface
100 * weston_surfaces. This means that the following implication does *not* hold:
101 * (shsurf->parent != NULL) ⇒ !wl_list_is_empty(shsurf->children_link)
102 */
103
Pekka Paalanen56cdea92011-11-23 16:14:12 +0200104struct shell_surface {
Jason Ekstrand651f00e2013-06-14 10:07:54 -0500105 struct wl_resource *resource;
106 struct wl_signal destroy_signal;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200107
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500108 struct weston_surface *surface;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500109 struct weston_view *view;
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600110 int32_t last_width, last_height;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200111 struct wl_listener surface_destroy_listener;
Kristian Høgsberg8150b192012-06-27 10:22:58 -0400112 struct weston_surface *parent;
Philip Withnall648a4dd2013-11-25 18:01:44 +0000113 struct wl_list children_list; /* child surfaces of this one */
114 struct wl_list children_link; /* sibling surfaces of this one */
Tiago Vignattibe143262012-04-16 17:31:41 +0300115 struct desktop_shell *shell;
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200116
Kristian Høgsbergc8f8dd82013-12-05 23:20:33 -0800117 enum shell_surface_type type;
Kristian Høgsberge7afd912012-05-02 09:47:44 -0400118 char *title, *class;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500119 int32_t saved_x, saved_y;
Rafael Antognolli3c4e3f72013-12-03 15:35:46 -0200120 int32_t saved_width, saved_height;
Alex Wu4539b082012-03-01 12:57:46 +0800121 bool saved_position_valid;
Rafael Antognolli3c4e3f72013-12-03 15:35:46 -0200122 bool saved_size_valid;
Alex Wu7bcb8bd2012-04-27 09:07:24 +0800123 bool saved_rotation_valid;
Kristian Høgsbergc85f1d42013-10-24 16:52:00 -0700124 int unresponsive, grabbed;
Kristian Høgsberg44cd1962014-02-05 21:36:04 -0800125 uint32_t resize_edges;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100126
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500127 struct {
Pekka Paalanen460099f2012-01-20 16:48:25 +0200128 struct weston_transform transform;
Kristian Høgsberg765e27b2012-01-27 13:36:13 -0500129 struct weston_matrix rotation;
Pekka Paalanen460099f2012-01-20 16:48:25 +0200130 } rotation;
131
132 struct {
Giulio Camuffo5085a752013-03-25 21:42:45 +0100133 struct wl_list grab_link;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500134 int32_t x, y;
Giulio Camuffo5085a752013-03-25 21:42:45 +0100135 struct shell_seat *shseat;
Kristian Høgsberg3730f362012-04-13 12:40:07 -0400136 uint32_t serial;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500137 } popup;
138
Alex Wu4539b082012-03-01 12:57:46 +0800139 struct {
Tiago Vignatti52e598c2012-05-07 15:23:08 +0300140 int32_t x, y;
Tiago Vignatti491bac12012-05-18 16:37:43 -0400141 uint32_t flags;
Tiago Vignatti52e598c2012-05-07 15:23:08 +0300142 } transient;
143
144 struct {
Alex Wu4539b082012-03-01 12:57:46 +0800145 enum wl_shell_surface_fullscreen_method type;
146 struct weston_transform transform; /* matrix from x, y */
147 uint32_t framerate;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500148 struct weston_view *black_view;
Alex Wu4539b082012-03-01 12:57:46 +0800149 } fullscreen;
150
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200151 struct weston_transform workspace_transform;
152
Kristian Høgsberg1cbf3262012-02-17 23:49:07 -0500153 struct weston_output *fullscreen_output;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500154 struct weston_output *output;
Rafael Antognolli65f98d82013-12-03 15:35:47 -0200155 struct weston_output *recommended_output;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100156 struct wl_list link;
Kristian Høgsberga61ca062012-05-22 16:05:52 -0400157
158 const struct weston_shell_client *client;
Rafael Antognolli03b16592013-12-03 15:35:42 -0200159
160 struct {
161 bool maximized;
162 bool fullscreen;
Rafael Antognollied207b42013-12-03 15:35:43 -0200163 bool relative;
Jasper St. Pierre8c6aa452014-02-08 18:29:49 -0500164 } state, next_state, requested_state; /* surface states */
Rafael Antognolli03b16592013-12-03 15:35:42 -0200165 bool state_changed;
Jasper St. Pierre8c6aa452014-02-08 18:29:49 -0500166 bool state_requested;
Jasper St. Pierrefaf27a92013-12-09 17:36:28 -0500167
168 int focus_count;
Pekka Paalanen56cdea92011-11-23 16:14:12 +0200169};
170
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300171struct shell_grab {
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -0400172 struct weston_pointer_grab grab;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300173 struct shell_surface *shsurf;
174 struct wl_listener shsurf_destroy_listener;
175};
176
Rusty Lynch1084da52013-08-15 09:10:08 -0700177struct shell_touch_grab {
178 struct weston_touch_grab grab;
179 struct shell_surface *shsurf;
180 struct wl_listener shsurf_destroy_listener;
181 struct weston_touch *touch;
182};
183
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300184struct weston_move_grab {
185 struct shell_grab base;
Daniel Stone103db7f2012-05-08 17:17:55 +0100186 wl_fixed_t dx, dy;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500187};
188
Rusty Lynch1084da52013-08-15 09:10:08 -0700189struct weston_touch_move_grab {
190 struct shell_touch_grab base;
Kristian Høgsberg8e80a312014-01-17 15:18:10 -0800191 int active;
Rusty Lynch1084da52013-08-15 09:10:08 -0700192 wl_fixed_t dx, dy;
193};
194
Pekka Paalanen460099f2012-01-20 16:48:25 +0200195struct rotate_grab {
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300196 struct shell_grab base;
Kristian Høgsberg765e27b2012-01-27 13:36:13 -0500197 struct weston_matrix rotation;
Pekka Paalanen460099f2012-01-20 16:48:25 +0200198 struct {
John Kåre Alsaker490d02a2012-09-30 02:57:21 +0200199 float x;
200 float y;
Pekka Paalanen460099f2012-01-20 16:48:25 +0200201 } center;
202};
203
Giulio Camuffo5085a752013-03-25 21:42:45 +0100204struct shell_seat {
205 struct weston_seat *seat;
206 struct wl_listener seat_destroy_listener;
Jasper St. Pierrefaf27a92013-12-09 17:36:28 -0500207 struct weston_surface *focused_surface;
Giulio Camuffo5085a752013-03-25 21:42:45 +0100208
209 struct {
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -0400210 struct weston_pointer_grab grab;
Giulio Camuffo5085a752013-03-25 21:42:45 +0100211 struct wl_list surfaces_list;
212 struct wl_client *client;
213 int32_t initial_up;
214 } popup_grab;
215};
216
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -0800217struct shell_client {
218 struct wl_resource *resource;
219 struct wl_client *client;
220 struct desktop_shell *shell;
221 struct wl_listener destroy_listener;
222 struct wl_event_source *ping_timer;
223 uint32_t ping_serial;
224 int unresponsive;
225};
226
Emilio Pozuelo Monfort1a26f1b2014-01-07 16:41:40 +0100227void
228set_alpha_if_fullscreen(struct shell_surface *shsurf)
229{
230 if (shsurf && shsurf->state.fullscreen)
231 shsurf->fullscreen.black_view->alpha = 0.25;
232}
233
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -0800234static struct shell_client *
235get_shell_client(struct wl_client *client);
236
Alex Wubd3354b2012-04-17 17:20:49 +0800237static struct desktop_shell *
238shell_surface_get_shell(struct shell_surface *shsurf);
239
Kristian Høgsberg0c369032013-02-14 21:31:44 -0500240static void
Kristian Høgsberge3148752013-05-06 23:19:49 -0400241surface_rotate(struct shell_surface *surface, struct weston_seat *seat);
Kristian Høgsberg0c369032013-02-14 21:31:44 -0500242
Pekka Paalanen79346ab2013-05-22 18:03:09 +0300243static void
244shell_fade_startup(struct desktop_shell *shell);
245
Philip Withnallbecb77e2013-11-25 18:01:30 +0000246static struct shell_seat *
247get_shell_seat(struct weston_seat *seat);
248
Philip Withnall648a4dd2013-11-25 18:01:44 +0000249static void
250shell_surface_update_child_surface_layers(struct shell_surface *shsurf);
251
Alex Wubd3354b2012-04-17 17:20:49 +0800252static bool
Rafael Antognollie2a34552013-12-03 15:35:45 -0200253shell_surface_is_wl_shell_surface(struct shell_surface *shsurf);
254
255static bool
256shell_surface_is_xdg_surface(struct shell_surface *shsurf);
257
258static bool
259shell_surface_is_xdg_popup(struct shell_surface *shsurf);
260
261static void
262shell_surface_set_parent(struct shell_surface *shsurf,
263 struct weston_surface *parent);
264
265static bool
Alex Wubd3354b2012-04-17 17:20:49 +0800266shell_surface_is_top_fullscreen(struct shell_surface *shsurf)
267{
268 struct desktop_shell *shell;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500269 struct weston_view *top_fs_ev;
Alex Wubd3354b2012-04-17 17:20:49 +0800270
271 shell = shell_surface_get_shell(shsurf);
Quentin Glidicc0d79ce2013-01-29 14:16:13 +0100272
Jason Ekstranda7af7042013-10-12 22:38:11 -0500273 if (wl_list_empty(&shell->fullscreen_layer.view_list))
Alex Wubd3354b2012-04-17 17:20:49 +0800274 return false;
275
Jason Ekstranda7af7042013-10-12 22:38:11 -0500276 top_fs_ev = container_of(shell->fullscreen_layer.view_list.next,
277 struct weston_view,
Alex Wubd3354b2012-04-17 17:20:49 +0800278 layer_link);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500279 return (shsurf == get_shell_surface(top_fs_ev->surface));
Alex Wubd3354b2012-04-17 17:20:49 +0800280}
281
Kristian Høgsberg6af8eb92012-01-25 16:57:11 -0500282static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400283destroy_shell_grab_shsurf(struct wl_listener *listener, void *data)
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300284{
285 struct shell_grab *grab;
286
287 grab = container_of(listener, struct shell_grab,
288 shsurf_destroy_listener);
289
290 grab->shsurf = NULL;
291}
292
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800293struct weston_view *
Jason Ekstranda7af7042013-10-12 22:38:11 -0500294get_default_view(struct weston_surface *surface)
295{
296 struct shell_surface *shsurf;
297 struct weston_view *view;
298
299 if (!surface || wl_list_empty(&surface->views))
300 return NULL;
301
302 shsurf = get_shell_surface(surface);
303 if (shsurf)
304 return shsurf->view;
305
306 wl_list_for_each(view, &surface->views, surface_link)
307 if (weston_view_is_mapped(view))
308 return view;
309
310 return container_of(surface->views.next, struct weston_view, surface_link);
311}
312
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300313static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -0400314popup_grab_end(struct weston_pointer *pointer);
Kristian Høgsberg57e09072012-10-30 14:07:27 -0400315
316static void
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300317shell_grab_start(struct shell_grab *grab,
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -0400318 const struct weston_pointer_grab_interface *interface,
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300319 struct shell_surface *shsurf,
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -0400320 struct weston_pointer *pointer,
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300321 enum desktop_shell_cursor cursor)
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300322{
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300323 struct desktop_shell *shell = shsurf->shell;
324
Kristian Høgsberg57e09072012-10-30 14:07:27 -0400325 popup_grab_end(pointer);
326
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300327 grab->grab.interface = interface;
328 grab->shsurf = shsurf;
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400329 grab->shsurf_destroy_listener.notify = destroy_shell_grab_shsurf;
Jason Ekstrand651f00e2013-06-14 10:07:54 -0500330 wl_signal_add(&shsurf->destroy_signal,
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400331 &grab->shsurf_destroy_listener);
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300332
Kristian Høgsbergc85f1d42013-10-24 16:52:00 -0700333 shsurf->grabbed = 1;
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -0400334 weston_pointer_start_grab(pointer, &grab->grab);
Kristian Høgsbergc9974a02013-07-03 19:24:57 -0400335 if (shell->child.desktop_shell) {
336 desktop_shell_send_grab_cursor(shell->child.desktop_shell,
337 cursor);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500338 weston_pointer_set_focus(pointer,
339 get_default_view(shell->grab_surface),
Kristian Høgsbergc9974a02013-07-03 19:24:57 -0400340 wl_fixed_from_int(0),
341 wl_fixed_from_int(0));
342 }
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300343}
344
345static void
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300346shell_grab_end(struct shell_grab *grab)
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300347{
Kristian Høgsbergc85f1d42013-10-24 16:52:00 -0700348 if (grab->shsurf) {
Kristian Høgsberg47b5dca2012-06-07 18:08:04 -0400349 wl_list_remove(&grab->shsurf_destroy_listener.link);
Kristian Høgsbergc85f1d42013-10-24 16:52:00 -0700350 grab->shsurf->grabbed = 0;
Kristian Høgsberg44cd1962014-02-05 21:36:04 -0800351 grab->shsurf->resize_edges = 0;
Kristian Høgsbergc85f1d42013-10-24 16:52:00 -0700352 }
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300353
Kristian Høgsberg9e5d7d12013-07-22 16:31:53 -0700354 weston_pointer_end_grab(grab->grab.pointer);
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300355}
356
357static void
Rusty Lynch1084da52013-08-15 09:10:08 -0700358shell_touch_grab_start(struct shell_touch_grab *grab,
359 const struct weston_touch_grab_interface *interface,
360 struct shell_surface *shsurf,
361 struct weston_touch *touch)
362{
363 struct desktop_shell *shell = shsurf->shell;
U. Artie Eoffcf5737a2014-01-17 10:08:25 -0800364
Rusty Lynch1084da52013-08-15 09:10:08 -0700365 grab->grab.interface = interface;
366 grab->shsurf = shsurf;
367 grab->shsurf_destroy_listener.notify = destroy_shell_grab_shsurf;
368 wl_signal_add(&shsurf->destroy_signal,
369 &grab->shsurf_destroy_listener);
370
371 grab->touch = touch;
Kristian Høgsbergc85f1d42013-10-24 16:52:00 -0700372 shsurf->grabbed = 1;
Rusty Lynch1084da52013-08-15 09:10:08 -0700373
374 weston_touch_start_grab(touch, &grab->grab);
375 if (shell->child.desktop_shell)
Jason Ekstranda7af7042013-10-12 22:38:11 -0500376 weston_touch_set_focus(touch->seat,
377 get_default_view(shell->grab_surface));
Rusty Lynch1084da52013-08-15 09:10:08 -0700378}
379
380static void
381shell_touch_grab_end(struct shell_touch_grab *grab)
382{
Kristian Høgsbergc85f1d42013-10-24 16:52:00 -0700383 if (grab->shsurf) {
Rusty Lynch1084da52013-08-15 09:10:08 -0700384 wl_list_remove(&grab->shsurf_destroy_listener.link);
Kristian Høgsbergc85f1d42013-10-24 16:52:00 -0700385 grab->shsurf->grabbed = 0;
386 }
Rusty Lynch1084da52013-08-15 09:10:08 -0700387
388 weston_touch_end_grab(grab->touch);
389}
390
391static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500392center_on_output(struct weston_view *view,
Alex Wu4539b082012-03-01 12:57:46 +0800393 struct weston_output *output);
394
Daniel Stone496ca172012-05-30 16:31:42 +0100395static enum weston_keyboard_modifier
Tiago Vignatti0b52d482012-04-20 18:54:25 +0300396get_modifier(char *modifier)
397{
398 if (!modifier)
399 return MODIFIER_SUPER;
400
401 if (!strcmp("ctrl", modifier))
402 return MODIFIER_CTRL;
403 else if (!strcmp("alt", modifier))
404 return MODIFIER_ALT;
405 else if (!strcmp("super", modifier))
406 return MODIFIER_SUPER;
407 else
408 return MODIFIER_SUPER;
409}
410
Juan Zhaoe10d2792012-04-25 19:09:52 +0800411static enum animation_type
412get_animation_type(char *animation)
413{
U. Artie Eoffb5719102014-01-15 14:26:31 -0800414 if (!animation)
415 return ANIMATION_NONE;
416
Juan Zhaoe10d2792012-04-25 19:09:52 +0800417 if (!strcmp("zoom", animation))
418 return ANIMATION_ZOOM;
419 else if (!strcmp("fade", animation))
420 return ANIMATION_FADE;
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100421 else if (!strcmp("dim-layer", animation))
422 return ANIMATION_DIM_LAYER;
Juan Zhaoe10d2792012-04-25 19:09:52 +0800423 else
424 return ANIMATION_NONE;
425}
426
Alex Wu4539b082012-03-01 12:57:46 +0800427static void
Kristian Høgsberg14e438c2013-05-26 21:48:14 -0400428shell_configuration(struct desktop_shell *shell)
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200429{
Kristian Høgsberg673a8892013-05-23 21:40:56 -0400430 struct weston_config_section *section;
431 int duration;
432 char *s;
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200433
Kristian Høgsberg673a8892013-05-23 21:40:56 -0400434 section = weston_config_get_section(shell->compositor->config,
435 "screensaver", NULL, NULL);
436 weston_config_section_get_string(section,
437 "path", &shell->screensaver.path, NULL);
438 weston_config_section_get_int(section, "duration", &duration, 60);
Ander Conselvan de Oliveira859e8852013-02-21 18:35:21 +0200439 shell->screensaver.duration = duration * 1000;
Kristian Høgsberg673a8892013-05-23 21:40:56 -0400440
441 section = weston_config_get_section(shell->compositor->config,
442 "shell", NULL, NULL);
443 weston_config_section_get_string(section,
Emilio Pozuelo Monfort8a81b832013-12-02 12:53:32 +0100444 "client", &s, LIBEXECDIR "/" WESTON_SHELL_CLIENT);
Emilio Pozuelo Monfort46ce7982013-11-20 13:22:29 +0100445 shell->client = s;
446 weston_config_section_get_string(section,
Kristian Høgsberg673a8892013-05-23 21:40:56 -0400447 "binding-modifier", &s, "super");
448 shell->binding_modifier = get_modifier(s);
Quentin Glidic8418c292013-06-18 09:11:03 +0200449 free(s);
Kristian Høgsbergd56ab4e2014-01-16 16:51:52 -0800450
451 weston_config_section_get_string(section,
452 "exposay-modifier", &s, "none");
453 if (strcmp(s, "none") == 0)
454 shell->exposay_modifier = 0;
455 else
456 shell->exposay_modifier = get_modifier(s);
457 free(s);
458
Kristian Høgsberg673a8892013-05-23 21:40:56 -0400459 weston_config_section_get_string(section, "animation", &s, "none");
460 shell->win_animation_type = get_animation_type(s);
Quentin Glidic8418c292013-06-18 09:11:03 +0200461 free(s);
Kristian Høgsberg724c8d92013-10-16 11:38:24 -0700462 weston_config_section_get_string(section,
463 "startup-animation", &s, "fade");
464 shell->startup_animation_type = get_animation_type(s);
465 free(s);
Kristian Høgsberg912e0a12013-10-30 08:59:55 -0700466 if (shell->startup_animation_type == ANIMATION_ZOOM)
467 shell->startup_animation_type = ANIMATION_NONE;
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100468 weston_config_section_get_string(section, "focus-animation", &s, "none");
469 shell->focus_animation_type = get_animation_type(s);
470 free(s);
Kristian Høgsberg673a8892013-05-23 21:40:56 -0400471 weston_config_section_get_uint(section, "num-workspaces",
472 &shell->workspaces.num,
473 DEFAULT_NUM_WORKSPACES);
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200474}
475
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800476struct weston_output *
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100477get_default_output(struct weston_compositor *compositor)
478{
479 return container_of(compositor->output_list.next,
480 struct weston_output, link);
481}
482
483
484/* no-op func for checking focus surface */
485static void
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600486focus_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100487{
488}
489
490static struct focus_surface *
491get_focus_surface(struct weston_surface *surface)
492{
493 if (surface->configure == focus_surface_configure)
494 return surface->configure_private;
495 else
496 return NULL;
497}
498
499static bool
500is_focus_surface (struct weston_surface *es)
501{
502 return (es->configure == focus_surface_configure);
503}
504
505static bool
506is_focus_view (struct weston_view *view)
507{
508 return is_focus_surface (view->surface);
509}
510
511static struct focus_surface *
512create_focus_surface(struct weston_compositor *ec,
513 struct weston_output *output)
514{
515 struct focus_surface *fsurf = NULL;
516 struct weston_surface *surface = NULL;
517
518 fsurf = malloc(sizeof *fsurf);
519 if (!fsurf)
520 return NULL;
521
522 fsurf->surface = weston_surface_create(ec);
523 surface = fsurf->surface;
524 if (surface == NULL) {
525 free(fsurf);
526 return NULL;
527 }
528
529 surface->configure = focus_surface_configure;
530 surface->output = output;
531 surface->configure_private = fsurf;
532
U. Artie Eoff0b23b2b2014-01-15 14:45:59 -0800533 fsurf->view = weston_view_create(surface);
534 if (fsurf->view == NULL) {
535 weston_surface_destroy(surface);
536 free(fsurf);
537 return NULL;
538 }
Emilio Pozuelo Monfortda644262013-11-19 11:37:19 +0100539 fsurf->view->output = output;
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100540
Jason Ekstrand5c11a332013-12-04 20:32:03 -0600541 weston_surface_set_size(surface, output->width, output->height);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600542 weston_view_set_position(fsurf->view, output->x, output->y);
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100543 weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1.0);
544 pixman_region32_fini(&surface->opaque);
545 pixman_region32_init_rect(&surface->opaque, output->x, output->y,
546 output->width, output->height);
547 pixman_region32_fini(&surface->input);
548 pixman_region32_init(&surface->input);
549
550 wl_list_init(&fsurf->workspace_transform.link);
551
552 return fsurf;
553}
554
555static void
556focus_surface_destroy(struct focus_surface *fsurf)
557{
558 weston_surface_destroy(fsurf->surface);
559 free(fsurf);
560}
561
562static void
563focus_animation_done(struct weston_view_animation *animation, void *data)
564{
565 struct workspace *ws = data;
566
567 ws->focus_animation = NULL;
568}
569
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200570static void
Jonas Ådahl04769742012-06-13 00:01:24 +0200571focus_state_destroy(struct focus_state *state)
572{
573 wl_list_remove(&state->seat_destroy_listener.link);
574 wl_list_remove(&state->surface_destroy_listener.link);
575 free(state);
576}
577
578static void
579focus_state_seat_destroy(struct wl_listener *listener, void *data)
580{
581 struct focus_state *state = container_of(listener,
582 struct focus_state,
583 seat_destroy_listener);
584
585 wl_list_remove(&state->link);
586 focus_state_destroy(state);
587}
588
589static void
590focus_state_surface_destroy(struct wl_listener *listener, void *data)
591{
592 struct focus_state *state = container_of(listener,
593 struct focus_state,
Kristian Høgsbergb8e0d0f2012-07-31 10:30:26 -0400594 surface_destroy_listener);
Kristian Høgsberge3778222012-07-31 17:29:30 -0400595 struct desktop_shell *shell;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500596 struct weston_surface *main_surface, *next;
597 struct weston_view *view;
Jonas Ådahl04769742012-06-13 00:01:24 +0200598
Pekka Paalanen01388e22013-04-25 13:57:44 +0300599 main_surface = weston_surface_get_main_surface(state->keyboard_focus);
600
Kristian Høgsberge3778222012-07-31 17:29:30 -0400601 next = NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500602 wl_list_for_each(view, &state->ws->layer.view_list, layer_link) {
603 if (view->surface == main_surface)
Kristian Høgsberge3778222012-07-31 17:29:30 -0400604 continue;
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100605 if (is_focus_view(view))
606 continue;
Kristian Høgsberge3778222012-07-31 17:29:30 -0400607
Jason Ekstranda7af7042013-10-12 22:38:11 -0500608 next = view->surface;
Kristian Høgsberge3778222012-07-31 17:29:30 -0400609 break;
610 }
611
Pekka Paalanen01388e22013-04-25 13:57:44 +0300612 /* if the focus was a sub-surface, activate its main surface */
613 if (main_surface != state->keyboard_focus)
614 next = main_surface;
615
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100616 shell = state->seat->compositor->shell_interface.shell;
Kristian Høgsberge3778222012-07-31 17:29:30 -0400617 if (next) {
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100618 state->keyboard_focus = NULL;
Kristian Høgsberge3778222012-07-31 17:29:30 -0400619 activate(shell, next, state->seat);
620 } else {
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100621 if (shell->focus_animation_type == ANIMATION_DIM_LAYER) {
622 if (state->ws->focus_animation)
623 weston_view_animation_destroy(state->ws->focus_animation);
624
625 state->ws->focus_animation = weston_fade_run(
626 state->ws->fsurf_front->view,
627 state->ws->fsurf_front->view->alpha, 0.0, 300,
628 focus_animation_done, state->ws);
629 }
630
Kristian Høgsberge3778222012-07-31 17:29:30 -0400631 wl_list_remove(&state->link);
632 focus_state_destroy(state);
633 }
Jonas Ådahl04769742012-06-13 00:01:24 +0200634}
635
636static struct focus_state *
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400637focus_state_create(struct weston_seat *seat, struct workspace *ws)
Jonas Ådahl04769742012-06-13 00:01:24 +0200638{
Jonas Ådahl04769742012-06-13 00:01:24 +0200639 struct focus_state *state;
Jonas Ådahl04769742012-06-13 00:01:24 +0200640
641 state = malloc(sizeof *state);
642 if (state == NULL)
643 return NULL;
644
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100645 state->keyboard_focus = NULL;
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400646 state->ws = ws;
Jonas Ådahl04769742012-06-13 00:01:24 +0200647 state->seat = seat;
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400648 wl_list_insert(&ws->focus_list, &state->link);
Jonas Ådahl04769742012-06-13 00:01:24 +0200649
650 state->seat_destroy_listener.notify = focus_state_seat_destroy;
651 state->surface_destroy_listener.notify = focus_state_surface_destroy;
Kristian Høgsberg49124542013-05-06 22:27:40 -0400652 wl_signal_add(&seat->destroy_signal,
Jonas Ådahl04769742012-06-13 00:01:24 +0200653 &state->seat_destroy_listener);
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400654 wl_list_init(&state->surface_destroy_listener.link);
Jonas Ådahl04769742012-06-13 00:01:24 +0200655
656 return state;
657}
658
Jonas Ådahl8538b222012-08-29 22:13:03 +0200659static struct focus_state *
660ensure_focus_state(struct desktop_shell *shell, struct weston_seat *seat)
661{
662 struct workspace *ws = get_current_workspace(shell);
663 struct focus_state *state;
664
665 wl_list_for_each(state, &ws->focus_list, link)
666 if (state->seat == seat)
667 break;
668
669 if (&state->link == &ws->focus_list)
670 state = focus_state_create(seat, ws);
671
672 return state;
673}
674
Jonas Ådahl04769742012-06-13 00:01:24 +0200675static void
Kristian Høgsbergd500bf12014-01-22 12:25:20 -0800676focus_state_set_focus(struct focus_state *state,
677 struct weston_surface *surface)
678{
679 if (state->keyboard_focus) {
680 wl_list_remove(&state->surface_destroy_listener.link);
681 wl_list_init(&state->surface_destroy_listener.link);
682 }
683
684 state->keyboard_focus = surface;
685 if (surface)
686 wl_signal_add(&surface->destroy_signal,
687 &state->surface_destroy_listener);
688}
689
690static void
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400691restore_focus_state(struct desktop_shell *shell, struct workspace *ws)
Jonas Ådahl04769742012-06-13 00:01:24 +0200692{
693 struct focus_state *state, *next;
Kristian Høgsbergfe7aa902013-05-08 09:54:37 -0400694 struct weston_surface *surface;
Jonas Ådahl04769742012-06-13 00:01:24 +0200695
696 wl_list_for_each_safe(state, next, &ws->focus_list, link) {
Kristian Høgsberge61d2f42014-01-17 12:18:53 -0800697 if (state->seat->keyboard == NULL)
698 continue;
699
Kristian Høgsbergfe7aa902013-05-08 09:54:37 -0400700 surface = state->keyboard_focus;
Jonas Ådahl56899442012-08-29 22:12:59 +0200701
Kristian Høgsberge3148752013-05-06 23:19:49 -0400702 weston_keyboard_set_focus(state->seat->keyboard, surface);
Jonas Ådahl04769742012-06-13 00:01:24 +0200703 }
704}
705
706static void
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200707replace_focus_state(struct desktop_shell *shell, struct workspace *ws,
708 struct weston_seat *seat)
709{
710 struct focus_state *state;
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200711
712 wl_list_for_each(state, &ws->focus_list, link) {
713 if (state->seat == seat) {
Kristian Høgsbergd500bf12014-01-22 12:25:20 -0800714 focus_state_set_focus(state, seat->keyboard->focus);
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200715 return;
716 }
717 }
718}
719
720static void
721drop_focus_state(struct desktop_shell *shell, struct workspace *ws,
722 struct weston_surface *surface)
723{
724 struct focus_state *state;
725
726 wl_list_for_each(state, &ws->focus_list, link)
727 if (state->keyboard_focus == surface)
Kristian Høgsbergd500bf12014-01-22 12:25:20 -0800728 focus_state_set_focus(state, NULL);
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200729}
730
731static void
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100732animate_focus_change(struct desktop_shell *shell, struct workspace *ws,
733 struct weston_view *from, struct weston_view *to)
734{
735 struct weston_output *output;
736 bool focus_surface_created = false;
737
738 /* FIXME: Only support dim animation using two layers */
739 if (from == to || shell->focus_animation_type != ANIMATION_DIM_LAYER)
740 return;
741
742 output = get_default_output(shell->compositor);
743 if (ws->fsurf_front == NULL && (from || to)) {
744 ws->fsurf_front = create_focus_surface(shell->compositor, output);
U. Artie Eoff0b23b2b2014-01-15 14:45:59 -0800745 if (ws->fsurf_front == NULL)
746 return;
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100747 ws->fsurf_front->view->alpha = 0.0;
U. Artie Eoff0b23b2b2014-01-15 14:45:59 -0800748
749 ws->fsurf_back = create_focus_surface(shell->compositor, output);
750 if (ws->fsurf_back == NULL) {
751 focus_surface_destroy(ws->fsurf_front);
752 return;
753 }
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100754 ws->fsurf_back->view->alpha = 0.0;
U. Artie Eoff0b23b2b2014-01-15 14:45:59 -0800755
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100756 focus_surface_created = true;
757 } else {
758 wl_list_remove(&ws->fsurf_front->view->layer_link);
759 wl_list_remove(&ws->fsurf_back->view->layer_link);
760 }
761
762 if (ws->focus_animation) {
763 weston_view_animation_destroy(ws->focus_animation);
764 ws->focus_animation = NULL;
765 }
766
767 if (to)
768 wl_list_insert(&to->layer_link,
769 &ws->fsurf_front->view->layer_link);
770 else if (from)
771 wl_list_insert(&ws->layer.view_list,
772 &ws->fsurf_front->view->layer_link);
773
774 if (focus_surface_created) {
775 ws->focus_animation = weston_fade_run(
776 ws->fsurf_front->view,
777 ws->fsurf_front->view->alpha, 0.6, 300,
778 focus_animation_done, ws);
779 } else if (from) {
780 wl_list_insert(&from->layer_link,
781 &ws->fsurf_back->view->layer_link);
782 ws->focus_animation = weston_stable_fade_run(
783 ws->fsurf_front->view, 0.0,
784 ws->fsurf_back->view, 0.6,
785 focus_animation_done, ws);
786 } else if (to) {
787 wl_list_insert(&ws->layer.view_list,
788 &ws->fsurf_back->view->layer_link);
789 ws->focus_animation = weston_stable_fade_run(
790 ws->fsurf_front->view, 0.0,
791 ws->fsurf_back->view, 0.6,
792 focus_animation_done, ws);
793 }
794}
795
796static void
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200797workspace_destroy(struct workspace *ws)
798{
Jonas Ådahl04769742012-06-13 00:01:24 +0200799 struct focus_state *state, *next;
800
801 wl_list_for_each_safe(state, next, &ws->focus_list, link)
802 focus_state_destroy(state);
803
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100804 if (ws->fsurf_front)
805 focus_surface_destroy(ws->fsurf_front);
806 if (ws->fsurf_back)
807 focus_surface_destroy(ws->fsurf_back);
808
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200809 free(ws);
810}
811
Jonas Ådahl04769742012-06-13 00:01:24 +0200812static void
813seat_destroyed(struct wl_listener *listener, void *data)
814{
815 struct weston_seat *seat = data;
816 struct focus_state *state, *next;
817 struct workspace *ws = container_of(listener,
818 struct workspace,
819 seat_destroyed_listener);
820
821 wl_list_for_each_safe(state, next, &ws->focus_list, link)
822 if (state->seat == seat)
823 wl_list_remove(&state->link);
824}
825
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200826static struct workspace *
827workspace_create(void)
828{
829 struct workspace *ws = malloc(sizeof *ws);
830 if (ws == NULL)
831 return NULL;
832
833 weston_layer_init(&ws->layer, NULL);
834
Jonas Ådahl04769742012-06-13 00:01:24 +0200835 wl_list_init(&ws->focus_list);
836 wl_list_init(&ws->seat_destroyed_listener.link);
837 ws->seat_destroyed_listener.notify = seat_destroyed;
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100838 ws->fsurf_front = NULL;
839 ws->fsurf_back = NULL;
840 ws->focus_animation = NULL;
Jonas Ådahl04769742012-06-13 00:01:24 +0200841
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200842 return ws;
843}
844
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200845static int
846workspace_is_empty(struct workspace *ws)
847{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500848 return wl_list_empty(&ws->layer.view_list);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200849}
850
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200851static struct workspace *
852get_workspace(struct desktop_shell *shell, unsigned int index)
853{
854 struct workspace **pws = shell->workspaces.array.data;
Philipp Brüschweiler067abf62012-09-01 16:03:05 +0200855 assert(index < shell->workspaces.num);
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200856 pws += index;
857 return *pws;
858}
859
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800860struct workspace *
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200861get_current_workspace(struct desktop_shell *shell)
862{
863 return get_workspace(shell, shell->workspaces.current);
864}
865
866static void
867activate_workspace(struct desktop_shell *shell, unsigned int index)
868{
869 struct workspace *ws;
870
871 ws = get_workspace(shell, index);
872 wl_list_insert(&shell->panel_layer.link, &ws->layer.link);
873
874 shell->workspaces.current = index;
875}
876
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200877static unsigned int
878get_output_height(struct weston_output *output)
879{
880 return abs(output->region.extents.y1 - output->region.extents.y2);
881}
882
883static void
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100884view_translate(struct workspace *ws, struct weston_view *view, double d)
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200885{
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200886 struct weston_transform *transform;
887
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100888 if (is_focus_view(view)) {
889 struct focus_surface *fsurf = get_focus_surface(view->surface);
890 transform = &fsurf->workspace_transform;
891 } else {
892 struct shell_surface *shsurf = get_shell_surface(view->surface);
893 transform = &shsurf->workspace_transform;
894 }
895
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200896 if (wl_list_empty(&transform->link))
Jason Ekstranda7af7042013-10-12 22:38:11 -0500897 wl_list_insert(view->geometry.transformation_list.prev,
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100898 &transform->link);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200899
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100900 weston_matrix_init(&transform->matrix);
901 weston_matrix_translate(&transform->matrix,
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200902 0.0, d, 0.0);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500903 weston_view_geometry_dirty(view);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200904}
905
906static void
907workspace_translate_out(struct workspace *ws, double fraction)
908{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500909 struct weston_view *view;
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200910 unsigned int height;
911 double d;
912
Jason Ekstranda7af7042013-10-12 22:38:11 -0500913 wl_list_for_each(view, &ws->layer.view_list, layer_link) {
914 height = get_output_height(view->surface->output);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200915 d = height * fraction;
916
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100917 view_translate(ws, view, d);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200918 }
919}
920
921static void
922workspace_translate_in(struct workspace *ws, double fraction)
923{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500924 struct weston_view *view;
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200925 unsigned int height;
926 double d;
927
Jason Ekstranda7af7042013-10-12 22:38:11 -0500928 wl_list_for_each(view, &ws->layer.view_list, layer_link) {
929 height = get_output_height(view->surface->output);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200930
931 if (fraction > 0)
932 d = -(height - height * fraction);
933 else
934 d = height + height * fraction;
935
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100936 view_translate(ws, view, d);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200937 }
938}
939
940static void
Jonas Ådahle9d22502012-08-29 22:13:01 +0200941broadcast_current_workspace_state(struct desktop_shell *shell)
942{
Kristian Høgsberg2e3c3962013-09-11 12:00:47 -0700943 struct wl_resource *resource;
Jonas Ådahle9d22502012-08-29 22:13:01 +0200944
Kristian Høgsberg2e3c3962013-09-11 12:00:47 -0700945 wl_resource_for_each(resource, &shell->workspaces.client_list)
946 workspace_manager_send_state(resource,
Jonas Ådahle9d22502012-08-29 22:13:01 +0200947 shell->workspaces.current,
948 shell->workspaces.num);
949}
950
951static void
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200952reverse_workspace_change_animation(struct desktop_shell *shell,
953 unsigned int index,
954 struct workspace *from,
955 struct workspace *to)
956{
957 shell->workspaces.current = index;
958
959 shell->workspaces.anim_to = to;
960 shell->workspaces.anim_from = from;
961 shell->workspaces.anim_dir = -1 * shell->workspaces.anim_dir;
962 shell->workspaces.anim_timestamp = 0;
963
Scott Moreau4272e632012-08-13 09:58:41 -0600964 weston_compositor_schedule_repaint(shell->compositor);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200965}
966
967static void
968workspace_deactivate_transforms(struct workspace *ws)
969{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500970 struct weston_view *view;
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100971 struct weston_transform *transform;
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200972
Jason Ekstranda7af7042013-10-12 22:38:11 -0500973 wl_list_for_each(view, &ws->layer.view_list, layer_link) {
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100974 if (is_focus_view(view)) {
975 struct focus_surface *fsurf = get_focus_surface(view->surface);
976 transform = &fsurf->workspace_transform;
977 } else {
978 struct shell_surface *shsurf = get_shell_surface(view->surface);
979 transform = &shsurf->workspace_transform;
980 }
981
982 if (!wl_list_empty(&transform->link)) {
983 wl_list_remove(&transform->link);
984 wl_list_init(&transform->link);
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200985 }
Jason Ekstranda7af7042013-10-12 22:38:11 -0500986 weston_view_geometry_dirty(view);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200987 }
988}
989
990static void
991finish_workspace_change_animation(struct desktop_shell *shell,
992 struct workspace *from,
993 struct workspace *to)
994{
Scott Moreau4272e632012-08-13 09:58:41 -0600995 weston_compositor_schedule_repaint(shell->compositor);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200996
997 wl_list_remove(&shell->workspaces.animation.link);
998 workspace_deactivate_transforms(from);
999 workspace_deactivate_transforms(to);
1000 shell->workspaces.anim_to = NULL;
1001
1002 wl_list_remove(&shell->workspaces.anim_from->layer.link);
1003}
1004
1005static void
1006animate_workspace_change_frame(struct weston_animation *animation,
1007 struct weston_output *output, uint32_t msecs)
1008{
1009 struct desktop_shell *shell =
1010 container_of(animation, struct desktop_shell,
1011 workspaces.animation);
1012 struct workspace *from = shell->workspaces.anim_from;
1013 struct workspace *to = shell->workspaces.anim_to;
1014 uint32_t t;
1015 double x, y;
1016
1017 if (workspace_is_empty(from) && workspace_is_empty(to)) {
1018 finish_workspace_change_animation(shell, from, to);
1019 return;
1020 }
1021
1022 if (shell->workspaces.anim_timestamp == 0) {
1023 if (shell->workspaces.anim_current == 0.0)
1024 shell->workspaces.anim_timestamp = msecs;
1025 else
1026 shell->workspaces.anim_timestamp =
1027 msecs -
1028 /* Invers of movement function 'y' below. */
1029 (asin(1.0 - shell->workspaces.anim_current) *
1030 DEFAULT_WORKSPACE_CHANGE_ANIMATION_LENGTH *
1031 M_2_PI);
1032 }
1033
1034 t = msecs - shell->workspaces.anim_timestamp;
1035
1036 /*
1037 * x = [0, π/2]
1038 * y(x) = sin(x)
1039 */
1040 x = t * (1.0/DEFAULT_WORKSPACE_CHANGE_ANIMATION_LENGTH) * M_PI_2;
1041 y = sin(x);
1042
1043 if (t < DEFAULT_WORKSPACE_CHANGE_ANIMATION_LENGTH) {
Scott Moreau4272e632012-08-13 09:58:41 -06001044 weston_compositor_schedule_repaint(shell->compositor);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001045
1046 workspace_translate_out(from, shell->workspaces.anim_dir * y);
1047 workspace_translate_in(to, shell->workspaces.anim_dir * y);
1048 shell->workspaces.anim_current = y;
1049
Scott Moreau4272e632012-08-13 09:58:41 -06001050 weston_compositor_schedule_repaint(shell->compositor);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001051 }
Jonas Ådahl04769742012-06-13 00:01:24 +02001052 else
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001053 finish_workspace_change_animation(shell, from, to);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001054}
1055
1056static void
1057animate_workspace_change(struct desktop_shell *shell,
1058 unsigned int index,
1059 struct workspace *from,
1060 struct workspace *to)
1061{
1062 struct weston_output *output;
1063
1064 int dir;
1065
1066 if (index > shell->workspaces.current)
1067 dir = -1;
1068 else
1069 dir = 1;
1070
1071 shell->workspaces.current = index;
1072
1073 shell->workspaces.anim_dir = dir;
1074 shell->workspaces.anim_from = from;
1075 shell->workspaces.anim_to = to;
1076 shell->workspaces.anim_current = 0.0;
1077 shell->workspaces.anim_timestamp = 0;
1078
1079 output = container_of(shell->compositor->output_list.next,
1080 struct weston_output, link);
1081 wl_list_insert(&output->animation_list,
1082 &shell->workspaces.animation.link);
1083
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001084 wl_list_insert(from->layer.link.prev, &to->layer.link);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001085
1086 workspace_translate_in(to, 0);
1087
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -04001088 restore_focus_state(shell, to);
Jonas Ådahl04769742012-06-13 00:01:24 +02001089
Scott Moreau4272e632012-08-13 09:58:41 -06001090 weston_compositor_schedule_repaint(shell->compositor);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001091}
1092
Jonas Ådahle3cddce2012-06-13 00:01:22 +02001093static void
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001094update_workspace(struct desktop_shell *shell, unsigned int index,
1095 struct workspace *from, struct workspace *to)
1096{
1097 shell->workspaces.current = index;
1098 wl_list_insert(&from->layer.link, &to->layer.link);
1099 wl_list_remove(&from->layer.link);
1100}
1101
1102static void
Jonas Ådahle3cddce2012-06-13 00:01:22 +02001103change_workspace(struct desktop_shell *shell, unsigned int index)
1104{
1105 struct workspace *from;
1106 struct workspace *to;
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01001107 struct focus_state *state;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02001108
1109 if (index == shell->workspaces.current)
1110 return;
1111
1112 /* Don't change workspace when there is any fullscreen surfaces. */
Jason Ekstranda7af7042013-10-12 22:38:11 -05001113 if (!wl_list_empty(&shell->fullscreen_layer.view_list))
Jonas Ådahle3cddce2012-06-13 00:01:22 +02001114 return;
1115
Jonas Ådahle3cddce2012-06-13 00:01:22 +02001116 from = get_current_workspace(shell);
1117 to = get_workspace(shell, index);
1118
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001119 if (shell->workspaces.anim_from == to &&
1120 shell->workspaces.anim_to == from) {
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001121 restore_focus_state(shell, to);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001122 reverse_workspace_change_animation(shell, index, from, to);
Jonas Ådahle9d22502012-08-29 22:13:01 +02001123 broadcast_current_workspace_state(shell);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001124 return;
1125 }
Jonas Ådahle3cddce2012-06-13 00:01:22 +02001126
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001127 if (shell->workspaces.anim_to != NULL)
1128 finish_workspace_change_animation(shell,
1129 shell->workspaces.anim_from,
1130 shell->workspaces.anim_to);
1131
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001132 restore_focus_state(shell, to);
Jonas Ådahl04769742012-06-13 00:01:24 +02001133
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01001134 if (shell->focus_animation_type != ANIMATION_NONE) {
1135 wl_list_for_each(state, &from->focus_list, link)
1136 if (state->keyboard_focus)
1137 animate_focus_change(shell, from,
1138 get_default_view(state->keyboard_focus), NULL);
1139
1140 wl_list_for_each(state, &to->focus_list, link)
1141 if (state->keyboard_focus)
1142 animate_focus_change(shell, to,
1143 NULL, get_default_view(state->keyboard_focus));
1144 }
1145
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001146 if (workspace_is_empty(to) && workspace_is_empty(from))
1147 update_workspace(shell, index, from, to);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001148 else
1149 animate_workspace_change(shell, index, from, to);
Jonas Ådahle9d22502012-08-29 22:13:01 +02001150
1151 broadcast_current_workspace_state(shell);
Pekka Paalanene955f1e2011-12-07 11:49:52 +02001152}
1153
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001154static bool
1155workspace_has_only(struct workspace *ws, struct weston_surface *surface)
1156{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001157 struct wl_list *list = &ws->layer.view_list;
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001158 struct wl_list *e;
1159
1160 if (wl_list_empty(list))
1161 return false;
1162
1163 e = list->next;
1164
1165 if (e->next != list)
1166 return false;
1167
Jason Ekstranda7af7042013-10-12 22:38:11 -05001168 return container_of(e, struct weston_view, layer_link)->surface == surface;
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001169}
1170
1171static void
Philip Withnall659163d2013-11-25 18:01:36 +00001172move_surface_to_workspace(struct desktop_shell *shell,
1173 struct shell_surface *shsurf,
1174 uint32_t workspace)
Jonas Ådahle9d22502012-08-29 22:13:01 +02001175{
1176 struct workspace *from;
1177 struct workspace *to;
1178 struct weston_seat *seat;
Pekka Paalanen01388e22013-04-25 13:57:44 +03001179 struct weston_surface *focus;
Philip Withnall659163d2013-11-25 18:01:36 +00001180 struct weston_view *view;
Jonas Ådahle9d22502012-08-29 22:13:01 +02001181
1182 if (workspace == shell->workspaces.current)
1183 return;
1184
Philip Withnall659163d2013-11-25 18:01:36 +00001185 view = get_default_view(shsurf->surface);
1186 if (!view)
1187 return;
1188
1189 assert(weston_surface_get_main_surface(view->surface) == view->surface);
1190
Philipp Brüschweiler067abf62012-09-01 16:03:05 +02001191 if (workspace >= shell->workspaces.num)
1192 workspace = shell->workspaces.num - 1;
1193
Jonas Ådahle9d22502012-08-29 22:13:01 +02001194 from = get_current_workspace(shell);
1195 to = get_workspace(shell, workspace);
1196
Jason Ekstranda7af7042013-10-12 22:38:11 -05001197 wl_list_remove(&view->layer_link);
1198 wl_list_insert(&to->layer.view_list, &view->layer_link);
Jonas Ådahle9d22502012-08-29 22:13:01 +02001199
Philip Withnall648a4dd2013-11-25 18:01:44 +00001200 shell_surface_update_child_surface_layers(shsurf);
1201
Jason Ekstranda7af7042013-10-12 22:38:11 -05001202 drop_focus_state(shell, from, view->surface);
Pekka Paalanen01388e22013-04-25 13:57:44 +03001203 wl_list_for_each(seat, &shell->compositor->seat_list, link) {
1204 if (!seat->keyboard)
1205 continue;
1206
1207 focus = weston_surface_get_main_surface(seat->keyboard->focus);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001208 if (focus == view->surface)
Kristian Høgsberge3148752013-05-06 23:19:49 -04001209 weston_keyboard_set_focus(seat->keyboard, NULL);
Pekka Paalanen01388e22013-04-25 13:57:44 +03001210 }
Jonas Ådahle9d22502012-08-29 22:13:01 +02001211
Jason Ekstranda7af7042013-10-12 22:38:11 -05001212 weston_view_damage_below(view);
Jonas Ådahle9d22502012-08-29 22:13:01 +02001213}
1214
1215static void
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001216take_surface_to_workspace_by_seat(struct desktop_shell *shell,
Kristian Høgsberge3148752013-05-06 23:19:49 -04001217 struct weston_seat *seat,
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001218 unsigned int index)
1219{
Pekka Paalanen01388e22013-04-25 13:57:44 +03001220 struct weston_surface *surface;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001221 struct weston_view *view;
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001222 struct shell_surface *shsurf;
1223 struct workspace *from;
1224 struct workspace *to;
Jonas Ådahl8538b222012-08-29 22:13:03 +02001225 struct focus_state *state;
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001226
Pekka Paalanen01388e22013-04-25 13:57:44 +03001227 surface = weston_surface_get_main_surface(seat->keyboard->focus);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001228 view = get_default_view(surface);
1229 if (view == NULL ||
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01001230 index == shell->workspaces.current ||
1231 is_focus_view(view))
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001232 return;
1233
1234 from = get_current_workspace(shell);
1235 to = get_workspace(shell, index);
1236
Jason Ekstranda7af7042013-10-12 22:38:11 -05001237 wl_list_remove(&view->layer_link);
1238 wl_list_insert(&to->layer.view_list, &view->layer_link);
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001239
Philip Withnall659163d2013-11-25 18:01:36 +00001240 shsurf = get_shell_surface(surface);
Philip Withnall648a4dd2013-11-25 18:01:44 +00001241 if (shsurf != NULL)
1242 shell_surface_update_child_surface_layers(shsurf);
Philip Withnall659163d2013-11-25 18:01:36 +00001243
Jonas Ådahle9d22502012-08-29 22:13:01 +02001244 replace_focus_state(shell, to, seat);
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001245 drop_focus_state(shell, from, surface);
1246
1247 if (shell->workspaces.anim_from == to &&
1248 shell->workspaces.anim_to == from) {
Jonas Ådahle9d22502012-08-29 22:13:01 +02001249 wl_list_remove(&to->layer.link);
1250 wl_list_insert(from->layer.link.prev, &to->layer.link);
1251
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001252 reverse_workspace_change_animation(shell, index, from, to);
Jonas Ådahle9d22502012-08-29 22:13:01 +02001253 broadcast_current_workspace_state(shell);
1254
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001255 return;
1256 }
1257
1258 if (shell->workspaces.anim_to != NULL)
1259 finish_workspace_change_animation(shell,
1260 shell->workspaces.anim_from,
1261 shell->workspaces.anim_to);
1262
1263 if (workspace_is_empty(from) &&
1264 workspace_has_only(to, surface))
1265 update_workspace(shell, index, from, to);
1266 else {
Philip Withnall2c3849b2013-11-25 18:01:45 +00001267 if (shsurf != NULL &&
1268 wl_list_empty(&shsurf->workspace_transform.link))
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001269 wl_list_insert(&shell->workspaces.anim_sticky_list,
1270 &shsurf->workspace_transform.link);
1271
1272 animate_workspace_change(shell, index, from, to);
1273 }
Jonas Ådahle9d22502012-08-29 22:13:01 +02001274
1275 broadcast_current_workspace_state(shell);
Jonas Ådahl8538b222012-08-29 22:13:03 +02001276
1277 state = ensure_focus_state(shell, seat);
1278 if (state != NULL)
Kristian Høgsbergd500bf12014-01-22 12:25:20 -08001279 focus_state_set_focus(state, surface);
Jonas Ådahle9d22502012-08-29 22:13:01 +02001280}
1281
1282static void
1283workspace_manager_move_surface(struct wl_client *client,
1284 struct wl_resource *resource,
1285 struct wl_resource *surface_resource,
1286 uint32_t workspace)
1287{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05001288 struct desktop_shell *shell = wl_resource_get_user_data(resource);
Jonas Ådahle9d22502012-08-29 22:13:01 +02001289 struct weston_surface *surface =
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05001290 wl_resource_get_user_data(surface_resource);
Pekka Paalanen01388e22013-04-25 13:57:44 +03001291 struct weston_surface *main_surface;
Philip Withnall659163d2013-11-25 18:01:36 +00001292 struct shell_surface *shell_surface;
Jonas Ådahle9d22502012-08-29 22:13:01 +02001293
Pekka Paalanen01388e22013-04-25 13:57:44 +03001294 main_surface = weston_surface_get_main_surface(surface);
Philip Withnall659163d2013-11-25 18:01:36 +00001295 shell_surface = get_shell_surface(main_surface);
1296 if (shell_surface == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001297 return;
Philip Withnall659163d2013-11-25 18:01:36 +00001298
1299 move_surface_to_workspace(shell, shell_surface, workspace);
Jonas Ådahle9d22502012-08-29 22:13:01 +02001300}
1301
1302static const struct workspace_manager_interface workspace_manager_implementation = {
1303 workspace_manager_move_surface,
1304};
1305
1306static void
1307unbind_resource(struct wl_resource *resource)
1308{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05001309 wl_list_remove(wl_resource_get_link(resource));
Jonas Ådahle9d22502012-08-29 22:13:01 +02001310}
1311
1312static void
1313bind_workspace_manager(struct wl_client *client,
1314 void *data, uint32_t version, uint32_t id)
1315{
1316 struct desktop_shell *shell = data;
1317 struct wl_resource *resource;
1318
Jason Ekstranda85118c2013-06-27 20:17:02 -05001319 resource = wl_resource_create(client,
1320 &workspace_manager_interface, 1, id);
Jonas Ådahle9d22502012-08-29 22:13:01 +02001321
1322 if (resource == NULL) {
1323 weston_log("couldn't add workspace manager object");
1324 return;
1325 }
1326
Jason Ekstranda85118c2013-06-27 20:17:02 -05001327 wl_resource_set_implementation(resource,
1328 &workspace_manager_implementation,
1329 shell, unbind_resource);
Jason Ekstrand651f00e2013-06-14 10:07:54 -05001330 wl_list_insert(&shell->workspaces.client_list,
1331 wl_resource_get_link(resource));
Jonas Ådahle9d22502012-08-29 22:13:01 +02001332
1333 workspace_manager_send_state(resource,
1334 shell->workspaces.current,
1335 shell->workspaces.num);
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001336}
1337
Pekka Paalanen56cdea92011-11-23 16:14:12 +02001338static void
Rusty Lynch1084da52013-08-15 09:10:08 -07001339touch_move_grab_down(struct weston_touch_grab *grab, uint32_t time,
1340 int touch_id, wl_fixed_t sx, wl_fixed_t sy)
1341{
1342}
1343
1344static void
1345touch_move_grab_up(struct weston_touch_grab *grab, uint32_t time, int touch_id)
1346{
Jonas Ådahl1c6e63e2013-10-25 23:18:04 +02001347 struct weston_touch_move_grab *move =
1348 (struct weston_touch_move_grab *) container_of(
1349 grab, struct shell_touch_grab, grab);
Neil Robertse14aa4f2013-10-03 16:43:07 +01001350
Kristian Høgsberg8e80a312014-01-17 15:18:10 -08001351 if (touch_id == 0)
1352 move->active = 0;
1353
Jonas Ådahl9484b692013-12-02 22:05:03 +01001354 if (grab->touch->num_tp == 0) {
Jonas Ådahl1c6e63e2013-10-25 23:18:04 +02001355 shell_touch_grab_end(&move->base);
1356 free(move);
1357 }
Rusty Lynch1084da52013-08-15 09:10:08 -07001358}
1359
1360static void
1361touch_move_grab_motion(struct weston_touch_grab *grab, uint32_t time,
1362 int touch_id, wl_fixed_t sx, wl_fixed_t sy)
1363{
1364 struct weston_touch_move_grab *move = (struct weston_touch_move_grab *) grab;
1365 struct shell_surface *shsurf = move->base.shsurf;
1366 struct weston_surface *es;
1367 int dx = wl_fixed_to_int(grab->touch->grab_x + move->dx);
1368 int dy = wl_fixed_to_int(grab->touch->grab_y + move->dy);
1369
Kristian Høgsberg8e80a312014-01-17 15:18:10 -08001370 if (!shsurf || !move->active)
Rusty Lynch1084da52013-08-15 09:10:08 -07001371 return;
1372
1373 es = shsurf->surface;
1374
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001375 weston_view_set_position(shsurf->view, dx, dy);
Rusty Lynch1084da52013-08-15 09:10:08 -07001376
1377 weston_compositor_schedule_repaint(es->compositor);
1378}
1379
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02001380static void
1381touch_move_grab_cancel(struct weston_touch_grab *grab)
1382{
1383 struct weston_touch_move_grab *move =
1384 (struct weston_touch_move_grab *) container_of(
1385 grab, struct shell_touch_grab, grab);
1386
1387 shell_touch_grab_end(&move->base);
1388 free(move);
1389}
1390
Rusty Lynch1084da52013-08-15 09:10:08 -07001391static const struct weston_touch_grab_interface touch_move_grab_interface = {
1392 touch_move_grab_down,
1393 touch_move_grab_up,
1394 touch_move_grab_motion,
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02001395 touch_move_grab_cancel,
Rusty Lynch1084da52013-08-15 09:10:08 -07001396};
1397
1398static int
1399surface_touch_move(struct shell_surface *shsurf, struct weston_seat *seat)
1400{
1401 struct weston_touch_move_grab *move;
1402
1403 if (!shsurf)
1404 return -1;
1405
Rafael Antognolli03b16592013-12-03 15:35:42 -02001406 if (shsurf->state.fullscreen)
Rusty Lynch1084da52013-08-15 09:10:08 -07001407 return 0;
Kristian Høgsbergc85f1d42013-10-24 16:52:00 -07001408 if (shsurf->grabbed)
1409 return 0;
Rusty Lynch1084da52013-08-15 09:10:08 -07001410
1411 move = malloc(sizeof *move);
1412 if (!move)
1413 return -1;
1414
Kristian Høgsberg8e80a312014-01-17 15:18:10 -08001415 move->active = 1;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001416 move->dx = wl_fixed_from_double(shsurf->view->geometry.x) -
Rusty Lynch1084da52013-08-15 09:10:08 -07001417 seat->touch->grab_x;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001418 move->dy = wl_fixed_from_double(shsurf->view->geometry.y) -
Rusty Lynch1084da52013-08-15 09:10:08 -07001419 seat->touch->grab_y;
1420
1421 shell_touch_grab_start(&move->base, &touch_move_grab_interface, shsurf,
1422 seat->touch);
1423
1424 return 0;
1425}
1426
1427static void
Kristian Høgsberg6848c252013-05-08 22:02:59 -04001428noop_grab_focus(struct weston_pointer_grab *grab)
Kristian Høgsberg9ddb8262012-01-04 21:30:29 -05001429{
Kristian Høgsberg9ddb8262012-01-04 21:30:29 -05001430}
1431
1432static void
Giulio Camuffo1959ab82013-11-14 23:42:52 +01001433move_grab_motion(struct weston_pointer_grab *grab, uint32_t time,
1434 wl_fixed_t x, wl_fixed_t y)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001435{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001436 struct weston_move_grab *move = (struct weston_move_grab *) grab;
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001437 struct weston_pointer *pointer = grab->pointer;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03001438 struct shell_surface *shsurf = move->base.shsurf;
Giulio Camuffo1959ab82013-11-14 23:42:52 +01001439 int dx, dy;
1440
1441 weston_pointer_move(pointer, x, y);
1442 dx = wl_fixed_to_int(pointer->x + move->dx);
1443 dy = wl_fixed_to_int(pointer->y + move->dy);
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03001444
1445 if (!shsurf)
1446 return;
1447
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001448 weston_view_set_position(shsurf->view, dx, dy);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001449
Jason Ekstranda7af7042013-10-12 22:38:11 -05001450 weston_compositor_schedule_repaint(shsurf->surface->compositor);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001451}
1452
1453static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001454move_grab_button(struct weston_pointer_grab *grab,
Daniel Stone4dbadb12012-05-30 16:31:51 +01001455 uint32_t time, uint32_t button, uint32_t state_w)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001456{
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03001457 struct shell_grab *shell_grab = container_of(grab, struct shell_grab,
1458 grab);
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001459 struct weston_pointer *pointer = grab->pointer;
Daniel Stone4dbadb12012-05-30 16:31:51 +01001460 enum wl_pointer_button_state state = state_w;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001461
Daniel Stone4dbadb12012-05-30 16:31:51 +01001462 if (pointer->button_count == 0 &&
1463 state == WL_POINTER_BUTTON_STATE_RELEASED) {
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001464 shell_grab_end(shell_grab);
Kristian Høgsberg9ddb8262012-01-04 21:30:29 -05001465 free(grab);
1466 }
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001467}
1468
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02001469static void
1470move_grab_cancel(struct weston_pointer_grab *grab)
1471{
1472 struct shell_grab *shell_grab =
1473 container_of(grab, struct shell_grab, grab);
1474
1475 shell_grab_end(shell_grab);
1476 free(grab);
1477}
1478
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001479static const struct weston_pointer_grab_interface move_grab_interface = {
Kristian Høgsberg9ddb8262012-01-04 21:30:29 -05001480 noop_grab_focus,
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001481 move_grab_motion,
1482 move_grab_button,
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02001483 move_grab_cancel,
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001484};
1485
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001486static int
Kristian Høgsberge3148752013-05-06 23:19:49 -04001487surface_move(struct shell_surface *shsurf, struct weston_seat *seat)
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001488{
1489 struct weston_move_grab *move;
1490
1491 if (!shsurf)
1492 return -1;
1493
Kristian Høgsbergc85f1d42013-10-24 16:52:00 -07001494 if (shsurf->grabbed)
1495 return 0;
Ricardo Vieiraf1c3bd82014-01-18 16:30:50 +00001496 if (shsurf->state.fullscreen || shsurf->state.maximized)
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001497 return 0;
1498
1499 move = malloc(sizeof *move);
1500 if (!move)
1501 return -1;
1502
Jason Ekstranda7af7042013-10-12 22:38:11 -05001503 move->dx = wl_fixed_from_double(shsurf->view->geometry.x) -
Kristian Høgsberge3148752013-05-06 23:19:49 -04001504 seat->pointer->grab_x;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001505 move->dy = wl_fixed_from_double(shsurf->view->geometry.y) -
Kristian Høgsberge3148752013-05-06 23:19:49 -04001506 seat->pointer->grab_y;
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001507
1508 shell_grab_start(&move->base, &move_grab_interface, shsurf,
Kristian Høgsberge3148752013-05-06 23:19:49 -04001509 seat->pointer, DESKTOP_SHELL_CURSOR_MOVE);
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001510
1511 return 0;
1512}
1513
1514static void
Rafael Antognollie2a34552013-12-03 15:35:45 -02001515common_surface_move(struct wl_resource *resource,
1516 struct wl_resource *seat_resource, uint32_t serial)
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001517{
Jason Ekstrand44a38632013-06-14 10:08:00 -05001518 struct weston_seat *seat = wl_resource_get_user_data(seat_resource);
Jason Ekstrand651f00e2013-06-14 10:07:54 -05001519 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
Giulio Camuffo61da3fc2013-04-25 13:57:45 +03001520 struct weston_surface *surface;
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001521
Kristian Høgsberge1b655d2013-08-28 23:16:20 -07001522 if (seat->pointer &&
Kristian Høgsberg70f29012014-01-09 15:43:17 -08001523 seat->pointer->focus &&
Kristian Høgsberge1b655d2013-08-28 23:16:20 -07001524 seat->pointer->button_count > 0 &&
1525 seat->pointer->grab_serial == serial) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001526 surface = weston_surface_get_main_surface(seat->pointer->focus->surface);
U. Artie Eoffcf5737a2014-01-17 10:08:25 -08001527 if ((surface == shsurf->surface) &&
Rusty Lynch1084da52013-08-15 09:10:08 -07001528 (surface_move(shsurf, seat) < 0))
1529 wl_resource_post_no_memory(resource);
Kristian Høgsberge1b655d2013-08-28 23:16:20 -07001530 } else if (seat->touch &&
Kristian Høgsberg70f29012014-01-09 15:43:17 -08001531 seat->touch->focus &&
Kristian Høgsberge1b655d2013-08-28 23:16:20 -07001532 seat->touch->grab_serial == serial) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001533 surface = weston_surface_get_main_surface(seat->touch->focus->surface);
U. Artie Eoffcf5737a2014-01-17 10:08:25 -08001534 if ((surface == shsurf->surface) &&
Rusty Lynch1084da52013-08-15 09:10:08 -07001535 (surface_touch_move(shsurf, seat) < 0))
1536 wl_resource_post_no_memory(resource);
1537 }
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001538}
1539
Rafael Antognollie2a34552013-12-03 15:35:45 -02001540static void
1541shell_surface_move(struct wl_client *client, struct wl_resource *resource,
1542 struct wl_resource *seat_resource, uint32_t serial)
1543{
1544 common_surface_move(resource, seat_resource, serial);
1545}
1546
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001547struct weston_resize_grab {
1548 struct shell_grab base;
1549 uint32_t edges;
1550 int32_t width, height;
1551};
1552
1553static void
Giulio Camuffo1959ab82013-11-14 23:42:52 +01001554resize_grab_motion(struct weston_pointer_grab *grab, uint32_t time,
1555 wl_fixed_t x, wl_fixed_t y)
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001556{
1557 struct weston_resize_grab *resize = (struct weston_resize_grab *) grab;
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001558 struct weston_pointer *pointer = grab->pointer;
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001559 struct shell_surface *shsurf = resize->base.shsurf;
1560 int32_t width, height;
1561 wl_fixed_t from_x, from_y;
1562 wl_fixed_t to_x, to_y;
1563
Giulio Camuffo1959ab82013-11-14 23:42:52 +01001564 weston_pointer_move(pointer, x, y);
1565
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001566 if (!shsurf)
1567 return;
1568
Jason Ekstranda7af7042013-10-12 22:38:11 -05001569 weston_view_from_global_fixed(shsurf->view,
1570 pointer->grab_x, pointer->grab_y,
1571 &from_x, &from_y);
1572 weston_view_from_global_fixed(shsurf->view,
1573 pointer->x, pointer->y, &to_x, &to_y);
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001574
1575 width = resize->width;
1576 if (resize->edges & WL_SHELL_SURFACE_RESIZE_LEFT) {
1577 width += wl_fixed_to_int(from_x - to_x);
1578 } else if (resize->edges & WL_SHELL_SURFACE_RESIZE_RIGHT) {
1579 width += wl_fixed_to_int(to_x - from_x);
1580 }
1581
1582 height = resize->height;
1583 if (resize->edges & WL_SHELL_SURFACE_RESIZE_TOP) {
1584 height += wl_fixed_to_int(from_y - to_y);
1585 } else if (resize->edges & WL_SHELL_SURFACE_RESIZE_BOTTOM) {
1586 height += wl_fixed_to_int(to_y - from_y);
1587 }
1588
1589 shsurf->client->send_configure(shsurf->surface,
1590 resize->edges, width, height);
1591}
1592
1593static void
1594send_configure(struct weston_surface *surface,
1595 uint32_t edges, int32_t width, int32_t height)
1596{
1597 struct shell_surface *shsurf = get_shell_surface(surface);
1598
U. Artie Eoffcf5737a2014-01-17 10:08:25 -08001599 assert(shsurf);
1600
Jason Ekstrand651f00e2013-06-14 10:07:54 -05001601 wl_shell_surface_send_configure(shsurf->resource,
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001602 edges, width, height);
1603}
1604
1605static const struct weston_shell_client shell_client = {
1606 send_configure
1607};
1608
1609static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001610resize_grab_button(struct weston_pointer_grab *grab,
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001611 uint32_t time, uint32_t button, uint32_t state_w)
1612{
1613 struct weston_resize_grab *resize = (struct weston_resize_grab *) grab;
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001614 struct weston_pointer *pointer = grab->pointer;
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001615 enum wl_pointer_button_state state = state_w;
1616
1617 if (pointer->button_count == 0 &&
1618 state == WL_POINTER_BUTTON_STATE_RELEASED) {
1619 shell_grab_end(&resize->base);
1620 free(grab);
1621 }
1622}
1623
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02001624static void
1625resize_grab_cancel(struct weston_pointer_grab *grab)
1626{
1627 struct weston_resize_grab *resize = (struct weston_resize_grab *) grab;
1628
1629 shell_grab_end(&resize->base);
1630 free(grab);
1631}
1632
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001633static const struct weston_pointer_grab_interface resize_grab_interface = {
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001634 noop_grab_focus,
1635 resize_grab_motion,
1636 resize_grab_button,
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02001637 resize_grab_cancel,
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001638};
1639
Giulio Camuffob8366642013-04-25 13:57:46 +03001640/*
1641 * Returns the bounding box of a surface and all its sub-surfaces,
1642 * in the surface coordinates system. */
1643static void
1644surface_subsurfaces_boundingbox(struct weston_surface *surface, int32_t *x,
1645 int32_t *y, int32_t *w, int32_t *h) {
1646 pixman_region32_t region;
1647 pixman_box32_t *box;
1648 struct weston_subsurface *subsurface;
1649
1650 pixman_region32_init_rect(&region, 0, 0,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001651 surface->width,
1652 surface->height);
Giulio Camuffob8366642013-04-25 13:57:46 +03001653
1654 wl_list_for_each(subsurface, &surface->subsurface_list, parent_link) {
1655 pixman_region32_union_rect(&region, &region,
1656 subsurface->position.x,
1657 subsurface->position.y,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001658 subsurface->surface->width,
1659 subsurface->surface->height);
Giulio Camuffob8366642013-04-25 13:57:46 +03001660 }
1661
1662 box = pixman_region32_extents(&region);
1663 if (x)
1664 *x = box->x1;
1665 if (y)
1666 *y = box->y1;
1667 if (w)
1668 *w = box->x2 - box->x1;
1669 if (h)
1670 *h = box->y2 - box->y1;
1671
1672 pixman_region32_fini(&region);
1673}
1674
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001675static int
1676surface_resize(struct shell_surface *shsurf,
Kristian Høgsberge3148752013-05-06 23:19:49 -04001677 struct weston_seat *seat, uint32_t edges)
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001678{
1679 struct weston_resize_grab *resize;
1680
Rafael Antognolli03b16592013-12-03 15:35:42 -02001681 if (shsurf->state.fullscreen || shsurf->state.maximized)
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001682 return 0;
1683
1684 if (edges == 0 || edges > 15 ||
1685 (edges & 3) == 3 || (edges & 12) == 12)
1686 return 0;
1687
1688 resize = malloc(sizeof *resize);
1689 if (!resize)
1690 return -1;
1691
1692 resize->edges = edges;
Giulio Camuffob8366642013-04-25 13:57:46 +03001693 surface_subsurfaces_boundingbox(shsurf->surface, NULL, NULL,
1694 &resize->width, &resize->height);
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001695
Kristian Høgsberg44cd1962014-02-05 21:36:04 -08001696 shsurf->resize_edges = edges;
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001697 shell_grab_start(&resize->base, &resize_grab_interface, shsurf,
Kristian Høgsberge3148752013-05-06 23:19:49 -04001698 seat->pointer, edges);
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001699
1700 return 0;
1701}
1702
1703static void
Rafael Antognollie2a34552013-12-03 15:35:45 -02001704common_surface_resize(struct wl_resource *resource,
1705 struct wl_resource *seat_resource, uint32_t serial,
1706 uint32_t edges)
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001707{
Jason Ekstrand44a38632013-06-14 10:08:00 -05001708 struct weston_seat *seat = wl_resource_get_user_data(seat_resource);
Jason Ekstrand651f00e2013-06-14 10:07:54 -05001709 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
Giulio Camuffo61da3fc2013-04-25 13:57:45 +03001710 struct weston_surface *surface;
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001711
Rafael Antognolli03b16592013-12-03 15:35:42 -02001712 if (shsurf->state.fullscreen)
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001713 return;
1714
Kristian Høgsberge3148752013-05-06 23:19:49 -04001715 if (seat->pointer->button_count == 0 ||
1716 seat->pointer->grab_serial != serial ||
Kristian Høgsberg70f29012014-01-09 15:43:17 -08001717 seat->pointer->focus == NULL)
1718 return;
1719
1720 surface = weston_surface_get_main_surface(seat->pointer->focus->surface);
1721 if (surface != shsurf->surface)
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001722 return;
1723
Kristian Høgsberge3148752013-05-06 23:19:49 -04001724 if (surface_resize(shsurf, seat, edges) < 0)
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001725 wl_resource_post_no_memory(resource);
1726}
1727
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001728static void
Rafael Antognollie2a34552013-12-03 15:35:45 -02001729shell_surface_resize(struct wl_client *client, struct wl_resource *resource,
1730 struct wl_resource *seat_resource, uint32_t serial,
1731 uint32_t edges)
1732{
1733 common_surface_resize(resource, seat_resource, serial, edges);
1734}
1735
1736static void
Kristian Høgsberg6848c252013-05-08 22:02:59 -04001737busy_cursor_grab_focus(struct weston_pointer_grab *base)
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001738{
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001739 struct shell_grab *grab = (struct shell_grab *) base;
Kristian Høgsberg6848c252013-05-08 22:02:59 -04001740 struct weston_pointer *pointer = base->pointer;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001741 struct weston_view *view;
Kristian Høgsberg6848c252013-05-08 22:02:59 -04001742 wl_fixed_t sx, sy;
1743
Jason Ekstranda7af7042013-10-12 22:38:11 -05001744 view = weston_compositor_pick_view(pointer->seat->compositor,
1745 pointer->x, pointer->y,
1746 &sx, &sy);
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001747
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08001748 if (!grab->shsurf || grab->shsurf->surface != view->surface) {
1749 shell_grab_end(grab);
1750 free(grab);
1751 }
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001752}
1753
1754static void
Giulio Camuffo1959ab82013-11-14 23:42:52 +01001755busy_cursor_grab_motion(struct weston_pointer_grab *grab, uint32_t time,
1756 wl_fixed_t x, wl_fixed_t y)
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001757{
Giulio Camuffo1959ab82013-11-14 23:42:52 +01001758 weston_pointer_move(grab->pointer, x, y);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001759}
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001760
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001761static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001762busy_cursor_grab_button(struct weston_pointer_grab *base,
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001763 uint32_t time, uint32_t button, uint32_t state)
1764{
Kristian Høgsbergbbe98392012-08-01 00:20:21 -04001765 struct shell_grab *grab = (struct shell_grab *) base;
Kristian Høgsberge122b7b2013-05-08 16:47:00 -04001766 struct shell_surface *shsurf = grab->shsurf;
Kristian Høgsberge3148752013-05-06 23:19:49 -04001767 struct weston_seat *seat = grab->grab.pointer->seat;
Kristian Høgsbergbbe98392012-08-01 00:20:21 -04001768
Kristian Høgsbergbbe98392012-08-01 00:20:21 -04001769 if (shsurf && button == BTN_LEFT && state) {
1770 activate(shsurf->shell, shsurf->surface, seat);
1771 surface_move(shsurf, seat);
Kristian Høgsberg0c369032013-02-14 21:31:44 -05001772 } else if (shsurf && button == BTN_RIGHT && state) {
1773 activate(shsurf->shell, shsurf->surface, seat);
Kristian Høgsberge3148752013-05-06 23:19:49 -04001774 surface_rotate(shsurf, seat);
Kristian Høgsbergbbe98392012-08-01 00:20:21 -04001775 }
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001776}
1777
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02001778static void
1779busy_cursor_grab_cancel(struct weston_pointer_grab *base)
1780{
1781 struct shell_grab *grab = (struct shell_grab *) base;
1782
1783 shell_grab_end(grab);
1784 free(grab);
1785}
1786
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001787static const struct weston_pointer_grab_interface busy_cursor_grab_interface = {
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001788 busy_cursor_grab_focus,
1789 busy_cursor_grab_motion,
1790 busy_cursor_grab_button,
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02001791 busy_cursor_grab_cancel,
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001792};
1793
1794static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001795set_busy_cursor(struct shell_surface *shsurf, struct weston_pointer *pointer)
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001796{
1797 struct shell_grab *grab;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001798
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08001799 if (pointer->grab->interface == &busy_cursor_grab_interface)
1800 return;
1801
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001802 grab = malloc(sizeof *grab);
1803 if (!grab)
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001804 return;
1805
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001806 shell_grab_start(grab, &busy_cursor_grab_interface, shsurf, pointer,
1807 DESKTOP_SHELL_CURSOR_BUSY);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001808}
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001809
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001810static void
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08001811end_busy_cursor(struct weston_compositor *compositor, struct wl_client *client)
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001812{
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08001813 struct shell_grab *grab;
1814 struct weston_seat *seat;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001815
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08001816 wl_list_for_each(seat, &compositor->seat_list, link) {
1817 if (seat->pointer == NULL)
1818 continue;
1819
1820 grab = (struct shell_grab *) seat->pointer->grab;
1821 if (grab->grab.interface == &busy_cursor_grab_interface &&
1822 wl_resource_get_client(grab->shsurf->resource) == client) {
1823 shell_grab_end(grab);
1824 free(grab);
1825 }
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001826 }
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001827}
1828
Scott Moreau9521d5e2012-04-19 13:06:17 -06001829static void
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08001830handle_shell_client_destroy(struct wl_listener *listener, void *data);
1831
1832static int
1833xdg_ping_timeout_handler(void *data)
1834{
1835 struct shell_client *sc = data;
1836 struct weston_seat *seat;
1837 struct shell_surface *shsurf;
1838
1839 /* Client is not responding */
1840 sc->unresponsive = 1;
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08001841 wl_list_for_each(seat, &sc->shell->compositor->seat_list, link) {
1842 if (seat->pointer == NULL || seat->pointer->focus == NULL)
1843 continue;
1844 if (seat->pointer->focus->surface->resource == NULL)
1845 continue;
1846
1847 shsurf = get_shell_surface(seat->pointer->focus->surface);
1848 if (shsurf &&
1849 wl_resource_get_client(shsurf->resource) == sc->client)
1850 set_busy_cursor(shsurf, seat->pointer);
1851 }
1852
1853 return 1;
1854}
1855
1856static void
1857handle_xdg_ping(struct shell_surface *shsurf, uint32_t serial)
1858{
1859 struct weston_compositor *compositor = shsurf->shell->compositor;
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08001860 struct wl_client *client = wl_resource_get_client(shsurf->resource);
1861 struct shell_client *sc;
1862 struct wl_event_loop *loop;
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08001863 static const int ping_timeout = 200;
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08001864
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08001865 sc = get_shell_client(client);
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08001866 if (sc->unresponsive) {
1867 xdg_ping_timeout_handler(sc);
1868 return;
1869 }
1870
1871 sc->ping_serial = serial;
1872 loop = wl_display_get_event_loop(compositor->wl_display);
1873 if (sc->ping_timer == NULL)
1874 sc->ping_timer =
1875 wl_event_loop_add_timer(loop,
1876 xdg_ping_timeout_handler, sc);
1877 if (sc->ping_timer == NULL)
1878 return;
1879
1880 wl_event_source_timer_update(sc->ping_timer, ping_timeout);
1881
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08001882 if (shell_surface_is_xdg_surface(shsurf) ||
1883 shell_surface_is_xdg_popup(shsurf))
1884 xdg_shell_send_ping(sc->resource, serial);
1885 else if (shell_surface_is_wl_shell_surface(shsurf))
1886 wl_shell_surface_send_ping(shsurf->resource, serial);
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08001887}
1888
Scott Moreauff1db4a2012-04-17 19:06:18 -06001889static void
1890ping_handler(struct weston_surface *surface, uint32_t serial)
1891{
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001892 struct shell_surface *shsurf = get_shell_surface(surface);
Scott Moreauff1db4a2012-04-17 19:06:18 -06001893
1894 if (!shsurf)
1895 return;
Jason Ekstrand651f00e2013-06-14 10:07:54 -05001896 if (!shsurf->resource)
Kristian Høgsbergca535c12012-04-21 23:20:07 -04001897 return;
Ander Conselvan de Oliveiraeac9a462012-07-16 14:15:48 +03001898 if (shsurf->surface == shsurf->shell->grab_surface)
1899 return;
1900
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08001901 handle_xdg_ping(shsurf, serial);
Scott Moreauff1db4a2012-04-17 19:06:18 -06001902}
1903
1904static void
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001905handle_pointer_focus(struct wl_listener *listener, void *data)
1906{
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001907 struct weston_pointer *pointer = data;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001908 struct weston_view *view = pointer->focus;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001909 struct weston_compositor *compositor;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001910 uint32_t serial;
1911
Jason Ekstranda7af7042013-10-12 22:38:11 -05001912 if (!view)
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001913 return;
1914
Jason Ekstranda7af7042013-10-12 22:38:11 -05001915 compositor = view->surface->compositor;
Kristian Høgsberge11ef642014-02-11 16:35:22 -08001916 serial = wl_display_next_serial(compositor->wl_display);
1917 ping_handler(view->surface, serial);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001918}
1919
1920static void
Kristian Høgsbergf4d2f232012-08-10 10:05:39 -04001921create_pointer_focus_listener(struct weston_seat *seat)
1922{
1923 struct wl_listener *listener;
1924
Kristian Høgsberge3148752013-05-06 23:19:49 -04001925 if (!seat->pointer)
Kristian Høgsbergf4d2f232012-08-10 10:05:39 -04001926 return;
1927
1928 listener = malloc(sizeof *listener);
1929 listener->notify = handle_pointer_focus;
Kristian Høgsberge3148752013-05-06 23:19:49 -04001930 wl_signal_add(&seat->pointer->focus_signal, listener);
Kristian Høgsbergf4d2f232012-08-10 10:05:39 -04001931}
1932
1933static void
Jasper St. Pierrefaf27a92013-12-09 17:36:28 -05001934shell_surface_lose_keyboard_focus(struct shell_surface *shsurf)
1935{
1936 if (--shsurf->focus_count == 0)
1937 if (shell_surface_is_xdg_surface(shsurf))
Jasper St. Pierreb223a722014-02-08 18:11:53 -05001938 xdg_surface_send_deactivated(shsurf->resource);
Jasper St. Pierrefaf27a92013-12-09 17:36:28 -05001939}
1940
1941static void
1942shell_surface_gain_keyboard_focus(struct shell_surface *shsurf)
1943{
1944 if (shsurf->focus_count++ == 0)
1945 if (shell_surface_is_xdg_surface(shsurf))
Jasper St. Pierreb223a722014-02-08 18:11:53 -05001946 xdg_surface_send_activated(shsurf->resource);
Jasper St. Pierrefaf27a92013-12-09 17:36:28 -05001947}
1948
1949static void
1950handle_keyboard_focus(struct wl_listener *listener, void *data)
1951{
1952 struct weston_keyboard *keyboard = data;
1953 struct shell_seat *seat = get_shell_seat(keyboard->seat);
1954
1955 if (seat->focused_surface) {
1956 struct shell_surface *shsurf = get_shell_surface(seat->focused_surface);
1957 if (shsurf)
1958 shell_surface_lose_keyboard_focus(shsurf);
1959 }
1960
1961 seat->focused_surface = keyboard->focus;
1962
1963 if (seat->focused_surface) {
1964 struct shell_surface *shsurf = get_shell_surface(seat->focused_surface);
1965 if (shsurf)
1966 shell_surface_gain_keyboard_focus(shsurf);
1967 }
1968}
1969
1970static void
1971create_keyboard_focus_listener(struct weston_seat *seat)
1972{
1973 struct wl_listener *listener;
1974
1975 if (!seat->keyboard)
1976 return;
1977
1978 listener = malloc(sizeof *listener);
1979 listener->notify = handle_keyboard_focus;
1980 wl_signal_add(&seat->keyboard->focus_signal, listener);
1981}
1982
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08001983static struct shell_client *
1984get_shell_client(struct wl_client *client)
Rafael Antognollie2a34552013-12-03 15:35:45 -02001985{
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08001986 struct wl_listener *listener;
Scott Moreauff1db4a2012-04-17 19:06:18 -06001987
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08001988 listener = wl_client_get_destroy_listener(client,
1989 handle_shell_client_destroy);
1990 if (listener == NULL)
1991 return NULL;
Kristian Høgsberg92374e12012-08-11 22:39:12 -04001992
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08001993 return container_of(listener, struct shell_client, destroy_listener);
Scott Moreauff1db4a2012-04-17 19:06:18 -06001994}
1995
Kristian Høgsberge7afd912012-05-02 09:47:44 -04001996static void
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08001997shell_client_pong(struct shell_client *sc, uint32_t serial)
Rafael Antognollie2a34552013-12-03 15:35:45 -02001998{
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08001999 if (sc->ping_serial != serial)
2000 return;
Rafael Antognollie2a34552013-12-03 15:35:45 -02002001
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08002002 sc->unresponsive = 0;
2003 end_busy_cursor(sc->shell->compositor, sc->client);
Rafael Antognollie2a34552013-12-03 15:35:45 -02002004
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08002005 if (sc->ping_timer) {
2006 wl_event_source_remove(sc->ping_timer);
2007 sc->ping_timer = NULL;
2008 }
2009
2010}
2011
2012static void
2013shell_surface_pong(struct wl_client *client,
2014 struct wl_resource *resource, uint32_t serial)
2015{
2016 struct shell_client *sc;
2017
2018 sc = get_shell_client(client);
2019 shell_client_pong(sc, serial);
Rafael Antognollie2a34552013-12-03 15:35:45 -02002020}
2021
2022static void
Giulio Camuffo62942ad2013-09-11 18:20:47 +02002023set_title(struct shell_surface *shsurf, const char *title)
2024{
2025 free(shsurf->title);
2026 shsurf->title = strdup(title);
2027}
2028
2029static void
Kristian Høgsberge7afd912012-05-02 09:47:44 -04002030shell_surface_set_title(struct wl_client *client,
2031 struct wl_resource *resource, const char *title)
2032{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05002033 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
Kristian Høgsberge7afd912012-05-02 09:47:44 -04002034
Giulio Camuffo62942ad2013-09-11 18:20:47 +02002035 set_title(shsurf, title);
Kristian Høgsberge7afd912012-05-02 09:47:44 -04002036}
2037
2038static void
2039shell_surface_set_class(struct wl_client *client,
2040 struct wl_resource *resource, const char *class)
2041{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05002042 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
Kristian Høgsberge7afd912012-05-02 09:47:44 -04002043
2044 free(shsurf->class);
2045 shsurf->class = strdup(class);
2046}
2047
Alex Wu4539b082012-03-01 12:57:46 +08002048static void
Alexander Larssonf82b6ca2013-05-28 16:23:39 +02002049restore_output_mode(struct weston_output *output)
2050{
Hardening57388e42013-09-18 23:56:36 +02002051 if (output->current_mode != output->original_mode ||
2052 (int32_t)output->current_scale != output->original_scale)
Alexander Larssonf82b6ca2013-05-28 16:23:39 +02002053 weston_output_switch_mode(output,
Hardening57388e42013-09-18 23:56:36 +02002054 output->original_mode,
2055 output->original_scale,
2056 WESTON_MODE_SWITCH_RESTORE_NATIVE);
Alexander Larssonf82b6ca2013-05-28 16:23:39 +02002057}
2058
2059static void
2060restore_all_output_modes(struct weston_compositor *compositor)
2061{
2062 struct weston_output *output;
2063
2064 wl_list_for_each(output, &compositor->output_list, link)
2065 restore_output_mode(output);
2066}
2067
Philip Withnallbecb77e2013-11-25 18:01:30 +00002068static int
2069get_output_panel_height(struct desktop_shell *shell,
2070 struct weston_output *output)
2071{
2072 struct weston_view *view;
2073 int panel_height = 0;
2074
2075 if (!output)
2076 return 0;
2077
2078 wl_list_for_each(view, &shell->panel_layer.view_list, layer_link) {
2079 if (view->surface->output == output) {
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06002080 panel_height = view->surface->height;
Philip Withnallbecb77e2013-11-25 18:01:30 +00002081 break;
2082 }
2083 }
2084
2085 return panel_height;
2086}
2087
Philip Withnall07926d92013-11-25 18:01:40 +00002088/* The surface will be inserted into the list immediately after the link
2089 * returned by this function (i.e. will be stacked immediately above the
2090 * returned link). */
2091static struct wl_list *
2092shell_surface_calculate_layer_link (struct shell_surface *shsurf)
2093{
2094 struct workspace *ws;
Kristian Høgsbergead52422014-01-01 13:51:52 -08002095 struct weston_view *parent;
Philip Withnall07926d92013-11-25 18:01:40 +00002096
2097 switch (shsurf->type) {
Kristian Høgsbergead52422014-01-01 13:51:52 -08002098 case SHELL_SURFACE_POPUP:
2099 case SHELL_SURFACE_TOPLEVEL:
Rafael Antognollied207b42013-12-03 15:35:43 -02002100 if (shsurf->state.fullscreen) {
Rafael Antognolli03b16592013-12-03 15:35:42 -02002101 return &shsurf->shell->fullscreen_layer.view_list;
Rafael Antognollied207b42013-12-03 15:35:43 -02002102 } else if (shsurf->parent) {
Kristian Høgsbergd55db692014-01-01 12:26:14 -08002103 /* Move the surface to its parent layer so
2104 * that surfaces which are transient for
2105 * fullscreen surfaces don't get hidden by the
2106 * fullscreen surfaces. */
Rafael Antognollied207b42013-12-03 15:35:43 -02002107
2108 /* TODO: Handle a parent with multiple views */
2109 parent = get_default_view(shsurf->parent);
2110 if (parent)
2111 return parent->layer_link.prev;
2112 }
Rafael Antognolli03b16592013-12-03 15:35:42 -02002113 break;
Philip Withnall07926d92013-11-25 18:01:40 +00002114
2115 case SHELL_SURFACE_XWAYLAND:
Kristian Høgsberg4804a302013-12-05 22:43:03 -08002116 return &shsurf->shell->fullscreen_layer.view_list;
2117
Philip Withnall07926d92013-11-25 18:01:40 +00002118 case SHELL_SURFACE_NONE:
2119 default:
2120 /* Go to the fallback, below. */
2121 break;
2122 }
2123
2124 /* Move the surface to a normal workspace layer so that surfaces
2125 * which were previously fullscreen or transient are no longer
2126 * rendered on top. */
2127 ws = get_current_workspace(shsurf->shell);
2128 return &ws->layer.view_list;
2129}
2130
Philip Withnall648a4dd2013-11-25 18:01:44 +00002131static void
2132shell_surface_update_child_surface_layers (struct shell_surface *shsurf)
2133{
2134 struct shell_surface *child;
2135
2136 /* Move the child layers to the same workspace as shsurf. They will be
2137 * stacked above shsurf. */
2138 wl_list_for_each_reverse(child, &shsurf->children_list, children_link) {
2139 if (shsurf->view->layer_link.prev != &child->view->layer_link) {
2140 weston_view_geometry_dirty(child->view);
2141 wl_list_remove(&child->view->layer_link);
2142 wl_list_insert(shsurf->view->layer_link.prev,
2143 &child->view->layer_link);
2144 weston_view_geometry_dirty(child->view);
2145 weston_surface_damage(child->surface);
2146
2147 /* Recurse. We don’t expect this to recurse very far (if
2148 * at all) because that would imply we have transient
2149 * (or popup) children of transient surfaces, which
2150 * would be unusual. */
2151 shell_surface_update_child_surface_layers(child);
2152 }
2153 }
2154}
2155
Philip Withnalle1d75ae2013-11-25 18:01:41 +00002156/* Update the surface’s layer. Mark both the old and new views as having dirty
Philip Withnall648a4dd2013-11-25 18:01:44 +00002157 * geometry to ensure the changes are redrawn.
2158 *
2159 * If any child surfaces exist and are mapped, ensure they’re in the same layer
2160 * as this surface. */
Philip Withnalle1d75ae2013-11-25 18:01:41 +00002161static void
2162shell_surface_update_layer(struct shell_surface *shsurf)
2163{
2164 struct wl_list *new_layer_link;
2165
2166 new_layer_link = shell_surface_calculate_layer_link(shsurf);
2167
2168 if (new_layer_link == &shsurf->view->layer_link)
2169 return;
2170
2171 weston_view_geometry_dirty(shsurf->view);
2172 wl_list_remove(&shsurf->view->layer_link);
2173 wl_list_insert(new_layer_link, &shsurf->view->layer_link);
2174 weston_view_geometry_dirty(shsurf->view);
2175 weston_surface_damage(shsurf->surface);
Philip Withnall648a4dd2013-11-25 18:01:44 +00002176
2177 shell_surface_update_child_surface_layers(shsurf);
Philip Withnalle1d75ae2013-11-25 18:01:41 +00002178}
2179
Alexander Larssonf82b6ca2013-05-28 16:23:39 +02002180static void
Philip Withnalldc4332f2013-11-25 18:01:38 +00002181shell_surface_set_parent(struct shell_surface *shsurf,
2182 struct weston_surface *parent)
2183{
2184 shsurf->parent = parent;
Philip Withnall648a4dd2013-11-25 18:01:44 +00002185
2186 wl_list_remove(&shsurf->children_link);
2187 wl_list_init(&shsurf->children_link);
2188
2189 /* Insert into the parent surface’s child list. */
2190 if (parent != NULL) {
2191 struct shell_surface *parent_shsurf = get_shell_surface(parent);
2192 if (parent_shsurf != NULL)
2193 wl_list_insert(&parent_shsurf->children_list,
2194 &shsurf->children_link);
2195 }
Philip Withnalldc4332f2013-11-25 18:01:38 +00002196}
2197
2198static void
Philip Withnall352e7ed2013-11-25 18:01:35 +00002199shell_surface_set_output(struct shell_surface *shsurf,
2200 struct weston_output *output)
2201{
2202 struct weston_surface *es = shsurf->surface;
2203
2204 /* get the default output, if the client set it as NULL
2205 check whether the ouput is available */
2206 if (output)
2207 shsurf->output = output;
2208 else if (es->output)
2209 shsurf->output = es->output;
2210 else
2211 shsurf->output = get_default_output(es->compositor);
2212}
2213
2214static void
Rafael Antognolli03b16592013-12-03 15:35:42 -02002215surface_clear_next_states(struct shell_surface *shsurf)
2216{
2217 shsurf->next_state.maximized = false;
2218 shsurf->next_state.fullscreen = false;
2219
2220 if ((shsurf->next_state.maximized != shsurf->state.maximized) ||
2221 (shsurf->next_state.fullscreen != shsurf->state.fullscreen))
2222 shsurf->state_changed = true;
2223}
2224
2225static void
Philip Withnallbecb77e2013-11-25 18:01:30 +00002226set_toplevel(struct shell_surface *shsurf)
2227{
Kristian Høgsberg41fbf6f2013-12-05 22:31:25 -08002228 shell_surface_set_parent(shsurf, NULL);
2229 surface_clear_next_states(shsurf);
Kristian Høgsbergc8f8dd82013-12-05 23:20:33 -08002230 shsurf->type = SHELL_SURFACE_TOPLEVEL;
Philip Withnall648a4dd2013-11-25 18:01:44 +00002231
2232 /* The layer_link is updated in set_surface_type(),
2233 * called from configure. */
Philip Withnallbecb77e2013-11-25 18:01:30 +00002234}
2235
2236static void
2237shell_surface_set_toplevel(struct wl_client *client,
2238 struct wl_resource *resource)
2239{
2240 struct shell_surface *surface = wl_resource_get_user_data(resource);
2241
2242 set_toplevel(surface);
2243}
2244
2245static void
2246set_transient(struct shell_surface *shsurf,
2247 struct weston_surface *parent, int x, int y, uint32_t flags)
2248{
Philip Withnalldc4332f2013-11-25 18:01:38 +00002249 assert(parent != NULL);
2250
Kristian Høgsberg9f7e3312014-01-02 22:40:37 -08002251 shell_surface_set_parent(shsurf, parent);
2252
2253 surface_clear_next_states(shsurf);
2254
Philip Withnallbecb77e2013-11-25 18:01:30 +00002255 shsurf->transient.x = x;
2256 shsurf->transient.y = y;
2257 shsurf->transient.flags = flags;
Philip Withnalldc4332f2013-11-25 18:01:38 +00002258
Rafael Antognollied207b42013-12-03 15:35:43 -02002259 shsurf->next_state.relative = true;
Kristian Høgsberga1df7ac2013-12-31 15:01:01 -08002260 shsurf->state_changed = true;
Kristian Høgsbergc8f8dd82013-12-05 23:20:33 -08002261 shsurf->type = SHELL_SURFACE_TOPLEVEL;
Philip Withnall648a4dd2013-11-25 18:01:44 +00002262
2263 /* The layer_link is updated in set_surface_type(),
2264 * called from configure. */
Philip Withnallbecb77e2013-11-25 18:01:30 +00002265}
2266
2267static void
2268shell_surface_set_transient(struct wl_client *client,
2269 struct wl_resource *resource,
2270 struct wl_resource *parent_resource,
2271 int x, int y, uint32_t flags)
2272{
2273 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
2274 struct weston_surface *parent =
2275 wl_resource_get_user_data(parent_resource);
2276
2277 set_transient(shsurf, parent, x, y, flags);
2278}
2279
2280static void
2281set_fullscreen(struct shell_surface *shsurf,
2282 uint32_t method,
2283 uint32_t framerate,
2284 struct weston_output *output)
2285{
Philip Withnall352e7ed2013-11-25 18:01:35 +00002286 shell_surface_set_output(shsurf, output);
Philip Withnallbecb77e2013-11-25 18:01:30 +00002287
2288 shsurf->fullscreen_output = shsurf->output;
2289 shsurf->fullscreen.type = method;
2290 shsurf->fullscreen.framerate = framerate;
Philip Withnalldc4332f2013-11-25 18:01:38 +00002291
Kristian Høgsbergc8f8dd82013-12-05 23:20:33 -08002292 shsurf->type = SHELL_SURFACE_TOPLEVEL;
Philip Withnallbecb77e2013-11-25 18:01:30 +00002293
2294 shsurf->client->send_configure(shsurf->surface, 0,
2295 shsurf->output->width,
2296 shsurf->output->height);
Philip Withnall648a4dd2013-11-25 18:01:44 +00002297
2298 /* The layer_link is updated in set_surface_type(),
2299 * called from configure. */
Philip Withnallbecb77e2013-11-25 18:01:30 +00002300}
2301
2302static void
Zhang, Xiong Y31236932013-12-13 22:10:57 +02002303weston_view_set_initial_position(struct weston_view *view,
2304 struct desktop_shell *shell);
2305
2306static void
Philip Withnallbecb77e2013-11-25 18:01:30 +00002307unset_fullscreen(struct shell_surface *shsurf)
Alex Wu4539b082012-03-01 12:57:46 +08002308{
Philip Withnallf85fe842013-11-25 18:01:37 +00002309 /* Unset the fullscreen output, driver configuration and transforms. */
Alex Wubd3354b2012-04-17 17:20:49 +08002310 if (shsurf->fullscreen.type == WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER &&
2311 shell_surface_is_top_fullscreen(shsurf)) {
Alexander Larssonf82b6ca2013-05-28 16:23:39 +02002312 restore_output_mode(shsurf->fullscreen_output);
Alex Wubd3354b2012-04-17 17:20:49 +08002313 }
Philip Withnallf85fe842013-11-25 18:01:37 +00002314 shsurf->fullscreen_output = NULL;
2315
Alex Wu4539b082012-03-01 12:57:46 +08002316 shsurf->fullscreen.type = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT;
2317 shsurf->fullscreen.framerate = 0;
Philip Withnallf85fe842013-11-25 18:01:37 +00002318
Alex Wu4539b082012-03-01 12:57:46 +08002319 wl_list_remove(&shsurf->fullscreen.transform.link);
2320 wl_list_init(&shsurf->fullscreen.transform.link);
Philip Withnallf85fe842013-11-25 18:01:37 +00002321
Jason Ekstranda7af7042013-10-12 22:38:11 -05002322 if (shsurf->fullscreen.black_view)
2323 weston_surface_destroy(shsurf->fullscreen.black_view->surface);
2324 shsurf->fullscreen.black_view = NULL;
Philip Withnallf85fe842013-11-25 18:01:37 +00002325
Zhang, Xiong Y31236932013-12-13 22:10:57 +02002326 if (shsurf->saved_position_valid)
2327 weston_view_set_position(shsurf->view,
2328 shsurf->saved_x, shsurf->saved_y);
2329 else
2330 weston_view_set_initial_position(shsurf->view, shsurf->shell);
2331
Alex Wu7bcb8bd2012-04-27 09:07:24 +08002332 if (shsurf->saved_rotation_valid) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05002333 wl_list_insert(&shsurf->view->geometry.transformation_list,
Philip Withnallbecb77e2013-11-25 18:01:30 +00002334 &shsurf->rotation.transform.link);
Alex Wu7bcb8bd2012-04-27 09:07:24 +08002335 shsurf->saved_rotation_valid = false;
2336 }
Rafal Mielniczuk3e3862c2012-10-07 20:25:36 +02002337
Philip Withnalle1d75ae2013-11-25 18:01:41 +00002338 /* Layer is updated in set_surface_type(). */
Alex Wu4539b082012-03-01 12:57:46 +08002339}
2340
Rafal Mielniczukfffdcdd2013-03-11 19:26:54 +01002341static void
Philip Withnallbecb77e2013-11-25 18:01:30 +00002342shell_surface_set_fullscreen(struct wl_client *client,
2343 struct wl_resource *resource,
2344 uint32_t method,
2345 uint32_t framerate,
2346 struct wl_resource *output_resource)
2347{
2348 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
2349 struct weston_output *output;
2350
2351 if (output_resource)
2352 output = wl_resource_get_user_data(output_resource);
2353 else
2354 output = NULL;
2355
Rafael Antognolli4b99a402013-12-03 15:35:44 -02002356 shell_surface_set_parent(shsurf, NULL);
2357
Rafael Antognolli03b16592013-12-03 15:35:42 -02002358 surface_clear_next_states(shsurf);
Philip Withnallbecb77e2013-11-25 18:01:30 +00002359 set_fullscreen(shsurf, method, framerate, output);
Jasper St. Pierre8c6aa452014-02-08 18:29:49 -05002360
2361 shsurf->next_state.fullscreen = true;
2362 shsurf->state_changed = true;
Philip Withnallbecb77e2013-11-25 18:01:30 +00002363}
2364
2365static void
2366set_popup(struct shell_surface *shsurf,
2367 struct weston_surface *parent,
2368 struct weston_seat *seat,
2369 uint32_t serial,
2370 int32_t x,
2371 int32_t y)
2372{
Philip Withnalldc4332f2013-11-25 18:01:38 +00002373 assert(parent != NULL);
2374
Philip Withnallbecb77e2013-11-25 18:01:30 +00002375 shsurf->popup.shseat = get_shell_seat(seat);
2376 shsurf->popup.serial = serial;
2377 shsurf->popup.x = x;
2378 shsurf->popup.y = y;
Philip Withnalldc4332f2013-11-25 18:01:38 +00002379
Kristian Høgsbergc8f8dd82013-12-05 23:20:33 -08002380 shsurf->type = SHELL_SURFACE_POPUP;
Philip Withnallbecb77e2013-11-25 18:01:30 +00002381}
2382
2383static void
2384shell_surface_set_popup(struct wl_client *client,
2385 struct wl_resource *resource,
2386 struct wl_resource *seat_resource,
2387 uint32_t serial,
2388 struct wl_resource *parent_resource,
2389 int32_t x, int32_t y, uint32_t flags)
2390{
2391 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
Rafael Antognolli4b99a402013-12-03 15:35:44 -02002392 struct weston_surface *parent =
2393 wl_resource_get_user_data(parent_resource);
2394
2395 shell_surface_set_parent(shsurf, parent);
Philip Withnallbecb77e2013-11-25 18:01:30 +00002396
Rafael Antognolli03b16592013-12-03 15:35:42 -02002397 surface_clear_next_states(shsurf);
Philip Withnallbecb77e2013-11-25 18:01:30 +00002398 set_popup(shsurf,
Rafael Antognolli4b99a402013-12-03 15:35:44 -02002399 parent,
Philip Withnallbecb77e2013-11-25 18:01:30 +00002400 wl_resource_get_user_data(seat_resource),
2401 serial, x, y);
2402}
2403
2404static void
2405set_maximized(struct shell_surface *shsurf,
2406 struct weston_output *output)
2407{
2408 struct desktop_shell *shell;
2409 uint32_t edges = 0, panel_height = 0;
Philip Withnallbecb77e2013-11-25 18:01:30 +00002410
Philip Withnall352e7ed2013-11-25 18:01:35 +00002411 shell_surface_set_output(shsurf, output);
Philip Withnallbecb77e2013-11-25 18:01:30 +00002412
2413 shell = shell_surface_get_shell(shsurf);
2414 panel_height = get_output_panel_height(shell, shsurf->output);
2415 edges = WL_SHELL_SURFACE_RESIZE_TOP | WL_SHELL_SURFACE_RESIZE_LEFT;
2416
2417 shsurf->client->send_configure(shsurf->surface, edges,
2418 shsurf->output->width,
2419 shsurf->output->height - panel_height);
2420
Kristian Høgsbergc8f8dd82013-12-05 23:20:33 -08002421 shsurf->type = SHELL_SURFACE_TOPLEVEL;
Philip Withnallbecb77e2013-11-25 18:01:30 +00002422}
2423
2424static void
2425unset_maximized(struct shell_surface *shsurf)
Rafal Mielniczukfffdcdd2013-03-11 19:26:54 +01002426{
Rafal Mielniczukfffdcdd2013-03-11 19:26:54 +01002427 /* undo all maximized things here */
2428 shsurf->output = get_default_output(shsurf->surface->compositor);
Zhang, Xiong Y31236932013-12-13 22:10:57 +02002429
2430 if (shsurf->saved_position_valid)
2431 weston_view_set_position(shsurf->view,
2432 shsurf->saved_x, shsurf->saved_y);
2433 else
2434 weston_view_set_initial_position(shsurf->view, shsurf->shell);
Rafal Mielniczukfffdcdd2013-03-11 19:26:54 +01002435
2436 if (shsurf->saved_rotation_valid) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05002437 wl_list_insert(&shsurf->view->geometry.transformation_list,
2438 &shsurf->rotation.transform.link);
Rafal Mielniczukfffdcdd2013-03-11 19:26:54 +01002439 shsurf->saved_rotation_valid = false;
2440 }
2441
Philip Withnalle1d75ae2013-11-25 18:01:41 +00002442 /* Layer is updated in set_surface_type(). */
Rafal Mielniczukfffdcdd2013-03-11 19:26:54 +01002443}
2444
Philip Withnallbecb77e2013-11-25 18:01:30 +00002445static void
2446shell_surface_set_maximized(struct wl_client *client,
2447 struct wl_resource *resource,
2448 struct wl_resource *output_resource)
2449{
2450 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
2451 struct weston_output *output;
2452
2453 if (output_resource)
2454 output = wl_resource_get_user_data(output_resource);
2455 else
2456 output = NULL;
2457
Rafael Antognolli4b99a402013-12-03 15:35:44 -02002458 shell_surface_set_parent(shsurf, NULL);
2459
Rafael Antognolli03b16592013-12-03 15:35:42 -02002460 surface_clear_next_states(shsurf);
Philip Withnallbecb77e2013-11-25 18:01:30 +00002461 set_maximized(shsurf, output);
Jasper St. Pierre8c6aa452014-02-08 18:29:49 -05002462
2463 shsurf->next_state.maximized = true;
2464 shsurf->state_changed = true;
Philip Withnallbecb77e2013-11-25 18:01:30 +00002465}
2466
Philip Withnalle1d75ae2013-11-25 18:01:41 +00002467/* This is only ever called from set_surface_type(), so there’s no need to
2468 * update layer_links here, since they’ll be updated when we return. */
Pekka Paalanen98262232011-12-01 10:42:22 +02002469static int
Philip Withnallbecb77e2013-11-25 18:01:30 +00002470reset_surface_type(struct shell_surface *surface)
Pekka Paalanen98262232011-12-01 10:42:22 +02002471{
Rafael Antognolli03b16592013-12-03 15:35:42 -02002472 if (surface->state.fullscreen)
Philip Withnallbecb77e2013-11-25 18:01:30 +00002473 unset_fullscreen(surface);
Rafael Antognolli03b16592013-12-03 15:35:42 -02002474 if (surface->state.maximized)
Philip Withnallbecb77e2013-11-25 18:01:30 +00002475 unset_maximized(surface);
Pekka Paalanen98262232011-12-01 10:42:22 +02002476
Pekka Paalanen98262232011-12-01 10:42:22 +02002477 return 0;
2478}
2479
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05002480static void
Rafael Antognolli03b16592013-12-03 15:35:42 -02002481set_full_output(struct shell_surface *shsurf)
2482{
2483 shsurf->saved_x = shsurf->view->geometry.x;
2484 shsurf->saved_y = shsurf->view->geometry.y;
Rafael Antognolli3c4e3f72013-12-03 15:35:46 -02002485 shsurf->saved_width = shsurf->surface->width;
2486 shsurf->saved_height = shsurf->surface->height;
2487 shsurf->saved_size_valid = true;
Rafael Antognolli03b16592013-12-03 15:35:42 -02002488 shsurf->saved_position_valid = true;
2489
2490 if (!wl_list_empty(&shsurf->rotation.transform.link)) {
2491 wl_list_remove(&shsurf->rotation.transform.link);
2492 wl_list_init(&shsurf->rotation.transform.link);
2493 weston_view_geometry_dirty(shsurf->view);
2494 shsurf->saved_rotation_valid = true;
2495 }
2496}
2497
2498static void
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04002499set_surface_type(struct shell_surface *shsurf)
2500{
Kristian Høgsberg8150b192012-06-27 10:22:58 -04002501 struct weston_surface *pes = shsurf->parent;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002502 struct weston_view *pev = get_default_view(pes);
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04002503
Philip Withnallbecb77e2013-11-25 18:01:30 +00002504 reset_surface_type(shsurf);
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04002505
Rafael Antognolli03b16592013-12-03 15:35:42 -02002506 shsurf->state = shsurf->next_state;
Rafael Antognolli03b16592013-12-03 15:35:42 -02002507 shsurf->state_changed = false;
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04002508
2509 switch (shsurf->type) {
2510 case SHELL_SURFACE_TOPLEVEL:
Rafael Antognollied207b42013-12-03 15:35:43 -02002511 if (shsurf->state.maximized || shsurf->state.fullscreen) {
Rafael Antognolli03b16592013-12-03 15:35:42 -02002512 set_full_output(shsurf);
Rafael Antognollied207b42013-12-03 15:35:43 -02002513 } else if (shsurf->state.relative && pev) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05002514 weston_view_set_position(shsurf->view,
2515 pev->geometry.x + shsurf->transient.x,
2516 pev->geometry.y + shsurf->transient.y);
Rafael Antognollied207b42013-12-03 15:35:43 -02002517 }
Rafael Antognolli44a31622013-12-04 18:37:16 -02002518 break;
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04002519
Tiago Vignattifb2adba2013-06-12 15:43:21 -03002520 case SHELL_SURFACE_XWAYLAND:
Jason Ekstranda7af7042013-10-12 22:38:11 -05002521 weston_view_set_position(shsurf->view, shsurf->transient.x,
2522 shsurf->transient.y);
Tiago Vignattifb2adba2013-06-12 15:43:21 -03002523 break;
2524
Philip Withnall0f640e22013-11-25 18:01:31 +00002525 case SHELL_SURFACE_POPUP:
2526 case SHELL_SURFACE_NONE:
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04002527 default:
2528 break;
2529 }
Philip Withnalle1d75ae2013-11-25 18:01:41 +00002530
2531 /* Update the surface’s layer. */
2532 shell_surface_update_layer(shsurf);
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04002533}
2534
Tiago Vignattibe143262012-04-16 17:31:41 +03002535static struct desktop_shell *
Juan Zhao96879df2012-02-07 08:45:41 +08002536shell_surface_get_shell(struct shell_surface *shsurf)
Pekka Paalanenaf0e34c2011-12-02 10:59:17 +02002537{
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04002538 return shsurf->shell;
Juan Zhao96879df2012-02-07 08:45:41 +08002539}
2540
Alex Wu21858432012-04-01 20:13:08 +08002541static void
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06002542black_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy);
Alex Wu21858432012-04-01 20:13:08 +08002543
Jason Ekstranda7af7042013-10-12 22:38:11 -05002544static struct weston_view *
Alex Wu4539b082012-03-01 12:57:46 +08002545create_black_surface(struct weston_compositor *ec,
Alex Wu21858432012-04-01 20:13:08 +08002546 struct weston_surface *fs_surface,
John Kåre Alsaker490d02a2012-09-30 02:57:21 +02002547 float x, float y, int w, int h)
Alex Wu4539b082012-03-01 12:57:46 +08002548{
2549 struct weston_surface *surface = NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002550 struct weston_view *view;
Alex Wu4539b082012-03-01 12:57:46 +08002551
2552 surface = weston_surface_create(ec);
2553 if (surface == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002554 weston_log("no memory\n");
Alex Wu4539b082012-03-01 12:57:46 +08002555 return NULL;
2556 }
Jason Ekstranda7af7042013-10-12 22:38:11 -05002557 view = weston_view_create(surface);
2558 if (surface == NULL) {
2559 weston_log("no memory\n");
2560 weston_surface_destroy(surface);
2561 return NULL;
2562 }
Alex Wu4539b082012-03-01 12:57:46 +08002563
Alex Wu21858432012-04-01 20:13:08 +08002564 surface->configure = black_surface_configure;
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01002565 surface->configure_private = fs_surface;
Alex Wu4539b082012-03-01 12:57:46 +08002566 weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1);
Pekka Paalanen71f6f3b2012-10-10 12:49:26 +03002567 pixman_region32_fini(&surface->opaque);
Kristian Høgsberg61f00f52012-08-03 16:31:36 -04002568 pixman_region32_init_rect(&surface->opaque, 0, 0, w, h);
Jonas Ådahl33619a42013-01-15 21:25:55 +01002569 pixman_region32_fini(&surface->input);
2570 pixman_region32_init_rect(&surface->input, 0, 0, w, h);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06002571
Jason Ekstrand6228ee22014-01-01 15:58:57 -06002572 weston_surface_set_size(surface, w, h);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06002573 weston_view_set_position(view, x, y);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002574
2575 return view;
Alex Wu4539b082012-03-01 12:57:46 +08002576}
2577
Philip Withnalled8f1a92013-11-25 18:01:43 +00002578static void
2579shell_ensure_fullscreen_black_view(struct shell_surface *shsurf)
2580{
2581 struct weston_output *output = shsurf->fullscreen_output;
2582
Rafael Antognolli03b16592013-12-03 15:35:42 -02002583 assert(shsurf->state.fullscreen);
Philip Withnalled8f1a92013-11-25 18:01:43 +00002584
2585 if (!shsurf->fullscreen.black_view)
2586 shsurf->fullscreen.black_view =
2587 create_black_surface(shsurf->surface->compositor,
2588 shsurf->surface,
2589 output->x, output->y,
2590 output->width,
2591 output->height);
2592
2593 weston_view_geometry_dirty(shsurf->fullscreen.black_view);
2594 wl_list_remove(&shsurf->fullscreen.black_view->layer_link);
2595 wl_list_insert(&shsurf->view->layer_link,
2596 &shsurf->fullscreen.black_view->layer_link);
2597 weston_view_geometry_dirty(shsurf->fullscreen.black_view);
2598 weston_surface_damage(shsurf->surface);
2599}
2600
Alex Wu4539b082012-03-01 12:57:46 +08002601/* Create black surface and append it to the associated fullscreen surface.
2602 * Handle size dismatch and positioning according to the method. */
2603static void
2604shell_configure_fullscreen(struct shell_surface *shsurf)
2605{
2606 struct weston_output *output = shsurf->fullscreen_output;
2607 struct weston_surface *surface = shsurf->surface;
2608 struct weston_matrix *matrix;
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04002609 float scale, output_aspect, surface_aspect, x, y;
Giulio Camuffob8366642013-04-25 13:57:46 +03002610 int32_t surf_x, surf_y, surf_width, surf_height;
Alex Wu4539b082012-03-01 12:57:46 +08002611
Alexander Larssonf82b6ca2013-05-28 16:23:39 +02002612 if (shsurf->fullscreen.type != WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER)
2613 restore_output_mode(output);
2614
Philip Withnalled8f1a92013-11-25 18:01:43 +00002615 shell_ensure_fullscreen_black_view(shsurf);
Alex Wu4539b082012-03-01 12:57:46 +08002616
Jason Ekstranda7af7042013-10-12 22:38:11 -05002617 surface_subsurfaces_boundingbox(shsurf->surface, &surf_x, &surf_y,
Giulio Camuffob8366642013-04-25 13:57:46 +03002618 &surf_width, &surf_height);
2619
Alex Wu4539b082012-03-01 12:57:46 +08002620 switch (shsurf->fullscreen.type) {
2621 case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT:
Pekka Paalanende685b82012-12-04 15:58:12 +02002622 if (surface->buffer_ref.buffer)
Jason Ekstranda7af7042013-10-12 22:38:11 -05002623 center_on_output(shsurf->view, shsurf->fullscreen_output);
Alex Wu4539b082012-03-01 12:57:46 +08002624 break;
2625 case WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE:
Rob Bradford9f3dd152013-02-12 11:53:47 +00002626 /* 1:1 mapping between surface and output dimensions */
Giulio Camuffob8366642013-04-25 13:57:46 +03002627 if (output->width == surf_width &&
2628 output->height == surf_height) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05002629 weston_view_set_position(shsurf->view,
2630 output->x - surf_x,
2631 output->y - surf_y);
Rob Bradford9f3dd152013-02-12 11:53:47 +00002632 break;
2633 }
2634
Alex Wu4539b082012-03-01 12:57:46 +08002635 matrix = &shsurf->fullscreen.transform.matrix;
2636 weston_matrix_init(matrix);
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04002637
Scott Moreau1bad5db2012-08-18 01:04:05 -06002638 output_aspect = (float) output->width /
2639 (float) output->height;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002640 /* XXX: Use surf_width and surf_height here? */
2641 surface_aspect = (float) surface->width /
2642 (float) surface->height;
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04002643 if (output_aspect < surface_aspect)
Scott Moreau1bad5db2012-08-18 01:04:05 -06002644 scale = (float) output->width /
Giulio Camuffob8366642013-04-25 13:57:46 +03002645 (float) surf_width;
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04002646 else
Scott Moreau1bad5db2012-08-18 01:04:05 -06002647 scale = (float) output->height /
Giulio Camuffob8366642013-04-25 13:57:46 +03002648 (float) surf_height;
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04002649
Alex Wu4539b082012-03-01 12:57:46 +08002650 weston_matrix_scale(matrix, scale, scale, 1);
2651 wl_list_remove(&shsurf->fullscreen.transform.link);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002652 wl_list_insert(&shsurf->view->geometry.transformation_list,
Alex Wu4539b082012-03-01 12:57:46 +08002653 &shsurf->fullscreen.transform.link);
Giulio Camuffob8366642013-04-25 13:57:46 +03002654 x = output->x + (output->width - surf_width * scale) / 2 - surf_x;
2655 y = output->y + (output->height - surf_height * scale) / 2 - surf_y;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002656 weston_view_set_position(shsurf->view, x, y);
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04002657
Alex Wu4539b082012-03-01 12:57:46 +08002658 break;
2659 case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER:
Alex Wubd3354b2012-04-17 17:20:49 +08002660 if (shell_surface_is_top_fullscreen(shsurf)) {
Quentin Glidicc0d79ce2013-01-29 14:16:13 +01002661 struct weston_mode mode = {0,
Pekka Paalanen1fd9c0f2013-11-26 18:19:41 +01002662 surf_width * surface->buffer_viewport.scale,
2663 surf_height * surface->buffer_viewport.scale,
Alex Wubd3354b2012-04-17 17:20:49 +08002664 shsurf->fullscreen.framerate};
2665
Pekka Paalanen1fd9c0f2013-11-26 18:19:41 +01002666 if (weston_output_switch_mode(output, &mode, surface->buffer_viewport.scale,
Hardening57388e42013-09-18 23:56:36 +02002667 WESTON_MODE_SWITCH_SET_TEMPORARY) == 0) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05002668 weston_view_set_position(shsurf->view,
2669 output->x - surf_x,
2670 output->y - surf_y);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06002671 shsurf->fullscreen.black_view->surface->width = output->width;
2672 shsurf->fullscreen.black_view->surface->height = output->height;
2673 weston_view_set_position(shsurf->fullscreen.black_view,
2674 output->x - surf_x,
2675 output->y - surf_y);
Alex Wubd3354b2012-04-17 17:20:49 +08002676 break;
Alexander Larssond622ed32013-05-28 16:23:40 +02002677 } else {
Alexander Larssonf82b6ca2013-05-28 16:23:39 +02002678 restore_output_mode(output);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002679 center_on_output(shsurf->view, output);
Alexander Larssond622ed32013-05-28 16:23:40 +02002680 }
Alex Wubd3354b2012-04-17 17:20:49 +08002681 }
Alex Wu4539b082012-03-01 12:57:46 +08002682 break;
2683 case WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL:
Jason Ekstranda7af7042013-10-12 22:38:11 -05002684 center_on_output(shsurf->view, output);
Alex Wu4539b082012-03-01 12:57:46 +08002685 break;
2686 default:
2687 break;
2688 }
2689}
2690
Alex Wu4539b082012-03-01 12:57:46 +08002691static void
2692shell_map_fullscreen(struct shell_surface *shsurf)
2693{
Alex Wubd3354b2012-04-17 17:20:49 +08002694 shell_configure_fullscreen(shsurf);
Alex Wu4539b082012-03-01 12:57:46 +08002695}
2696
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04002697static void
Tiago Vignattifb2adba2013-06-12 15:43:21 -03002698set_xwayland(struct shell_surface *shsurf, int x, int y, uint32_t flags)
2699{
2700 /* XXX: using the same fields for transient type */
Rafael Antognolli03b16592013-12-03 15:35:42 -02002701 surface_clear_next_states(shsurf);
Tiago Vignattifb2adba2013-06-12 15:43:21 -03002702 shsurf->transient.x = x;
2703 shsurf->transient.y = y;
2704 shsurf->transient.flags = flags;
Philip Withnalldc4332f2013-11-25 18:01:38 +00002705
2706 shell_surface_set_parent(shsurf, NULL);
2707
Kristian Høgsbergc8f8dd82013-12-05 23:20:33 -08002708 shsurf->type = SHELL_SURFACE_XWAYLAND;
Kristian Høgsberg8bc525c2014-01-01 22:34:49 -08002709 shsurf->state_changed = true;
Tiago Vignattifb2adba2013-06-12 15:43:21 -03002710}
2711
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04002712static const struct weston_pointer_grab_interface popup_grab_interface;
Giulio Camuffo5085a752013-03-25 21:42:45 +01002713
2714static void
2715destroy_shell_seat(struct wl_listener *listener, void *data)
2716{
2717 struct shell_seat *shseat =
2718 container_of(listener,
2719 struct shell_seat, seat_destroy_listener);
2720 struct shell_surface *shsurf, *prev = NULL;
2721
2722 if (shseat->popup_grab.grab.interface == &popup_grab_interface) {
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04002723 weston_pointer_end_grab(shseat->popup_grab.grab.pointer);
Giulio Camuffo5085a752013-03-25 21:42:45 +01002724 shseat->popup_grab.client = NULL;
2725
2726 wl_list_for_each(shsurf, &shseat->popup_grab.surfaces_list, popup.grab_link) {
2727 shsurf->popup.shseat = NULL;
2728 if (prev) {
2729 wl_list_init(&prev->popup.grab_link);
2730 }
2731 prev = shsurf;
2732 }
2733 wl_list_init(&prev->popup.grab_link);
2734 }
2735
2736 wl_list_remove(&shseat->seat_destroy_listener.link);
2737 free(shseat);
2738}
2739
2740static struct shell_seat *
2741create_shell_seat(struct weston_seat *seat)
2742{
2743 struct shell_seat *shseat;
2744
2745 shseat = calloc(1, sizeof *shseat);
2746 if (!shseat) {
2747 weston_log("no memory to allocate shell seat\n");
2748 return NULL;
2749 }
2750
2751 shseat->seat = seat;
2752 wl_list_init(&shseat->popup_grab.surfaces_list);
2753
2754 shseat->seat_destroy_listener.notify = destroy_shell_seat;
2755 wl_signal_add(&seat->destroy_signal,
2756 &shseat->seat_destroy_listener);
2757
2758 return shseat;
2759}
2760
2761static struct shell_seat *
2762get_shell_seat(struct weston_seat *seat)
2763{
2764 struct wl_listener *listener;
2765
2766 listener = wl_signal_get(&seat->destroy_signal, destroy_shell_seat);
2767 if (listener == NULL)
2768 return create_shell_seat(seat);
2769
2770 return container_of(listener,
2771 struct shell_seat, seat_destroy_listener);
2772}
2773
Kristian Høgsbergb810eb52013-02-12 20:07:05 -05002774static void
Kristian Høgsberg6848c252013-05-08 22:02:59 -04002775popup_grab_focus(struct weston_pointer_grab *grab)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002776{
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04002777 struct weston_pointer *pointer = grab->pointer;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002778 struct weston_view *view;
Giulio Camuffo5085a752013-03-25 21:42:45 +01002779 struct shell_seat *shseat =
2780 container_of(grab, struct shell_seat, popup_grab.grab);
2781 struct wl_client *client = shseat->popup_grab.client;
Kristian Høgsberg6848c252013-05-08 22:02:59 -04002782 wl_fixed_t sx, sy;
2783
Jason Ekstranda7af7042013-10-12 22:38:11 -05002784 view = weston_compositor_pick_view(pointer->seat->compositor,
2785 pointer->x, pointer->y,
2786 &sx, &sy);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002787
Jason Ekstranda7af7042013-10-12 22:38:11 -05002788 if (view && view->surface->resource &&
2789 wl_resource_get_client(view->surface->resource) == client) {
2790 weston_pointer_set_focus(pointer, view, sx, sy);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002791 } else {
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04002792 weston_pointer_set_focus(pointer, NULL,
2793 wl_fixed_from_int(0),
2794 wl_fixed_from_int(0));
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002795 }
2796}
2797
2798static void
Giulio Camuffo1959ab82013-11-14 23:42:52 +01002799popup_grab_motion(struct weston_pointer_grab *grab, uint32_t time,
2800 wl_fixed_t x, wl_fixed_t y)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002801{
Kristian Høgsbergbe6403e2013-05-08 21:03:21 -04002802 struct weston_pointer *pointer = grab->pointer;
Neil Roberts96d790e2013-09-19 17:32:00 +01002803 struct wl_resource *resource;
Kristian Høgsbergbe6403e2013-05-08 21:03:21 -04002804 wl_fixed_t sx, sy;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002805
Giulio Camuffo1959ab82013-11-14 23:42:52 +01002806 weston_pointer_move(pointer, x, y);
2807
Neil Roberts96d790e2013-09-19 17:32:00 +01002808 wl_resource_for_each(resource, &pointer->focus_resource_list) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05002809 weston_view_from_global_fixed(pointer->focus,
2810 pointer->x, pointer->y,
2811 &sx, &sy);
Neil Roberts96d790e2013-09-19 17:32:00 +01002812 wl_pointer_send_motion(resource, time, sx, sy);
Kristian Høgsbergbe6403e2013-05-08 21:03:21 -04002813 }
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002814}
2815
2816static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04002817popup_grab_button(struct weston_pointer_grab *grab,
Daniel Stone4dbadb12012-05-30 16:31:51 +01002818 uint32_t time, uint32_t button, uint32_t state_w)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002819{
2820 struct wl_resource *resource;
Giulio Camuffo5085a752013-03-25 21:42:45 +01002821 struct shell_seat *shseat =
2822 container_of(grab, struct shell_seat, popup_grab.grab);
Rob Bradford880ebc72013-07-22 17:31:38 +01002823 struct wl_display *display = shseat->seat->compositor->wl_display;
Daniel Stone4dbadb12012-05-30 16:31:51 +01002824 enum wl_pointer_button_state state = state_w;
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04002825 uint32_t serial;
Neil Roberts96d790e2013-09-19 17:32:00 +01002826 struct wl_list *resource_list;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002827
Neil Roberts96d790e2013-09-19 17:32:00 +01002828 resource_list = &grab->pointer->focus_resource_list;
2829 if (!wl_list_empty(resource_list)) {
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04002830 serial = wl_display_get_serial(display);
Neil Roberts96d790e2013-09-19 17:32:00 +01002831 wl_resource_for_each(resource, resource_list) {
2832 wl_pointer_send_button(resource, serial,
2833 time, button, state);
2834 }
Daniel Stone4dbadb12012-05-30 16:31:51 +01002835 } else if (state == WL_POINTER_BUTTON_STATE_RELEASED &&
Giulio Camuffo5085a752013-03-25 21:42:45 +01002836 (shseat->popup_grab.initial_up ||
Kristian Høgsberge3148752013-05-06 23:19:49 -04002837 time - shseat->seat->pointer->grab_time > 500)) {
Kristian Høgsberg57e09072012-10-30 14:07:27 -04002838 popup_grab_end(grab->pointer);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002839 }
2840
Daniel Stone4dbadb12012-05-30 16:31:51 +01002841 if (state == WL_POINTER_BUTTON_STATE_RELEASED)
Giulio Camuffo5085a752013-03-25 21:42:45 +01002842 shseat->popup_grab.initial_up = 1;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002843}
2844
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02002845static void
2846popup_grab_cancel(struct weston_pointer_grab *grab)
2847{
2848 popup_grab_end(grab->pointer);
2849}
2850
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04002851static const struct weston_pointer_grab_interface popup_grab_interface = {
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002852 popup_grab_focus,
2853 popup_grab_motion,
2854 popup_grab_button,
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02002855 popup_grab_cancel,
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002856};
2857
2858static void
Rafael Antognollie2a34552013-12-03 15:35:45 -02002859shell_surface_send_popup_done(struct shell_surface *shsurf)
2860{
2861 if (shell_surface_is_wl_shell_surface(shsurf))
2862 wl_shell_surface_send_popup_done(shsurf->resource);
2863 else if (shell_surface_is_xdg_popup(shsurf))
2864 xdg_popup_send_popup_done(shsurf->resource,
2865 shsurf->popup.serial);
2866}
2867
2868static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04002869popup_grab_end(struct weston_pointer *pointer)
Kristian Høgsberg57e09072012-10-30 14:07:27 -04002870{
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04002871 struct weston_pointer_grab *grab = pointer->grab;
Giulio Camuffo5085a752013-03-25 21:42:45 +01002872 struct shell_seat *shseat =
2873 container_of(grab, struct shell_seat, popup_grab.grab);
2874 struct shell_surface *shsurf;
2875 struct shell_surface *prev = NULL;
Kristian Høgsberg57e09072012-10-30 14:07:27 -04002876
2877 if (pointer->grab->interface == &popup_grab_interface) {
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04002878 weston_pointer_end_grab(grab->pointer);
Giulio Camuffo5085a752013-03-25 21:42:45 +01002879 shseat->popup_grab.client = NULL;
Philipp Brüschweiler63e7be62013-04-15 21:09:54 +02002880 shseat->popup_grab.grab.interface = NULL;
2881 assert(!wl_list_empty(&shseat->popup_grab.surfaces_list));
Giulio Camuffo5085a752013-03-25 21:42:45 +01002882 /* Send the popup_done event to all the popups open */
2883 wl_list_for_each(shsurf, &shseat->popup_grab.surfaces_list, popup.grab_link) {
Rafael Antognollie2a34552013-12-03 15:35:45 -02002884 shell_surface_send_popup_done(shsurf);
Giulio Camuffo5085a752013-03-25 21:42:45 +01002885 shsurf->popup.shseat = NULL;
2886 if (prev) {
2887 wl_list_init(&prev->popup.grab_link);
2888 }
2889 prev = shsurf;
2890 }
2891 wl_list_init(&prev->popup.grab_link);
2892 wl_list_init(&shseat->popup_grab.surfaces_list);
2893 }
2894}
2895
2896static void
2897add_popup_grab(struct shell_surface *shsurf, struct shell_seat *shseat)
2898{
Kristian Høgsberge3148752013-05-06 23:19:49 -04002899 struct weston_seat *seat = shseat->seat;
Giulio Camuffo5085a752013-03-25 21:42:45 +01002900
2901 if (wl_list_empty(&shseat->popup_grab.surfaces_list)) {
Jason Ekstrand651f00e2013-06-14 10:07:54 -05002902 shseat->popup_grab.client = wl_resource_get_client(shsurf->resource);
Giulio Camuffo5085a752013-03-25 21:42:45 +01002903 shseat->popup_grab.grab.interface = &popup_grab_interface;
Giulio Camuffo1b4b61a2013-03-27 18:05:26 +01002904 /* We must make sure here that this popup was opened after
2905 * a mouse press, and not just by moving around with other
2906 * popups already open. */
Kristian Høgsberge3148752013-05-06 23:19:49 -04002907 if (shseat->seat->pointer->button_count > 0)
Giulio Camuffo1b4b61a2013-03-27 18:05:26 +01002908 shseat->popup_grab.initial_up = 0;
Giulio Camuffo5085a752013-03-25 21:42:45 +01002909
Rob Bradforddfe31052013-06-26 19:49:11 +01002910 wl_list_insert(&shseat->popup_grab.surfaces_list, &shsurf->popup.grab_link);
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04002911 weston_pointer_start_grab(seat->pointer, &shseat->popup_grab.grab);
Rob Bradforddfe31052013-06-26 19:49:11 +01002912 } else {
2913 wl_list_insert(&shseat->popup_grab.surfaces_list, &shsurf->popup.grab_link);
Giulio Camuffo5085a752013-03-25 21:42:45 +01002914 }
Giulio Camuffo5085a752013-03-25 21:42:45 +01002915}
2916
2917static void
2918remove_popup_grab(struct shell_surface *shsurf)
2919{
2920 struct shell_seat *shseat = shsurf->popup.shseat;
2921
2922 wl_list_remove(&shsurf->popup.grab_link);
2923 wl_list_init(&shsurf->popup.grab_link);
2924 if (wl_list_empty(&shseat->popup_grab.surfaces_list)) {
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04002925 weston_pointer_end_grab(shseat->popup_grab.grab.pointer);
Philipp Brüschweiler63e7be62013-04-15 21:09:54 +02002926 shseat->popup_grab.grab.interface = NULL;
Kristian Høgsberg57e09072012-10-30 14:07:27 -04002927 }
2928}
2929
2930static void
Kristian Høgsberg3730f362012-04-13 12:40:07 -04002931shell_map_popup(struct shell_surface *shsurf)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002932{
Giulio Camuffo5085a752013-03-25 21:42:45 +01002933 struct shell_seat *shseat = shsurf->popup.shseat;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002934 struct weston_view *parent_view = get_default_view(shsurf->parent);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002935
Jason Ekstranda7af7042013-10-12 22:38:11 -05002936 shsurf->surface->output = parent_view->output;
2937 shsurf->view->output = parent_view->output;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002938
Jason Ekstranda7af7042013-10-12 22:38:11 -05002939 weston_view_set_transform_parent(shsurf->view, parent_view);
2940 weston_view_set_position(shsurf->view, shsurf->popup.x, shsurf->popup.y);
2941 weston_view_update_transform(shsurf->view);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002942
Kristian Høgsberge3148752013-05-06 23:19:49 -04002943 if (shseat->seat->pointer->grab_serial == shsurf->popup.serial) {
Giulio Camuffo5085a752013-03-25 21:42:45 +01002944 add_popup_grab(shsurf, shseat);
Kristian Høgsberg3730f362012-04-13 12:40:07 -04002945 } else {
Rafael Antognollie2a34552013-12-03 15:35:45 -02002946 shell_surface_send_popup_done(shsurf);
Giulio Camuffo5085a752013-03-25 21:42:45 +01002947 shseat->popup_grab.client = NULL;
Kristian Høgsberg3730f362012-04-13 12:40:07 -04002948 }
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002949}
2950
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002951static const struct wl_shell_surface_interface shell_surface_implementation = {
Scott Moreauff1db4a2012-04-17 19:06:18 -06002952 shell_surface_pong,
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002953 shell_surface_move,
2954 shell_surface_resize,
2955 shell_surface_set_toplevel,
2956 shell_surface_set_transient,
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002957 shell_surface_set_fullscreen,
Juan Zhao96879df2012-02-07 08:45:41 +08002958 shell_surface_set_popup,
Kristian Høgsberge7afd912012-05-02 09:47:44 -04002959 shell_surface_set_maximized,
2960 shell_surface_set_title,
2961 shell_surface_set_class
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002962};
2963
2964static void
Tiago Vignattibc052c92012-04-19 16:18:18 +03002965destroy_shell_surface(struct shell_surface *shsurf)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002966{
Kristian Høgsberg9046d242014-01-10 00:25:30 -08002967 struct shell_surface *child, *next;
2968
Jason Ekstrand651f00e2013-06-14 10:07:54 -05002969 wl_signal_emit(&shsurf->destroy_signal, shsurf);
2970
Giulio Camuffo5085a752013-03-25 21:42:45 +01002971 if (!wl_list_empty(&shsurf->popup.grab_link)) {
2972 remove_popup_grab(shsurf);
2973 }
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002974
Alex Wubd3354b2012-04-17 17:20:49 +08002975 if (shsurf->fullscreen.type == WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER &&
Alexander Larssonf82b6ca2013-05-28 16:23:39 +02002976 shell_surface_is_top_fullscreen(shsurf))
2977 restore_output_mode (shsurf->fullscreen_output);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002978
Jason Ekstranda7af7042013-10-12 22:38:11 -05002979 if (shsurf->fullscreen.black_view)
2980 weston_surface_destroy(shsurf->fullscreen.black_view->surface);
Alex Wuaa08e2d2012-03-05 11:01:40 +08002981
Alex Wubd3354b2012-04-17 17:20:49 +08002982 /* As destroy_resource() use wl_list_for_each_safe(),
2983 * we can always remove the listener.
2984 */
2985 wl_list_remove(&shsurf->surface_destroy_listener.link);
2986 shsurf->surface->configure = NULL;
Scott Moreau976a0502013-03-07 10:15:17 -07002987 free(shsurf->title);
Alex Wubd3354b2012-04-17 17:20:49 +08002988
Jason Ekstranda7af7042013-10-12 22:38:11 -05002989 weston_view_destroy(shsurf->view);
2990
Philip Withnall648a4dd2013-11-25 18:01:44 +00002991 wl_list_remove(&shsurf->children_link);
Emilio Pozuelo Monfortadaa20c2014-01-28 13:54:16 +01002992 wl_list_for_each_safe(child, next, &shsurf->children_list, children_link)
2993 shell_surface_set_parent(child, NULL);
Philip Withnall648a4dd2013-11-25 18:01:44 +00002994
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002995 wl_list_remove(&shsurf->link);
2996 free(shsurf);
2997}
2998
2999static void
Tiago Vignattibc052c92012-04-19 16:18:18 +03003000shell_destroy_shell_surface(struct wl_resource *resource)
3001{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05003002 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
Tiago Vignattibc052c92012-04-19 16:18:18 +03003003
3004 destroy_shell_surface(shsurf);
3005}
3006
3007static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04003008shell_handle_surface_destroy(struct wl_listener *listener, void *data)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003009{
3010 struct shell_surface *shsurf = container_of(listener,
3011 struct shell_surface,
3012 surface_destroy_listener);
3013
Jason Ekstrand651f00e2013-06-14 10:07:54 -05003014 if (shsurf->resource)
3015 wl_resource_destroy(shsurf->resource);
3016 else
Tiago Vignattibc052c92012-04-19 16:18:18 +03003017 destroy_shell_surface(shsurf);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003018}
3019
Kristian Høgsbergd8134452012-06-21 12:49:02 -04003020static void
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06003021shell_surface_configure(struct weston_surface *, int32_t, int32_t);
Kristian Høgsbergd8134452012-06-21 12:49:02 -04003022
Kristian Høgsberg1ef23132013-12-04 00:20:01 -08003023struct shell_surface *
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05003024get_shell_surface(struct weston_surface *surface)
Pekka Paalanenec2b32f2011-11-28 15:12:34 +02003025{
Kristian Høgsbergd8134452012-06-21 12:49:02 -04003026 if (surface->configure == shell_surface_configure)
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01003027 return surface->configure_private;
Kristian Høgsbergd8134452012-06-21 12:49:02 -04003028 else
3029 return NULL;
Pekka Paalanenec2b32f2011-11-28 15:12:34 +02003030}
3031
Rafael Antognollie2a34552013-12-03 15:35:45 -02003032static struct shell_surface *
3033create_common_surface(void *shell, struct weston_surface *surface,
3034 const struct weston_shell_client *client)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003035{
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003036 struct shell_surface *shsurf;
3037
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03003038 if (surface->configure) {
Martin Minarik6d118362012-06-07 18:01:59 +02003039 weston_log("surface->configure already set\n");
Kristian Høgsberg45ba8692012-05-21 14:27:33 -04003040 return NULL;
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03003041 }
3042
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003043 shsurf = calloc(1, sizeof *shsurf);
3044 if (!shsurf) {
Martin Minarik6d118362012-06-07 18:01:59 +02003045 weston_log("no memory to allocate shell surface\n");
Kristian Høgsberg45ba8692012-05-21 14:27:33 -04003046 return NULL;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003047 }
3048
Jason Ekstranda7af7042013-10-12 22:38:11 -05003049 shsurf->view = weston_view_create(surface);
3050 if (!shsurf->view) {
3051 weston_log("no memory to allocate shell surface\n");
3052 free(shsurf);
3053 return NULL;
3054 }
3055
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03003056 surface->configure = shell_surface_configure;
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01003057 surface->configure_private = shsurf;
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03003058
Tiago Vignattibc052c92012-04-19 16:18:18 +03003059 shsurf->shell = (struct desktop_shell *) shell;
Scott Moreauff1db4a2012-04-17 19:06:18 -06003060 shsurf->unresponsive = 0;
Alex Wu4539b082012-03-01 12:57:46 +08003061 shsurf->saved_position_valid = false;
Rafael Antognolli3c4e3f72013-12-03 15:35:46 -02003062 shsurf->saved_size_valid = false;
Alex Wu7bcb8bd2012-04-27 09:07:24 +08003063 shsurf->saved_rotation_valid = false;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003064 shsurf->surface = surface;
Alex Wu4539b082012-03-01 12:57:46 +08003065 shsurf->fullscreen.type = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT;
3066 shsurf->fullscreen.framerate = 0;
Jason Ekstranda7af7042013-10-12 22:38:11 -05003067 shsurf->fullscreen.black_view = NULL;
Alex Wu4539b082012-03-01 12:57:46 +08003068 wl_list_init(&shsurf->fullscreen.transform.link);
3069
Jason Ekstrand651f00e2013-06-14 10:07:54 -05003070 wl_signal_init(&shsurf->destroy_signal);
Kristian Høgsberg27e30522012-04-11 23:18:23 -04003071 shsurf->surface_destroy_listener.notify = shell_handle_surface_destroy;
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05003072 wl_signal_add(&surface->destroy_signal,
Kristian Høgsberg27e30522012-04-11 23:18:23 -04003073 &shsurf->surface_destroy_listener);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003074
3075 /* init link so its safe to always remove it in destroy_shell_surface */
3076 wl_list_init(&shsurf->link);
Giulio Camuffo5085a752013-03-25 21:42:45 +01003077 wl_list_init(&shsurf->popup.grab_link);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003078
Pekka Paalanen460099f2012-01-20 16:48:25 +02003079 /* empty when not in use */
3080 wl_list_init(&shsurf->rotation.transform.link);
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05003081 weston_matrix_init(&shsurf->rotation.rotation);
Pekka Paalanen460099f2012-01-20 16:48:25 +02003082
Jonas Ådahl62fcd042012-06-13 00:01:23 +02003083 wl_list_init(&shsurf->workspace_transform.link);
3084
Philip Withnall648a4dd2013-11-25 18:01:44 +00003085 wl_list_init(&shsurf->children_link);
3086 wl_list_init(&shsurf->children_list);
3087 shsurf->parent = NULL;
3088
Pekka Paalanen98262232011-12-01 10:42:22 +02003089 shsurf->type = SHELL_SURFACE_NONE;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003090
Kristian Høgsberga61ca062012-05-22 16:05:52 -04003091 shsurf->client = client;
3092
Kristian Høgsberg45ba8692012-05-21 14:27:33 -04003093 return shsurf;
Tiago Vignattibc052c92012-04-19 16:18:18 +03003094}
3095
Rafael Antognollie2a34552013-12-03 15:35:45 -02003096static struct shell_surface *
3097create_shell_surface(void *shell, struct weston_surface *surface,
3098 const struct weston_shell_client *client)
3099{
Kristian Høgsbergc8f8dd82013-12-05 23:20:33 -08003100 return create_common_surface(shell, surface, client);
Rafael Antognollie2a34552013-12-03 15:35:45 -02003101}
3102
Jason Ekstranda7af7042013-10-12 22:38:11 -05003103static struct weston_view *
3104get_primary_view(void *shell, struct shell_surface *shsurf)
3105{
3106 return shsurf->view;
3107}
3108
Tiago Vignattibc052c92012-04-19 16:18:18 +03003109static void
3110shell_get_shell_surface(struct wl_client *client,
3111 struct wl_resource *resource,
3112 uint32_t id,
3113 struct wl_resource *surface_resource)
3114{
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05003115 struct weston_surface *surface =
3116 wl_resource_get_user_data(surface_resource);
Jason Ekstrand651f00e2013-06-14 10:07:54 -05003117 struct desktop_shell *shell = wl_resource_get_user_data(resource);
Tiago Vignattibc052c92012-04-19 16:18:18 +03003118 struct shell_surface *shsurf;
3119
3120 if (get_shell_surface(surface)) {
3121 wl_resource_post_error(surface_resource,
Kristian Høgsberg9540ea62012-05-21 14:28:57 -04003122 WL_DISPLAY_ERROR_INVALID_OBJECT,
3123 "desktop_shell::get_shell_surface already requested");
Tiago Vignattibc052c92012-04-19 16:18:18 +03003124 return;
3125 }
3126
Kristian Høgsberga61ca062012-05-22 16:05:52 -04003127 shsurf = create_shell_surface(shell, surface, &shell_client);
Kristian Høgsberg9540ea62012-05-21 14:28:57 -04003128 if (!shsurf) {
3129 wl_resource_post_error(surface_resource,
3130 WL_DISPLAY_ERROR_INVALID_OBJECT,
3131 "surface->configure already set");
3132 return;
3133 }
Tiago Vignattibc052c92012-04-19 16:18:18 +03003134
Jason Ekstranda85118c2013-06-27 20:17:02 -05003135 shsurf->resource =
3136 wl_resource_create(client,
3137 &wl_shell_surface_interface, 1, id);
3138 wl_resource_set_implementation(shsurf->resource,
3139 &shell_surface_implementation,
3140 shsurf, shell_destroy_shell_surface);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003141}
3142
Rafael Antognollie2a34552013-12-03 15:35:45 -02003143static bool
3144shell_surface_is_wl_shell_surface(struct shell_surface *shsurf)
3145{
Kristian Høgsberg0b7d9952014-02-03 15:50:38 -08003146 /* A shell surface without a resource is created from xwayland
3147 * and is considered a wl_shell surface for now. */
3148
3149 return shsurf->resource == NULL ||
3150 wl_resource_instance_of(shsurf->resource,
3151 &wl_shell_surface_interface,
3152 &shell_surface_implementation);
Rafael Antognollie2a34552013-12-03 15:35:45 -02003153}
3154
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003155static const struct wl_shell_interface shell_implementation = {
Pekka Paalanen46229672011-11-29 15:49:31 +02003156 shell_get_shell_surface
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05003157};
3158
Rafael Antognollie2a34552013-12-03 15:35:45 -02003159/****************************
3160 * xdg-shell implementation */
3161
3162static void
3163xdg_surface_destroy(struct wl_client *client,
3164 struct wl_resource *resource)
3165{
3166 wl_resource_destroy(resource);
3167}
3168
3169static void
Jasper St. Pierre63a9c332014-02-01 18:35:15 -05003170xdg_surface_set_transient_for(struct wl_client *client,
3171 struct wl_resource *resource,
3172 struct wl_resource *parent_resource)
3173{
3174 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
3175 struct weston_surface *parent;
3176
3177 if (parent_resource)
3178 parent = wl_resource_get_user_data(parent_resource);
3179 else
3180 parent = NULL;
3181
3182 shell_surface_set_parent(shsurf, parent);
3183}
3184
3185static void
Jasper St. Pierre74073452014-02-01 18:36:41 -05003186xdg_surface_set_margin(struct wl_client *client,
3187 struct wl_resource *resource,
3188 int32_t left,
3189 int32_t right,
3190 int32_t top,
3191 int32_t bottom)
3192{
3193 /* Do nothing, Weston doesn't try to constrain or place
3194 * surfaces in any special manner... */
3195}
3196
3197static void
Rafael Antognollie2a34552013-12-03 15:35:45 -02003198xdg_surface_set_app_id(struct wl_client *client,
3199 struct wl_resource *resource,
3200 const char *app_id)
3201{
3202 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
3203
3204 free(shsurf->class);
3205 shsurf->class = strdup(app_id);
3206}
3207
3208static void
3209xdg_surface_set_title(struct wl_client *client,
3210 struct wl_resource *resource, const char *title)
3211{
3212 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
3213
3214 set_title(shsurf, title);
3215}
3216
3217static void
3218xdg_surface_move(struct wl_client *client, struct wl_resource *resource,
3219 struct wl_resource *seat_resource, uint32_t serial)
3220{
3221 common_surface_move(resource, seat_resource, serial);
3222}
3223
3224static void
3225xdg_surface_resize(struct wl_client *client, struct wl_resource *resource,
3226 struct wl_resource *seat_resource, uint32_t serial,
3227 uint32_t edges)
3228{
3229 common_surface_resize(resource, seat_resource, serial, edges);
3230}
3231
3232static void
3233xdg_surface_set_output(struct wl_client *client,
3234 struct wl_resource *resource,
3235 struct wl_resource *output_resource)
3236{
3237 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
3238 struct weston_output *output;
3239
3240 if (output_resource)
3241 output = wl_resource_get_user_data(output_resource);
3242 else
3243 output = NULL;
3244
Rafael Antognolli65f98d82013-12-03 15:35:47 -02003245 shsurf->recommended_output = output;
Rafael Antognollie2a34552013-12-03 15:35:45 -02003246}
3247
3248static void
Kristian Høgsberg283bf372014-02-18 23:28:09 -08003249xdg_surface_change_state(struct shell_surface *shsurf,
3250 uint32_t state, uint32_t value, uint32_t serial)
Rafael Antognollie2a34552013-12-03 15:35:45 -02003251{
Kristian Høgsberg283bf372014-02-18 23:28:09 -08003252 xdg_surface_send_change_state(shsurf->resource, state, value, serial);
Jasper St. Pierre8c6aa452014-02-08 18:29:49 -05003253 shsurf->state_requested = true;
Rafael Antognollie2a34552013-12-03 15:35:45 -02003254
Kristian Høgsberg283bf372014-02-18 23:28:09 -08003255 switch (state) {
3256 case XDG_SURFACE_STATE_MAXIMIZED:
3257 shsurf->requested_state.maximized = value;
3258 if (value)
3259 set_maximized(shsurf, NULL);
3260 break;
3261 case XDG_SURFACE_STATE_FULLSCREEN:
3262 shsurf->requested_state.fullscreen = value;
Rafael Antognollie2a34552013-12-03 15:35:45 -02003263
Kristian Høgsberg283bf372014-02-18 23:28:09 -08003264 if (value)
3265 set_fullscreen(shsurf,
3266 WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
3267 0, shsurf->recommended_output);
3268 break;
3269 }
Jasper St. Pierre8c6aa452014-02-08 18:29:49 -05003270}
3271
3272static void
3273xdg_surface_request_change_state(struct wl_client *client,
3274 struct wl_resource *resource,
3275 uint32_t state,
3276 uint32_t value,
3277 uint32_t serial)
Rafael Antognollie2a34552013-12-03 15:35:45 -02003278{
3279 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
Jasper St. Pierre8c6aa452014-02-08 18:29:49 -05003280
3281 /* The client can't know what the current state is, so we need
3282 to always send a state change in response. */
Rafael Antognollie2a34552013-12-03 15:35:45 -02003283
3284 if (shsurf->type != SHELL_SURFACE_TOPLEVEL)
3285 return;
3286
Jasper St. Pierre8c6aa452014-02-08 18:29:49 -05003287 switch (state) {
3288 case XDG_SURFACE_STATE_MAXIMIZED:
Jasper St. Pierre8c6aa452014-02-08 18:29:49 -05003289 case XDG_SURFACE_STATE_FULLSCREEN:
Jasper St. Pierre8c6aa452014-02-08 18:29:49 -05003290 break;
Kristian Høgsberg283bf372014-02-18 23:28:09 -08003291 default:
3292 /* send error? ignore? send change state with value 0? */
3293 return;
Rafael Antognolli3c4e3f72013-12-03 15:35:46 -02003294 }
Kristian Høgsberg283bf372014-02-18 23:28:09 -08003295
3296 xdg_surface_change_state(shsurf, state, value, serial);
Rafael Antognollie2a34552013-12-03 15:35:45 -02003297}
3298
3299static void
Jasper St. Pierre8c6aa452014-02-08 18:29:49 -05003300xdg_surface_ack_change_state(struct wl_client *client,
3301 struct wl_resource *resource,
3302 uint32_t state,
3303 uint32_t value,
3304 uint32_t serial)
Rafael Antognollie2a34552013-12-03 15:35:45 -02003305{
3306 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
3307
Jasper St. Pierre8c6aa452014-02-08 18:29:49 -05003308 if (shsurf->state_requested) {
3309 shsurf->next_state = shsurf->requested_state;
3310 shsurf->state_changed = true;
3311 shsurf->state_requested = false;
Rafael Antognolli3c4e3f72013-12-03 15:35:46 -02003312 }
Rafael Antognollie2a34552013-12-03 15:35:45 -02003313}
3314
3315static const struct xdg_surface_interface xdg_surface_implementation = {
3316 xdg_surface_destroy,
3317 xdg_surface_set_transient_for,
Jasper St. Pierre74073452014-02-01 18:36:41 -05003318 xdg_surface_set_margin,
Rafael Antognollie2a34552013-12-03 15:35:45 -02003319 xdg_surface_set_title,
3320 xdg_surface_set_app_id,
Rafael Antognollie2a34552013-12-03 15:35:45 -02003321 xdg_surface_move,
3322 xdg_surface_resize,
3323 xdg_surface_set_output,
Jasper St. Pierre8c6aa452014-02-08 18:29:49 -05003324 xdg_surface_request_change_state,
3325 xdg_surface_ack_change_state,
Rafael Antognollie2a34552013-12-03 15:35:45 -02003326 NULL /* set_minimized */
3327};
3328
3329static void
3330xdg_send_configure(struct weston_surface *surface,
3331 uint32_t edges, int32_t width, int32_t height)
3332{
3333 struct shell_surface *shsurf = get_shell_surface(surface);
3334
U. Artie Eoffcf5737a2014-01-17 10:08:25 -08003335 assert(shsurf);
3336
Kristian Høgsberg44cd1962014-02-05 21:36:04 -08003337 xdg_surface_send_configure(shsurf->resource, width, height);
Rafael Antognollie2a34552013-12-03 15:35:45 -02003338}
3339
3340static const struct weston_shell_client xdg_client = {
3341 xdg_send_configure
3342};
3343
3344static void
3345xdg_use_unstable_version(struct wl_client *client,
3346 struct wl_resource *resource,
3347 int32_t version)
3348{
3349 if (version > 1) {
3350 wl_resource_post_error(resource,
3351 1,
3352 "xdg-shell:: version not implemented yet.");
3353 return;
3354 }
3355}
3356
3357static struct shell_surface *
3358create_xdg_surface(void *shell, struct weston_surface *surface,
3359 const struct weston_shell_client *client)
3360{
3361 struct shell_surface *shsurf;
Rafael Antognollie2a34552013-12-03 15:35:45 -02003362
Kristian Høgsbergc8f8dd82013-12-05 23:20:33 -08003363 shsurf = create_common_surface(shell, surface, client);
3364 shsurf->type = SHELL_SURFACE_TOPLEVEL;
Rafael Antognollie2a34552013-12-03 15:35:45 -02003365
3366 return shsurf;
3367}
3368
3369static void
3370xdg_get_xdg_surface(struct wl_client *client,
3371 struct wl_resource *resource,
3372 uint32_t id,
3373 struct wl_resource *surface_resource)
3374{
3375 struct weston_surface *surface =
3376 wl_resource_get_user_data(surface_resource);
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08003377 struct shell_client *sc = wl_resource_get_user_data(resource);
3378 struct desktop_shell *shell = sc->shell;
Rafael Antognollie2a34552013-12-03 15:35:45 -02003379 struct shell_surface *shsurf;
3380
3381 if (get_shell_surface(surface)) {
3382 wl_resource_post_error(surface_resource,
3383 WL_DISPLAY_ERROR_INVALID_OBJECT,
3384 "desktop_shell::get_shell_surface already requested");
3385 return;
3386 }
3387
3388 shsurf = create_xdg_surface(shell, surface, &xdg_client);
3389 if (!shsurf) {
3390 wl_resource_post_error(surface_resource,
3391 WL_DISPLAY_ERROR_INVALID_OBJECT,
3392 "surface->configure already set");
3393 return;
3394 }
3395
3396 shsurf->resource =
3397 wl_resource_create(client,
3398 &xdg_surface_interface, 1, id);
3399 wl_resource_set_implementation(shsurf->resource,
3400 &xdg_surface_implementation,
3401 shsurf, shell_destroy_shell_surface);
3402}
3403
3404static bool
3405shell_surface_is_xdg_surface(struct shell_surface *shsurf)
3406{
Kristian Høgsberg0b7d9952014-02-03 15:50:38 -08003407 return shsurf->resource &&
3408 wl_resource_instance_of(shsurf->resource,
3409 &xdg_surface_interface,
3410 &xdg_surface_implementation);
Rafael Antognollie2a34552013-12-03 15:35:45 -02003411}
3412
3413/* xdg-popup implementation */
3414
3415static void
3416xdg_popup_destroy(struct wl_client *client,
3417 struct wl_resource *resource)
3418{
3419 wl_resource_destroy(resource);
3420}
3421
Rafael Antognollie2a34552013-12-03 15:35:45 -02003422static const struct xdg_popup_interface xdg_popup_implementation = {
3423 xdg_popup_destroy,
Rafael Antognollie2a34552013-12-03 15:35:45 -02003424};
3425
3426static void
3427xdg_popup_send_configure(struct weston_surface *surface,
3428 uint32_t edges, int32_t width, int32_t height)
3429{
3430}
3431
3432static const struct weston_shell_client xdg_popup_client = {
3433 xdg_popup_send_configure
3434};
3435
3436static struct shell_surface *
3437create_xdg_popup(void *shell, struct weston_surface *surface,
3438 const struct weston_shell_client *client,
3439 struct weston_surface *parent,
3440 struct shell_seat *seat,
3441 uint32_t serial,
3442 int32_t x, int32_t y)
3443{
3444 struct shell_surface *shsurf;
Rafael Antognollie2a34552013-12-03 15:35:45 -02003445
Kristian Høgsbergc8f8dd82013-12-05 23:20:33 -08003446 shsurf = create_common_surface(shell, surface, client);
3447 shsurf->type = SHELL_SURFACE_POPUP;
Rafael Antognollie2a34552013-12-03 15:35:45 -02003448 shsurf->popup.shseat = seat;
3449 shsurf->popup.serial = serial;
3450 shsurf->popup.x = x;
3451 shsurf->popup.y = y;
3452 shell_surface_set_parent(shsurf, parent);
3453
3454 return shsurf;
3455}
3456
3457static void
3458xdg_get_xdg_popup(struct wl_client *client,
3459 struct wl_resource *resource,
3460 uint32_t id,
3461 struct wl_resource *surface_resource,
3462 struct wl_resource *parent_resource,
3463 struct wl_resource *seat_resource,
3464 uint32_t serial,
3465 int32_t x, int32_t y, uint32_t flags)
3466{
3467 struct weston_surface *surface =
3468 wl_resource_get_user_data(surface_resource);
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08003469 struct shell_client *sc = wl_resource_get_user_data(resource);
3470 struct desktop_shell *shell = sc->shell;
Rafael Antognollie2a34552013-12-03 15:35:45 -02003471 struct shell_surface *shsurf;
3472 struct weston_surface *parent;
3473 struct shell_seat *seat;
3474
3475 if (get_shell_surface(surface)) {
3476 wl_resource_post_error(surface_resource,
3477 WL_DISPLAY_ERROR_INVALID_OBJECT,
3478 "desktop_shell::get_shell_surface already requested");
3479 return;
3480 }
3481
3482 if (!parent_resource) {
3483 wl_resource_post_error(surface_resource,
3484 WL_DISPLAY_ERROR_INVALID_OBJECT,
3485 "xdg_shell::get_xdg_popup requires a parent shell surface");
3486 }
3487
3488 parent = wl_resource_get_user_data(parent_resource);
3489 seat = get_shell_seat(wl_resource_get_user_data(seat_resource));;
3490
3491 shsurf = create_xdg_popup(shell, surface, &xdg_popup_client,
3492 parent, seat, serial, x, y);
3493 if (!shsurf) {
3494 wl_resource_post_error(surface_resource,
3495 WL_DISPLAY_ERROR_INVALID_OBJECT,
3496 "surface->configure already set");
3497 return;
3498 }
3499
3500 shsurf->resource =
3501 wl_resource_create(client,
3502 &xdg_popup_interface, 1, id);
3503 wl_resource_set_implementation(shsurf->resource,
3504 &xdg_popup_implementation,
3505 shsurf, shell_destroy_shell_surface);
3506}
3507
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08003508static void
3509xdg_pong(struct wl_client *client,
3510 struct wl_resource *resource, uint32_t serial)
3511{
3512 struct shell_client *sc = wl_resource_get_user_data(resource);
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08003513
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08003514 shell_client_pong(sc, serial);
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08003515}
3516
Rafael Antognollie2a34552013-12-03 15:35:45 -02003517static bool
3518shell_surface_is_xdg_popup(struct shell_surface *shsurf)
3519{
3520 return wl_resource_instance_of(shsurf->resource,
3521 &xdg_popup_interface,
3522 &xdg_popup_implementation);
3523}
3524
3525static const struct xdg_shell_interface xdg_implementation = {
3526 xdg_use_unstable_version,
3527 xdg_get_xdg_surface,
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08003528 xdg_get_xdg_popup,
3529 xdg_pong
Rafael Antognollie2a34552013-12-03 15:35:45 -02003530};
3531
3532static int
3533xdg_shell_unversioned_dispatch(const void *implementation,
3534 void *_target, uint32_t opcode,
3535 const struct wl_message *message,
3536 union wl_argument *args)
3537{
3538 struct wl_resource *resource = _target;
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08003539 struct shell_client *sc = wl_resource_get_user_data(resource);
Rafael Antognollie2a34552013-12-03 15:35:45 -02003540
3541 if (opcode != 0) {
3542 wl_resource_post_error(resource,
3543 WL_DISPLAY_ERROR_INVALID_OBJECT,
3544 "must call use_unstable_version first");
3545 return 0;
3546 }
3547
Kristian Høgsberg239902b2014-02-11 13:50:08 -08003548#define XDG_SERVER_VERSION 2
Rafael Antognollie2a34552013-12-03 15:35:45 -02003549
Kristian Høgsberg8d344a02013-12-08 22:27:11 -08003550 static_assert(XDG_SERVER_VERSION == XDG_SHELL_VERSION_CURRENT,
3551 "shell implementation doesn't match protocol version");
3552
Rafael Antognollie2a34552013-12-03 15:35:45 -02003553 if (args[0].i != XDG_SERVER_VERSION) {
3554 wl_resource_post_error(resource,
3555 WL_DISPLAY_ERROR_INVALID_OBJECT,
3556 "incompatible version, server is %d "
3557 "client wants %d",
3558 XDG_SERVER_VERSION, args[0].i);
3559 return 0;
3560 }
3561
3562 wl_resource_set_implementation(resource, &xdg_implementation,
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08003563 sc, NULL);
Rafael Antognollie2a34552013-12-03 15:35:45 -02003564
3565 return 1;
3566}
3567
3568/* end of xdg-shell implementation */
3569/***********************************/
3570
Kristian Høgsberg07937562011-04-12 17:25:42 -04003571static void
Ander Conselvan de Oliveira859e8852013-02-21 18:35:21 +02003572shell_fade(struct desktop_shell *shell, enum fade_type type);
3573
3574static int
3575screensaver_timeout(void *data)
3576{
3577 struct desktop_shell *shell = data;
3578
3579 shell_fade(shell, FADE_OUT);
3580
3581 return 1;
3582}
3583
3584static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05003585handle_screensaver_sigchld(struct weston_process *proc, int status)
Pekka Paalanen18027e52011-12-02 16:31:49 +02003586{
Ander Conselvan de Oliveira18639f82013-02-15 18:44:19 +02003587 struct desktop_shell *shell =
3588 container_of(proc, struct desktop_shell, screensaver.process);
Ander Conselvan de Oliveira18639f82013-02-15 18:44:19 +02003589
Pekka Paalanen18027e52011-12-02 16:31:49 +02003590 proc->pid = 0;
Ander Conselvan de Oliveira18639f82013-02-15 18:44:19 +02003591
3592 if (shell->locked)
Ander Conselvan de Oliveirab17537e2013-02-22 14:16:18 +02003593 weston_compositor_sleep(shell->compositor);
Pekka Paalanen18027e52011-12-02 16:31:49 +02003594}
3595
3596static void
Tiago Vignattibe143262012-04-16 17:31:41 +03003597launch_screensaver(struct desktop_shell *shell)
Pekka Paalanen77346a62011-11-30 16:26:35 +02003598{
3599 if (shell->screensaver.binding)
3600 return;
3601
Ander Conselvan de Oliveiradda9d782013-02-22 14:16:19 +02003602 if (!shell->screensaver.path) {
3603 weston_compositor_sleep(shell->compositor);
Pekka Paalanene955f1e2011-12-07 11:49:52 +02003604 return;
Ander Conselvan de Oliveiradda9d782013-02-22 14:16:19 +02003605 }
Pekka Paalanene955f1e2011-12-07 11:49:52 +02003606
Kristian Høgsberg32bed572012-03-01 17:11:36 -05003607 if (shell->screensaver.process.pid != 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02003608 weston_log("old screensaver still running\n");
Kristian Høgsberg32bed572012-03-01 17:11:36 -05003609 return;
3610 }
3611
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05003612 weston_client_launch(shell->compositor,
Pekka Paalanen18027e52011-12-02 16:31:49 +02003613 &shell->screensaver.process,
Pekka Paalanene955f1e2011-12-07 11:49:52 +02003614 shell->screensaver.path,
Pekka Paalanen18027e52011-12-02 16:31:49 +02003615 handle_screensaver_sigchld);
Pekka Paalanen77346a62011-11-30 16:26:35 +02003616}
3617
3618static void
Tiago Vignattibe143262012-04-16 17:31:41 +03003619terminate_screensaver(struct desktop_shell *shell)
Pekka Paalanen77346a62011-11-30 16:26:35 +02003620{
Pekka Paalanen18027e52011-12-02 16:31:49 +02003621 if (shell->screensaver.process.pid == 0)
3622 return;
3623
3624 kill(shell->screensaver.process.pid, SIGTERM);
Pekka Paalanen77346a62011-11-30 16:26:35 +02003625}
3626
3627static void
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06003628configure_static_view(struct weston_view *ev, struct weston_layer *layer)
Kristian Høgsberg962342c2012-06-26 16:29:50 -04003629{
Jason Ekstranda7af7042013-10-12 22:38:11 -05003630 struct weston_view *v, *next;
Kristian Høgsberg962342c2012-06-26 16:29:50 -04003631
Jason Ekstranda7af7042013-10-12 22:38:11 -05003632 wl_list_for_each_safe(v, next, &layer->view_list, layer_link) {
3633 if (v->output == ev->output && v != ev) {
3634 weston_view_unmap(v);
3635 v->surface->configure = NULL;
Kristian Høgsberg962342c2012-06-26 16:29:50 -04003636 }
3637 }
3638
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06003639 weston_view_set_position(ev, ev->output->x, ev->output->y);
Kristian Høgsberg962342c2012-06-26 16:29:50 -04003640
Jason Ekstranda7af7042013-10-12 22:38:11 -05003641 if (wl_list_empty(&ev->layer_link)) {
3642 wl_list_insert(&layer->view_list, &ev->layer_link);
3643 weston_compositor_schedule_repaint(ev->surface->compositor);
Kristian Høgsberg962342c2012-06-26 16:29:50 -04003644 }
3645}
3646
3647static void
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06003648background_configure(struct weston_surface *es, int32_t sx, int32_t sy)
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04003649{
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01003650 struct desktop_shell *shell = es->configure_private;
Jason Ekstranda7af7042013-10-12 22:38:11 -05003651 struct weston_view *view;
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04003652
Jason Ekstranda7af7042013-10-12 22:38:11 -05003653 view = container_of(es->views.next, struct weston_view, surface_link);
3654
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06003655 configure_static_view(view, &shell->background_layer);
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04003656}
3657
3658static void
Kristian Høgsberg75840622011-09-06 13:48:16 -04003659desktop_shell_set_background(struct wl_client *client,
3660 struct wl_resource *resource,
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01003661 struct wl_resource *output_resource,
Kristian Høgsberg75840622011-09-06 13:48:16 -04003662 struct wl_resource *surface_resource)
3663{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05003664 struct desktop_shell *shell = wl_resource_get_user_data(resource);
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05003665 struct weston_surface *surface =
3666 wl_resource_get_user_data(surface_resource);
Jason Ekstranda7af7042013-10-12 22:38:11 -05003667 struct weston_view *view, *next;
Kristian Høgsberg75840622011-09-06 13:48:16 -04003668
Kristian Høgsberg962342c2012-06-26 16:29:50 -04003669 if (surface->configure) {
3670 wl_resource_post_error(surface_resource,
3671 WL_DISPLAY_ERROR_INVALID_OBJECT,
3672 "surface role already assigned");
3673 return;
3674 }
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01003675
Jason Ekstranda7af7042013-10-12 22:38:11 -05003676 wl_list_for_each_safe(view, next, &surface->views, surface_link)
3677 weston_view_destroy(view);
3678 view = weston_view_create(surface);
3679
Kristian Høgsberg962342c2012-06-26 16:29:50 -04003680 surface->configure = background_configure;
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01003681 surface->configure_private = shell;
Jason Ekstranda0d2dde2013-06-14 10:08:01 -05003682 surface->output = wl_resource_get_user_data(output_resource);
Jason Ekstranda7af7042013-10-12 22:38:11 -05003683 view->output = surface->output;
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04003684 desktop_shell_send_configure(resource, 0,
Kristian Høgsberg0b5cd0c2012-03-04 21:57:37 -05003685 surface_resource,
Scott Moreau1bad5db2012-08-18 01:04:05 -06003686 surface->output->width,
3687 surface->output->height);
Kristian Høgsberg75840622011-09-06 13:48:16 -04003688}
3689
3690static void
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06003691panel_configure(struct weston_surface *es, int32_t sx, int32_t sy)
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04003692{
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01003693 struct desktop_shell *shell = es->configure_private;
Jason Ekstranda7af7042013-10-12 22:38:11 -05003694 struct weston_view *view;
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04003695
Jason Ekstranda7af7042013-10-12 22:38:11 -05003696 view = container_of(es->views.next, struct weston_view, surface_link);
3697
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06003698 configure_static_view(view, &shell->panel_layer);
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04003699}
3700
3701static void
Kristian Høgsberg75840622011-09-06 13:48:16 -04003702desktop_shell_set_panel(struct wl_client *client,
3703 struct wl_resource *resource,
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01003704 struct wl_resource *output_resource,
Kristian Høgsberg75840622011-09-06 13:48:16 -04003705 struct wl_resource *surface_resource)
3706{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05003707 struct desktop_shell *shell = wl_resource_get_user_data(resource);
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05003708 struct weston_surface *surface =
3709 wl_resource_get_user_data(surface_resource);
Jason Ekstranda7af7042013-10-12 22:38:11 -05003710 struct weston_view *view, *next;
Kristian Høgsberg75840622011-09-06 13:48:16 -04003711
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04003712 if (surface->configure) {
3713 wl_resource_post_error(surface_resource,
3714 WL_DISPLAY_ERROR_INVALID_OBJECT,
3715 "surface role already assigned");
3716 return;
3717 }
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01003718
Jason Ekstranda7af7042013-10-12 22:38:11 -05003719 wl_list_for_each_safe(view, next, &surface->views, surface_link)
3720 weston_view_destroy(view);
3721 view = weston_view_create(surface);
3722
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04003723 surface->configure = panel_configure;
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01003724 surface->configure_private = shell;
Jason Ekstranda0d2dde2013-06-14 10:08:01 -05003725 surface->output = wl_resource_get_user_data(output_resource);
Jason Ekstranda7af7042013-10-12 22:38:11 -05003726 view->output = surface->output;
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04003727 desktop_shell_send_configure(resource, 0,
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04003728 surface_resource,
Scott Moreau1bad5db2012-08-18 01:04:05 -06003729 surface->output->width,
3730 surface->output->height);
Kristian Høgsberg75840622011-09-06 13:48:16 -04003731}
3732
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02003733static void
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06003734lock_surface_configure(struct weston_surface *surface, int32_t sx, int32_t sy)
Kristian Høgsberg730c94d2012-06-26 21:44:35 -04003735{
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01003736 struct desktop_shell *shell = surface->configure_private;
Jason Ekstranda7af7042013-10-12 22:38:11 -05003737 struct weston_view *view;
3738
3739 view = container_of(surface->views.next, struct weston_view, surface_link);
Kristian Høgsberg730c94d2012-06-26 21:44:35 -04003740
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06003741 if (surface->width == 0)
Giulio Camuffo184df502013-02-21 11:29:21 +01003742 return;
3743
Jason Ekstranda7af7042013-10-12 22:38:11 -05003744 center_on_output(view, get_default_output(shell->compositor));
Kristian Høgsberg730c94d2012-06-26 21:44:35 -04003745
3746 if (!weston_surface_is_mapped(surface)) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05003747 wl_list_insert(&shell->lock_layer.view_list,
3748 &view->layer_link);
3749 weston_view_update_transform(view);
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02003750 shell_fade(shell, FADE_IN);
Kristian Høgsberg730c94d2012-06-26 21:44:35 -04003751 }
3752}
3753
3754static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04003755handle_lock_surface_destroy(struct wl_listener *listener, void *data)
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05003756{
Tiago Vignattibe143262012-04-16 17:31:41 +03003757 struct desktop_shell *shell =
3758 container_of(listener, struct desktop_shell, lock_surface_listener);
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05003759
Martin Minarik6d118362012-06-07 18:01:59 +02003760 weston_log("lock surface gone\n");
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05003761 shell->lock_surface = NULL;
3762}
3763
3764static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02003765desktop_shell_set_lock_surface(struct wl_client *client,
3766 struct wl_resource *resource,
3767 struct wl_resource *surface_resource)
3768{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05003769 struct desktop_shell *shell = wl_resource_get_user_data(resource);
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05003770 struct weston_surface *surface =
3771 wl_resource_get_user_data(surface_resource);
Pekka Paalanen98262232011-12-01 10:42:22 +02003772
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02003773 shell->prepare_event_sent = false;
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +02003774
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02003775 if (!shell->locked)
3776 return;
3777
Pekka Paalanen98262232011-12-01 10:42:22 +02003778 shell->lock_surface = surface;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02003779
Kristian Høgsberg27e30522012-04-11 23:18:23 -04003780 shell->lock_surface_listener.notify = handle_lock_surface_destroy;
Jason Ekstrand651f00e2013-06-14 10:07:54 -05003781 wl_signal_add(&surface->destroy_signal,
Kristian Høgsberg27e30522012-04-11 23:18:23 -04003782 &shell->lock_surface_listener);
Pekka Paalanen57da4a82011-11-23 16:42:16 +02003783
Kristian Høgsbergaa2ee8b2013-10-30 15:49:45 -07003784 weston_view_create(surface);
Kristian Høgsberg730c94d2012-06-26 21:44:35 -04003785 surface->configure = lock_surface_configure;
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01003786 surface->configure_private = shell;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02003787}
3788
3789static void
Tiago Vignattibe143262012-04-16 17:31:41 +03003790resume_desktop(struct desktop_shell *shell)
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02003791{
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04003792 struct workspace *ws = get_current_workspace(shell);
Pekka Paalanen77346a62011-11-30 16:26:35 +02003793
Pekka Paalanen77346a62011-11-30 16:26:35 +02003794 terminate_screensaver(shell);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02003795
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05003796 wl_list_remove(&shell->lock_layer.link);
3797 wl_list_insert(&shell->compositor->cursor_layer.link,
3798 &shell->fullscreen_layer.link);
3799 wl_list_insert(&shell->fullscreen_layer.link,
3800 &shell->panel_layer.link);
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02003801 if (shell->showing_input_panels) {
3802 wl_list_insert(&shell->panel_layer.link,
3803 &shell->input_panel_layer.link);
3804 wl_list_insert(&shell->input_panel_layer.link,
3805 &ws->layer.link);
3806 } else {
3807 wl_list_insert(&shell->panel_layer.link, &ws->layer.link);
3808 }
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02003809
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -04003810 restore_focus_state(shell, get_current_workspace(shell));
Jonas Ådahl04769742012-06-13 00:01:24 +02003811
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02003812 shell->locked = false;
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02003813 shell_fade(shell, FADE_IN);
Pekka Paalanenfc6d91a2012-02-10 15:33:10 +02003814 weston_compositor_damage_all(shell->compositor);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02003815}
3816
3817static void
3818desktop_shell_unlock(struct wl_client *client,
3819 struct wl_resource *resource)
3820{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05003821 struct desktop_shell *shell = wl_resource_get_user_data(resource);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02003822
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02003823 shell->prepare_event_sent = false;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02003824
3825 if (shell->locked)
3826 resume_desktop(shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02003827}
3828
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04003829static void
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03003830desktop_shell_set_grab_surface(struct wl_client *client,
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04003831 struct wl_resource *resource,
3832 struct wl_resource *surface_resource)
3833{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05003834 struct desktop_shell *shell = wl_resource_get_user_data(resource);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04003835
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05003836 shell->grab_surface = wl_resource_get_user_data(surface_resource);
Kristian Høgsberg48588f82013-10-24 15:51:35 -07003837 weston_view_create(shell->grab_surface);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04003838}
3839
Pekka Paalanen79346ab2013-05-22 18:03:09 +03003840static void
3841desktop_shell_desktop_ready(struct wl_client *client,
3842 struct wl_resource *resource)
3843{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05003844 struct desktop_shell *shell = wl_resource_get_user_data(resource);
Pekka Paalanen79346ab2013-05-22 18:03:09 +03003845
3846 shell_fade_startup(shell);
3847}
3848
Kristian Høgsberg75840622011-09-06 13:48:16 -04003849static const struct desktop_shell_interface desktop_shell_implementation = {
3850 desktop_shell_set_background,
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02003851 desktop_shell_set_panel,
3852 desktop_shell_set_lock_surface,
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04003853 desktop_shell_unlock,
Pekka Paalanen79346ab2013-05-22 18:03:09 +03003854 desktop_shell_set_grab_surface,
3855 desktop_shell_desktop_ready
Kristian Høgsberg75840622011-09-06 13:48:16 -04003856};
3857
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02003858static enum shell_surface_type
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05003859get_shell_surface_type(struct weston_surface *surface)
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02003860{
3861 struct shell_surface *shsurf;
3862
3863 shsurf = get_shell_surface(surface);
3864 if (!shsurf)
Pekka Paalanen98262232011-12-01 10:42:22 +02003865 return SHELL_SURFACE_NONE;
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02003866 return shsurf->type;
3867}
3868
Kristian Høgsberg75840622011-09-06 13:48:16 -04003869static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04003870move_binding(struct weston_seat *seat, uint32_t time, uint32_t button, void *data)
Kristian Høgsberg07937562011-04-12 17:25:42 -04003871{
Rafal Mielniczukb2917a22014-01-05 20:04:59 +01003872 struct weston_surface *focus;
Pekka Paalanen01388e22013-04-25 13:57:44 +03003873 struct weston_surface *surface;
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04003874 struct shell_surface *shsurf;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -05003875
Rafal Mielniczukb2917a22014-01-05 20:04:59 +01003876 if (seat->pointer->focus == NULL)
3877 return;
3878
3879 focus = seat->pointer->focus->surface;
3880
Pekka Paalanen01388e22013-04-25 13:57:44 +03003881 surface = weston_surface_get_main_surface(focus);
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01003882 if (surface == NULL)
3883 return;
Kristian Høgsberg07937562011-04-12 17:25:42 -04003884
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04003885 shsurf = get_shell_surface(surface);
Rafael Antognolli03b16592013-12-03 15:35:42 -02003886 if (shsurf == NULL || shsurf->state.fullscreen ||
3887 shsurf->state.maximized)
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04003888 return;
3889
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04003890 surface_move(shsurf, (struct weston_seat *) seat);
Kristian Høgsberg07937562011-04-12 17:25:42 -04003891}
3892
3893static void
Rafael Antognolliea997ac2013-12-03 15:35:48 -02003894maximize_binding(struct weston_seat *seat, uint32_t time, uint32_t button, void *data)
3895{
Emilio Pozuelo Monfort38b58eb2014-01-29 11:11:12 +01003896 struct weston_surface *focus = seat->keyboard->focus;
Rafael Antognolliea997ac2013-12-03 15:35:48 -02003897 struct weston_surface *surface;
3898 struct shell_surface *shsurf;
Kristian Høgsberg283bf372014-02-18 23:28:09 -08003899 uint32_t serial;
Rafael Antognolliea997ac2013-12-03 15:35:48 -02003900
3901 surface = weston_surface_get_main_surface(focus);
3902 if (surface == NULL)
3903 return;
3904
3905 shsurf = get_shell_surface(surface);
3906 if (shsurf == NULL)
3907 return;
3908
3909 if (!shell_surface_is_xdg_surface(shsurf))
3910 return;
3911
Kristian Høgsberg283bf372014-02-18 23:28:09 -08003912 serial = wl_display_next_serial(seat->compositor->wl_display);
3913 xdg_surface_change_state(shsurf, XDG_SURFACE_STATE_MAXIMIZED,
3914 !shsurf->state.maximized, serial);
Rafael Antognolliea997ac2013-12-03 15:35:48 -02003915}
3916
3917static void
3918fullscreen_binding(struct weston_seat *seat, uint32_t time, uint32_t button, void *data)
3919{
Emilio Pozuelo Monfort38b58eb2014-01-29 11:11:12 +01003920 struct weston_surface *focus = seat->keyboard->focus;
Rafael Antognolliea997ac2013-12-03 15:35:48 -02003921 struct weston_surface *surface;
3922 struct shell_surface *shsurf;
Kristian Høgsberg283bf372014-02-18 23:28:09 -08003923 uint32_t serial;
Rafael Antognolliea997ac2013-12-03 15:35:48 -02003924
3925 surface = weston_surface_get_main_surface(focus);
3926 if (surface == NULL)
3927 return;
3928
3929 shsurf = get_shell_surface(surface);
3930 if (shsurf == NULL)
3931 return;
3932
3933 if (!shell_surface_is_xdg_surface(shsurf))
3934 return;
3935
Kristian Høgsberg283bf372014-02-18 23:28:09 -08003936 serial = wl_display_next_serial(seat->compositor->wl_display);
3937 xdg_surface_change_state(shsurf, XDG_SURFACE_STATE_FULLSCREEN,
3938 !shsurf->state.fullscreen, serial);
Rafael Antognolliea997ac2013-12-03 15:35:48 -02003939}
3940
3941static void
Neil Robertsaba0f252013-10-03 16:43:05 +01003942touch_move_binding(struct weston_seat *seat, uint32_t time, void *data)
3943{
Kristian Høgsberg7ab139c2013-10-24 16:21:39 -07003944 struct weston_surface *focus = seat->touch->focus->surface;
Neil Robertsaba0f252013-10-03 16:43:05 +01003945 struct weston_surface *surface;
3946 struct shell_surface *shsurf;
3947
3948 surface = weston_surface_get_main_surface(focus);
3949 if (surface == NULL)
3950 return;
3951
3952 shsurf = get_shell_surface(surface);
Rafael Antognolli03b16592013-12-03 15:35:42 -02003953 if (shsurf == NULL || shsurf->state.fullscreen ||
3954 shsurf->state.maximized)
Neil Robertsaba0f252013-10-03 16:43:05 +01003955 return;
3956
3957 surface_touch_move(shsurf, (struct weston_seat *) seat);
3958}
3959
3960static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04003961resize_binding(struct weston_seat *seat, uint32_t time, uint32_t button, void *data)
Kristian Høgsberg07937562011-04-12 17:25:42 -04003962{
Rafal Mielniczukb2917a22014-01-05 20:04:59 +01003963 struct weston_surface *focus;
Pekka Paalanen01388e22013-04-25 13:57:44 +03003964 struct weston_surface *surface;
Kristian Høgsberg07937562011-04-12 17:25:42 -04003965 uint32_t edges = 0;
3966 int32_t x, y;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003967 struct shell_surface *shsurf;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -05003968
Rafal Mielniczukb2917a22014-01-05 20:04:59 +01003969 if (seat->pointer->focus == NULL)
3970 return;
3971
3972 focus = seat->pointer->focus->surface;
3973
Pekka Paalanen01388e22013-04-25 13:57:44 +03003974 surface = weston_surface_get_main_surface(focus);
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01003975 if (surface == NULL)
3976 return;
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02003977
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003978 shsurf = get_shell_surface(surface);
Rafael Antognolli03b16592013-12-03 15:35:42 -02003979 if (shsurf == NULL || shsurf->state.fullscreen ||
3980 shsurf->state.maximized)
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02003981 return;
3982
Jason Ekstranda7af7042013-10-12 22:38:11 -05003983 weston_view_from_global(shsurf->view,
3984 wl_fixed_to_int(seat->pointer->grab_x),
3985 wl_fixed_to_int(seat->pointer->grab_y),
3986 &x, &y);
Kristian Høgsberg07937562011-04-12 17:25:42 -04003987
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06003988 if (x < shsurf->surface->width / 3)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003989 edges |= WL_SHELL_SURFACE_RESIZE_LEFT;
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06003990 else if (x < 2 * shsurf->surface->width / 3)
Kristian Høgsberg07937562011-04-12 17:25:42 -04003991 edges |= 0;
3992 else
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003993 edges |= WL_SHELL_SURFACE_RESIZE_RIGHT;
Kristian Høgsberg07937562011-04-12 17:25:42 -04003994
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06003995 if (y < shsurf->surface->height / 3)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003996 edges |= WL_SHELL_SURFACE_RESIZE_TOP;
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06003997 else if (y < 2 * shsurf->surface->height / 3)
Kristian Høgsberg07937562011-04-12 17:25:42 -04003998 edges |= 0;
3999 else
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02004000 edges |= WL_SHELL_SURFACE_RESIZE_BOTTOM;
Kristian Høgsberg07937562011-04-12 17:25:42 -04004001
Kristian Høgsbergc1693f22012-05-22 16:56:23 -04004002 surface_resize(shsurf, (struct weston_seat *) seat, edges);
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04004003}
4004
4005static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04004006surface_opacity_binding(struct weston_seat *seat, uint32_t time, uint32_t axis,
Daniel Stone0c1e46e2012-05-30 16:31:59 +01004007 wl_fixed_t value, void *data)
Scott Moreaua3aa9c92012-03-22 11:01:03 -06004008{
Jonas Ådahlb0b87ba2012-09-27 18:40:42 +02004009 float step = 0.005;
Scott Moreaua3aa9c92012-03-22 11:01:03 -06004010 struct shell_surface *shsurf;
Kristian Høgsberg7ab139c2013-10-24 16:21:39 -07004011 struct weston_surface *focus = seat->pointer->focus->surface;
Pekka Paalanen01388e22013-04-25 13:57:44 +03004012 struct weston_surface *surface;
Scott Moreaua3aa9c92012-03-22 11:01:03 -06004013
Pekka Paalanen01388e22013-04-25 13:57:44 +03004014 /* XXX: broken for windows containing sub-surfaces */
4015 surface = weston_surface_get_main_surface(focus);
Scott Moreaua3aa9c92012-03-22 11:01:03 -06004016 if (surface == NULL)
4017 return;
4018
4019 shsurf = get_shell_surface(surface);
4020 if (!shsurf)
4021 return;
4022
Jason Ekstranda7af7042013-10-12 22:38:11 -05004023 shsurf->view->alpha -= wl_fixed_to_double(value) * step;
Scott Moreaua3aa9c92012-03-22 11:01:03 -06004024
Jason Ekstranda7af7042013-10-12 22:38:11 -05004025 if (shsurf->view->alpha > 1.0)
4026 shsurf->view->alpha = 1.0;
4027 if (shsurf->view->alpha < step)
4028 shsurf->view->alpha = step;
Scott Moreaua3aa9c92012-03-22 11:01:03 -06004029
Jason Ekstranda7af7042013-10-12 22:38:11 -05004030 weston_view_geometry_dirty(shsurf->view);
Scott Moreaua3aa9c92012-03-22 11:01:03 -06004031 weston_surface_damage(surface);
4032}
4033
4034static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04004035do_zoom(struct weston_seat *seat, uint32_t time, uint32_t key, uint32_t axis,
Daniel Stone0c1e46e2012-05-30 16:31:59 +01004036 wl_fixed_t value)
Scott Moreauccbf29d2012-02-22 14:21:41 -07004037{
Daniel Stone37816df2012-05-16 18:45:18 +01004038 struct weston_seat *ws = (struct weston_seat *) seat;
4039 struct weston_compositor *compositor = ws->compositor;
Scott Moreauccbf29d2012-02-22 14:21:41 -07004040 struct weston_output *output;
Scott Moreaue6603982012-06-11 13:07:51 -06004041 float increment;
Scott Moreauccbf29d2012-02-22 14:21:41 -07004042
4043 wl_list_for_each(output, &compositor->output_list, link) {
4044 if (pixman_region32_contains_point(&output->region,
Daniel Stone37816df2012-05-16 18:45:18 +01004045 wl_fixed_to_double(seat->pointer->x),
4046 wl_fixed_to_double(seat->pointer->y),
Daniel Stone103db7f2012-05-08 17:17:55 +01004047 NULL)) {
Daniel Stone325fc2d2012-05-30 16:31:58 +01004048 if (key == KEY_PAGEUP)
Kristian Høgsberg9b68af02012-05-22 12:55:18 -04004049 increment = output->zoom.increment;
Daniel Stone325fc2d2012-05-30 16:31:58 +01004050 else if (key == KEY_PAGEDOWN)
Kristian Høgsberg9b68af02012-05-22 12:55:18 -04004051 increment = -output->zoom.increment;
4052 else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
Jonas Ådahlb0b87ba2012-09-27 18:40:42 +02004053 /* For every pixel zoom 20th of a step */
Daniel Stone0c1e46e2012-05-30 16:31:59 +01004054 increment = output->zoom.increment *
Jonas Ådahlb0b87ba2012-09-27 18:40:42 +02004055 -wl_fixed_to_double(value) / 20.0;
Kristian Høgsberg9b68af02012-05-22 12:55:18 -04004056 else
4057 increment = 0;
4058
Kristian Høgsberg9b68af02012-05-22 12:55:18 -04004059 output->zoom.level += increment;
Scott Moreauc6d7f602012-02-23 22:28:37 -07004060
Scott Moreaue6603982012-06-11 13:07:51 -06004061 if (output->zoom.level < 0.0)
Scott Moreau850ca422012-05-21 15:21:25 -06004062 output->zoom.level = 0.0;
Scott Moreaue6603982012-06-11 13:07:51 -06004063 else if (output->zoom.level > output->zoom.max_level)
4064 output->zoom.level = output->zoom.max_level;
Ville Syrjäläaa628d02012-11-16 11:48:47 +02004065 else if (!output->zoom.active) {
Giulio Camuffo412b0242013-11-14 23:42:51 +01004066 weston_output_activate_zoom(output);
Kristian Høgsberg79af73e2012-08-03 15:45:23 -04004067 }
Scott Moreauccbf29d2012-02-22 14:21:41 -07004068
Scott Moreaue6603982012-06-11 13:07:51 -06004069 output->zoom.spring_z.target = output->zoom.level;
Scott Moreauccbf29d2012-02-22 14:21:41 -07004070
Jason Ekstranda7af7042013-10-12 22:38:11 -05004071 weston_output_update_zoom(output);
Scott Moreauccbf29d2012-02-22 14:21:41 -07004072 }
4073 }
4074}
4075
Scott Moreauccbf29d2012-02-22 14:21:41 -07004076static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04004077zoom_axis_binding(struct weston_seat *seat, uint32_t time, uint32_t axis,
Daniel Stone0c1e46e2012-05-30 16:31:59 +01004078 wl_fixed_t value, void *data)
Daniel Stone325fc2d2012-05-30 16:31:58 +01004079{
4080 do_zoom(seat, time, 0, axis, value);
4081}
4082
4083static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04004084zoom_key_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
Daniel Stone325fc2d2012-05-30 16:31:58 +01004085 void *data)
4086{
4087 do_zoom(seat, time, key, 0, 0);
4088}
4089
4090static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04004091terminate_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
Daniel Stone325fc2d2012-05-30 16:31:58 +01004092 void *data)
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05004093{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05004094 struct weston_compositor *compositor = data;
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05004095
Daniel Stone325fc2d2012-05-30 16:31:58 +01004096 wl_display_terminate(compositor->wl_display);
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05004097}
4098
Emilio Pozuelo Monfort03251b62013-11-19 11:37:16 +01004099static void
Giulio Camuffo1959ab82013-11-14 23:42:52 +01004100rotate_grab_motion(struct weston_pointer_grab *grab, uint32_t time,
4101 wl_fixed_t x, wl_fixed_t y)
Pekka Paalanen460099f2012-01-20 16:48:25 +02004102{
4103 struct rotate_grab *rotate =
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004104 container_of(grab, struct rotate_grab, base.grab);
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04004105 struct weston_pointer *pointer = grab->pointer;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004106 struct shell_surface *shsurf = rotate->base.shsurf;
John Kåre Alsaker490d02a2012-09-30 02:57:21 +02004107 float cx, cy, dx, dy, cposx, cposy, dposx, dposy, r;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004108
Giulio Camuffo1959ab82013-11-14 23:42:52 +01004109 weston_pointer_move(pointer, x, y);
4110
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004111 if (!shsurf)
4112 return;
4113
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004114 cx = 0.5f * shsurf->surface->width;
4115 cy = 0.5f * shsurf->surface->height;
Pekka Paalanen460099f2012-01-20 16:48:25 +02004116
Daniel Stone37816df2012-05-16 18:45:18 +01004117 dx = wl_fixed_to_double(pointer->x) - rotate->center.x;
4118 dy = wl_fixed_to_double(pointer->y) - rotate->center.y;
Pekka Paalanen460099f2012-01-20 16:48:25 +02004119 r = sqrtf(dx * dx + dy * dy);
4120
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004121 wl_list_remove(&shsurf->rotation.transform.link);
Jason Ekstranda7af7042013-10-12 22:38:11 -05004122 weston_view_geometry_dirty(shsurf->view);
Pekka Paalanen460099f2012-01-20 16:48:25 +02004123
4124 if (r > 20.0f) {
Pekka Paalanen460099f2012-01-20 16:48:25 +02004125 struct weston_matrix *matrix =
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004126 &shsurf->rotation.transform.matrix;
Pekka Paalanen460099f2012-01-20 16:48:25 +02004127
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05004128 weston_matrix_init(&rotate->rotation);
Vasily Khoruzhick1bbf3722013-01-28 22:40:28 +03004129 weston_matrix_rotate_xy(&rotate->rotation, dx / r, dy / r);
Pekka Paalanen460099f2012-01-20 16:48:25 +02004130
4131 weston_matrix_init(matrix);
Pekka Paalanen7b3bd3d2012-01-30 14:16:34 +02004132 weston_matrix_translate(matrix, -cx, -cy, 0.0f);
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004133 weston_matrix_multiply(matrix, &shsurf->rotation.rotation);
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05004134 weston_matrix_multiply(matrix, &rotate->rotation);
Pekka Paalanen7b3bd3d2012-01-30 14:16:34 +02004135 weston_matrix_translate(matrix, cx, cy, 0.0f);
Pekka Paalanen460099f2012-01-20 16:48:25 +02004136
Pekka Paalanenbc0b7e72012-01-24 09:53:37 +02004137 wl_list_insert(
Jason Ekstranda7af7042013-10-12 22:38:11 -05004138 &shsurf->view->geometry.transformation_list,
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004139 &shsurf->rotation.transform.link);
Pekka Paalanen460099f2012-01-20 16:48:25 +02004140 } else {
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004141 wl_list_init(&shsurf->rotation.transform.link);
4142 weston_matrix_init(&shsurf->rotation.rotation);
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05004143 weston_matrix_init(&rotate->rotation);
Pekka Paalanen460099f2012-01-20 16:48:25 +02004144 }
Pekka Paalanenb45ac5e2012-02-09 15:58:44 +02004145
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01004146 /* We need to adjust the position of the surface
4147 * in case it was resized in a rotated state before */
Jason Ekstranda7af7042013-10-12 22:38:11 -05004148 cposx = shsurf->view->geometry.x + cx;
4149 cposy = shsurf->view->geometry.y + cy;
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01004150 dposx = rotate->center.x - cposx;
4151 dposy = rotate->center.y - cposy;
4152 if (dposx != 0.0f || dposy != 0.0f) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05004153 weston_view_set_position(shsurf->view,
4154 shsurf->view->geometry.x + dposx,
4155 shsurf->view->geometry.y + dposy);
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01004156 }
4157
Pekka Paalanenb45ac5e2012-02-09 15:58:44 +02004158 /* Repaint implies weston_surface_update_transform(), which
4159 * lazily applies the damage due to rotation update.
4160 */
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004161 weston_compositor_schedule_repaint(shsurf->surface->compositor);
Pekka Paalanen460099f2012-01-20 16:48:25 +02004162}
4163
4164static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04004165rotate_grab_button(struct weston_pointer_grab *grab,
4166 uint32_t time, uint32_t button, uint32_t state_w)
Pekka Paalanen460099f2012-01-20 16:48:25 +02004167{
4168 struct rotate_grab *rotate =
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004169 container_of(grab, struct rotate_grab, base.grab);
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04004170 struct weston_pointer *pointer = grab->pointer;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004171 struct shell_surface *shsurf = rotate->base.shsurf;
Daniel Stone4dbadb12012-05-30 16:31:51 +01004172 enum wl_pointer_button_state state = state_w;
Pekka Paalanen460099f2012-01-20 16:48:25 +02004173
Daniel Stone4dbadb12012-05-30 16:31:51 +01004174 if (pointer->button_count == 0 &&
4175 state == WL_POINTER_BUTTON_STATE_RELEASED) {
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004176 if (shsurf)
4177 weston_matrix_multiply(&shsurf->rotation.rotation,
4178 &rotate->rotation);
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03004179 shell_grab_end(&rotate->base);
Pekka Paalanen460099f2012-01-20 16:48:25 +02004180 free(rotate);
4181 }
4182}
4183
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02004184static void
4185rotate_grab_cancel(struct weston_pointer_grab *grab)
4186{
4187 struct rotate_grab *rotate =
4188 container_of(grab, struct rotate_grab, base.grab);
4189
4190 shell_grab_end(&rotate->base);
4191 free(rotate);
4192}
4193
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04004194static const struct weston_pointer_grab_interface rotate_grab_interface = {
Pekka Paalanen460099f2012-01-20 16:48:25 +02004195 noop_grab_focus,
4196 rotate_grab_motion,
4197 rotate_grab_button,
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02004198 rotate_grab_cancel,
Pekka Paalanen460099f2012-01-20 16:48:25 +02004199};
4200
4201static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04004202surface_rotate(struct shell_surface *surface, struct weston_seat *seat)
Pekka Paalanen460099f2012-01-20 16:48:25 +02004203{
Pekka Paalanen460099f2012-01-20 16:48:25 +02004204 struct rotate_grab *rotate;
John Kåre Alsaker490d02a2012-09-30 02:57:21 +02004205 float dx, dy;
4206 float r;
Pekka Paalanen460099f2012-01-20 16:48:25 +02004207
Pekka Paalanen460099f2012-01-20 16:48:25 +02004208 rotate = malloc(sizeof *rotate);
4209 if (!rotate)
4210 return;
4211
Jason Ekstranda7af7042013-10-12 22:38:11 -05004212 weston_view_to_global_float(surface->view,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004213 surface->surface->width * 0.5f,
4214 surface->surface->height * 0.5f,
Jason Ekstranda7af7042013-10-12 22:38:11 -05004215 &rotate->center.x, &rotate->center.y);
Pekka Paalanen460099f2012-01-20 16:48:25 +02004216
Daniel Stone37816df2012-05-16 18:45:18 +01004217 dx = wl_fixed_to_double(seat->pointer->x) - rotate->center.x;
4218 dy = wl_fixed_to_double(seat->pointer->y) - rotate->center.y;
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05004219 r = sqrtf(dx * dx + dy * dy);
4220 if (r > 20.0f) {
4221 struct weston_matrix inverse;
4222
4223 weston_matrix_init(&inverse);
Vasily Khoruzhick1bbf3722013-01-28 22:40:28 +03004224 weston_matrix_rotate_xy(&inverse, dx / r, -dy / r);
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05004225 weston_matrix_multiply(&surface->rotation.rotation, &inverse);
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01004226
4227 weston_matrix_init(&rotate->rotation);
Vasily Khoruzhick1bbf3722013-01-28 22:40:28 +03004228 weston_matrix_rotate_xy(&rotate->rotation, dx / r, dy / r);
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05004229 } else {
4230 weston_matrix_init(&surface->rotation.rotation);
4231 weston_matrix_init(&rotate->rotation);
4232 }
4233
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03004234 shell_grab_start(&rotate->base, &rotate_grab_interface, surface,
4235 seat->pointer, DESKTOP_SHELL_CURSOR_ARROW);
Pekka Paalanen460099f2012-01-20 16:48:25 +02004236}
4237
4238static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04004239rotate_binding(struct weston_seat *seat, uint32_t time, uint32_t button,
Kristian Høgsberg0c369032013-02-14 21:31:44 -05004240 void *data)
4241{
Rafal Mielniczukb2917a22014-01-05 20:04:59 +01004242 struct weston_surface *focus;
Pekka Paalanen01388e22013-04-25 13:57:44 +03004243 struct weston_surface *base_surface;
Kristian Høgsberg0c369032013-02-14 21:31:44 -05004244 struct shell_surface *surface;
4245
Rafal Mielniczukb2917a22014-01-05 20:04:59 +01004246 if (seat->pointer->focus == NULL)
4247 return;
4248
4249 focus = seat->pointer->focus->surface;
4250
Pekka Paalanen01388e22013-04-25 13:57:44 +03004251 base_surface = weston_surface_get_main_surface(focus);
Kristian Høgsberg0c369032013-02-14 21:31:44 -05004252 if (base_surface == NULL)
4253 return;
4254
4255 surface = get_shell_surface(base_surface);
Rafael Antognolli03b16592013-12-03 15:35:42 -02004256 if (surface == NULL || surface->state.fullscreen ||
4257 surface->state.maximized)
Kristian Høgsberg0c369032013-02-14 21:31:44 -05004258 return;
4259
4260 surface_rotate(surface, seat);
4261}
4262
Philip Withnall83ffd9d2013-11-25 18:01:42 +00004263/* Move all fullscreen layers down to the current workspace in a non-reversible
4264 * manner. This should be used when implementing shell-wide overlays, such as
4265 * the alt-tab switcher, which need to de-promote fullscreen layers. */
Kristian Høgsberg1ef23132013-12-04 00:20:01 -08004266void
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04004267lower_fullscreen_layer(struct desktop_shell *shell)
4268{
4269 struct workspace *ws;
Jason Ekstranda7af7042013-10-12 22:38:11 -05004270 struct weston_view *view, *prev;
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04004271
4272 ws = get_current_workspace(shell);
Jason Ekstranda7af7042013-10-12 22:38:11 -05004273 wl_list_for_each_reverse_safe(view, prev,
4274 &shell->fullscreen_layer.view_list,
Philip Withnall83ffd9d2013-11-25 18:01:42 +00004275 layer_link) {
4276 wl_list_remove(&view->layer_link);
4277 wl_list_insert(&ws->layer.view_list, &view->layer_link);
4278 weston_view_damage_below(view);
4279 weston_surface_damage(view->surface);
4280 }
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04004281}
4282
Kristian Høgsberg1ef23132013-12-04 00:20:01 -08004283void
Tiago Vignattibe143262012-04-16 17:31:41 +03004284activate(struct desktop_shell *shell, struct weston_surface *es,
Daniel Stone37816df2012-05-16 18:45:18 +01004285 struct weston_seat *seat)
Kristian Høgsberg75840622011-09-06 13:48:16 -04004286{
Pekka Paalanen01388e22013-04-25 13:57:44 +03004287 struct weston_surface *main_surface;
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -04004288 struct focus_state *state;
Jonas Ådahl8538b222012-08-29 22:13:03 +02004289 struct workspace *ws;
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01004290 struct weston_surface *old_es;
Rafael Antognolli03b16592013-12-03 15:35:42 -02004291 struct shell_surface *shsurf;
Kristian Høgsberg75840622011-09-06 13:48:16 -04004292
Pekka Paalanen01388e22013-04-25 13:57:44 +03004293 main_surface = weston_surface_get_main_surface(es);
4294
Daniel Stone37816df2012-05-16 18:45:18 +01004295 weston_surface_activate(es, seat);
Kristian Høgsberg75840622011-09-06 13:48:16 -04004296
Jonas Ådahl8538b222012-08-29 22:13:03 +02004297 state = ensure_focus_state(shell, seat);
4298 if (state == NULL)
4299 return;
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -04004300
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01004301 old_es = state->keyboard_focus;
Kristian Høgsbergd500bf12014-01-22 12:25:20 -08004302 focus_state_set_focus(state, es);
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -04004303
Rafael Antognolli03b16592013-12-03 15:35:42 -02004304 shsurf = get_shell_surface(main_surface);
U. Artie Eoffcf5737a2014-01-17 10:08:25 -08004305 assert(shsurf);
4306
Rafael Antognolli03b16592013-12-03 15:35:42 -02004307 if (shsurf->state.fullscreen)
4308 shell_configure_fullscreen(shsurf);
4309 else
Alexander Larssonf82b6ca2013-05-28 16:23:39 +02004310 restore_all_output_modes(shell->compositor);
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01004311
Emilio Pozuelo Monfort7908bff2014-01-30 13:49:39 +01004312 /* Update the surface’s layer. This brings it to the top of the stacking
4313 * order as appropriate. */
4314 shell_surface_update_layer(shsurf);
4315
Philip Withnall83ffd9d2013-11-25 18:01:42 +00004316 if (shell->focus_animation_type != ANIMATION_NONE) {
4317 ws = get_current_workspace(shell);
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01004318 animate_focus_change(shell, ws, get_default_view(old_es), get_default_view(es));
Philip Withnall83ffd9d2013-11-25 18:01:42 +00004319 }
Kristian Høgsberg75840622011-09-06 13:48:16 -04004320}
4321
Alex Wu21858432012-04-01 20:13:08 +08004322/* no-op func for checking black surface */
4323static void
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004324black_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
Alex Wu21858432012-04-01 20:13:08 +08004325{
4326}
4327
Quentin Glidicc0d79ce2013-01-29 14:16:13 +01004328static bool
Alex Wu21858432012-04-01 20:13:08 +08004329is_black_surface (struct weston_surface *es, struct weston_surface **fs_surface)
4330{
4331 if (es->configure == black_surface_configure) {
4332 if (fs_surface)
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01004333 *fs_surface = (struct weston_surface *)es->configure_private;
Alex Wu21858432012-04-01 20:13:08 +08004334 return true;
4335 }
4336 return false;
4337}
4338
Kristian Høgsberg75840622011-09-06 13:48:16 -04004339static void
Neil Robertsa28c6932013-10-03 16:43:04 +01004340activate_binding(struct weston_seat *seat,
4341 struct desktop_shell *shell,
4342 struct weston_surface *focus)
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05004343{
Pekka Paalanen01388e22013-04-25 13:57:44 +03004344 struct weston_surface *main_surface;
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05004345
Alex Wu9c35e6b2012-03-05 14:13:13 +08004346 if (!focus)
4347 return;
4348
Pekka Paalanen01388e22013-04-25 13:57:44 +03004349 if (is_black_surface(focus, &main_surface))
4350 focus = main_surface;
Alex Wu4539b082012-03-01 12:57:46 +08004351
Pekka Paalanen01388e22013-04-25 13:57:44 +03004352 main_surface = weston_surface_get_main_surface(focus);
4353 if (get_shell_surface_type(main_surface) == SHELL_SURFACE_NONE)
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04004354 return;
Kristian Høgsberg85b2e4b2012-06-21 16:49:42 -04004355
Neil Robertsa28c6932013-10-03 16:43:04 +01004356 activate(shell, focus, seat);
4357}
4358
4359static void
4360click_to_activate_binding(struct weston_seat *seat, uint32_t time, uint32_t button,
4361 void *data)
4362{
4363 if (seat->pointer->grab != &seat->pointer->default_grab)
4364 return;
Kristian Høgsberg7c4f6cc2014-01-01 16:28:32 -08004365 if (seat->pointer->focus == NULL)
4366 return;
Neil Robertsa28c6932013-10-03 16:43:04 +01004367
Kristian Høgsberg7ab139c2013-10-24 16:21:39 -07004368 activate_binding(seat, data, seat->pointer->focus->surface);
Neil Robertsa28c6932013-10-03 16:43:04 +01004369}
4370
4371static void
4372touch_to_activate_binding(struct weston_seat *seat, uint32_t time, void *data)
4373{
4374 if (seat->touch->grab != &seat->touch->default_grab)
4375 return;
Kristian Høgsberg0ed67502014-01-02 23:00:11 -08004376 if (seat->touch->focus == NULL)
4377 return;
Neil Robertsa28c6932013-10-03 16:43:04 +01004378
Kristian Høgsberg7ab139c2013-10-24 16:21:39 -07004379 activate_binding(seat, data, seat->touch->focus->surface);
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05004380}
4381
4382static void
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004383lock(struct desktop_shell *shell)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04004384{
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04004385 struct workspace *ws = get_current_workspace(shell);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02004386
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004387 if (shell->locked) {
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02004388 weston_compositor_sleep(shell->compositor);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02004389 return;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004390 }
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02004391
4392 shell->locked = true;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02004393
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05004394 /* Hide all surfaces by removing the fullscreen, panel and
4395 * toplevel layers. This way nothing else can show or receive
4396 * input events while we are locked. */
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02004397
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05004398 wl_list_remove(&shell->panel_layer.link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05004399 wl_list_remove(&shell->fullscreen_layer.link);
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02004400 if (shell->showing_input_panels)
4401 wl_list_remove(&shell->input_panel_layer.link);
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04004402 wl_list_remove(&ws->layer.link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05004403 wl_list_insert(&shell->compositor->cursor_layer.link,
4404 &shell->lock_layer.link);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02004405
Pekka Paalanen77346a62011-11-30 16:26:35 +02004406 launch_screensaver(shell);
4407
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02004408 /* TODO: disable bindings that should not work while locked. */
4409
4410 /* All this must be undone in resume_desktop(). */
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02004411}
4412
4413static void
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004414unlock(struct desktop_shell *shell)
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02004415{
Pekka Paalanend81c2162011-11-16 13:47:34 +02004416 if (!shell->locked || shell->lock_surface) {
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02004417 shell_fade(shell, FADE_IN);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02004418 return;
4419 }
4420
4421 /* If desktop-shell client has gone away, unlock immediately. */
4422 if (!shell->child.desktop_shell) {
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02004423 resume_desktop(shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02004424 return;
4425 }
4426
4427 if (shell->prepare_event_sent)
4428 return;
4429
Kristian Høgsberg0b5cd0c2012-03-04 21:57:37 -05004430 desktop_shell_send_prepare_lock_surface(shell->child.desktop_shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02004431 shell->prepare_event_sent = true;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04004432}
4433
4434static void
Jason Ekstranda7af7042013-10-12 22:38:11 -05004435shell_fade_done(struct weston_view_animation *animation, void *data)
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004436{
4437 struct desktop_shell *shell = data;
4438
4439 shell->fade.animation = NULL;
4440
4441 switch (shell->fade.type) {
4442 case FADE_IN:
Jason Ekstranda7af7042013-10-12 22:38:11 -05004443 weston_surface_destroy(shell->fade.view->surface);
4444 shell->fade.view = NULL;
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004445 break;
4446 case FADE_OUT:
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004447 lock(shell);
4448 break;
Philip Withnall4a86a0a2013-11-25 18:01:32 +00004449 default:
4450 break;
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004451 }
4452}
4453
Jason Ekstranda7af7042013-10-12 22:38:11 -05004454static struct weston_view *
Pekka Paalanen79346ab2013-05-22 18:03:09 +03004455shell_fade_create_surface(struct desktop_shell *shell)
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004456{
4457 struct weston_compositor *compositor = shell->compositor;
4458 struct weston_surface *surface;
Jason Ekstranda7af7042013-10-12 22:38:11 -05004459 struct weston_view *view;
Pekka Paalanen79346ab2013-05-22 18:03:09 +03004460
4461 surface = weston_surface_create(compositor);
4462 if (!surface)
4463 return NULL;
4464
Jason Ekstranda7af7042013-10-12 22:38:11 -05004465 view = weston_view_create(surface);
4466 if (!view) {
4467 weston_surface_destroy(surface);
4468 return NULL;
4469 }
4470
Jason Ekstrand5c11a332013-12-04 20:32:03 -06004471 weston_surface_set_size(surface, 8192, 8192);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004472 weston_view_set_position(view, 0, 0);
Pekka Paalanen79346ab2013-05-22 18:03:09 +03004473 weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1.0);
Jason Ekstranda7af7042013-10-12 22:38:11 -05004474 wl_list_insert(&compositor->fade_layer.view_list,
4475 &view->layer_link);
Pekka Paalanen79346ab2013-05-22 18:03:09 +03004476 pixman_region32_init(&surface->input);
4477
Jason Ekstranda7af7042013-10-12 22:38:11 -05004478 return view;
Pekka Paalanen79346ab2013-05-22 18:03:09 +03004479}
4480
4481static void
4482shell_fade(struct desktop_shell *shell, enum fade_type type)
4483{
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004484 float tint;
4485
4486 switch (type) {
4487 case FADE_IN:
4488 tint = 0.0;
4489 break;
4490 case FADE_OUT:
4491 tint = 1.0;
4492 break;
4493 default:
4494 weston_log("shell: invalid fade type\n");
4495 return;
4496 }
4497
4498 shell->fade.type = type;
4499
Jason Ekstranda7af7042013-10-12 22:38:11 -05004500 if (shell->fade.view == NULL) {
4501 shell->fade.view = shell_fade_create_surface(shell);
4502 if (!shell->fade.view)
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004503 return;
4504
Jason Ekstranda7af7042013-10-12 22:38:11 -05004505 shell->fade.view->alpha = 1.0 - tint;
4506 weston_view_update_transform(shell->fade.view);
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004507 }
4508
Kristian Høgsberg87d3b612014-01-19 21:48:10 -08004509 if (shell->fade.view->output == NULL) {
4510 /* If the black view gets a NULL output, we lost the
4511 * last output and we'll just cancel the fade. This
4512 * happens when you close the last window under the
4513 * X11 or Wayland backends. */
4514 shell->locked = false;
4515 weston_surface_destroy(shell->fade.view->surface);
4516 shell->fade.view = NULL;
4517 } else if (shell->fade.animation) {
Kristian Høgsberg5281fb12013-06-17 10:10:28 -04004518 weston_fade_update(shell->fade.animation, tint);
Kristian Høgsberg87d3b612014-01-19 21:48:10 -08004519 } else {
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004520 shell->fade.animation =
Jason Ekstranda7af7042013-10-12 22:38:11 -05004521 weston_fade_run(shell->fade.view,
Kristian Høgsberg5281fb12013-06-17 10:10:28 -04004522 1.0 - tint, tint, 300.0,
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004523 shell_fade_done, shell);
Kristian Høgsberg87d3b612014-01-19 21:48:10 -08004524 }
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004525}
4526
4527static void
Pekka Paalanen79346ab2013-05-22 18:03:09 +03004528do_shell_fade_startup(void *data)
4529{
4530 struct desktop_shell *shell = data;
4531
Kristian Høgsberg724c8d92013-10-16 11:38:24 -07004532 if (shell->startup_animation_type == ANIMATION_FADE)
4533 shell_fade(shell, FADE_IN);
4534 else if (shell->startup_animation_type == ANIMATION_NONE) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05004535 weston_surface_destroy(shell->fade.view->surface);
4536 shell->fade.view = NULL;
Kristian Høgsberg724c8d92013-10-16 11:38:24 -07004537 }
Pekka Paalanen79346ab2013-05-22 18:03:09 +03004538}
4539
4540static void
4541shell_fade_startup(struct desktop_shell *shell)
4542{
4543 struct wl_event_loop *loop;
4544
4545 if (!shell->fade.startup_timer)
4546 return;
4547
4548 wl_event_source_remove(shell->fade.startup_timer);
4549 shell->fade.startup_timer = NULL;
4550
4551 loop = wl_display_get_event_loop(shell->compositor->wl_display);
4552 wl_event_loop_add_idle(loop, do_shell_fade_startup, shell);
4553}
4554
4555static int
4556fade_startup_timeout(void *data)
4557{
4558 struct desktop_shell *shell = data;
4559
4560 shell_fade_startup(shell);
4561 return 0;
4562}
4563
4564static void
4565shell_fade_init(struct desktop_shell *shell)
4566{
4567 /* Make compositor output all black, and wait for the desktop-shell
4568 * client to signal it is ready, then fade in. The timer triggers a
4569 * fade-in, in case the desktop-shell client takes too long.
4570 */
4571
4572 struct wl_event_loop *loop;
4573
Jason Ekstranda7af7042013-10-12 22:38:11 -05004574 if (shell->fade.view != NULL) {
Pekka Paalanen79346ab2013-05-22 18:03:09 +03004575 weston_log("%s: warning: fade surface already exists\n",
4576 __func__);
4577 return;
4578 }
4579
Jason Ekstranda7af7042013-10-12 22:38:11 -05004580 shell->fade.view = shell_fade_create_surface(shell);
4581 if (!shell->fade.view)
Pekka Paalanen79346ab2013-05-22 18:03:09 +03004582 return;
4583
Jason Ekstranda7af7042013-10-12 22:38:11 -05004584 weston_view_update_transform(shell->fade.view);
4585 weston_surface_damage(shell->fade.view->surface);
Pekka Paalanen79346ab2013-05-22 18:03:09 +03004586
4587 loop = wl_display_get_event_loop(shell->compositor->wl_display);
4588 shell->fade.startup_timer =
4589 wl_event_loop_add_timer(loop, fade_startup_timeout, shell);
4590 wl_event_source_timer_update(shell->fade.startup_timer, 15000);
4591}
4592
4593static void
Ander Conselvan de Oliveiraa4575632013-02-21 18:35:23 +02004594idle_handler(struct wl_listener *listener, void *data)
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004595{
4596 struct desktop_shell *shell =
Ander Conselvan de Oliveiraa4575632013-02-21 18:35:23 +02004597 container_of(listener, struct desktop_shell, idle_listener);
Kristian Høgsberg27d5fa82014-01-17 16:22:50 -08004598 struct weston_seat *seat;
4599
4600 wl_list_for_each(seat, &shell->compositor->seat_list, link)
4601 if (seat->pointer)
4602 popup_grab_end(seat->pointer);
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004603
4604 shell_fade(shell, FADE_OUT);
4605 /* lock() is called from shell_fade_done() */
4606}
4607
4608static void
Ander Conselvan de Oliveiraa4575632013-02-21 18:35:23 +02004609wake_handler(struct wl_listener *listener, void *data)
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004610{
4611 struct desktop_shell *shell =
Ander Conselvan de Oliveiraa4575632013-02-21 18:35:23 +02004612 container_of(listener, struct desktop_shell, wake_listener);
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004613
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004614 unlock(shell);
4615}
4616
4617static void
Jason Ekstranda7af7042013-10-12 22:38:11 -05004618center_on_output(struct weston_view *view, struct weston_output *output)
Pekka Paalanen77346a62011-11-30 16:26:35 +02004619{
Giulio Camuffob8366642013-04-25 13:57:46 +03004620 int32_t surf_x, surf_y, width, height;
Ander Conselvan de Oliveira012b4c72012-11-27 17:03:42 +02004621 float x, y;
Pekka Paalanen77346a62011-11-30 16:26:35 +02004622
Jason Ekstranda7af7042013-10-12 22:38:11 -05004623 surface_subsurfaces_boundingbox(view->surface, &surf_x, &surf_y, &width, &height);
Giulio Camuffob8366642013-04-25 13:57:46 +03004624
4625 x = output->x + (output->width - width) / 2 - surf_x / 2;
4626 y = output->y + (output->height - height) / 2 - surf_y / 2;
Ander Conselvan de Oliveira012b4c72012-11-27 17:03:42 +02004627
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004628 weston_view_set_position(view, x, y);
Pekka Paalanen77346a62011-11-30 16:26:35 +02004629}
4630
4631static void
Jason Ekstranda7af7042013-10-12 22:38:11 -05004632weston_view_set_initial_position(struct weston_view *view,
4633 struct desktop_shell *shell)
Rob Bradfordac63e5b2012-08-13 14:07:52 +01004634{
4635 struct weston_compositor *compositor = shell->compositor;
4636 int ix = 0, iy = 0;
4637 int range_x, range_y;
4638 int dx, dy, x, y, panel_height;
4639 struct weston_output *output, *target_output = NULL;
4640 struct weston_seat *seat;
4641
4642 /* As a heuristic place the new window on the same output as the
4643 * pointer. Falling back to the output containing 0, 0.
4644 *
4645 * TODO: Do something clever for touch too?
4646 */
4647 wl_list_for_each(seat, &compositor->seat_list, link) {
Kristian Høgsberg2bf87622013-05-07 23:17:41 -04004648 if (seat->pointer) {
Kristian Høgsberge3148752013-05-06 23:19:49 -04004649 ix = wl_fixed_to_int(seat->pointer->x);
4650 iy = wl_fixed_to_int(seat->pointer->y);
Rob Bradfordac63e5b2012-08-13 14:07:52 +01004651 break;
4652 }
4653 }
4654
4655 wl_list_for_each(output, &compositor->output_list, link) {
4656 if (pixman_region32_contains_point(&output->region, ix, iy, NULL)) {
4657 target_output = output;
4658 break;
4659 }
4660 }
4661
4662 if (!target_output) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05004663 weston_view_set_position(view, 10 + random() % 400,
4664 10 + random() % 400);
Rob Bradfordac63e5b2012-08-13 14:07:52 +01004665 return;
4666 }
4667
4668 /* Valid range within output where the surface will still be onscreen.
4669 * If this is negative it means that the surface is bigger than
4670 * output.
4671 */
4672 panel_height = get_output_panel_height(shell, target_output);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004673 range_x = target_output->width - view->surface->width;
Scott Moreau1bad5db2012-08-18 01:04:05 -06004674 range_y = (target_output->height - panel_height) -
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004675 view->surface->height;
Rob Bradfordac63e5b2012-08-13 14:07:52 +01004676
Rob Bradford4cb88c72012-08-13 15:18:44 +01004677 if (range_x > 0)
Rob Bradfordac63e5b2012-08-13 14:07:52 +01004678 dx = random() % range_x;
Rob Bradfordac63e5b2012-08-13 14:07:52 +01004679 else
Rob Bradford4cb88c72012-08-13 15:18:44 +01004680 dx = 0;
4681
4682 if (range_y > 0)
Rob Bradfordac63e5b2012-08-13 14:07:52 +01004683 dy = panel_height + random() % range_y;
Rob Bradford4cb88c72012-08-13 15:18:44 +01004684 else
4685 dy = panel_height;
Rob Bradfordac63e5b2012-08-13 14:07:52 +01004686
4687 x = target_output->x + dx;
4688 y = target_output->y + dy;
4689
Jason Ekstranda7af7042013-10-12 22:38:11 -05004690 weston_view_set_position(view, x, y);
Rob Bradfordac63e5b2012-08-13 14:07:52 +01004691}
4692
4693static void
Jason Ekstranda7af7042013-10-12 22:38:11 -05004694map(struct desktop_shell *shell, struct shell_surface *shsurf,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004695 int32_t sx, int32_t sy)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04004696{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05004697 struct weston_compositor *compositor = shell->compositor;
Daniel Stoneb2104682012-05-30 16:31:56 +01004698 struct weston_seat *seat;
Juan Zhao96879df2012-02-07 08:45:41 +08004699 int panel_height = 0;
Giulio Camuffob8366642013-04-25 13:57:46 +03004700 int32_t surf_x, surf_y;
Pekka Paalanen57da4a82011-11-23 16:42:16 +02004701
Pekka Paalanen77346a62011-11-30 16:26:35 +02004702 /* initial positioning, see also configure() */
Jason Ekstranda7af7042013-10-12 22:38:11 -05004703 switch (shsurf->type) {
Rafael Antognollied207b42013-12-03 15:35:43 -02004704 case SHELL_SURFACE_TOPLEVEL:
Rafael Antognolli03b16592013-12-03 15:35:42 -02004705 if (shsurf->state.fullscreen) {
4706 center_on_output(shsurf->view, shsurf->fullscreen_output);
4707 shell_map_fullscreen(shsurf);
4708 } else if (shsurf->state.maximized) {
4709 /* use surface configure to set the geometry */
4710 panel_height = get_output_panel_height(shell, shsurf->output);
4711 surface_subsurfaces_boundingbox(shsurf->surface,
4712 &surf_x, &surf_y, NULL, NULL);
4713 weston_view_set_position(shsurf->view,
4714 shsurf->output->x - surf_x,
4715 shsurf->output->y +
4716 panel_height - surf_y);
Rafael Antognollied207b42013-12-03 15:35:43 -02004717 } else if (!shsurf->state.relative) {
Rafael Antognolli03b16592013-12-03 15:35:42 -02004718 weston_view_set_initial_position(shsurf->view, shell);
4719 }
Juan Zhao96879df2012-02-07 08:45:41 +08004720 break;
Tiago Vignatti0f997012012-02-10 16:17:23 +02004721 case SHELL_SURFACE_POPUP:
Kristian Høgsberg3730f362012-04-13 12:40:07 -04004722 shell_map_popup(shsurf);
Rob Bradforddb999382012-12-06 12:07:48 +00004723 break;
Ander Conselvan de Oliveirae9e05152012-02-15 17:02:56 +02004724 case SHELL_SURFACE_NONE:
Jason Ekstranda7af7042013-10-12 22:38:11 -05004725 weston_view_set_position(shsurf->view,
4726 shsurf->view->geometry.x + sx,
4727 shsurf->view->geometry.y + sy);
Tiago Vignatti0f997012012-02-10 16:17:23 +02004728 break;
Philip Withnall0f640e22013-11-25 18:01:31 +00004729 case SHELL_SURFACE_XWAYLAND:
Pekka Paalanen77346a62011-11-30 16:26:35 +02004730 default:
4731 ;
4732 }
Kristian Høgsberg75840622011-09-06 13:48:16 -04004733
Philip Withnalle1d75ae2013-11-25 18:01:41 +00004734 /* Surface stacking order, see also activate(). */
4735 shell_surface_update_layer(shsurf);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02004736
Jason Ekstranda7af7042013-10-12 22:38:11 -05004737 if (shsurf->type != SHELL_SURFACE_NONE) {
4738 weston_view_update_transform(shsurf->view);
Rafael Antognolli03b16592013-12-03 15:35:42 -02004739 if (shsurf->state.maximized) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05004740 shsurf->surface->output = shsurf->output;
4741 shsurf->view->output = shsurf->output;
4742 }
Ander Conselvan de Oliveirade56c312012-03-05 15:39:23 +02004743 }
Kristian Høgsberg2f88a402011-12-04 15:32:59 -05004744
Jason Ekstranda7af7042013-10-12 22:38:11 -05004745 switch (shsurf->type) {
Tiago Vignattifb2adba2013-06-12 15:43:21 -03004746 /* XXX: xwayland's using the same fields for transient type */
4747 case SHELL_SURFACE_XWAYLAND:
Tiago Vignatti99aeb1e2012-05-23 22:06:26 +03004748 if (shsurf->transient.flags ==
4749 WL_SHELL_SURFACE_TRANSIENT_INACTIVE)
4750 break;
4751 case SHELL_SURFACE_TOPLEVEL:
Rafael Antognollied207b42013-12-03 15:35:43 -02004752 if (shsurf->state.relative &&
4753 shsurf->transient.flags == WL_SHELL_SURFACE_TRANSIENT_INACTIVE)
4754 break;
Rafael Antognolliba5d2d72013-12-04 17:49:55 -02004755 if (shell->locked)
Rafael Antognollied207b42013-12-03 15:35:43 -02004756 break;
4757 wl_list_for_each(seat, &compositor->seat_list, link)
4758 activate(shell, shsurf->surface, seat);
Juan Zhao7bb92f02011-12-15 11:31:51 -05004759 break;
Philip Withnall0f640e22013-11-25 18:01:31 +00004760 case SHELL_SURFACE_POPUP:
4761 case SHELL_SURFACE_NONE:
Juan Zhao7bb92f02011-12-15 11:31:51 -05004762 default:
4763 break;
4764 }
4765
Rafael Antognolli03b16592013-12-03 15:35:42 -02004766 if (shsurf->type == SHELL_SURFACE_TOPLEVEL &&
4767 !shsurf->state.maximized && !shsurf->state.fullscreen)
Juan Zhaoe10d2792012-04-25 19:09:52 +08004768 {
4769 switch (shell->win_animation_type) {
4770 case ANIMATION_FADE:
Jason Ekstranda7af7042013-10-12 22:38:11 -05004771 weston_fade_run(shsurf->view, 0.0, 1.0, 300.0, NULL, NULL);
Juan Zhaoe10d2792012-04-25 19:09:52 +08004772 break;
4773 case ANIMATION_ZOOM:
Jason Ekstranda7af7042013-10-12 22:38:11 -05004774 weston_zoom_run(shsurf->view, 0.5, 1.0, NULL, NULL);
Juan Zhaoe10d2792012-04-25 19:09:52 +08004775 break;
Philip Withnall4a86a0a2013-11-25 18:01:32 +00004776 case ANIMATION_NONE:
Juan Zhaoe10d2792012-04-25 19:09:52 +08004777 default:
4778 break;
4779 }
4780 }
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05004781}
4782
4783static void
Tiago Vignattibe143262012-04-16 17:31:41 +03004784configure(struct desktop_shell *shell, struct weston_surface *surface,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004785 float x, float y)
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05004786{
Pekka Paalanen77346a62011-11-30 16:26:35 +02004787 struct shell_surface *shsurf;
Jason Ekstranda7af7042013-10-12 22:38:11 -05004788 struct weston_view *view;
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004789 int32_t mx, my, surf_x, surf_y;
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05004790
Pekka Paalanen77346a62011-11-30 16:26:35 +02004791 shsurf = get_shell_surface(surface);
Pekka Paalanen77346a62011-11-30 16:26:35 +02004792
U. Artie Eoffcf5737a2014-01-17 10:08:25 -08004793 assert(shsurf);
4794
Rafael Antognolli03b16592013-12-03 15:35:42 -02004795 if (shsurf->state.fullscreen)
Alex Wu4539b082012-03-01 12:57:46 +08004796 shell_configure_fullscreen(shsurf);
Rafael Antognolli03b16592013-12-03 15:35:42 -02004797 else if (shsurf->state.maximized) {
Alex Wu4539b082012-03-01 12:57:46 +08004798 /* setting x, y and using configure to change that geometry */
Giulio Camuffob8366642013-04-25 13:57:46 +03004799 surface_subsurfaces_boundingbox(shsurf->surface, &surf_x, &surf_y,
4800 NULL, NULL);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004801 mx = shsurf->output->x - surf_x;
4802 my = shsurf->output->y +
4803 get_output_panel_height(shell,shsurf->output) - surf_y;
4804 weston_view_set_position(shsurf->view, mx, my);
Rafael Antognolli03b16592013-12-03 15:35:42 -02004805 } else {
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004806 weston_view_set_position(shsurf->view, x, y);
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04004807 }
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05004808
Alex Wu4539b082012-03-01 12:57:46 +08004809 /* XXX: would a fullscreen surface need the same handling? */
Kristian Høgsberg6a8b5532012-02-16 23:43:59 -05004810 if (surface->output) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05004811 wl_list_for_each(view, &surface->views, surface_link)
4812 weston_view_update_transform(view);
Pekka Paalanen77346a62011-11-30 16:26:35 +02004813
Rafael Antognolli03b16592013-12-03 15:35:42 -02004814 if (shsurf->state.maximized)
Juan Zhao96879df2012-02-07 08:45:41 +08004815 surface->output = shsurf->output;
Pekka Paalanen77346a62011-11-30 16:26:35 +02004816 }
Kristian Høgsberg07937562011-04-12 17:25:42 -04004817}
4818
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03004819static void
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004820shell_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03004821{
Ander Conselvan de Oliveira7fb9f952012-03-27 17:36:42 +03004822 struct shell_surface *shsurf = get_shell_surface(es);
U. Artie Eoffcf5737a2014-01-17 10:08:25 -08004823 struct desktop_shell *shell;
Tiago Vignatti70e5c9c2012-05-07 15:23:07 +03004824 int type_changed = 0;
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03004825
U. Artie Eoffcf5737a2014-01-17 10:08:25 -08004826 assert(shsurf);
4827
4828 shell = shsurf->shell;
4829
Kristian Høgsberg8eb0f4f2013-06-17 10:33:14 -04004830 if (!weston_surface_is_mapped(es) &&
4831 !wl_list_empty(&shsurf->popup.grab_link)) {
Giulio Camuffo5085a752013-03-25 21:42:45 +01004832 remove_popup_grab(shsurf);
4833 }
4834
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004835 if (es->width == 0)
Giulio Camuffo184df502013-02-21 11:29:21 +01004836 return;
4837
Kristian Høgsbergc8f8dd82013-12-05 23:20:33 -08004838 if (shsurf->state_changed) {
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04004839 set_surface_type(shsurf);
Kristian Høgsbergf7e23d52012-04-27 17:51:59 -04004840 type_changed = 1;
4841 }
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04004842
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03004843 if (!weston_surface_is_mapped(es)) {
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004844 map(shell, shsurf, sx, sy);
Kristian Høgsbergf7e23d52012-04-27 17:51:59 -04004845 } else if (type_changed || sx != 0 || sy != 0 ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004846 shsurf->last_width != es->width ||
4847 shsurf->last_height != es->height) {
John Kåre Alsaker490d02a2012-09-30 02:57:21 +02004848 float from_x, from_y;
4849 float to_x, to_y;
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03004850
Kristian Høgsberg44cd1962014-02-05 21:36:04 -08004851 if (shsurf->resize_edges) {
4852 sx = 0;
4853 sy = 0;
4854 }
4855
4856 if (shsurf->resize_edges & WL_SHELL_SURFACE_RESIZE_LEFT)
4857 sx = shsurf->last_width - es->width;
4858 if (shsurf->resize_edges & WL_SHELL_SURFACE_RESIZE_TOP)
4859 sy = shsurf->last_height - es->height;
4860
4861 shsurf->last_width = es->width;
4862 shsurf->last_height = es->height;
4863
Jason Ekstranda7af7042013-10-12 22:38:11 -05004864 weston_view_to_global_float(shsurf->view, 0, 0, &from_x, &from_y);
4865 weston_view_to_global_float(shsurf->view, sx, sy, &to_x, &to_y);
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03004866 configure(shell, es,
Jason Ekstranda7af7042013-10-12 22:38:11 -05004867 shsurf->view->geometry.x + to_x - from_x,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004868 shsurf->view->geometry.y + to_y - from_y);
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03004869 }
4870}
4871
Tiago Vignattib7dbbd62012-09-25 17:57:01 +03004872static void launch_desktop_shell_process(void *data);
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02004873
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04004874static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05004875desktop_shell_sigchld(struct weston_process *process, int status)
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02004876{
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02004877 uint32_t time;
Tiago Vignattibe143262012-04-16 17:31:41 +03004878 struct desktop_shell *shell =
4879 container_of(process, struct desktop_shell, child.process);
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02004880
4881 shell->child.process.pid = 0;
4882 shell->child.client = NULL; /* already destroyed by wayland */
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02004883
4884 /* if desktop-shell dies more than 5 times in 30 seconds, give up */
4885 time = weston_compositor_get_time();
Kristian Høgsbergf03a6162012-01-17 11:07:42 -05004886 if (time - shell->child.deathstamp > 30000) {
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02004887 shell->child.deathstamp = time;
4888 shell->child.deathcount = 0;
4889 }
4890
4891 shell->child.deathcount++;
4892 if (shell->child.deathcount > 5) {
Emilio Pozuelo Monfort46ce7982013-11-20 13:22:29 +01004893 weston_log("%s died, giving up.\n", shell->client);
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02004894 return;
4895 }
4896
Emilio Pozuelo Monfort46ce7982013-11-20 13:22:29 +01004897 weston_log("%s died, respawning...\n", shell->client);
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02004898 launch_desktop_shell_process(shell);
Pekka Paalanen79346ab2013-05-22 18:03:09 +03004899 shell_fade_startup(shell);
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02004900}
4901
Tiago Vignattib7dbbd62012-09-25 17:57:01 +03004902static void
Ander Conselvan de Oliveira312ea4c2013-12-20 21:07:01 +02004903desktop_shell_client_destroy(struct wl_listener *listener, void *data)
4904{
4905 struct desktop_shell *shell;
4906
4907 shell = container_of(listener, struct desktop_shell,
4908 child.client_destroy_listener);
4909
4910 shell->child.client = NULL;
4911}
4912
4913static void
Tiago Vignattib7dbbd62012-09-25 17:57:01 +03004914launch_desktop_shell_process(void *data)
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02004915{
Tiago Vignattib7dbbd62012-09-25 17:57:01 +03004916 struct desktop_shell *shell = data;
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02004917
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05004918 shell->child.client = weston_client_launch(shell->compositor,
Pekka Paalanen409ef0a2011-12-02 15:30:21 +02004919 &shell->child.process,
Emilio Pozuelo Monfort46ce7982013-11-20 13:22:29 +01004920 shell->client,
Pekka Paalanen409ef0a2011-12-02 15:30:21 +02004921 desktop_shell_sigchld);
4922
4923 if (!shell->child.client)
Emilio Pozuelo Monfort46ce7982013-11-20 13:22:29 +01004924 weston_log("not able to start %s\n", shell->client);
Ander Conselvan de Oliveira312ea4c2013-12-20 21:07:01 +02004925
4926 shell->child.client_destroy_listener.notify =
4927 desktop_shell_client_destroy;
4928 wl_client_add_destroy_listener(shell->child.client,
4929 &shell->child.client_destroy_listener);
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02004930}
4931
4932static void
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08004933handle_shell_client_destroy(struct wl_listener *listener, void *data)
4934{
4935 struct shell_client *sc =
4936 container_of(listener, struct shell_client, destroy_listener);
4937
4938 if (sc->ping_timer)
4939 wl_event_source_remove(sc->ping_timer);
4940 free(sc);
4941}
4942
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08004943static struct shell_client *
4944shell_client_create(struct wl_client *client, struct desktop_shell *shell,
4945 const struct wl_interface *interface, uint32_t id)
Rafael Antognollie2a34552013-12-03 15:35:45 -02004946{
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08004947 struct shell_client *sc;
Rafael Antognollie2a34552013-12-03 15:35:45 -02004948
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08004949 sc = zalloc(sizeof *sc);
4950 if (sc == NULL) {
4951 wl_client_post_no_memory(client);
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08004952 return NULL;
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08004953 }
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08004954
4955 sc->resource = wl_resource_create(client, interface, 1, id);
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08004956 if (sc->resource == NULL) {
4957 free(sc);
4958 wl_client_post_no_memory(client);
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08004959 return NULL;
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08004960 }
4961
4962 sc->client = client;
4963 sc->shell = shell;
4964 sc->destroy_listener.notify = handle_shell_client_destroy;
4965 wl_client_add_destroy_listener(client, &sc->destroy_listener);
4966
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08004967 return sc;
4968}
4969
4970static void
4971bind_shell(struct wl_client *client, void *data, uint32_t version, uint32_t id)
4972{
4973 struct desktop_shell *shell = data;
4974 struct shell_client *sc;
4975
4976 sc = shell_client_create(client, shell, &wl_shell_interface, id);
4977 if (sc)
4978 wl_resource_set_implementation(sc->resource,
4979 &shell_implementation,
4980 shell, NULL);
4981}
4982
4983static void
4984bind_xdg_shell(struct wl_client *client, void *data, uint32_t version, uint32_t id)
4985{
4986 struct desktop_shell *shell = data;
4987 struct shell_client *sc;
4988
4989 sc = shell_client_create(client, shell, &xdg_shell_interface, id);
4990 if (sc)
4991 wl_resource_set_dispatcher(sc->resource,
4992 xdg_shell_unversioned_dispatch,
4993 NULL, sc, NULL);
Rafael Antognollie2a34552013-12-03 15:35:45 -02004994}
4995
4996static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02004997unbind_desktop_shell(struct wl_resource *resource)
4998{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05004999 struct desktop_shell *shell = wl_resource_get_user_data(resource);
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05005000
5001 if (shell->locked)
5002 resume_desktop(shell);
5003
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02005004 shell->child.desktop_shell = NULL;
5005 shell->prepare_event_sent = false;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02005006}
5007
5008static void
Kristian Høgsberg75840622011-09-06 13:48:16 -04005009bind_desktop_shell(struct wl_client *client,
5010 void *data, uint32_t version, uint32_t id)
5011{
Tiago Vignattibe143262012-04-16 17:31:41 +03005012 struct desktop_shell *shell = data;
Pekka Paalanenbbe60522011-11-03 14:11:33 +02005013 struct wl_resource *resource;
Kristian Høgsberg75840622011-09-06 13:48:16 -04005014
Jason Ekstranda85118c2013-06-27 20:17:02 -05005015 resource = wl_resource_create(client, &desktop_shell_interface,
5016 MIN(version, 2), id);
Pekka Paalanenbbe60522011-11-03 14:11:33 +02005017
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02005018 if (client == shell->child.client) {
Jason Ekstranda85118c2013-06-27 20:17:02 -05005019 wl_resource_set_implementation(resource,
5020 &desktop_shell_implementation,
5021 shell, unbind_desktop_shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02005022 shell->child.desktop_shell = resource;
Pekka Paalanen79346ab2013-05-22 18:03:09 +03005023
5024 if (version < 2)
5025 shell_fade_startup(shell);
5026
Pekka Paalanenbbe60522011-11-03 14:11:33 +02005027 return;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02005028 }
Pekka Paalanenbbe60522011-11-03 14:11:33 +02005029
5030 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
5031 "permission to bind desktop_shell denied");
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04005032 wl_resource_destroy(resource);
Kristian Høgsberg75840622011-09-06 13:48:16 -04005033}
5034
Pekka Paalanen6e168112011-11-24 11:34:05 +02005035static void
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06005036screensaver_configure(struct weston_surface *surface, int32_t sx, int32_t sy)
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04005037{
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01005038 struct desktop_shell *shell = surface->configure_private;
Jason Ekstranda7af7042013-10-12 22:38:11 -05005039 struct weston_view *view;
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04005040
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06005041 if (surface->width == 0)
Giulio Camuffo184df502013-02-21 11:29:21 +01005042 return;
5043
Pekka Paalanen3a1d07d2012-12-20 14:02:13 +02005044 /* XXX: starting weston-screensaver beforehand does not work */
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04005045 if (!shell->locked)
5046 return;
5047
Jason Ekstranda7af7042013-10-12 22:38:11 -05005048 view = container_of(surface->views.next, struct weston_view, surface_link);
5049 center_on_output(view, surface->output);
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04005050
Jason Ekstranda7af7042013-10-12 22:38:11 -05005051 if (wl_list_empty(&view->layer_link)) {
5052 wl_list_insert(shell->lock_layer.view_list.prev,
5053 &view->layer_link);
5054 weston_view_update_transform(view);
Ander Conselvan de Oliveira859e8852013-02-21 18:35:21 +02005055 wl_event_source_timer_update(shell->screensaver.timer,
5056 shell->screensaver.duration);
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02005057 shell_fade(shell, FADE_IN);
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04005058 }
5059}
5060
5061static void
Pekka Paalanen6e168112011-11-24 11:34:05 +02005062screensaver_set_surface(struct wl_client *client,
5063 struct wl_resource *resource,
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04005064 struct wl_resource *surface_resource,
Pekka Paalanen6e168112011-11-24 11:34:05 +02005065 struct wl_resource *output_resource)
5066{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05005067 struct desktop_shell *shell = wl_resource_get_user_data(resource);
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05005068 struct weston_surface *surface =
5069 wl_resource_get_user_data(surface_resource);
Jason Ekstranda0d2dde2013-06-14 10:08:01 -05005070 struct weston_output *output = wl_resource_get_user_data(output_resource);
Jason Ekstranda7af7042013-10-12 22:38:11 -05005071 struct weston_view *view, *next;
5072
5073 /* Make sure we only have one view */
5074 wl_list_for_each_safe(view, next, &surface->views, surface_link)
5075 weston_view_destroy(view);
5076 weston_view_create(surface);
Pekka Paalanen6e168112011-11-24 11:34:05 +02005077
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04005078 surface->configure = screensaver_configure;
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01005079 surface->configure_private = shell;
Pekka Paalanen77346a62011-11-30 16:26:35 +02005080 surface->output = output;
Pekka Paalanen6e168112011-11-24 11:34:05 +02005081}
5082
5083static const struct screensaver_interface screensaver_implementation = {
5084 screensaver_set_surface
5085};
5086
5087static void
5088unbind_screensaver(struct wl_resource *resource)
5089{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05005090 struct desktop_shell *shell = wl_resource_get_user_data(resource);
Pekka Paalanen6e168112011-11-24 11:34:05 +02005091
Pekka Paalanen77346a62011-11-30 16:26:35 +02005092 shell->screensaver.binding = NULL;
Pekka Paalanen6e168112011-11-24 11:34:05 +02005093}
5094
5095static void
5096bind_screensaver(struct wl_client *client,
5097 void *data, uint32_t version, uint32_t id)
5098{
Tiago Vignattibe143262012-04-16 17:31:41 +03005099 struct desktop_shell *shell = data;
Pekka Paalanen6e168112011-11-24 11:34:05 +02005100 struct wl_resource *resource;
5101
Jason Ekstranda85118c2013-06-27 20:17:02 -05005102 resource = wl_resource_create(client, &screensaver_interface, 1, id);
Pekka Paalanen6e168112011-11-24 11:34:05 +02005103
Pekka Paalanen77346a62011-11-30 16:26:35 +02005104 if (shell->screensaver.binding == NULL) {
Jason Ekstranda85118c2013-06-27 20:17:02 -05005105 wl_resource_set_implementation(resource,
5106 &screensaver_implementation,
5107 shell, unbind_screensaver);
Pekka Paalanen77346a62011-11-30 16:26:35 +02005108 shell->screensaver.binding = resource;
Pekka Paalanen6e168112011-11-24 11:34:05 +02005109 return;
5110 }
5111
5112 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
5113 "interface object already bound");
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04005114 wl_resource_destroy(resource);
Pekka Paalanen6e168112011-11-24 11:34:05 +02005115}
5116
Kristian Høgsberg07045392012-02-19 18:52:44 -05005117struct switcher {
Tiago Vignattibe143262012-04-16 17:31:41 +03005118 struct desktop_shell *shell;
Kristian Høgsberg07045392012-02-19 18:52:44 -05005119 struct weston_surface *current;
5120 struct wl_listener listener;
Kristian Høgsberg29139d42013-04-18 15:25:39 -04005121 struct weston_keyboard_grab grab;
Kristian Høgsberg07045392012-02-19 18:52:44 -05005122};
5123
5124static void
5125switcher_next(struct switcher *switcher)
5126{
Jason Ekstranda7af7042013-10-12 22:38:11 -05005127 struct weston_view *view;
Kristian Høgsberg07045392012-02-19 18:52:44 -05005128 struct weston_surface *first = NULL, *prev = NULL, *next = NULL;
Kristian Høgsberg32e56862012-04-02 22:18:58 -04005129 struct shell_surface *shsurf;
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04005130 struct workspace *ws = get_current_workspace(switcher->shell);
Kristian Høgsberg07045392012-02-19 18:52:44 -05005131
Jason Ekstranda7af7042013-10-12 22:38:11 -05005132 wl_list_for_each(view, &ws->layer.view_list, layer_link) {
Rafael Antognollied207b42013-12-03 15:35:43 -02005133 shsurf = get_shell_surface(view->surface);
Rafael Antognolli5031cbe2013-12-05 19:01:21 -02005134 if (shsurf &&
5135 shsurf->type == SHELL_SURFACE_TOPLEVEL &&
5136 shsurf->parent == NULL) {
Kristian Høgsberg07045392012-02-19 18:52:44 -05005137 if (first == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05005138 first = view->surface;
Kristian Høgsberg07045392012-02-19 18:52:44 -05005139 if (prev == switcher->current)
Jason Ekstranda7af7042013-10-12 22:38:11 -05005140 next = view->surface;
5141 prev = view->surface;
5142 view->alpha = 0.25;
5143 weston_view_geometry_dirty(view);
5144 weston_surface_damage(view->surface);
Kristian Høgsberg07045392012-02-19 18:52:44 -05005145 }
Alex Wu1659daa2012-04-01 20:13:09 +08005146
Jason Ekstranda7af7042013-10-12 22:38:11 -05005147 if (is_black_surface(view->surface, NULL)) {
5148 view->alpha = 0.25;
5149 weston_view_geometry_dirty(view);
5150 weston_surface_damage(view->surface);
Alex Wu1659daa2012-04-01 20:13:09 +08005151 }
Kristian Høgsberg07045392012-02-19 18:52:44 -05005152 }
5153
5154 if (next == NULL)
5155 next = first;
5156
Alex Wu07b26062012-03-12 16:06:01 +08005157 if (next == NULL)
5158 return;
5159
Kristian Høgsberg07045392012-02-19 18:52:44 -05005160 wl_list_remove(&switcher->listener.link);
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05005161 wl_signal_add(&next->destroy_signal, &switcher->listener);
Kristian Høgsberg07045392012-02-19 18:52:44 -05005162
5163 switcher->current = next;
Jason Ekstranda7af7042013-10-12 22:38:11 -05005164 wl_list_for_each(view, &next->views, surface_link)
5165 view->alpha = 1.0;
Alex Wu1659daa2012-04-01 20:13:09 +08005166
Kristian Høgsberg32e56862012-04-02 22:18:58 -04005167 shsurf = get_shell_surface(switcher->current);
Rafael Antognolli03b16592013-12-03 15:35:42 -02005168 if (shsurf && shsurf->state.fullscreen)
Jason Ekstranda7af7042013-10-12 22:38:11 -05005169 shsurf->fullscreen.black_view->alpha = 1.0;
Kristian Høgsberg07045392012-02-19 18:52:44 -05005170}
5171
5172static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04005173switcher_handle_surface_destroy(struct wl_listener *listener, void *data)
Kristian Høgsberg07045392012-02-19 18:52:44 -05005174{
5175 struct switcher *switcher =
5176 container_of(listener, struct switcher, listener);
5177
5178 switcher_next(switcher);
5179}
5180
5181static void
Daniel Stone351eb612012-05-31 15:27:47 -04005182switcher_destroy(struct switcher *switcher)
Kristian Høgsberg07045392012-02-19 18:52:44 -05005183{
Jason Ekstranda7af7042013-10-12 22:38:11 -05005184 struct weston_view *view;
Kristian Høgsberg29139d42013-04-18 15:25:39 -04005185 struct weston_keyboard *keyboard = switcher->grab.keyboard;
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04005186 struct workspace *ws = get_current_workspace(switcher->shell);
Kristian Høgsberg07045392012-02-19 18:52:44 -05005187
Jason Ekstranda7af7042013-10-12 22:38:11 -05005188 wl_list_for_each(view, &ws->layer.view_list, layer_link) {
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01005189 if (is_focus_view(view))
5190 continue;
5191
Jason Ekstranda7af7042013-10-12 22:38:11 -05005192 view->alpha = 1.0;
5193 weston_surface_damage(view->surface);
Kristian Høgsberg07045392012-02-19 18:52:44 -05005194 }
5195
Alex Wu07b26062012-03-12 16:06:01 +08005196 if (switcher->current)
Daniel Stone37816df2012-05-16 18:45:18 +01005197 activate(switcher->shell, switcher->current,
5198 (struct weston_seat *) keyboard->seat);
Kristian Høgsberg07045392012-02-19 18:52:44 -05005199 wl_list_remove(&switcher->listener.link);
Kristian Høgsberg29139d42013-04-18 15:25:39 -04005200 weston_keyboard_end_grab(keyboard);
5201 if (keyboard->input_method_resource)
5202 keyboard->grab = &keyboard->input_method_grab;
Kristian Høgsberg07045392012-02-19 18:52:44 -05005203 free(switcher);
5204}
5205
5206static void
Kristian Høgsberg29139d42013-04-18 15:25:39 -04005207switcher_key(struct weston_keyboard_grab *grab,
Daniel Stonec9785ea2012-05-30 16:31:52 +01005208 uint32_t time, uint32_t key, uint32_t state_w)
Kristian Høgsberg07045392012-02-19 18:52:44 -05005209{
5210 struct switcher *switcher = container_of(grab, struct switcher, grab);
Daniel Stonec9785ea2012-05-30 16:31:52 +01005211 enum wl_keyboard_key_state state = state_w;
Daniel Stone351eb612012-05-31 15:27:47 -04005212
Daniel Stonec9785ea2012-05-30 16:31:52 +01005213 if (key == KEY_TAB && state == WL_KEYBOARD_KEY_STATE_PRESSED)
Daniel Stone351eb612012-05-31 15:27:47 -04005214 switcher_next(switcher);
5215}
5216
5217static void
Kristian Høgsberg29139d42013-04-18 15:25:39 -04005218switcher_modifier(struct weston_keyboard_grab *grab, uint32_t serial,
Daniel Stone351eb612012-05-31 15:27:47 -04005219 uint32_t mods_depressed, uint32_t mods_latched,
5220 uint32_t mods_locked, uint32_t group)
5221{
5222 struct switcher *switcher = container_of(grab, struct switcher, grab);
Daniel Stone37816df2012-05-16 18:45:18 +01005223 struct weston_seat *seat = (struct weston_seat *) grab->keyboard->seat;
Kristian Høgsberg07045392012-02-19 18:52:44 -05005224
Daniel Stone351eb612012-05-31 15:27:47 -04005225 if ((seat->modifier_state & switcher->shell->binding_modifier) == 0)
5226 switcher_destroy(switcher);
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04005227}
Kristian Høgsberg07045392012-02-19 18:52:44 -05005228
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02005229static void
5230switcher_cancel(struct weston_keyboard_grab *grab)
5231{
5232 struct switcher *switcher = container_of(grab, struct switcher, grab);
5233
5234 switcher_destroy(switcher);
5235}
5236
Kristian Høgsberg29139d42013-04-18 15:25:39 -04005237static const struct weston_keyboard_grab_interface switcher_grab = {
Daniel Stone351eb612012-05-31 15:27:47 -04005238 switcher_key,
5239 switcher_modifier,
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02005240 switcher_cancel,
Kristian Høgsberg07045392012-02-19 18:52:44 -05005241};
5242
5243static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04005244switcher_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
Daniel Stone325fc2d2012-05-30 16:31:58 +01005245 void *data)
Kristian Høgsberg07045392012-02-19 18:52:44 -05005246{
Tiago Vignattibe143262012-04-16 17:31:41 +03005247 struct desktop_shell *shell = data;
Kristian Høgsberg07045392012-02-19 18:52:44 -05005248 struct switcher *switcher;
5249
5250 switcher = malloc(sizeof *switcher);
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04005251 switcher->shell = shell;
Kristian Høgsberg07045392012-02-19 18:52:44 -05005252 switcher->current = NULL;
Kristian Høgsberg27e30522012-04-11 23:18:23 -04005253 switcher->listener.notify = switcher_handle_surface_destroy;
Kristian Høgsberg07045392012-02-19 18:52:44 -05005254 wl_list_init(&switcher->listener.link);
5255
Alexander Larssonf82b6ca2013-05-28 16:23:39 +02005256 restore_all_output_modes(shell->compositor);
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04005257 lower_fullscreen_layer(switcher->shell);
Kristian Høgsberg07045392012-02-19 18:52:44 -05005258 switcher->grab.interface = &switcher_grab;
Kristian Høgsberg29139d42013-04-18 15:25:39 -04005259 weston_keyboard_start_grab(seat->keyboard, &switcher->grab);
5260 weston_keyboard_set_focus(seat->keyboard, NULL);
Kristian Høgsberg07045392012-02-19 18:52:44 -05005261 switcher_next(switcher);
5262}
5263
Pekka Paalanen3c647232011-12-22 13:43:43 +02005264static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04005265backlight_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
Daniel Stone325fc2d2012-05-30 16:31:58 +01005266 void *data)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02005267{
5268 struct weston_compositor *compositor = data;
5269 struct weston_output *output;
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03005270 long backlight_new = 0;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02005271
5272 /* TODO: we're limiting to simple use cases, where we assume just
5273 * control on the primary display. We'd have to extend later if we
5274 * ever get support for setting backlights on random desktop LCD
5275 * panels though */
5276 output = get_default_output(compositor);
5277 if (!output)
5278 return;
5279
5280 if (!output->set_backlight)
5281 return;
5282
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03005283 if (key == KEY_F9 || key == KEY_BRIGHTNESSDOWN)
5284 backlight_new = output->backlight_current - 25;
5285 else if (key == KEY_F10 || key == KEY_BRIGHTNESSUP)
5286 backlight_new = output->backlight_current + 25;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02005287
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03005288 if (backlight_new < 5)
5289 backlight_new = 5;
5290 if (backlight_new > 255)
5291 backlight_new = 255;
5292
5293 output->backlight_current = backlight_new;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02005294 output->set_backlight(output, output->backlight_current);
5295}
5296
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005297struct debug_binding_grab {
Kristian Høgsberg29139d42013-04-18 15:25:39 -04005298 struct weston_keyboard_grab grab;
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005299 struct weston_seat *seat;
5300 uint32_t key[2];
5301 int key_released[2];
5302};
5303
5304static void
Kristian Høgsberg29139d42013-04-18 15:25:39 -04005305debug_binding_key(struct weston_keyboard_grab *grab, uint32_t time,
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005306 uint32_t key, uint32_t state)
5307{
5308 struct debug_binding_grab *db = (struct debug_binding_grab *) grab;
Rob Bradford880ebc72013-07-22 17:31:38 +01005309 struct weston_compositor *ec = db->seat->compositor;
5310 struct wl_display *display = ec->wl_display;
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005311 struct wl_resource *resource;
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005312 uint32_t serial;
5313 int send = 0, terminate = 0;
5314 int check_binding = 1;
5315 int i;
Neil Roberts96d790e2013-09-19 17:32:00 +01005316 struct wl_list *resource_list;
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005317
5318 if (state == WL_KEYBOARD_KEY_STATE_RELEASED) {
5319 /* Do not run bindings on key releases */
5320 check_binding = 0;
5321
5322 for (i = 0; i < 2; i++)
5323 if (key == db->key[i])
5324 db->key_released[i] = 1;
5325
5326 if (db->key_released[0] && db->key_released[1]) {
5327 /* All key releases been swalled so end the grab */
5328 terminate = 1;
5329 } else if (key != db->key[0] && key != db->key[1]) {
5330 /* Should not swallow release of other keys */
5331 send = 1;
5332 }
5333 } else if (key == db->key[0] && !db->key_released[0]) {
5334 /* Do not check bindings for the first press of the binding
5335 * key. This allows it to be used as a debug shortcut.
5336 * We still need to swallow this event. */
5337 check_binding = 0;
5338 } else if (db->key[1]) {
5339 /* If we already ran a binding don't process another one since
5340 * we can't keep track of all the binding keys that were
5341 * pressed in order to swallow the release events. */
5342 send = 1;
5343 check_binding = 0;
5344 }
5345
5346 if (check_binding) {
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005347 if (weston_compositor_run_debug_binding(ec, db->seat, time,
5348 key, state)) {
5349 /* We ran a binding so swallow the press and keep the
5350 * grab to swallow the released too. */
5351 send = 0;
5352 terminate = 0;
5353 db->key[1] = key;
5354 } else {
5355 /* Terminate the grab since the key pressed is not a
5356 * debug binding key. */
5357 send = 1;
5358 terminate = 1;
5359 }
5360 }
5361
5362 if (send) {
Neil Roberts96d790e2013-09-19 17:32:00 +01005363 serial = wl_display_next_serial(display);
5364 resource_list = &grab->keyboard->focus_resource_list;
5365 wl_resource_for_each(resource, resource_list) {
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005366 wl_keyboard_send_key(resource, serial, time, key, state);
5367 }
5368 }
5369
5370 if (terminate) {
Kristian Høgsberg29139d42013-04-18 15:25:39 -04005371 weston_keyboard_end_grab(grab->keyboard);
5372 if (grab->keyboard->input_method_resource)
5373 grab->keyboard->grab = &grab->keyboard->input_method_grab;
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005374 free(db);
5375 }
5376}
5377
5378static void
Kristian Høgsberg29139d42013-04-18 15:25:39 -04005379debug_binding_modifiers(struct weston_keyboard_grab *grab, uint32_t serial,
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005380 uint32_t mods_depressed, uint32_t mods_latched,
5381 uint32_t mods_locked, uint32_t group)
5382{
5383 struct wl_resource *resource;
Neil Roberts96d790e2013-09-19 17:32:00 +01005384 struct wl_list *resource_list;
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005385
Neil Roberts96d790e2013-09-19 17:32:00 +01005386 resource_list = &grab->keyboard->focus_resource_list;
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005387
Neil Roberts96d790e2013-09-19 17:32:00 +01005388 wl_resource_for_each(resource, resource_list) {
5389 wl_keyboard_send_modifiers(resource, serial, mods_depressed,
5390 mods_latched, mods_locked, group);
5391 }
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005392}
5393
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02005394static void
5395debug_binding_cancel(struct weston_keyboard_grab *grab)
5396{
5397 struct debug_binding_grab *db = (struct debug_binding_grab *) grab;
5398
5399 weston_keyboard_end_grab(grab->keyboard);
5400 free(db);
5401}
5402
Kristian Høgsberg29139d42013-04-18 15:25:39 -04005403struct weston_keyboard_grab_interface debug_binding_keyboard_grab = {
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005404 debug_binding_key,
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02005405 debug_binding_modifiers,
5406 debug_binding_cancel,
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005407};
5408
5409static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04005410debug_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005411{
5412 struct debug_binding_grab *grab;
5413
5414 grab = calloc(1, sizeof *grab);
5415 if (!grab)
5416 return;
5417
5418 grab->seat = (struct weston_seat *) seat;
5419 grab->key[0] = key;
5420 grab->grab.interface = &debug_binding_keyboard_grab;
Kristian Høgsberg29139d42013-04-18 15:25:39 -04005421 weston_keyboard_start_grab(seat->keyboard, &grab->grab);
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005422}
5423
Kristian Høgsbergb41c0812012-03-04 14:53:40 -05005424static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04005425force_kill_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
Daniel Stone325fc2d2012-05-30 16:31:58 +01005426 void *data)
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04005427{
Kristian Høgsbergfe7aa902013-05-08 09:54:37 -04005428 struct weston_surface *focus_surface;
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04005429 struct wl_client *client;
Tiago Vignatti1d01b012012-09-27 17:48:36 +03005430 struct desktop_shell *shell = data;
5431 struct weston_compositor *compositor = shell->compositor;
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04005432 pid_t pid;
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04005433
Philipp Brüschweiler6cef0092012-08-13 21:27:27 +02005434 focus_surface = seat->keyboard->focus;
5435 if (!focus_surface)
5436 return;
5437
Tiago Vignatti1d01b012012-09-27 17:48:36 +03005438 wl_signal_emit(&compositor->kill_signal, focus_surface);
5439
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05005440 client = wl_resource_get_client(focus_surface->resource);
Tiago Vignatti920f1972012-09-27 17:48:35 +03005441 wl_client_get_credentials(client, &pid, NULL, NULL);
5442
5443 /* Skip clients that we launched ourselves (the credentials of
5444 * the socketpair is ours) */
5445 if (pid == getpid())
5446 return;
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04005447
Daniel Stone325fc2d2012-05-30 16:31:58 +01005448 kill(pid, SIGKILL);
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04005449}
5450
5451static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04005452workspace_up_binding(struct weston_seat *seat, uint32_t time,
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005453 uint32_t key, void *data)
5454{
5455 struct desktop_shell *shell = data;
5456 unsigned int new_index = shell->workspaces.current;
5457
Kristian Høgsbergce345b02012-06-25 21:35:29 -04005458 if (shell->locked)
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04005459 return;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005460 if (new_index != 0)
5461 new_index--;
5462
5463 change_workspace(shell, new_index);
5464}
5465
5466static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04005467workspace_down_binding(struct weston_seat *seat, uint32_t time,
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005468 uint32_t key, void *data)
5469{
5470 struct desktop_shell *shell = data;
5471 unsigned int new_index = shell->workspaces.current;
5472
Kristian Høgsbergce345b02012-06-25 21:35:29 -04005473 if (shell->locked)
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04005474 return;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005475 if (new_index < shell->workspaces.num - 1)
5476 new_index++;
5477
5478 change_workspace(shell, new_index);
5479}
5480
5481static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04005482workspace_f_binding(struct weston_seat *seat, uint32_t time,
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005483 uint32_t key, void *data)
5484{
5485 struct desktop_shell *shell = data;
5486 unsigned int new_index;
5487
Kristian Høgsbergce345b02012-06-25 21:35:29 -04005488 if (shell->locked)
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04005489 return;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005490 new_index = key - KEY_F1;
5491 if (new_index >= shell->workspaces.num)
5492 new_index = shell->workspaces.num - 1;
5493
5494 change_workspace(shell, new_index);
5495}
5496
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02005497static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04005498workspace_move_surface_up_binding(struct weston_seat *seat, uint32_t time,
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02005499 uint32_t key, void *data)
5500{
5501 struct desktop_shell *shell = data;
5502 unsigned int new_index = shell->workspaces.current;
5503
5504 if (shell->locked)
5505 return;
5506
5507 if (new_index != 0)
5508 new_index--;
5509
5510 take_surface_to_workspace_by_seat(shell, seat, new_index);
5511}
5512
5513static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04005514workspace_move_surface_down_binding(struct weston_seat *seat, uint32_t time,
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02005515 uint32_t key, void *data)
5516{
5517 struct desktop_shell *shell = data;
5518 unsigned int new_index = shell->workspaces.current;
5519
5520 if (shell->locked)
5521 return;
5522
5523 if (new_index < shell->workspaces.num - 1)
5524 new_index++;
5525
5526 take_surface_to_workspace_by_seat(shell, seat, new_index);
5527}
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005528
5529static void
Ander Conselvan de Oliveirac94d6222014-01-29 18:47:54 +02005530shell_reposition_view_on_output_destroy(struct weston_view *view)
5531{
5532 struct weston_output *output, *first_output;
5533 struct weston_compositor *ec = view->surface->compositor;
5534 struct shell_surface *shsurf;
5535 float x, y;
5536 int visible;
5537
5538 x = view->geometry.x;
5539 y = view->geometry.y;
5540
5541 /* At this point the destroyed output is not in the list anymore.
5542 * If the view is still visible somewhere, we leave where it is,
5543 * otherwise, move it to the first output. */
5544 visible = 0;
5545 wl_list_for_each(output, &ec->output_list, link) {
5546 if (pixman_region32_contains_point(&output->region,
5547 x, y, NULL)) {
5548 visible = 1;
5549 break;
5550 }
5551 }
5552
5553 if (!visible) {
5554 first_output = container_of(ec->output_list.next,
5555 struct weston_output, link);
5556
5557 x = first_output->x + first_output->width / 4;
5558 y = first_output->y + first_output->height / 4;
5559 }
5560
5561 weston_view_set_position(view, x, y);
5562
5563 shsurf = get_shell_surface(view->surface);
5564
5565 if (shsurf) {
5566 shsurf->saved_position_valid = false;
5567 shsurf->next_state.maximized = false;
5568 shsurf->next_state.fullscreen = false;
5569 shsurf->state_changed = true;
5570 }
5571}
5572
5573static void
5574shell_reposition_views_on_output_destroy(struct shell_output *shell_output)
5575{
5576 struct desktop_shell *shell = shell_output->shell;
5577 struct weston_output *output = shell_output->output;
5578 struct weston_layer *layer;
5579 struct weston_view *view;
5580
5581 /* Move all views in the layers owned by the shell */
5582 wl_list_for_each(layer, shell->fullscreen_layer.link.prev, link) {
5583 wl_list_for_each(view, &layer->view_list, layer_link) {
5584 if (view->output != output)
5585 continue;
5586
5587 shell_reposition_view_on_output_destroy(view);
5588 }
5589
5590 /* We don't start from the beggining of the layer list, so
5591 * make sure we don't wrap around it. */
5592 if (layer == &shell->background_layer)
5593 break;
5594 }
5595}
5596
5597static void
Xiong Zhang6b481422013-10-23 13:58:32 +08005598handle_output_destroy(struct wl_listener *listener, void *data)
5599{
5600 struct shell_output *output_listener =
5601 container_of(listener, struct shell_output, destroy_listener);
5602
Ander Conselvan de Oliveirac94d6222014-01-29 18:47:54 +02005603 shell_reposition_views_on_output_destroy(output_listener);
5604
Xiong Zhang6b481422013-10-23 13:58:32 +08005605 wl_list_remove(&output_listener->destroy_listener.link);
5606 wl_list_remove(&output_listener->link);
5607 free(output_listener);
5608}
5609
5610static void
5611create_shell_output(struct desktop_shell *shell,
5612 struct weston_output *output)
5613{
5614 struct shell_output *shell_output;
5615
5616 shell_output = zalloc(sizeof *shell_output);
5617 if (shell_output == NULL)
5618 return;
5619
5620 shell_output->output = output;
5621 shell_output->shell = shell;
5622 shell_output->destroy_listener.notify = handle_output_destroy;
5623 wl_signal_add(&output->destroy_signal,
5624 &shell_output->destroy_listener);
Kristian Høgsberga3a0e182013-10-23 23:36:04 -07005625 wl_list_insert(shell->output_list.prev, &shell_output->link);
Xiong Zhang6b481422013-10-23 13:58:32 +08005626}
5627
5628static void
5629handle_output_create(struct wl_listener *listener, void *data)
5630{
5631 struct desktop_shell *shell =
5632 container_of(listener, struct desktop_shell, output_create_listener);
5633 struct weston_output *output = (struct weston_output *)data;
5634
5635 create_shell_output(shell, output);
5636}
5637
5638static void
Ander Conselvan de Oliveiraa8a9baf2014-01-29 18:47:52 +02005639handle_output_move(struct wl_listener *listener, void *data)
5640{
5641 struct desktop_shell *shell;
5642 struct weston_output *output;
5643 struct weston_layer *layer;
5644 struct weston_view *view;
5645 float x, y;
5646
5647 shell = container_of(listener, struct desktop_shell,
5648 output_move_listener);
5649 output = data;
5650
5651 /* Move all views in the layers owned by the shell */
5652 wl_list_for_each(layer, shell->fullscreen_layer.link.prev, link) {
5653 wl_list_for_each(view, &layer->view_list, layer_link) {
5654 if (view->output != output)
5655 continue;
5656
5657 x = view->geometry.x + output->move_x;
5658 y = view->geometry.y + output->move_y;
5659 weston_view_set_position(view, x, y);
5660 }
5661
5662 /* We don't start from the beggining of the layer list, so
5663 * make sure we don't wrap around it. */
5664 if (layer == &shell->background_layer)
5665 break;
5666 }
5667}
5668
5669static void
Xiong Zhang6b481422013-10-23 13:58:32 +08005670setup_output_destroy_handler(struct weston_compositor *ec,
5671 struct desktop_shell *shell)
5672{
5673 struct weston_output *output;
5674
5675 wl_list_init(&shell->output_list);
5676 wl_list_for_each(output, &ec->output_list, link)
5677 create_shell_output(shell, output);
5678
5679 shell->output_create_listener.notify = handle_output_create;
5680 wl_signal_add(&ec->output_created_signal,
5681 &shell->output_create_listener);
Ander Conselvan de Oliveiraa8a9baf2014-01-29 18:47:52 +02005682
5683 shell->output_move_listener.notify = handle_output_move;
5684 wl_signal_add(&ec->output_moved_signal, &shell->output_move_listener);
Xiong Zhang6b481422013-10-23 13:58:32 +08005685}
5686
5687static void
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04005688shell_destroy(struct wl_listener *listener, void *data)
Pekka Paalanen3c647232011-12-22 13:43:43 +02005689{
Tiago Vignattibe143262012-04-16 17:31:41 +03005690 struct desktop_shell *shell =
5691 container_of(listener, struct desktop_shell, destroy_listener);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005692 struct workspace **ws;
Xiong Zhang6b481422013-10-23 13:58:32 +08005693 struct shell_output *shell_output, *tmp;
Pekka Paalanen3c647232011-12-22 13:43:43 +02005694
Kristian Høgsberg17bccae2014-01-16 16:46:28 -08005695 /* Force state to unlocked so we don't try to fade */
5696 shell->locked = false;
Pekka Paalanen9cf5cc82012-01-02 16:00:24 +02005697 if (shell->child.client)
5698 wl_client_destroy(shell->child.client);
5699
Ander Conselvan de Oliveiraa4575632013-02-21 18:35:23 +02005700 wl_list_remove(&shell->idle_listener.link);
5701 wl_list_remove(&shell->wake_listener.link);
Kristian Høgsberg677a5f52013-12-04 11:00:19 -08005702
5703 input_panel_destroy(shell);
Kristian Høgsberg88c16072012-05-16 08:04:19 -04005704
Xiong Zhang6b481422013-10-23 13:58:32 +08005705 wl_list_for_each_safe(shell_output, tmp, &shell->output_list, link) {
5706 wl_list_remove(&shell_output->destroy_listener.link);
5707 wl_list_remove(&shell_output->link);
5708 free(shell_output);
5709 }
5710
5711 wl_list_remove(&shell->output_create_listener.link);
5712
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005713 wl_array_for_each(ws, &shell->workspaces.array)
5714 workspace_destroy(*ws);
5715 wl_array_release(&shell->workspaces.array);
5716
Pekka Paalanen3c647232011-12-22 13:43:43 +02005717 free(shell->screensaver.path);
Emilio Pozuelo Monfort46ce7982013-11-20 13:22:29 +01005718 free(shell->client);
Pekka Paalanen3c647232011-12-22 13:43:43 +02005719 free(shell);
5720}
5721
Tiago Vignatti0b52d482012-04-20 18:54:25 +03005722static void
5723shell_add_bindings(struct weston_compositor *ec, struct desktop_shell *shell)
5724{
5725 uint32_t mod;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005726 int i, num_workspace_bindings;
Tiago Vignatti0b52d482012-04-20 18:54:25 +03005727
5728 /* fixed bindings */
Daniel Stone325fc2d2012-05-30 16:31:58 +01005729 weston_compositor_add_key_binding(ec, KEY_BACKSPACE,
5730 MODIFIER_CTRL | MODIFIER_ALT,
5731 terminate_binding, ec);
5732 weston_compositor_add_button_binding(ec, BTN_LEFT, 0,
5733 click_to_activate_binding,
5734 shell);
Neil Robertsa28c6932013-10-03 16:43:04 +01005735 weston_compositor_add_touch_binding(ec, 0,
5736 touch_to_activate_binding,
5737 shell);
Daniel Stone325fc2d2012-05-30 16:31:58 +01005738 weston_compositor_add_axis_binding(ec, WL_POINTER_AXIS_VERTICAL_SCROLL,
5739 MODIFIER_SUPER | MODIFIER_ALT,
5740 surface_opacity_binding, NULL);
5741 weston_compositor_add_axis_binding(ec, WL_POINTER_AXIS_VERTICAL_SCROLL,
5742 MODIFIER_SUPER, zoom_axis_binding,
5743 NULL);
Tiago Vignatti0b52d482012-04-20 18:54:25 +03005744
5745 /* configurable bindings */
5746 mod = shell->binding_modifier;
Daniel Stone325fc2d2012-05-30 16:31:58 +01005747 weston_compositor_add_key_binding(ec, KEY_PAGEUP, mod,
5748 zoom_key_binding, NULL);
5749 weston_compositor_add_key_binding(ec, KEY_PAGEDOWN, mod,
5750 zoom_key_binding, NULL);
Kristian Høgsberg211b5172014-01-11 13:10:21 -08005751 weston_compositor_add_key_binding(ec, KEY_M, mod | MODIFIER_SHIFT,
5752 maximize_binding, NULL);
5753 weston_compositor_add_key_binding(ec, KEY_F, mod | MODIFIER_SHIFT,
5754 fullscreen_binding, NULL);
Daniel Stone325fc2d2012-05-30 16:31:58 +01005755 weston_compositor_add_button_binding(ec, BTN_LEFT, mod, move_binding,
5756 shell);
Neil Robertsaba0f252013-10-03 16:43:05 +01005757 weston_compositor_add_touch_binding(ec, mod, touch_move_binding, shell);
Daniel Stone325fc2d2012-05-30 16:31:58 +01005758 weston_compositor_add_button_binding(ec, BTN_MIDDLE, mod,
5759 resize_binding, shell);
Kristian Høgsberg0837fa92014-01-20 10:35:26 -08005760 weston_compositor_add_button_binding(ec, BTN_LEFT,
5761 mod | MODIFIER_SHIFT,
5762 resize_binding, shell);
Pekka Paalanen7bb65102013-05-22 18:03:04 +03005763
5764 if (ec->capabilities & WESTON_CAP_ROTATION_ANY)
5765 weston_compositor_add_button_binding(ec, BTN_RIGHT, mod,
5766 rotate_binding, NULL);
5767
Daniel Stone325fc2d2012-05-30 16:31:58 +01005768 weston_compositor_add_key_binding(ec, KEY_TAB, mod, switcher_binding,
5769 shell);
5770 weston_compositor_add_key_binding(ec, KEY_F9, mod, backlight_binding,
5771 ec);
5772 weston_compositor_add_key_binding(ec, KEY_BRIGHTNESSDOWN, 0,
5773 backlight_binding, ec);
5774 weston_compositor_add_key_binding(ec, KEY_F10, mod, backlight_binding,
5775 ec);
5776 weston_compositor_add_key_binding(ec, KEY_BRIGHTNESSUP, 0,
5777 backlight_binding, ec);
Daniel Stone325fc2d2012-05-30 16:31:58 +01005778 weston_compositor_add_key_binding(ec, KEY_K, mod,
5779 force_kill_binding, shell);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005780 weston_compositor_add_key_binding(ec, KEY_UP, mod,
5781 workspace_up_binding, shell);
5782 weston_compositor_add_key_binding(ec, KEY_DOWN, mod,
5783 workspace_down_binding, shell);
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02005784 weston_compositor_add_key_binding(ec, KEY_UP, mod | MODIFIER_SHIFT,
5785 workspace_move_surface_up_binding,
5786 shell);
5787 weston_compositor_add_key_binding(ec, KEY_DOWN, mod | MODIFIER_SHIFT,
5788 workspace_move_surface_down_binding,
5789 shell);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005790
Kristian Høgsbergd56ab4e2014-01-16 16:51:52 -08005791 if (shell->exposay_modifier)
5792 weston_compositor_add_modifier_binding(ec, shell->exposay_modifier,
5793 exposay_binding, shell);
Daniel Stonedf8133b2013-11-19 11:37:14 +01005794
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005795 /* Add bindings for mod+F[1-6] for workspace 1 to 6. */
5796 if (shell->workspaces.num > 1) {
5797 num_workspace_bindings = shell->workspaces.num;
5798 if (num_workspace_bindings > 6)
5799 num_workspace_bindings = 6;
5800 for (i = 0; i < num_workspace_bindings; i++)
5801 weston_compositor_add_key_binding(ec, KEY_F1 + i, mod,
5802 workspace_f_binding,
5803 shell);
5804 }
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005805
5806 /* Debug bindings */
5807 weston_compositor_add_key_binding(ec, KEY_SPACE, mod | MODIFIER_SHIFT,
5808 debug_binding, shell);
Tiago Vignatti0b52d482012-04-20 18:54:25 +03005809}
5810
Kristian Høgsberg1c562182011-05-02 22:09:20 -04005811WL_EXPORT int
Kristian Høgsbergcb4685b2013-02-20 15:37:49 -05005812module_init(struct weston_compositor *ec,
Ossama Othmana50e6e42013-05-14 09:48:26 -07005813 int *argc, char *argv[])
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05005814{
Kristian Høgsbergf4d2f232012-08-10 10:05:39 -04005815 struct weston_seat *seat;
Tiago Vignattibe143262012-04-16 17:31:41 +03005816 struct desktop_shell *shell;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005817 struct workspace **pws;
5818 unsigned int i;
Tiago Vignattib7dbbd62012-09-25 17:57:01 +03005819 struct wl_event_loop *loop;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04005820
Peter Huttererf3d62272013-08-08 11:57:05 +10005821 shell = zalloc(sizeof *shell);
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04005822 if (shell == NULL)
5823 return -1;
5824
Kristian Høgsberg75840622011-09-06 13:48:16 -04005825 shell->compositor = ec;
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04005826
5827 shell->destroy_listener.notify = shell_destroy;
5828 wl_signal_add(&ec->destroy_signal, &shell->destroy_listener);
Ander Conselvan de Oliveiraa4575632013-02-21 18:35:23 +02005829 shell->idle_listener.notify = idle_handler;
5830 wl_signal_add(&ec->idle_signal, &shell->idle_listener);
5831 shell->wake_listener.notify = wake_handler;
5832 wl_signal_add(&ec->wake_signal, &shell->wake_listener);
Kristian Høgsberg677a5f52013-12-04 11:00:19 -08005833
Kristian Høgsberg82a1d112012-07-19 14:02:00 -04005834 ec->shell_interface.shell = shell;
Tiago Vignattibc052c92012-04-19 16:18:18 +03005835 ec->shell_interface.create_shell_surface = create_shell_surface;
Jason Ekstranda7af7042013-10-12 22:38:11 -05005836 ec->shell_interface.get_primary_view = get_primary_view;
Tiago Vignattibc052c92012-04-19 16:18:18 +03005837 ec->shell_interface.set_toplevel = set_toplevel;
Tiago Vignatti491bac12012-05-18 16:37:43 -04005838 ec->shell_interface.set_transient = set_transient;
Kristian Høgsbergb810eb52013-02-12 20:07:05 -05005839 ec->shell_interface.set_fullscreen = set_fullscreen;
Tiago Vignattifb2adba2013-06-12 15:43:21 -03005840 ec->shell_interface.set_xwayland = set_xwayland;
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04005841 ec->shell_interface.move = surface_move;
Kristian Høgsbergc1693f22012-05-22 16:56:23 -04005842 ec->shell_interface.resize = surface_resize;
Giulio Camuffo62942ad2013-09-11 18:20:47 +02005843 ec->shell_interface.set_title = set_title;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05005844
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05005845 weston_layer_init(&shell->fullscreen_layer, &ec->cursor_layer.link);
5846 weston_layer_init(&shell->panel_layer, &shell->fullscreen_layer.link);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005847 weston_layer_init(&shell->background_layer, &shell->panel_layer.link);
5848 weston_layer_init(&shell->lock_layer, NULL);
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02005849 weston_layer_init(&shell->input_panel_layer, NULL);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005850
5851 wl_array_init(&shell->workspaces.array);
Jonas Ådahle9d22502012-08-29 22:13:01 +02005852 wl_list_init(&shell->workspaces.client_list);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05005853
Kristian Høgsberg677a5f52013-12-04 11:00:19 -08005854 if (input_panel_setup(shell) < 0)
5855 return -1;
5856
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04005857 shell_configuration(shell);
Pekka Paalanene955f1e2011-12-07 11:49:52 +02005858
Daniel Stonedf8133b2013-11-19 11:37:14 +01005859 shell->exposay.state_cur = EXPOSAY_LAYOUT_INACTIVE;
5860 shell->exposay.state_target = EXPOSAY_TARGET_CANCEL;
5861
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005862 for (i = 0; i < shell->workspaces.num; i++) {
5863 pws = wl_array_add(&shell->workspaces.array, sizeof *pws);
5864 if (pws == NULL)
5865 return -1;
5866
5867 *pws = workspace_create();
5868 if (*pws == NULL)
5869 return -1;
5870 }
5871 activate_workspace(shell, 0);
5872
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02005873 wl_list_init(&shell->workspaces.anim_sticky_list);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02005874 wl_list_init(&shell->workspaces.animation.link);
5875 shell->workspaces.animation.frame = animate_workspace_change_frame;
5876
Kristian Høgsberg919cddb2013-07-08 19:03:57 -04005877 if (wl_global_create(ec->wl_display, &wl_shell_interface, 1,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04005878 shell, bind_shell) == NULL)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05005879 return -1;
5880
Rafael Antognollie2a34552013-12-03 15:35:45 -02005881 if (wl_global_create(ec->wl_display, &xdg_shell_interface, 1,
5882 shell, bind_xdg_shell) == NULL)
5883 return -1;
5884
Kristian Høgsberg919cddb2013-07-08 19:03:57 -04005885 if (wl_global_create(ec->wl_display,
5886 &desktop_shell_interface, 2,
5887 shell, bind_desktop_shell) == NULL)
Kristian Høgsberg75840622011-09-06 13:48:16 -04005888 return -1;
5889
Kristian Høgsberg919cddb2013-07-08 19:03:57 -04005890 if (wl_global_create(ec->wl_display, &screensaver_interface, 1,
5891 shell, bind_screensaver) == NULL)
Pekka Paalanen6e168112011-11-24 11:34:05 +02005892 return -1;
5893
Kristian Høgsberg919cddb2013-07-08 19:03:57 -04005894 if (wl_global_create(ec->wl_display, &workspace_manager_interface, 1,
5895 shell, bind_workspace_manager) == NULL)
Jonas Ådahle9d22502012-08-29 22:13:01 +02005896 return -1;
5897
Kristian Høgsbergf03a6162012-01-17 11:07:42 -05005898 shell->child.deathstamp = weston_compositor_get_time();
Tiago Vignattib7dbbd62012-09-25 17:57:01 +03005899
Xiong Zhang6b481422013-10-23 13:58:32 +08005900 setup_output_destroy_handler(ec, shell);
5901
Tiago Vignattib7dbbd62012-09-25 17:57:01 +03005902 loop = wl_display_get_event_loop(ec->wl_display);
5903 wl_event_loop_add_idle(loop, launch_desktop_shell_process, shell);
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02005904
Ander Conselvan de Oliveira859e8852013-02-21 18:35:21 +02005905 shell->screensaver.timer =
5906 wl_event_loop_add_timer(loop, screensaver_timeout, shell);
5907
Jasper St. Pierrefaf27a92013-12-09 17:36:28 -05005908 wl_list_for_each(seat, &ec->seat_list, link) {
Kristian Høgsbergf4d2f232012-08-10 10:05:39 -04005909 create_pointer_focus_listener(seat);
Jasper St. Pierrefaf27a92013-12-09 17:36:28 -05005910 create_keyboard_focus_listener(seat);
5911 }
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04005912
Tiago Vignatti0b52d482012-04-20 18:54:25 +03005913 shell_add_bindings(ec, shell);
Kristian Høgsberg07937562011-04-12 17:25:42 -04005914
Pekka Paalanen79346ab2013-05-22 18:03:09 +03005915 shell_fade_init(shell);
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02005916
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05005917 return 0;
5918}