blob: e8abeb596c187b3f6467765a9177969af487830f [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;
Rafael Antognolli03b16592013-12-03 15:35:42 -0200164 } state, next_state; /* surface states */
165 bool state_changed;
Jasper St. Pierrefaf27a92013-12-09 17:36:28 -0500166
167 int focus_count;
Pekka Paalanen56cdea92011-11-23 16:14:12 +0200168};
169
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300170struct shell_grab {
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -0400171 struct weston_pointer_grab grab;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300172 struct shell_surface *shsurf;
173 struct wl_listener shsurf_destroy_listener;
174};
175
Rusty Lynch1084da52013-08-15 09:10:08 -0700176struct shell_touch_grab {
177 struct weston_touch_grab grab;
178 struct shell_surface *shsurf;
179 struct wl_listener shsurf_destroy_listener;
180 struct weston_touch *touch;
181};
182
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300183struct weston_move_grab {
184 struct shell_grab base;
Daniel Stone103db7f2012-05-08 17:17:55 +0100185 wl_fixed_t dx, dy;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500186};
187
Rusty Lynch1084da52013-08-15 09:10:08 -0700188struct weston_touch_move_grab {
189 struct shell_touch_grab base;
Kristian Høgsberg8e80a312014-01-17 15:18:10 -0800190 int active;
Rusty Lynch1084da52013-08-15 09:10:08 -0700191 wl_fixed_t dx, dy;
192};
193
Pekka Paalanen460099f2012-01-20 16:48:25 +0200194struct rotate_grab {
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300195 struct shell_grab base;
Kristian Høgsberg765e27b2012-01-27 13:36:13 -0500196 struct weston_matrix rotation;
Pekka Paalanen460099f2012-01-20 16:48:25 +0200197 struct {
John Kåre Alsaker490d02a2012-09-30 02:57:21 +0200198 float x;
199 float y;
Pekka Paalanen460099f2012-01-20 16:48:25 +0200200 } center;
201};
202
Giulio Camuffo5085a752013-03-25 21:42:45 +0100203struct shell_seat {
204 struct weston_seat *seat;
205 struct wl_listener seat_destroy_listener;
Jasper St. Pierrefaf27a92013-12-09 17:36:28 -0500206 struct weston_surface *focused_surface;
Giulio Camuffo5085a752013-03-25 21:42:45 +0100207
208 struct {
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -0400209 struct weston_pointer_grab grab;
Giulio Camuffo5085a752013-03-25 21:42:45 +0100210 struct wl_list surfaces_list;
211 struct wl_client *client;
212 int32_t initial_up;
213 } popup_grab;
214};
215
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -0800216struct shell_client {
217 struct wl_resource *resource;
218 struct wl_client *client;
219 struct desktop_shell *shell;
220 struct wl_listener destroy_listener;
221 struct wl_event_source *ping_timer;
222 uint32_t ping_serial;
223 int unresponsive;
224};
225
Emilio Pozuelo Monfort1a26f1b2014-01-07 16:41:40 +0100226void
227set_alpha_if_fullscreen(struct shell_surface *shsurf)
228{
229 if (shsurf && shsurf->state.fullscreen)
230 shsurf->fullscreen.black_view->alpha = 0.25;
231}
232
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -0800233static struct shell_client *
234get_shell_client(struct wl_client *client);
235
Alex Wubd3354b2012-04-17 17:20:49 +0800236static struct desktop_shell *
237shell_surface_get_shell(struct shell_surface *shsurf);
238
Kristian Høgsberg0c369032013-02-14 21:31:44 -0500239static void
Kristian Høgsberge3148752013-05-06 23:19:49 -0400240surface_rotate(struct shell_surface *surface, struct weston_seat *seat);
Kristian Høgsberg0c369032013-02-14 21:31:44 -0500241
Pekka Paalanen79346ab2013-05-22 18:03:09 +0300242static void
243shell_fade_startup(struct desktop_shell *shell);
244
Philip Withnallbecb77e2013-11-25 18:01:30 +0000245static struct shell_seat *
246get_shell_seat(struct weston_seat *seat);
247
Philip Withnall648a4dd2013-11-25 18:01:44 +0000248static void
249shell_surface_update_child_surface_layers(struct shell_surface *shsurf);
250
Alex Wubd3354b2012-04-17 17:20:49 +0800251static bool
Rafael Antognollie2a34552013-12-03 15:35:45 -0200252shell_surface_is_wl_shell_surface(struct shell_surface *shsurf);
253
254static bool
255shell_surface_is_xdg_surface(struct shell_surface *shsurf);
256
257static bool
258shell_surface_is_xdg_popup(struct shell_surface *shsurf);
259
260static void
261shell_surface_set_parent(struct shell_surface *shsurf,
262 struct weston_surface *parent);
263
264static bool
Alex Wubd3354b2012-04-17 17:20:49 +0800265shell_surface_is_top_fullscreen(struct shell_surface *shsurf)
266{
267 struct desktop_shell *shell;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500268 struct weston_view *top_fs_ev;
Alex Wubd3354b2012-04-17 17:20:49 +0800269
270 shell = shell_surface_get_shell(shsurf);
Quentin Glidicc0d79ce2013-01-29 14:16:13 +0100271
Jason Ekstranda7af7042013-10-12 22:38:11 -0500272 if (wl_list_empty(&shell->fullscreen_layer.view_list))
Alex Wubd3354b2012-04-17 17:20:49 +0800273 return false;
274
Jason Ekstranda7af7042013-10-12 22:38:11 -0500275 top_fs_ev = container_of(shell->fullscreen_layer.view_list.next,
276 struct weston_view,
Alex Wubd3354b2012-04-17 17:20:49 +0800277 layer_link);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500278 return (shsurf == get_shell_surface(top_fs_ev->surface));
Alex Wubd3354b2012-04-17 17:20:49 +0800279}
280
Kristian Høgsberg6af8eb92012-01-25 16:57:11 -0500281static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400282destroy_shell_grab_shsurf(struct wl_listener *listener, void *data)
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300283{
284 struct shell_grab *grab;
285
286 grab = container_of(listener, struct shell_grab,
287 shsurf_destroy_listener);
288
289 grab->shsurf = NULL;
290}
291
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800292struct weston_view *
Jason Ekstranda7af7042013-10-12 22:38:11 -0500293get_default_view(struct weston_surface *surface)
294{
295 struct shell_surface *shsurf;
296 struct weston_view *view;
297
298 if (!surface || wl_list_empty(&surface->views))
299 return NULL;
300
301 shsurf = get_shell_surface(surface);
302 if (shsurf)
303 return shsurf->view;
304
305 wl_list_for_each(view, &surface->views, surface_link)
306 if (weston_view_is_mapped(view))
307 return view;
308
309 return container_of(surface->views.next, struct weston_view, surface_link);
310}
311
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300312static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -0400313popup_grab_end(struct weston_pointer *pointer);
Kristian Høgsberg57e09072012-10-30 14:07:27 -0400314
315static void
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300316shell_grab_start(struct shell_grab *grab,
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -0400317 const struct weston_pointer_grab_interface *interface,
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300318 struct shell_surface *shsurf,
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -0400319 struct weston_pointer *pointer,
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300320 enum desktop_shell_cursor cursor)
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300321{
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300322 struct desktop_shell *shell = shsurf->shell;
323
Kristian Høgsberg57e09072012-10-30 14:07:27 -0400324 popup_grab_end(pointer);
325
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300326 grab->grab.interface = interface;
327 grab->shsurf = shsurf;
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400328 grab->shsurf_destroy_listener.notify = destroy_shell_grab_shsurf;
Jason Ekstrand651f00e2013-06-14 10:07:54 -0500329 wl_signal_add(&shsurf->destroy_signal,
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400330 &grab->shsurf_destroy_listener);
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300331
Kristian Høgsbergc85f1d42013-10-24 16:52:00 -0700332 shsurf->grabbed = 1;
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -0400333 weston_pointer_start_grab(pointer, &grab->grab);
Kristian Høgsbergc9974a02013-07-03 19:24:57 -0400334 if (shell->child.desktop_shell) {
335 desktop_shell_send_grab_cursor(shell->child.desktop_shell,
336 cursor);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500337 weston_pointer_set_focus(pointer,
338 get_default_view(shell->grab_surface),
Kristian Høgsbergc9974a02013-07-03 19:24:57 -0400339 wl_fixed_from_int(0),
340 wl_fixed_from_int(0));
341 }
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300342}
343
344static void
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300345shell_grab_end(struct shell_grab *grab)
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300346{
Kristian Høgsbergc85f1d42013-10-24 16:52:00 -0700347 if (grab->shsurf) {
Kristian Høgsberg47b5dca2012-06-07 18:08:04 -0400348 wl_list_remove(&grab->shsurf_destroy_listener.link);
Kristian Høgsbergc85f1d42013-10-24 16:52:00 -0700349 grab->shsurf->grabbed = 0;
Kristian Høgsberg44cd1962014-02-05 21:36:04 -0800350 grab->shsurf->resize_edges = 0;
Kristian Høgsbergc85f1d42013-10-24 16:52:00 -0700351 }
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300352
Kristian Høgsberg9e5d7d12013-07-22 16:31:53 -0700353 weston_pointer_end_grab(grab->grab.pointer);
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300354}
355
356static void
Rusty Lynch1084da52013-08-15 09:10:08 -0700357shell_touch_grab_start(struct shell_touch_grab *grab,
358 const struct weston_touch_grab_interface *interface,
359 struct shell_surface *shsurf,
360 struct weston_touch *touch)
361{
362 struct desktop_shell *shell = shsurf->shell;
U. Artie Eoffcf5737a2014-01-17 10:08:25 -0800363
Rusty Lynch1084da52013-08-15 09:10:08 -0700364 grab->grab.interface = interface;
365 grab->shsurf = shsurf;
366 grab->shsurf_destroy_listener.notify = destroy_shell_grab_shsurf;
367 wl_signal_add(&shsurf->destroy_signal,
368 &grab->shsurf_destroy_listener);
369
370 grab->touch = touch;
Kristian Høgsbergc85f1d42013-10-24 16:52:00 -0700371 shsurf->grabbed = 1;
Rusty Lynch1084da52013-08-15 09:10:08 -0700372
373 weston_touch_start_grab(touch, &grab->grab);
374 if (shell->child.desktop_shell)
Jason Ekstranda7af7042013-10-12 22:38:11 -0500375 weston_touch_set_focus(touch->seat,
376 get_default_view(shell->grab_surface));
Rusty Lynch1084da52013-08-15 09:10:08 -0700377}
378
379static void
380shell_touch_grab_end(struct shell_touch_grab *grab)
381{
Kristian Høgsbergc85f1d42013-10-24 16:52:00 -0700382 if (grab->shsurf) {
Rusty Lynch1084da52013-08-15 09:10:08 -0700383 wl_list_remove(&grab->shsurf_destroy_listener.link);
Kristian Høgsbergc85f1d42013-10-24 16:52:00 -0700384 grab->shsurf->grabbed = 0;
385 }
Rusty Lynch1084da52013-08-15 09:10:08 -0700386
387 weston_touch_end_grab(grab->touch);
388}
389
390static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500391center_on_output(struct weston_view *view,
Alex Wu4539b082012-03-01 12:57:46 +0800392 struct weston_output *output);
393
Daniel Stone496ca172012-05-30 16:31:42 +0100394static enum weston_keyboard_modifier
Tiago Vignatti0b52d482012-04-20 18:54:25 +0300395get_modifier(char *modifier)
396{
397 if (!modifier)
398 return MODIFIER_SUPER;
399
400 if (!strcmp("ctrl", modifier))
401 return MODIFIER_CTRL;
402 else if (!strcmp("alt", modifier))
403 return MODIFIER_ALT;
404 else if (!strcmp("super", modifier))
405 return MODIFIER_SUPER;
406 else
407 return MODIFIER_SUPER;
408}
409
Juan Zhaoe10d2792012-04-25 19:09:52 +0800410static enum animation_type
411get_animation_type(char *animation)
412{
U. Artie Eoffb5719102014-01-15 14:26:31 -0800413 if (!animation)
414 return ANIMATION_NONE;
415
Juan Zhaoe10d2792012-04-25 19:09:52 +0800416 if (!strcmp("zoom", animation))
417 return ANIMATION_ZOOM;
418 else if (!strcmp("fade", animation))
419 return ANIMATION_FADE;
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100420 else if (!strcmp("dim-layer", animation))
421 return ANIMATION_DIM_LAYER;
Juan Zhaoe10d2792012-04-25 19:09:52 +0800422 else
423 return ANIMATION_NONE;
424}
425
Alex Wu4539b082012-03-01 12:57:46 +0800426static void
Kristian Høgsberg14e438c2013-05-26 21:48:14 -0400427shell_configuration(struct desktop_shell *shell)
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200428{
Kristian Høgsberg673a8892013-05-23 21:40:56 -0400429 struct weston_config_section *section;
430 int duration;
431 char *s;
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200432
Kristian Høgsberg673a8892013-05-23 21:40:56 -0400433 section = weston_config_get_section(shell->compositor->config,
434 "screensaver", NULL, NULL);
435 weston_config_section_get_string(section,
436 "path", &shell->screensaver.path, NULL);
437 weston_config_section_get_int(section, "duration", &duration, 60);
Ander Conselvan de Oliveira859e8852013-02-21 18:35:21 +0200438 shell->screensaver.duration = duration * 1000;
Kristian Høgsberg673a8892013-05-23 21:40:56 -0400439
440 section = weston_config_get_section(shell->compositor->config,
441 "shell", NULL, NULL);
442 weston_config_section_get_string(section,
Emilio Pozuelo Monfort8a81b832013-12-02 12:53:32 +0100443 "client", &s, LIBEXECDIR "/" WESTON_SHELL_CLIENT);
Emilio Pozuelo Monfort46ce7982013-11-20 13:22:29 +0100444 shell->client = s;
445 weston_config_section_get_string(section,
Kristian Høgsberg673a8892013-05-23 21:40:56 -0400446 "binding-modifier", &s, "super");
447 shell->binding_modifier = get_modifier(s);
Quentin Glidic8418c292013-06-18 09:11:03 +0200448 free(s);
Kristian Høgsbergd56ab4e2014-01-16 16:51:52 -0800449
450 weston_config_section_get_string(section,
451 "exposay-modifier", &s, "none");
452 if (strcmp(s, "none") == 0)
453 shell->exposay_modifier = 0;
454 else
455 shell->exposay_modifier = get_modifier(s);
456 free(s);
457
Kristian Høgsberg673a8892013-05-23 21:40:56 -0400458 weston_config_section_get_string(section, "animation", &s, "none");
459 shell->win_animation_type = get_animation_type(s);
Quentin Glidic8418c292013-06-18 09:11:03 +0200460 free(s);
Kristian Høgsberg724c8d92013-10-16 11:38:24 -0700461 weston_config_section_get_string(section,
462 "startup-animation", &s, "fade");
463 shell->startup_animation_type = get_animation_type(s);
464 free(s);
Kristian Høgsberg912e0a12013-10-30 08:59:55 -0700465 if (shell->startup_animation_type == ANIMATION_ZOOM)
466 shell->startup_animation_type = ANIMATION_NONE;
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100467 weston_config_section_get_string(section, "focus-animation", &s, "none");
468 shell->focus_animation_type = get_animation_type(s);
469 free(s);
Kristian Høgsberg673a8892013-05-23 21:40:56 -0400470 weston_config_section_get_uint(section, "num-workspaces",
471 &shell->workspaces.num,
472 DEFAULT_NUM_WORKSPACES);
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200473}
474
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800475struct weston_output *
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100476get_default_output(struct weston_compositor *compositor)
477{
478 return container_of(compositor->output_list.next,
479 struct weston_output, link);
480}
481
482
483/* no-op func for checking focus surface */
484static void
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600485focus_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100486{
487}
488
489static struct focus_surface *
490get_focus_surface(struct weston_surface *surface)
491{
492 if (surface->configure == focus_surface_configure)
493 return surface->configure_private;
494 else
495 return NULL;
496}
497
498static bool
499is_focus_surface (struct weston_surface *es)
500{
501 return (es->configure == focus_surface_configure);
502}
503
504static bool
505is_focus_view (struct weston_view *view)
506{
507 return is_focus_surface (view->surface);
508}
509
510static struct focus_surface *
511create_focus_surface(struct weston_compositor *ec,
512 struct weston_output *output)
513{
514 struct focus_surface *fsurf = NULL;
515 struct weston_surface *surface = NULL;
516
517 fsurf = malloc(sizeof *fsurf);
518 if (!fsurf)
519 return NULL;
520
521 fsurf->surface = weston_surface_create(ec);
522 surface = fsurf->surface;
523 if (surface == NULL) {
524 free(fsurf);
525 return NULL;
526 }
527
528 surface->configure = focus_surface_configure;
529 surface->output = output;
530 surface->configure_private = fsurf;
531
U. Artie Eoff0b23b2b2014-01-15 14:45:59 -0800532 fsurf->view = weston_view_create(surface);
533 if (fsurf->view == NULL) {
534 weston_surface_destroy(surface);
535 free(fsurf);
536 return NULL;
537 }
Emilio Pozuelo Monfortda644262013-11-19 11:37:19 +0100538 fsurf->view->output = output;
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100539
Jason Ekstrand5c11a332013-12-04 20:32:03 -0600540 weston_surface_set_size(surface, output->width, output->height);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600541 weston_view_set_position(fsurf->view, output->x, output->y);
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100542 weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1.0);
543 pixman_region32_fini(&surface->opaque);
544 pixman_region32_init_rect(&surface->opaque, output->x, output->y,
545 output->width, output->height);
546 pixman_region32_fini(&surface->input);
547 pixman_region32_init(&surface->input);
548
549 wl_list_init(&fsurf->workspace_transform.link);
550
551 return fsurf;
552}
553
554static void
555focus_surface_destroy(struct focus_surface *fsurf)
556{
557 weston_surface_destroy(fsurf->surface);
558 free(fsurf);
559}
560
561static void
562focus_animation_done(struct weston_view_animation *animation, void *data)
563{
564 struct workspace *ws = data;
565
566 ws->focus_animation = NULL;
567}
568
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200569static void
Jonas Ådahl04769742012-06-13 00:01:24 +0200570focus_state_destroy(struct focus_state *state)
571{
572 wl_list_remove(&state->seat_destroy_listener.link);
573 wl_list_remove(&state->surface_destroy_listener.link);
574 free(state);
575}
576
577static void
578focus_state_seat_destroy(struct wl_listener *listener, void *data)
579{
580 struct focus_state *state = container_of(listener,
581 struct focus_state,
582 seat_destroy_listener);
583
584 wl_list_remove(&state->link);
585 focus_state_destroy(state);
586}
587
588static void
589focus_state_surface_destroy(struct wl_listener *listener, void *data)
590{
591 struct focus_state *state = container_of(listener,
592 struct focus_state,
Kristian Høgsbergb8e0d0f2012-07-31 10:30:26 -0400593 surface_destroy_listener);
Kristian Høgsberge3778222012-07-31 17:29:30 -0400594 struct desktop_shell *shell;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500595 struct weston_surface *main_surface, *next;
596 struct weston_view *view;
Jonas Ådahl04769742012-06-13 00:01:24 +0200597
Pekka Paalanen01388e22013-04-25 13:57:44 +0300598 main_surface = weston_surface_get_main_surface(state->keyboard_focus);
599
Kristian Høgsberge3778222012-07-31 17:29:30 -0400600 next = NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500601 wl_list_for_each(view, &state->ws->layer.view_list, layer_link) {
602 if (view->surface == main_surface)
Kristian Høgsberge3778222012-07-31 17:29:30 -0400603 continue;
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100604 if (is_focus_view(view))
605 continue;
Kristian Høgsberge3778222012-07-31 17:29:30 -0400606
Jason Ekstranda7af7042013-10-12 22:38:11 -0500607 next = view->surface;
Kristian Høgsberge3778222012-07-31 17:29:30 -0400608 break;
609 }
610
Pekka Paalanen01388e22013-04-25 13:57:44 +0300611 /* if the focus was a sub-surface, activate its main surface */
612 if (main_surface != state->keyboard_focus)
613 next = main_surface;
614
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100615 shell = state->seat->compositor->shell_interface.shell;
Kristian Høgsberge3778222012-07-31 17:29:30 -0400616 if (next) {
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100617 state->keyboard_focus = NULL;
Kristian Høgsberge3778222012-07-31 17:29:30 -0400618 activate(shell, next, state->seat);
619 } else {
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100620 if (shell->focus_animation_type == ANIMATION_DIM_LAYER) {
621 if (state->ws->focus_animation)
622 weston_view_animation_destroy(state->ws->focus_animation);
623
624 state->ws->focus_animation = weston_fade_run(
625 state->ws->fsurf_front->view,
626 state->ws->fsurf_front->view->alpha, 0.0, 300,
627 focus_animation_done, state->ws);
628 }
629
Kristian Høgsberge3778222012-07-31 17:29:30 -0400630 wl_list_remove(&state->link);
631 focus_state_destroy(state);
632 }
Jonas Ådahl04769742012-06-13 00:01:24 +0200633}
634
635static struct focus_state *
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400636focus_state_create(struct weston_seat *seat, struct workspace *ws)
Jonas Ådahl04769742012-06-13 00:01:24 +0200637{
Jonas Ådahl04769742012-06-13 00:01:24 +0200638 struct focus_state *state;
Jonas Ådahl04769742012-06-13 00:01:24 +0200639
640 state = malloc(sizeof *state);
641 if (state == NULL)
642 return NULL;
643
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100644 state->keyboard_focus = NULL;
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400645 state->ws = ws;
Jonas Ådahl04769742012-06-13 00:01:24 +0200646 state->seat = seat;
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400647 wl_list_insert(&ws->focus_list, &state->link);
Jonas Ådahl04769742012-06-13 00:01:24 +0200648
649 state->seat_destroy_listener.notify = focus_state_seat_destroy;
650 state->surface_destroy_listener.notify = focus_state_surface_destroy;
Kristian Høgsberg49124542013-05-06 22:27:40 -0400651 wl_signal_add(&seat->destroy_signal,
Jonas Ådahl04769742012-06-13 00:01:24 +0200652 &state->seat_destroy_listener);
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400653 wl_list_init(&state->surface_destroy_listener.link);
Jonas Ådahl04769742012-06-13 00:01:24 +0200654
655 return state;
656}
657
Jonas Ådahl8538b222012-08-29 22:13:03 +0200658static struct focus_state *
659ensure_focus_state(struct desktop_shell *shell, struct weston_seat *seat)
660{
661 struct workspace *ws = get_current_workspace(shell);
662 struct focus_state *state;
663
664 wl_list_for_each(state, &ws->focus_list, link)
665 if (state->seat == seat)
666 break;
667
668 if (&state->link == &ws->focus_list)
669 state = focus_state_create(seat, ws);
670
671 return state;
672}
673
Jonas Ådahl04769742012-06-13 00:01:24 +0200674static void
Kristian Høgsbergd500bf12014-01-22 12:25:20 -0800675focus_state_set_focus(struct focus_state *state,
676 struct weston_surface *surface)
677{
678 if (state->keyboard_focus) {
679 wl_list_remove(&state->surface_destroy_listener.link);
680 wl_list_init(&state->surface_destroy_listener.link);
681 }
682
683 state->keyboard_focus = surface;
684 if (surface)
685 wl_signal_add(&surface->destroy_signal,
686 &state->surface_destroy_listener);
687}
688
689static void
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400690restore_focus_state(struct desktop_shell *shell, struct workspace *ws)
Jonas Ådahl04769742012-06-13 00:01:24 +0200691{
692 struct focus_state *state, *next;
Kristian Høgsbergfe7aa902013-05-08 09:54:37 -0400693 struct weston_surface *surface;
Jonas Ådahl04769742012-06-13 00:01:24 +0200694
695 wl_list_for_each_safe(state, next, &ws->focus_list, link) {
Kristian Høgsberge61d2f42014-01-17 12:18:53 -0800696 if (state->seat->keyboard == NULL)
697 continue;
698
Kristian Høgsbergfe7aa902013-05-08 09:54:37 -0400699 surface = state->keyboard_focus;
Jonas Ådahl56899442012-08-29 22:12:59 +0200700
Kristian Høgsberge3148752013-05-06 23:19:49 -0400701 weston_keyboard_set_focus(state->seat->keyboard, surface);
Jonas Ådahl04769742012-06-13 00:01:24 +0200702 }
703}
704
705static void
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200706replace_focus_state(struct desktop_shell *shell, struct workspace *ws,
707 struct weston_seat *seat)
708{
709 struct focus_state *state;
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200710
711 wl_list_for_each(state, &ws->focus_list, link) {
712 if (state->seat == seat) {
Kristian Høgsbergd500bf12014-01-22 12:25:20 -0800713 focus_state_set_focus(state, seat->keyboard->focus);
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200714 return;
715 }
716 }
717}
718
719static void
720drop_focus_state(struct desktop_shell *shell, struct workspace *ws,
721 struct weston_surface *surface)
722{
723 struct focus_state *state;
724
725 wl_list_for_each(state, &ws->focus_list, link)
726 if (state->keyboard_focus == surface)
Kristian Høgsbergd500bf12014-01-22 12:25:20 -0800727 focus_state_set_focus(state, NULL);
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200728}
729
730static void
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100731animate_focus_change(struct desktop_shell *shell, struct workspace *ws,
732 struct weston_view *from, struct weston_view *to)
733{
734 struct weston_output *output;
735 bool focus_surface_created = false;
736
737 /* FIXME: Only support dim animation using two layers */
738 if (from == to || shell->focus_animation_type != ANIMATION_DIM_LAYER)
739 return;
740
741 output = get_default_output(shell->compositor);
742 if (ws->fsurf_front == NULL && (from || to)) {
743 ws->fsurf_front = create_focus_surface(shell->compositor, output);
U. Artie Eoff0b23b2b2014-01-15 14:45:59 -0800744 if (ws->fsurf_front == NULL)
745 return;
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100746 ws->fsurf_front->view->alpha = 0.0;
U. Artie Eoff0b23b2b2014-01-15 14:45:59 -0800747
748 ws->fsurf_back = create_focus_surface(shell->compositor, output);
749 if (ws->fsurf_back == NULL) {
750 focus_surface_destroy(ws->fsurf_front);
751 return;
752 }
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100753 ws->fsurf_back->view->alpha = 0.0;
U. Artie Eoff0b23b2b2014-01-15 14:45:59 -0800754
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100755 focus_surface_created = true;
756 } else {
757 wl_list_remove(&ws->fsurf_front->view->layer_link);
758 wl_list_remove(&ws->fsurf_back->view->layer_link);
759 }
760
761 if (ws->focus_animation) {
762 weston_view_animation_destroy(ws->focus_animation);
763 ws->focus_animation = NULL;
764 }
765
766 if (to)
767 wl_list_insert(&to->layer_link,
768 &ws->fsurf_front->view->layer_link);
769 else if (from)
770 wl_list_insert(&ws->layer.view_list,
771 &ws->fsurf_front->view->layer_link);
772
773 if (focus_surface_created) {
774 ws->focus_animation = weston_fade_run(
775 ws->fsurf_front->view,
776 ws->fsurf_front->view->alpha, 0.6, 300,
777 focus_animation_done, ws);
778 } else if (from) {
779 wl_list_insert(&from->layer_link,
780 &ws->fsurf_back->view->layer_link);
781 ws->focus_animation = weston_stable_fade_run(
782 ws->fsurf_front->view, 0.0,
783 ws->fsurf_back->view, 0.6,
784 focus_animation_done, ws);
785 } else if (to) {
786 wl_list_insert(&ws->layer.view_list,
787 &ws->fsurf_back->view->layer_link);
788 ws->focus_animation = weston_stable_fade_run(
789 ws->fsurf_front->view, 0.0,
790 ws->fsurf_back->view, 0.6,
791 focus_animation_done, ws);
792 }
793}
794
795static void
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200796workspace_destroy(struct workspace *ws)
797{
Jonas Ådahl04769742012-06-13 00:01:24 +0200798 struct focus_state *state, *next;
799
800 wl_list_for_each_safe(state, next, &ws->focus_list, link)
801 focus_state_destroy(state);
802
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100803 if (ws->fsurf_front)
804 focus_surface_destroy(ws->fsurf_front);
805 if (ws->fsurf_back)
806 focus_surface_destroy(ws->fsurf_back);
807
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200808 free(ws);
809}
810
Jonas Ådahl04769742012-06-13 00:01:24 +0200811static void
812seat_destroyed(struct wl_listener *listener, void *data)
813{
814 struct weston_seat *seat = data;
815 struct focus_state *state, *next;
816 struct workspace *ws = container_of(listener,
817 struct workspace,
818 seat_destroyed_listener);
819
820 wl_list_for_each_safe(state, next, &ws->focus_list, link)
821 if (state->seat == seat)
822 wl_list_remove(&state->link);
823}
824
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200825static struct workspace *
826workspace_create(void)
827{
828 struct workspace *ws = malloc(sizeof *ws);
829 if (ws == NULL)
830 return NULL;
831
832 weston_layer_init(&ws->layer, NULL);
833
Jonas Ådahl04769742012-06-13 00:01:24 +0200834 wl_list_init(&ws->focus_list);
835 wl_list_init(&ws->seat_destroyed_listener.link);
836 ws->seat_destroyed_listener.notify = seat_destroyed;
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100837 ws->fsurf_front = NULL;
838 ws->fsurf_back = NULL;
839 ws->focus_animation = NULL;
Jonas Ådahl04769742012-06-13 00:01:24 +0200840
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200841 return ws;
842}
843
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200844static int
845workspace_is_empty(struct workspace *ws)
846{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500847 return wl_list_empty(&ws->layer.view_list);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200848}
849
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200850static struct workspace *
851get_workspace(struct desktop_shell *shell, unsigned int index)
852{
853 struct workspace **pws = shell->workspaces.array.data;
Philipp Brüschweiler067abf62012-09-01 16:03:05 +0200854 assert(index < shell->workspaces.num);
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200855 pws += index;
856 return *pws;
857}
858
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800859struct workspace *
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200860get_current_workspace(struct desktop_shell *shell)
861{
862 return get_workspace(shell, shell->workspaces.current);
863}
864
865static void
866activate_workspace(struct desktop_shell *shell, unsigned int index)
867{
868 struct workspace *ws;
869
870 ws = get_workspace(shell, index);
871 wl_list_insert(&shell->panel_layer.link, &ws->layer.link);
872
873 shell->workspaces.current = index;
874}
875
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200876static unsigned int
877get_output_height(struct weston_output *output)
878{
879 return abs(output->region.extents.y1 - output->region.extents.y2);
880}
881
882static void
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100883view_translate(struct workspace *ws, struct weston_view *view, double d)
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200884{
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200885 struct weston_transform *transform;
886
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100887 if (is_focus_view(view)) {
888 struct focus_surface *fsurf = get_focus_surface(view->surface);
889 transform = &fsurf->workspace_transform;
890 } else {
891 struct shell_surface *shsurf = get_shell_surface(view->surface);
892 transform = &shsurf->workspace_transform;
893 }
894
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200895 if (wl_list_empty(&transform->link))
Jason Ekstranda7af7042013-10-12 22:38:11 -0500896 wl_list_insert(view->geometry.transformation_list.prev,
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100897 &transform->link);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200898
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100899 weston_matrix_init(&transform->matrix);
900 weston_matrix_translate(&transform->matrix,
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200901 0.0, d, 0.0);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500902 weston_view_geometry_dirty(view);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200903}
904
905static void
906workspace_translate_out(struct workspace *ws, double fraction)
907{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500908 struct weston_view *view;
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200909 unsigned int height;
910 double d;
911
Jason Ekstranda7af7042013-10-12 22:38:11 -0500912 wl_list_for_each(view, &ws->layer.view_list, layer_link) {
913 height = get_output_height(view->surface->output);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200914 d = height * fraction;
915
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100916 view_translate(ws, view, d);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200917 }
918}
919
920static void
921workspace_translate_in(struct workspace *ws, double fraction)
922{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500923 struct weston_view *view;
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200924 unsigned int height;
925 double d;
926
Jason Ekstranda7af7042013-10-12 22:38:11 -0500927 wl_list_for_each(view, &ws->layer.view_list, layer_link) {
928 height = get_output_height(view->surface->output);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200929
930 if (fraction > 0)
931 d = -(height - height * fraction);
932 else
933 d = height + height * fraction;
934
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100935 view_translate(ws, view, d);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200936 }
937}
938
939static void
Jonas Ådahle9d22502012-08-29 22:13:01 +0200940broadcast_current_workspace_state(struct desktop_shell *shell)
941{
Kristian Høgsberg2e3c3962013-09-11 12:00:47 -0700942 struct wl_resource *resource;
Jonas Ådahle9d22502012-08-29 22:13:01 +0200943
Kristian Høgsberg2e3c3962013-09-11 12:00:47 -0700944 wl_resource_for_each(resource, &shell->workspaces.client_list)
945 workspace_manager_send_state(resource,
Jonas Ådahle9d22502012-08-29 22:13:01 +0200946 shell->workspaces.current,
947 shell->workspaces.num);
948}
949
950static void
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200951reverse_workspace_change_animation(struct desktop_shell *shell,
952 unsigned int index,
953 struct workspace *from,
954 struct workspace *to)
955{
956 shell->workspaces.current = index;
957
958 shell->workspaces.anim_to = to;
959 shell->workspaces.anim_from = from;
960 shell->workspaces.anim_dir = -1 * shell->workspaces.anim_dir;
961 shell->workspaces.anim_timestamp = 0;
962
Scott Moreau4272e632012-08-13 09:58:41 -0600963 weston_compositor_schedule_repaint(shell->compositor);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200964}
965
966static void
967workspace_deactivate_transforms(struct workspace *ws)
968{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500969 struct weston_view *view;
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100970 struct weston_transform *transform;
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200971
Jason Ekstranda7af7042013-10-12 22:38:11 -0500972 wl_list_for_each(view, &ws->layer.view_list, layer_link) {
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100973 if (is_focus_view(view)) {
974 struct focus_surface *fsurf = get_focus_surface(view->surface);
975 transform = &fsurf->workspace_transform;
976 } else {
977 struct shell_surface *shsurf = get_shell_surface(view->surface);
978 transform = &shsurf->workspace_transform;
979 }
980
981 if (!wl_list_empty(&transform->link)) {
982 wl_list_remove(&transform->link);
983 wl_list_init(&transform->link);
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200984 }
Jason Ekstranda7af7042013-10-12 22:38:11 -0500985 weston_view_geometry_dirty(view);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200986 }
987}
988
989static void
990finish_workspace_change_animation(struct desktop_shell *shell,
991 struct workspace *from,
992 struct workspace *to)
993{
Scott Moreau4272e632012-08-13 09:58:41 -0600994 weston_compositor_schedule_repaint(shell->compositor);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200995
996 wl_list_remove(&shell->workspaces.animation.link);
997 workspace_deactivate_transforms(from);
998 workspace_deactivate_transforms(to);
999 shell->workspaces.anim_to = NULL;
1000
1001 wl_list_remove(&shell->workspaces.anim_from->layer.link);
1002}
1003
1004static void
1005animate_workspace_change_frame(struct weston_animation *animation,
1006 struct weston_output *output, uint32_t msecs)
1007{
1008 struct desktop_shell *shell =
1009 container_of(animation, struct desktop_shell,
1010 workspaces.animation);
1011 struct workspace *from = shell->workspaces.anim_from;
1012 struct workspace *to = shell->workspaces.anim_to;
1013 uint32_t t;
1014 double x, y;
1015
1016 if (workspace_is_empty(from) && workspace_is_empty(to)) {
1017 finish_workspace_change_animation(shell, from, to);
1018 return;
1019 }
1020
1021 if (shell->workspaces.anim_timestamp == 0) {
1022 if (shell->workspaces.anim_current == 0.0)
1023 shell->workspaces.anim_timestamp = msecs;
1024 else
1025 shell->workspaces.anim_timestamp =
1026 msecs -
1027 /* Invers of movement function 'y' below. */
1028 (asin(1.0 - shell->workspaces.anim_current) *
1029 DEFAULT_WORKSPACE_CHANGE_ANIMATION_LENGTH *
1030 M_2_PI);
1031 }
1032
1033 t = msecs - shell->workspaces.anim_timestamp;
1034
1035 /*
1036 * x = [0, π/2]
1037 * y(x) = sin(x)
1038 */
1039 x = t * (1.0/DEFAULT_WORKSPACE_CHANGE_ANIMATION_LENGTH) * M_PI_2;
1040 y = sin(x);
1041
1042 if (t < DEFAULT_WORKSPACE_CHANGE_ANIMATION_LENGTH) {
Scott Moreau4272e632012-08-13 09:58:41 -06001043 weston_compositor_schedule_repaint(shell->compositor);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001044
1045 workspace_translate_out(from, shell->workspaces.anim_dir * y);
1046 workspace_translate_in(to, shell->workspaces.anim_dir * y);
1047 shell->workspaces.anim_current = y;
1048
Scott Moreau4272e632012-08-13 09:58:41 -06001049 weston_compositor_schedule_repaint(shell->compositor);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001050 }
Jonas Ådahl04769742012-06-13 00:01:24 +02001051 else
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001052 finish_workspace_change_animation(shell, from, to);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001053}
1054
1055static void
1056animate_workspace_change(struct desktop_shell *shell,
1057 unsigned int index,
1058 struct workspace *from,
1059 struct workspace *to)
1060{
1061 struct weston_output *output;
1062
1063 int dir;
1064
1065 if (index > shell->workspaces.current)
1066 dir = -1;
1067 else
1068 dir = 1;
1069
1070 shell->workspaces.current = index;
1071
1072 shell->workspaces.anim_dir = dir;
1073 shell->workspaces.anim_from = from;
1074 shell->workspaces.anim_to = to;
1075 shell->workspaces.anim_current = 0.0;
1076 shell->workspaces.anim_timestamp = 0;
1077
1078 output = container_of(shell->compositor->output_list.next,
1079 struct weston_output, link);
1080 wl_list_insert(&output->animation_list,
1081 &shell->workspaces.animation.link);
1082
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001083 wl_list_insert(from->layer.link.prev, &to->layer.link);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001084
1085 workspace_translate_in(to, 0);
1086
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -04001087 restore_focus_state(shell, to);
Jonas Ådahl04769742012-06-13 00:01:24 +02001088
Scott Moreau4272e632012-08-13 09:58:41 -06001089 weston_compositor_schedule_repaint(shell->compositor);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001090}
1091
Jonas Ådahle3cddce2012-06-13 00:01:22 +02001092static void
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001093update_workspace(struct desktop_shell *shell, unsigned int index,
1094 struct workspace *from, struct workspace *to)
1095{
1096 shell->workspaces.current = index;
1097 wl_list_insert(&from->layer.link, &to->layer.link);
1098 wl_list_remove(&from->layer.link);
1099}
1100
1101static void
Jonas Ådahle3cddce2012-06-13 00:01:22 +02001102change_workspace(struct desktop_shell *shell, unsigned int index)
1103{
1104 struct workspace *from;
1105 struct workspace *to;
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01001106 struct focus_state *state;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02001107
1108 if (index == shell->workspaces.current)
1109 return;
1110
1111 /* Don't change workspace when there is any fullscreen surfaces. */
Jason Ekstranda7af7042013-10-12 22:38:11 -05001112 if (!wl_list_empty(&shell->fullscreen_layer.view_list))
Jonas Ådahle3cddce2012-06-13 00:01:22 +02001113 return;
1114
Jonas Ådahle3cddce2012-06-13 00:01:22 +02001115 from = get_current_workspace(shell);
1116 to = get_workspace(shell, index);
1117
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001118 if (shell->workspaces.anim_from == to &&
1119 shell->workspaces.anim_to == from) {
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001120 restore_focus_state(shell, to);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001121 reverse_workspace_change_animation(shell, index, from, to);
Jonas Ådahle9d22502012-08-29 22:13:01 +02001122 broadcast_current_workspace_state(shell);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001123 return;
1124 }
Jonas Ådahle3cddce2012-06-13 00:01:22 +02001125
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001126 if (shell->workspaces.anim_to != NULL)
1127 finish_workspace_change_animation(shell,
1128 shell->workspaces.anim_from,
1129 shell->workspaces.anim_to);
1130
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001131 restore_focus_state(shell, to);
Jonas Ådahl04769742012-06-13 00:01:24 +02001132
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01001133 if (shell->focus_animation_type != ANIMATION_NONE) {
1134 wl_list_for_each(state, &from->focus_list, link)
1135 if (state->keyboard_focus)
1136 animate_focus_change(shell, from,
1137 get_default_view(state->keyboard_focus), NULL);
1138
1139 wl_list_for_each(state, &to->focus_list, link)
1140 if (state->keyboard_focus)
1141 animate_focus_change(shell, to,
1142 NULL, get_default_view(state->keyboard_focus));
1143 }
1144
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001145 if (workspace_is_empty(to) && workspace_is_empty(from))
1146 update_workspace(shell, index, from, to);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001147 else
1148 animate_workspace_change(shell, index, from, to);
Jonas Ådahle9d22502012-08-29 22:13:01 +02001149
1150 broadcast_current_workspace_state(shell);
Pekka Paalanene955f1e2011-12-07 11:49:52 +02001151}
1152
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001153static bool
1154workspace_has_only(struct workspace *ws, struct weston_surface *surface)
1155{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001156 struct wl_list *list = &ws->layer.view_list;
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001157 struct wl_list *e;
1158
1159 if (wl_list_empty(list))
1160 return false;
1161
1162 e = list->next;
1163
1164 if (e->next != list)
1165 return false;
1166
Jason Ekstranda7af7042013-10-12 22:38:11 -05001167 return container_of(e, struct weston_view, layer_link)->surface == surface;
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001168}
1169
1170static void
Philip Withnall659163d2013-11-25 18:01:36 +00001171move_surface_to_workspace(struct desktop_shell *shell,
1172 struct shell_surface *shsurf,
1173 uint32_t workspace)
Jonas Ådahle9d22502012-08-29 22:13:01 +02001174{
1175 struct workspace *from;
1176 struct workspace *to;
1177 struct weston_seat *seat;
Pekka Paalanen01388e22013-04-25 13:57:44 +03001178 struct weston_surface *focus;
Philip Withnall659163d2013-11-25 18:01:36 +00001179 struct weston_view *view;
Jonas Ådahle9d22502012-08-29 22:13:01 +02001180
1181 if (workspace == shell->workspaces.current)
1182 return;
1183
Philip Withnall659163d2013-11-25 18:01:36 +00001184 view = get_default_view(shsurf->surface);
1185 if (!view)
1186 return;
1187
1188 assert(weston_surface_get_main_surface(view->surface) == view->surface);
1189
Philipp Brüschweiler067abf62012-09-01 16:03:05 +02001190 if (workspace >= shell->workspaces.num)
1191 workspace = shell->workspaces.num - 1;
1192
Jonas Ådahle9d22502012-08-29 22:13:01 +02001193 from = get_current_workspace(shell);
1194 to = get_workspace(shell, workspace);
1195
Jason Ekstranda7af7042013-10-12 22:38:11 -05001196 wl_list_remove(&view->layer_link);
1197 wl_list_insert(&to->layer.view_list, &view->layer_link);
Jonas Ådahle9d22502012-08-29 22:13:01 +02001198
Philip Withnall648a4dd2013-11-25 18:01:44 +00001199 shell_surface_update_child_surface_layers(shsurf);
1200
Jason Ekstranda7af7042013-10-12 22:38:11 -05001201 drop_focus_state(shell, from, view->surface);
Pekka Paalanen01388e22013-04-25 13:57:44 +03001202 wl_list_for_each(seat, &shell->compositor->seat_list, link) {
1203 if (!seat->keyboard)
1204 continue;
1205
1206 focus = weston_surface_get_main_surface(seat->keyboard->focus);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001207 if (focus == view->surface)
Kristian Høgsberge3148752013-05-06 23:19:49 -04001208 weston_keyboard_set_focus(seat->keyboard, NULL);
Pekka Paalanen01388e22013-04-25 13:57:44 +03001209 }
Jonas Ådahle9d22502012-08-29 22:13:01 +02001210
Jason Ekstranda7af7042013-10-12 22:38:11 -05001211 weston_view_damage_below(view);
Jonas Ådahle9d22502012-08-29 22:13:01 +02001212}
1213
1214static void
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001215take_surface_to_workspace_by_seat(struct desktop_shell *shell,
Kristian Høgsberge3148752013-05-06 23:19:49 -04001216 struct weston_seat *seat,
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001217 unsigned int index)
1218{
Pekka Paalanen01388e22013-04-25 13:57:44 +03001219 struct weston_surface *surface;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001220 struct weston_view *view;
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001221 struct shell_surface *shsurf;
1222 struct workspace *from;
1223 struct workspace *to;
Jonas Ådahl8538b222012-08-29 22:13:03 +02001224 struct focus_state *state;
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001225
Pekka Paalanen01388e22013-04-25 13:57:44 +03001226 surface = weston_surface_get_main_surface(seat->keyboard->focus);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001227 view = get_default_view(surface);
1228 if (view == NULL ||
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01001229 index == shell->workspaces.current ||
1230 is_focus_view(view))
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001231 return;
1232
1233 from = get_current_workspace(shell);
1234 to = get_workspace(shell, index);
1235
Jason Ekstranda7af7042013-10-12 22:38:11 -05001236 wl_list_remove(&view->layer_link);
1237 wl_list_insert(&to->layer.view_list, &view->layer_link);
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001238
Philip Withnall659163d2013-11-25 18:01:36 +00001239 shsurf = get_shell_surface(surface);
Philip Withnall648a4dd2013-11-25 18:01:44 +00001240 if (shsurf != NULL)
1241 shell_surface_update_child_surface_layers(shsurf);
Philip Withnall659163d2013-11-25 18:01:36 +00001242
Jonas Ådahle9d22502012-08-29 22:13:01 +02001243 replace_focus_state(shell, to, seat);
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001244 drop_focus_state(shell, from, surface);
1245
1246 if (shell->workspaces.anim_from == to &&
1247 shell->workspaces.anim_to == from) {
Jonas Ådahle9d22502012-08-29 22:13:01 +02001248 wl_list_remove(&to->layer.link);
1249 wl_list_insert(from->layer.link.prev, &to->layer.link);
1250
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001251 reverse_workspace_change_animation(shell, index, from, to);
Jonas Ådahle9d22502012-08-29 22:13:01 +02001252 broadcast_current_workspace_state(shell);
1253
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001254 return;
1255 }
1256
1257 if (shell->workspaces.anim_to != NULL)
1258 finish_workspace_change_animation(shell,
1259 shell->workspaces.anim_from,
1260 shell->workspaces.anim_to);
1261
1262 if (workspace_is_empty(from) &&
1263 workspace_has_only(to, surface))
1264 update_workspace(shell, index, from, to);
1265 else {
Philip Withnall2c3849b2013-11-25 18:01:45 +00001266 if (shsurf != NULL &&
1267 wl_list_empty(&shsurf->workspace_transform.link))
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001268 wl_list_insert(&shell->workspaces.anim_sticky_list,
1269 &shsurf->workspace_transform.link);
1270
1271 animate_workspace_change(shell, index, from, to);
1272 }
Jonas Ådahle9d22502012-08-29 22:13:01 +02001273
1274 broadcast_current_workspace_state(shell);
Jonas Ådahl8538b222012-08-29 22:13:03 +02001275
1276 state = ensure_focus_state(shell, seat);
1277 if (state != NULL)
Kristian Høgsbergd500bf12014-01-22 12:25:20 -08001278 focus_state_set_focus(state, surface);
Jonas Ådahle9d22502012-08-29 22:13:01 +02001279}
1280
1281static void
1282workspace_manager_move_surface(struct wl_client *client,
1283 struct wl_resource *resource,
1284 struct wl_resource *surface_resource,
1285 uint32_t workspace)
1286{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05001287 struct desktop_shell *shell = wl_resource_get_user_data(resource);
Jonas Ådahle9d22502012-08-29 22:13:01 +02001288 struct weston_surface *surface =
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05001289 wl_resource_get_user_data(surface_resource);
Pekka Paalanen01388e22013-04-25 13:57:44 +03001290 struct weston_surface *main_surface;
Philip Withnall659163d2013-11-25 18:01:36 +00001291 struct shell_surface *shell_surface;
Jonas Ådahle9d22502012-08-29 22:13:01 +02001292
Pekka Paalanen01388e22013-04-25 13:57:44 +03001293 main_surface = weston_surface_get_main_surface(surface);
Philip Withnall659163d2013-11-25 18:01:36 +00001294 shell_surface = get_shell_surface(main_surface);
1295 if (shell_surface == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001296 return;
Philip Withnall659163d2013-11-25 18:01:36 +00001297
1298 move_surface_to_workspace(shell, shell_surface, workspace);
Jonas Ådahle9d22502012-08-29 22:13:01 +02001299}
1300
1301static const struct workspace_manager_interface workspace_manager_implementation = {
1302 workspace_manager_move_surface,
1303};
1304
1305static void
1306unbind_resource(struct wl_resource *resource)
1307{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05001308 wl_list_remove(wl_resource_get_link(resource));
Jonas Ådahle9d22502012-08-29 22:13:01 +02001309}
1310
1311static void
1312bind_workspace_manager(struct wl_client *client,
1313 void *data, uint32_t version, uint32_t id)
1314{
1315 struct desktop_shell *shell = data;
1316 struct wl_resource *resource;
1317
Jason Ekstranda85118c2013-06-27 20:17:02 -05001318 resource = wl_resource_create(client,
1319 &workspace_manager_interface, 1, id);
Jonas Ådahle9d22502012-08-29 22:13:01 +02001320
1321 if (resource == NULL) {
1322 weston_log("couldn't add workspace manager object");
1323 return;
1324 }
1325
Jason Ekstranda85118c2013-06-27 20:17:02 -05001326 wl_resource_set_implementation(resource,
1327 &workspace_manager_implementation,
1328 shell, unbind_resource);
Jason Ekstrand651f00e2013-06-14 10:07:54 -05001329 wl_list_insert(&shell->workspaces.client_list,
1330 wl_resource_get_link(resource));
Jonas Ådahle9d22502012-08-29 22:13:01 +02001331
1332 workspace_manager_send_state(resource,
1333 shell->workspaces.current,
1334 shell->workspaces.num);
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001335}
1336
Pekka Paalanen56cdea92011-11-23 16:14:12 +02001337static void
Rusty Lynch1084da52013-08-15 09:10:08 -07001338touch_move_grab_down(struct weston_touch_grab *grab, uint32_t time,
1339 int touch_id, wl_fixed_t sx, wl_fixed_t sy)
1340{
1341}
1342
1343static void
1344touch_move_grab_up(struct weston_touch_grab *grab, uint32_t time, int touch_id)
1345{
Jonas Ådahl1c6e63e2013-10-25 23:18:04 +02001346 struct weston_touch_move_grab *move =
1347 (struct weston_touch_move_grab *) container_of(
1348 grab, struct shell_touch_grab, grab);
Neil Robertse14aa4f2013-10-03 16:43:07 +01001349
Kristian Høgsberg8e80a312014-01-17 15:18:10 -08001350 if (touch_id == 0)
1351 move->active = 0;
1352
Jonas Ådahl9484b692013-12-02 22:05:03 +01001353 if (grab->touch->num_tp == 0) {
Jonas Ådahl1c6e63e2013-10-25 23:18:04 +02001354 shell_touch_grab_end(&move->base);
1355 free(move);
1356 }
Rusty Lynch1084da52013-08-15 09:10:08 -07001357}
1358
1359static void
1360touch_move_grab_motion(struct weston_touch_grab *grab, uint32_t time,
1361 int touch_id, wl_fixed_t sx, wl_fixed_t sy)
1362{
1363 struct weston_touch_move_grab *move = (struct weston_touch_move_grab *) grab;
1364 struct shell_surface *shsurf = move->base.shsurf;
1365 struct weston_surface *es;
1366 int dx = wl_fixed_to_int(grab->touch->grab_x + move->dx);
1367 int dy = wl_fixed_to_int(grab->touch->grab_y + move->dy);
1368
Kristian Høgsberg8e80a312014-01-17 15:18:10 -08001369 if (!shsurf || !move->active)
Rusty Lynch1084da52013-08-15 09:10:08 -07001370 return;
1371
1372 es = shsurf->surface;
1373
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001374 weston_view_set_position(shsurf->view, dx, dy);
Rusty Lynch1084da52013-08-15 09:10:08 -07001375
1376 weston_compositor_schedule_repaint(es->compositor);
1377}
1378
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02001379static void
1380touch_move_grab_cancel(struct weston_touch_grab *grab)
1381{
1382 struct weston_touch_move_grab *move =
1383 (struct weston_touch_move_grab *) container_of(
1384 grab, struct shell_touch_grab, grab);
1385
1386 shell_touch_grab_end(&move->base);
1387 free(move);
1388}
1389
Rusty Lynch1084da52013-08-15 09:10:08 -07001390static const struct weston_touch_grab_interface touch_move_grab_interface = {
1391 touch_move_grab_down,
1392 touch_move_grab_up,
1393 touch_move_grab_motion,
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02001394 touch_move_grab_cancel,
Rusty Lynch1084da52013-08-15 09:10:08 -07001395};
1396
1397static int
1398surface_touch_move(struct shell_surface *shsurf, struct weston_seat *seat)
1399{
1400 struct weston_touch_move_grab *move;
1401
1402 if (!shsurf)
1403 return -1;
1404
Rafael Antognolli03b16592013-12-03 15:35:42 -02001405 if (shsurf->state.fullscreen)
Rusty Lynch1084da52013-08-15 09:10:08 -07001406 return 0;
Kristian Høgsbergc85f1d42013-10-24 16:52:00 -07001407 if (shsurf->grabbed)
1408 return 0;
Rusty Lynch1084da52013-08-15 09:10:08 -07001409
1410 move = malloc(sizeof *move);
1411 if (!move)
1412 return -1;
1413
Kristian Høgsberg8e80a312014-01-17 15:18:10 -08001414 move->active = 1;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001415 move->dx = wl_fixed_from_double(shsurf->view->geometry.x) -
Rusty Lynch1084da52013-08-15 09:10:08 -07001416 seat->touch->grab_x;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001417 move->dy = wl_fixed_from_double(shsurf->view->geometry.y) -
Rusty Lynch1084da52013-08-15 09:10:08 -07001418 seat->touch->grab_y;
1419
1420 shell_touch_grab_start(&move->base, &touch_move_grab_interface, shsurf,
1421 seat->touch);
1422
1423 return 0;
1424}
1425
1426static void
Kristian Høgsberg6848c252013-05-08 22:02:59 -04001427noop_grab_focus(struct weston_pointer_grab *grab)
Kristian Høgsberg9ddb8262012-01-04 21:30:29 -05001428{
Kristian Høgsberg9ddb8262012-01-04 21:30:29 -05001429}
1430
1431static void
Giulio Camuffo1959ab82013-11-14 23:42:52 +01001432move_grab_motion(struct weston_pointer_grab *grab, uint32_t time,
1433 wl_fixed_t x, wl_fixed_t y)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001434{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001435 struct weston_move_grab *move = (struct weston_move_grab *) grab;
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001436 struct weston_pointer *pointer = grab->pointer;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03001437 struct shell_surface *shsurf = move->base.shsurf;
Giulio Camuffo1959ab82013-11-14 23:42:52 +01001438 int dx, dy;
1439
1440 weston_pointer_move(pointer, x, y);
1441 dx = wl_fixed_to_int(pointer->x + move->dx);
1442 dy = wl_fixed_to_int(pointer->y + move->dy);
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03001443
1444 if (!shsurf)
1445 return;
1446
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001447 weston_view_set_position(shsurf->view, dx, dy);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001448
Jason Ekstranda7af7042013-10-12 22:38:11 -05001449 weston_compositor_schedule_repaint(shsurf->surface->compositor);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001450}
1451
1452static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001453move_grab_button(struct weston_pointer_grab *grab,
Daniel Stone4dbadb12012-05-30 16:31:51 +01001454 uint32_t time, uint32_t button, uint32_t state_w)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001455{
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03001456 struct shell_grab *shell_grab = container_of(grab, struct shell_grab,
1457 grab);
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001458 struct weston_pointer *pointer = grab->pointer;
Daniel Stone4dbadb12012-05-30 16:31:51 +01001459 enum wl_pointer_button_state state = state_w;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001460
Daniel Stone4dbadb12012-05-30 16:31:51 +01001461 if (pointer->button_count == 0 &&
1462 state == WL_POINTER_BUTTON_STATE_RELEASED) {
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001463 shell_grab_end(shell_grab);
Kristian Høgsberg9ddb8262012-01-04 21:30:29 -05001464 free(grab);
1465 }
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001466}
1467
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02001468static void
1469move_grab_cancel(struct weston_pointer_grab *grab)
1470{
1471 struct shell_grab *shell_grab =
1472 container_of(grab, struct shell_grab, grab);
1473
1474 shell_grab_end(shell_grab);
1475 free(grab);
1476}
1477
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001478static const struct weston_pointer_grab_interface move_grab_interface = {
Kristian Høgsberg9ddb8262012-01-04 21:30:29 -05001479 noop_grab_focus,
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001480 move_grab_motion,
1481 move_grab_button,
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02001482 move_grab_cancel,
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001483};
1484
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001485static int
Kristian Høgsberge3148752013-05-06 23:19:49 -04001486surface_move(struct shell_surface *shsurf, struct weston_seat *seat)
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001487{
1488 struct weston_move_grab *move;
1489
1490 if (!shsurf)
1491 return -1;
1492
Kristian Høgsbergc85f1d42013-10-24 16:52:00 -07001493 if (shsurf->grabbed)
1494 return 0;
Ricardo Vieiraf1c3bd82014-01-18 16:30:50 +00001495 if (shsurf->state.fullscreen || shsurf->state.maximized)
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001496 return 0;
1497
1498 move = malloc(sizeof *move);
1499 if (!move)
1500 return -1;
1501
Jason Ekstranda7af7042013-10-12 22:38:11 -05001502 move->dx = wl_fixed_from_double(shsurf->view->geometry.x) -
Kristian Høgsberge3148752013-05-06 23:19:49 -04001503 seat->pointer->grab_x;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001504 move->dy = wl_fixed_from_double(shsurf->view->geometry.y) -
Kristian Høgsberge3148752013-05-06 23:19:49 -04001505 seat->pointer->grab_y;
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001506
1507 shell_grab_start(&move->base, &move_grab_interface, shsurf,
Kristian Høgsberge3148752013-05-06 23:19:49 -04001508 seat->pointer, DESKTOP_SHELL_CURSOR_MOVE);
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001509
1510 return 0;
1511}
1512
1513static void
Rafael Antognollie2a34552013-12-03 15:35:45 -02001514common_surface_move(struct wl_resource *resource,
1515 struct wl_resource *seat_resource, uint32_t serial)
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001516{
Jason Ekstrand44a38632013-06-14 10:08:00 -05001517 struct weston_seat *seat = wl_resource_get_user_data(seat_resource);
Jason Ekstrand651f00e2013-06-14 10:07:54 -05001518 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
Giulio Camuffo61da3fc2013-04-25 13:57:45 +03001519 struct weston_surface *surface;
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001520
Kristian Høgsberge1b655d2013-08-28 23:16:20 -07001521 if (seat->pointer &&
Kristian Høgsberg70f29012014-01-09 15:43:17 -08001522 seat->pointer->focus &&
Kristian Høgsberge1b655d2013-08-28 23:16:20 -07001523 seat->pointer->button_count > 0 &&
1524 seat->pointer->grab_serial == serial) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001525 surface = weston_surface_get_main_surface(seat->pointer->focus->surface);
U. Artie Eoffcf5737a2014-01-17 10:08:25 -08001526 if ((surface == shsurf->surface) &&
Rusty Lynch1084da52013-08-15 09:10:08 -07001527 (surface_move(shsurf, seat) < 0))
1528 wl_resource_post_no_memory(resource);
Kristian Høgsberge1b655d2013-08-28 23:16:20 -07001529 } else if (seat->touch &&
Kristian Høgsberg70f29012014-01-09 15:43:17 -08001530 seat->touch->focus &&
Kristian Høgsberge1b655d2013-08-28 23:16:20 -07001531 seat->touch->grab_serial == serial) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001532 surface = weston_surface_get_main_surface(seat->touch->focus->surface);
U. Artie Eoffcf5737a2014-01-17 10:08:25 -08001533 if ((surface == shsurf->surface) &&
Rusty Lynch1084da52013-08-15 09:10:08 -07001534 (surface_touch_move(shsurf, seat) < 0))
1535 wl_resource_post_no_memory(resource);
1536 }
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001537}
1538
Rafael Antognollie2a34552013-12-03 15:35:45 -02001539static void
1540shell_surface_move(struct wl_client *client, struct wl_resource *resource,
1541 struct wl_resource *seat_resource, uint32_t serial)
1542{
1543 common_surface_move(resource, seat_resource, serial);
1544}
1545
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001546struct weston_resize_grab {
1547 struct shell_grab base;
1548 uint32_t edges;
1549 int32_t width, height;
1550};
1551
1552static void
Giulio Camuffo1959ab82013-11-14 23:42:52 +01001553resize_grab_motion(struct weston_pointer_grab *grab, uint32_t time,
1554 wl_fixed_t x, wl_fixed_t y)
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001555{
1556 struct weston_resize_grab *resize = (struct weston_resize_grab *) grab;
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001557 struct weston_pointer *pointer = grab->pointer;
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001558 struct shell_surface *shsurf = resize->base.shsurf;
1559 int32_t width, height;
1560 wl_fixed_t from_x, from_y;
1561 wl_fixed_t to_x, to_y;
1562
Giulio Camuffo1959ab82013-11-14 23:42:52 +01001563 weston_pointer_move(pointer, x, y);
1564
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001565 if (!shsurf)
1566 return;
1567
Jason Ekstranda7af7042013-10-12 22:38:11 -05001568 weston_view_from_global_fixed(shsurf->view,
1569 pointer->grab_x, pointer->grab_y,
1570 &from_x, &from_y);
1571 weston_view_from_global_fixed(shsurf->view,
1572 pointer->x, pointer->y, &to_x, &to_y);
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001573
1574 width = resize->width;
1575 if (resize->edges & WL_SHELL_SURFACE_RESIZE_LEFT) {
1576 width += wl_fixed_to_int(from_x - to_x);
1577 } else if (resize->edges & WL_SHELL_SURFACE_RESIZE_RIGHT) {
1578 width += wl_fixed_to_int(to_x - from_x);
1579 }
1580
1581 height = resize->height;
1582 if (resize->edges & WL_SHELL_SURFACE_RESIZE_TOP) {
1583 height += wl_fixed_to_int(from_y - to_y);
1584 } else if (resize->edges & WL_SHELL_SURFACE_RESIZE_BOTTOM) {
1585 height += wl_fixed_to_int(to_y - from_y);
1586 }
1587
1588 shsurf->client->send_configure(shsurf->surface,
1589 resize->edges, width, height);
1590}
1591
1592static void
1593send_configure(struct weston_surface *surface,
1594 uint32_t edges, int32_t width, int32_t height)
1595{
1596 struct shell_surface *shsurf = get_shell_surface(surface);
1597
U. Artie Eoffcf5737a2014-01-17 10:08:25 -08001598 assert(shsurf);
1599
Jason Ekstrand651f00e2013-06-14 10:07:54 -05001600 wl_shell_surface_send_configure(shsurf->resource,
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001601 edges, width, height);
1602}
1603
1604static const struct weston_shell_client shell_client = {
1605 send_configure
1606};
1607
1608static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001609resize_grab_button(struct weston_pointer_grab *grab,
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001610 uint32_t time, uint32_t button, uint32_t state_w)
1611{
1612 struct weston_resize_grab *resize = (struct weston_resize_grab *) grab;
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001613 struct weston_pointer *pointer = grab->pointer;
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001614 enum wl_pointer_button_state state = state_w;
1615
1616 if (pointer->button_count == 0 &&
1617 state == WL_POINTER_BUTTON_STATE_RELEASED) {
1618 shell_grab_end(&resize->base);
1619 free(grab);
1620 }
1621}
1622
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02001623static void
1624resize_grab_cancel(struct weston_pointer_grab *grab)
1625{
1626 struct weston_resize_grab *resize = (struct weston_resize_grab *) grab;
1627
1628 shell_grab_end(&resize->base);
1629 free(grab);
1630}
1631
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001632static const struct weston_pointer_grab_interface resize_grab_interface = {
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001633 noop_grab_focus,
1634 resize_grab_motion,
1635 resize_grab_button,
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02001636 resize_grab_cancel,
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001637};
1638
Giulio Camuffob8366642013-04-25 13:57:46 +03001639/*
1640 * Returns the bounding box of a surface and all its sub-surfaces,
1641 * in the surface coordinates system. */
1642static void
1643surface_subsurfaces_boundingbox(struct weston_surface *surface, int32_t *x,
1644 int32_t *y, int32_t *w, int32_t *h) {
1645 pixman_region32_t region;
1646 pixman_box32_t *box;
1647 struct weston_subsurface *subsurface;
1648
1649 pixman_region32_init_rect(&region, 0, 0,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001650 surface->width,
1651 surface->height);
Giulio Camuffob8366642013-04-25 13:57:46 +03001652
1653 wl_list_for_each(subsurface, &surface->subsurface_list, parent_link) {
1654 pixman_region32_union_rect(&region, &region,
1655 subsurface->position.x,
1656 subsurface->position.y,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001657 subsurface->surface->width,
1658 subsurface->surface->height);
Giulio Camuffob8366642013-04-25 13:57:46 +03001659 }
1660
1661 box = pixman_region32_extents(&region);
1662 if (x)
1663 *x = box->x1;
1664 if (y)
1665 *y = box->y1;
1666 if (w)
1667 *w = box->x2 - box->x1;
1668 if (h)
1669 *h = box->y2 - box->y1;
1670
1671 pixman_region32_fini(&region);
1672}
1673
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001674static int
1675surface_resize(struct shell_surface *shsurf,
Kristian Høgsberge3148752013-05-06 23:19:49 -04001676 struct weston_seat *seat, uint32_t edges)
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001677{
1678 struct weston_resize_grab *resize;
1679
Rafael Antognolli03b16592013-12-03 15:35:42 -02001680 if (shsurf->state.fullscreen || shsurf->state.maximized)
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001681 return 0;
1682
1683 if (edges == 0 || edges > 15 ||
1684 (edges & 3) == 3 || (edges & 12) == 12)
1685 return 0;
1686
1687 resize = malloc(sizeof *resize);
1688 if (!resize)
1689 return -1;
1690
1691 resize->edges = edges;
Giulio Camuffob8366642013-04-25 13:57:46 +03001692 surface_subsurfaces_boundingbox(shsurf->surface, NULL, NULL,
1693 &resize->width, &resize->height);
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001694
Kristian Høgsberg44cd1962014-02-05 21:36:04 -08001695 shsurf->resize_edges = edges;
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001696 shell_grab_start(&resize->base, &resize_grab_interface, shsurf,
Kristian Høgsberge3148752013-05-06 23:19:49 -04001697 seat->pointer, edges);
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001698
1699 return 0;
1700}
1701
1702static void
Rafael Antognollie2a34552013-12-03 15:35:45 -02001703common_surface_resize(struct wl_resource *resource,
1704 struct wl_resource *seat_resource, uint32_t serial,
1705 uint32_t edges)
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001706{
Jason Ekstrand44a38632013-06-14 10:08:00 -05001707 struct weston_seat *seat = wl_resource_get_user_data(seat_resource);
Jason Ekstrand651f00e2013-06-14 10:07:54 -05001708 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
Giulio Camuffo61da3fc2013-04-25 13:57:45 +03001709 struct weston_surface *surface;
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001710
Rafael Antognolli03b16592013-12-03 15:35:42 -02001711 if (shsurf->state.fullscreen)
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001712 return;
1713
Kristian Høgsberge3148752013-05-06 23:19:49 -04001714 if (seat->pointer->button_count == 0 ||
1715 seat->pointer->grab_serial != serial ||
Kristian Høgsberg70f29012014-01-09 15:43:17 -08001716 seat->pointer->focus == NULL)
1717 return;
1718
1719 surface = weston_surface_get_main_surface(seat->pointer->focus->surface);
1720 if (surface != shsurf->surface)
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001721 return;
1722
Kristian Høgsberge3148752013-05-06 23:19:49 -04001723 if (surface_resize(shsurf, seat, edges) < 0)
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001724 wl_resource_post_no_memory(resource);
1725}
1726
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001727static void
Rafael Antognollie2a34552013-12-03 15:35:45 -02001728shell_surface_resize(struct wl_client *client, struct wl_resource *resource,
1729 struct wl_resource *seat_resource, uint32_t serial,
1730 uint32_t edges)
1731{
1732 common_surface_resize(resource, seat_resource, serial, edges);
1733}
1734
1735static void
Kristian Høgsberg6848c252013-05-08 22:02:59 -04001736busy_cursor_grab_focus(struct weston_pointer_grab *base)
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001737{
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001738 struct shell_grab *grab = (struct shell_grab *) base;
Kristian Høgsberg6848c252013-05-08 22:02:59 -04001739 struct weston_pointer *pointer = base->pointer;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001740 struct weston_view *view;
Kristian Høgsberg6848c252013-05-08 22:02:59 -04001741 wl_fixed_t sx, sy;
1742
Jason Ekstranda7af7042013-10-12 22:38:11 -05001743 view = weston_compositor_pick_view(pointer->seat->compositor,
1744 pointer->x, pointer->y,
1745 &sx, &sy);
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001746
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08001747 if (!grab->shsurf || grab->shsurf->surface != view->surface) {
1748 shell_grab_end(grab);
1749 free(grab);
1750 }
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001751}
1752
1753static void
Giulio Camuffo1959ab82013-11-14 23:42:52 +01001754busy_cursor_grab_motion(struct weston_pointer_grab *grab, uint32_t time,
1755 wl_fixed_t x, wl_fixed_t y)
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001756{
Giulio Camuffo1959ab82013-11-14 23:42:52 +01001757 weston_pointer_move(grab->pointer, x, y);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001758}
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001759
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001760static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001761busy_cursor_grab_button(struct weston_pointer_grab *base,
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001762 uint32_t time, uint32_t button, uint32_t state)
1763{
Kristian Høgsbergbbe98392012-08-01 00:20:21 -04001764 struct shell_grab *grab = (struct shell_grab *) base;
Kristian Høgsberge122b7b2013-05-08 16:47:00 -04001765 struct shell_surface *shsurf = grab->shsurf;
Kristian Høgsberge3148752013-05-06 23:19:49 -04001766 struct weston_seat *seat = grab->grab.pointer->seat;
Kristian Høgsbergbbe98392012-08-01 00:20:21 -04001767
Kristian Høgsbergbbe98392012-08-01 00:20:21 -04001768 if (shsurf && button == BTN_LEFT && state) {
1769 activate(shsurf->shell, shsurf->surface, seat);
1770 surface_move(shsurf, seat);
Kristian Høgsberg0c369032013-02-14 21:31:44 -05001771 } else if (shsurf && button == BTN_RIGHT && state) {
1772 activate(shsurf->shell, shsurf->surface, seat);
Kristian Høgsberge3148752013-05-06 23:19:49 -04001773 surface_rotate(shsurf, seat);
Kristian Høgsbergbbe98392012-08-01 00:20:21 -04001774 }
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001775}
1776
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02001777static void
1778busy_cursor_grab_cancel(struct weston_pointer_grab *base)
1779{
1780 struct shell_grab *grab = (struct shell_grab *) base;
1781
1782 shell_grab_end(grab);
1783 free(grab);
1784}
1785
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001786static const struct weston_pointer_grab_interface busy_cursor_grab_interface = {
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001787 busy_cursor_grab_focus,
1788 busy_cursor_grab_motion,
1789 busy_cursor_grab_button,
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02001790 busy_cursor_grab_cancel,
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001791};
1792
1793static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001794set_busy_cursor(struct shell_surface *shsurf, struct weston_pointer *pointer)
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001795{
1796 struct shell_grab *grab;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001797
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08001798 if (pointer->grab->interface == &busy_cursor_grab_interface)
1799 return;
1800
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001801 grab = malloc(sizeof *grab);
1802 if (!grab)
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001803 return;
1804
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001805 shell_grab_start(grab, &busy_cursor_grab_interface, shsurf, pointer,
1806 DESKTOP_SHELL_CURSOR_BUSY);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001807}
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001808
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001809static void
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08001810end_busy_cursor(struct weston_compositor *compositor, struct wl_client *client)
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001811{
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08001812 struct shell_grab *grab;
1813 struct weston_seat *seat;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001814
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08001815 wl_list_for_each(seat, &compositor->seat_list, link) {
1816 if (seat->pointer == NULL)
1817 continue;
1818
1819 grab = (struct shell_grab *) seat->pointer->grab;
1820 if (grab->grab.interface == &busy_cursor_grab_interface &&
1821 wl_resource_get_client(grab->shsurf->resource) == client) {
1822 shell_grab_end(grab);
1823 free(grab);
1824 }
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001825 }
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001826}
1827
Scott Moreau9521d5e2012-04-19 13:06:17 -06001828static void
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08001829handle_shell_client_destroy(struct wl_listener *listener, void *data);
1830
1831static int
1832xdg_ping_timeout_handler(void *data)
1833{
1834 struct shell_client *sc = data;
1835 struct weston_seat *seat;
1836 struct shell_surface *shsurf;
1837
1838 /* Client is not responding */
1839 sc->unresponsive = 1;
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08001840 wl_list_for_each(seat, &sc->shell->compositor->seat_list, link) {
1841 if (seat->pointer == NULL || seat->pointer->focus == NULL)
1842 continue;
1843 if (seat->pointer->focus->surface->resource == NULL)
1844 continue;
1845
1846 shsurf = get_shell_surface(seat->pointer->focus->surface);
1847 if (shsurf &&
1848 wl_resource_get_client(shsurf->resource) == sc->client)
1849 set_busy_cursor(shsurf, seat->pointer);
1850 }
1851
1852 return 1;
1853}
1854
1855static void
1856handle_xdg_ping(struct shell_surface *shsurf, uint32_t serial)
1857{
1858 struct weston_compositor *compositor = shsurf->shell->compositor;
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08001859 struct wl_client *client = wl_resource_get_client(shsurf->resource);
1860 struct shell_client *sc;
1861 struct wl_event_loop *loop;
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08001862 static const int ping_timeout = 200;
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08001863
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08001864 sc = get_shell_client(client);
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08001865 if (sc->unresponsive) {
1866 xdg_ping_timeout_handler(sc);
1867 return;
1868 }
1869
1870 sc->ping_serial = serial;
1871 loop = wl_display_get_event_loop(compositor->wl_display);
1872 if (sc->ping_timer == NULL)
1873 sc->ping_timer =
1874 wl_event_loop_add_timer(loop,
1875 xdg_ping_timeout_handler, sc);
1876 if (sc->ping_timer == NULL)
1877 return;
1878
1879 wl_event_source_timer_update(sc->ping_timer, ping_timeout);
1880
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08001881 if (shell_surface_is_xdg_surface(shsurf) ||
1882 shell_surface_is_xdg_popup(shsurf))
1883 xdg_shell_send_ping(sc->resource, serial);
1884 else if (shell_surface_is_wl_shell_surface(shsurf))
1885 wl_shell_surface_send_ping(shsurf->resource, serial);
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08001886}
1887
Scott Moreauff1db4a2012-04-17 19:06:18 -06001888static void
1889ping_handler(struct weston_surface *surface, uint32_t serial)
1890{
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001891 struct shell_surface *shsurf = get_shell_surface(surface);
Scott Moreauff1db4a2012-04-17 19:06:18 -06001892
1893 if (!shsurf)
1894 return;
Jason Ekstrand651f00e2013-06-14 10:07:54 -05001895 if (!shsurf->resource)
Kristian Høgsbergca535c12012-04-21 23:20:07 -04001896 return;
Ander Conselvan de Oliveiraeac9a462012-07-16 14:15:48 +03001897 if (shsurf->surface == shsurf->shell->grab_surface)
1898 return;
1899
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08001900 handle_xdg_ping(shsurf, serial);
Scott Moreauff1db4a2012-04-17 19:06:18 -06001901}
1902
1903static void
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001904handle_pointer_focus(struct wl_listener *listener, void *data)
1905{
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001906 struct weston_pointer *pointer = data;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001907 struct weston_view *view = pointer->focus;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001908 struct weston_compositor *compositor;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001909 uint32_t serial;
1910
Jason Ekstranda7af7042013-10-12 22:38:11 -05001911 if (!view)
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001912 return;
1913
Jason Ekstranda7af7042013-10-12 22:38:11 -05001914 compositor = view->surface->compositor;
Kristian Høgsberge11ef642014-02-11 16:35:22 -08001915 serial = wl_display_next_serial(compositor->wl_display);
1916 ping_handler(view->surface, serial);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001917}
1918
1919static void
Kristian Høgsbergf4d2f232012-08-10 10:05:39 -04001920create_pointer_focus_listener(struct weston_seat *seat)
1921{
1922 struct wl_listener *listener;
1923
Kristian Høgsberge3148752013-05-06 23:19:49 -04001924 if (!seat->pointer)
Kristian Høgsbergf4d2f232012-08-10 10:05:39 -04001925 return;
1926
1927 listener = malloc(sizeof *listener);
1928 listener->notify = handle_pointer_focus;
Kristian Høgsberge3148752013-05-06 23:19:49 -04001929 wl_signal_add(&seat->pointer->focus_signal, listener);
Kristian Høgsbergf4d2f232012-08-10 10:05:39 -04001930}
1931
1932static void
Jasper St. Pierrefaf27a92013-12-09 17:36:28 -05001933shell_surface_lose_keyboard_focus(struct shell_surface *shsurf)
1934{
1935 if (--shsurf->focus_count == 0)
1936 if (shell_surface_is_xdg_surface(shsurf))
1937 xdg_surface_send_focused_unset(shsurf->resource);
1938}
1939
1940static void
1941shell_surface_gain_keyboard_focus(struct shell_surface *shsurf)
1942{
1943 if (shsurf->focus_count++ == 0)
1944 if (shell_surface_is_xdg_surface(shsurf))
1945 xdg_surface_send_focused_set(shsurf->resource);
1946}
1947
1948static void
1949handle_keyboard_focus(struct wl_listener *listener, void *data)
1950{
1951 struct weston_keyboard *keyboard = data;
1952 struct shell_seat *seat = get_shell_seat(keyboard->seat);
1953
1954 if (seat->focused_surface) {
1955 struct shell_surface *shsurf = get_shell_surface(seat->focused_surface);
1956 if (shsurf)
1957 shell_surface_lose_keyboard_focus(shsurf);
1958 }
1959
1960 seat->focused_surface = keyboard->focus;
1961
1962 if (seat->focused_surface) {
1963 struct shell_surface *shsurf = get_shell_surface(seat->focused_surface);
1964 if (shsurf)
1965 shell_surface_gain_keyboard_focus(shsurf);
1966 }
1967}
1968
1969static void
1970create_keyboard_focus_listener(struct weston_seat *seat)
1971{
1972 struct wl_listener *listener;
1973
1974 if (!seat->keyboard)
1975 return;
1976
1977 listener = malloc(sizeof *listener);
1978 listener->notify = handle_keyboard_focus;
1979 wl_signal_add(&seat->keyboard->focus_signal, listener);
1980}
1981
1982static void
Rafael Antognollie2a34552013-12-03 15:35:45 -02001983xdg_surface_set_transient_for(struct wl_client *client,
1984 struct wl_resource *resource,
1985 struct wl_resource *parent_resource)
Scott Moreauff1db4a2012-04-17 19:06:18 -06001986{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05001987 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
Jasper St. Pierre8f180d42013-12-07 13:49:28 -05001988 struct weston_surface *parent;
1989
1990 if (parent_resource)
1991 parent = wl_resource_get_user_data(parent_resource);
1992 else
1993 parent = NULL;
Rafael Antognollie2a34552013-12-03 15:35:45 -02001994
1995 shell_surface_set_parent(shsurf, parent);
1996}
1997
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08001998static struct shell_client *
1999get_shell_client(struct wl_client *client)
Rafael Antognollie2a34552013-12-03 15:35:45 -02002000{
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08002001 struct wl_listener *listener;
Scott Moreauff1db4a2012-04-17 19:06:18 -06002002
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08002003 listener = wl_client_get_destroy_listener(client,
2004 handle_shell_client_destroy);
2005 if (listener == NULL)
2006 return NULL;
Kristian Høgsberg92374e12012-08-11 22:39:12 -04002007
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08002008 return container_of(listener, struct shell_client, destroy_listener);
Scott Moreauff1db4a2012-04-17 19:06:18 -06002009}
2010
Kristian Høgsberge7afd912012-05-02 09:47:44 -04002011static void
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08002012shell_client_pong(struct shell_client *sc, uint32_t serial)
Rafael Antognollie2a34552013-12-03 15:35:45 -02002013{
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08002014 if (sc->ping_serial != serial)
2015 return;
Rafael Antognollie2a34552013-12-03 15:35:45 -02002016
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08002017 sc->unresponsive = 0;
2018 end_busy_cursor(sc->shell->compositor, sc->client);
Rafael Antognollie2a34552013-12-03 15:35:45 -02002019
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08002020 if (sc->ping_timer) {
2021 wl_event_source_remove(sc->ping_timer);
2022 sc->ping_timer = NULL;
2023 }
2024
2025}
2026
2027static void
2028shell_surface_pong(struct wl_client *client,
2029 struct wl_resource *resource, uint32_t serial)
2030{
2031 struct shell_client *sc;
2032
2033 sc = get_shell_client(client);
2034 shell_client_pong(sc, serial);
Rafael Antognollie2a34552013-12-03 15:35:45 -02002035}
2036
2037static void
Giulio Camuffo62942ad2013-09-11 18:20:47 +02002038set_title(struct shell_surface *shsurf, const char *title)
2039{
2040 free(shsurf->title);
2041 shsurf->title = strdup(title);
2042}
2043
2044static void
Kristian Høgsberge7afd912012-05-02 09:47:44 -04002045shell_surface_set_title(struct wl_client *client,
2046 struct wl_resource *resource, const char *title)
2047{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05002048 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
Kristian Høgsberge7afd912012-05-02 09:47:44 -04002049
Giulio Camuffo62942ad2013-09-11 18:20:47 +02002050 set_title(shsurf, title);
Kristian Høgsberge7afd912012-05-02 09:47:44 -04002051}
2052
2053static void
2054shell_surface_set_class(struct wl_client *client,
2055 struct wl_resource *resource, const char *class)
2056{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05002057 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
Kristian Høgsberge7afd912012-05-02 09:47:44 -04002058
2059 free(shsurf->class);
2060 shsurf->class = strdup(class);
2061}
2062
Alex Wu4539b082012-03-01 12:57:46 +08002063static void
Alexander Larssonf82b6ca2013-05-28 16:23:39 +02002064restore_output_mode(struct weston_output *output)
2065{
Hardening57388e42013-09-18 23:56:36 +02002066 if (output->current_mode != output->original_mode ||
2067 (int32_t)output->current_scale != output->original_scale)
Alexander Larssonf82b6ca2013-05-28 16:23:39 +02002068 weston_output_switch_mode(output,
Hardening57388e42013-09-18 23:56:36 +02002069 output->original_mode,
2070 output->original_scale,
2071 WESTON_MODE_SWITCH_RESTORE_NATIVE);
Alexander Larssonf82b6ca2013-05-28 16:23:39 +02002072}
2073
2074static void
2075restore_all_output_modes(struct weston_compositor *compositor)
2076{
2077 struct weston_output *output;
2078
2079 wl_list_for_each(output, &compositor->output_list, link)
2080 restore_output_mode(output);
2081}
2082
Philip Withnallbecb77e2013-11-25 18:01:30 +00002083static int
2084get_output_panel_height(struct desktop_shell *shell,
2085 struct weston_output *output)
2086{
2087 struct weston_view *view;
2088 int panel_height = 0;
2089
2090 if (!output)
2091 return 0;
2092
2093 wl_list_for_each(view, &shell->panel_layer.view_list, layer_link) {
2094 if (view->surface->output == output) {
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06002095 panel_height = view->surface->height;
Philip Withnallbecb77e2013-11-25 18:01:30 +00002096 break;
2097 }
2098 }
2099
2100 return panel_height;
2101}
2102
Philip Withnall07926d92013-11-25 18:01:40 +00002103/* The surface will be inserted into the list immediately after the link
2104 * returned by this function (i.e. will be stacked immediately above the
2105 * returned link). */
2106static struct wl_list *
2107shell_surface_calculate_layer_link (struct shell_surface *shsurf)
2108{
2109 struct workspace *ws;
Kristian Høgsbergead52422014-01-01 13:51:52 -08002110 struct weston_view *parent;
Philip Withnall07926d92013-11-25 18:01:40 +00002111
2112 switch (shsurf->type) {
Kristian Høgsbergead52422014-01-01 13:51:52 -08002113 case SHELL_SURFACE_POPUP:
2114 case SHELL_SURFACE_TOPLEVEL:
Rafael Antognollied207b42013-12-03 15:35:43 -02002115 if (shsurf->state.fullscreen) {
Rafael Antognolli03b16592013-12-03 15:35:42 -02002116 return &shsurf->shell->fullscreen_layer.view_list;
Rafael Antognollied207b42013-12-03 15:35:43 -02002117 } else if (shsurf->parent) {
Kristian Høgsbergd55db692014-01-01 12:26:14 -08002118 /* Move the surface to its parent layer so
2119 * that surfaces which are transient for
2120 * fullscreen surfaces don't get hidden by the
2121 * fullscreen surfaces. */
Rafael Antognollied207b42013-12-03 15:35:43 -02002122
2123 /* TODO: Handle a parent with multiple views */
2124 parent = get_default_view(shsurf->parent);
2125 if (parent)
2126 return parent->layer_link.prev;
2127 }
Rafael Antognolli03b16592013-12-03 15:35:42 -02002128 break;
Philip Withnall07926d92013-11-25 18:01:40 +00002129
2130 case SHELL_SURFACE_XWAYLAND:
Kristian Høgsberg4804a302013-12-05 22:43:03 -08002131 return &shsurf->shell->fullscreen_layer.view_list;
2132
Philip Withnall07926d92013-11-25 18:01:40 +00002133 case SHELL_SURFACE_NONE:
2134 default:
2135 /* Go to the fallback, below. */
2136 break;
2137 }
2138
2139 /* Move the surface to a normal workspace layer so that surfaces
2140 * which were previously fullscreen or transient are no longer
2141 * rendered on top. */
2142 ws = get_current_workspace(shsurf->shell);
2143 return &ws->layer.view_list;
2144}
2145
Philip Withnall648a4dd2013-11-25 18:01:44 +00002146static void
2147shell_surface_update_child_surface_layers (struct shell_surface *shsurf)
2148{
2149 struct shell_surface *child;
2150
2151 /* Move the child layers to the same workspace as shsurf. They will be
2152 * stacked above shsurf. */
2153 wl_list_for_each_reverse(child, &shsurf->children_list, children_link) {
2154 if (shsurf->view->layer_link.prev != &child->view->layer_link) {
2155 weston_view_geometry_dirty(child->view);
2156 wl_list_remove(&child->view->layer_link);
2157 wl_list_insert(shsurf->view->layer_link.prev,
2158 &child->view->layer_link);
2159 weston_view_geometry_dirty(child->view);
2160 weston_surface_damage(child->surface);
2161
2162 /* Recurse. We don’t expect this to recurse very far (if
2163 * at all) because that would imply we have transient
2164 * (or popup) children of transient surfaces, which
2165 * would be unusual. */
2166 shell_surface_update_child_surface_layers(child);
2167 }
2168 }
2169}
2170
Philip Withnalle1d75ae2013-11-25 18:01:41 +00002171/* Update the surface’s layer. Mark both the old and new views as having dirty
Philip Withnall648a4dd2013-11-25 18:01:44 +00002172 * geometry to ensure the changes are redrawn.
2173 *
2174 * If any child surfaces exist and are mapped, ensure they’re in the same layer
2175 * as this surface. */
Philip Withnalle1d75ae2013-11-25 18:01:41 +00002176static void
2177shell_surface_update_layer(struct shell_surface *shsurf)
2178{
2179 struct wl_list *new_layer_link;
2180
2181 new_layer_link = shell_surface_calculate_layer_link(shsurf);
2182
2183 if (new_layer_link == &shsurf->view->layer_link)
2184 return;
2185
2186 weston_view_geometry_dirty(shsurf->view);
2187 wl_list_remove(&shsurf->view->layer_link);
2188 wl_list_insert(new_layer_link, &shsurf->view->layer_link);
2189 weston_view_geometry_dirty(shsurf->view);
2190 weston_surface_damage(shsurf->surface);
Philip Withnall648a4dd2013-11-25 18:01:44 +00002191
2192 shell_surface_update_child_surface_layers(shsurf);
Philip Withnalle1d75ae2013-11-25 18:01:41 +00002193}
2194
Alexander Larssonf82b6ca2013-05-28 16:23:39 +02002195static void
Philip Withnalldc4332f2013-11-25 18:01:38 +00002196shell_surface_set_parent(struct shell_surface *shsurf,
2197 struct weston_surface *parent)
2198{
2199 shsurf->parent = parent;
Philip Withnall648a4dd2013-11-25 18:01:44 +00002200
2201 wl_list_remove(&shsurf->children_link);
2202 wl_list_init(&shsurf->children_link);
2203
2204 /* Insert into the parent surface’s child list. */
2205 if (parent != NULL) {
2206 struct shell_surface *parent_shsurf = get_shell_surface(parent);
2207 if (parent_shsurf != NULL)
2208 wl_list_insert(&parent_shsurf->children_list,
2209 &shsurf->children_link);
2210 }
Philip Withnalldc4332f2013-11-25 18:01:38 +00002211}
2212
2213static void
Philip Withnall352e7ed2013-11-25 18:01:35 +00002214shell_surface_set_output(struct shell_surface *shsurf,
2215 struct weston_output *output)
2216{
2217 struct weston_surface *es = shsurf->surface;
2218
2219 /* get the default output, if the client set it as NULL
2220 check whether the ouput is available */
2221 if (output)
2222 shsurf->output = output;
2223 else if (es->output)
2224 shsurf->output = es->output;
2225 else
2226 shsurf->output = get_default_output(es->compositor);
2227}
2228
2229static void
Rafael Antognolli03b16592013-12-03 15:35:42 -02002230surface_clear_next_states(struct shell_surface *shsurf)
2231{
2232 shsurf->next_state.maximized = false;
2233 shsurf->next_state.fullscreen = false;
2234
2235 if ((shsurf->next_state.maximized != shsurf->state.maximized) ||
2236 (shsurf->next_state.fullscreen != shsurf->state.fullscreen))
2237 shsurf->state_changed = true;
2238}
2239
2240static void
Philip Withnallbecb77e2013-11-25 18:01:30 +00002241set_toplevel(struct shell_surface *shsurf)
2242{
Kristian Høgsberg41fbf6f2013-12-05 22:31:25 -08002243 shell_surface_set_parent(shsurf, NULL);
2244 surface_clear_next_states(shsurf);
Kristian Høgsbergc8f8dd82013-12-05 23:20:33 -08002245 shsurf->type = SHELL_SURFACE_TOPLEVEL;
Philip Withnall648a4dd2013-11-25 18:01:44 +00002246
2247 /* The layer_link is updated in set_surface_type(),
2248 * called from configure. */
Philip Withnallbecb77e2013-11-25 18:01:30 +00002249}
2250
2251static void
2252shell_surface_set_toplevel(struct wl_client *client,
2253 struct wl_resource *resource)
2254{
2255 struct shell_surface *surface = wl_resource_get_user_data(resource);
2256
2257 set_toplevel(surface);
2258}
2259
2260static void
2261set_transient(struct shell_surface *shsurf,
2262 struct weston_surface *parent, int x, int y, uint32_t flags)
2263{
Philip Withnalldc4332f2013-11-25 18:01:38 +00002264 assert(parent != NULL);
2265
Kristian Høgsberg9f7e3312014-01-02 22:40:37 -08002266 shell_surface_set_parent(shsurf, parent);
2267
2268 surface_clear_next_states(shsurf);
2269
Philip Withnallbecb77e2013-11-25 18:01:30 +00002270 shsurf->transient.x = x;
2271 shsurf->transient.y = y;
2272 shsurf->transient.flags = flags;
Philip Withnalldc4332f2013-11-25 18:01:38 +00002273
Rafael Antognollied207b42013-12-03 15:35:43 -02002274 shsurf->next_state.relative = true;
Kristian Høgsberga1df7ac2013-12-31 15:01:01 -08002275 shsurf->state_changed = true;
Kristian Høgsbergc8f8dd82013-12-05 23:20:33 -08002276 shsurf->type = SHELL_SURFACE_TOPLEVEL;
Philip Withnall648a4dd2013-11-25 18:01:44 +00002277
2278 /* The layer_link is updated in set_surface_type(),
2279 * called from configure. */
Philip Withnallbecb77e2013-11-25 18:01:30 +00002280}
2281
2282static void
2283shell_surface_set_transient(struct wl_client *client,
2284 struct wl_resource *resource,
2285 struct wl_resource *parent_resource,
2286 int x, int y, uint32_t flags)
2287{
2288 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
2289 struct weston_surface *parent =
2290 wl_resource_get_user_data(parent_resource);
2291
2292 set_transient(shsurf, parent, x, y, flags);
2293}
2294
2295static void
2296set_fullscreen(struct shell_surface *shsurf,
2297 uint32_t method,
2298 uint32_t framerate,
2299 struct weston_output *output)
2300{
Philip Withnall352e7ed2013-11-25 18:01:35 +00002301 shell_surface_set_output(shsurf, output);
Philip Withnallbecb77e2013-11-25 18:01:30 +00002302
2303 shsurf->fullscreen_output = shsurf->output;
2304 shsurf->fullscreen.type = method;
2305 shsurf->fullscreen.framerate = framerate;
Philip Withnalldc4332f2013-11-25 18:01:38 +00002306
Kristian Høgsberge960b3f2013-12-05 22:04:42 -08002307 shsurf->next_state.fullscreen = true;
2308 shsurf->state_changed = true;
Kristian Høgsbergc8f8dd82013-12-05 23:20:33 -08002309 shsurf->type = SHELL_SURFACE_TOPLEVEL;
Philip Withnallbecb77e2013-11-25 18:01:30 +00002310
2311 shsurf->client->send_configure(shsurf->surface, 0,
2312 shsurf->output->width,
2313 shsurf->output->height);
Philip Withnall648a4dd2013-11-25 18:01:44 +00002314
2315 /* The layer_link is updated in set_surface_type(),
2316 * called from configure. */
Philip Withnallbecb77e2013-11-25 18:01:30 +00002317}
2318
2319static void
Zhang, Xiong Y31236932013-12-13 22:10:57 +02002320weston_view_set_initial_position(struct weston_view *view,
2321 struct desktop_shell *shell);
2322
2323static void
Philip Withnallbecb77e2013-11-25 18:01:30 +00002324unset_fullscreen(struct shell_surface *shsurf)
Alex Wu4539b082012-03-01 12:57:46 +08002325{
Philip Withnallf85fe842013-11-25 18:01:37 +00002326 /* Unset the fullscreen output, driver configuration and transforms. */
Alex Wubd3354b2012-04-17 17:20:49 +08002327 if (shsurf->fullscreen.type == WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER &&
2328 shell_surface_is_top_fullscreen(shsurf)) {
Alexander Larssonf82b6ca2013-05-28 16:23:39 +02002329 restore_output_mode(shsurf->fullscreen_output);
Alex Wubd3354b2012-04-17 17:20:49 +08002330 }
Philip Withnallf85fe842013-11-25 18:01:37 +00002331 shsurf->fullscreen_output = NULL;
2332
Alex Wu4539b082012-03-01 12:57:46 +08002333 shsurf->fullscreen.type = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT;
2334 shsurf->fullscreen.framerate = 0;
Philip Withnallf85fe842013-11-25 18:01:37 +00002335
Alex Wu4539b082012-03-01 12:57:46 +08002336 wl_list_remove(&shsurf->fullscreen.transform.link);
2337 wl_list_init(&shsurf->fullscreen.transform.link);
Philip Withnallf85fe842013-11-25 18:01:37 +00002338
Jason Ekstranda7af7042013-10-12 22:38:11 -05002339 if (shsurf->fullscreen.black_view)
2340 weston_surface_destroy(shsurf->fullscreen.black_view->surface);
2341 shsurf->fullscreen.black_view = NULL;
Philip Withnallf85fe842013-11-25 18:01:37 +00002342
Zhang, Xiong Y31236932013-12-13 22:10:57 +02002343 if (shsurf->saved_position_valid)
2344 weston_view_set_position(shsurf->view,
2345 shsurf->saved_x, shsurf->saved_y);
2346 else
2347 weston_view_set_initial_position(shsurf->view, shsurf->shell);
2348
Alex Wu7bcb8bd2012-04-27 09:07:24 +08002349 if (shsurf->saved_rotation_valid) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05002350 wl_list_insert(&shsurf->view->geometry.transformation_list,
Philip Withnallbecb77e2013-11-25 18:01:30 +00002351 &shsurf->rotation.transform.link);
Alex Wu7bcb8bd2012-04-27 09:07:24 +08002352 shsurf->saved_rotation_valid = false;
2353 }
Rafal Mielniczuk3e3862c2012-10-07 20:25:36 +02002354
Philip Withnalle1d75ae2013-11-25 18:01:41 +00002355 /* Layer is updated in set_surface_type(). */
Alex Wu4539b082012-03-01 12:57:46 +08002356}
2357
Rafal Mielniczukfffdcdd2013-03-11 19:26:54 +01002358static void
Philip Withnallbecb77e2013-11-25 18:01:30 +00002359shell_surface_set_fullscreen(struct wl_client *client,
2360 struct wl_resource *resource,
2361 uint32_t method,
2362 uint32_t framerate,
2363 struct wl_resource *output_resource)
2364{
2365 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
2366 struct weston_output *output;
2367
2368 if (output_resource)
2369 output = wl_resource_get_user_data(output_resource);
2370 else
2371 output = NULL;
2372
Rafael Antognolli4b99a402013-12-03 15:35:44 -02002373 shell_surface_set_parent(shsurf, NULL);
2374
Rafael Antognolli03b16592013-12-03 15:35:42 -02002375 surface_clear_next_states(shsurf);
Philip Withnallbecb77e2013-11-25 18:01:30 +00002376 set_fullscreen(shsurf, method, framerate, output);
2377}
2378
2379static void
2380set_popup(struct shell_surface *shsurf,
2381 struct weston_surface *parent,
2382 struct weston_seat *seat,
2383 uint32_t serial,
2384 int32_t x,
2385 int32_t y)
2386{
Philip Withnalldc4332f2013-11-25 18:01:38 +00002387 assert(parent != NULL);
2388
Philip Withnallbecb77e2013-11-25 18:01:30 +00002389 shsurf->popup.shseat = get_shell_seat(seat);
2390 shsurf->popup.serial = serial;
2391 shsurf->popup.x = x;
2392 shsurf->popup.y = y;
Philip Withnalldc4332f2013-11-25 18:01:38 +00002393
Kristian Høgsbergc8f8dd82013-12-05 23:20:33 -08002394 shsurf->type = SHELL_SURFACE_POPUP;
Philip Withnallbecb77e2013-11-25 18:01:30 +00002395}
2396
2397static void
2398shell_surface_set_popup(struct wl_client *client,
2399 struct wl_resource *resource,
2400 struct wl_resource *seat_resource,
2401 uint32_t serial,
2402 struct wl_resource *parent_resource,
2403 int32_t x, int32_t y, uint32_t flags)
2404{
2405 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
Rafael Antognolli4b99a402013-12-03 15:35:44 -02002406 struct weston_surface *parent =
2407 wl_resource_get_user_data(parent_resource);
2408
2409 shell_surface_set_parent(shsurf, parent);
Philip Withnallbecb77e2013-11-25 18:01:30 +00002410
Rafael Antognolli03b16592013-12-03 15:35:42 -02002411 surface_clear_next_states(shsurf);
Philip Withnallbecb77e2013-11-25 18:01:30 +00002412 set_popup(shsurf,
Rafael Antognolli4b99a402013-12-03 15:35:44 -02002413 parent,
Philip Withnallbecb77e2013-11-25 18:01:30 +00002414 wl_resource_get_user_data(seat_resource),
2415 serial, x, y);
2416}
2417
2418static void
2419set_maximized(struct shell_surface *shsurf,
2420 struct weston_output *output)
2421{
2422 struct desktop_shell *shell;
2423 uint32_t edges = 0, panel_height = 0;
Philip Withnallbecb77e2013-11-25 18:01:30 +00002424
Philip Withnall352e7ed2013-11-25 18:01:35 +00002425 shell_surface_set_output(shsurf, output);
Philip Withnallbecb77e2013-11-25 18:01:30 +00002426
2427 shell = shell_surface_get_shell(shsurf);
2428 panel_height = get_output_panel_height(shell, shsurf->output);
2429 edges = WL_SHELL_SURFACE_RESIZE_TOP | WL_SHELL_SURFACE_RESIZE_LEFT;
2430
2431 shsurf->client->send_configure(shsurf->surface, edges,
2432 shsurf->output->width,
2433 shsurf->output->height - panel_height);
2434
Kristian Høgsbergc2745b12013-12-05 22:00:40 -08002435 shsurf->next_state.maximized = true;
2436 shsurf->state_changed = true;
Kristian Høgsbergc8f8dd82013-12-05 23:20:33 -08002437 shsurf->type = SHELL_SURFACE_TOPLEVEL;
Philip Withnallbecb77e2013-11-25 18:01:30 +00002438}
2439
2440static void
2441unset_maximized(struct shell_surface *shsurf)
Rafal Mielniczukfffdcdd2013-03-11 19:26:54 +01002442{
Rafal Mielniczukfffdcdd2013-03-11 19:26:54 +01002443 /* undo all maximized things here */
2444 shsurf->output = get_default_output(shsurf->surface->compositor);
Zhang, Xiong Y31236932013-12-13 22:10:57 +02002445
2446 if (shsurf->saved_position_valid)
2447 weston_view_set_position(shsurf->view,
2448 shsurf->saved_x, shsurf->saved_y);
2449 else
2450 weston_view_set_initial_position(shsurf->view, shsurf->shell);
Rafal Mielniczukfffdcdd2013-03-11 19:26:54 +01002451
2452 if (shsurf->saved_rotation_valid) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05002453 wl_list_insert(&shsurf->view->geometry.transformation_list,
2454 &shsurf->rotation.transform.link);
Rafal Mielniczukfffdcdd2013-03-11 19:26:54 +01002455 shsurf->saved_rotation_valid = false;
2456 }
2457
Philip Withnalle1d75ae2013-11-25 18:01:41 +00002458 /* Layer is updated in set_surface_type(). */
Rafal Mielniczukfffdcdd2013-03-11 19:26:54 +01002459}
2460
Philip Withnallbecb77e2013-11-25 18:01:30 +00002461static void
2462shell_surface_set_maximized(struct wl_client *client,
2463 struct wl_resource *resource,
2464 struct wl_resource *output_resource)
2465{
2466 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
2467 struct weston_output *output;
2468
2469 if (output_resource)
2470 output = wl_resource_get_user_data(output_resource);
2471 else
2472 output = NULL;
2473
Rafael Antognolli4b99a402013-12-03 15:35:44 -02002474 shell_surface_set_parent(shsurf, NULL);
2475
Rafael Antognolli03b16592013-12-03 15:35:42 -02002476 surface_clear_next_states(shsurf);
Philip Withnallbecb77e2013-11-25 18:01:30 +00002477 set_maximized(shsurf, output);
2478}
2479
Philip Withnalle1d75ae2013-11-25 18:01:41 +00002480/* This is only ever called from set_surface_type(), so there’s no need to
2481 * update layer_links here, since they’ll be updated when we return. */
Pekka Paalanen98262232011-12-01 10:42:22 +02002482static int
Philip Withnallbecb77e2013-11-25 18:01:30 +00002483reset_surface_type(struct shell_surface *surface)
Pekka Paalanen98262232011-12-01 10:42:22 +02002484{
Rafael Antognolli03b16592013-12-03 15:35:42 -02002485 if (surface->state.fullscreen)
Philip Withnallbecb77e2013-11-25 18:01:30 +00002486 unset_fullscreen(surface);
Rafael Antognolli03b16592013-12-03 15:35:42 -02002487 if (surface->state.maximized)
Philip Withnallbecb77e2013-11-25 18:01:30 +00002488 unset_maximized(surface);
Pekka Paalanen98262232011-12-01 10:42:22 +02002489
Pekka Paalanen98262232011-12-01 10:42:22 +02002490 return 0;
2491}
2492
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05002493static void
Rafael Antognolli03b16592013-12-03 15:35:42 -02002494set_full_output(struct shell_surface *shsurf)
2495{
2496 shsurf->saved_x = shsurf->view->geometry.x;
2497 shsurf->saved_y = shsurf->view->geometry.y;
Rafael Antognolli3c4e3f72013-12-03 15:35:46 -02002498 shsurf->saved_width = shsurf->surface->width;
2499 shsurf->saved_height = shsurf->surface->height;
2500 shsurf->saved_size_valid = true;
Rafael Antognolli03b16592013-12-03 15:35:42 -02002501 shsurf->saved_position_valid = true;
2502
2503 if (!wl_list_empty(&shsurf->rotation.transform.link)) {
2504 wl_list_remove(&shsurf->rotation.transform.link);
2505 wl_list_init(&shsurf->rotation.transform.link);
2506 weston_view_geometry_dirty(shsurf->view);
2507 shsurf->saved_rotation_valid = true;
2508 }
2509}
2510
2511static void
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04002512set_surface_type(struct shell_surface *shsurf)
2513{
Kristian Høgsberg8150b192012-06-27 10:22:58 -04002514 struct weston_surface *pes = shsurf->parent;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002515 struct weston_view *pev = get_default_view(pes);
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04002516
Philip Withnallbecb77e2013-11-25 18:01:30 +00002517 reset_surface_type(shsurf);
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04002518
Rafael Antognolli03b16592013-12-03 15:35:42 -02002519 shsurf->state = shsurf->next_state;
Rafael Antognolli03b16592013-12-03 15:35:42 -02002520 shsurf->state_changed = false;
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04002521
2522 switch (shsurf->type) {
2523 case SHELL_SURFACE_TOPLEVEL:
Rafael Antognollied207b42013-12-03 15:35:43 -02002524 if (shsurf->state.maximized || shsurf->state.fullscreen) {
Rafael Antognolli03b16592013-12-03 15:35:42 -02002525 set_full_output(shsurf);
Rafael Antognollied207b42013-12-03 15:35:43 -02002526 } else if (shsurf->state.relative && pev) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05002527 weston_view_set_position(shsurf->view,
2528 pev->geometry.x + shsurf->transient.x,
2529 pev->geometry.y + shsurf->transient.y);
Rafael Antognollied207b42013-12-03 15:35:43 -02002530 }
Rafael Antognolli44a31622013-12-04 18:37:16 -02002531 break;
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04002532
Tiago Vignattifb2adba2013-06-12 15:43:21 -03002533 case SHELL_SURFACE_XWAYLAND:
Jason Ekstranda7af7042013-10-12 22:38:11 -05002534 weston_view_set_position(shsurf->view, shsurf->transient.x,
2535 shsurf->transient.y);
Tiago Vignattifb2adba2013-06-12 15:43:21 -03002536 break;
2537
Philip Withnall0f640e22013-11-25 18:01:31 +00002538 case SHELL_SURFACE_POPUP:
2539 case SHELL_SURFACE_NONE:
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04002540 default:
2541 break;
2542 }
Philip Withnalle1d75ae2013-11-25 18:01:41 +00002543
2544 /* Update the surface’s layer. */
2545 shell_surface_update_layer(shsurf);
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04002546}
2547
Tiago Vignattibe143262012-04-16 17:31:41 +03002548static struct desktop_shell *
Juan Zhao96879df2012-02-07 08:45:41 +08002549shell_surface_get_shell(struct shell_surface *shsurf)
Pekka Paalanenaf0e34c2011-12-02 10:59:17 +02002550{
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04002551 return shsurf->shell;
Juan Zhao96879df2012-02-07 08:45:41 +08002552}
2553
Alex Wu21858432012-04-01 20:13:08 +08002554static void
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06002555black_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy);
Alex Wu21858432012-04-01 20:13:08 +08002556
Jason Ekstranda7af7042013-10-12 22:38:11 -05002557static struct weston_view *
Alex Wu4539b082012-03-01 12:57:46 +08002558create_black_surface(struct weston_compositor *ec,
Alex Wu21858432012-04-01 20:13:08 +08002559 struct weston_surface *fs_surface,
John Kåre Alsaker490d02a2012-09-30 02:57:21 +02002560 float x, float y, int w, int h)
Alex Wu4539b082012-03-01 12:57:46 +08002561{
2562 struct weston_surface *surface = NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002563 struct weston_view *view;
Alex Wu4539b082012-03-01 12:57:46 +08002564
2565 surface = weston_surface_create(ec);
2566 if (surface == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002567 weston_log("no memory\n");
Alex Wu4539b082012-03-01 12:57:46 +08002568 return NULL;
2569 }
Jason Ekstranda7af7042013-10-12 22:38:11 -05002570 view = weston_view_create(surface);
2571 if (surface == NULL) {
2572 weston_log("no memory\n");
2573 weston_surface_destroy(surface);
2574 return NULL;
2575 }
Alex Wu4539b082012-03-01 12:57:46 +08002576
Alex Wu21858432012-04-01 20:13:08 +08002577 surface->configure = black_surface_configure;
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01002578 surface->configure_private = fs_surface;
Alex Wu4539b082012-03-01 12:57:46 +08002579 weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1);
Pekka Paalanen71f6f3b2012-10-10 12:49:26 +03002580 pixman_region32_fini(&surface->opaque);
Kristian Høgsberg61f00f52012-08-03 16:31:36 -04002581 pixman_region32_init_rect(&surface->opaque, 0, 0, w, h);
Jonas Ådahl33619a42013-01-15 21:25:55 +01002582 pixman_region32_fini(&surface->input);
2583 pixman_region32_init_rect(&surface->input, 0, 0, w, h);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06002584
Jason Ekstrand6228ee22014-01-01 15:58:57 -06002585 weston_surface_set_size(surface, w, h);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06002586 weston_view_set_position(view, x, y);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002587
2588 return view;
Alex Wu4539b082012-03-01 12:57:46 +08002589}
2590
Philip Withnalled8f1a92013-11-25 18:01:43 +00002591static void
2592shell_ensure_fullscreen_black_view(struct shell_surface *shsurf)
2593{
2594 struct weston_output *output = shsurf->fullscreen_output;
2595
Rafael Antognolli03b16592013-12-03 15:35:42 -02002596 assert(shsurf->state.fullscreen);
Philip Withnalled8f1a92013-11-25 18:01:43 +00002597
2598 if (!shsurf->fullscreen.black_view)
2599 shsurf->fullscreen.black_view =
2600 create_black_surface(shsurf->surface->compositor,
2601 shsurf->surface,
2602 output->x, output->y,
2603 output->width,
2604 output->height);
2605
2606 weston_view_geometry_dirty(shsurf->fullscreen.black_view);
2607 wl_list_remove(&shsurf->fullscreen.black_view->layer_link);
2608 wl_list_insert(&shsurf->view->layer_link,
2609 &shsurf->fullscreen.black_view->layer_link);
2610 weston_view_geometry_dirty(shsurf->fullscreen.black_view);
2611 weston_surface_damage(shsurf->surface);
2612}
2613
Alex Wu4539b082012-03-01 12:57:46 +08002614/* Create black surface and append it to the associated fullscreen surface.
2615 * Handle size dismatch and positioning according to the method. */
2616static void
2617shell_configure_fullscreen(struct shell_surface *shsurf)
2618{
2619 struct weston_output *output = shsurf->fullscreen_output;
2620 struct weston_surface *surface = shsurf->surface;
2621 struct weston_matrix *matrix;
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04002622 float scale, output_aspect, surface_aspect, x, y;
Giulio Camuffob8366642013-04-25 13:57:46 +03002623 int32_t surf_x, surf_y, surf_width, surf_height;
Alex Wu4539b082012-03-01 12:57:46 +08002624
Alexander Larssonf82b6ca2013-05-28 16:23:39 +02002625 if (shsurf->fullscreen.type != WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER)
2626 restore_output_mode(output);
2627
Philip Withnalled8f1a92013-11-25 18:01:43 +00002628 shell_ensure_fullscreen_black_view(shsurf);
Alex Wu4539b082012-03-01 12:57:46 +08002629
Jason Ekstranda7af7042013-10-12 22:38:11 -05002630 surface_subsurfaces_boundingbox(shsurf->surface, &surf_x, &surf_y,
Giulio Camuffob8366642013-04-25 13:57:46 +03002631 &surf_width, &surf_height);
2632
Alex Wu4539b082012-03-01 12:57:46 +08002633 switch (shsurf->fullscreen.type) {
2634 case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT:
Pekka Paalanende685b82012-12-04 15:58:12 +02002635 if (surface->buffer_ref.buffer)
Jason Ekstranda7af7042013-10-12 22:38:11 -05002636 center_on_output(shsurf->view, shsurf->fullscreen_output);
Alex Wu4539b082012-03-01 12:57:46 +08002637 break;
2638 case WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE:
Rob Bradford9f3dd152013-02-12 11:53:47 +00002639 /* 1:1 mapping between surface and output dimensions */
Giulio Camuffob8366642013-04-25 13:57:46 +03002640 if (output->width == surf_width &&
2641 output->height == surf_height) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05002642 weston_view_set_position(shsurf->view,
2643 output->x - surf_x,
2644 output->y - surf_y);
Rob Bradford9f3dd152013-02-12 11:53:47 +00002645 break;
2646 }
2647
Alex Wu4539b082012-03-01 12:57:46 +08002648 matrix = &shsurf->fullscreen.transform.matrix;
2649 weston_matrix_init(matrix);
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04002650
Scott Moreau1bad5db2012-08-18 01:04:05 -06002651 output_aspect = (float) output->width /
2652 (float) output->height;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002653 /* XXX: Use surf_width and surf_height here? */
2654 surface_aspect = (float) surface->width /
2655 (float) surface->height;
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04002656 if (output_aspect < surface_aspect)
Scott Moreau1bad5db2012-08-18 01:04:05 -06002657 scale = (float) output->width /
Giulio Camuffob8366642013-04-25 13:57:46 +03002658 (float) surf_width;
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04002659 else
Scott Moreau1bad5db2012-08-18 01:04:05 -06002660 scale = (float) output->height /
Giulio Camuffob8366642013-04-25 13:57:46 +03002661 (float) surf_height;
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04002662
Alex Wu4539b082012-03-01 12:57:46 +08002663 weston_matrix_scale(matrix, scale, scale, 1);
2664 wl_list_remove(&shsurf->fullscreen.transform.link);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002665 wl_list_insert(&shsurf->view->geometry.transformation_list,
Alex Wu4539b082012-03-01 12:57:46 +08002666 &shsurf->fullscreen.transform.link);
Giulio Camuffob8366642013-04-25 13:57:46 +03002667 x = output->x + (output->width - surf_width * scale) / 2 - surf_x;
2668 y = output->y + (output->height - surf_height * scale) / 2 - surf_y;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002669 weston_view_set_position(shsurf->view, x, y);
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04002670
Alex Wu4539b082012-03-01 12:57:46 +08002671 break;
2672 case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER:
Alex Wubd3354b2012-04-17 17:20:49 +08002673 if (shell_surface_is_top_fullscreen(shsurf)) {
Quentin Glidicc0d79ce2013-01-29 14:16:13 +01002674 struct weston_mode mode = {0,
Pekka Paalanen1fd9c0f2013-11-26 18:19:41 +01002675 surf_width * surface->buffer_viewport.scale,
2676 surf_height * surface->buffer_viewport.scale,
Alex Wubd3354b2012-04-17 17:20:49 +08002677 shsurf->fullscreen.framerate};
2678
Pekka Paalanen1fd9c0f2013-11-26 18:19:41 +01002679 if (weston_output_switch_mode(output, &mode, surface->buffer_viewport.scale,
Hardening57388e42013-09-18 23:56:36 +02002680 WESTON_MODE_SWITCH_SET_TEMPORARY) == 0) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05002681 weston_view_set_position(shsurf->view,
2682 output->x - surf_x,
2683 output->y - surf_y);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06002684 shsurf->fullscreen.black_view->surface->width = output->width;
2685 shsurf->fullscreen.black_view->surface->height = output->height;
2686 weston_view_set_position(shsurf->fullscreen.black_view,
2687 output->x - surf_x,
2688 output->y - surf_y);
Alex Wubd3354b2012-04-17 17:20:49 +08002689 break;
Alexander Larssond622ed32013-05-28 16:23:40 +02002690 } else {
Alexander Larssonf82b6ca2013-05-28 16:23:39 +02002691 restore_output_mode(output);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002692 center_on_output(shsurf->view, output);
Alexander Larssond622ed32013-05-28 16:23:40 +02002693 }
Alex Wubd3354b2012-04-17 17:20:49 +08002694 }
Alex Wu4539b082012-03-01 12:57:46 +08002695 break;
2696 case WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL:
Jason Ekstranda7af7042013-10-12 22:38:11 -05002697 center_on_output(shsurf->view, output);
Alex Wu4539b082012-03-01 12:57:46 +08002698 break;
2699 default:
2700 break;
2701 }
2702}
2703
Alex Wu4539b082012-03-01 12:57:46 +08002704static void
2705shell_map_fullscreen(struct shell_surface *shsurf)
2706{
Alex Wubd3354b2012-04-17 17:20:49 +08002707 shell_configure_fullscreen(shsurf);
Alex Wu4539b082012-03-01 12:57:46 +08002708}
2709
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04002710static void
Tiago Vignattifb2adba2013-06-12 15:43:21 -03002711set_xwayland(struct shell_surface *shsurf, int x, int y, uint32_t flags)
2712{
2713 /* XXX: using the same fields for transient type */
Rafael Antognolli03b16592013-12-03 15:35:42 -02002714 surface_clear_next_states(shsurf);
Tiago Vignattifb2adba2013-06-12 15:43:21 -03002715 shsurf->transient.x = x;
2716 shsurf->transient.y = y;
2717 shsurf->transient.flags = flags;
Philip Withnalldc4332f2013-11-25 18:01:38 +00002718
2719 shell_surface_set_parent(shsurf, NULL);
2720
Kristian Høgsbergc8f8dd82013-12-05 23:20:33 -08002721 shsurf->type = SHELL_SURFACE_XWAYLAND;
Kristian Høgsberg8bc525c2014-01-01 22:34:49 -08002722 shsurf->state_changed = true;
Tiago Vignattifb2adba2013-06-12 15:43:21 -03002723}
2724
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04002725static const struct weston_pointer_grab_interface popup_grab_interface;
Giulio Camuffo5085a752013-03-25 21:42:45 +01002726
2727static void
2728destroy_shell_seat(struct wl_listener *listener, void *data)
2729{
2730 struct shell_seat *shseat =
2731 container_of(listener,
2732 struct shell_seat, seat_destroy_listener);
2733 struct shell_surface *shsurf, *prev = NULL;
2734
2735 if (shseat->popup_grab.grab.interface == &popup_grab_interface) {
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04002736 weston_pointer_end_grab(shseat->popup_grab.grab.pointer);
Giulio Camuffo5085a752013-03-25 21:42:45 +01002737 shseat->popup_grab.client = NULL;
2738
2739 wl_list_for_each(shsurf, &shseat->popup_grab.surfaces_list, popup.grab_link) {
2740 shsurf->popup.shseat = NULL;
2741 if (prev) {
2742 wl_list_init(&prev->popup.grab_link);
2743 }
2744 prev = shsurf;
2745 }
2746 wl_list_init(&prev->popup.grab_link);
2747 }
2748
2749 wl_list_remove(&shseat->seat_destroy_listener.link);
2750 free(shseat);
2751}
2752
2753static struct shell_seat *
2754create_shell_seat(struct weston_seat *seat)
2755{
2756 struct shell_seat *shseat;
2757
2758 shseat = calloc(1, sizeof *shseat);
2759 if (!shseat) {
2760 weston_log("no memory to allocate shell seat\n");
2761 return NULL;
2762 }
2763
2764 shseat->seat = seat;
2765 wl_list_init(&shseat->popup_grab.surfaces_list);
2766
2767 shseat->seat_destroy_listener.notify = destroy_shell_seat;
2768 wl_signal_add(&seat->destroy_signal,
2769 &shseat->seat_destroy_listener);
2770
2771 return shseat;
2772}
2773
2774static struct shell_seat *
2775get_shell_seat(struct weston_seat *seat)
2776{
2777 struct wl_listener *listener;
2778
2779 listener = wl_signal_get(&seat->destroy_signal, destroy_shell_seat);
2780 if (listener == NULL)
2781 return create_shell_seat(seat);
2782
2783 return container_of(listener,
2784 struct shell_seat, seat_destroy_listener);
2785}
2786
Kristian Høgsbergb810eb52013-02-12 20:07:05 -05002787static void
Kristian Høgsberg6848c252013-05-08 22:02:59 -04002788popup_grab_focus(struct weston_pointer_grab *grab)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002789{
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04002790 struct weston_pointer *pointer = grab->pointer;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002791 struct weston_view *view;
Giulio Camuffo5085a752013-03-25 21:42:45 +01002792 struct shell_seat *shseat =
2793 container_of(grab, struct shell_seat, popup_grab.grab);
2794 struct wl_client *client = shseat->popup_grab.client;
Kristian Høgsberg6848c252013-05-08 22:02:59 -04002795 wl_fixed_t sx, sy;
2796
Jason Ekstranda7af7042013-10-12 22:38:11 -05002797 view = weston_compositor_pick_view(pointer->seat->compositor,
2798 pointer->x, pointer->y,
2799 &sx, &sy);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002800
Jason Ekstranda7af7042013-10-12 22:38:11 -05002801 if (view && view->surface->resource &&
2802 wl_resource_get_client(view->surface->resource) == client) {
2803 weston_pointer_set_focus(pointer, view, sx, sy);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002804 } else {
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04002805 weston_pointer_set_focus(pointer, NULL,
2806 wl_fixed_from_int(0),
2807 wl_fixed_from_int(0));
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002808 }
2809}
2810
2811static void
Giulio Camuffo1959ab82013-11-14 23:42:52 +01002812popup_grab_motion(struct weston_pointer_grab *grab, uint32_t time,
2813 wl_fixed_t x, wl_fixed_t y)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002814{
Kristian Høgsbergbe6403e2013-05-08 21:03:21 -04002815 struct weston_pointer *pointer = grab->pointer;
Neil Roberts96d790e2013-09-19 17:32:00 +01002816 struct wl_resource *resource;
Kristian Høgsbergbe6403e2013-05-08 21:03:21 -04002817 wl_fixed_t sx, sy;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002818
Giulio Camuffo1959ab82013-11-14 23:42:52 +01002819 weston_pointer_move(pointer, x, y);
2820
Neil Roberts96d790e2013-09-19 17:32:00 +01002821 wl_resource_for_each(resource, &pointer->focus_resource_list) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05002822 weston_view_from_global_fixed(pointer->focus,
2823 pointer->x, pointer->y,
2824 &sx, &sy);
Neil Roberts96d790e2013-09-19 17:32:00 +01002825 wl_pointer_send_motion(resource, time, sx, sy);
Kristian Høgsbergbe6403e2013-05-08 21:03:21 -04002826 }
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002827}
2828
2829static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04002830popup_grab_button(struct weston_pointer_grab *grab,
Daniel Stone4dbadb12012-05-30 16:31:51 +01002831 uint32_t time, uint32_t button, uint32_t state_w)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002832{
2833 struct wl_resource *resource;
Giulio Camuffo5085a752013-03-25 21:42:45 +01002834 struct shell_seat *shseat =
2835 container_of(grab, struct shell_seat, popup_grab.grab);
Rob Bradford880ebc72013-07-22 17:31:38 +01002836 struct wl_display *display = shseat->seat->compositor->wl_display;
Daniel Stone4dbadb12012-05-30 16:31:51 +01002837 enum wl_pointer_button_state state = state_w;
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04002838 uint32_t serial;
Neil Roberts96d790e2013-09-19 17:32:00 +01002839 struct wl_list *resource_list;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002840
Neil Roberts96d790e2013-09-19 17:32:00 +01002841 resource_list = &grab->pointer->focus_resource_list;
2842 if (!wl_list_empty(resource_list)) {
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04002843 serial = wl_display_get_serial(display);
Neil Roberts96d790e2013-09-19 17:32:00 +01002844 wl_resource_for_each(resource, resource_list) {
2845 wl_pointer_send_button(resource, serial,
2846 time, button, state);
2847 }
Daniel Stone4dbadb12012-05-30 16:31:51 +01002848 } else if (state == WL_POINTER_BUTTON_STATE_RELEASED &&
Giulio Camuffo5085a752013-03-25 21:42:45 +01002849 (shseat->popup_grab.initial_up ||
Kristian Høgsberge3148752013-05-06 23:19:49 -04002850 time - shseat->seat->pointer->grab_time > 500)) {
Kristian Høgsberg57e09072012-10-30 14:07:27 -04002851 popup_grab_end(grab->pointer);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002852 }
2853
Daniel Stone4dbadb12012-05-30 16:31:51 +01002854 if (state == WL_POINTER_BUTTON_STATE_RELEASED)
Giulio Camuffo5085a752013-03-25 21:42:45 +01002855 shseat->popup_grab.initial_up = 1;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002856}
2857
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02002858static void
2859popup_grab_cancel(struct weston_pointer_grab *grab)
2860{
2861 popup_grab_end(grab->pointer);
2862}
2863
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04002864static const struct weston_pointer_grab_interface popup_grab_interface = {
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002865 popup_grab_focus,
2866 popup_grab_motion,
2867 popup_grab_button,
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02002868 popup_grab_cancel,
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002869};
2870
2871static void
Rafael Antognollie2a34552013-12-03 15:35:45 -02002872shell_surface_send_popup_done(struct shell_surface *shsurf)
2873{
2874 if (shell_surface_is_wl_shell_surface(shsurf))
2875 wl_shell_surface_send_popup_done(shsurf->resource);
2876 else if (shell_surface_is_xdg_popup(shsurf))
2877 xdg_popup_send_popup_done(shsurf->resource,
2878 shsurf->popup.serial);
2879}
2880
2881static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04002882popup_grab_end(struct weston_pointer *pointer)
Kristian Høgsberg57e09072012-10-30 14:07:27 -04002883{
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04002884 struct weston_pointer_grab *grab = pointer->grab;
Giulio Camuffo5085a752013-03-25 21:42:45 +01002885 struct shell_seat *shseat =
2886 container_of(grab, struct shell_seat, popup_grab.grab);
2887 struct shell_surface *shsurf;
2888 struct shell_surface *prev = NULL;
Kristian Høgsberg57e09072012-10-30 14:07:27 -04002889
2890 if (pointer->grab->interface == &popup_grab_interface) {
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04002891 weston_pointer_end_grab(grab->pointer);
Giulio Camuffo5085a752013-03-25 21:42:45 +01002892 shseat->popup_grab.client = NULL;
Philipp Brüschweiler63e7be62013-04-15 21:09:54 +02002893 shseat->popup_grab.grab.interface = NULL;
2894 assert(!wl_list_empty(&shseat->popup_grab.surfaces_list));
Giulio Camuffo5085a752013-03-25 21:42:45 +01002895 /* Send the popup_done event to all the popups open */
2896 wl_list_for_each(shsurf, &shseat->popup_grab.surfaces_list, popup.grab_link) {
Rafael Antognollie2a34552013-12-03 15:35:45 -02002897 shell_surface_send_popup_done(shsurf);
Giulio Camuffo5085a752013-03-25 21:42:45 +01002898 shsurf->popup.shseat = NULL;
2899 if (prev) {
2900 wl_list_init(&prev->popup.grab_link);
2901 }
2902 prev = shsurf;
2903 }
2904 wl_list_init(&prev->popup.grab_link);
2905 wl_list_init(&shseat->popup_grab.surfaces_list);
2906 }
2907}
2908
2909static void
2910add_popup_grab(struct shell_surface *shsurf, struct shell_seat *shseat)
2911{
Kristian Høgsberge3148752013-05-06 23:19:49 -04002912 struct weston_seat *seat = shseat->seat;
Giulio Camuffo5085a752013-03-25 21:42:45 +01002913
2914 if (wl_list_empty(&shseat->popup_grab.surfaces_list)) {
Jason Ekstrand651f00e2013-06-14 10:07:54 -05002915 shseat->popup_grab.client = wl_resource_get_client(shsurf->resource);
Giulio Camuffo5085a752013-03-25 21:42:45 +01002916 shseat->popup_grab.grab.interface = &popup_grab_interface;
Giulio Camuffo1b4b61a2013-03-27 18:05:26 +01002917 /* We must make sure here that this popup was opened after
2918 * a mouse press, and not just by moving around with other
2919 * popups already open. */
Kristian Høgsberge3148752013-05-06 23:19:49 -04002920 if (shseat->seat->pointer->button_count > 0)
Giulio Camuffo1b4b61a2013-03-27 18:05:26 +01002921 shseat->popup_grab.initial_up = 0;
Giulio Camuffo5085a752013-03-25 21:42:45 +01002922
Rob Bradforddfe31052013-06-26 19:49:11 +01002923 wl_list_insert(&shseat->popup_grab.surfaces_list, &shsurf->popup.grab_link);
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04002924 weston_pointer_start_grab(seat->pointer, &shseat->popup_grab.grab);
Rob Bradforddfe31052013-06-26 19:49:11 +01002925 } else {
2926 wl_list_insert(&shseat->popup_grab.surfaces_list, &shsurf->popup.grab_link);
Giulio Camuffo5085a752013-03-25 21:42:45 +01002927 }
Giulio Camuffo5085a752013-03-25 21:42:45 +01002928}
2929
2930static void
2931remove_popup_grab(struct shell_surface *shsurf)
2932{
2933 struct shell_seat *shseat = shsurf->popup.shseat;
2934
2935 wl_list_remove(&shsurf->popup.grab_link);
2936 wl_list_init(&shsurf->popup.grab_link);
2937 if (wl_list_empty(&shseat->popup_grab.surfaces_list)) {
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04002938 weston_pointer_end_grab(shseat->popup_grab.grab.pointer);
Philipp Brüschweiler63e7be62013-04-15 21:09:54 +02002939 shseat->popup_grab.grab.interface = NULL;
Kristian Høgsberg57e09072012-10-30 14:07:27 -04002940 }
2941}
2942
2943static void
Kristian Høgsberg3730f362012-04-13 12:40:07 -04002944shell_map_popup(struct shell_surface *shsurf)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002945{
Giulio Camuffo5085a752013-03-25 21:42:45 +01002946 struct shell_seat *shseat = shsurf->popup.shseat;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002947 struct weston_view *parent_view = get_default_view(shsurf->parent);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002948
Jason Ekstranda7af7042013-10-12 22:38:11 -05002949 shsurf->surface->output = parent_view->output;
2950 shsurf->view->output = parent_view->output;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002951
Jason Ekstranda7af7042013-10-12 22:38:11 -05002952 weston_view_set_transform_parent(shsurf->view, parent_view);
2953 weston_view_set_position(shsurf->view, shsurf->popup.x, shsurf->popup.y);
2954 weston_view_update_transform(shsurf->view);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002955
Kristian Høgsberge3148752013-05-06 23:19:49 -04002956 if (shseat->seat->pointer->grab_serial == shsurf->popup.serial) {
Giulio Camuffo5085a752013-03-25 21:42:45 +01002957 add_popup_grab(shsurf, shseat);
Kristian Høgsberg3730f362012-04-13 12:40:07 -04002958 } else {
Rafael Antognollie2a34552013-12-03 15:35:45 -02002959 shell_surface_send_popup_done(shsurf);
Giulio Camuffo5085a752013-03-25 21:42:45 +01002960 shseat->popup_grab.client = NULL;
Kristian Høgsberg3730f362012-04-13 12:40:07 -04002961 }
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002962}
2963
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002964static const struct wl_shell_surface_interface shell_surface_implementation = {
Scott Moreauff1db4a2012-04-17 19:06:18 -06002965 shell_surface_pong,
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002966 shell_surface_move,
2967 shell_surface_resize,
2968 shell_surface_set_toplevel,
2969 shell_surface_set_transient,
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002970 shell_surface_set_fullscreen,
Juan Zhao96879df2012-02-07 08:45:41 +08002971 shell_surface_set_popup,
Kristian Høgsberge7afd912012-05-02 09:47:44 -04002972 shell_surface_set_maximized,
2973 shell_surface_set_title,
2974 shell_surface_set_class
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002975};
2976
2977static void
Tiago Vignattibc052c92012-04-19 16:18:18 +03002978destroy_shell_surface(struct shell_surface *shsurf)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002979{
Kristian Høgsberg9046d242014-01-10 00:25:30 -08002980 struct shell_surface *child, *next;
2981
Jason Ekstrand651f00e2013-06-14 10:07:54 -05002982 wl_signal_emit(&shsurf->destroy_signal, shsurf);
2983
Giulio Camuffo5085a752013-03-25 21:42:45 +01002984 if (!wl_list_empty(&shsurf->popup.grab_link)) {
2985 remove_popup_grab(shsurf);
2986 }
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002987
Alex Wubd3354b2012-04-17 17:20:49 +08002988 if (shsurf->fullscreen.type == WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER &&
Alexander Larssonf82b6ca2013-05-28 16:23:39 +02002989 shell_surface_is_top_fullscreen(shsurf))
2990 restore_output_mode (shsurf->fullscreen_output);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002991
Jason Ekstranda7af7042013-10-12 22:38:11 -05002992 if (shsurf->fullscreen.black_view)
2993 weston_surface_destroy(shsurf->fullscreen.black_view->surface);
Alex Wuaa08e2d2012-03-05 11:01:40 +08002994
Alex Wubd3354b2012-04-17 17:20:49 +08002995 /* As destroy_resource() use wl_list_for_each_safe(),
2996 * we can always remove the listener.
2997 */
2998 wl_list_remove(&shsurf->surface_destroy_listener.link);
2999 shsurf->surface->configure = NULL;
Scott Moreau976a0502013-03-07 10:15:17 -07003000 free(shsurf->title);
Alex Wubd3354b2012-04-17 17:20:49 +08003001
Jason Ekstranda7af7042013-10-12 22:38:11 -05003002 weston_view_destroy(shsurf->view);
3003
Philip Withnall648a4dd2013-11-25 18:01:44 +00003004 wl_list_remove(&shsurf->children_link);
Emilio Pozuelo Monfortadaa20c2014-01-28 13:54:16 +01003005 wl_list_for_each_safe(child, next, &shsurf->children_list, children_link)
3006 shell_surface_set_parent(child, NULL);
Philip Withnall648a4dd2013-11-25 18:01:44 +00003007
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003008 wl_list_remove(&shsurf->link);
3009 free(shsurf);
3010}
3011
3012static void
Tiago Vignattibc052c92012-04-19 16:18:18 +03003013shell_destroy_shell_surface(struct wl_resource *resource)
3014{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05003015 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
Tiago Vignattibc052c92012-04-19 16:18:18 +03003016
3017 destroy_shell_surface(shsurf);
3018}
3019
3020static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04003021shell_handle_surface_destroy(struct wl_listener *listener, void *data)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003022{
3023 struct shell_surface *shsurf = container_of(listener,
3024 struct shell_surface,
3025 surface_destroy_listener);
3026
Jason Ekstrand651f00e2013-06-14 10:07:54 -05003027 if (shsurf->resource)
3028 wl_resource_destroy(shsurf->resource);
3029 else
Tiago Vignattibc052c92012-04-19 16:18:18 +03003030 destroy_shell_surface(shsurf);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003031}
3032
Kristian Høgsbergd8134452012-06-21 12:49:02 -04003033static void
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06003034shell_surface_configure(struct weston_surface *, int32_t, int32_t);
Kristian Høgsbergd8134452012-06-21 12:49:02 -04003035
Kristian Høgsberg1ef23132013-12-04 00:20:01 -08003036struct shell_surface *
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05003037get_shell_surface(struct weston_surface *surface)
Pekka Paalanenec2b32f2011-11-28 15:12:34 +02003038{
Kristian Høgsbergd8134452012-06-21 12:49:02 -04003039 if (surface->configure == shell_surface_configure)
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01003040 return surface->configure_private;
Kristian Høgsbergd8134452012-06-21 12:49:02 -04003041 else
3042 return NULL;
Pekka Paalanenec2b32f2011-11-28 15:12:34 +02003043}
3044
Rafael Antognollie2a34552013-12-03 15:35:45 -02003045static struct shell_surface *
3046create_common_surface(void *shell, struct weston_surface *surface,
3047 const struct weston_shell_client *client)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003048{
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003049 struct shell_surface *shsurf;
3050
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03003051 if (surface->configure) {
Martin Minarik6d118362012-06-07 18:01:59 +02003052 weston_log("surface->configure already set\n");
Kristian Høgsberg45ba8692012-05-21 14:27:33 -04003053 return NULL;
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03003054 }
3055
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003056 shsurf = calloc(1, sizeof *shsurf);
3057 if (!shsurf) {
Martin Minarik6d118362012-06-07 18:01:59 +02003058 weston_log("no memory to allocate shell surface\n");
Kristian Høgsberg45ba8692012-05-21 14:27:33 -04003059 return NULL;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003060 }
3061
Jason Ekstranda7af7042013-10-12 22:38:11 -05003062 shsurf->view = weston_view_create(surface);
3063 if (!shsurf->view) {
3064 weston_log("no memory to allocate shell surface\n");
3065 free(shsurf);
3066 return NULL;
3067 }
3068
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03003069 surface->configure = shell_surface_configure;
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01003070 surface->configure_private = shsurf;
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03003071
Tiago Vignattibc052c92012-04-19 16:18:18 +03003072 shsurf->shell = (struct desktop_shell *) shell;
Scott Moreauff1db4a2012-04-17 19:06:18 -06003073 shsurf->unresponsive = 0;
Alex Wu4539b082012-03-01 12:57:46 +08003074 shsurf->saved_position_valid = false;
Rafael Antognolli3c4e3f72013-12-03 15:35:46 -02003075 shsurf->saved_size_valid = false;
Alex Wu7bcb8bd2012-04-27 09:07:24 +08003076 shsurf->saved_rotation_valid = false;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003077 shsurf->surface = surface;
Alex Wu4539b082012-03-01 12:57:46 +08003078 shsurf->fullscreen.type = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT;
3079 shsurf->fullscreen.framerate = 0;
Jason Ekstranda7af7042013-10-12 22:38:11 -05003080 shsurf->fullscreen.black_view = NULL;
Alex Wu4539b082012-03-01 12:57:46 +08003081 wl_list_init(&shsurf->fullscreen.transform.link);
3082
Jason Ekstrand651f00e2013-06-14 10:07:54 -05003083 wl_signal_init(&shsurf->destroy_signal);
Kristian Høgsberg27e30522012-04-11 23:18:23 -04003084 shsurf->surface_destroy_listener.notify = shell_handle_surface_destroy;
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05003085 wl_signal_add(&surface->destroy_signal,
Kristian Høgsberg27e30522012-04-11 23:18:23 -04003086 &shsurf->surface_destroy_listener);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003087
3088 /* init link so its safe to always remove it in destroy_shell_surface */
3089 wl_list_init(&shsurf->link);
Giulio Camuffo5085a752013-03-25 21:42:45 +01003090 wl_list_init(&shsurf->popup.grab_link);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003091
Pekka Paalanen460099f2012-01-20 16:48:25 +02003092 /* empty when not in use */
3093 wl_list_init(&shsurf->rotation.transform.link);
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05003094 weston_matrix_init(&shsurf->rotation.rotation);
Pekka Paalanen460099f2012-01-20 16:48:25 +02003095
Jonas Ådahl62fcd042012-06-13 00:01:23 +02003096 wl_list_init(&shsurf->workspace_transform.link);
3097
Philip Withnall648a4dd2013-11-25 18:01:44 +00003098 wl_list_init(&shsurf->children_link);
3099 wl_list_init(&shsurf->children_list);
3100 shsurf->parent = NULL;
3101
Pekka Paalanen98262232011-12-01 10:42:22 +02003102 shsurf->type = SHELL_SURFACE_NONE;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003103
Kristian Høgsberga61ca062012-05-22 16:05:52 -04003104 shsurf->client = client;
3105
Kristian Høgsberg45ba8692012-05-21 14:27:33 -04003106 return shsurf;
Tiago Vignattibc052c92012-04-19 16:18:18 +03003107}
3108
Rafael Antognollie2a34552013-12-03 15:35:45 -02003109static struct shell_surface *
3110create_shell_surface(void *shell, struct weston_surface *surface,
3111 const struct weston_shell_client *client)
3112{
Kristian Høgsbergc8f8dd82013-12-05 23:20:33 -08003113 return create_common_surface(shell, surface, client);
Rafael Antognollie2a34552013-12-03 15:35:45 -02003114}
3115
Jason Ekstranda7af7042013-10-12 22:38:11 -05003116static struct weston_view *
3117get_primary_view(void *shell, struct shell_surface *shsurf)
3118{
3119 return shsurf->view;
3120}
3121
Tiago Vignattibc052c92012-04-19 16:18:18 +03003122static void
3123shell_get_shell_surface(struct wl_client *client,
3124 struct wl_resource *resource,
3125 uint32_t id,
3126 struct wl_resource *surface_resource)
3127{
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05003128 struct weston_surface *surface =
3129 wl_resource_get_user_data(surface_resource);
Jason Ekstrand651f00e2013-06-14 10:07:54 -05003130 struct desktop_shell *shell = wl_resource_get_user_data(resource);
Tiago Vignattibc052c92012-04-19 16:18:18 +03003131 struct shell_surface *shsurf;
3132
3133 if (get_shell_surface(surface)) {
3134 wl_resource_post_error(surface_resource,
Kristian Høgsberg9540ea62012-05-21 14:28:57 -04003135 WL_DISPLAY_ERROR_INVALID_OBJECT,
3136 "desktop_shell::get_shell_surface already requested");
Tiago Vignattibc052c92012-04-19 16:18:18 +03003137 return;
3138 }
3139
Kristian Høgsberga61ca062012-05-22 16:05:52 -04003140 shsurf = create_shell_surface(shell, surface, &shell_client);
Kristian Høgsberg9540ea62012-05-21 14:28:57 -04003141 if (!shsurf) {
3142 wl_resource_post_error(surface_resource,
3143 WL_DISPLAY_ERROR_INVALID_OBJECT,
3144 "surface->configure already set");
3145 return;
3146 }
Tiago Vignattibc052c92012-04-19 16:18:18 +03003147
Jason Ekstranda85118c2013-06-27 20:17:02 -05003148 shsurf->resource =
3149 wl_resource_create(client,
3150 &wl_shell_surface_interface, 1, id);
3151 wl_resource_set_implementation(shsurf->resource,
3152 &shell_surface_implementation,
3153 shsurf, shell_destroy_shell_surface);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003154}
3155
Rafael Antognollie2a34552013-12-03 15:35:45 -02003156static bool
3157shell_surface_is_wl_shell_surface(struct shell_surface *shsurf)
3158{
Kristian Høgsberg0b7d9952014-02-03 15:50:38 -08003159 /* A shell surface without a resource is created from xwayland
3160 * and is considered a wl_shell surface for now. */
3161
3162 return shsurf->resource == NULL ||
3163 wl_resource_instance_of(shsurf->resource,
3164 &wl_shell_surface_interface,
3165 &shell_surface_implementation);
Rafael Antognollie2a34552013-12-03 15:35:45 -02003166}
3167
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003168static const struct wl_shell_interface shell_implementation = {
Pekka Paalanen46229672011-11-29 15:49:31 +02003169 shell_get_shell_surface
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05003170};
3171
Rafael Antognollie2a34552013-12-03 15:35:45 -02003172/****************************
3173 * xdg-shell implementation */
3174
3175static void
3176xdg_surface_destroy(struct wl_client *client,
3177 struct wl_resource *resource)
3178{
3179 wl_resource_destroy(resource);
3180}
3181
3182static void
Jasper St. Pierre74073452014-02-01 18:36:41 -05003183xdg_surface_set_margin(struct wl_client *client,
3184 struct wl_resource *resource,
3185 int32_t left,
3186 int32_t right,
3187 int32_t top,
3188 int32_t bottom)
3189{
3190 /* Do nothing, Weston doesn't try to constrain or place
3191 * surfaces in any special manner... */
3192}
3193
3194static void
Rafael Antognollie2a34552013-12-03 15:35:45 -02003195xdg_surface_set_app_id(struct wl_client *client,
3196 struct wl_resource *resource,
3197 const char *app_id)
3198{
3199 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
3200
3201 free(shsurf->class);
3202 shsurf->class = strdup(app_id);
3203}
3204
3205static void
3206xdg_surface_set_title(struct wl_client *client,
3207 struct wl_resource *resource, const char *title)
3208{
3209 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
3210
3211 set_title(shsurf, title);
3212}
3213
3214static void
3215xdg_surface_move(struct wl_client *client, struct wl_resource *resource,
3216 struct wl_resource *seat_resource, uint32_t serial)
3217{
3218 common_surface_move(resource, seat_resource, serial);
3219}
3220
3221static void
3222xdg_surface_resize(struct wl_client *client, struct wl_resource *resource,
3223 struct wl_resource *seat_resource, uint32_t serial,
3224 uint32_t edges)
3225{
3226 common_surface_resize(resource, seat_resource, serial, edges);
3227}
3228
3229static void
3230xdg_surface_set_output(struct wl_client *client,
3231 struct wl_resource *resource,
3232 struct wl_resource *output_resource)
3233{
3234 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
3235 struct weston_output *output;
3236
3237 if (output_resource)
3238 output = wl_resource_get_user_data(output_resource);
3239 else
3240 output = NULL;
3241
Rafael Antognolli65f98d82013-12-03 15:35:47 -02003242 shsurf->recommended_output = output;
Rafael Antognollie2a34552013-12-03 15:35:45 -02003243}
3244
3245static void
3246xdg_surface_set_fullscreen(struct wl_client *client,
3247 struct wl_resource *resource)
3248{
3249 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
3250
3251 if (shsurf->type != SHELL_SURFACE_TOPLEVEL)
3252 return;
3253
Kristian Høgsberge960b3f2013-12-05 22:04:42 -08003254 if (!shsurf->next_state.fullscreen)
Rafael Antognollie2a34552013-12-03 15:35:45 -02003255 set_fullscreen(shsurf,
3256 WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
Rafael Antognolli65f98d82013-12-03 15:35:47 -02003257 0, shsurf->recommended_output);
Rafael Antognollie2a34552013-12-03 15:35:45 -02003258}
3259
3260static void
3261xdg_surface_unset_fullscreen(struct wl_client *client,
3262 struct wl_resource *resource)
3263{
3264 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
Rafael Antognolli3c4e3f72013-12-03 15:35:46 -02003265 int32_t width, height;
Rafael Antognollie2a34552013-12-03 15:35:45 -02003266
3267 if (shsurf->type != SHELL_SURFACE_TOPLEVEL)
3268 return;
3269
Rafael Antognolli3c4e3f72013-12-03 15:35:46 -02003270 if (!shsurf->next_state.fullscreen)
3271 return;
3272
Rafael Antognollie2a34552013-12-03 15:35:45 -02003273 shsurf->next_state.fullscreen = false;
3274 shsurf->state_changed = true;
Rafael Antognolli3c4e3f72013-12-03 15:35:46 -02003275
3276 if (shsurf->saved_size_valid) {
3277 width = shsurf->saved_width;
3278 height = shsurf->saved_height;
3279 shsurf->saved_size_valid = false;
3280 } else {
3281 width = shsurf->surface->width;
3282 height = shsurf->surface->height;
3283 }
3284
3285 shsurf->client->send_configure(shsurf->surface, 0, width, height);
Rafael Antognollie2a34552013-12-03 15:35:45 -02003286}
3287
3288static void
3289xdg_surface_set_maximized(struct wl_client *client,
3290 struct wl_resource *resource)
3291{
3292 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
3293
3294 if (shsurf->type != SHELL_SURFACE_TOPLEVEL)
3295 return;
3296
Kristian Høgsbergc2745b12013-12-05 22:00:40 -08003297 if (!shsurf->next_state.maximized)
Rafael Antognolli65f98d82013-12-03 15:35:47 -02003298 set_maximized(shsurf, NULL);
Rafael Antognollie2a34552013-12-03 15:35:45 -02003299}
3300
3301static void
3302xdg_surface_unset_maximized(struct wl_client *client,
3303 struct wl_resource *resource)
3304{
3305 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
Rafael Antognolli3c4e3f72013-12-03 15:35:46 -02003306 int32_t width, height;
Rafael Antognollie2a34552013-12-03 15:35:45 -02003307
3308 if (shsurf->type != SHELL_SURFACE_TOPLEVEL)
3309 return;
3310
Rafael Antognolli3c4e3f72013-12-03 15:35:46 -02003311 if (!shsurf->next_state.maximized)
3312 return;
3313
Rafael Antognollie2a34552013-12-03 15:35:45 -02003314 shsurf->next_state.maximized = false;
3315 shsurf->state_changed = true;
Rafael Antognolli3c4e3f72013-12-03 15:35:46 -02003316
3317 if (shsurf->saved_size_valid) {
3318 width = shsurf->saved_width;
3319 height = shsurf->saved_height;
3320 shsurf->saved_size_valid = false;
3321 } else {
3322 width = shsurf->surface->width;
3323 height = shsurf->surface->height;
3324 }
3325
3326 shsurf->client->send_configure(shsurf->surface, 0, width, height);
Rafael Antognollie2a34552013-12-03 15:35:45 -02003327}
3328
3329static const struct xdg_surface_interface xdg_surface_implementation = {
3330 xdg_surface_destroy,
3331 xdg_surface_set_transient_for,
Jasper St. Pierre74073452014-02-01 18:36:41 -05003332 xdg_surface_set_margin,
Rafael Antognollie2a34552013-12-03 15:35:45 -02003333 xdg_surface_set_title,
3334 xdg_surface_set_app_id,
Rafael Antognollie2a34552013-12-03 15:35:45 -02003335 xdg_surface_move,
3336 xdg_surface_resize,
3337 xdg_surface_set_output,
3338 xdg_surface_set_fullscreen,
3339 xdg_surface_unset_fullscreen,
3340 xdg_surface_set_maximized,
3341 xdg_surface_unset_maximized,
3342 NULL /* set_minimized */
3343};
3344
3345static void
3346xdg_send_configure(struct weston_surface *surface,
3347 uint32_t edges, int32_t width, int32_t height)
3348{
3349 struct shell_surface *shsurf = get_shell_surface(surface);
3350
U. Artie Eoffcf5737a2014-01-17 10:08:25 -08003351 assert(shsurf);
3352
Kristian Høgsberg44cd1962014-02-05 21:36:04 -08003353 xdg_surface_send_configure(shsurf->resource, width, height);
Rafael Antognollie2a34552013-12-03 15:35:45 -02003354}
3355
3356static const struct weston_shell_client xdg_client = {
3357 xdg_send_configure
3358};
3359
3360static void
3361xdg_use_unstable_version(struct wl_client *client,
3362 struct wl_resource *resource,
3363 int32_t version)
3364{
3365 if (version > 1) {
3366 wl_resource_post_error(resource,
3367 1,
3368 "xdg-shell:: version not implemented yet.");
3369 return;
3370 }
3371}
3372
3373static struct shell_surface *
3374create_xdg_surface(void *shell, struct weston_surface *surface,
3375 const struct weston_shell_client *client)
3376{
3377 struct shell_surface *shsurf;
Rafael Antognollie2a34552013-12-03 15:35:45 -02003378
Kristian Høgsbergc8f8dd82013-12-05 23:20:33 -08003379 shsurf = create_common_surface(shell, surface, client);
3380 shsurf->type = SHELL_SURFACE_TOPLEVEL;
Rafael Antognollie2a34552013-12-03 15:35:45 -02003381
3382 return shsurf;
3383}
3384
3385static void
3386xdg_get_xdg_surface(struct wl_client *client,
3387 struct wl_resource *resource,
3388 uint32_t id,
3389 struct wl_resource *surface_resource)
3390{
3391 struct weston_surface *surface =
3392 wl_resource_get_user_data(surface_resource);
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08003393 struct shell_client *sc = wl_resource_get_user_data(resource);
3394 struct desktop_shell *shell = sc->shell;
Rafael Antognollie2a34552013-12-03 15:35:45 -02003395 struct shell_surface *shsurf;
3396
3397 if (get_shell_surface(surface)) {
3398 wl_resource_post_error(surface_resource,
3399 WL_DISPLAY_ERROR_INVALID_OBJECT,
3400 "desktop_shell::get_shell_surface already requested");
3401 return;
3402 }
3403
3404 shsurf = create_xdg_surface(shell, surface, &xdg_client);
3405 if (!shsurf) {
3406 wl_resource_post_error(surface_resource,
3407 WL_DISPLAY_ERROR_INVALID_OBJECT,
3408 "surface->configure already set");
3409 return;
3410 }
3411
3412 shsurf->resource =
3413 wl_resource_create(client,
3414 &xdg_surface_interface, 1, id);
3415 wl_resource_set_implementation(shsurf->resource,
3416 &xdg_surface_implementation,
3417 shsurf, shell_destroy_shell_surface);
3418}
3419
3420static bool
3421shell_surface_is_xdg_surface(struct shell_surface *shsurf)
3422{
Kristian Høgsberg0b7d9952014-02-03 15:50:38 -08003423 return shsurf->resource &&
3424 wl_resource_instance_of(shsurf->resource,
3425 &xdg_surface_interface,
3426 &xdg_surface_implementation);
Rafael Antognollie2a34552013-12-03 15:35:45 -02003427}
3428
3429/* xdg-popup implementation */
3430
3431static void
3432xdg_popup_destroy(struct wl_client *client,
3433 struct wl_resource *resource)
3434{
3435 wl_resource_destroy(resource);
3436}
3437
Rafael Antognollie2a34552013-12-03 15:35:45 -02003438static const struct xdg_popup_interface xdg_popup_implementation = {
3439 xdg_popup_destroy,
Rafael Antognollie2a34552013-12-03 15:35:45 -02003440};
3441
3442static void
3443xdg_popup_send_configure(struct weston_surface *surface,
3444 uint32_t edges, int32_t width, int32_t height)
3445{
3446}
3447
3448static const struct weston_shell_client xdg_popup_client = {
3449 xdg_popup_send_configure
3450};
3451
3452static struct shell_surface *
3453create_xdg_popup(void *shell, struct weston_surface *surface,
3454 const struct weston_shell_client *client,
3455 struct weston_surface *parent,
3456 struct shell_seat *seat,
3457 uint32_t serial,
3458 int32_t x, int32_t y)
3459{
3460 struct shell_surface *shsurf;
Rafael Antognollie2a34552013-12-03 15:35:45 -02003461
Kristian Høgsbergc8f8dd82013-12-05 23:20:33 -08003462 shsurf = create_common_surface(shell, surface, client);
3463 shsurf->type = SHELL_SURFACE_POPUP;
Rafael Antognollie2a34552013-12-03 15:35:45 -02003464 shsurf->popup.shseat = seat;
3465 shsurf->popup.serial = serial;
3466 shsurf->popup.x = x;
3467 shsurf->popup.y = y;
3468 shell_surface_set_parent(shsurf, parent);
3469
3470 return shsurf;
3471}
3472
3473static void
3474xdg_get_xdg_popup(struct wl_client *client,
3475 struct wl_resource *resource,
3476 uint32_t id,
3477 struct wl_resource *surface_resource,
3478 struct wl_resource *parent_resource,
3479 struct wl_resource *seat_resource,
3480 uint32_t serial,
3481 int32_t x, int32_t y, uint32_t flags)
3482{
3483 struct weston_surface *surface =
3484 wl_resource_get_user_data(surface_resource);
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08003485 struct shell_client *sc = wl_resource_get_user_data(resource);
3486 struct desktop_shell *shell = sc->shell;
Rafael Antognollie2a34552013-12-03 15:35:45 -02003487 struct shell_surface *shsurf;
3488 struct weston_surface *parent;
3489 struct shell_seat *seat;
3490
3491 if (get_shell_surface(surface)) {
3492 wl_resource_post_error(surface_resource,
3493 WL_DISPLAY_ERROR_INVALID_OBJECT,
3494 "desktop_shell::get_shell_surface already requested");
3495 return;
3496 }
3497
3498 if (!parent_resource) {
3499 wl_resource_post_error(surface_resource,
3500 WL_DISPLAY_ERROR_INVALID_OBJECT,
3501 "xdg_shell::get_xdg_popup requires a parent shell surface");
3502 }
3503
3504 parent = wl_resource_get_user_data(parent_resource);
3505 seat = get_shell_seat(wl_resource_get_user_data(seat_resource));;
3506
3507 shsurf = create_xdg_popup(shell, surface, &xdg_popup_client,
3508 parent, seat, serial, x, y);
3509 if (!shsurf) {
3510 wl_resource_post_error(surface_resource,
3511 WL_DISPLAY_ERROR_INVALID_OBJECT,
3512 "surface->configure already set");
3513 return;
3514 }
3515
3516 shsurf->resource =
3517 wl_resource_create(client,
3518 &xdg_popup_interface, 1, id);
3519 wl_resource_set_implementation(shsurf->resource,
3520 &xdg_popup_implementation,
3521 shsurf, shell_destroy_shell_surface);
3522}
3523
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08003524static void
3525xdg_pong(struct wl_client *client,
3526 struct wl_resource *resource, uint32_t serial)
3527{
3528 struct shell_client *sc = wl_resource_get_user_data(resource);
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08003529
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08003530 shell_client_pong(sc, serial);
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08003531}
3532
Rafael Antognollie2a34552013-12-03 15:35:45 -02003533static bool
3534shell_surface_is_xdg_popup(struct shell_surface *shsurf)
3535{
3536 return wl_resource_instance_of(shsurf->resource,
3537 &xdg_popup_interface,
3538 &xdg_popup_implementation);
3539}
3540
3541static const struct xdg_shell_interface xdg_implementation = {
3542 xdg_use_unstable_version,
3543 xdg_get_xdg_surface,
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08003544 xdg_get_xdg_popup,
3545 xdg_pong
Rafael Antognollie2a34552013-12-03 15:35:45 -02003546};
3547
3548static int
3549xdg_shell_unversioned_dispatch(const void *implementation,
3550 void *_target, uint32_t opcode,
3551 const struct wl_message *message,
3552 union wl_argument *args)
3553{
3554 struct wl_resource *resource = _target;
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08003555 struct shell_client *sc = wl_resource_get_user_data(resource);
Rafael Antognollie2a34552013-12-03 15:35:45 -02003556
3557 if (opcode != 0) {
3558 wl_resource_post_error(resource,
3559 WL_DISPLAY_ERROR_INVALID_OBJECT,
3560 "must call use_unstable_version first");
3561 return 0;
3562 }
3563
Kristian Høgsberg239902b2014-02-11 13:50:08 -08003564#define XDG_SERVER_VERSION 2
Rafael Antognollie2a34552013-12-03 15:35:45 -02003565
Kristian Høgsberg8d344a02013-12-08 22:27:11 -08003566 static_assert(XDG_SERVER_VERSION == XDG_SHELL_VERSION_CURRENT,
3567 "shell implementation doesn't match protocol version");
3568
Rafael Antognollie2a34552013-12-03 15:35:45 -02003569 if (args[0].i != XDG_SERVER_VERSION) {
3570 wl_resource_post_error(resource,
3571 WL_DISPLAY_ERROR_INVALID_OBJECT,
3572 "incompatible version, server is %d "
3573 "client wants %d",
3574 XDG_SERVER_VERSION, args[0].i);
3575 return 0;
3576 }
3577
3578 wl_resource_set_implementation(resource, &xdg_implementation,
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08003579 sc, NULL);
Rafael Antognollie2a34552013-12-03 15:35:45 -02003580
3581 return 1;
3582}
3583
3584/* end of xdg-shell implementation */
3585/***********************************/
3586
Kristian Høgsberg07937562011-04-12 17:25:42 -04003587static void
Ander Conselvan de Oliveira859e8852013-02-21 18:35:21 +02003588shell_fade(struct desktop_shell *shell, enum fade_type type);
3589
3590static int
3591screensaver_timeout(void *data)
3592{
3593 struct desktop_shell *shell = data;
3594
3595 shell_fade(shell, FADE_OUT);
3596
3597 return 1;
3598}
3599
3600static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05003601handle_screensaver_sigchld(struct weston_process *proc, int status)
Pekka Paalanen18027e52011-12-02 16:31:49 +02003602{
Ander Conselvan de Oliveira18639f82013-02-15 18:44:19 +02003603 struct desktop_shell *shell =
3604 container_of(proc, struct desktop_shell, screensaver.process);
Ander Conselvan de Oliveira18639f82013-02-15 18:44:19 +02003605
Pekka Paalanen18027e52011-12-02 16:31:49 +02003606 proc->pid = 0;
Ander Conselvan de Oliveira18639f82013-02-15 18:44:19 +02003607
3608 if (shell->locked)
Ander Conselvan de Oliveirab17537e2013-02-22 14:16:18 +02003609 weston_compositor_sleep(shell->compositor);
Pekka Paalanen18027e52011-12-02 16:31:49 +02003610}
3611
3612static void
Tiago Vignattibe143262012-04-16 17:31:41 +03003613launch_screensaver(struct desktop_shell *shell)
Pekka Paalanen77346a62011-11-30 16:26:35 +02003614{
3615 if (shell->screensaver.binding)
3616 return;
3617
Ander Conselvan de Oliveiradda9d782013-02-22 14:16:19 +02003618 if (!shell->screensaver.path) {
3619 weston_compositor_sleep(shell->compositor);
Pekka Paalanene955f1e2011-12-07 11:49:52 +02003620 return;
Ander Conselvan de Oliveiradda9d782013-02-22 14:16:19 +02003621 }
Pekka Paalanene955f1e2011-12-07 11:49:52 +02003622
Kristian Høgsberg32bed572012-03-01 17:11:36 -05003623 if (shell->screensaver.process.pid != 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02003624 weston_log("old screensaver still running\n");
Kristian Høgsberg32bed572012-03-01 17:11:36 -05003625 return;
3626 }
3627
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05003628 weston_client_launch(shell->compositor,
Pekka Paalanen18027e52011-12-02 16:31:49 +02003629 &shell->screensaver.process,
Pekka Paalanene955f1e2011-12-07 11:49:52 +02003630 shell->screensaver.path,
Pekka Paalanen18027e52011-12-02 16:31:49 +02003631 handle_screensaver_sigchld);
Pekka Paalanen77346a62011-11-30 16:26:35 +02003632}
3633
3634static void
Tiago Vignattibe143262012-04-16 17:31:41 +03003635terminate_screensaver(struct desktop_shell *shell)
Pekka Paalanen77346a62011-11-30 16:26:35 +02003636{
Pekka Paalanen18027e52011-12-02 16:31:49 +02003637 if (shell->screensaver.process.pid == 0)
3638 return;
3639
3640 kill(shell->screensaver.process.pid, SIGTERM);
Pekka Paalanen77346a62011-11-30 16:26:35 +02003641}
3642
3643static void
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06003644configure_static_view(struct weston_view *ev, struct weston_layer *layer)
Kristian Høgsberg962342c2012-06-26 16:29:50 -04003645{
Jason Ekstranda7af7042013-10-12 22:38:11 -05003646 struct weston_view *v, *next;
Kristian Høgsberg962342c2012-06-26 16:29:50 -04003647
Jason Ekstranda7af7042013-10-12 22:38:11 -05003648 wl_list_for_each_safe(v, next, &layer->view_list, layer_link) {
3649 if (v->output == ev->output && v != ev) {
3650 weston_view_unmap(v);
3651 v->surface->configure = NULL;
Kristian Høgsberg962342c2012-06-26 16:29:50 -04003652 }
3653 }
3654
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06003655 weston_view_set_position(ev, ev->output->x, ev->output->y);
Kristian Høgsberg962342c2012-06-26 16:29:50 -04003656
Jason Ekstranda7af7042013-10-12 22:38:11 -05003657 if (wl_list_empty(&ev->layer_link)) {
3658 wl_list_insert(&layer->view_list, &ev->layer_link);
3659 weston_compositor_schedule_repaint(ev->surface->compositor);
Kristian Høgsberg962342c2012-06-26 16:29:50 -04003660 }
3661}
3662
3663static void
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06003664background_configure(struct weston_surface *es, int32_t sx, int32_t sy)
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04003665{
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01003666 struct desktop_shell *shell = es->configure_private;
Jason Ekstranda7af7042013-10-12 22:38:11 -05003667 struct weston_view *view;
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04003668
Jason Ekstranda7af7042013-10-12 22:38:11 -05003669 view = container_of(es->views.next, struct weston_view, surface_link);
3670
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06003671 configure_static_view(view, &shell->background_layer);
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04003672}
3673
3674static void
Kristian Høgsberg75840622011-09-06 13:48:16 -04003675desktop_shell_set_background(struct wl_client *client,
3676 struct wl_resource *resource,
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01003677 struct wl_resource *output_resource,
Kristian Høgsberg75840622011-09-06 13:48:16 -04003678 struct wl_resource *surface_resource)
3679{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05003680 struct desktop_shell *shell = wl_resource_get_user_data(resource);
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05003681 struct weston_surface *surface =
3682 wl_resource_get_user_data(surface_resource);
Jason Ekstranda7af7042013-10-12 22:38:11 -05003683 struct weston_view *view, *next;
Kristian Høgsberg75840622011-09-06 13:48:16 -04003684
Kristian Høgsberg962342c2012-06-26 16:29:50 -04003685 if (surface->configure) {
3686 wl_resource_post_error(surface_resource,
3687 WL_DISPLAY_ERROR_INVALID_OBJECT,
3688 "surface role already assigned");
3689 return;
3690 }
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01003691
Jason Ekstranda7af7042013-10-12 22:38:11 -05003692 wl_list_for_each_safe(view, next, &surface->views, surface_link)
3693 weston_view_destroy(view);
3694 view = weston_view_create(surface);
3695
Kristian Høgsberg962342c2012-06-26 16:29:50 -04003696 surface->configure = background_configure;
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01003697 surface->configure_private = shell;
Jason Ekstranda0d2dde2013-06-14 10:08:01 -05003698 surface->output = wl_resource_get_user_data(output_resource);
Jason Ekstranda7af7042013-10-12 22:38:11 -05003699 view->output = surface->output;
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04003700 desktop_shell_send_configure(resource, 0,
Kristian Høgsberg0b5cd0c2012-03-04 21:57:37 -05003701 surface_resource,
Scott Moreau1bad5db2012-08-18 01:04:05 -06003702 surface->output->width,
3703 surface->output->height);
Kristian Høgsberg75840622011-09-06 13:48:16 -04003704}
3705
3706static void
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06003707panel_configure(struct weston_surface *es, int32_t sx, int32_t sy)
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04003708{
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01003709 struct desktop_shell *shell = es->configure_private;
Jason Ekstranda7af7042013-10-12 22:38:11 -05003710 struct weston_view *view;
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04003711
Jason Ekstranda7af7042013-10-12 22:38:11 -05003712 view = container_of(es->views.next, struct weston_view, surface_link);
3713
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06003714 configure_static_view(view, &shell->panel_layer);
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04003715}
3716
3717static void
Kristian Høgsberg75840622011-09-06 13:48:16 -04003718desktop_shell_set_panel(struct wl_client *client,
3719 struct wl_resource *resource,
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01003720 struct wl_resource *output_resource,
Kristian Høgsberg75840622011-09-06 13:48:16 -04003721 struct wl_resource *surface_resource)
3722{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05003723 struct desktop_shell *shell = wl_resource_get_user_data(resource);
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05003724 struct weston_surface *surface =
3725 wl_resource_get_user_data(surface_resource);
Jason Ekstranda7af7042013-10-12 22:38:11 -05003726 struct weston_view *view, *next;
Kristian Høgsberg75840622011-09-06 13:48:16 -04003727
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04003728 if (surface->configure) {
3729 wl_resource_post_error(surface_resource,
3730 WL_DISPLAY_ERROR_INVALID_OBJECT,
3731 "surface role already assigned");
3732 return;
3733 }
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01003734
Jason Ekstranda7af7042013-10-12 22:38:11 -05003735 wl_list_for_each_safe(view, next, &surface->views, surface_link)
3736 weston_view_destroy(view);
3737 view = weston_view_create(surface);
3738
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04003739 surface->configure = panel_configure;
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01003740 surface->configure_private = shell;
Jason Ekstranda0d2dde2013-06-14 10:08:01 -05003741 surface->output = wl_resource_get_user_data(output_resource);
Jason Ekstranda7af7042013-10-12 22:38:11 -05003742 view->output = surface->output;
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04003743 desktop_shell_send_configure(resource, 0,
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04003744 surface_resource,
Scott Moreau1bad5db2012-08-18 01:04:05 -06003745 surface->output->width,
3746 surface->output->height);
Kristian Høgsberg75840622011-09-06 13:48:16 -04003747}
3748
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02003749static void
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06003750lock_surface_configure(struct weston_surface *surface, int32_t sx, int32_t sy)
Kristian Høgsberg730c94d2012-06-26 21:44:35 -04003751{
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01003752 struct desktop_shell *shell = surface->configure_private;
Jason Ekstranda7af7042013-10-12 22:38:11 -05003753 struct weston_view *view;
3754
3755 view = container_of(surface->views.next, struct weston_view, surface_link);
Kristian Høgsberg730c94d2012-06-26 21:44:35 -04003756
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06003757 if (surface->width == 0)
Giulio Camuffo184df502013-02-21 11:29:21 +01003758 return;
3759
Jason Ekstranda7af7042013-10-12 22:38:11 -05003760 center_on_output(view, get_default_output(shell->compositor));
Kristian Høgsberg730c94d2012-06-26 21:44:35 -04003761
3762 if (!weston_surface_is_mapped(surface)) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05003763 wl_list_insert(&shell->lock_layer.view_list,
3764 &view->layer_link);
3765 weston_view_update_transform(view);
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02003766 shell_fade(shell, FADE_IN);
Kristian Høgsberg730c94d2012-06-26 21:44:35 -04003767 }
3768}
3769
3770static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04003771handle_lock_surface_destroy(struct wl_listener *listener, void *data)
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05003772{
Tiago Vignattibe143262012-04-16 17:31:41 +03003773 struct desktop_shell *shell =
3774 container_of(listener, struct desktop_shell, lock_surface_listener);
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05003775
Martin Minarik6d118362012-06-07 18:01:59 +02003776 weston_log("lock surface gone\n");
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05003777 shell->lock_surface = NULL;
3778}
3779
3780static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02003781desktop_shell_set_lock_surface(struct wl_client *client,
3782 struct wl_resource *resource,
3783 struct wl_resource *surface_resource)
3784{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05003785 struct desktop_shell *shell = wl_resource_get_user_data(resource);
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05003786 struct weston_surface *surface =
3787 wl_resource_get_user_data(surface_resource);
Pekka Paalanen98262232011-12-01 10:42:22 +02003788
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02003789 shell->prepare_event_sent = false;
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +02003790
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02003791 if (!shell->locked)
3792 return;
3793
Pekka Paalanen98262232011-12-01 10:42:22 +02003794 shell->lock_surface = surface;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02003795
Kristian Høgsberg27e30522012-04-11 23:18:23 -04003796 shell->lock_surface_listener.notify = handle_lock_surface_destroy;
Jason Ekstrand651f00e2013-06-14 10:07:54 -05003797 wl_signal_add(&surface->destroy_signal,
Kristian Høgsberg27e30522012-04-11 23:18:23 -04003798 &shell->lock_surface_listener);
Pekka Paalanen57da4a82011-11-23 16:42:16 +02003799
Kristian Høgsbergaa2ee8b2013-10-30 15:49:45 -07003800 weston_view_create(surface);
Kristian Høgsberg730c94d2012-06-26 21:44:35 -04003801 surface->configure = lock_surface_configure;
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01003802 surface->configure_private = shell;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02003803}
3804
3805static void
Tiago Vignattibe143262012-04-16 17:31:41 +03003806resume_desktop(struct desktop_shell *shell)
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02003807{
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04003808 struct workspace *ws = get_current_workspace(shell);
Pekka Paalanen77346a62011-11-30 16:26:35 +02003809
Pekka Paalanen77346a62011-11-30 16:26:35 +02003810 terminate_screensaver(shell);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02003811
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05003812 wl_list_remove(&shell->lock_layer.link);
3813 wl_list_insert(&shell->compositor->cursor_layer.link,
3814 &shell->fullscreen_layer.link);
3815 wl_list_insert(&shell->fullscreen_layer.link,
3816 &shell->panel_layer.link);
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02003817 if (shell->showing_input_panels) {
3818 wl_list_insert(&shell->panel_layer.link,
3819 &shell->input_panel_layer.link);
3820 wl_list_insert(&shell->input_panel_layer.link,
3821 &ws->layer.link);
3822 } else {
3823 wl_list_insert(&shell->panel_layer.link, &ws->layer.link);
3824 }
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02003825
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -04003826 restore_focus_state(shell, get_current_workspace(shell));
Jonas Ådahl04769742012-06-13 00:01:24 +02003827
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02003828 shell->locked = false;
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02003829 shell_fade(shell, FADE_IN);
Pekka Paalanenfc6d91a2012-02-10 15:33:10 +02003830 weston_compositor_damage_all(shell->compositor);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02003831}
3832
3833static void
3834desktop_shell_unlock(struct wl_client *client,
3835 struct wl_resource *resource)
3836{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05003837 struct desktop_shell *shell = wl_resource_get_user_data(resource);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02003838
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02003839 shell->prepare_event_sent = false;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02003840
3841 if (shell->locked)
3842 resume_desktop(shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02003843}
3844
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04003845static void
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03003846desktop_shell_set_grab_surface(struct wl_client *client,
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04003847 struct wl_resource *resource,
3848 struct wl_resource *surface_resource)
3849{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05003850 struct desktop_shell *shell = wl_resource_get_user_data(resource);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04003851
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05003852 shell->grab_surface = wl_resource_get_user_data(surface_resource);
Kristian Høgsberg48588f82013-10-24 15:51:35 -07003853 weston_view_create(shell->grab_surface);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04003854}
3855
Pekka Paalanen79346ab2013-05-22 18:03:09 +03003856static void
3857desktop_shell_desktop_ready(struct wl_client *client,
3858 struct wl_resource *resource)
3859{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05003860 struct desktop_shell *shell = wl_resource_get_user_data(resource);
Pekka Paalanen79346ab2013-05-22 18:03:09 +03003861
3862 shell_fade_startup(shell);
3863}
3864
Kristian Høgsberg75840622011-09-06 13:48:16 -04003865static const struct desktop_shell_interface desktop_shell_implementation = {
3866 desktop_shell_set_background,
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02003867 desktop_shell_set_panel,
3868 desktop_shell_set_lock_surface,
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04003869 desktop_shell_unlock,
Pekka Paalanen79346ab2013-05-22 18:03:09 +03003870 desktop_shell_set_grab_surface,
3871 desktop_shell_desktop_ready
Kristian Høgsberg75840622011-09-06 13:48:16 -04003872};
3873
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02003874static enum shell_surface_type
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05003875get_shell_surface_type(struct weston_surface *surface)
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02003876{
3877 struct shell_surface *shsurf;
3878
3879 shsurf = get_shell_surface(surface);
3880 if (!shsurf)
Pekka Paalanen98262232011-12-01 10:42:22 +02003881 return SHELL_SURFACE_NONE;
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02003882 return shsurf->type;
3883}
3884
Kristian Høgsberg75840622011-09-06 13:48:16 -04003885static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04003886move_binding(struct weston_seat *seat, uint32_t time, uint32_t button, void *data)
Kristian Høgsberg07937562011-04-12 17:25:42 -04003887{
Rafal Mielniczukb2917a22014-01-05 20:04:59 +01003888 struct weston_surface *focus;
Pekka Paalanen01388e22013-04-25 13:57:44 +03003889 struct weston_surface *surface;
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04003890 struct shell_surface *shsurf;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -05003891
Rafal Mielniczukb2917a22014-01-05 20:04:59 +01003892 if (seat->pointer->focus == NULL)
3893 return;
3894
3895 focus = seat->pointer->focus->surface;
3896
Pekka Paalanen01388e22013-04-25 13:57:44 +03003897 surface = weston_surface_get_main_surface(focus);
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01003898 if (surface == NULL)
3899 return;
Kristian Høgsberg07937562011-04-12 17:25:42 -04003900
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04003901 shsurf = get_shell_surface(surface);
Rafael Antognolli03b16592013-12-03 15:35:42 -02003902 if (shsurf == NULL || shsurf->state.fullscreen ||
3903 shsurf->state.maximized)
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04003904 return;
3905
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04003906 surface_move(shsurf, (struct weston_seat *) seat);
Kristian Høgsberg07937562011-04-12 17:25:42 -04003907}
3908
3909static void
Rafael Antognolliea997ac2013-12-03 15:35:48 -02003910maximize_binding(struct weston_seat *seat, uint32_t time, uint32_t button, void *data)
3911{
Emilio Pozuelo Monfort38b58eb2014-01-29 11:11:12 +01003912 struct weston_surface *focus = seat->keyboard->focus;
Rafael Antognolliea997ac2013-12-03 15:35:48 -02003913 struct weston_surface *surface;
3914 struct shell_surface *shsurf;
3915
3916 surface = weston_surface_get_main_surface(focus);
3917 if (surface == NULL)
3918 return;
3919
3920 shsurf = get_shell_surface(surface);
3921 if (shsurf == NULL)
3922 return;
3923
3924 if (!shell_surface_is_xdg_surface(shsurf))
3925 return;
3926
3927 if (shsurf->state.maximized)
3928 xdg_surface_send_request_unset_maximized(shsurf->resource);
3929 else
3930 xdg_surface_send_request_set_maximized(shsurf->resource);
3931}
3932
3933static void
3934fullscreen_binding(struct weston_seat *seat, uint32_t time, uint32_t button, void *data)
3935{
Emilio Pozuelo Monfort38b58eb2014-01-29 11:11:12 +01003936 struct weston_surface *focus = seat->keyboard->focus;
Rafael Antognolliea997ac2013-12-03 15:35:48 -02003937 struct weston_surface *surface;
3938 struct shell_surface *shsurf;
3939
3940 surface = weston_surface_get_main_surface(focus);
3941 if (surface == NULL)
3942 return;
3943
3944 shsurf = get_shell_surface(surface);
3945 if (shsurf == NULL)
3946 return;
3947
3948 if (!shell_surface_is_xdg_surface(shsurf))
3949 return;
3950
3951 if (shsurf->state.fullscreen)
3952 xdg_surface_send_request_unset_fullscreen(shsurf->resource);
3953 else
3954 xdg_surface_send_request_set_fullscreen(shsurf->resource);
3955}
3956
3957static void
Neil Robertsaba0f252013-10-03 16:43:05 +01003958touch_move_binding(struct weston_seat *seat, uint32_t time, void *data)
3959{
Kristian Høgsberg7ab139c2013-10-24 16:21:39 -07003960 struct weston_surface *focus = seat->touch->focus->surface;
Neil Robertsaba0f252013-10-03 16:43:05 +01003961 struct weston_surface *surface;
3962 struct shell_surface *shsurf;
3963
3964 surface = weston_surface_get_main_surface(focus);
3965 if (surface == NULL)
3966 return;
3967
3968 shsurf = get_shell_surface(surface);
Rafael Antognolli03b16592013-12-03 15:35:42 -02003969 if (shsurf == NULL || shsurf->state.fullscreen ||
3970 shsurf->state.maximized)
Neil Robertsaba0f252013-10-03 16:43:05 +01003971 return;
3972
3973 surface_touch_move(shsurf, (struct weston_seat *) seat);
3974}
3975
3976static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04003977resize_binding(struct weston_seat *seat, uint32_t time, uint32_t button, void *data)
Kristian Høgsberg07937562011-04-12 17:25:42 -04003978{
Rafal Mielniczukb2917a22014-01-05 20:04:59 +01003979 struct weston_surface *focus;
Pekka Paalanen01388e22013-04-25 13:57:44 +03003980 struct weston_surface *surface;
Kristian Høgsberg07937562011-04-12 17:25:42 -04003981 uint32_t edges = 0;
3982 int32_t x, y;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003983 struct shell_surface *shsurf;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -05003984
Rafal Mielniczukb2917a22014-01-05 20:04:59 +01003985 if (seat->pointer->focus == NULL)
3986 return;
3987
3988 focus = seat->pointer->focus->surface;
3989
Pekka Paalanen01388e22013-04-25 13:57:44 +03003990 surface = weston_surface_get_main_surface(focus);
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01003991 if (surface == NULL)
3992 return;
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02003993
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003994 shsurf = get_shell_surface(surface);
Rafael Antognolli03b16592013-12-03 15:35:42 -02003995 if (shsurf == NULL || shsurf->state.fullscreen ||
3996 shsurf->state.maximized)
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02003997 return;
3998
Jason Ekstranda7af7042013-10-12 22:38:11 -05003999 weston_view_from_global(shsurf->view,
4000 wl_fixed_to_int(seat->pointer->grab_x),
4001 wl_fixed_to_int(seat->pointer->grab_y),
4002 &x, &y);
Kristian Høgsberg07937562011-04-12 17:25:42 -04004003
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004004 if (x < shsurf->surface->width / 3)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02004005 edges |= WL_SHELL_SURFACE_RESIZE_LEFT;
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004006 else if (x < 2 * shsurf->surface->width / 3)
Kristian Høgsberg07937562011-04-12 17:25:42 -04004007 edges |= 0;
4008 else
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02004009 edges |= WL_SHELL_SURFACE_RESIZE_RIGHT;
Kristian Høgsberg07937562011-04-12 17:25:42 -04004010
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004011 if (y < shsurf->surface->height / 3)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02004012 edges |= WL_SHELL_SURFACE_RESIZE_TOP;
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004013 else if (y < 2 * shsurf->surface->height / 3)
Kristian Høgsberg07937562011-04-12 17:25:42 -04004014 edges |= 0;
4015 else
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02004016 edges |= WL_SHELL_SURFACE_RESIZE_BOTTOM;
Kristian Høgsberg07937562011-04-12 17:25:42 -04004017
Kristian Høgsbergc1693f22012-05-22 16:56:23 -04004018 surface_resize(shsurf, (struct weston_seat *) seat, edges);
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04004019}
4020
4021static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04004022surface_opacity_binding(struct weston_seat *seat, uint32_t time, uint32_t axis,
Daniel Stone0c1e46e2012-05-30 16:31:59 +01004023 wl_fixed_t value, void *data)
Scott Moreaua3aa9c92012-03-22 11:01:03 -06004024{
Jonas Ådahlb0b87ba2012-09-27 18:40:42 +02004025 float step = 0.005;
Scott Moreaua3aa9c92012-03-22 11:01:03 -06004026 struct shell_surface *shsurf;
Kristian Høgsberg7ab139c2013-10-24 16:21:39 -07004027 struct weston_surface *focus = seat->pointer->focus->surface;
Pekka Paalanen01388e22013-04-25 13:57:44 +03004028 struct weston_surface *surface;
Scott Moreaua3aa9c92012-03-22 11:01:03 -06004029
Pekka Paalanen01388e22013-04-25 13:57:44 +03004030 /* XXX: broken for windows containing sub-surfaces */
4031 surface = weston_surface_get_main_surface(focus);
Scott Moreaua3aa9c92012-03-22 11:01:03 -06004032 if (surface == NULL)
4033 return;
4034
4035 shsurf = get_shell_surface(surface);
4036 if (!shsurf)
4037 return;
4038
Jason Ekstranda7af7042013-10-12 22:38:11 -05004039 shsurf->view->alpha -= wl_fixed_to_double(value) * step;
Scott Moreaua3aa9c92012-03-22 11:01:03 -06004040
Jason Ekstranda7af7042013-10-12 22:38:11 -05004041 if (shsurf->view->alpha > 1.0)
4042 shsurf->view->alpha = 1.0;
4043 if (shsurf->view->alpha < step)
4044 shsurf->view->alpha = step;
Scott Moreaua3aa9c92012-03-22 11:01:03 -06004045
Jason Ekstranda7af7042013-10-12 22:38:11 -05004046 weston_view_geometry_dirty(shsurf->view);
Scott Moreaua3aa9c92012-03-22 11:01:03 -06004047 weston_surface_damage(surface);
4048}
4049
4050static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04004051do_zoom(struct weston_seat *seat, uint32_t time, uint32_t key, uint32_t axis,
Daniel Stone0c1e46e2012-05-30 16:31:59 +01004052 wl_fixed_t value)
Scott Moreauccbf29d2012-02-22 14:21:41 -07004053{
Daniel Stone37816df2012-05-16 18:45:18 +01004054 struct weston_seat *ws = (struct weston_seat *) seat;
4055 struct weston_compositor *compositor = ws->compositor;
Scott Moreauccbf29d2012-02-22 14:21:41 -07004056 struct weston_output *output;
Scott Moreaue6603982012-06-11 13:07:51 -06004057 float increment;
Scott Moreauccbf29d2012-02-22 14:21:41 -07004058
4059 wl_list_for_each(output, &compositor->output_list, link) {
4060 if (pixman_region32_contains_point(&output->region,
Daniel Stone37816df2012-05-16 18:45:18 +01004061 wl_fixed_to_double(seat->pointer->x),
4062 wl_fixed_to_double(seat->pointer->y),
Daniel Stone103db7f2012-05-08 17:17:55 +01004063 NULL)) {
Daniel Stone325fc2d2012-05-30 16:31:58 +01004064 if (key == KEY_PAGEUP)
Kristian Høgsberg9b68af02012-05-22 12:55:18 -04004065 increment = output->zoom.increment;
Daniel Stone325fc2d2012-05-30 16:31:58 +01004066 else if (key == KEY_PAGEDOWN)
Kristian Høgsberg9b68af02012-05-22 12:55:18 -04004067 increment = -output->zoom.increment;
4068 else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
Jonas Ådahlb0b87ba2012-09-27 18:40:42 +02004069 /* For every pixel zoom 20th of a step */
Daniel Stone0c1e46e2012-05-30 16:31:59 +01004070 increment = output->zoom.increment *
Jonas Ådahlb0b87ba2012-09-27 18:40:42 +02004071 -wl_fixed_to_double(value) / 20.0;
Kristian Høgsberg9b68af02012-05-22 12:55:18 -04004072 else
4073 increment = 0;
4074
Kristian Høgsberg9b68af02012-05-22 12:55:18 -04004075 output->zoom.level += increment;
Scott Moreauc6d7f602012-02-23 22:28:37 -07004076
Scott Moreaue6603982012-06-11 13:07:51 -06004077 if (output->zoom.level < 0.0)
Scott Moreau850ca422012-05-21 15:21:25 -06004078 output->zoom.level = 0.0;
Scott Moreaue6603982012-06-11 13:07:51 -06004079 else if (output->zoom.level > output->zoom.max_level)
4080 output->zoom.level = output->zoom.max_level;
Ville Syrjäläaa628d02012-11-16 11:48:47 +02004081 else if (!output->zoom.active) {
Giulio Camuffo412b0242013-11-14 23:42:51 +01004082 weston_output_activate_zoom(output);
Kristian Høgsberg79af73e2012-08-03 15:45:23 -04004083 }
Scott Moreauccbf29d2012-02-22 14:21:41 -07004084
Scott Moreaue6603982012-06-11 13:07:51 -06004085 output->zoom.spring_z.target = output->zoom.level;
Scott Moreauccbf29d2012-02-22 14:21:41 -07004086
Jason Ekstranda7af7042013-10-12 22:38:11 -05004087 weston_output_update_zoom(output);
Scott Moreauccbf29d2012-02-22 14:21:41 -07004088 }
4089 }
4090}
4091
Scott Moreauccbf29d2012-02-22 14:21:41 -07004092static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04004093zoom_axis_binding(struct weston_seat *seat, uint32_t time, uint32_t axis,
Daniel Stone0c1e46e2012-05-30 16:31:59 +01004094 wl_fixed_t value, void *data)
Daniel Stone325fc2d2012-05-30 16:31:58 +01004095{
4096 do_zoom(seat, time, 0, axis, value);
4097}
4098
4099static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04004100zoom_key_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
Daniel Stone325fc2d2012-05-30 16:31:58 +01004101 void *data)
4102{
4103 do_zoom(seat, time, key, 0, 0);
4104}
4105
4106static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04004107terminate_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
Daniel Stone325fc2d2012-05-30 16:31:58 +01004108 void *data)
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05004109{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05004110 struct weston_compositor *compositor = data;
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05004111
Daniel Stone325fc2d2012-05-30 16:31:58 +01004112 wl_display_terminate(compositor->wl_display);
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05004113}
4114
Emilio Pozuelo Monfort03251b62013-11-19 11:37:16 +01004115static void
Giulio Camuffo1959ab82013-11-14 23:42:52 +01004116rotate_grab_motion(struct weston_pointer_grab *grab, uint32_t time,
4117 wl_fixed_t x, wl_fixed_t y)
Pekka Paalanen460099f2012-01-20 16:48:25 +02004118{
4119 struct rotate_grab *rotate =
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004120 container_of(grab, struct rotate_grab, base.grab);
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04004121 struct weston_pointer *pointer = grab->pointer;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004122 struct shell_surface *shsurf = rotate->base.shsurf;
John Kåre Alsaker490d02a2012-09-30 02:57:21 +02004123 float cx, cy, dx, dy, cposx, cposy, dposx, dposy, r;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004124
Giulio Camuffo1959ab82013-11-14 23:42:52 +01004125 weston_pointer_move(pointer, x, y);
4126
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004127 if (!shsurf)
4128 return;
4129
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004130 cx = 0.5f * shsurf->surface->width;
4131 cy = 0.5f * shsurf->surface->height;
Pekka Paalanen460099f2012-01-20 16:48:25 +02004132
Daniel Stone37816df2012-05-16 18:45:18 +01004133 dx = wl_fixed_to_double(pointer->x) - rotate->center.x;
4134 dy = wl_fixed_to_double(pointer->y) - rotate->center.y;
Pekka Paalanen460099f2012-01-20 16:48:25 +02004135 r = sqrtf(dx * dx + dy * dy);
4136
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004137 wl_list_remove(&shsurf->rotation.transform.link);
Jason Ekstranda7af7042013-10-12 22:38:11 -05004138 weston_view_geometry_dirty(shsurf->view);
Pekka Paalanen460099f2012-01-20 16:48:25 +02004139
4140 if (r > 20.0f) {
Pekka Paalanen460099f2012-01-20 16:48:25 +02004141 struct weston_matrix *matrix =
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004142 &shsurf->rotation.transform.matrix;
Pekka Paalanen460099f2012-01-20 16:48:25 +02004143
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05004144 weston_matrix_init(&rotate->rotation);
Vasily Khoruzhick1bbf3722013-01-28 22:40:28 +03004145 weston_matrix_rotate_xy(&rotate->rotation, dx / r, dy / r);
Pekka Paalanen460099f2012-01-20 16:48:25 +02004146
4147 weston_matrix_init(matrix);
Pekka Paalanen7b3bd3d2012-01-30 14:16:34 +02004148 weston_matrix_translate(matrix, -cx, -cy, 0.0f);
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004149 weston_matrix_multiply(matrix, &shsurf->rotation.rotation);
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05004150 weston_matrix_multiply(matrix, &rotate->rotation);
Pekka Paalanen7b3bd3d2012-01-30 14:16:34 +02004151 weston_matrix_translate(matrix, cx, cy, 0.0f);
Pekka Paalanen460099f2012-01-20 16:48:25 +02004152
Pekka Paalanenbc0b7e72012-01-24 09:53:37 +02004153 wl_list_insert(
Jason Ekstranda7af7042013-10-12 22:38:11 -05004154 &shsurf->view->geometry.transformation_list,
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004155 &shsurf->rotation.transform.link);
Pekka Paalanen460099f2012-01-20 16:48:25 +02004156 } else {
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004157 wl_list_init(&shsurf->rotation.transform.link);
4158 weston_matrix_init(&shsurf->rotation.rotation);
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05004159 weston_matrix_init(&rotate->rotation);
Pekka Paalanen460099f2012-01-20 16:48:25 +02004160 }
Pekka Paalanenb45ac5e2012-02-09 15:58:44 +02004161
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01004162 /* We need to adjust the position of the surface
4163 * in case it was resized in a rotated state before */
Jason Ekstranda7af7042013-10-12 22:38:11 -05004164 cposx = shsurf->view->geometry.x + cx;
4165 cposy = shsurf->view->geometry.y + cy;
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01004166 dposx = rotate->center.x - cposx;
4167 dposy = rotate->center.y - cposy;
4168 if (dposx != 0.0f || dposy != 0.0f) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05004169 weston_view_set_position(shsurf->view,
4170 shsurf->view->geometry.x + dposx,
4171 shsurf->view->geometry.y + dposy);
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01004172 }
4173
Pekka Paalanenb45ac5e2012-02-09 15:58:44 +02004174 /* Repaint implies weston_surface_update_transform(), which
4175 * lazily applies the damage due to rotation update.
4176 */
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004177 weston_compositor_schedule_repaint(shsurf->surface->compositor);
Pekka Paalanen460099f2012-01-20 16:48:25 +02004178}
4179
4180static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04004181rotate_grab_button(struct weston_pointer_grab *grab,
4182 uint32_t time, uint32_t button, uint32_t state_w)
Pekka Paalanen460099f2012-01-20 16:48:25 +02004183{
4184 struct rotate_grab *rotate =
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004185 container_of(grab, struct rotate_grab, base.grab);
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04004186 struct weston_pointer *pointer = grab->pointer;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004187 struct shell_surface *shsurf = rotate->base.shsurf;
Daniel Stone4dbadb12012-05-30 16:31:51 +01004188 enum wl_pointer_button_state state = state_w;
Pekka Paalanen460099f2012-01-20 16:48:25 +02004189
Daniel Stone4dbadb12012-05-30 16:31:51 +01004190 if (pointer->button_count == 0 &&
4191 state == WL_POINTER_BUTTON_STATE_RELEASED) {
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004192 if (shsurf)
4193 weston_matrix_multiply(&shsurf->rotation.rotation,
4194 &rotate->rotation);
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03004195 shell_grab_end(&rotate->base);
Pekka Paalanen460099f2012-01-20 16:48:25 +02004196 free(rotate);
4197 }
4198}
4199
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02004200static void
4201rotate_grab_cancel(struct weston_pointer_grab *grab)
4202{
4203 struct rotate_grab *rotate =
4204 container_of(grab, struct rotate_grab, base.grab);
4205
4206 shell_grab_end(&rotate->base);
4207 free(rotate);
4208}
4209
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04004210static const struct weston_pointer_grab_interface rotate_grab_interface = {
Pekka Paalanen460099f2012-01-20 16:48:25 +02004211 noop_grab_focus,
4212 rotate_grab_motion,
4213 rotate_grab_button,
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02004214 rotate_grab_cancel,
Pekka Paalanen460099f2012-01-20 16:48:25 +02004215};
4216
4217static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04004218surface_rotate(struct shell_surface *surface, struct weston_seat *seat)
Pekka Paalanen460099f2012-01-20 16:48:25 +02004219{
Pekka Paalanen460099f2012-01-20 16:48:25 +02004220 struct rotate_grab *rotate;
John Kåre Alsaker490d02a2012-09-30 02:57:21 +02004221 float dx, dy;
4222 float r;
Pekka Paalanen460099f2012-01-20 16:48:25 +02004223
Pekka Paalanen460099f2012-01-20 16:48:25 +02004224 rotate = malloc(sizeof *rotate);
4225 if (!rotate)
4226 return;
4227
Jason Ekstranda7af7042013-10-12 22:38:11 -05004228 weston_view_to_global_float(surface->view,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004229 surface->surface->width * 0.5f,
4230 surface->surface->height * 0.5f,
Jason Ekstranda7af7042013-10-12 22:38:11 -05004231 &rotate->center.x, &rotate->center.y);
Pekka Paalanen460099f2012-01-20 16:48:25 +02004232
Daniel Stone37816df2012-05-16 18:45:18 +01004233 dx = wl_fixed_to_double(seat->pointer->x) - rotate->center.x;
4234 dy = wl_fixed_to_double(seat->pointer->y) - rotate->center.y;
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05004235 r = sqrtf(dx * dx + dy * dy);
4236 if (r > 20.0f) {
4237 struct weston_matrix inverse;
4238
4239 weston_matrix_init(&inverse);
Vasily Khoruzhick1bbf3722013-01-28 22:40:28 +03004240 weston_matrix_rotate_xy(&inverse, dx / r, -dy / r);
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05004241 weston_matrix_multiply(&surface->rotation.rotation, &inverse);
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01004242
4243 weston_matrix_init(&rotate->rotation);
Vasily Khoruzhick1bbf3722013-01-28 22:40:28 +03004244 weston_matrix_rotate_xy(&rotate->rotation, dx / r, dy / r);
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05004245 } else {
4246 weston_matrix_init(&surface->rotation.rotation);
4247 weston_matrix_init(&rotate->rotation);
4248 }
4249
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03004250 shell_grab_start(&rotate->base, &rotate_grab_interface, surface,
4251 seat->pointer, DESKTOP_SHELL_CURSOR_ARROW);
Pekka Paalanen460099f2012-01-20 16:48:25 +02004252}
4253
4254static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04004255rotate_binding(struct weston_seat *seat, uint32_t time, uint32_t button,
Kristian Høgsberg0c369032013-02-14 21:31:44 -05004256 void *data)
4257{
Rafal Mielniczukb2917a22014-01-05 20:04:59 +01004258 struct weston_surface *focus;
Pekka Paalanen01388e22013-04-25 13:57:44 +03004259 struct weston_surface *base_surface;
Kristian Høgsberg0c369032013-02-14 21:31:44 -05004260 struct shell_surface *surface;
4261
Rafal Mielniczukb2917a22014-01-05 20:04:59 +01004262 if (seat->pointer->focus == NULL)
4263 return;
4264
4265 focus = seat->pointer->focus->surface;
4266
Pekka Paalanen01388e22013-04-25 13:57:44 +03004267 base_surface = weston_surface_get_main_surface(focus);
Kristian Høgsberg0c369032013-02-14 21:31:44 -05004268 if (base_surface == NULL)
4269 return;
4270
4271 surface = get_shell_surface(base_surface);
Rafael Antognolli03b16592013-12-03 15:35:42 -02004272 if (surface == NULL || surface->state.fullscreen ||
4273 surface->state.maximized)
Kristian Høgsberg0c369032013-02-14 21:31:44 -05004274 return;
4275
4276 surface_rotate(surface, seat);
4277}
4278
Philip Withnall83ffd9d2013-11-25 18:01:42 +00004279/* Move all fullscreen layers down to the current workspace in a non-reversible
4280 * manner. This should be used when implementing shell-wide overlays, such as
4281 * the alt-tab switcher, which need to de-promote fullscreen layers. */
Kristian Høgsberg1ef23132013-12-04 00:20:01 -08004282void
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04004283lower_fullscreen_layer(struct desktop_shell *shell)
4284{
4285 struct workspace *ws;
Jason Ekstranda7af7042013-10-12 22:38:11 -05004286 struct weston_view *view, *prev;
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04004287
4288 ws = get_current_workspace(shell);
Jason Ekstranda7af7042013-10-12 22:38:11 -05004289 wl_list_for_each_reverse_safe(view, prev,
4290 &shell->fullscreen_layer.view_list,
Philip Withnall83ffd9d2013-11-25 18:01:42 +00004291 layer_link) {
4292 wl_list_remove(&view->layer_link);
4293 wl_list_insert(&ws->layer.view_list, &view->layer_link);
4294 weston_view_damage_below(view);
4295 weston_surface_damage(view->surface);
4296 }
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04004297}
4298
Kristian Høgsberg1ef23132013-12-04 00:20:01 -08004299void
Tiago Vignattibe143262012-04-16 17:31:41 +03004300activate(struct desktop_shell *shell, struct weston_surface *es,
Daniel Stone37816df2012-05-16 18:45:18 +01004301 struct weston_seat *seat)
Kristian Høgsberg75840622011-09-06 13:48:16 -04004302{
Pekka Paalanen01388e22013-04-25 13:57:44 +03004303 struct weston_surface *main_surface;
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -04004304 struct focus_state *state;
Jonas Ådahl8538b222012-08-29 22:13:03 +02004305 struct workspace *ws;
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01004306 struct weston_surface *old_es;
Rafael Antognolli03b16592013-12-03 15:35:42 -02004307 struct shell_surface *shsurf;
Kristian Høgsberg75840622011-09-06 13:48:16 -04004308
Pekka Paalanen01388e22013-04-25 13:57:44 +03004309 main_surface = weston_surface_get_main_surface(es);
4310
Daniel Stone37816df2012-05-16 18:45:18 +01004311 weston_surface_activate(es, seat);
Kristian Høgsberg75840622011-09-06 13:48:16 -04004312
Jonas Ådahl8538b222012-08-29 22:13:03 +02004313 state = ensure_focus_state(shell, seat);
4314 if (state == NULL)
4315 return;
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -04004316
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01004317 old_es = state->keyboard_focus;
Kristian Høgsbergd500bf12014-01-22 12:25:20 -08004318 focus_state_set_focus(state, es);
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -04004319
Rafael Antognolli03b16592013-12-03 15:35:42 -02004320 shsurf = get_shell_surface(main_surface);
U. Artie Eoffcf5737a2014-01-17 10:08:25 -08004321 assert(shsurf);
4322
Rafael Antognolli03b16592013-12-03 15:35:42 -02004323 if (shsurf->state.fullscreen)
4324 shell_configure_fullscreen(shsurf);
4325 else
Alexander Larssonf82b6ca2013-05-28 16:23:39 +02004326 restore_all_output_modes(shell->compositor);
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01004327
Emilio Pozuelo Monfort7908bff2014-01-30 13:49:39 +01004328 /* Update the surface’s layer. This brings it to the top of the stacking
4329 * order as appropriate. */
4330 shell_surface_update_layer(shsurf);
4331
Philip Withnall83ffd9d2013-11-25 18:01:42 +00004332 if (shell->focus_animation_type != ANIMATION_NONE) {
4333 ws = get_current_workspace(shell);
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01004334 animate_focus_change(shell, ws, get_default_view(old_es), get_default_view(es));
Philip Withnall83ffd9d2013-11-25 18:01:42 +00004335 }
Kristian Høgsberg75840622011-09-06 13:48:16 -04004336}
4337
Alex Wu21858432012-04-01 20:13:08 +08004338/* no-op func for checking black surface */
4339static void
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004340black_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
Alex Wu21858432012-04-01 20:13:08 +08004341{
4342}
4343
Quentin Glidicc0d79ce2013-01-29 14:16:13 +01004344static bool
Alex Wu21858432012-04-01 20:13:08 +08004345is_black_surface (struct weston_surface *es, struct weston_surface **fs_surface)
4346{
4347 if (es->configure == black_surface_configure) {
4348 if (fs_surface)
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01004349 *fs_surface = (struct weston_surface *)es->configure_private;
Alex Wu21858432012-04-01 20:13:08 +08004350 return true;
4351 }
4352 return false;
4353}
4354
Kristian Høgsberg75840622011-09-06 13:48:16 -04004355static void
Neil Robertsa28c6932013-10-03 16:43:04 +01004356activate_binding(struct weston_seat *seat,
4357 struct desktop_shell *shell,
4358 struct weston_surface *focus)
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05004359{
Pekka Paalanen01388e22013-04-25 13:57:44 +03004360 struct weston_surface *main_surface;
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05004361
Alex Wu9c35e6b2012-03-05 14:13:13 +08004362 if (!focus)
4363 return;
4364
Pekka Paalanen01388e22013-04-25 13:57:44 +03004365 if (is_black_surface(focus, &main_surface))
4366 focus = main_surface;
Alex Wu4539b082012-03-01 12:57:46 +08004367
Pekka Paalanen01388e22013-04-25 13:57:44 +03004368 main_surface = weston_surface_get_main_surface(focus);
4369 if (get_shell_surface_type(main_surface) == SHELL_SURFACE_NONE)
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04004370 return;
Kristian Høgsberg85b2e4b2012-06-21 16:49:42 -04004371
Neil Robertsa28c6932013-10-03 16:43:04 +01004372 activate(shell, focus, seat);
4373}
4374
4375static void
4376click_to_activate_binding(struct weston_seat *seat, uint32_t time, uint32_t button,
4377 void *data)
4378{
4379 if (seat->pointer->grab != &seat->pointer->default_grab)
4380 return;
Kristian Høgsberg7c4f6cc2014-01-01 16:28:32 -08004381 if (seat->pointer->focus == NULL)
4382 return;
Neil Robertsa28c6932013-10-03 16:43:04 +01004383
Kristian Høgsberg7ab139c2013-10-24 16:21:39 -07004384 activate_binding(seat, data, seat->pointer->focus->surface);
Neil Robertsa28c6932013-10-03 16:43:04 +01004385}
4386
4387static void
4388touch_to_activate_binding(struct weston_seat *seat, uint32_t time, void *data)
4389{
4390 if (seat->touch->grab != &seat->touch->default_grab)
4391 return;
Kristian Høgsberg0ed67502014-01-02 23:00:11 -08004392 if (seat->touch->focus == NULL)
4393 return;
Neil Robertsa28c6932013-10-03 16:43:04 +01004394
Kristian Høgsberg7ab139c2013-10-24 16:21:39 -07004395 activate_binding(seat, data, seat->touch->focus->surface);
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05004396}
4397
4398static void
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004399lock(struct desktop_shell *shell)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04004400{
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04004401 struct workspace *ws = get_current_workspace(shell);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02004402
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004403 if (shell->locked) {
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02004404 weston_compositor_sleep(shell->compositor);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02004405 return;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004406 }
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02004407
4408 shell->locked = true;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02004409
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05004410 /* Hide all surfaces by removing the fullscreen, panel and
4411 * toplevel layers. This way nothing else can show or receive
4412 * input events while we are locked. */
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02004413
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05004414 wl_list_remove(&shell->panel_layer.link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05004415 wl_list_remove(&shell->fullscreen_layer.link);
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02004416 if (shell->showing_input_panels)
4417 wl_list_remove(&shell->input_panel_layer.link);
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04004418 wl_list_remove(&ws->layer.link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05004419 wl_list_insert(&shell->compositor->cursor_layer.link,
4420 &shell->lock_layer.link);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02004421
Pekka Paalanen77346a62011-11-30 16:26:35 +02004422 launch_screensaver(shell);
4423
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02004424 /* TODO: disable bindings that should not work while locked. */
4425
4426 /* All this must be undone in resume_desktop(). */
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02004427}
4428
4429static void
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004430unlock(struct desktop_shell *shell)
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02004431{
Pekka Paalanend81c2162011-11-16 13:47:34 +02004432 if (!shell->locked || shell->lock_surface) {
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02004433 shell_fade(shell, FADE_IN);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02004434 return;
4435 }
4436
4437 /* If desktop-shell client has gone away, unlock immediately. */
4438 if (!shell->child.desktop_shell) {
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02004439 resume_desktop(shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02004440 return;
4441 }
4442
4443 if (shell->prepare_event_sent)
4444 return;
4445
Kristian Høgsberg0b5cd0c2012-03-04 21:57:37 -05004446 desktop_shell_send_prepare_lock_surface(shell->child.desktop_shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02004447 shell->prepare_event_sent = true;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04004448}
4449
4450static void
Jason Ekstranda7af7042013-10-12 22:38:11 -05004451shell_fade_done(struct weston_view_animation *animation, void *data)
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004452{
4453 struct desktop_shell *shell = data;
4454
4455 shell->fade.animation = NULL;
4456
4457 switch (shell->fade.type) {
4458 case FADE_IN:
Jason Ekstranda7af7042013-10-12 22:38:11 -05004459 weston_surface_destroy(shell->fade.view->surface);
4460 shell->fade.view = NULL;
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004461 break;
4462 case FADE_OUT:
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004463 lock(shell);
4464 break;
Philip Withnall4a86a0a2013-11-25 18:01:32 +00004465 default:
4466 break;
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004467 }
4468}
4469
Jason Ekstranda7af7042013-10-12 22:38:11 -05004470static struct weston_view *
Pekka Paalanen79346ab2013-05-22 18:03:09 +03004471shell_fade_create_surface(struct desktop_shell *shell)
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004472{
4473 struct weston_compositor *compositor = shell->compositor;
4474 struct weston_surface *surface;
Jason Ekstranda7af7042013-10-12 22:38:11 -05004475 struct weston_view *view;
Pekka Paalanen79346ab2013-05-22 18:03:09 +03004476
4477 surface = weston_surface_create(compositor);
4478 if (!surface)
4479 return NULL;
4480
Jason Ekstranda7af7042013-10-12 22:38:11 -05004481 view = weston_view_create(surface);
4482 if (!view) {
4483 weston_surface_destroy(surface);
4484 return NULL;
4485 }
4486
Jason Ekstrand5c11a332013-12-04 20:32:03 -06004487 weston_surface_set_size(surface, 8192, 8192);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004488 weston_view_set_position(view, 0, 0);
Pekka Paalanen79346ab2013-05-22 18:03:09 +03004489 weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1.0);
Jason Ekstranda7af7042013-10-12 22:38:11 -05004490 wl_list_insert(&compositor->fade_layer.view_list,
4491 &view->layer_link);
Pekka Paalanen79346ab2013-05-22 18:03:09 +03004492 pixman_region32_init(&surface->input);
4493
Jason Ekstranda7af7042013-10-12 22:38:11 -05004494 return view;
Pekka Paalanen79346ab2013-05-22 18:03:09 +03004495}
4496
4497static void
4498shell_fade(struct desktop_shell *shell, enum fade_type type)
4499{
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004500 float tint;
4501
4502 switch (type) {
4503 case FADE_IN:
4504 tint = 0.0;
4505 break;
4506 case FADE_OUT:
4507 tint = 1.0;
4508 break;
4509 default:
4510 weston_log("shell: invalid fade type\n");
4511 return;
4512 }
4513
4514 shell->fade.type = type;
4515
Jason Ekstranda7af7042013-10-12 22:38:11 -05004516 if (shell->fade.view == NULL) {
4517 shell->fade.view = shell_fade_create_surface(shell);
4518 if (!shell->fade.view)
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004519 return;
4520
Jason Ekstranda7af7042013-10-12 22:38:11 -05004521 shell->fade.view->alpha = 1.0 - tint;
4522 weston_view_update_transform(shell->fade.view);
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004523 }
4524
Kristian Høgsberg87d3b612014-01-19 21:48:10 -08004525 if (shell->fade.view->output == NULL) {
4526 /* If the black view gets a NULL output, we lost the
4527 * last output and we'll just cancel the fade. This
4528 * happens when you close the last window under the
4529 * X11 or Wayland backends. */
4530 shell->locked = false;
4531 weston_surface_destroy(shell->fade.view->surface);
4532 shell->fade.view = NULL;
4533 } else if (shell->fade.animation) {
Kristian Høgsberg5281fb12013-06-17 10:10:28 -04004534 weston_fade_update(shell->fade.animation, tint);
Kristian Høgsberg87d3b612014-01-19 21:48:10 -08004535 } else {
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004536 shell->fade.animation =
Jason Ekstranda7af7042013-10-12 22:38:11 -05004537 weston_fade_run(shell->fade.view,
Kristian Høgsberg5281fb12013-06-17 10:10:28 -04004538 1.0 - tint, tint, 300.0,
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004539 shell_fade_done, shell);
Kristian Høgsberg87d3b612014-01-19 21:48:10 -08004540 }
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004541}
4542
4543static void
Pekka Paalanen79346ab2013-05-22 18:03:09 +03004544do_shell_fade_startup(void *data)
4545{
4546 struct desktop_shell *shell = data;
4547
Kristian Høgsberg724c8d92013-10-16 11:38:24 -07004548 if (shell->startup_animation_type == ANIMATION_FADE)
4549 shell_fade(shell, FADE_IN);
4550 else if (shell->startup_animation_type == ANIMATION_NONE) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05004551 weston_surface_destroy(shell->fade.view->surface);
4552 shell->fade.view = NULL;
Kristian Høgsberg724c8d92013-10-16 11:38:24 -07004553 }
Pekka Paalanen79346ab2013-05-22 18:03:09 +03004554}
4555
4556static void
4557shell_fade_startup(struct desktop_shell *shell)
4558{
4559 struct wl_event_loop *loop;
4560
4561 if (!shell->fade.startup_timer)
4562 return;
4563
4564 wl_event_source_remove(shell->fade.startup_timer);
4565 shell->fade.startup_timer = NULL;
4566
4567 loop = wl_display_get_event_loop(shell->compositor->wl_display);
4568 wl_event_loop_add_idle(loop, do_shell_fade_startup, shell);
4569}
4570
4571static int
4572fade_startup_timeout(void *data)
4573{
4574 struct desktop_shell *shell = data;
4575
4576 shell_fade_startup(shell);
4577 return 0;
4578}
4579
4580static void
4581shell_fade_init(struct desktop_shell *shell)
4582{
4583 /* Make compositor output all black, and wait for the desktop-shell
4584 * client to signal it is ready, then fade in. The timer triggers a
4585 * fade-in, in case the desktop-shell client takes too long.
4586 */
4587
4588 struct wl_event_loop *loop;
4589
Jason Ekstranda7af7042013-10-12 22:38:11 -05004590 if (shell->fade.view != NULL) {
Pekka Paalanen79346ab2013-05-22 18:03:09 +03004591 weston_log("%s: warning: fade surface already exists\n",
4592 __func__);
4593 return;
4594 }
4595
Jason Ekstranda7af7042013-10-12 22:38:11 -05004596 shell->fade.view = shell_fade_create_surface(shell);
4597 if (!shell->fade.view)
Pekka Paalanen79346ab2013-05-22 18:03:09 +03004598 return;
4599
Jason Ekstranda7af7042013-10-12 22:38:11 -05004600 weston_view_update_transform(shell->fade.view);
4601 weston_surface_damage(shell->fade.view->surface);
Pekka Paalanen79346ab2013-05-22 18:03:09 +03004602
4603 loop = wl_display_get_event_loop(shell->compositor->wl_display);
4604 shell->fade.startup_timer =
4605 wl_event_loop_add_timer(loop, fade_startup_timeout, shell);
4606 wl_event_source_timer_update(shell->fade.startup_timer, 15000);
4607}
4608
4609static void
Ander Conselvan de Oliveiraa4575632013-02-21 18:35:23 +02004610idle_handler(struct wl_listener *listener, void *data)
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004611{
4612 struct desktop_shell *shell =
Ander Conselvan de Oliveiraa4575632013-02-21 18:35:23 +02004613 container_of(listener, struct desktop_shell, idle_listener);
Kristian Høgsberg27d5fa82014-01-17 16:22:50 -08004614 struct weston_seat *seat;
4615
4616 wl_list_for_each(seat, &shell->compositor->seat_list, link)
4617 if (seat->pointer)
4618 popup_grab_end(seat->pointer);
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004619
4620 shell_fade(shell, FADE_OUT);
4621 /* lock() is called from shell_fade_done() */
4622}
4623
4624static void
Ander Conselvan de Oliveiraa4575632013-02-21 18:35:23 +02004625wake_handler(struct wl_listener *listener, void *data)
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004626{
4627 struct desktop_shell *shell =
Ander Conselvan de Oliveiraa4575632013-02-21 18:35:23 +02004628 container_of(listener, struct desktop_shell, wake_listener);
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004629
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004630 unlock(shell);
4631}
4632
4633static void
Jason Ekstranda7af7042013-10-12 22:38:11 -05004634center_on_output(struct weston_view *view, struct weston_output *output)
Pekka Paalanen77346a62011-11-30 16:26:35 +02004635{
Giulio Camuffob8366642013-04-25 13:57:46 +03004636 int32_t surf_x, surf_y, width, height;
Ander Conselvan de Oliveira012b4c72012-11-27 17:03:42 +02004637 float x, y;
Pekka Paalanen77346a62011-11-30 16:26:35 +02004638
Jason Ekstranda7af7042013-10-12 22:38:11 -05004639 surface_subsurfaces_boundingbox(view->surface, &surf_x, &surf_y, &width, &height);
Giulio Camuffob8366642013-04-25 13:57:46 +03004640
4641 x = output->x + (output->width - width) / 2 - surf_x / 2;
4642 y = output->y + (output->height - height) / 2 - surf_y / 2;
Ander Conselvan de Oliveira012b4c72012-11-27 17:03:42 +02004643
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004644 weston_view_set_position(view, x, y);
Pekka Paalanen77346a62011-11-30 16:26:35 +02004645}
4646
4647static void
Jason Ekstranda7af7042013-10-12 22:38:11 -05004648weston_view_set_initial_position(struct weston_view *view,
4649 struct desktop_shell *shell)
Rob Bradfordac63e5b2012-08-13 14:07:52 +01004650{
4651 struct weston_compositor *compositor = shell->compositor;
4652 int ix = 0, iy = 0;
4653 int range_x, range_y;
4654 int dx, dy, x, y, panel_height;
4655 struct weston_output *output, *target_output = NULL;
4656 struct weston_seat *seat;
4657
4658 /* As a heuristic place the new window on the same output as the
4659 * pointer. Falling back to the output containing 0, 0.
4660 *
4661 * TODO: Do something clever for touch too?
4662 */
4663 wl_list_for_each(seat, &compositor->seat_list, link) {
Kristian Høgsberg2bf87622013-05-07 23:17:41 -04004664 if (seat->pointer) {
Kristian Høgsberge3148752013-05-06 23:19:49 -04004665 ix = wl_fixed_to_int(seat->pointer->x);
4666 iy = wl_fixed_to_int(seat->pointer->y);
Rob Bradfordac63e5b2012-08-13 14:07:52 +01004667 break;
4668 }
4669 }
4670
4671 wl_list_for_each(output, &compositor->output_list, link) {
4672 if (pixman_region32_contains_point(&output->region, ix, iy, NULL)) {
4673 target_output = output;
4674 break;
4675 }
4676 }
4677
4678 if (!target_output) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05004679 weston_view_set_position(view, 10 + random() % 400,
4680 10 + random() % 400);
Rob Bradfordac63e5b2012-08-13 14:07:52 +01004681 return;
4682 }
4683
4684 /* Valid range within output where the surface will still be onscreen.
4685 * If this is negative it means that the surface is bigger than
4686 * output.
4687 */
4688 panel_height = get_output_panel_height(shell, target_output);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004689 range_x = target_output->width - view->surface->width;
Scott Moreau1bad5db2012-08-18 01:04:05 -06004690 range_y = (target_output->height - panel_height) -
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004691 view->surface->height;
Rob Bradfordac63e5b2012-08-13 14:07:52 +01004692
Rob Bradford4cb88c72012-08-13 15:18:44 +01004693 if (range_x > 0)
Rob Bradfordac63e5b2012-08-13 14:07:52 +01004694 dx = random() % range_x;
Rob Bradfordac63e5b2012-08-13 14:07:52 +01004695 else
Rob Bradford4cb88c72012-08-13 15:18:44 +01004696 dx = 0;
4697
4698 if (range_y > 0)
Rob Bradfordac63e5b2012-08-13 14:07:52 +01004699 dy = panel_height + random() % range_y;
Rob Bradford4cb88c72012-08-13 15:18:44 +01004700 else
4701 dy = panel_height;
Rob Bradfordac63e5b2012-08-13 14:07:52 +01004702
4703 x = target_output->x + dx;
4704 y = target_output->y + dy;
4705
Jason Ekstranda7af7042013-10-12 22:38:11 -05004706 weston_view_set_position(view, x, y);
Rob Bradfordac63e5b2012-08-13 14:07:52 +01004707}
4708
4709static void
Jason Ekstranda7af7042013-10-12 22:38:11 -05004710map(struct desktop_shell *shell, struct shell_surface *shsurf,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004711 int32_t sx, int32_t sy)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04004712{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05004713 struct weston_compositor *compositor = shell->compositor;
Daniel Stoneb2104682012-05-30 16:31:56 +01004714 struct weston_seat *seat;
Juan Zhao96879df2012-02-07 08:45:41 +08004715 int panel_height = 0;
Giulio Camuffob8366642013-04-25 13:57:46 +03004716 int32_t surf_x, surf_y;
Pekka Paalanen57da4a82011-11-23 16:42:16 +02004717
Pekka Paalanen77346a62011-11-30 16:26:35 +02004718 /* initial positioning, see also configure() */
Jason Ekstranda7af7042013-10-12 22:38:11 -05004719 switch (shsurf->type) {
Rafael Antognollied207b42013-12-03 15:35:43 -02004720 case SHELL_SURFACE_TOPLEVEL:
Rafael Antognolli03b16592013-12-03 15:35:42 -02004721 if (shsurf->state.fullscreen) {
4722 center_on_output(shsurf->view, shsurf->fullscreen_output);
4723 shell_map_fullscreen(shsurf);
4724 } else if (shsurf->state.maximized) {
4725 /* use surface configure to set the geometry */
4726 panel_height = get_output_panel_height(shell, shsurf->output);
4727 surface_subsurfaces_boundingbox(shsurf->surface,
4728 &surf_x, &surf_y, NULL, NULL);
4729 weston_view_set_position(shsurf->view,
4730 shsurf->output->x - surf_x,
4731 shsurf->output->y +
4732 panel_height - surf_y);
Rafael Antognollied207b42013-12-03 15:35:43 -02004733 } else if (!shsurf->state.relative) {
Rafael Antognolli03b16592013-12-03 15:35:42 -02004734 weston_view_set_initial_position(shsurf->view, shell);
4735 }
Juan Zhao96879df2012-02-07 08:45:41 +08004736 break;
Tiago Vignatti0f997012012-02-10 16:17:23 +02004737 case SHELL_SURFACE_POPUP:
Kristian Høgsberg3730f362012-04-13 12:40:07 -04004738 shell_map_popup(shsurf);
Rob Bradforddb999382012-12-06 12:07:48 +00004739 break;
Ander Conselvan de Oliveirae9e05152012-02-15 17:02:56 +02004740 case SHELL_SURFACE_NONE:
Jason Ekstranda7af7042013-10-12 22:38:11 -05004741 weston_view_set_position(shsurf->view,
4742 shsurf->view->geometry.x + sx,
4743 shsurf->view->geometry.y + sy);
Tiago Vignatti0f997012012-02-10 16:17:23 +02004744 break;
Philip Withnall0f640e22013-11-25 18:01:31 +00004745 case SHELL_SURFACE_XWAYLAND:
Pekka Paalanen77346a62011-11-30 16:26:35 +02004746 default:
4747 ;
4748 }
Kristian Høgsberg75840622011-09-06 13:48:16 -04004749
Philip Withnalle1d75ae2013-11-25 18:01:41 +00004750 /* Surface stacking order, see also activate(). */
4751 shell_surface_update_layer(shsurf);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02004752
Jason Ekstranda7af7042013-10-12 22:38:11 -05004753 if (shsurf->type != SHELL_SURFACE_NONE) {
4754 weston_view_update_transform(shsurf->view);
Rafael Antognolli03b16592013-12-03 15:35:42 -02004755 if (shsurf->state.maximized) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05004756 shsurf->surface->output = shsurf->output;
4757 shsurf->view->output = shsurf->output;
4758 }
Ander Conselvan de Oliveirade56c312012-03-05 15:39:23 +02004759 }
Kristian Høgsberg2f88a402011-12-04 15:32:59 -05004760
Jason Ekstranda7af7042013-10-12 22:38:11 -05004761 switch (shsurf->type) {
Tiago Vignattifb2adba2013-06-12 15:43:21 -03004762 /* XXX: xwayland's using the same fields for transient type */
4763 case SHELL_SURFACE_XWAYLAND:
Tiago Vignatti99aeb1e2012-05-23 22:06:26 +03004764 if (shsurf->transient.flags ==
4765 WL_SHELL_SURFACE_TRANSIENT_INACTIVE)
4766 break;
4767 case SHELL_SURFACE_TOPLEVEL:
Rafael Antognollied207b42013-12-03 15:35:43 -02004768 if (shsurf->state.relative &&
4769 shsurf->transient.flags == WL_SHELL_SURFACE_TRANSIENT_INACTIVE)
4770 break;
Rafael Antognolliba5d2d72013-12-04 17:49:55 -02004771 if (shell->locked)
Rafael Antognollied207b42013-12-03 15:35:43 -02004772 break;
4773 wl_list_for_each(seat, &compositor->seat_list, link)
4774 activate(shell, shsurf->surface, seat);
Juan Zhao7bb92f02011-12-15 11:31:51 -05004775 break;
Philip Withnall0f640e22013-11-25 18:01:31 +00004776 case SHELL_SURFACE_POPUP:
4777 case SHELL_SURFACE_NONE:
Juan Zhao7bb92f02011-12-15 11:31:51 -05004778 default:
4779 break;
4780 }
4781
Rafael Antognolli03b16592013-12-03 15:35:42 -02004782 if (shsurf->type == SHELL_SURFACE_TOPLEVEL &&
4783 !shsurf->state.maximized && !shsurf->state.fullscreen)
Juan Zhaoe10d2792012-04-25 19:09:52 +08004784 {
4785 switch (shell->win_animation_type) {
4786 case ANIMATION_FADE:
Jason Ekstranda7af7042013-10-12 22:38:11 -05004787 weston_fade_run(shsurf->view, 0.0, 1.0, 300.0, NULL, NULL);
Juan Zhaoe10d2792012-04-25 19:09:52 +08004788 break;
4789 case ANIMATION_ZOOM:
Jason Ekstranda7af7042013-10-12 22:38:11 -05004790 weston_zoom_run(shsurf->view, 0.5, 1.0, NULL, NULL);
Juan Zhaoe10d2792012-04-25 19:09:52 +08004791 break;
Philip Withnall4a86a0a2013-11-25 18:01:32 +00004792 case ANIMATION_NONE:
Juan Zhaoe10d2792012-04-25 19:09:52 +08004793 default:
4794 break;
4795 }
4796 }
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05004797}
4798
4799static void
Tiago Vignattibe143262012-04-16 17:31:41 +03004800configure(struct desktop_shell *shell, struct weston_surface *surface,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004801 float x, float y)
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05004802{
Pekka Paalanen77346a62011-11-30 16:26:35 +02004803 struct shell_surface *shsurf;
Jason Ekstranda7af7042013-10-12 22:38:11 -05004804 struct weston_view *view;
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004805 int32_t mx, my, surf_x, surf_y;
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05004806
Pekka Paalanen77346a62011-11-30 16:26:35 +02004807 shsurf = get_shell_surface(surface);
Pekka Paalanen77346a62011-11-30 16:26:35 +02004808
U. Artie Eoffcf5737a2014-01-17 10:08:25 -08004809 assert(shsurf);
4810
Rafael Antognolli03b16592013-12-03 15:35:42 -02004811 if (shsurf->state.fullscreen)
Alex Wu4539b082012-03-01 12:57:46 +08004812 shell_configure_fullscreen(shsurf);
Rafael Antognolli03b16592013-12-03 15:35:42 -02004813 else if (shsurf->state.maximized) {
Alex Wu4539b082012-03-01 12:57:46 +08004814 /* setting x, y and using configure to change that geometry */
Giulio Camuffob8366642013-04-25 13:57:46 +03004815 surface_subsurfaces_boundingbox(shsurf->surface, &surf_x, &surf_y,
4816 NULL, NULL);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004817 mx = shsurf->output->x - surf_x;
4818 my = shsurf->output->y +
4819 get_output_panel_height(shell,shsurf->output) - surf_y;
4820 weston_view_set_position(shsurf->view, mx, my);
Rafael Antognolli03b16592013-12-03 15:35:42 -02004821 } else {
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004822 weston_view_set_position(shsurf->view, x, y);
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04004823 }
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05004824
Alex Wu4539b082012-03-01 12:57:46 +08004825 /* XXX: would a fullscreen surface need the same handling? */
Kristian Høgsberg6a8b5532012-02-16 23:43:59 -05004826 if (surface->output) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05004827 wl_list_for_each(view, &surface->views, surface_link)
4828 weston_view_update_transform(view);
Pekka Paalanen77346a62011-11-30 16:26:35 +02004829
Rafael Antognolli03b16592013-12-03 15:35:42 -02004830 if (shsurf->state.maximized)
Juan Zhao96879df2012-02-07 08:45:41 +08004831 surface->output = shsurf->output;
Pekka Paalanen77346a62011-11-30 16:26:35 +02004832 }
Kristian Høgsberg07937562011-04-12 17:25:42 -04004833}
4834
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03004835static void
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004836shell_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03004837{
Ander Conselvan de Oliveira7fb9f952012-03-27 17:36:42 +03004838 struct shell_surface *shsurf = get_shell_surface(es);
U. Artie Eoffcf5737a2014-01-17 10:08:25 -08004839 struct desktop_shell *shell;
Tiago Vignatti70e5c9c2012-05-07 15:23:07 +03004840 int type_changed = 0;
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03004841
U. Artie Eoffcf5737a2014-01-17 10:08:25 -08004842 assert(shsurf);
4843
4844 shell = shsurf->shell;
4845
Kristian Høgsberg8eb0f4f2013-06-17 10:33:14 -04004846 if (!weston_surface_is_mapped(es) &&
4847 !wl_list_empty(&shsurf->popup.grab_link)) {
Giulio Camuffo5085a752013-03-25 21:42:45 +01004848 remove_popup_grab(shsurf);
4849 }
4850
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004851 if (es->width == 0)
Giulio Camuffo184df502013-02-21 11:29:21 +01004852 return;
4853
Kristian Høgsbergc8f8dd82013-12-05 23:20:33 -08004854 if (shsurf->state_changed) {
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04004855 set_surface_type(shsurf);
Kristian Høgsbergf7e23d52012-04-27 17:51:59 -04004856 type_changed = 1;
4857 }
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04004858
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03004859 if (!weston_surface_is_mapped(es)) {
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004860 map(shell, shsurf, sx, sy);
Kristian Høgsbergf7e23d52012-04-27 17:51:59 -04004861 } else if (type_changed || sx != 0 || sy != 0 ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004862 shsurf->last_width != es->width ||
4863 shsurf->last_height != es->height) {
John Kåre Alsaker490d02a2012-09-30 02:57:21 +02004864 float from_x, from_y;
4865 float to_x, to_y;
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03004866
Kristian Høgsberg44cd1962014-02-05 21:36:04 -08004867 if (shsurf->resize_edges) {
4868 sx = 0;
4869 sy = 0;
4870 }
4871
4872 if (shsurf->resize_edges & WL_SHELL_SURFACE_RESIZE_LEFT)
4873 sx = shsurf->last_width - es->width;
4874 if (shsurf->resize_edges & WL_SHELL_SURFACE_RESIZE_TOP)
4875 sy = shsurf->last_height - es->height;
4876
4877 shsurf->last_width = es->width;
4878 shsurf->last_height = es->height;
4879
Jason Ekstranda7af7042013-10-12 22:38:11 -05004880 weston_view_to_global_float(shsurf->view, 0, 0, &from_x, &from_y);
4881 weston_view_to_global_float(shsurf->view, sx, sy, &to_x, &to_y);
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03004882 configure(shell, es,
Jason Ekstranda7af7042013-10-12 22:38:11 -05004883 shsurf->view->geometry.x + to_x - from_x,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004884 shsurf->view->geometry.y + to_y - from_y);
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03004885 }
4886}
4887
Tiago Vignattib7dbbd62012-09-25 17:57:01 +03004888static void launch_desktop_shell_process(void *data);
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02004889
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04004890static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05004891desktop_shell_sigchld(struct weston_process *process, int status)
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02004892{
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02004893 uint32_t time;
Tiago Vignattibe143262012-04-16 17:31:41 +03004894 struct desktop_shell *shell =
4895 container_of(process, struct desktop_shell, child.process);
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02004896
4897 shell->child.process.pid = 0;
4898 shell->child.client = NULL; /* already destroyed by wayland */
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02004899
4900 /* if desktop-shell dies more than 5 times in 30 seconds, give up */
4901 time = weston_compositor_get_time();
Kristian Høgsbergf03a6162012-01-17 11:07:42 -05004902 if (time - shell->child.deathstamp > 30000) {
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02004903 shell->child.deathstamp = time;
4904 shell->child.deathcount = 0;
4905 }
4906
4907 shell->child.deathcount++;
4908 if (shell->child.deathcount > 5) {
Emilio Pozuelo Monfort46ce7982013-11-20 13:22:29 +01004909 weston_log("%s died, giving up.\n", shell->client);
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02004910 return;
4911 }
4912
Emilio Pozuelo Monfort46ce7982013-11-20 13:22:29 +01004913 weston_log("%s died, respawning...\n", shell->client);
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02004914 launch_desktop_shell_process(shell);
Pekka Paalanen79346ab2013-05-22 18:03:09 +03004915 shell_fade_startup(shell);
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02004916}
4917
Tiago Vignattib7dbbd62012-09-25 17:57:01 +03004918static void
Ander Conselvan de Oliveira312ea4c2013-12-20 21:07:01 +02004919desktop_shell_client_destroy(struct wl_listener *listener, void *data)
4920{
4921 struct desktop_shell *shell;
4922
4923 shell = container_of(listener, struct desktop_shell,
4924 child.client_destroy_listener);
4925
4926 shell->child.client = NULL;
4927}
4928
4929static void
Tiago Vignattib7dbbd62012-09-25 17:57:01 +03004930launch_desktop_shell_process(void *data)
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02004931{
Tiago Vignattib7dbbd62012-09-25 17:57:01 +03004932 struct desktop_shell *shell = data;
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02004933
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05004934 shell->child.client = weston_client_launch(shell->compositor,
Pekka Paalanen409ef0a2011-12-02 15:30:21 +02004935 &shell->child.process,
Emilio Pozuelo Monfort46ce7982013-11-20 13:22:29 +01004936 shell->client,
Pekka Paalanen409ef0a2011-12-02 15:30:21 +02004937 desktop_shell_sigchld);
4938
4939 if (!shell->child.client)
Emilio Pozuelo Monfort46ce7982013-11-20 13:22:29 +01004940 weston_log("not able to start %s\n", shell->client);
Ander Conselvan de Oliveira312ea4c2013-12-20 21:07:01 +02004941
4942 shell->child.client_destroy_listener.notify =
4943 desktop_shell_client_destroy;
4944 wl_client_add_destroy_listener(shell->child.client,
4945 &shell->child.client_destroy_listener);
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02004946}
4947
4948static void
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08004949handle_shell_client_destroy(struct wl_listener *listener, void *data)
4950{
4951 struct shell_client *sc =
4952 container_of(listener, struct shell_client, destroy_listener);
4953
4954 if (sc->ping_timer)
4955 wl_event_source_remove(sc->ping_timer);
4956 free(sc);
4957}
4958
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08004959static struct shell_client *
4960shell_client_create(struct wl_client *client, struct desktop_shell *shell,
4961 const struct wl_interface *interface, uint32_t id)
Rafael Antognollie2a34552013-12-03 15:35:45 -02004962{
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08004963 struct shell_client *sc;
Rafael Antognollie2a34552013-12-03 15:35:45 -02004964
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08004965 sc = zalloc(sizeof *sc);
4966 if (sc == NULL) {
4967 wl_client_post_no_memory(client);
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08004968 return NULL;
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08004969 }
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08004970
4971 sc->resource = wl_resource_create(client, interface, 1, id);
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08004972 if (sc->resource == NULL) {
4973 free(sc);
4974 wl_client_post_no_memory(client);
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08004975 return NULL;
Kristian Høgsberg2bff94e2014-02-11 12:22:51 -08004976 }
4977
4978 sc->client = client;
4979 sc->shell = shell;
4980 sc->destroy_listener.notify = handle_shell_client_destroy;
4981 wl_client_add_destroy_listener(client, &sc->destroy_listener);
4982
Kristian Høgsbergdd62aba2014-02-12 09:56:19 -08004983 return sc;
4984}
4985
4986static void
4987bind_shell(struct wl_client *client, void *data, uint32_t version, uint32_t id)
4988{
4989 struct desktop_shell *shell = data;
4990 struct shell_client *sc;
4991
4992 sc = shell_client_create(client, shell, &wl_shell_interface, id);
4993 if (sc)
4994 wl_resource_set_implementation(sc->resource,
4995 &shell_implementation,
4996 shell, NULL);
4997}
4998
4999static void
5000bind_xdg_shell(struct wl_client *client, void *data, uint32_t version, uint32_t id)
5001{
5002 struct desktop_shell *shell = data;
5003 struct shell_client *sc;
5004
5005 sc = shell_client_create(client, shell, &xdg_shell_interface, id);
5006 if (sc)
5007 wl_resource_set_dispatcher(sc->resource,
5008 xdg_shell_unversioned_dispatch,
5009 NULL, sc, NULL);
Rafael Antognollie2a34552013-12-03 15:35:45 -02005010}
5011
5012static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02005013unbind_desktop_shell(struct wl_resource *resource)
5014{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05005015 struct desktop_shell *shell = wl_resource_get_user_data(resource);
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05005016
5017 if (shell->locked)
5018 resume_desktop(shell);
5019
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02005020 shell->child.desktop_shell = NULL;
5021 shell->prepare_event_sent = false;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02005022}
5023
5024static void
Kristian Høgsberg75840622011-09-06 13:48:16 -04005025bind_desktop_shell(struct wl_client *client,
5026 void *data, uint32_t version, uint32_t id)
5027{
Tiago Vignattibe143262012-04-16 17:31:41 +03005028 struct desktop_shell *shell = data;
Pekka Paalanenbbe60522011-11-03 14:11:33 +02005029 struct wl_resource *resource;
Kristian Høgsberg75840622011-09-06 13:48:16 -04005030
Jason Ekstranda85118c2013-06-27 20:17:02 -05005031 resource = wl_resource_create(client, &desktop_shell_interface,
5032 MIN(version, 2), id);
Pekka Paalanenbbe60522011-11-03 14:11:33 +02005033
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02005034 if (client == shell->child.client) {
Jason Ekstranda85118c2013-06-27 20:17:02 -05005035 wl_resource_set_implementation(resource,
5036 &desktop_shell_implementation,
5037 shell, unbind_desktop_shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02005038 shell->child.desktop_shell = resource;
Pekka Paalanen79346ab2013-05-22 18:03:09 +03005039
5040 if (version < 2)
5041 shell_fade_startup(shell);
5042
Pekka Paalanenbbe60522011-11-03 14:11:33 +02005043 return;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02005044 }
Pekka Paalanenbbe60522011-11-03 14:11:33 +02005045
5046 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
5047 "permission to bind desktop_shell denied");
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04005048 wl_resource_destroy(resource);
Kristian Høgsberg75840622011-09-06 13:48:16 -04005049}
5050
Pekka Paalanen6e168112011-11-24 11:34:05 +02005051static void
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06005052screensaver_configure(struct weston_surface *surface, int32_t sx, int32_t sy)
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04005053{
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01005054 struct desktop_shell *shell = surface->configure_private;
Jason Ekstranda7af7042013-10-12 22:38:11 -05005055 struct weston_view *view;
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04005056
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06005057 if (surface->width == 0)
Giulio Camuffo184df502013-02-21 11:29:21 +01005058 return;
5059
Pekka Paalanen3a1d07d2012-12-20 14:02:13 +02005060 /* XXX: starting weston-screensaver beforehand does not work */
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04005061 if (!shell->locked)
5062 return;
5063
Jason Ekstranda7af7042013-10-12 22:38:11 -05005064 view = container_of(surface->views.next, struct weston_view, surface_link);
5065 center_on_output(view, surface->output);
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04005066
Jason Ekstranda7af7042013-10-12 22:38:11 -05005067 if (wl_list_empty(&view->layer_link)) {
5068 wl_list_insert(shell->lock_layer.view_list.prev,
5069 &view->layer_link);
5070 weston_view_update_transform(view);
Ander Conselvan de Oliveira859e8852013-02-21 18:35:21 +02005071 wl_event_source_timer_update(shell->screensaver.timer,
5072 shell->screensaver.duration);
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02005073 shell_fade(shell, FADE_IN);
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04005074 }
5075}
5076
5077static void
Pekka Paalanen6e168112011-11-24 11:34:05 +02005078screensaver_set_surface(struct wl_client *client,
5079 struct wl_resource *resource,
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04005080 struct wl_resource *surface_resource,
Pekka Paalanen6e168112011-11-24 11:34:05 +02005081 struct wl_resource *output_resource)
5082{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05005083 struct desktop_shell *shell = wl_resource_get_user_data(resource);
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05005084 struct weston_surface *surface =
5085 wl_resource_get_user_data(surface_resource);
Jason Ekstranda0d2dde2013-06-14 10:08:01 -05005086 struct weston_output *output = wl_resource_get_user_data(output_resource);
Jason Ekstranda7af7042013-10-12 22:38:11 -05005087 struct weston_view *view, *next;
5088
5089 /* Make sure we only have one view */
5090 wl_list_for_each_safe(view, next, &surface->views, surface_link)
5091 weston_view_destroy(view);
5092 weston_view_create(surface);
Pekka Paalanen6e168112011-11-24 11:34:05 +02005093
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04005094 surface->configure = screensaver_configure;
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01005095 surface->configure_private = shell;
Pekka Paalanen77346a62011-11-30 16:26:35 +02005096 surface->output = output;
Pekka Paalanen6e168112011-11-24 11:34:05 +02005097}
5098
5099static const struct screensaver_interface screensaver_implementation = {
5100 screensaver_set_surface
5101};
5102
5103static void
5104unbind_screensaver(struct wl_resource *resource)
5105{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05005106 struct desktop_shell *shell = wl_resource_get_user_data(resource);
Pekka Paalanen6e168112011-11-24 11:34:05 +02005107
Pekka Paalanen77346a62011-11-30 16:26:35 +02005108 shell->screensaver.binding = NULL;
Pekka Paalanen6e168112011-11-24 11:34:05 +02005109}
5110
5111static void
5112bind_screensaver(struct wl_client *client,
5113 void *data, uint32_t version, uint32_t id)
5114{
Tiago Vignattibe143262012-04-16 17:31:41 +03005115 struct desktop_shell *shell = data;
Pekka Paalanen6e168112011-11-24 11:34:05 +02005116 struct wl_resource *resource;
5117
Jason Ekstranda85118c2013-06-27 20:17:02 -05005118 resource = wl_resource_create(client, &screensaver_interface, 1, id);
Pekka Paalanen6e168112011-11-24 11:34:05 +02005119
Pekka Paalanen77346a62011-11-30 16:26:35 +02005120 if (shell->screensaver.binding == NULL) {
Jason Ekstranda85118c2013-06-27 20:17:02 -05005121 wl_resource_set_implementation(resource,
5122 &screensaver_implementation,
5123 shell, unbind_screensaver);
Pekka Paalanen77346a62011-11-30 16:26:35 +02005124 shell->screensaver.binding = resource;
Pekka Paalanen6e168112011-11-24 11:34:05 +02005125 return;
5126 }
5127
5128 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
5129 "interface object already bound");
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04005130 wl_resource_destroy(resource);
Pekka Paalanen6e168112011-11-24 11:34:05 +02005131}
5132
Kristian Høgsberg07045392012-02-19 18:52:44 -05005133struct switcher {
Tiago Vignattibe143262012-04-16 17:31:41 +03005134 struct desktop_shell *shell;
Kristian Høgsberg07045392012-02-19 18:52:44 -05005135 struct weston_surface *current;
5136 struct wl_listener listener;
Kristian Høgsberg29139d42013-04-18 15:25:39 -04005137 struct weston_keyboard_grab grab;
Kristian Høgsberg07045392012-02-19 18:52:44 -05005138};
5139
5140static void
5141switcher_next(struct switcher *switcher)
5142{
Jason Ekstranda7af7042013-10-12 22:38:11 -05005143 struct weston_view *view;
Kristian Høgsberg07045392012-02-19 18:52:44 -05005144 struct weston_surface *first = NULL, *prev = NULL, *next = NULL;
Kristian Høgsberg32e56862012-04-02 22:18:58 -04005145 struct shell_surface *shsurf;
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04005146 struct workspace *ws = get_current_workspace(switcher->shell);
Kristian Høgsberg07045392012-02-19 18:52:44 -05005147
Jason Ekstranda7af7042013-10-12 22:38:11 -05005148 wl_list_for_each(view, &ws->layer.view_list, layer_link) {
Rafael Antognollied207b42013-12-03 15:35:43 -02005149 shsurf = get_shell_surface(view->surface);
Rafael Antognolli5031cbe2013-12-05 19:01:21 -02005150 if (shsurf &&
5151 shsurf->type == SHELL_SURFACE_TOPLEVEL &&
5152 shsurf->parent == NULL) {
Kristian Høgsberg07045392012-02-19 18:52:44 -05005153 if (first == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05005154 first = view->surface;
Kristian Høgsberg07045392012-02-19 18:52:44 -05005155 if (prev == switcher->current)
Jason Ekstranda7af7042013-10-12 22:38:11 -05005156 next = view->surface;
5157 prev = view->surface;
5158 view->alpha = 0.25;
5159 weston_view_geometry_dirty(view);
5160 weston_surface_damage(view->surface);
Kristian Høgsberg07045392012-02-19 18:52:44 -05005161 }
Alex Wu1659daa2012-04-01 20:13:09 +08005162
Jason Ekstranda7af7042013-10-12 22:38:11 -05005163 if (is_black_surface(view->surface, NULL)) {
5164 view->alpha = 0.25;
5165 weston_view_geometry_dirty(view);
5166 weston_surface_damage(view->surface);
Alex Wu1659daa2012-04-01 20:13:09 +08005167 }
Kristian Høgsberg07045392012-02-19 18:52:44 -05005168 }
5169
5170 if (next == NULL)
5171 next = first;
5172
Alex Wu07b26062012-03-12 16:06:01 +08005173 if (next == NULL)
5174 return;
5175
Kristian Høgsberg07045392012-02-19 18:52:44 -05005176 wl_list_remove(&switcher->listener.link);
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05005177 wl_signal_add(&next->destroy_signal, &switcher->listener);
Kristian Høgsberg07045392012-02-19 18:52:44 -05005178
5179 switcher->current = next;
Jason Ekstranda7af7042013-10-12 22:38:11 -05005180 wl_list_for_each(view, &next->views, surface_link)
5181 view->alpha = 1.0;
Alex Wu1659daa2012-04-01 20:13:09 +08005182
Kristian Høgsberg32e56862012-04-02 22:18:58 -04005183 shsurf = get_shell_surface(switcher->current);
Rafael Antognolli03b16592013-12-03 15:35:42 -02005184 if (shsurf && shsurf->state.fullscreen)
Jason Ekstranda7af7042013-10-12 22:38:11 -05005185 shsurf->fullscreen.black_view->alpha = 1.0;
Kristian Høgsberg07045392012-02-19 18:52:44 -05005186}
5187
5188static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04005189switcher_handle_surface_destroy(struct wl_listener *listener, void *data)
Kristian Høgsberg07045392012-02-19 18:52:44 -05005190{
5191 struct switcher *switcher =
5192 container_of(listener, struct switcher, listener);
5193
5194 switcher_next(switcher);
5195}
5196
5197static void
Daniel Stone351eb612012-05-31 15:27:47 -04005198switcher_destroy(struct switcher *switcher)
Kristian Høgsberg07045392012-02-19 18:52:44 -05005199{
Jason Ekstranda7af7042013-10-12 22:38:11 -05005200 struct weston_view *view;
Kristian Høgsberg29139d42013-04-18 15:25:39 -04005201 struct weston_keyboard *keyboard = switcher->grab.keyboard;
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04005202 struct workspace *ws = get_current_workspace(switcher->shell);
Kristian Høgsberg07045392012-02-19 18:52:44 -05005203
Jason Ekstranda7af7042013-10-12 22:38:11 -05005204 wl_list_for_each(view, &ws->layer.view_list, layer_link) {
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01005205 if (is_focus_view(view))
5206 continue;
5207
Jason Ekstranda7af7042013-10-12 22:38:11 -05005208 view->alpha = 1.0;
5209 weston_surface_damage(view->surface);
Kristian Høgsberg07045392012-02-19 18:52:44 -05005210 }
5211
Alex Wu07b26062012-03-12 16:06:01 +08005212 if (switcher->current)
Daniel Stone37816df2012-05-16 18:45:18 +01005213 activate(switcher->shell, switcher->current,
5214 (struct weston_seat *) keyboard->seat);
Kristian Høgsberg07045392012-02-19 18:52:44 -05005215 wl_list_remove(&switcher->listener.link);
Kristian Høgsberg29139d42013-04-18 15:25:39 -04005216 weston_keyboard_end_grab(keyboard);
5217 if (keyboard->input_method_resource)
5218 keyboard->grab = &keyboard->input_method_grab;
Kristian Høgsberg07045392012-02-19 18:52:44 -05005219 free(switcher);
5220}
5221
5222static void
Kristian Høgsberg29139d42013-04-18 15:25:39 -04005223switcher_key(struct weston_keyboard_grab *grab,
Daniel Stonec9785ea2012-05-30 16:31:52 +01005224 uint32_t time, uint32_t key, uint32_t state_w)
Kristian Høgsberg07045392012-02-19 18:52:44 -05005225{
5226 struct switcher *switcher = container_of(grab, struct switcher, grab);
Daniel Stonec9785ea2012-05-30 16:31:52 +01005227 enum wl_keyboard_key_state state = state_w;
Daniel Stone351eb612012-05-31 15:27:47 -04005228
Daniel Stonec9785ea2012-05-30 16:31:52 +01005229 if (key == KEY_TAB && state == WL_KEYBOARD_KEY_STATE_PRESSED)
Daniel Stone351eb612012-05-31 15:27:47 -04005230 switcher_next(switcher);
5231}
5232
5233static void
Kristian Høgsberg29139d42013-04-18 15:25:39 -04005234switcher_modifier(struct weston_keyboard_grab *grab, uint32_t serial,
Daniel Stone351eb612012-05-31 15:27:47 -04005235 uint32_t mods_depressed, uint32_t mods_latched,
5236 uint32_t mods_locked, uint32_t group)
5237{
5238 struct switcher *switcher = container_of(grab, struct switcher, grab);
Daniel Stone37816df2012-05-16 18:45:18 +01005239 struct weston_seat *seat = (struct weston_seat *) grab->keyboard->seat;
Kristian Høgsberg07045392012-02-19 18:52:44 -05005240
Daniel Stone351eb612012-05-31 15:27:47 -04005241 if ((seat->modifier_state & switcher->shell->binding_modifier) == 0)
5242 switcher_destroy(switcher);
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04005243}
Kristian Høgsberg07045392012-02-19 18:52:44 -05005244
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02005245static void
5246switcher_cancel(struct weston_keyboard_grab *grab)
5247{
5248 struct switcher *switcher = container_of(grab, struct switcher, grab);
5249
5250 switcher_destroy(switcher);
5251}
5252
Kristian Høgsberg29139d42013-04-18 15:25:39 -04005253static const struct weston_keyboard_grab_interface switcher_grab = {
Daniel Stone351eb612012-05-31 15:27:47 -04005254 switcher_key,
5255 switcher_modifier,
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02005256 switcher_cancel,
Kristian Høgsberg07045392012-02-19 18:52:44 -05005257};
5258
5259static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04005260switcher_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
Daniel Stone325fc2d2012-05-30 16:31:58 +01005261 void *data)
Kristian Høgsberg07045392012-02-19 18:52:44 -05005262{
Tiago Vignattibe143262012-04-16 17:31:41 +03005263 struct desktop_shell *shell = data;
Kristian Høgsberg07045392012-02-19 18:52:44 -05005264 struct switcher *switcher;
5265
5266 switcher = malloc(sizeof *switcher);
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04005267 switcher->shell = shell;
Kristian Høgsberg07045392012-02-19 18:52:44 -05005268 switcher->current = NULL;
Kristian Høgsberg27e30522012-04-11 23:18:23 -04005269 switcher->listener.notify = switcher_handle_surface_destroy;
Kristian Høgsberg07045392012-02-19 18:52:44 -05005270 wl_list_init(&switcher->listener.link);
5271
Alexander Larssonf82b6ca2013-05-28 16:23:39 +02005272 restore_all_output_modes(shell->compositor);
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04005273 lower_fullscreen_layer(switcher->shell);
Kristian Høgsberg07045392012-02-19 18:52:44 -05005274 switcher->grab.interface = &switcher_grab;
Kristian Høgsberg29139d42013-04-18 15:25:39 -04005275 weston_keyboard_start_grab(seat->keyboard, &switcher->grab);
5276 weston_keyboard_set_focus(seat->keyboard, NULL);
Kristian Høgsberg07045392012-02-19 18:52:44 -05005277 switcher_next(switcher);
5278}
5279
Pekka Paalanen3c647232011-12-22 13:43:43 +02005280static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04005281backlight_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
Daniel Stone325fc2d2012-05-30 16:31:58 +01005282 void *data)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02005283{
5284 struct weston_compositor *compositor = data;
5285 struct weston_output *output;
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03005286 long backlight_new = 0;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02005287
5288 /* TODO: we're limiting to simple use cases, where we assume just
5289 * control on the primary display. We'd have to extend later if we
5290 * ever get support for setting backlights on random desktop LCD
5291 * panels though */
5292 output = get_default_output(compositor);
5293 if (!output)
5294 return;
5295
5296 if (!output->set_backlight)
5297 return;
5298
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03005299 if (key == KEY_F9 || key == KEY_BRIGHTNESSDOWN)
5300 backlight_new = output->backlight_current - 25;
5301 else if (key == KEY_F10 || key == KEY_BRIGHTNESSUP)
5302 backlight_new = output->backlight_current + 25;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02005303
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03005304 if (backlight_new < 5)
5305 backlight_new = 5;
5306 if (backlight_new > 255)
5307 backlight_new = 255;
5308
5309 output->backlight_current = backlight_new;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02005310 output->set_backlight(output, output->backlight_current);
5311}
5312
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005313struct debug_binding_grab {
Kristian Høgsberg29139d42013-04-18 15:25:39 -04005314 struct weston_keyboard_grab grab;
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005315 struct weston_seat *seat;
5316 uint32_t key[2];
5317 int key_released[2];
5318};
5319
5320static void
Kristian Høgsberg29139d42013-04-18 15:25:39 -04005321debug_binding_key(struct weston_keyboard_grab *grab, uint32_t time,
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005322 uint32_t key, uint32_t state)
5323{
5324 struct debug_binding_grab *db = (struct debug_binding_grab *) grab;
Rob Bradford880ebc72013-07-22 17:31:38 +01005325 struct weston_compositor *ec = db->seat->compositor;
5326 struct wl_display *display = ec->wl_display;
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005327 struct wl_resource *resource;
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005328 uint32_t serial;
5329 int send = 0, terminate = 0;
5330 int check_binding = 1;
5331 int i;
Neil Roberts96d790e2013-09-19 17:32:00 +01005332 struct wl_list *resource_list;
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005333
5334 if (state == WL_KEYBOARD_KEY_STATE_RELEASED) {
5335 /* Do not run bindings on key releases */
5336 check_binding = 0;
5337
5338 for (i = 0; i < 2; i++)
5339 if (key == db->key[i])
5340 db->key_released[i] = 1;
5341
5342 if (db->key_released[0] && db->key_released[1]) {
5343 /* All key releases been swalled so end the grab */
5344 terminate = 1;
5345 } else if (key != db->key[0] && key != db->key[1]) {
5346 /* Should not swallow release of other keys */
5347 send = 1;
5348 }
5349 } else if (key == db->key[0] && !db->key_released[0]) {
5350 /* Do not check bindings for the first press of the binding
5351 * key. This allows it to be used as a debug shortcut.
5352 * We still need to swallow this event. */
5353 check_binding = 0;
5354 } else if (db->key[1]) {
5355 /* If we already ran a binding don't process another one since
5356 * we can't keep track of all the binding keys that were
5357 * pressed in order to swallow the release events. */
5358 send = 1;
5359 check_binding = 0;
5360 }
5361
5362 if (check_binding) {
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005363 if (weston_compositor_run_debug_binding(ec, db->seat, time,
5364 key, state)) {
5365 /* We ran a binding so swallow the press and keep the
5366 * grab to swallow the released too. */
5367 send = 0;
5368 terminate = 0;
5369 db->key[1] = key;
5370 } else {
5371 /* Terminate the grab since the key pressed is not a
5372 * debug binding key. */
5373 send = 1;
5374 terminate = 1;
5375 }
5376 }
5377
5378 if (send) {
Neil Roberts96d790e2013-09-19 17:32:00 +01005379 serial = wl_display_next_serial(display);
5380 resource_list = &grab->keyboard->focus_resource_list;
5381 wl_resource_for_each(resource, resource_list) {
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005382 wl_keyboard_send_key(resource, serial, time, key, state);
5383 }
5384 }
5385
5386 if (terminate) {
Kristian Høgsberg29139d42013-04-18 15:25:39 -04005387 weston_keyboard_end_grab(grab->keyboard);
5388 if (grab->keyboard->input_method_resource)
5389 grab->keyboard->grab = &grab->keyboard->input_method_grab;
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005390 free(db);
5391 }
5392}
5393
5394static void
Kristian Høgsberg29139d42013-04-18 15:25:39 -04005395debug_binding_modifiers(struct weston_keyboard_grab *grab, uint32_t serial,
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005396 uint32_t mods_depressed, uint32_t mods_latched,
5397 uint32_t mods_locked, uint32_t group)
5398{
5399 struct wl_resource *resource;
Neil Roberts96d790e2013-09-19 17:32:00 +01005400 struct wl_list *resource_list;
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005401
Neil Roberts96d790e2013-09-19 17:32:00 +01005402 resource_list = &grab->keyboard->focus_resource_list;
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005403
Neil Roberts96d790e2013-09-19 17:32:00 +01005404 wl_resource_for_each(resource, resource_list) {
5405 wl_keyboard_send_modifiers(resource, serial, mods_depressed,
5406 mods_latched, mods_locked, group);
5407 }
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005408}
5409
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02005410static void
5411debug_binding_cancel(struct weston_keyboard_grab *grab)
5412{
5413 struct debug_binding_grab *db = (struct debug_binding_grab *) grab;
5414
5415 weston_keyboard_end_grab(grab->keyboard);
5416 free(db);
5417}
5418
Kristian Høgsberg29139d42013-04-18 15:25:39 -04005419struct weston_keyboard_grab_interface debug_binding_keyboard_grab = {
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005420 debug_binding_key,
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02005421 debug_binding_modifiers,
5422 debug_binding_cancel,
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005423};
5424
5425static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04005426debug_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005427{
5428 struct debug_binding_grab *grab;
5429
5430 grab = calloc(1, sizeof *grab);
5431 if (!grab)
5432 return;
5433
5434 grab->seat = (struct weston_seat *) seat;
5435 grab->key[0] = key;
5436 grab->grab.interface = &debug_binding_keyboard_grab;
Kristian Høgsberg29139d42013-04-18 15:25:39 -04005437 weston_keyboard_start_grab(seat->keyboard, &grab->grab);
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005438}
5439
Kristian Høgsbergb41c0812012-03-04 14:53:40 -05005440static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04005441force_kill_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
Daniel Stone325fc2d2012-05-30 16:31:58 +01005442 void *data)
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04005443{
Kristian Høgsbergfe7aa902013-05-08 09:54:37 -04005444 struct weston_surface *focus_surface;
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04005445 struct wl_client *client;
Tiago Vignatti1d01b012012-09-27 17:48:36 +03005446 struct desktop_shell *shell = data;
5447 struct weston_compositor *compositor = shell->compositor;
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04005448 pid_t pid;
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04005449
Philipp Brüschweiler6cef0092012-08-13 21:27:27 +02005450 focus_surface = seat->keyboard->focus;
5451 if (!focus_surface)
5452 return;
5453
Tiago Vignatti1d01b012012-09-27 17:48:36 +03005454 wl_signal_emit(&compositor->kill_signal, focus_surface);
5455
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05005456 client = wl_resource_get_client(focus_surface->resource);
Tiago Vignatti920f1972012-09-27 17:48:35 +03005457 wl_client_get_credentials(client, &pid, NULL, NULL);
5458
5459 /* Skip clients that we launched ourselves (the credentials of
5460 * the socketpair is ours) */
5461 if (pid == getpid())
5462 return;
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04005463
Daniel Stone325fc2d2012-05-30 16:31:58 +01005464 kill(pid, SIGKILL);
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04005465}
5466
5467static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04005468workspace_up_binding(struct weston_seat *seat, uint32_t time,
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005469 uint32_t key, void *data)
5470{
5471 struct desktop_shell *shell = data;
5472 unsigned int new_index = shell->workspaces.current;
5473
Kristian Høgsbergce345b02012-06-25 21:35:29 -04005474 if (shell->locked)
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04005475 return;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005476 if (new_index != 0)
5477 new_index--;
5478
5479 change_workspace(shell, new_index);
5480}
5481
5482static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04005483workspace_down_binding(struct weston_seat *seat, uint32_t time,
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005484 uint32_t key, void *data)
5485{
5486 struct desktop_shell *shell = data;
5487 unsigned int new_index = shell->workspaces.current;
5488
Kristian Høgsbergce345b02012-06-25 21:35:29 -04005489 if (shell->locked)
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04005490 return;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005491 if (new_index < shell->workspaces.num - 1)
5492 new_index++;
5493
5494 change_workspace(shell, new_index);
5495}
5496
5497static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04005498workspace_f_binding(struct weston_seat *seat, uint32_t time,
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005499 uint32_t key, void *data)
5500{
5501 struct desktop_shell *shell = data;
5502 unsigned int new_index;
5503
Kristian Høgsbergce345b02012-06-25 21:35:29 -04005504 if (shell->locked)
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04005505 return;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005506 new_index = key - KEY_F1;
5507 if (new_index >= shell->workspaces.num)
5508 new_index = shell->workspaces.num - 1;
5509
5510 change_workspace(shell, new_index);
5511}
5512
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02005513static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04005514workspace_move_surface_up_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 != 0)
5524 new_index--;
5525
5526 take_surface_to_workspace_by_seat(shell, seat, new_index);
5527}
5528
5529static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04005530workspace_move_surface_down_binding(struct weston_seat *seat, uint32_t time,
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02005531 uint32_t key, void *data)
5532{
5533 struct desktop_shell *shell = data;
5534 unsigned int new_index = shell->workspaces.current;
5535
5536 if (shell->locked)
5537 return;
5538
5539 if (new_index < shell->workspaces.num - 1)
5540 new_index++;
5541
5542 take_surface_to_workspace_by_seat(shell, seat, new_index);
5543}
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005544
5545static void
Ander Conselvan de Oliveirac94d6222014-01-29 18:47:54 +02005546shell_reposition_view_on_output_destroy(struct weston_view *view)
5547{
5548 struct weston_output *output, *first_output;
5549 struct weston_compositor *ec = view->surface->compositor;
5550 struct shell_surface *shsurf;
5551 float x, y;
5552 int visible;
5553
5554 x = view->geometry.x;
5555 y = view->geometry.y;
5556
5557 /* At this point the destroyed output is not in the list anymore.
5558 * If the view is still visible somewhere, we leave where it is,
5559 * otherwise, move it to the first output. */
5560 visible = 0;
5561 wl_list_for_each(output, &ec->output_list, link) {
5562 if (pixman_region32_contains_point(&output->region,
5563 x, y, NULL)) {
5564 visible = 1;
5565 break;
5566 }
5567 }
5568
5569 if (!visible) {
5570 first_output = container_of(ec->output_list.next,
5571 struct weston_output, link);
5572
5573 x = first_output->x + first_output->width / 4;
5574 y = first_output->y + first_output->height / 4;
5575 }
5576
5577 weston_view_set_position(view, x, y);
5578
5579 shsurf = get_shell_surface(view->surface);
5580
5581 if (shsurf) {
5582 shsurf->saved_position_valid = false;
5583 shsurf->next_state.maximized = false;
5584 shsurf->next_state.fullscreen = false;
5585 shsurf->state_changed = true;
5586 }
5587}
5588
5589static void
5590shell_reposition_views_on_output_destroy(struct shell_output *shell_output)
5591{
5592 struct desktop_shell *shell = shell_output->shell;
5593 struct weston_output *output = shell_output->output;
5594 struct weston_layer *layer;
5595 struct weston_view *view;
5596
5597 /* Move all views in the layers owned by the shell */
5598 wl_list_for_each(layer, shell->fullscreen_layer.link.prev, link) {
5599 wl_list_for_each(view, &layer->view_list, layer_link) {
5600 if (view->output != output)
5601 continue;
5602
5603 shell_reposition_view_on_output_destroy(view);
5604 }
5605
5606 /* We don't start from the beggining of the layer list, so
5607 * make sure we don't wrap around it. */
5608 if (layer == &shell->background_layer)
5609 break;
5610 }
5611}
5612
5613static void
Xiong Zhang6b481422013-10-23 13:58:32 +08005614handle_output_destroy(struct wl_listener *listener, void *data)
5615{
5616 struct shell_output *output_listener =
5617 container_of(listener, struct shell_output, destroy_listener);
5618
Ander Conselvan de Oliveirac94d6222014-01-29 18:47:54 +02005619 shell_reposition_views_on_output_destroy(output_listener);
5620
Xiong Zhang6b481422013-10-23 13:58:32 +08005621 wl_list_remove(&output_listener->destroy_listener.link);
5622 wl_list_remove(&output_listener->link);
5623 free(output_listener);
5624}
5625
5626static void
5627create_shell_output(struct desktop_shell *shell,
5628 struct weston_output *output)
5629{
5630 struct shell_output *shell_output;
5631
5632 shell_output = zalloc(sizeof *shell_output);
5633 if (shell_output == NULL)
5634 return;
5635
5636 shell_output->output = output;
5637 shell_output->shell = shell;
5638 shell_output->destroy_listener.notify = handle_output_destroy;
5639 wl_signal_add(&output->destroy_signal,
5640 &shell_output->destroy_listener);
Kristian Høgsberga3a0e182013-10-23 23:36:04 -07005641 wl_list_insert(shell->output_list.prev, &shell_output->link);
Xiong Zhang6b481422013-10-23 13:58:32 +08005642}
5643
5644static void
5645handle_output_create(struct wl_listener *listener, void *data)
5646{
5647 struct desktop_shell *shell =
5648 container_of(listener, struct desktop_shell, output_create_listener);
5649 struct weston_output *output = (struct weston_output *)data;
5650
5651 create_shell_output(shell, output);
5652}
5653
5654static void
Ander Conselvan de Oliveiraa8a9baf2014-01-29 18:47:52 +02005655handle_output_move(struct wl_listener *listener, void *data)
5656{
5657 struct desktop_shell *shell;
5658 struct weston_output *output;
5659 struct weston_layer *layer;
5660 struct weston_view *view;
5661 float x, y;
5662
5663 shell = container_of(listener, struct desktop_shell,
5664 output_move_listener);
5665 output = data;
5666
5667 /* Move all views in the layers owned by the shell */
5668 wl_list_for_each(layer, shell->fullscreen_layer.link.prev, link) {
5669 wl_list_for_each(view, &layer->view_list, layer_link) {
5670 if (view->output != output)
5671 continue;
5672
5673 x = view->geometry.x + output->move_x;
5674 y = view->geometry.y + output->move_y;
5675 weston_view_set_position(view, x, y);
5676 }
5677
5678 /* We don't start from the beggining of the layer list, so
5679 * make sure we don't wrap around it. */
5680 if (layer == &shell->background_layer)
5681 break;
5682 }
5683}
5684
5685static void
Xiong Zhang6b481422013-10-23 13:58:32 +08005686setup_output_destroy_handler(struct weston_compositor *ec,
5687 struct desktop_shell *shell)
5688{
5689 struct weston_output *output;
5690
5691 wl_list_init(&shell->output_list);
5692 wl_list_for_each(output, &ec->output_list, link)
5693 create_shell_output(shell, output);
5694
5695 shell->output_create_listener.notify = handle_output_create;
5696 wl_signal_add(&ec->output_created_signal,
5697 &shell->output_create_listener);
Ander Conselvan de Oliveiraa8a9baf2014-01-29 18:47:52 +02005698
5699 shell->output_move_listener.notify = handle_output_move;
5700 wl_signal_add(&ec->output_moved_signal, &shell->output_move_listener);
Xiong Zhang6b481422013-10-23 13:58:32 +08005701}
5702
5703static void
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04005704shell_destroy(struct wl_listener *listener, void *data)
Pekka Paalanen3c647232011-12-22 13:43:43 +02005705{
Tiago Vignattibe143262012-04-16 17:31:41 +03005706 struct desktop_shell *shell =
5707 container_of(listener, struct desktop_shell, destroy_listener);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005708 struct workspace **ws;
Xiong Zhang6b481422013-10-23 13:58:32 +08005709 struct shell_output *shell_output, *tmp;
Pekka Paalanen3c647232011-12-22 13:43:43 +02005710
Kristian Høgsberg17bccae2014-01-16 16:46:28 -08005711 /* Force state to unlocked so we don't try to fade */
5712 shell->locked = false;
Pekka Paalanen9cf5cc82012-01-02 16:00:24 +02005713 if (shell->child.client)
5714 wl_client_destroy(shell->child.client);
5715
Ander Conselvan de Oliveiraa4575632013-02-21 18:35:23 +02005716 wl_list_remove(&shell->idle_listener.link);
5717 wl_list_remove(&shell->wake_listener.link);
Kristian Høgsberg677a5f52013-12-04 11:00:19 -08005718
5719 input_panel_destroy(shell);
Kristian Høgsberg88c16072012-05-16 08:04:19 -04005720
Xiong Zhang6b481422013-10-23 13:58:32 +08005721 wl_list_for_each_safe(shell_output, tmp, &shell->output_list, link) {
5722 wl_list_remove(&shell_output->destroy_listener.link);
5723 wl_list_remove(&shell_output->link);
5724 free(shell_output);
5725 }
5726
5727 wl_list_remove(&shell->output_create_listener.link);
5728
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005729 wl_array_for_each(ws, &shell->workspaces.array)
5730 workspace_destroy(*ws);
5731 wl_array_release(&shell->workspaces.array);
5732
Pekka Paalanen3c647232011-12-22 13:43:43 +02005733 free(shell->screensaver.path);
Emilio Pozuelo Monfort46ce7982013-11-20 13:22:29 +01005734 free(shell->client);
Pekka Paalanen3c647232011-12-22 13:43:43 +02005735 free(shell);
5736}
5737
Tiago Vignatti0b52d482012-04-20 18:54:25 +03005738static void
5739shell_add_bindings(struct weston_compositor *ec, struct desktop_shell *shell)
5740{
5741 uint32_t mod;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005742 int i, num_workspace_bindings;
Tiago Vignatti0b52d482012-04-20 18:54:25 +03005743
5744 /* fixed bindings */
Daniel Stone325fc2d2012-05-30 16:31:58 +01005745 weston_compositor_add_key_binding(ec, KEY_BACKSPACE,
5746 MODIFIER_CTRL | MODIFIER_ALT,
5747 terminate_binding, ec);
5748 weston_compositor_add_button_binding(ec, BTN_LEFT, 0,
5749 click_to_activate_binding,
5750 shell);
Neil Robertsa28c6932013-10-03 16:43:04 +01005751 weston_compositor_add_touch_binding(ec, 0,
5752 touch_to_activate_binding,
5753 shell);
Daniel Stone325fc2d2012-05-30 16:31:58 +01005754 weston_compositor_add_axis_binding(ec, WL_POINTER_AXIS_VERTICAL_SCROLL,
5755 MODIFIER_SUPER | MODIFIER_ALT,
5756 surface_opacity_binding, NULL);
5757 weston_compositor_add_axis_binding(ec, WL_POINTER_AXIS_VERTICAL_SCROLL,
5758 MODIFIER_SUPER, zoom_axis_binding,
5759 NULL);
Tiago Vignatti0b52d482012-04-20 18:54:25 +03005760
5761 /* configurable bindings */
5762 mod = shell->binding_modifier;
Daniel Stone325fc2d2012-05-30 16:31:58 +01005763 weston_compositor_add_key_binding(ec, KEY_PAGEUP, mod,
5764 zoom_key_binding, NULL);
5765 weston_compositor_add_key_binding(ec, KEY_PAGEDOWN, mod,
5766 zoom_key_binding, NULL);
Kristian Høgsberg211b5172014-01-11 13:10:21 -08005767 weston_compositor_add_key_binding(ec, KEY_M, mod | MODIFIER_SHIFT,
5768 maximize_binding, NULL);
5769 weston_compositor_add_key_binding(ec, KEY_F, mod | MODIFIER_SHIFT,
5770 fullscreen_binding, NULL);
Daniel Stone325fc2d2012-05-30 16:31:58 +01005771 weston_compositor_add_button_binding(ec, BTN_LEFT, mod, move_binding,
5772 shell);
Neil Robertsaba0f252013-10-03 16:43:05 +01005773 weston_compositor_add_touch_binding(ec, mod, touch_move_binding, shell);
Daniel Stone325fc2d2012-05-30 16:31:58 +01005774 weston_compositor_add_button_binding(ec, BTN_MIDDLE, mod,
5775 resize_binding, shell);
Kristian Høgsberg0837fa92014-01-20 10:35:26 -08005776 weston_compositor_add_button_binding(ec, BTN_LEFT,
5777 mod | MODIFIER_SHIFT,
5778 resize_binding, shell);
Pekka Paalanen7bb65102013-05-22 18:03:04 +03005779
5780 if (ec->capabilities & WESTON_CAP_ROTATION_ANY)
5781 weston_compositor_add_button_binding(ec, BTN_RIGHT, mod,
5782 rotate_binding, NULL);
5783
Daniel Stone325fc2d2012-05-30 16:31:58 +01005784 weston_compositor_add_key_binding(ec, KEY_TAB, mod, switcher_binding,
5785 shell);
5786 weston_compositor_add_key_binding(ec, KEY_F9, mod, backlight_binding,
5787 ec);
5788 weston_compositor_add_key_binding(ec, KEY_BRIGHTNESSDOWN, 0,
5789 backlight_binding, ec);
5790 weston_compositor_add_key_binding(ec, KEY_F10, mod, backlight_binding,
5791 ec);
5792 weston_compositor_add_key_binding(ec, KEY_BRIGHTNESSUP, 0,
5793 backlight_binding, ec);
Daniel Stone325fc2d2012-05-30 16:31:58 +01005794 weston_compositor_add_key_binding(ec, KEY_K, mod,
5795 force_kill_binding, shell);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005796 weston_compositor_add_key_binding(ec, KEY_UP, mod,
5797 workspace_up_binding, shell);
5798 weston_compositor_add_key_binding(ec, KEY_DOWN, mod,
5799 workspace_down_binding, shell);
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02005800 weston_compositor_add_key_binding(ec, KEY_UP, mod | MODIFIER_SHIFT,
5801 workspace_move_surface_up_binding,
5802 shell);
5803 weston_compositor_add_key_binding(ec, KEY_DOWN, mod | MODIFIER_SHIFT,
5804 workspace_move_surface_down_binding,
5805 shell);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005806
Kristian Høgsbergd56ab4e2014-01-16 16:51:52 -08005807 if (shell->exposay_modifier)
5808 weston_compositor_add_modifier_binding(ec, shell->exposay_modifier,
5809 exposay_binding, shell);
Daniel Stonedf8133b2013-11-19 11:37:14 +01005810
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005811 /* Add bindings for mod+F[1-6] for workspace 1 to 6. */
5812 if (shell->workspaces.num > 1) {
5813 num_workspace_bindings = shell->workspaces.num;
5814 if (num_workspace_bindings > 6)
5815 num_workspace_bindings = 6;
5816 for (i = 0; i < num_workspace_bindings; i++)
5817 weston_compositor_add_key_binding(ec, KEY_F1 + i, mod,
5818 workspace_f_binding,
5819 shell);
5820 }
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005821
5822 /* Debug bindings */
5823 weston_compositor_add_key_binding(ec, KEY_SPACE, mod | MODIFIER_SHIFT,
5824 debug_binding, shell);
Tiago Vignatti0b52d482012-04-20 18:54:25 +03005825}
5826
Kristian Høgsberg1c562182011-05-02 22:09:20 -04005827WL_EXPORT int
Kristian Høgsbergcb4685b2013-02-20 15:37:49 -05005828module_init(struct weston_compositor *ec,
Ossama Othmana50e6e42013-05-14 09:48:26 -07005829 int *argc, char *argv[])
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05005830{
Kristian Høgsbergf4d2f232012-08-10 10:05:39 -04005831 struct weston_seat *seat;
Tiago Vignattibe143262012-04-16 17:31:41 +03005832 struct desktop_shell *shell;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005833 struct workspace **pws;
5834 unsigned int i;
Tiago Vignattib7dbbd62012-09-25 17:57:01 +03005835 struct wl_event_loop *loop;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04005836
Peter Huttererf3d62272013-08-08 11:57:05 +10005837 shell = zalloc(sizeof *shell);
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04005838 if (shell == NULL)
5839 return -1;
5840
Kristian Høgsberg75840622011-09-06 13:48:16 -04005841 shell->compositor = ec;
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04005842
5843 shell->destroy_listener.notify = shell_destroy;
5844 wl_signal_add(&ec->destroy_signal, &shell->destroy_listener);
Ander Conselvan de Oliveiraa4575632013-02-21 18:35:23 +02005845 shell->idle_listener.notify = idle_handler;
5846 wl_signal_add(&ec->idle_signal, &shell->idle_listener);
5847 shell->wake_listener.notify = wake_handler;
5848 wl_signal_add(&ec->wake_signal, &shell->wake_listener);
Kristian Høgsberg677a5f52013-12-04 11:00:19 -08005849
Kristian Høgsberg82a1d112012-07-19 14:02:00 -04005850 ec->shell_interface.shell = shell;
Tiago Vignattibc052c92012-04-19 16:18:18 +03005851 ec->shell_interface.create_shell_surface = create_shell_surface;
Jason Ekstranda7af7042013-10-12 22:38:11 -05005852 ec->shell_interface.get_primary_view = get_primary_view;
Tiago Vignattibc052c92012-04-19 16:18:18 +03005853 ec->shell_interface.set_toplevel = set_toplevel;
Tiago Vignatti491bac12012-05-18 16:37:43 -04005854 ec->shell_interface.set_transient = set_transient;
Kristian Høgsbergb810eb52013-02-12 20:07:05 -05005855 ec->shell_interface.set_fullscreen = set_fullscreen;
Tiago Vignattifb2adba2013-06-12 15:43:21 -03005856 ec->shell_interface.set_xwayland = set_xwayland;
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04005857 ec->shell_interface.move = surface_move;
Kristian Høgsbergc1693f22012-05-22 16:56:23 -04005858 ec->shell_interface.resize = surface_resize;
Giulio Camuffo62942ad2013-09-11 18:20:47 +02005859 ec->shell_interface.set_title = set_title;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05005860
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05005861 weston_layer_init(&shell->fullscreen_layer, &ec->cursor_layer.link);
5862 weston_layer_init(&shell->panel_layer, &shell->fullscreen_layer.link);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005863 weston_layer_init(&shell->background_layer, &shell->panel_layer.link);
5864 weston_layer_init(&shell->lock_layer, NULL);
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02005865 weston_layer_init(&shell->input_panel_layer, NULL);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005866
5867 wl_array_init(&shell->workspaces.array);
Jonas Ådahle9d22502012-08-29 22:13:01 +02005868 wl_list_init(&shell->workspaces.client_list);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05005869
Kristian Høgsberg677a5f52013-12-04 11:00:19 -08005870 if (input_panel_setup(shell) < 0)
5871 return -1;
5872
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04005873 shell_configuration(shell);
Pekka Paalanene955f1e2011-12-07 11:49:52 +02005874
Daniel Stonedf8133b2013-11-19 11:37:14 +01005875 shell->exposay.state_cur = EXPOSAY_LAYOUT_INACTIVE;
5876 shell->exposay.state_target = EXPOSAY_TARGET_CANCEL;
5877
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005878 for (i = 0; i < shell->workspaces.num; i++) {
5879 pws = wl_array_add(&shell->workspaces.array, sizeof *pws);
5880 if (pws == NULL)
5881 return -1;
5882
5883 *pws = workspace_create();
5884 if (*pws == NULL)
5885 return -1;
5886 }
5887 activate_workspace(shell, 0);
5888
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02005889 wl_list_init(&shell->workspaces.anim_sticky_list);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02005890 wl_list_init(&shell->workspaces.animation.link);
5891 shell->workspaces.animation.frame = animate_workspace_change_frame;
5892
Kristian Høgsberg919cddb2013-07-08 19:03:57 -04005893 if (wl_global_create(ec->wl_display, &wl_shell_interface, 1,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04005894 shell, bind_shell) == NULL)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05005895 return -1;
5896
Rafael Antognollie2a34552013-12-03 15:35:45 -02005897 if (wl_global_create(ec->wl_display, &xdg_shell_interface, 1,
5898 shell, bind_xdg_shell) == NULL)
5899 return -1;
5900
Kristian Høgsberg919cddb2013-07-08 19:03:57 -04005901 if (wl_global_create(ec->wl_display,
5902 &desktop_shell_interface, 2,
5903 shell, bind_desktop_shell) == NULL)
Kristian Høgsberg75840622011-09-06 13:48:16 -04005904 return -1;
5905
Kristian Høgsberg919cddb2013-07-08 19:03:57 -04005906 if (wl_global_create(ec->wl_display, &screensaver_interface, 1,
5907 shell, bind_screensaver) == NULL)
Pekka Paalanen6e168112011-11-24 11:34:05 +02005908 return -1;
5909
Kristian Høgsberg919cddb2013-07-08 19:03:57 -04005910 if (wl_global_create(ec->wl_display, &workspace_manager_interface, 1,
5911 shell, bind_workspace_manager) == NULL)
Jonas Ådahle9d22502012-08-29 22:13:01 +02005912 return -1;
5913
Kristian Høgsbergf03a6162012-01-17 11:07:42 -05005914 shell->child.deathstamp = weston_compositor_get_time();
Tiago Vignattib7dbbd62012-09-25 17:57:01 +03005915
Xiong Zhang6b481422013-10-23 13:58:32 +08005916 setup_output_destroy_handler(ec, shell);
5917
Tiago Vignattib7dbbd62012-09-25 17:57:01 +03005918 loop = wl_display_get_event_loop(ec->wl_display);
5919 wl_event_loop_add_idle(loop, launch_desktop_shell_process, shell);
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02005920
Ander Conselvan de Oliveira859e8852013-02-21 18:35:21 +02005921 shell->screensaver.timer =
5922 wl_event_loop_add_timer(loop, screensaver_timeout, shell);
5923
Jasper St. Pierrefaf27a92013-12-09 17:36:28 -05005924 wl_list_for_each(seat, &ec->seat_list, link) {
Kristian Høgsbergf4d2f232012-08-10 10:05:39 -04005925 create_pointer_focus_listener(seat);
Jasper St. Pierrefaf27a92013-12-09 17:36:28 -05005926 create_keyboard_focus_listener(seat);
5927 }
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04005928
Tiago Vignatti0b52d482012-04-20 18:54:25 +03005929 shell_add_bindings(ec, shell);
Kristian Høgsberg07937562011-04-12 17:25:42 -04005930
Pekka Paalanen79346ab2013-05-22 18:03:09 +03005931 shell_fade_init(shell);
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02005932
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05005933 return 0;
5934}