blob: 79e6518720e48b54db014733f7e9c01c167fc7f1 [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
Xiong Zhang6b481422013-10-23 13:58:32 +080059struct shell_output {
60 struct desktop_shell *shell;
61 struct weston_output *output;
62 struct wl_listener destroy_listener;
63 struct wl_list link;
64};
65
Kristian Høgsbergd2abb832011-11-23 10:52:40 -050066enum shell_surface_type {
Pekka Paalanen98262232011-12-01 10:42:22 +020067 SHELL_SURFACE_NONE,
Kristian Høgsbergd2abb832011-11-23 10:52:40 -050068 SHELL_SURFACE_TOPLEVEL,
Tiago Vignattifb2adba2013-06-12 15:43:21 -030069 SHELL_SURFACE_POPUP,
70 SHELL_SURFACE_XWAYLAND
Pekka Paalanen57da4a82011-11-23 16:42:16 +020071};
72
Scott Moreauff1db4a2012-04-17 19:06:18 -060073struct ping_timer {
74 struct wl_event_source *source;
Scott Moreauff1db4a2012-04-17 19:06:18 -060075 uint32_t serial;
76};
77
Philip Withnall648a4dd2013-11-25 18:01:44 +000078/*
79 * Surface stacking and ordering.
80 *
81 * This is handled using several linked lists of surfaces, organised into
82 * ‘layers’. The layers are ordered, and each of the surfaces in one layer are
83 * above all of the surfaces in the layer below. The set of layers is static and
84 * in the following order (top-most first):
85 * • Lock layer (only ever displayed on its own)
86 * • Cursor layer
87 * • Fullscreen layer
88 * • Panel layer
89 * • Input panel layer
90 * • Workspace layers
91 * • Background layer
92 *
93 * The list of layers may be manipulated to remove whole layers of surfaces from
94 * display. For example, when locking the screen, all layers except the lock
95 * layer are removed.
96 *
97 * A surface’s layer is modified on configuring the surface, in
98 * set_surface_type() (which is only called when the surface’s type change is
99 * _committed_). If a surface’s type changes (e.g. when making a window
100 * fullscreen) its layer changes too.
101 *
102 * In order to allow popup and transient surfaces to be correctly stacked above
103 * their parent surfaces, each surface tracks both its parent surface, and a
104 * linked list of its children. When a surface’s layer is updated, so are the
105 * layers of its children. Note that child surfaces are *not* the same as
106 * subsurfaces — child/parent surfaces are purely for maintaining stacking
107 * order.
108 *
109 * The children_link list of siblings of a surface (i.e. those surfaces which
110 * have the same parent) only contains weston_surfaces which have a
111 * shell_surface. Stacking is not implemented for non-shell_surface
112 * weston_surfaces. This means that the following implication does *not* hold:
113 * (shsurf->parent != NULL) ⇒ !wl_list_is_empty(shsurf->children_link)
114 */
115
Pekka Paalanen56cdea92011-11-23 16:14:12 +0200116struct shell_surface {
Jason Ekstrand651f00e2013-06-14 10:07:54 -0500117 struct wl_resource *resource;
118 struct wl_signal destroy_signal;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200119
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500120 struct weston_surface *surface;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500121 struct weston_view *view;
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600122 int32_t last_width, last_height;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200123 struct wl_listener surface_destroy_listener;
Kristian Høgsberg8150b192012-06-27 10:22:58 -0400124 struct weston_surface *parent;
Philip Withnall648a4dd2013-11-25 18:01:44 +0000125 struct wl_list children_list; /* child surfaces of this one */
126 struct wl_list children_link; /* sibling surfaces of this one */
Tiago Vignattibe143262012-04-16 17:31:41 +0300127 struct desktop_shell *shell;
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200128
Kristian Høgsbergc8f8dd82013-12-05 23:20:33 -0800129 enum shell_surface_type type;
Kristian Høgsberge7afd912012-05-02 09:47:44 -0400130 char *title, *class;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500131 int32_t saved_x, saved_y;
Rafael Antognolli3c4e3f72013-12-03 15:35:46 -0200132 int32_t saved_width, saved_height;
Alex Wu4539b082012-03-01 12:57:46 +0800133 bool saved_position_valid;
Rafael Antognolli3c4e3f72013-12-03 15:35:46 -0200134 bool saved_size_valid;
Alex Wu7bcb8bd2012-04-27 09:07:24 +0800135 bool saved_rotation_valid;
Kristian Høgsbergc85f1d42013-10-24 16:52:00 -0700136 int unresponsive, grabbed;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100137
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500138 struct {
Pekka Paalanen460099f2012-01-20 16:48:25 +0200139 struct weston_transform transform;
Kristian Høgsberg765e27b2012-01-27 13:36:13 -0500140 struct weston_matrix rotation;
Pekka Paalanen460099f2012-01-20 16:48:25 +0200141 } rotation;
142
143 struct {
Giulio Camuffo5085a752013-03-25 21:42:45 +0100144 struct wl_list grab_link;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500145 int32_t x, y;
Giulio Camuffo5085a752013-03-25 21:42:45 +0100146 struct shell_seat *shseat;
Kristian Høgsberg3730f362012-04-13 12:40:07 -0400147 uint32_t serial;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500148 } popup;
149
Alex Wu4539b082012-03-01 12:57:46 +0800150 struct {
Tiago Vignatti52e598c2012-05-07 15:23:08 +0300151 int32_t x, y;
Tiago Vignatti491bac12012-05-18 16:37:43 -0400152 uint32_t flags;
Tiago Vignatti52e598c2012-05-07 15:23:08 +0300153 } transient;
154
155 struct {
Alex Wu4539b082012-03-01 12:57:46 +0800156 enum wl_shell_surface_fullscreen_method type;
157 struct weston_transform transform; /* matrix from x, y */
158 uint32_t framerate;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500159 struct weston_view *black_view;
Alex Wu4539b082012-03-01 12:57:46 +0800160 } fullscreen;
161
Scott Moreauff1db4a2012-04-17 19:06:18 -0600162 struct ping_timer *ping_timer;
163
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200164 struct weston_transform workspace_transform;
165
Kristian Høgsberg1cbf3262012-02-17 23:49:07 -0500166 struct weston_output *fullscreen_output;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500167 struct weston_output *output;
Rafael Antognolli65f98d82013-12-03 15:35:47 -0200168 struct weston_output *recommended_output;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100169 struct wl_list link;
Kristian Høgsberga61ca062012-05-22 16:05:52 -0400170
171 const struct weston_shell_client *client;
Rafael Antognolli03b16592013-12-03 15:35:42 -0200172
173 struct {
174 bool maximized;
175 bool fullscreen;
Rafael Antognollied207b42013-12-03 15:35:43 -0200176 bool relative;
Rafael Antognolli03b16592013-12-03 15:35:42 -0200177 } state, next_state; /* surface states */
178 bool state_changed;
Pekka Paalanen56cdea92011-11-23 16:14:12 +0200179};
180
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300181struct shell_grab {
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -0400182 struct weston_pointer_grab grab;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300183 struct shell_surface *shsurf;
184 struct wl_listener shsurf_destroy_listener;
185};
186
Rusty Lynch1084da52013-08-15 09:10:08 -0700187struct shell_touch_grab {
188 struct weston_touch_grab grab;
189 struct shell_surface *shsurf;
190 struct wl_listener shsurf_destroy_listener;
191 struct weston_touch *touch;
192};
193
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300194struct weston_move_grab {
195 struct shell_grab base;
Daniel Stone103db7f2012-05-08 17:17:55 +0100196 wl_fixed_t dx, dy;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500197};
198
Rusty Lynch1084da52013-08-15 09:10:08 -0700199struct weston_touch_move_grab {
200 struct shell_touch_grab base;
201 wl_fixed_t dx, dy;
202};
203
Pekka Paalanen460099f2012-01-20 16:48:25 +0200204struct rotate_grab {
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300205 struct shell_grab base;
Kristian Høgsberg765e27b2012-01-27 13:36:13 -0500206 struct weston_matrix rotation;
Pekka Paalanen460099f2012-01-20 16:48:25 +0200207 struct {
John Kåre Alsaker490d02a2012-09-30 02:57:21 +0200208 float x;
209 float y;
Pekka Paalanen460099f2012-01-20 16:48:25 +0200210 } center;
211};
212
Giulio Camuffo5085a752013-03-25 21:42:45 +0100213struct shell_seat {
214 struct weston_seat *seat;
215 struct wl_listener seat_destroy_listener;
216
217 struct {
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -0400218 struct weston_pointer_grab grab;
Giulio Camuffo5085a752013-03-25 21:42:45 +0100219 struct wl_list surfaces_list;
220 struct wl_client *client;
221 int32_t initial_up;
222 } popup_grab;
223};
224
Emilio Pozuelo Monfort1a26f1b2014-01-07 16:41:40 +0100225void
226set_alpha_if_fullscreen(struct shell_surface *shsurf)
227{
228 if (shsurf && shsurf->state.fullscreen)
229 shsurf->fullscreen.black_view->alpha = 0.25;
230}
231
Alex Wubd3354b2012-04-17 17:20:49 +0800232static struct desktop_shell *
233shell_surface_get_shell(struct shell_surface *shsurf);
234
Kristian Høgsberg0c369032013-02-14 21:31:44 -0500235static void
Kristian Høgsberge3148752013-05-06 23:19:49 -0400236surface_rotate(struct shell_surface *surface, struct weston_seat *seat);
Kristian Høgsberg0c369032013-02-14 21:31:44 -0500237
Pekka Paalanen79346ab2013-05-22 18:03:09 +0300238static void
239shell_fade_startup(struct desktop_shell *shell);
240
Philip Withnallbecb77e2013-11-25 18:01:30 +0000241static struct shell_seat *
242get_shell_seat(struct weston_seat *seat);
243
Philip Withnall648a4dd2013-11-25 18:01:44 +0000244static void
245shell_surface_update_child_surface_layers(struct shell_surface *shsurf);
246
Alex Wubd3354b2012-04-17 17:20:49 +0800247static bool
Rafael Antognollie2a34552013-12-03 15:35:45 -0200248shell_surface_is_wl_shell_surface(struct shell_surface *shsurf);
249
250static bool
251shell_surface_is_xdg_surface(struct shell_surface *shsurf);
252
253static bool
254shell_surface_is_xdg_popup(struct shell_surface *shsurf);
255
256static void
257shell_surface_set_parent(struct shell_surface *shsurf,
258 struct weston_surface *parent);
259
260static bool
Alex Wubd3354b2012-04-17 17:20:49 +0800261shell_surface_is_top_fullscreen(struct shell_surface *shsurf)
262{
263 struct desktop_shell *shell;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500264 struct weston_view *top_fs_ev;
Alex Wubd3354b2012-04-17 17:20:49 +0800265
266 shell = shell_surface_get_shell(shsurf);
Quentin Glidicc0d79ce2013-01-29 14:16:13 +0100267
Jason Ekstranda7af7042013-10-12 22:38:11 -0500268 if (wl_list_empty(&shell->fullscreen_layer.view_list))
Alex Wubd3354b2012-04-17 17:20:49 +0800269 return false;
270
Jason Ekstranda7af7042013-10-12 22:38:11 -0500271 top_fs_ev = container_of(shell->fullscreen_layer.view_list.next,
272 struct weston_view,
Alex Wubd3354b2012-04-17 17:20:49 +0800273 layer_link);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500274 return (shsurf == get_shell_surface(top_fs_ev->surface));
Alex Wubd3354b2012-04-17 17:20:49 +0800275}
276
Kristian Høgsberg6af8eb92012-01-25 16:57:11 -0500277static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400278destroy_shell_grab_shsurf(struct wl_listener *listener, void *data)
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300279{
280 struct shell_grab *grab;
281
282 grab = container_of(listener, struct shell_grab,
283 shsurf_destroy_listener);
284
285 grab->shsurf = NULL;
286}
287
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800288struct weston_view *
Jason Ekstranda7af7042013-10-12 22:38:11 -0500289get_default_view(struct weston_surface *surface)
290{
291 struct shell_surface *shsurf;
292 struct weston_view *view;
293
294 if (!surface || wl_list_empty(&surface->views))
295 return NULL;
296
297 shsurf = get_shell_surface(surface);
298 if (shsurf)
299 return shsurf->view;
300
301 wl_list_for_each(view, &surface->views, surface_link)
302 if (weston_view_is_mapped(view))
303 return view;
304
305 return container_of(surface->views.next, struct weston_view, surface_link);
306}
307
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300308static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -0400309popup_grab_end(struct weston_pointer *pointer);
Kristian Høgsberg57e09072012-10-30 14:07:27 -0400310
311static void
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300312shell_grab_start(struct shell_grab *grab,
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -0400313 const struct weston_pointer_grab_interface *interface,
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300314 struct shell_surface *shsurf,
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -0400315 struct weston_pointer *pointer,
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300316 enum desktop_shell_cursor cursor)
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300317{
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300318 struct desktop_shell *shell = shsurf->shell;
319
Kristian Høgsberg57e09072012-10-30 14:07:27 -0400320 popup_grab_end(pointer);
321
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300322 grab->grab.interface = interface;
323 grab->shsurf = shsurf;
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400324 grab->shsurf_destroy_listener.notify = destroy_shell_grab_shsurf;
Jason Ekstrand651f00e2013-06-14 10:07:54 -0500325 wl_signal_add(&shsurf->destroy_signal,
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400326 &grab->shsurf_destroy_listener);
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300327
Kristian Høgsbergc85f1d42013-10-24 16:52:00 -0700328 shsurf->grabbed = 1;
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -0400329 weston_pointer_start_grab(pointer, &grab->grab);
Kristian Høgsbergc9974a02013-07-03 19:24:57 -0400330 if (shell->child.desktop_shell) {
331 desktop_shell_send_grab_cursor(shell->child.desktop_shell,
332 cursor);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500333 weston_pointer_set_focus(pointer,
334 get_default_view(shell->grab_surface),
Kristian Høgsbergc9974a02013-07-03 19:24:57 -0400335 wl_fixed_from_int(0),
336 wl_fixed_from_int(0));
337 }
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300338}
339
340static void
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300341shell_grab_end(struct shell_grab *grab)
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300342{
Kristian Høgsbergc85f1d42013-10-24 16:52:00 -0700343 if (grab->shsurf) {
Kristian Høgsberg47b5dca2012-06-07 18:08:04 -0400344 wl_list_remove(&grab->shsurf_destroy_listener.link);
Kristian Høgsbergc85f1d42013-10-24 16:52:00 -0700345 grab->shsurf->grabbed = 0;
346 }
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300347
Kristian Høgsberg9e5d7d12013-07-22 16:31:53 -0700348 weston_pointer_end_grab(grab->grab.pointer);
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300349}
350
351static void
Rusty Lynch1084da52013-08-15 09:10:08 -0700352shell_touch_grab_start(struct shell_touch_grab *grab,
353 const struct weston_touch_grab_interface *interface,
354 struct shell_surface *shsurf,
355 struct weston_touch *touch)
356{
357 struct desktop_shell *shell = shsurf->shell;
358
359 grab->grab.interface = interface;
360 grab->shsurf = shsurf;
361 grab->shsurf_destroy_listener.notify = destroy_shell_grab_shsurf;
362 wl_signal_add(&shsurf->destroy_signal,
363 &grab->shsurf_destroy_listener);
364
365 grab->touch = touch;
Kristian Høgsbergc85f1d42013-10-24 16:52:00 -0700366 shsurf->grabbed = 1;
Rusty Lynch1084da52013-08-15 09:10:08 -0700367
368 weston_touch_start_grab(touch, &grab->grab);
369 if (shell->child.desktop_shell)
Jason Ekstranda7af7042013-10-12 22:38:11 -0500370 weston_touch_set_focus(touch->seat,
371 get_default_view(shell->grab_surface));
Rusty Lynch1084da52013-08-15 09:10:08 -0700372}
373
374static void
375shell_touch_grab_end(struct shell_touch_grab *grab)
376{
Kristian Høgsbergc85f1d42013-10-24 16:52:00 -0700377 if (grab->shsurf) {
Rusty Lynch1084da52013-08-15 09:10:08 -0700378 wl_list_remove(&grab->shsurf_destroy_listener.link);
Kristian Høgsbergc85f1d42013-10-24 16:52:00 -0700379 grab->shsurf->grabbed = 0;
380 }
Rusty Lynch1084da52013-08-15 09:10:08 -0700381
382 weston_touch_end_grab(grab->touch);
383}
384
385static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500386center_on_output(struct weston_view *view,
Alex Wu4539b082012-03-01 12:57:46 +0800387 struct weston_output *output);
388
Daniel Stone496ca172012-05-30 16:31:42 +0100389static enum weston_keyboard_modifier
Tiago Vignatti0b52d482012-04-20 18:54:25 +0300390get_modifier(char *modifier)
391{
392 if (!modifier)
393 return MODIFIER_SUPER;
394
395 if (!strcmp("ctrl", modifier))
396 return MODIFIER_CTRL;
397 else if (!strcmp("alt", modifier))
398 return MODIFIER_ALT;
399 else if (!strcmp("super", modifier))
400 return MODIFIER_SUPER;
401 else
402 return MODIFIER_SUPER;
403}
404
Juan Zhaoe10d2792012-04-25 19:09:52 +0800405static enum animation_type
406get_animation_type(char *animation)
407{
Juan Zhaoe10d2792012-04-25 19:09:52 +0800408 if (!strcmp("zoom", animation))
409 return ANIMATION_ZOOM;
410 else if (!strcmp("fade", animation))
411 return ANIMATION_FADE;
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100412 else if (!strcmp("dim-layer", animation))
413 return ANIMATION_DIM_LAYER;
Juan Zhaoe10d2792012-04-25 19:09:52 +0800414 else
415 return ANIMATION_NONE;
416}
417
Alex Wu4539b082012-03-01 12:57:46 +0800418static void
Kristian Høgsberg14e438c2013-05-26 21:48:14 -0400419shell_configuration(struct desktop_shell *shell)
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200420{
Kristian Høgsberg673a8892013-05-23 21:40:56 -0400421 struct weston_config_section *section;
422 int duration;
423 char *s;
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200424
Kristian Høgsberg673a8892013-05-23 21:40:56 -0400425 section = weston_config_get_section(shell->compositor->config,
426 "screensaver", NULL, NULL);
427 weston_config_section_get_string(section,
428 "path", &shell->screensaver.path, NULL);
429 weston_config_section_get_int(section, "duration", &duration, 60);
Ander Conselvan de Oliveira859e8852013-02-21 18:35:21 +0200430 shell->screensaver.duration = duration * 1000;
Kristian Høgsberg673a8892013-05-23 21:40:56 -0400431
432 section = weston_config_get_section(shell->compositor->config,
433 "shell", NULL, NULL);
434 weston_config_section_get_string(section,
Emilio Pozuelo Monfort8a81b832013-12-02 12:53:32 +0100435 "client", &s, LIBEXECDIR "/" WESTON_SHELL_CLIENT);
Emilio Pozuelo Monfort46ce7982013-11-20 13:22:29 +0100436 shell->client = s;
437 weston_config_section_get_string(section,
Kristian Høgsberg673a8892013-05-23 21:40:56 -0400438 "binding-modifier", &s, "super");
439 shell->binding_modifier = get_modifier(s);
Quentin Glidic8418c292013-06-18 09:11:03 +0200440 free(s);
Kristian Høgsbergd56ab4e2014-01-16 16:51:52 -0800441
442 weston_config_section_get_string(section,
443 "exposay-modifier", &s, "none");
444 if (strcmp(s, "none") == 0)
445 shell->exposay_modifier = 0;
446 else
447 shell->exposay_modifier = get_modifier(s);
448 free(s);
449
Kristian Høgsberg673a8892013-05-23 21:40:56 -0400450 weston_config_section_get_string(section, "animation", &s, "none");
451 shell->win_animation_type = get_animation_type(s);
Quentin Glidic8418c292013-06-18 09:11:03 +0200452 free(s);
Kristian Høgsberg724c8d92013-10-16 11:38:24 -0700453 weston_config_section_get_string(section,
454 "startup-animation", &s, "fade");
455 shell->startup_animation_type = get_animation_type(s);
456 free(s);
Kristian Høgsberg912e0a12013-10-30 08:59:55 -0700457 if (shell->startup_animation_type == ANIMATION_ZOOM)
458 shell->startup_animation_type = ANIMATION_NONE;
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100459 weston_config_section_get_string(section, "focus-animation", &s, "none");
460 shell->focus_animation_type = get_animation_type(s);
461 free(s);
Kristian Høgsberg673a8892013-05-23 21:40:56 -0400462 weston_config_section_get_uint(section, "num-workspaces",
463 &shell->workspaces.num,
464 DEFAULT_NUM_WORKSPACES);
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200465}
466
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800467struct weston_output *
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100468get_default_output(struct weston_compositor *compositor)
469{
470 return container_of(compositor->output_list.next,
471 struct weston_output, link);
472}
473
474
475/* no-op func for checking focus surface */
476static void
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600477focus_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100478{
479}
480
481static struct focus_surface *
482get_focus_surface(struct weston_surface *surface)
483{
484 if (surface->configure == focus_surface_configure)
485 return surface->configure_private;
486 else
487 return NULL;
488}
489
490static bool
491is_focus_surface (struct weston_surface *es)
492{
493 return (es->configure == focus_surface_configure);
494}
495
496static bool
497is_focus_view (struct weston_view *view)
498{
499 return is_focus_surface (view->surface);
500}
501
502static struct focus_surface *
503create_focus_surface(struct weston_compositor *ec,
504 struct weston_output *output)
505{
506 struct focus_surface *fsurf = NULL;
507 struct weston_surface *surface = NULL;
508
509 fsurf = malloc(sizeof *fsurf);
510 if (!fsurf)
511 return NULL;
512
513 fsurf->surface = weston_surface_create(ec);
514 surface = fsurf->surface;
515 if (surface == NULL) {
516 free(fsurf);
517 return NULL;
518 }
519
520 surface->configure = focus_surface_configure;
521 surface->output = output;
522 surface->configure_private = fsurf;
523
524 fsurf->view = weston_view_create (surface);
Emilio Pozuelo Monfortda644262013-11-19 11:37:19 +0100525 fsurf->view->output = output;
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100526
Jason Ekstrand5c11a332013-12-04 20:32:03 -0600527 weston_surface_set_size(surface, output->width, output->height);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600528 weston_view_set_position(fsurf->view, output->x, output->y);
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100529 weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1.0);
530 pixman_region32_fini(&surface->opaque);
531 pixman_region32_init_rect(&surface->opaque, output->x, output->y,
532 output->width, output->height);
533 pixman_region32_fini(&surface->input);
534 pixman_region32_init(&surface->input);
535
536 wl_list_init(&fsurf->workspace_transform.link);
537
538 return fsurf;
539}
540
541static void
542focus_surface_destroy(struct focus_surface *fsurf)
543{
544 weston_surface_destroy(fsurf->surface);
545 free(fsurf);
546}
547
548static void
549focus_animation_done(struct weston_view_animation *animation, void *data)
550{
551 struct workspace *ws = data;
552
553 ws->focus_animation = NULL;
554}
555
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200556static void
Jonas Ådahl04769742012-06-13 00:01:24 +0200557focus_state_destroy(struct focus_state *state)
558{
559 wl_list_remove(&state->seat_destroy_listener.link);
560 wl_list_remove(&state->surface_destroy_listener.link);
561 free(state);
562}
563
564static void
565focus_state_seat_destroy(struct wl_listener *listener, void *data)
566{
567 struct focus_state *state = container_of(listener,
568 struct focus_state,
569 seat_destroy_listener);
570
571 wl_list_remove(&state->link);
572 focus_state_destroy(state);
573}
574
575static void
576focus_state_surface_destroy(struct wl_listener *listener, void *data)
577{
578 struct focus_state *state = container_of(listener,
579 struct focus_state,
Kristian Høgsbergb8e0d0f2012-07-31 10:30:26 -0400580 surface_destroy_listener);
Kristian Høgsberge3778222012-07-31 17:29:30 -0400581 struct desktop_shell *shell;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500582 struct weston_surface *main_surface, *next;
583 struct weston_view *view;
Jonas Ådahl04769742012-06-13 00:01:24 +0200584
Pekka Paalanen01388e22013-04-25 13:57:44 +0300585 main_surface = weston_surface_get_main_surface(state->keyboard_focus);
586
Kristian Høgsberge3778222012-07-31 17:29:30 -0400587 next = NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500588 wl_list_for_each(view, &state->ws->layer.view_list, layer_link) {
589 if (view->surface == main_surface)
Kristian Høgsberge3778222012-07-31 17:29:30 -0400590 continue;
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100591 if (is_focus_view(view))
592 continue;
Kristian Høgsberge3778222012-07-31 17:29:30 -0400593
Jason Ekstranda7af7042013-10-12 22:38:11 -0500594 next = view->surface;
Kristian Høgsberge3778222012-07-31 17:29:30 -0400595 break;
596 }
597
Pekka Paalanen01388e22013-04-25 13:57:44 +0300598 /* if the focus was a sub-surface, activate its main surface */
599 if (main_surface != state->keyboard_focus)
600 next = main_surface;
601
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100602 shell = state->seat->compositor->shell_interface.shell;
Kristian Høgsberge3778222012-07-31 17:29:30 -0400603 if (next) {
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100604 state->keyboard_focus = NULL;
Kristian Høgsberge3778222012-07-31 17:29:30 -0400605 activate(shell, next, state->seat);
606 } else {
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100607 if (shell->focus_animation_type == ANIMATION_DIM_LAYER) {
608 if (state->ws->focus_animation)
609 weston_view_animation_destroy(state->ws->focus_animation);
610
611 state->ws->focus_animation = weston_fade_run(
612 state->ws->fsurf_front->view,
613 state->ws->fsurf_front->view->alpha, 0.0, 300,
614 focus_animation_done, state->ws);
615 }
616
Kristian Høgsberge3778222012-07-31 17:29:30 -0400617 wl_list_remove(&state->link);
618 focus_state_destroy(state);
619 }
Jonas Ådahl04769742012-06-13 00:01:24 +0200620}
621
622static struct focus_state *
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400623focus_state_create(struct weston_seat *seat, struct workspace *ws)
Jonas Ådahl04769742012-06-13 00:01:24 +0200624{
Jonas Ådahl04769742012-06-13 00:01:24 +0200625 struct focus_state *state;
Jonas Ådahl04769742012-06-13 00:01:24 +0200626
627 state = malloc(sizeof *state);
628 if (state == NULL)
629 return NULL;
630
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100631 state->keyboard_focus = NULL;
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400632 state->ws = ws;
Jonas Ådahl04769742012-06-13 00:01:24 +0200633 state->seat = seat;
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400634 wl_list_insert(&ws->focus_list, &state->link);
Jonas Ådahl04769742012-06-13 00:01:24 +0200635
636 state->seat_destroy_listener.notify = focus_state_seat_destroy;
637 state->surface_destroy_listener.notify = focus_state_surface_destroy;
Kristian Høgsberg49124542013-05-06 22:27:40 -0400638 wl_signal_add(&seat->destroy_signal,
Jonas Ådahl04769742012-06-13 00:01:24 +0200639 &state->seat_destroy_listener);
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400640 wl_list_init(&state->surface_destroy_listener.link);
Jonas Ådahl04769742012-06-13 00:01:24 +0200641
642 return state;
643}
644
Jonas Ådahl8538b222012-08-29 22:13:03 +0200645static struct focus_state *
646ensure_focus_state(struct desktop_shell *shell, struct weston_seat *seat)
647{
648 struct workspace *ws = get_current_workspace(shell);
649 struct focus_state *state;
650
651 wl_list_for_each(state, &ws->focus_list, link)
652 if (state->seat == seat)
653 break;
654
655 if (&state->link == &ws->focus_list)
656 state = focus_state_create(seat, ws);
657
658 return state;
659}
660
Jonas Ådahl04769742012-06-13 00:01:24 +0200661static void
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400662restore_focus_state(struct desktop_shell *shell, struct workspace *ws)
Jonas Ådahl04769742012-06-13 00:01:24 +0200663{
664 struct focus_state *state, *next;
Kristian Høgsbergfe7aa902013-05-08 09:54:37 -0400665 struct weston_surface *surface;
Jonas Ådahl04769742012-06-13 00:01:24 +0200666
667 wl_list_for_each_safe(state, next, &ws->focus_list, link) {
Kristian Høgsbergfe7aa902013-05-08 09:54:37 -0400668 surface = state->keyboard_focus;
Jonas Ådahl56899442012-08-29 22:12:59 +0200669
Kristian Høgsberge3148752013-05-06 23:19:49 -0400670 weston_keyboard_set_focus(state->seat->keyboard, surface);
Jonas Ådahl04769742012-06-13 00:01:24 +0200671 }
672}
673
674static void
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200675replace_focus_state(struct desktop_shell *shell, struct workspace *ws,
676 struct weston_seat *seat)
677{
678 struct focus_state *state;
Kristian Høgsbergfe7aa902013-05-08 09:54:37 -0400679 struct weston_surface *surface;
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200680
681 wl_list_for_each(state, &ws->focus_list, link) {
682 if (state->seat == seat) {
Kristian Høgsberge3148752013-05-06 23:19:49 -0400683 surface = seat->keyboard->focus;
Jason Ekstrand651f00e2013-06-14 10:07:54 -0500684 state->keyboard_focus = surface;
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200685 return;
686 }
687 }
688}
689
690static void
691drop_focus_state(struct desktop_shell *shell, struct workspace *ws,
692 struct weston_surface *surface)
693{
694 struct focus_state *state;
695
696 wl_list_for_each(state, &ws->focus_list, link)
697 if (state->keyboard_focus == surface)
698 state->keyboard_focus = NULL;
699}
700
701static void
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100702animate_focus_change(struct desktop_shell *shell, struct workspace *ws,
703 struct weston_view *from, struct weston_view *to)
704{
705 struct weston_output *output;
706 bool focus_surface_created = false;
707
708 /* FIXME: Only support dim animation using two layers */
709 if (from == to || shell->focus_animation_type != ANIMATION_DIM_LAYER)
710 return;
711
712 output = get_default_output(shell->compositor);
713 if (ws->fsurf_front == NULL && (from || to)) {
714 ws->fsurf_front = create_focus_surface(shell->compositor, output);
715 ws->fsurf_back = create_focus_surface(shell->compositor, output);
716 ws->fsurf_front->view->alpha = 0.0;
717 ws->fsurf_back->view->alpha = 0.0;
718 focus_surface_created = true;
719 } else {
720 wl_list_remove(&ws->fsurf_front->view->layer_link);
721 wl_list_remove(&ws->fsurf_back->view->layer_link);
722 }
723
724 if (ws->focus_animation) {
725 weston_view_animation_destroy(ws->focus_animation);
726 ws->focus_animation = NULL;
727 }
728
729 if (to)
730 wl_list_insert(&to->layer_link,
731 &ws->fsurf_front->view->layer_link);
732 else if (from)
733 wl_list_insert(&ws->layer.view_list,
734 &ws->fsurf_front->view->layer_link);
735
736 if (focus_surface_created) {
737 ws->focus_animation = weston_fade_run(
738 ws->fsurf_front->view,
739 ws->fsurf_front->view->alpha, 0.6, 300,
740 focus_animation_done, ws);
741 } else if (from) {
742 wl_list_insert(&from->layer_link,
743 &ws->fsurf_back->view->layer_link);
744 ws->focus_animation = weston_stable_fade_run(
745 ws->fsurf_front->view, 0.0,
746 ws->fsurf_back->view, 0.6,
747 focus_animation_done, ws);
748 } else if (to) {
749 wl_list_insert(&ws->layer.view_list,
750 &ws->fsurf_back->view->layer_link);
751 ws->focus_animation = weston_stable_fade_run(
752 ws->fsurf_front->view, 0.0,
753 ws->fsurf_back->view, 0.6,
754 focus_animation_done, ws);
755 }
756}
757
758static void
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200759workspace_destroy(struct workspace *ws)
760{
Jonas Ådahl04769742012-06-13 00:01:24 +0200761 struct focus_state *state, *next;
762
763 wl_list_for_each_safe(state, next, &ws->focus_list, link)
764 focus_state_destroy(state);
765
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100766 if (ws->fsurf_front)
767 focus_surface_destroy(ws->fsurf_front);
768 if (ws->fsurf_back)
769 focus_surface_destroy(ws->fsurf_back);
770
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200771 free(ws);
772}
773
Jonas Ådahl04769742012-06-13 00:01:24 +0200774static void
775seat_destroyed(struct wl_listener *listener, void *data)
776{
777 struct weston_seat *seat = data;
778 struct focus_state *state, *next;
779 struct workspace *ws = container_of(listener,
780 struct workspace,
781 seat_destroyed_listener);
782
783 wl_list_for_each_safe(state, next, &ws->focus_list, link)
784 if (state->seat == seat)
785 wl_list_remove(&state->link);
786}
787
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200788static struct workspace *
789workspace_create(void)
790{
791 struct workspace *ws = malloc(sizeof *ws);
792 if (ws == NULL)
793 return NULL;
794
795 weston_layer_init(&ws->layer, NULL);
796
Jonas Ådahl04769742012-06-13 00:01:24 +0200797 wl_list_init(&ws->focus_list);
798 wl_list_init(&ws->seat_destroyed_listener.link);
799 ws->seat_destroyed_listener.notify = seat_destroyed;
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100800 ws->fsurf_front = NULL;
801 ws->fsurf_back = NULL;
802 ws->focus_animation = NULL;
Jonas Ådahl04769742012-06-13 00:01:24 +0200803
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200804 return ws;
805}
806
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200807static int
808workspace_is_empty(struct workspace *ws)
809{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500810 return wl_list_empty(&ws->layer.view_list);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200811}
812
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200813static struct workspace *
814get_workspace(struct desktop_shell *shell, unsigned int index)
815{
816 struct workspace **pws = shell->workspaces.array.data;
Philipp Brüschweiler067abf62012-09-01 16:03:05 +0200817 assert(index < shell->workspaces.num);
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200818 pws += index;
819 return *pws;
820}
821
Kristian Høgsberg1ef23132013-12-04 00:20:01 -0800822struct workspace *
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200823get_current_workspace(struct desktop_shell *shell)
824{
825 return get_workspace(shell, shell->workspaces.current);
826}
827
828static void
829activate_workspace(struct desktop_shell *shell, unsigned int index)
830{
831 struct workspace *ws;
832
833 ws = get_workspace(shell, index);
834 wl_list_insert(&shell->panel_layer.link, &ws->layer.link);
835
836 shell->workspaces.current = index;
837}
838
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200839static unsigned int
840get_output_height(struct weston_output *output)
841{
842 return abs(output->region.extents.y1 - output->region.extents.y2);
843}
844
845static void
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100846view_translate(struct workspace *ws, struct weston_view *view, double d)
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200847{
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200848 struct weston_transform *transform;
849
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100850 if (is_focus_view(view)) {
851 struct focus_surface *fsurf = get_focus_surface(view->surface);
852 transform = &fsurf->workspace_transform;
853 } else {
854 struct shell_surface *shsurf = get_shell_surface(view->surface);
855 transform = &shsurf->workspace_transform;
856 }
857
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200858 if (wl_list_empty(&transform->link))
Jason Ekstranda7af7042013-10-12 22:38:11 -0500859 wl_list_insert(view->geometry.transformation_list.prev,
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100860 &transform->link);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200861
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100862 weston_matrix_init(&transform->matrix);
863 weston_matrix_translate(&transform->matrix,
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200864 0.0, d, 0.0);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500865 weston_view_geometry_dirty(view);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200866}
867
868static void
869workspace_translate_out(struct workspace *ws, double fraction)
870{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500871 struct weston_view *view;
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200872 unsigned int height;
873 double d;
874
Jason Ekstranda7af7042013-10-12 22:38:11 -0500875 wl_list_for_each(view, &ws->layer.view_list, layer_link) {
876 height = get_output_height(view->surface->output);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200877 d = height * fraction;
878
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100879 view_translate(ws, view, d);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200880 }
881}
882
883static void
884workspace_translate_in(struct workspace *ws, double fraction)
885{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500886 struct weston_view *view;
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200887 unsigned int height;
888 double d;
889
Jason Ekstranda7af7042013-10-12 22:38:11 -0500890 wl_list_for_each(view, &ws->layer.view_list, layer_link) {
891 height = get_output_height(view->surface->output);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200892
893 if (fraction > 0)
894 d = -(height - height * fraction);
895 else
896 d = height + height * fraction;
897
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100898 view_translate(ws, view, d);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200899 }
900}
901
902static void
Jonas Ådahle9d22502012-08-29 22:13:01 +0200903broadcast_current_workspace_state(struct desktop_shell *shell)
904{
Kristian Høgsberg2e3c3962013-09-11 12:00:47 -0700905 struct wl_resource *resource;
Jonas Ådahle9d22502012-08-29 22:13:01 +0200906
Kristian Høgsberg2e3c3962013-09-11 12:00:47 -0700907 wl_resource_for_each(resource, &shell->workspaces.client_list)
908 workspace_manager_send_state(resource,
Jonas Ådahle9d22502012-08-29 22:13:01 +0200909 shell->workspaces.current,
910 shell->workspaces.num);
911}
912
913static void
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200914reverse_workspace_change_animation(struct desktop_shell *shell,
915 unsigned int index,
916 struct workspace *from,
917 struct workspace *to)
918{
919 shell->workspaces.current = index;
920
921 shell->workspaces.anim_to = to;
922 shell->workspaces.anim_from = from;
923 shell->workspaces.anim_dir = -1 * shell->workspaces.anim_dir;
924 shell->workspaces.anim_timestamp = 0;
925
Scott Moreau4272e632012-08-13 09:58:41 -0600926 weston_compositor_schedule_repaint(shell->compositor);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200927}
928
929static void
930workspace_deactivate_transforms(struct workspace *ws)
931{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500932 struct weston_view *view;
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100933 struct weston_transform *transform;
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200934
Jason Ekstranda7af7042013-10-12 22:38:11 -0500935 wl_list_for_each(view, &ws->layer.view_list, layer_link) {
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +0100936 if (is_focus_view(view)) {
937 struct focus_surface *fsurf = get_focus_surface(view->surface);
938 transform = &fsurf->workspace_transform;
939 } else {
940 struct shell_surface *shsurf = get_shell_surface(view->surface);
941 transform = &shsurf->workspace_transform;
942 }
943
944 if (!wl_list_empty(&transform->link)) {
945 wl_list_remove(&transform->link);
946 wl_list_init(&transform->link);
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200947 }
Jason Ekstranda7af7042013-10-12 22:38:11 -0500948 weston_view_geometry_dirty(view);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200949 }
950}
951
952static void
953finish_workspace_change_animation(struct desktop_shell *shell,
954 struct workspace *from,
955 struct workspace *to)
956{
Scott Moreau4272e632012-08-13 09:58:41 -0600957 weston_compositor_schedule_repaint(shell->compositor);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200958
959 wl_list_remove(&shell->workspaces.animation.link);
960 workspace_deactivate_transforms(from);
961 workspace_deactivate_transforms(to);
962 shell->workspaces.anim_to = NULL;
963
964 wl_list_remove(&shell->workspaces.anim_from->layer.link);
965}
966
967static void
968animate_workspace_change_frame(struct weston_animation *animation,
969 struct weston_output *output, uint32_t msecs)
970{
971 struct desktop_shell *shell =
972 container_of(animation, struct desktop_shell,
973 workspaces.animation);
974 struct workspace *from = shell->workspaces.anim_from;
975 struct workspace *to = shell->workspaces.anim_to;
976 uint32_t t;
977 double x, y;
978
979 if (workspace_is_empty(from) && workspace_is_empty(to)) {
980 finish_workspace_change_animation(shell, from, to);
981 return;
982 }
983
984 if (shell->workspaces.anim_timestamp == 0) {
985 if (shell->workspaces.anim_current == 0.0)
986 shell->workspaces.anim_timestamp = msecs;
987 else
988 shell->workspaces.anim_timestamp =
989 msecs -
990 /* Invers of movement function 'y' below. */
991 (asin(1.0 - shell->workspaces.anim_current) *
992 DEFAULT_WORKSPACE_CHANGE_ANIMATION_LENGTH *
993 M_2_PI);
994 }
995
996 t = msecs - shell->workspaces.anim_timestamp;
997
998 /*
999 * x = [0, π/2]
1000 * y(x) = sin(x)
1001 */
1002 x = t * (1.0/DEFAULT_WORKSPACE_CHANGE_ANIMATION_LENGTH) * M_PI_2;
1003 y = sin(x);
1004
1005 if (t < DEFAULT_WORKSPACE_CHANGE_ANIMATION_LENGTH) {
Scott Moreau4272e632012-08-13 09:58:41 -06001006 weston_compositor_schedule_repaint(shell->compositor);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001007
1008 workspace_translate_out(from, shell->workspaces.anim_dir * y);
1009 workspace_translate_in(to, shell->workspaces.anim_dir * y);
1010 shell->workspaces.anim_current = y;
1011
Scott Moreau4272e632012-08-13 09:58:41 -06001012 weston_compositor_schedule_repaint(shell->compositor);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001013 }
Jonas Ådahl04769742012-06-13 00:01:24 +02001014 else
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001015 finish_workspace_change_animation(shell, from, to);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001016}
1017
1018static void
1019animate_workspace_change(struct desktop_shell *shell,
1020 unsigned int index,
1021 struct workspace *from,
1022 struct workspace *to)
1023{
1024 struct weston_output *output;
1025
1026 int dir;
1027
1028 if (index > shell->workspaces.current)
1029 dir = -1;
1030 else
1031 dir = 1;
1032
1033 shell->workspaces.current = index;
1034
1035 shell->workspaces.anim_dir = dir;
1036 shell->workspaces.anim_from = from;
1037 shell->workspaces.anim_to = to;
1038 shell->workspaces.anim_current = 0.0;
1039 shell->workspaces.anim_timestamp = 0;
1040
1041 output = container_of(shell->compositor->output_list.next,
1042 struct weston_output, link);
1043 wl_list_insert(&output->animation_list,
1044 &shell->workspaces.animation.link);
1045
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001046 wl_list_insert(from->layer.link.prev, &to->layer.link);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001047
1048 workspace_translate_in(to, 0);
1049
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -04001050 restore_focus_state(shell, to);
Jonas Ådahl04769742012-06-13 00:01:24 +02001051
Scott Moreau4272e632012-08-13 09:58:41 -06001052 weston_compositor_schedule_repaint(shell->compositor);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001053}
1054
Jonas Ådahle3cddce2012-06-13 00:01:22 +02001055static void
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001056update_workspace(struct desktop_shell *shell, unsigned int index,
1057 struct workspace *from, struct workspace *to)
1058{
1059 shell->workspaces.current = index;
1060 wl_list_insert(&from->layer.link, &to->layer.link);
1061 wl_list_remove(&from->layer.link);
1062}
1063
1064static void
Jonas Ådahle3cddce2012-06-13 00:01:22 +02001065change_workspace(struct desktop_shell *shell, unsigned int index)
1066{
1067 struct workspace *from;
1068 struct workspace *to;
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01001069 struct focus_state *state;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02001070
1071 if (index == shell->workspaces.current)
1072 return;
1073
1074 /* Don't change workspace when there is any fullscreen surfaces. */
Jason Ekstranda7af7042013-10-12 22:38:11 -05001075 if (!wl_list_empty(&shell->fullscreen_layer.view_list))
Jonas Ådahle3cddce2012-06-13 00:01:22 +02001076 return;
1077
Jonas Ådahle3cddce2012-06-13 00:01:22 +02001078 from = get_current_workspace(shell);
1079 to = get_workspace(shell, index);
1080
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001081 if (shell->workspaces.anim_from == to &&
1082 shell->workspaces.anim_to == from) {
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001083 restore_focus_state(shell, to);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001084 reverse_workspace_change_animation(shell, index, from, to);
Jonas Ådahle9d22502012-08-29 22:13:01 +02001085 broadcast_current_workspace_state(shell);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001086 return;
1087 }
Jonas Ådahle3cddce2012-06-13 00:01:22 +02001088
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001089 if (shell->workspaces.anim_to != NULL)
1090 finish_workspace_change_animation(shell,
1091 shell->workspaces.anim_from,
1092 shell->workspaces.anim_to);
1093
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001094 restore_focus_state(shell, to);
Jonas Ådahl04769742012-06-13 00:01:24 +02001095
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01001096 if (shell->focus_animation_type != ANIMATION_NONE) {
1097 wl_list_for_each(state, &from->focus_list, link)
1098 if (state->keyboard_focus)
1099 animate_focus_change(shell, from,
1100 get_default_view(state->keyboard_focus), NULL);
1101
1102 wl_list_for_each(state, &to->focus_list, link)
1103 if (state->keyboard_focus)
1104 animate_focus_change(shell, to,
1105 NULL, get_default_view(state->keyboard_focus));
1106 }
1107
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001108 if (workspace_is_empty(to) && workspace_is_empty(from))
1109 update_workspace(shell, index, from, to);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001110 else
1111 animate_workspace_change(shell, index, from, to);
Jonas Ådahle9d22502012-08-29 22:13:01 +02001112
1113 broadcast_current_workspace_state(shell);
Pekka Paalanene955f1e2011-12-07 11:49:52 +02001114}
1115
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001116static bool
1117workspace_has_only(struct workspace *ws, struct weston_surface *surface)
1118{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001119 struct wl_list *list = &ws->layer.view_list;
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001120 struct wl_list *e;
1121
1122 if (wl_list_empty(list))
1123 return false;
1124
1125 e = list->next;
1126
1127 if (e->next != list)
1128 return false;
1129
Jason Ekstranda7af7042013-10-12 22:38:11 -05001130 return container_of(e, struct weston_view, layer_link)->surface == surface;
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001131}
1132
1133static void
Philip Withnall659163d2013-11-25 18:01:36 +00001134move_surface_to_workspace(struct desktop_shell *shell,
1135 struct shell_surface *shsurf,
1136 uint32_t workspace)
Jonas Ådahle9d22502012-08-29 22:13:01 +02001137{
1138 struct workspace *from;
1139 struct workspace *to;
1140 struct weston_seat *seat;
Pekka Paalanen01388e22013-04-25 13:57:44 +03001141 struct weston_surface *focus;
Philip Withnall659163d2013-11-25 18:01:36 +00001142 struct weston_view *view;
Jonas Ådahle9d22502012-08-29 22:13:01 +02001143
1144 if (workspace == shell->workspaces.current)
1145 return;
1146
Philip Withnall659163d2013-11-25 18:01:36 +00001147 view = get_default_view(shsurf->surface);
1148 if (!view)
1149 return;
1150
1151 assert(weston_surface_get_main_surface(view->surface) == view->surface);
1152
Philipp Brüschweiler067abf62012-09-01 16:03:05 +02001153 if (workspace >= shell->workspaces.num)
1154 workspace = shell->workspaces.num - 1;
1155
Jonas Ådahle9d22502012-08-29 22:13:01 +02001156 from = get_current_workspace(shell);
1157 to = get_workspace(shell, workspace);
1158
Jason Ekstranda7af7042013-10-12 22:38:11 -05001159 wl_list_remove(&view->layer_link);
1160 wl_list_insert(&to->layer.view_list, &view->layer_link);
Jonas Ådahle9d22502012-08-29 22:13:01 +02001161
Philip Withnall648a4dd2013-11-25 18:01:44 +00001162 shell_surface_update_child_surface_layers(shsurf);
1163
Jason Ekstranda7af7042013-10-12 22:38:11 -05001164 drop_focus_state(shell, from, view->surface);
Pekka Paalanen01388e22013-04-25 13:57:44 +03001165 wl_list_for_each(seat, &shell->compositor->seat_list, link) {
1166 if (!seat->keyboard)
1167 continue;
1168
1169 focus = weston_surface_get_main_surface(seat->keyboard->focus);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001170 if (focus == view->surface)
Kristian Høgsberge3148752013-05-06 23:19:49 -04001171 weston_keyboard_set_focus(seat->keyboard, NULL);
Pekka Paalanen01388e22013-04-25 13:57:44 +03001172 }
Jonas Ådahle9d22502012-08-29 22:13:01 +02001173
Jason Ekstranda7af7042013-10-12 22:38:11 -05001174 weston_view_damage_below(view);
Jonas Ådahle9d22502012-08-29 22:13:01 +02001175}
1176
1177static void
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001178take_surface_to_workspace_by_seat(struct desktop_shell *shell,
Kristian Høgsberge3148752013-05-06 23:19:49 -04001179 struct weston_seat *seat,
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001180 unsigned int index)
1181{
Pekka Paalanen01388e22013-04-25 13:57:44 +03001182 struct weston_surface *surface;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001183 struct weston_view *view;
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001184 struct shell_surface *shsurf;
1185 struct workspace *from;
1186 struct workspace *to;
Jonas Ådahl8538b222012-08-29 22:13:03 +02001187 struct focus_state *state;
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001188
Pekka Paalanen01388e22013-04-25 13:57:44 +03001189 surface = weston_surface_get_main_surface(seat->keyboard->focus);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001190 view = get_default_view(surface);
1191 if (view == NULL ||
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01001192 index == shell->workspaces.current ||
1193 is_focus_view(view))
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001194 return;
1195
1196 from = get_current_workspace(shell);
1197 to = get_workspace(shell, index);
1198
Jason Ekstranda7af7042013-10-12 22:38:11 -05001199 wl_list_remove(&view->layer_link);
1200 wl_list_insert(&to->layer.view_list, &view->layer_link);
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001201
Philip Withnall659163d2013-11-25 18:01:36 +00001202 shsurf = get_shell_surface(surface);
Philip Withnall648a4dd2013-11-25 18:01:44 +00001203 if (shsurf != NULL)
1204 shell_surface_update_child_surface_layers(shsurf);
Philip Withnall659163d2013-11-25 18:01:36 +00001205
Jonas Ådahle9d22502012-08-29 22:13:01 +02001206 replace_focus_state(shell, to, seat);
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001207 drop_focus_state(shell, from, surface);
1208
1209 if (shell->workspaces.anim_from == to &&
1210 shell->workspaces.anim_to == from) {
Jonas Ådahle9d22502012-08-29 22:13:01 +02001211 wl_list_remove(&to->layer.link);
1212 wl_list_insert(from->layer.link.prev, &to->layer.link);
1213
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001214 reverse_workspace_change_animation(shell, index, from, to);
Jonas Ådahle9d22502012-08-29 22:13:01 +02001215 broadcast_current_workspace_state(shell);
1216
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001217 return;
1218 }
1219
1220 if (shell->workspaces.anim_to != NULL)
1221 finish_workspace_change_animation(shell,
1222 shell->workspaces.anim_from,
1223 shell->workspaces.anim_to);
1224
1225 if (workspace_is_empty(from) &&
1226 workspace_has_only(to, surface))
1227 update_workspace(shell, index, from, to);
1228 else {
Philip Withnall2c3849b2013-11-25 18:01:45 +00001229 if (shsurf != NULL &&
1230 wl_list_empty(&shsurf->workspace_transform.link))
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001231 wl_list_insert(&shell->workspaces.anim_sticky_list,
1232 &shsurf->workspace_transform.link);
1233
1234 animate_workspace_change(shell, index, from, to);
1235 }
Jonas Ådahle9d22502012-08-29 22:13:01 +02001236
1237 broadcast_current_workspace_state(shell);
Jonas Ådahl8538b222012-08-29 22:13:03 +02001238
1239 state = ensure_focus_state(shell, seat);
1240 if (state != NULL)
1241 state->keyboard_focus = surface;
Jonas Ådahle9d22502012-08-29 22:13:01 +02001242}
1243
1244static void
1245workspace_manager_move_surface(struct wl_client *client,
1246 struct wl_resource *resource,
1247 struct wl_resource *surface_resource,
1248 uint32_t workspace)
1249{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05001250 struct desktop_shell *shell = wl_resource_get_user_data(resource);
Jonas Ådahle9d22502012-08-29 22:13:01 +02001251 struct weston_surface *surface =
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05001252 wl_resource_get_user_data(surface_resource);
Pekka Paalanen01388e22013-04-25 13:57:44 +03001253 struct weston_surface *main_surface;
Philip Withnall659163d2013-11-25 18:01:36 +00001254 struct shell_surface *shell_surface;
Jonas Ådahle9d22502012-08-29 22:13:01 +02001255
Pekka Paalanen01388e22013-04-25 13:57:44 +03001256 main_surface = weston_surface_get_main_surface(surface);
Philip Withnall659163d2013-11-25 18:01:36 +00001257 shell_surface = get_shell_surface(main_surface);
1258 if (shell_surface == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001259 return;
Philip Withnall659163d2013-11-25 18:01:36 +00001260
1261 move_surface_to_workspace(shell, shell_surface, workspace);
Jonas Ådahle9d22502012-08-29 22:13:01 +02001262}
1263
1264static const struct workspace_manager_interface workspace_manager_implementation = {
1265 workspace_manager_move_surface,
1266};
1267
1268static void
1269unbind_resource(struct wl_resource *resource)
1270{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05001271 wl_list_remove(wl_resource_get_link(resource));
Jonas Ådahle9d22502012-08-29 22:13:01 +02001272}
1273
1274static void
1275bind_workspace_manager(struct wl_client *client,
1276 void *data, uint32_t version, uint32_t id)
1277{
1278 struct desktop_shell *shell = data;
1279 struct wl_resource *resource;
1280
Jason Ekstranda85118c2013-06-27 20:17:02 -05001281 resource = wl_resource_create(client,
1282 &workspace_manager_interface, 1, id);
Jonas Ådahle9d22502012-08-29 22:13:01 +02001283
1284 if (resource == NULL) {
1285 weston_log("couldn't add workspace manager object");
1286 return;
1287 }
1288
Jason Ekstranda85118c2013-06-27 20:17:02 -05001289 wl_resource_set_implementation(resource,
1290 &workspace_manager_implementation,
1291 shell, unbind_resource);
Jason Ekstrand651f00e2013-06-14 10:07:54 -05001292 wl_list_insert(&shell->workspaces.client_list,
1293 wl_resource_get_link(resource));
Jonas Ådahle9d22502012-08-29 22:13:01 +02001294
1295 workspace_manager_send_state(resource,
1296 shell->workspaces.current,
1297 shell->workspaces.num);
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001298}
1299
Pekka Paalanen56cdea92011-11-23 16:14:12 +02001300static void
Rusty Lynch1084da52013-08-15 09:10:08 -07001301touch_move_grab_down(struct weston_touch_grab *grab, uint32_t time,
1302 int touch_id, wl_fixed_t sx, wl_fixed_t sy)
1303{
1304}
1305
1306static void
1307touch_move_grab_up(struct weston_touch_grab *grab, uint32_t time, int touch_id)
1308{
Jonas Ådahl1c6e63e2013-10-25 23:18:04 +02001309 struct weston_touch_move_grab *move =
1310 (struct weston_touch_move_grab *) container_of(
1311 grab, struct shell_touch_grab, grab);
Neil Robertse14aa4f2013-10-03 16:43:07 +01001312
Jonas Ådahl9484b692013-12-02 22:05:03 +01001313 if (grab->touch->num_tp == 0) {
Jonas Ådahl1c6e63e2013-10-25 23:18:04 +02001314 shell_touch_grab_end(&move->base);
1315 free(move);
1316 }
Rusty Lynch1084da52013-08-15 09:10:08 -07001317}
1318
1319static void
1320touch_move_grab_motion(struct weston_touch_grab *grab, uint32_t time,
1321 int touch_id, wl_fixed_t sx, wl_fixed_t sy)
1322{
1323 struct weston_touch_move_grab *move = (struct weston_touch_move_grab *) grab;
1324 struct shell_surface *shsurf = move->base.shsurf;
1325 struct weston_surface *es;
1326 int dx = wl_fixed_to_int(grab->touch->grab_x + move->dx);
1327 int dy = wl_fixed_to_int(grab->touch->grab_y + move->dy);
1328
1329 if (!shsurf)
1330 return;
1331
1332 es = shsurf->surface;
1333
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001334 weston_view_set_position(shsurf->view, dx, dy);
Rusty Lynch1084da52013-08-15 09:10:08 -07001335
1336 weston_compositor_schedule_repaint(es->compositor);
1337}
1338
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02001339static void
1340touch_move_grab_cancel(struct weston_touch_grab *grab)
1341{
1342 struct weston_touch_move_grab *move =
1343 (struct weston_touch_move_grab *) container_of(
1344 grab, struct shell_touch_grab, grab);
1345
1346 shell_touch_grab_end(&move->base);
1347 free(move);
1348}
1349
Rusty Lynch1084da52013-08-15 09:10:08 -07001350static const struct weston_touch_grab_interface touch_move_grab_interface = {
1351 touch_move_grab_down,
1352 touch_move_grab_up,
1353 touch_move_grab_motion,
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02001354 touch_move_grab_cancel,
Rusty Lynch1084da52013-08-15 09:10:08 -07001355};
1356
1357static int
1358surface_touch_move(struct shell_surface *shsurf, struct weston_seat *seat)
1359{
1360 struct weston_touch_move_grab *move;
1361
1362 if (!shsurf)
1363 return -1;
1364
Rafael Antognolli03b16592013-12-03 15:35:42 -02001365 if (shsurf->state.fullscreen)
Rusty Lynch1084da52013-08-15 09:10:08 -07001366 return 0;
Kristian Høgsbergc85f1d42013-10-24 16:52:00 -07001367 if (shsurf->grabbed)
1368 return 0;
Rusty Lynch1084da52013-08-15 09:10:08 -07001369
1370 move = malloc(sizeof *move);
1371 if (!move)
1372 return -1;
1373
Jason Ekstranda7af7042013-10-12 22:38:11 -05001374 move->dx = wl_fixed_from_double(shsurf->view->geometry.x) -
Rusty Lynch1084da52013-08-15 09:10:08 -07001375 seat->touch->grab_x;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001376 move->dy = wl_fixed_from_double(shsurf->view->geometry.y) -
Rusty Lynch1084da52013-08-15 09:10:08 -07001377 seat->touch->grab_y;
1378
1379 shell_touch_grab_start(&move->base, &touch_move_grab_interface, shsurf,
1380 seat->touch);
1381
1382 return 0;
1383}
1384
1385static void
Kristian Høgsberg6848c252013-05-08 22:02:59 -04001386noop_grab_focus(struct weston_pointer_grab *grab)
Kristian Høgsberg9ddb8262012-01-04 21:30:29 -05001387{
Kristian Høgsberg9ddb8262012-01-04 21:30:29 -05001388}
1389
1390static void
Giulio Camuffo1959ab82013-11-14 23:42:52 +01001391move_grab_motion(struct weston_pointer_grab *grab, uint32_t time,
1392 wl_fixed_t x, wl_fixed_t y)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001393{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001394 struct weston_move_grab *move = (struct weston_move_grab *) grab;
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001395 struct weston_pointer *pointer = grab->pointer;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03001396 struct shell_surface *shsurf = move->base.shsurf;
Giulio Camuffo1959ab82013-11-14 23:42:52 +01001397 int dx, dy;
1398
1399 weston_pointer_move(pointer, x, y);
1400 dx = wl_fixed_to_int(pointer->x + move->dx);
1401 dy = wl_fixed_to_int(pointer->y + move->dy);
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03001402
1403 if (!shsurf)
1404 return;
1405
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001406 weston_view_set_position(shsurf->view, dx, dy);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001407
Jason Ekstranda7af7042013-10-12 22:38:11 -05001408 weston_compositor_schedule_repaint(shsurf->surface->compositor);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001409}
1410
1411static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001412move_grab_button(struct weston_pointer_grab *grab,
Daniel Stone4dbadb12012-05-30 16:31:51 +01001413 uint32_t time, uint32_t button, uint32_t state_w)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001414{
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03001415 struct shell_grab *shell_grab = container_of(grab, struct shell_grab,
1416 grab);
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001417 struct weston_pointer *pointer = grab->pointer;
Daniel Stone4dbadb12012-05-30 16:31:51 +01001418 enum wl_pointer_button_state state = state_w;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001419
Daniel Stone4dbadb12012-05-30 16:31:51 +01001420 if (pointer->button_count == 0 &&
1421 state == WL_POINTER_BUTTON_STATE_RELEASED) {
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001422 shell_grab_end(shell_grab);
Kristian Høgsberg9ddb8262012-01-04 21:30:29 -05001423 free(grab);
1424 }
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001425}
1426
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02001427static void
1428move_grab_cancel(struct weston_pointer_grab *grab)
1429{
1430 struct shell_grab *shell_grab =
1431 container_of(grab, struct shell_grab, grab);
1432
1433 shell_grab_end(shell_grab);
1434 free(grab);
1435}
1436
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001437static const struct weston_pointer_grab_interface move_grab_interface = {
Kristian Høgsberg9ddb8262012-01-04 21:30:29 -05001438 noop_grab_focus,
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001439 move_grab_motion,
1440 move_grab_button,
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02001441 move_grab_cancel,
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001442};
1443
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001444static int
Kristian Høgsberge3148752013-05-06 23:19:49 -04001445surface_move(struct shell_surface *shsurf, struct weston_seat *seat)
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001446{
1447 struct weston_move_grab *move;
1448
1449 if (!shsurf)
1450 return -1;
1451
Kristian Høgsbergc85f1d42013-10-24 16:52:00 -07001452 if (shsurf->grabbed)
1453 return 0;
Rafael Antognolli03b16592013-12-03 15:35:42 -02001454 if (shsurf->state.fullscreen)
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001455 return 0;
1456
1457 move = malloc(sizeof *move);
1458 if (!move)
1459 return -1;
1460
Jason Ekstranda7af7042013-10-12 22:38:11 -05001461 move->dx = wl_fixed_from_double(shsurf->view->geometry.x) -
Kristian Høgsberge3148752013-05-06 23:19:49 -04001462 seat->pointer->grab_x;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001463 move->dy = wl_fixed_from_double(shsurf->view->geometry.y) -
Kristian Høgsberge3148752013-05-06 23:19:49 -04001464 seat->pointer->grab_y;
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001465
1466 shell_grab_start(&move->base, &move_grab_interface, shsurf,
Kristian Høgsberge3148752013-05-06 23:19:49 -04001467 seat->pointer, DESKTOP_SHELL_CURSOR_MOVE);
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001468
1469 return 0;
1470}
1471
1472static void
Rafael Antognollie2a34552013-12-03 15:35:45 -02001473common_surface_move(struct wl_resource *resource,
1474 struct wl_resource *seat_resource, uint32_t serial)
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001475{
Jason Ekstrand44a38632013-06-14 10:08:00 -05001476 struct weston_seat *seat = wl_resource_get_user_data(seat_resource);
Jason Ekstrand651f00e2013-06-14 10:07:54 -05001477 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
Giulio Camuffo61da3fc2013-04-25 13:57:45 +03001478 struct weston_surface *surface;
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001479
Kristian Høgsberge1b655d2013-08-28 23:16:20 -07001480 if (seat->pointer &&
Kristian Høgsberg70f29012014-01-09 15:43:17 -08001481 seat->pointer->focus &&
Kristian Høgsberge1b655d2013-08-28 23:16:20 -07001482 seat->pointer->button_count > 0 &&
1483 seat->pointer->grab_serial == serial) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001484 surface = weston_surface_get_main_surface(seat->pointer->focus->surface);
Rusty Lynch1084da52013-08-15 09:10:08 -07001485 if ((surface == shsurf->surface) &&
1486 (surface_move(shsurf, seat) < 0))
1487 wl_resource_post_no_memory(resource);
Kristian Høgsberge1b655d2013-08-28 23:16:20 -07001488 } else if (seat->touch &&
Kristian Høgsberg70f29012014-01-09 15:43:17 -08001489 seat->touch->focus &&
Kristian Høgsberge1b655d2013-08-28 23:16:20 -07001490 seat->touch->grab_serial == serial) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001491 surface = weston_surface_get_main_surface(seat->touch->focus->surface);
Rusty Lynch1084da52013-08-15 09:10:08 -07001492 if ((surface == shsurf->surface) &&
1493 (surface_touch_move(shsurf, seat) < 0))
1494 wl_resource_post_no_memory(resource);
1495 }
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001496}
1497
Rafael Antognollie2a34552013-12-03 15:35:45 -02001498static void
1499shell_surface_move(struct wl_client *client, struct wl_resource *resource,
1500 struct wl_resource *seat_resource, uint32_t serial)
1501{
1502 common_surface_move(resource, seat_resource, serial);
1503}
1504
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001505struct weston_resize_grab {
1506 struct shell_grab base;
1507 uint32_t edges;
1508 int32_t width, height;
1509};
1510
1511static void
Giulio Camuffo1959ab82013-11-14 23:42:52 +01001512resize_grab_motion(struct weston_pointer_grab *grab, uint32_t time,
1513 wl_fixed_t x, wl_fixed_t y)
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001514{
1515 struct weston_resize_grab *resize = (struct weston_resize_grab *) grab;
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001516 struct weston_pointer *pointer = grab->pointer;
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001517 struct shell_surface *shsurf = resize->base.shsurf;
1518 int32_t width, height;
1519 wl_fixed_t from_x, from_y;
1520 wl_fixed_t to_x, to_y;
1521
Giulio Camuffo1959ab82013-11-14 23:42:52 +01001522 weston_pointer_move(pointer, x, y);
1523
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001524 if (!shsurf)
1525 return;
1526
Jason Ekstranda7af7042013-10-12 22:38:11 -05001527 weston_view_from_global_fixed(shsurf->view,
1528 pointer->grab_x, pointer->grab_y,
1529 &from_x, &from_y);
1530 weston_view_from_global_fixed(shsurf->view,
1531 pointer->x, pointer->y, &to_x, &to_y);
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001532
1533 width = resize->width;
1534 if (resize->edges & WL_SHELL_SURFACE_RESIZE_LEFT) {
1535 width += wl_fixed_to_int(from_x - to_x);
1536 } else if (resize->edges & WL_SHELL_SURFACE_RESIZE_RIGHT) {
1537 width += wl_fixed_to_int(to_x - from_x);
1538 }
1539
1540 height = resize->height;
1541 if (resize->edges & WL_SHELL_SURFACE_RESIZE_TOP) {
1542 height += wl_fixed_to_int(from_y - to_y);
1543 } else if (resize->edges & WL_SHELL_SURFACE_RESIZE_BOTTOM) {
1544 height += wl_fixed_to_int(to_y - from_y);
1545 }
1546
1547 shsurf->client->send_configure(shsurf->surface,
1548 resize->edges, width, height);
1549}
1550
1551static void
1552send_configure(struct weston_surface *surface,
1553 uint32_t edges, int32_t width, int32_t height)
1554{
1555 struct shell_surface *shsurf = get_shell_surface(surface);
1556
Jason Ekstrand651f00e2013-06-14 10:07:54 -05001557 wl_shell_surface_send_configure(shsurf->resource,
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001558 edges, width, height);
1559}
1560
1561static const struct weston_shell_client shell_client = {
1562 send_configure
1563};
1564
1565static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001566resize_grab_button(struct weston_pointer_grab *grab,
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001567 uint32_t time, uint32_t button, uint32_t state_w)
1568{
1569 struct weston_resize_grab *resize = (struct weston_resize_grab *) grab;
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001570 struct weston_pointer *pointer = grab->pointer;
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001571 enum wl_pointer_button_state state = state_w;
1572
1573 if (pointer->button_count == 0 &&
1574 state == WL_POINTER_BUTTON_STATE_RELEASED) {
1575 shell_grab_end(&resize->base);
1576 free(grab);
1577 }
1578}
1579
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02001580static void
1581resize_grab_cancel(struct weston_pointer_grab *grab)
1582{
1583 struct weston_resize_grab *resize = (struct weston_resize_grab *) grab;
1584
1585 shell_grab_end(&resize->base);
1586 free(grab);
1587}
1588
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001589static const struct weston_pointer_grab_interface resize_grab_interface = {
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001590 noop_grab_focus,
1591 resize_grab_motion,
1592 resize_grab_button,
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02001593 resize_grab_cancel,
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001594};
1595
Giulio Camuffob8366642013-04-25 13:57:46 +03001596/*
1597 * Returns the bounding box of a surface and all its sub-surfaces,
1598 * in the surface coordinates system. */
1599static void
1600surface_subsurfaces_boundingbox(struct weston_surface *surface, int32_t *x,
1601 int32_t *y, int32_t *w, int32_t *h) {
1602 pixman_region32_t region;
1603 pixman_box32_t *box;
1604 struct weston_subsurface *subsurface;
1605
1606 pixman_region32_init_rect(&region, 0, 0,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001607 surface->width,
1608 surface->height);
Giulio Camuffob8366642013-04-25 13:57:46 +03001609
1610 wl_list_for_each(subsurface, &surface->subsurface_list, parent_link) {
1611 pixman_region32_union_rect(&region, &region,
1612 subsurface->position.x,
1613 subsurface->position.y,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001614 subsurface->surface->width,
1615 subsurface->surface->height);
Giulio Camuffob8366642013-04-25 13:57:46 +03001616 }
1617
1618 box = pixman_region32_extents(&region);
1619 if (x)
1620 *x = box->x1;
1621 if (y)
1622 *y = box->y1;
1623 if (w)
1624 *w = box->x2 - box->x1;
1625 if (h)
1626 *h = box->y2 - box->y1;
1627
1628 pixman_region32_fini(&region);
1629}
1630
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001631static int
1632surface_resize(struct shell_surface *shsurf,
Kristian Høgsberge3148752013-05-06 23:19:49 -04001633 struct weston_seat *seat, uint32_t edges)
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001634{
1635 struct weston_resize_grab *resize;
1636
Rafael Antognolli03b16592013-12-03 15:35:42 -02001637 if (shsurf->state.fullscreen || shsurf->state.maximized)
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001638 return 0;
1639
1640 if (edges == 0 || edges > 15 ||
1641 (edges & 3) == 3 || (edges & 12) == 12)
1642 return 0;
1643
1644 resize = malloc(sizeof *resize);
1645 if (!resize)
1646 return -1;
1647
1648 resize->edges = edges;
Giulio Camuffob8366642013-04-25 13:57:46 +03001649 surface_subsurfaces_boundingbox(shsurf->surface, NULL, NULL,
1650 &resize->width, &resize->height);
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001651
1652 shell_grab_start(&resize->base, &resize_grab_interface, shsurf,
Kristian Høgsberge3148752013-05-06 23:19:49 -04001653 seat->pointer, edges);
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001654
1655 return 0;
1656}
1657
1658static void
Rafael Antognollie2a34552013-12-03 15:35:45 -02001659common_surface_resize(struct wl_resource *resource,
1660 struct wl_resource *seat_resource, uint32_t serial,
1661 uint32_t edges)
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001662{
Jason Ekstrand44a38632013-06-14 10:08:00 -05001663 struct weston_seat *seat = wl_resource_get_user_data(seat_resource);
Jason Ekstrand651f00e2013-06-14 10:07:54 -05001664 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
Giulio Camuffo61da3fc2013-04-25 13:57:45 +03001665 struct weston_surface *surface;
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001666
Rafael Antognolli03b16592013-12-03 15:35:42 -02001667 if (shsurf->state.fullscreen)
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001668 return;
1669
Kristian Høgsberge3148752013-05-06 23:19:49 -04001670 if (seat->pointer->button_count == 0 ||
1671 seat->pointer->grab_serial != serial ||
Kristian Høgsberg70f29012014-01-09 15:43:17 -08001672 seat->pointer->focus == NULL)
1673 return;
1674
1675 surface = weston_surface_get_main_surface(seat->pointer->focus->surface);
1676 if (surface != shsurf->surface)
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001677 return;
1678
Kristian Høgsberge3148752013-05-06 23:19:49 -04001679 if (surface_resize(shsurf, seat, edges) < 0)
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001680 wl_resource_post_no_memory(resource);
1681}
1682
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001683static void
Rafael Antognollie2a34552013-12-03 15:35:45 -02001684shell_surface_resize(struct wl_client *client, struct wl_resource *resource,
1685 struct wl_resource *seat_resource, uint32_t serial,
1686 uint32_t edges)
1687{
1688 common_surface_resize(resource, seat_resource, serial, edges);
1689}
1690
1691static void
Kristian Høgsberg67800732013-07-04 01:12:17 -04001692end_busy_cursor(struct shell_surface *shsurf, struct weston_pointer *pointer);
1693
1694static void
Kristian Høgsberg6848c252013-05-08 22:02:59 -04001695busy_cursor_grab_focus(struct weston_pointer_grab *base)
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001696{
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001697 struct shell_grab *grab = (struct shell_grab *) base;
Kristian Høgsberg6848c252013-05-08 22:02:59 -04001698 struct weston_pointer *pointer = base->pointer;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001699 struct weston_view *view;
Kristian Høgsberg6848c252013-05-08 22:02:59 -04001700 wl_fixed_t sx, sy;
1701
Jason Ekstranda7af7042013-10-12 22:38:11 -05001702 view = weston_compositor_pick_view(pointer->seat->compositor,
1703 pointer->x, pointer->y,
1704 &sx, &sy);
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001705
Jason Ekstranda7af7042013-10-12 22:38:11 -05001706 if (!grab->shsurf || grab->shsurf->surface != view->surface)
Kristian Høgsberg67800732013-07-04 01:12:17 -04001707 end_busy_cursor(grab->shsurf, pointer);
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001708}
1709
1710static void
Giulio Camuffo1959ab82013-11-14 23:42:52 +01001711busy_cursor_grab_motion(struct weston_pointer_grab *grab, uint32_t time,
1712 wl_fixed_t x, wl_fixed_t y)
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001713{
Giulio Camuffo1959ab82013-11-14 23:42:52 +01001714 weston_pointer_move(grab->pointer, x, y);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001715}
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001716
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001717static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001718busy_cursor_grab_button(struct weston_pointer_grab *base,
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001719 uint32_t time, uint32_t button, uint32_t state)
1720{
Kristian Høgsbergbbe98392012-08-01 00:20:21 -04001721 struct shell_grab *grab = (struct shell_grab *) base;
Kristian Høgsberge122b7b2013-05-08 16:47:00 -04001722 struct shell_surface *shsurf = grab->shsurf;
Kristian Høgsberge3148752013-05-06 23:19:49 -04001723 struct weston_seat *seat = grab->grab.pointer->seat;
Kristian Høgsbergbbe98392012-08-01 00:20:21 -04001724
Kristian Høgsbergbbe98392012-08-01 00:20:21 -04001725 if (shsurf && button == BTN_LEFT && state) {
1726 activate(shsurf->shell, shsurf->surface, seat);
1727 surface_move(shsurf, seat);
Kristian Høgsberg0c369032013-02-14 21:31:44 -05001728 } else if (shsurf && button == BTN_RIGHT && state) {
1729 activate(shsurf->shell, shsurf->surface, seat);
Kristian Høgsberge3148752013-05-06 23:19:49 -04001730 surface_rotate(shsurf, seat);
Kristian Høgsbergbbe98392012-08-01 00:20:21 -04001731 }
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001732}
1733
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02001734static void
1735busy_cursor_grab_cancel(struct weston_pointer_grab *base)
1736{
1737 struct shell_grab *grab = (struct shell_grab *) base;
1738
1739 shell_grab_end(grab);
1740 free(grab);
1741}
1742
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001743static const struct weston_pointer_grab_interface busy_cursor_grab_interface = {
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001744 busy_cursor_grab_focus,
1745 busy_cursor_grab_motion,
1746 busy_cursor_grab_button,
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02001747 busy_cursor_grab_cancel,
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001748};
1749
1750static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001751set_busy_cursor(struct shell_surface *shsurf, struct weston_pointer *pointer)
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001752{
1753 struct shell_grab *grab;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001754
1755 grab = malloc(sizeof *grab);
1756 if (!grab)
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001757 return;
1758
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001759 shell_grab_start(grab, &busy_cursor_grab_interface, shsurf, pointer,
1760 DESKTOP_SHELL_CURSOR_BUSY);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001761}
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001762
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001763static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001764end_busy_cursor(struct shell_surface *shsurf, struct weston_pointer *pointer)
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001765{
1766 struct shell_grab *grab = (struct shell_grab *) pointer->grab;
1767
Kristian Høgsberge122b7b2013-05-08 16:47:00 -04001768 if (grab->grab.interface == &busy_cursor_grab_interface &&
1769 grab->shsurf == shsurf) {
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001770 shell_grab_end(grab);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001771 free(grab);
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001772 }
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001773}
1774
Scott Moreau9521d5e2012-04-19 13:06:17 -06001775static void
1776ping_timer_destroy(struct shell_surface *shsurf)
1777{
1778 if (!shsurf || !shsurf->ping_timer)
1779 return;
1780
1781 if (shsurf->ping_timer->source)
1782 wl_event_source_remove(shsurf->ping_timer->source);
1783
1784 free(shsurf->ping_timer);
1785 shsurf->ping_timer = NULL;
1786}
1787
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001788static int
Scott Moreauff1db4a2012-04-17 19:06:18 -06001789ping_timeout_handler(void *data)
1790{
1791 struct shell_surface *shsurf = data;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001792 struct weston_seat *seat;
Scott Moreauff1db4a2012-04-17 19:06:18 -06001793
Scott Moreau9521d5e2012-04-19 13:06:17 -06001794 /* Client is not responding */
1795 shsurf->unresponsive = 1;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001796
1797 wl_list_for_each(seat, &shsurf->surface->compositor->seat_list, link)
Kristian Høgsberg17bccae2014-01-16 16:46:28 -08001798 if (seat->pointer->focus &&
Emilio Pozuelo Monfort3d0fc762013-11-22 16:21:20 +01001799 seat->pointer->focus->surface == shsurf->surface)
Kristian Høgsberge3148752013-05-06 23:19:49 -04001800 set_busy_cursor(shsurf, seat->pointer);
Scott Moreauff1db4a2012-04-17 19:06:18 -06001801
1802 return 1;
1803}
1804
1805static void
1806ping_handler(struct weston_surface *surface, uint32_t serial)
1807{
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001808 struct shell_surface *shsurf = get_shell_surface(surface);
Scott Moreauff1db4a2012-04-17 19:06:18 -06001809 struct wl_event_loop *loop;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001810 int ping_timeout = 200;
Scott Moreauff1db4a2012-04-17 19:06:18 -06001811
1812 if (!shsurf)
1813 return;
Jason Ekstrand651f00e2013-06-14 10:07:54 -05001814 if (!shsurf->resource)
Kristian Høgsbergca535c12012-04-21 23:20:07 -04001815 return;
Scott Moreauff1db4a2012-04-17 19:06:18 -06001816
Ander Conselvan de Oliveiraeac9a462012-07-16 14:15:48 +03001817 if (shsurf->surface == shsurf->shell->grab_surface)
1818 return;
1819
Scott Moreauff1db4a2012-04-17 19:06:18 -06001820 if (!shsurf->ping_timer) {
Ander Conselvan de Oliveirafb980892012-04-27 13:55:55 +03001821 shsurf->ping_timer = malloc(sizeof *shsurf->ping_timer);
Scott Moreauff1db4a2012-04-17 19:06:18 -06001822 if (!shsurf->ping_timer)
1823 return;
1824
1825 shsurf->ping_timer->serial = serial;
Scott Moreauff1db4a2012-04-17 19:06:18 -06001826 loop = wl_display_get_event_loop(surface->compositor->wl_display);
1827 shsurf->ping_timer->source =
1828 wl_event_loop_add_timer(loop, ping_timeout_handler, shsurf);
1829 wl_event_source_timer_update(shsurf->ping_timer->source, ping_timeout);
1830
Rafael Antognollie2a34552013-12-03 15:35:45 -02001831 if (shell_surface_is_wl_shell_surface(shsurf))
1832 wl_shell_surface_send_ping(shsurf->resource, serial);
1833 else if (shell_surface_is_xdg_surface(shsurf))
1834 xdg_surface_send_ping(shsurf->resource, serial);
1835 else if (shell_surface_is_xdg_popup(shsurf))
1836 xdg_popup_send_ping(shsurf->resource, serial);
Scott Moreauff1db4a2012-04-17 19:06:18 -06001837 }
1838}
1839
1840static void
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001841handle_pointer_focus(struct wl_listener *listener, void *data)
1842{
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001843 struct weston_pointer *pointer = data;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001844 struct weston_view *view = pointer->focus;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001845 struct weston_compositor *compositor;
1846 struct shell_surface *shsurf;
1847 uint32_t serial;
1848
Jason Ekstranda7af7042013-10-12 22:38:11 -05001849 if (!view)
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001850 return;
1851
Jason Ekstranda7af7042013-10-12 22:38:11 -05001852 compositor = view->surface->compositor;
1853 shsurf = get_shell_surface(view->surface);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001854
Pekka Paalanen4e1f2ff2012-06-06 16:59:45 +03001855 if (shsurf && shsurf->unresponsive) {
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001856 set_busy_cursor(shsurf, pointer);
1857 } else {
1858 serial = wl_display_next_serial(compositor->wl_display);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001859 ping_handler(view->surface, serial);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001860 }
1861}
1862
1863static void
Kristian Høgsbergf4d2f232012-08-10 10:05:39 -04001864create_pointer_focus_listener(struct weston_seat *seat)
1865{
1866 struct wl_listener *listener;
1867
Kristian Høgsberge3148752013-05-06 23:19:49 -04001868 if (!seat->pointer)
Kristian Høgsbergf4d2f232012-08-10 10:05:39 -04001869 return;
1870
1871 listener = malloc(sizeof *listener);
1872 listener->notify = handle_pointer_focus;
Kristian Høgsberge3148752013-05-06 23:19:49 -04001873 wl_signal_add(&seat->pointer->focus_signal, listener);
Kristian Høgsbergf4d2f232012-08-10 10:05:39 -04001874}
1875
1876static void
Rafael Antognollie2a34552013-12-03 15:35:45 -02001877xdg_surface_set_transient_for(struct wl_client *client,
1878 struct wl_resource *resource,
1879 struct wl_resource *parent_resource)
Scott Moreauff1db4a2012-04-17 19:06:18 -06001880{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05001881 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
Jasper St. Pierre8f180d42013-12-07 13:49:28 -05001882 struct weston_surface *parent;
1883
1884 if (parent_resource)
1885 parent = wl_resource_get_user_data(parent_resource);
1886 else
1887 parent = NULL;
Rafael Antognollie2a34552013-12-03 15:35:45 -02001888
1889 shell_surface_set_parent(shsurf, parent);
1890}
1891
1892static void
1893surface_pong(struct shell_surface *shsurf, uint32_t serial)
1894{
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001895 struct weston_compositor *ec = shsurf->surface->compositor;
Rafael Antognollie2a34552013-12-03 15:35:45 -02001896 struct weston_seat *seat;
Scott Moreauff1db4a2012-04-17 19:06:18 -06001897
Kristian Høgsberg92374e12012-08-11 22:39:12 -04001898 if (shsurf->ping_timer == NULL)
1899 /* Just ignore unsolicited pong. */
1900 return;
1901
Scott Moreauff1db4a2012-04-17 19:06:18 -06001902 if (shsurf->ping_timer->serial == serial) {
Scott Moreauff1db4a2012-04-17 19:06:18 -06001903 shsurf->unresponsive = 0;
Hardeningeb1e1302013-05-17 18:07:41 +02001904 wl_list_for_each(seat, &ec->seat_list, link) {
1905 if(seat->pointer)
1906 end_busy_cursor(shsurf, seat->pointer);
1907 }
Scott Moreau9521d5e2012-04-19 13:06:17 -06001908 ping_timer_destroy(shsurf);
Scott Moreauff1db4a2012-04-17 19:06:18 -06001909 }
1910}
1911
Kristian Høgsberge7afd912012-05-02 09:47:44 -04001912static void
Rafael Antognollie2a34552013-12-03 15:35:45 -02001913shell_surface_pong(struct wl_client *client, struct wl_resource *resource,
1914 uint32_t serial)
1915{
1916 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
1917
1918 surface_pong(shsurf, serial);
1919
1920}
1921
1922static void
Giulio Camuffo62942ad2013-09-11 18:20:47 +02001923set_title(struct shell_surface *shsurf, const char *title)
1924{
1925 free(shsurf->title);
1926 shsurf->title = strdup(title);
1927}
1928
1929static void
Kristian Høgsberge7afd912012-05-02 09:47:44 -04001930shell_surface_set_title(struct wl_client *client,
1931 struct wl_resource *resource, const char *title)
1932{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05001933 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
Kristian Høgsberge7afd912012-05-02 09:47:44 -04001934
Giulio Camuffo62942ad2013-09-11 18:20:47 +02001935 set_title(shsurf, title);
Kristian Høgsberge7afd912012-05-02 09:47:44 -04001936}
1937
1938static void
1939shell_surface_set_class(struct wl_client *client,
1940 struct wl_resource *resource, const char *class)
1941{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05001942 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
Kristian Høgsberge7afd912012-05-02 09:47:44 -04001943
1944 free(shsurf->class);
1945 shsurf->class = strdup(class);
1946}
1947
Alex Wu4539b082012-03-01 12:57:46 +08001948static void
Alexander Larssonf82b6ca2013-05-28 16:23:39 +02001949restore_output_mode(struct weston_output *output)
1950{
Hardening57388e42013-09-18 23:56:36 +02001951 if (output->current_mode != output->original_mode ||
1952 (int32_t)output->current_scale != output->original_scale)
Alexander Larssonf82b6ca2013-05-28 16:23:39 +02001953 weston_output_switch_mode(output,
Hardening57388e42013-09-18 23:56:36 +02001954 output->original_mode,
1955 output->original_scale,
1956 WESTON_MODE_SWITCH_RESTORE_NATIVE);
Alexander Larssonf82b6ca2013-05-28 16:23:39 +02001957}
1958
1959static void
1960restore_all_output_modes(struct weston_compositor *compositor)
1961{
1962 struct weston_output *output;
1963
1964 wl_list_for_each(output, &compositor->output_list, link)
1965 restore_output_mode(output);
1966}
1967
Philip Withnallbecb77e2013-11-25 18:01:30 +00001968static int
1969get_output_panel_height(struct desktop_shell *shell,
1970 struct weston_output *output)
1971{
1972 struct weston_view *view;
1973 int panel_height = 0;
1974
1975 if (!output)
1976 return 0;
1977
1978 wl_list_for_each(view, &shell->panel_layer.view_list, layer_link) {
1979 if (view->surface->output == output) {
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001980 panel_height = view->surface->height;
Philip Withnallbecb77e2013-11-25 18:01:30 +00001981 break;
1982 }
1983 }
1984
1985 return panel_height;
1986}
1987
Philip Withnall07926d92013-11-25 18:01:40 +00001988/* The surface will be inserted into the list immediately after the link
1989 * returned by this function (i.e. will be stacked immediately above the
1990 * returned link). */
1991static struct wl_list *
1992shell_surface_calculate_layer_link (struct shell_surface *shsurf)
1993{
1994 struct workspace *ws;
Kristian Høgsbergead52422014-01-01 13:51:52 -08001995 struct weston_view *parent;
Philip Withnall07926d92013-11-25 18:01:40 +00001996
1997 switch (shsurf->type) {
Kristian Høgsbergead52422014-01-01 13:51:52 -08001998 case SHELL_SURFACE_POPUP:
1999 case SHELL_SURFACE_TOPLEVEL:
Rafael Antognollied207b42013-12-03 15:35:43 -02002000 if (shsurf->state.fullscreen) {
Rafael Antognolli03b16592013-12-03 15:35:42 -02002001 return &shsurf->shell->fullscreen_layer.view_list;
Rafael Antognollied207b42013-12-03 15:35:43 -02002002 } else if (shsurf->parent) {
Kristian Høgsbergd55db692014-01-01 12:26:14 -08002003 /* Move the surface to its parent layer so
2004 * that surfaces which are transient for
2005 * fullscreen surfaces don't get hidden by the
2006 * fullscreen surfaces. */
Rafael Antognollied207b42013-12-03 15:35:43 -02002007
2008 /* TODO: Handle a parent with multiple views */
2009 parent = get_default_view(shsurf->parent);
2010 if (parent)
2011 return parent->layer_link.prev;
2012 }
Rafael Antognolli03b16592013-12-03 15:35:42 -02002013 break;
Philip Withnall07926d92013-11-25 18:01:40 +00002014
2015 case SHELL_SURFACE_XWAYLAND:
Kristian Høgsberg4804a302013-12-05 22:43:03 -08002016 return &shsurf->shell->fullscreen_layer.view_list;
2017
Philip Withnall07926d92013-11-25 18:01:40 +00002018 case SHELL_SURFACE_NONE:
2019 default:
2020 /* Go to the fallback, below. */
2021 break;
2022 }
2023
2024 /* Move the surface to a normal workspace layer so that surfaces
2025 * which were previously fullscreen or transient are no longer
2026 * rendered on top. */
2027 ws = get_current_workspace(shsurf->shell);
2028 return &ws->layer.view_list;
2029}
2030
Philip Withnall648a4dd2013-11-25 18:01:44 +00002031static void
2032shell_surface_update_child_surface_layers (struct shell_surface *shsurf)
2033{
2034 struct shell_surface *child;
2035
2036 /* Move the child layers to the same workspace as shsurf. They will be
2037 * stacked above shsurf. */
2038 wl_list_for_each_reverse(child, &shsurf->children_list, children_link) {
2039 if (shsurf->view->layer_link.prev != &child->view->layer_link) {
2040 weston_view_geometry_dirty(child->view);
2041 wl_list_remove(&child->view->layer_link);
2042 wl_list_insert(shsurf->view->layer_link.prev,
2043 &child->view->layer_link);
2044 weston_view_geometry_dirty(child->view);
2045 weston_surface_damage(child->surface);
2046
2047 /* Recurse. We don’t expect this to recurse very far (if
2048 * at all) because that would imply we have transient
2049 * (or popup) children of transient surfaces, which
2050 * would be unusual. */
2051 shell_surface_update_child_surface_layers(child);
2052 }
2053 }
2054}
2055
Philip Withnalle1d75ae2013-11-25 18:01:41 +00002056/* Update the surface’s layer. Mark both the old and new views as having dirty
Philip Withnall648a4dd2013-11-25 18:01:44 +00002057 * geometry to ensure the changes are redrawn.
2058 *
2059 * If any child surfaces exist and are mapped, ensure they’re in the same layer
2060 * as this surface. */
Philip Withnalle1d75ae2013-11-25 18:01:41 +00002061static void
2062shell_surface_update_layer(struct shell_surface *shsurf)
2063{
2064 struct wl_list *new_layer_link;
2065
2066 new_layer_link = shell_surface_calculate_layer_link(shsurf);
2067
2068 if (new_layer_link == &shsurf->view->layer_link)
2069 return;
2070
2071 weston_view_geometry_dirty(shsurf->view);
2072 wl_list_remove(&shsurf->view->layer_link);
2073 wl_list_insert(new_layer_link, &shsurf->view->layer_link);
2074 weston_view_geometry_dirty(shsurf->view);
2075 weston_surface_damage(shsurf->surface);
Philip Withnall648a4dd2013-11-25 18:01:44 +00002076
2077 shell_surface_update_child_surface_layers(shsurf);
Philip Withnalle1d75ae2013-11-25 18:01:41 +00002078}
2079
Alexander Larssonf82b6ca2013-05-28 16:23:39 +02002080static void
Philip Withnalldc4332f2013-11-25 18:01:38 +00002081shell_surface_set_parent(struct shell_surface *shsurf,
2082 struct weston_surface *parent)
2083{
2084 shsurf->parent = parent;
Philip Withnall648a4dd2013-11-25 18:01:44 +00002085
2086 wl_list_remove(&shsurf->children_link);
2087 wl_list_init(&shsurf->children_link);
2088
2089 /* Insert into the parent surface’s child list. */
2090 if (parent != NULL) {
2091 struct shell_surface *parent_shsurf = get_shell_surface(parent);
2092 if (parent_shsurf != NULL)
2093 wl_list_insert(&parent_shsurf->children_list,
2094 &shsurf->children_link);
2095 }
Philip Withnalldc4332f2013-11-25 18:01:38 +00002096}
2097
2098static void
Philip Withnall352e7ed2013-11-25 18:01:35 +00002099shell_surface_set_output(struct shell_surface *shsurf,
2100 struct weston_output *output)
2101{
2102 struct weston_surface *es = shsurf->surface;
2103
2104 /* get the default output, if the client set it as NULL
2105 check whether the ouput is available */
2106 if (output)
2107 shsurf->output = output;
2108 else if (es->output)
2109 shsurf->output = es->output;
2110 else
2111 shsurf->output = get_default_output(es->compositor);
2112}
2113
2114static void
Rafael Antognolli03b16592013-12-03 15:35:42 -02002115surface_clear_next_states(struct shell_surface *shsurf)
2116{
2117 shsurf->next_state.maximized = false;
2118 shsurf->next_state.fullscreen = false;
2119
2120 if ((shsurf->next_state.maximized != shsurf->state.maximized) ||
2121 (shsurf->next_state.fullscreen != shsurf->state.fullscreen))
2122 shsurf->state_changed = true;
2123}
2124
2125static void
Philip Withnallbecb77e2013-11-25 18:01:30 +00002126set_toplevel(struct shell_surface *shsurf)
2127{
Kristian Høgsberg41fbf6f2013-12-05 22:31:25 -08002128 shell_surface_set_parent(shsurf, NULL);
2129 surface_clear_next_states(shsurf);
Kristian Høgsbergc8f8dd82013-12-05 23:20:33 -08002130 shsurf->type = SHELL_SURFACE_TOPLEVEL;
Philip Withnall648a4dd2013-11-25 18:01:44 +00002131
2132 /* The layer_link is updated in set_surface_type(),
2133 * called from configure. */
Philip Withnallbecb77e2013-11-25 18:01:30 +00002134}
2135
2136static void
2137shell_surface_set_toplevel(struct wl_client *client,
2138 struct wl_resource *resource)
2139{
2140 struct shell_surface *surface = wl_resource_get_user_data(resource);
2141
2142 set_toplevel(surface);
2143}
2144
2145static void
2146set_transient(struct shell_surface *shsurf,
2147 struct weston_surface *parent, int x, int y, uint32_t flags)
2148{
Philip Withnalldc4332f2013-11-25 18:01:38 +00002149 assert(parent != NULL);
2150
Kristian Høgsberg9f7e3312014-01-02 22:40:37 -08002151 shell_surface_set_parent(shsurf, parent);
2152
2153 surface_clear_next_states(shsurf);
2154
Philip Withnallbecb77e2013-11-25 18:01:30 +00002155 shsurf->transient.x = x;
2156 shsurf->transient.y = y;
2157 shsurf->transient.flags = flags;
Philip Withnalldc4332f2013-11-25 18:01:38 +00002158
Rafael Antognollied207b42013-12-03 15:35:43 -02002159 shsurf->next_state.relative = true;
Kristian Høgsberga1df7ac2013-12-31 15:01:01 -08002160 shsurf->state_changed = true;
Kristian Høgsbergc8f8dd82013-12-05 23:20:33 -08002161 shsurf->type = SHELL_SURFACE_TOPLEVEL;
Philip Withnall648a4dd2013-11-25 18:01:44 +00002162
2163 /* The layer_link is updated in set_surface_type(),
2164 * called from configure. */
Philip Withnallbecb77e2013-11-25 18:01:30 +00002165}
2166
2167static void
2168shell_surface_set_transient(struct wl_client *client,
2169 struct wl_resource *resource,
2170 struct wl_resource *parent_resource,
2171 int x, int y, uint32_t flags)
2172{
2173 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
2174 struct weston_surface *parent =
2175 wl_resource_get_user_data(parent_resource);
2176
2177 set_transient(shsurf, parent, x, y, flags);
2178}
2179
2180static void
2181set_fullscreen(struct shell_surface *shsurf,
2182 uint32_t method,
2183 uint32_t framerate,
2184 struct weston_output *output)
2185{
Philip Withnall352e7ed2013-11-25 18:01:35 +00002186 shell_surface_set_output(shsurf, output);
Philip Withnallbecb77e2013-11-25 18:01:30 +00002187
2188 shsurf->fullscreen_output = shsurf->output;
2189 shsurf->fullscreen.type = method;
2190 shsurf->fullscreen.framerate = framerate;
Philip Withnalldc4332f2013-11-25 18:01:38 +00002191
Kristian Høgsberge960b3f2013-12-05 22:04:42 -08002192 shsurf->next_state.fullscreen = true;
2193 shsurf->state_changed = true;
Kristian Høgsbergc8f8dd82013-12-05 23:20:33 -08002194 shsurf->type = SHELL_SURFACE_TOPLEVEL;
Philip Withnallbecb77e2013-11-25 18:01:30 +00002195
2196 shsurf->client->send_configure(shsurf->surface, 0,
2197 shsurf->output->width,
2198 shsurf->output->height);
Philip Withnall648a4dd2013-11-25 18:01:44 +00002199
2200 /* The layer_link is updated in set_surface_type(),
2201 * called from configure. */
Philip Withnallbecb77e2013-11-25 18:01:30 +00002202}
2203
2204static void
Zhang, Xiong Y31236932013-12-13 22:10:57 +02002205weston_view_set_initial_position(struct weston_view *view,
2206 struct desktop_shell *shell);
2207
2208static void
Philip Withnallbecb77e2013-11-25 18:01:30 +00002209unset_fullscreen(struct shell_surface *shsurf)
Alex Wu4539b082012-03-01 12:57:46 +08002210{
Philip Withnallf85fe842013-11-25 18:01:37 +00002211 /* Unset the fullscreen output, driver configuration and transforms. */
Alex Wubd3354b2012-04-17 17:20:49 +08002212 if (shsurf->fullscreen.type == WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER &&
2213 shell_surface_is_top_fullscreen(shsurf)) {
Alexander Larssonf82b6ca2013-05-28 16:23:39 +02002214 restore_output_mode(shsurf->fullscreen_output);
Alex Wubd3354b2012-04-17 17:20:49 +08002215 }
Philip Withnallf85fe842013-11-25 18:01:37 +00002216 shsurf->fullscreen_output = NULL;
2217
Alex Wu4539b082012-03-01 12:57:46 +08002218 shsurf->fullscreen.type = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT;
2219 shsurf->fullscreen.framerate = 0;
Philip Withnallf85fe842013-11-25 18:01:37 +00002220
Alex Wu4539b082012-03-01 12:57:46 +08002221 wl_list_remove(&shsurf->fullscreen.transform.link);
2222 wl_list_init(&shsurf->fullscreen.transform.link);
Philip Withnallf85fe842013-11-25 18:01:37 +00002223
Jason Ekstranda7af7042013-10-12 22:38:11 -05002224 if (shsurf->fullscreen.black_view)
2225 weston_surface_destroy(shsurf->fullscreen.black_view->surface);
2226 shsurf->fullscreen.black_view = NULL;
Philip Withnallf85fe842013-11-25 18:01:37 +00002227
Zhang, Xiong Y31236932013-12-13 22:10:57 +02002228 if (shsurf->saved_position_valid)
2229 weston_view_set_position(shsurf->view,
2230 shsurf->saved_x, shsurf->saved_y);
2231 else
2232 weston_view_set_initial_position(shsurf->view, shsurf->shell);
2233
Alex Wu7bcb8bd2012-04-27 09:07:24 +08002234 if (shsurf->saved_rotation_valid) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05002235 wl_list_insert(&shsurf->view->geometry.transformation_list,
Philip Withnallbecb77e2013-11-25 18:01:30 +00002236 &shsurf->rotation.transform.link);
Alex Wu7bcb8bd2012-04-27 09:07:24 +08002237 shsurf->saved_rotation_valid = false;
2238 }
Rafal Mielniczuk3e3862c2012-10-07 20:25:36 +02002239
Philip Withnalle1d75ae2013-11-25 18:01:41 +00002240 /* Layer is updated in set_surface_type(). */
Alex Wu4539b082012-03-01 12:57:46 +08002241}
2242
Rafal Mielniczukfffdcdd2013-03-11 19:26:54 +01002243static void
Philip Withnallbecb77e2013-11-25 18:01:30 +00002244shell_surface_set_fullscreen(struct wl_client *client,
2245 struct wl_resource *resource,
2246 uint32_t method,
2247 uint32_t framerate,
2248 struct wl_resource *output_resource)
2249{
2250 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
2251 struct weston_output *output;
2252
2253 if (output_resource)
2254 output = wl_resource_get_user_data(output_resource);
2255 else
2256 output = NULL;
2257
Rafael Antognolli4b99a402013-12-03 15:35:44 -02002258 shell_surface_set_parent(shsurf, NULL);
2259
Rafael Antognolli03b16592013-12-03 15:35:42 -02002260 surface_clear_next_states(shsurf);
Philip Withnallbecb77e2013-11-25 18:01:30 +00002261 set_fullscreen(shsurf, method, framerate, output);
2262}
2263
2264static void
2265set_popup(struct shell_surface *shsurf,
2266 struct weston_surface *parent,
2267 struct weston_seat *seat,
2268 uint32_t serial,
2269 int32_t x,
2270 int32_t y)
2271{
Philip Withnalldc4332f2013-11-25 18:01:38 +00002272 assert(parent != NULL);
2273
Philip Withnallbecb77e2013-11-25 18:01:30 +00002274 shsurf->popup.shseat = get_shell_seat(seat);
2275 shsurf->popup.serial = serial;
2276 shsurf->popup.x = x;
2277 shsurf->popup.y = y;
Philip Withnalldc4332f2013-11-25 18:01:38 +00002278
Kristian Høgsbergc8f8dd82013-12-05 23:20:33 -08002279 shsurf->type = SHELL_SURFACE_POPUP;
Philip Withnallbecb77e2013-11-25 18:01:30 +00002280}
2281
2282static void
2283shell_surface_set_popup(struct wl_client *client,
2284 struct wl_resource *resource,
2285 struct wl_resource *seat_resource,
2286 uint32_t serial,
2287 struct wl_resource *parent_resource,
2288 int32_t x, int32_t y, uint32_t flags)
2289{
2290 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
Rafael Antognolli4b99a402013-12-03 15:35:44 -02002291 struct weston_surface *parent =
2292 wl_resource_get_user_data(parent_resource);
2293
2294 shell_surface_set_parent(shsurf, parent);
Philip Withnallbecb77e2013-11-25 18:01:30 +00002295
Rafael Antognolli03b16592013-12-03 15:35:42 -02002296 surface_clear_next_states(shsurf);
Philip Withnallbecb77e2013-11-25 18:01:30 +00002297 set_popup(shsurf,
Rafael Antognolli4b99a402013-12-03 15:35:44 -02002298 parent,
Philip Withnallbecb77e2013-11-25 18:01:30 +00002299 wl_resource_get_user_data(seat_resource),
2300 serial, x, y);
2301}
2302
2303static void
2304set_maximized(struct shell_surface *shsurf,
2305 struct weston_output *output)
2306{
2307 struct desktop_shell *shell;
2308 uint32_t edges = 0, panel_height = 0;
Philip Withnallbecb77e2013-11-25 18:01:30 +00002309
Philip Withnall352e7ed2013-11-25 18:01:35 +00002310 shell_surface_set_output(shsurf, output);
Philip Withnallbecb77e2013-11-25 18:01:30 +00002311
2312 shell = shell_surface_get_shell(shsurf);
2313 panel_height = get_output_panel_height(shell, shsurf->output);
2314 edges = WL_SHELL_SURFACE_RESIZE_TOP | WL_SHELL_SURFACE_RESIZE_LEFT;
2315
2316 shsurf->client->send_configure(shsurf->surface, edges,
2317 shsurf->output->width,
2318 shsurf->output->height - panel_height);
2319
Kristian Høgsbergc2745b12013-12-05 22:00:40 -08002320 shsurf->next_state.maximized = true;
2321 shsurf->state_changed = true;
Kristian Høgsbergc8f8dd82013-12-05 23:20:33 -08002322 shsurf->type = SHELL_SURFACE_TOPLEVEL;
Philip Withnallbecb77e2013-11-25 18:01:30 +00002323}
2324
2325static void
2326unset_maximized(struct shell_surface *shsurf)
Rafal Mielniczukfffdcdd2013-03-11 19:26:54 +01002327{
Rafal Mielniczukfffdcdd2013-03-11 19:26:54 +01002328 /* undo all maximized things here */
2329 shsurf->output = get_default_output(shsurf->surface->compositor);
Zhang, Xiong Y31236932013-12-13 22:10:57 +02002330
2331 if (shsurf->saved_position_valid)
2332 weston_view_set_position(shsurf->view,
2333 shsurf->saved_x, shsurf->saved_y);
2334 else
2335 weston_view_set_initial_position(shsurf->view, shsurf->shell);
Rafal Mielniczukfffdcdd2013-03-11 19:26:54 +01002336
2337 if (shsurf->saved_rotation_valid) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05002338 wl_list_insert(&shsurf->view->geometry.transformation_list,
2339 &shsurf->rotation.transform.link);
Rafal Mielniczukfffdcdd2013-03-11 19:26:54 +01002340 shsurf->saved_rotation_valid = false;
2341 }
2342
Philip Withnalle1d75ae2013-11-25 18:01:41 +00002343 /* Layer is updated in set_surface_type(). */
Rafal Mielniczukfffdcdd2013-03-11 19:26:54 +01002344}
2345
Philip Withnallbecb77e2013-11-25 18:01:30 +00002346static void
2347shell_surface_set_maximized(struct wl_client *client,
2348 struct wl_resource *resource,
2349 struct wl_resource *output_resource)
2350{
2351 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
2352 struct weston_output *output;
2353
2354 if (output_resource)
2355 output = wl_resource_get_user_data(output_resource);
2356 else
2357 output = NULL;
2358
Rafael Antognolli4b99a402013-12-03 15:35:44 -02002359 shell_surface_set_parent(shsurf, NULL);
2360
Rafael Antognolli03b16592013-12-03 15:35:42 -02002361 surface_clear_next_states(shsurf);
Philip Withnallbecb77e2013-11-25 18:01:30 +00002362 set_maximized(shsurf, output);
2363}
2364
Philip Withnalle1d75ae2013-11-25 18:01:41 +00002365/* This is only ever called from set_surface_type(), so there’s no need to
2366 * update layer_links here, since they’ll be updated when we return. */
Pekka Paalanen98262232011-12-01 10:42:22 +02002367static int
Philip Withnallbecb77e2013-11-25 18:01:30 +00002368reset_surface_type(struct shell_surface *surface)
Pekka Paalanen98262232011-12-01 10:42:22 +02002369{
Rafael Antognolli03b16592013-12-03 15:35:42 -02002370 if (surface->state.fullscreen)
Philip Withnallbecb77e2013-11-25 18:01:30 +00002371 unset_fullscreen(surface);
Rafael Antognolli03b16592013-12-03 15:35:42 -02002372 if (surface->state.maximized)
Philip Withnallbecb77e2013-11-25 18:01:30 +00002373 unset_maximized(surface);
Pekka Paalanen98262232011-12-01 10:42:22 +02002374
Pekka Paalanen98262232011-12-01 10:42:22 +02002375 return 0;
2376}
2377
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05002378static void
Rafael Antognolli03b16592013-12-03 15:35:42 -02002379set_full_output(struct shell_surface *shsurf)
2380{
2381 shsurf->saved_x = shsurf->view->geometry.x;
2382 shsurf->saved_y = shsurf->view->geometry.y;
Rafael Antognolli3c4e3f72013-12-03 15:35:46 -02002383 shsurf->saved_width = shsurf->surface->width;
2384 shsurf->saved_height = shsurf->surface->height;
2385 shsurf->saved_size_valid = true;
Rafael Antognolli03b16592013-12-03 15:35:42 -02002386 shsurf->saved_position_valid = true;
2387
2388 if (!wl_list_empty(&shsurf->rotation.transform.link)) {
2389 wl_list_remove(&shsurf->rotation.transform.link);
2390 wl_list_init(&shsurf->rotation.transform.link);
2391 weston_view_geometry_dirty(shsurf->view);
2392 shsurf->saved_rotation_valid = true;
2393 }
2394}
2395
2396static void
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04002397set_surface_type(struct shell_surface *shsurf)
2398{
Kristian Høgsberg8150b192012-06-27 10:22:58 -04002399 struct weston_surface *pes = shsurf->parent;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002400 struct weston_view *pev = get_default_view(pes);
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04002401
Philip Withnallbecb77e2013-11-25 18:01:30 +00002402 reset_surface_type(shsurf);
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04002403
Rafael Antognolli03b16592013-12-03 15:35:42 -02002404 shsurf->state = shsurf->next_state;
Rafael Antognolli03b16592013-12-03 15:35:42 -02002405 shsurf->state_changed = false;
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04002406
2407 switch (shsurf->type) {
2408 case SHELL_SURFACE_TOPLEVEL:
Rafael Antognollied207b42013-12-03 15:35:43 -02002409 if (shsurf->state.maximized || shsurf->state.fullscreen) {
Rafael Antognolli03b16592013-12-03 15:35:42 -02002410 set_full_output(shsurf);
Rafael Antognollied207b42013-12-03 15:35:43 -02002411 } else if (shsurf->state.relative && pev) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05002412 weston_view_set_position(shsurf->view,
2413 pev->geometry.x + shsurf->transient.x,
2414 pev->geometry.y + shsurf->transient.y);
Rafael Antognollied207b42013-12-03 15:35:43 -02002415 }
Rafael Antognolli44a31622013-12-04 18:37:16 -02002416 break;
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04002417
Tiago Vignattifb2adba2013-06-12 15:43:21 -03002418 case SHELL_SURFACE_XWAYLAND:
Jason Ekstranda7af7042013-10-12 22:38:11 -05002419 weston_view_set_position(shsurf->view, shsurf->transient.x,
2420 shsurf->transient.y);
Tiago Vignattifb2adba2013-06-12 15:43:21 -03002421 break;
2422
Philip Withnall0f640e22013-11-25 18:01:31 +00002423 case SHELL_SURFACE_POPUP:
2424 case SHELL_SURFACE_NONE:
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04002425 default:
2426 break;
2427 }
Philip Withnalle1d75ae2013-11-25 18:01:41 +00002428
2429 /* Update the surface’s layer. */
2430 shell_surface_update_layer(shsurf);
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04002431}
2432
Tiago Vignattibe143262012-04-16 17:31:41 +03002433static struct desktop_shell *
Juan Zhao96879df2012-02-07 08:45:41 +08002434shell_surface_get_shell(struct shell_surface *shsurf)
Pekka Paalanenaf0e34c2011-12-02 10:59:17 +02002435{
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04002436 return shsurf->shell;
Juan Zhao96879df2012-02-07 08:45:41 +08002437}
2438
Alex Wu21858432012-04-01 20:13:08 +08002439static void
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06002440black_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy);
Alex Wu21858432012-04-01 20:13:08 +08002441
Jason Ekstranda7af7042013-10-12 22:38:11 -05002442static struct weston_view *
Alex Wu4539b082012-03-01 12:57:46 +08002443create_black_surface(struct weston_compositor *ec,
Alex Wu21858432012-04-01 20:13:08 +08002444 struct weston_surface *fs_surface,
John Kåre Alsaker490d02a2012-09-30 02:57:21 +02002445 float x, float y, int w, int h)
Alex Wu4539b082012-03-01 12:57:46 +08002446{
2447 struct weston_surface *surface = NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002448 struct weston_view *view;
Alex Wu4539b082012-03-01 12:57:46 +08002449
2450 surface = weston_surface_create(ec);
2451 if (surface == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002452 weston_log("no memory\n");
Alex Wu4539b082012-03-01 12:57:46 +08002453 return NULL;
2454 }
Jason Ekstranda7af7042013-10-12 22:38:11 -05002455 view = weston_view_create(surface);
2456 if (surface == NULL) {
2457 weston_log("no memory\n");
2458 weston_surface_destroy(surface);
2459 return NULL;
2460 }
Alex Wu4539b082012-03-01 12:57:46 +08002461
Alex Wu21858432012-04-01 20:13:08 +08002462 surface->configure = black_surface_configure;
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01002463 surface->configure_private = fs_surface;
Alex Wu4539b082012-03-01 12:57:46 +08002464 weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1);
Pekka Paalanen71f6f3b2012-10-10 12:49:26 +03002465 pixman_region32_fini(&surface->opaque);
Kristian Høgsberg61f00f52012-08-03 16:31:36 -04002466 pixman_region32_init_rect(&surface->opaque, 0, 0, w, h);
Jonas Ådahl33619a42013-01-15 21:25:55 +01002467 pixman_region32_fini(&surface->input);
2468 pixman_region32_init_rect(&surface->input, 0, 0, w, h);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06002469
Jason Ekstrand6228ee22014-01-01 15:58:57 -06002470 weston_surface_set_size(surface, w, h);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06002471 weston_view_set_position(view, x, y);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002472
2473 return view;
Alex Wu4539b082012-03-01 12:57:46 +08002474}
2475
Philip Withnalled8f1a92013-11-25 18:01:43 +00002476static void
2477shell_ensure_fullscreen_black_view(struct shell_surface *shsurf)
2478{
2479 struct weston_output *output = shsurf->fullscreen_output;
2480
Rafael Antognolli03b16592013-12-03 15:35:42 -02002481 assert(shsurf->state.fullscreen);
Philip Withnalled8f1a92013-11-25 18:01:43 +00002482
2483 if (!shsurf->fullscreen.black_view)
2484 shsurf->fullscreen.black_view =
2485 create_black_surface(shsurf->surface->compositor,
2486 shsurf->surface,
2487 output->x, output->y,
2488 output->width,
2489 output->height);
2490
2491 weston_view_geometry_dirty(shsurf->fullscreen.black_view);
2492 wl_list_remove(&shsurf->fullscreen.black_view->layer_link);
2493 wl_list_insert(&shsurf->view->layer_link,
2494 &shsurf->fullscreen.black_view->layer_link);
2495 weston_view_geometry_dirty(shsurf->fullscreen.black_view);
2496 weston_surface_damage(shsurf->surface);
2497}
2498
Alex Wu4539b082012-03-01 12:57:46 +08002499/* Create black surface and append it to the associated fullscreen surface.
2500 * Handle size dismatch and positioning according to the method. */
2501static void
2502shell_configure_fullscreen(struct shell_surface *shsurf)
2503{
2504 struct weston_output *output = shsurf->fullscreen_output;
2505 struct weston_surface *surface = shsurf->surface;
2506 struct weston_matrix *matrix;
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04002507 float scale, output_aspect, surface_aspect, x, y;
Giulio Camuffob8366642013-04-25 13:57:46 +03002508 int32_t surf_x, surf_y, surf_width, surf_height;
Alex Wu4539b082012-03-01 12:57:46 +08002509
Alexander Larssonf82b6ca2013-05-28 16:23:39 +02002510 if (shsurf->fullscreen.type != WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER)
2511 restore_output_mode(output);
2512
Philip Withnalled8f1a92013-11-25 18:01:43 +00002513 shell_ensure_fullscreen_black_view(shsurf);
Alex Wu4539b082012-03-01 12:57:46 +08002514
Jason Ekstranda7af7042013-10-12 22:38:11 -05002515 surface_subsurfaces_boundingbox(shsurf->surface, &surf_x, &surf_y,
Giulio Camuffob8366642013-04-25 13:57:46 +03002516 &surf_width, &surf_height);
2517
Alex Wu4539b082012-03-01 12:57:46 +08002518 switch (shsurf->fullscreen.type) {
2519 case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT:
Pekka Paalanende685b82012-12-04 15:58:12 +02002520 if (surface->buffer_ref.buffer)
Jason Ekstranda7af7042013-10-12 22:38:11 -05002521 center_on_output(shsurf->view, shsurf->fullscreen_output);
Alex Wu4539b082012-03-01 12:57:46 +08002522 break;
2523 case WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE:
Rob Bradford9f3dd152013-02-12 11:53:47 +00002524 /* 1:1 mapping between surface and output dimensions */
Giulio Camuffob8366642013-04-25 13:57:46 +03002525 if (output->width == surf_width &&
2526 output->height == surf_height) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05002527 weston_view_set_position(shsurf->view,
2528 output->x - surf_x,
2529 output->y - surf_y);
Rob Bradford9f3dd152013-02-12 11:53:47 +00002530 break;
2531 }
2532
Alex Wu4539b082012-03-01 12:57:46 +08002533 matrix = &shsurf->fullscreen.transform.matrix;
2534 weston_matrix_init(matrix);
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04002535
Scott Moreau1bad5db2012-08-18 01:04:05 -06002536 output_aspect = (float) output->width /
2537 (float) output->height;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002538 /* XXX: Use surf_width and surf_height here? */
2539 surface_aspect = (float) surface->width /
2540 (float) surface->height;
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04002541 if (output_aspect < surface_aspect)
Scott Moreau1bad5db2012-08-18 01:04:05 -06002542 scale = (float) output->width /
Giulio Camuffob8366642013-04-25 13:57:46 +03002543 (float) surf_width;
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04002544 else
Scott Moreau1bad5db2012-08-18 01:04:05 -06002545 scale = (float) output->height /
Giulio Camuffob8366642013-04-25 13:57:46 +03002546 (float) surf_height;
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04002547
Alex Wu4539b082012-03-01 12:57:46 +08002548 weston_matrix_scale(matrix, scale, scale, 1);
2549 wl_list_remove(&shsurf->fullscreen.transform.link);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002550 wl_list_insert(&shsurf->view->geometry.transformation_list,
Alex Wu4539b082012-03-01 12:57:46 +08002551 &shsurf->fullscreen.transform.link);
Giulio Camuffob8366642013-04-25 13:57:46 +03002552 x = output->x + (output->width - surf_width * scale) / 2 - surf_x;
2553 y = output->y + (output->height - surf_height * scale) / 2 - surf_y;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002554 weston_view_set_position(shsurf->view, x, y);
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04002555
Alex Wu4539b082012-03-01 12:57:46 +08002556 break;
2557 case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER:
Alex Wubd3354b2012-04-17 17:20:49 +08002558 if (shell_surface_is_top_fullscreen(shsurf)) {
Quentin Glidicc0d79ce2013-01-29 14:16:13 +01002559 struct weston_mode mode = {0,
Pekka Paalanen1fd9c0f2013-11-26 18:19:41 +01002560 surf_width * surface->buffer_viewport.scale,
2561 surf_height * surface->buffer_viewport.scale,
Alex Wubd3354b2012-04-17 17:20:49 +08002562 shsurf->fullscreen.framerate};
2563
Pekka Paalanen1fd9c0f2013-11-26 18:19:41 +01002564 if (weston_output_switch_mode(output, &mode, surface->buffer_viewport.scale,
Hardening57388e42013-09-18 23:56:36 +02002565 WESTON_MODE_SWITCH_SET_TEMPORARY) == 0) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05002566 weston_view_set_position(shsurf->view,
2567 output->x - surf_x,
2568 output->y - surf_y);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06002569 shsurf->fullscreen.black_view->surface->width = output->width;
2570 shsurf->fullscreen.black_view->surface->height = output->height;
2571 weston_view_set_position(shsurf->fullscreen.black_view,
2572 output->x - surf_x,
2573 output->y - surf_y);
Alex Wubd3354b2012-04-17 17:20:49 +08002574 break;
Alexander Larssond622ed32013-05-28 16:23:40 +02002575 } else {
Alexander Larssonf82b6ca2013-05-28 16:23:39 +02002576 restore_output_mode(output);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002577 center_on_output(shsurf->view, output);
Alexander Larssond622ed32013-05-28 16:23:40 +02002578 }
Alex Wubd3354b2012-04-17 17:20:49 +08002579 }
Alex Wu4539b082012-03-01 12:57:46 +08002580 break;
2581 case WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL:
Jason Ekstranda7af7042013-10-12 22:38:11 -05002582 center_on_output(shsurf->view, output);
Alex Wu4539b082012-03-01 12:57:46 +08002583 break;
2584 default:
2585 break;
2586 }
2587}
2588
Alex Wu4539b082012-03-01 12:57:46 +08002589static void
2590shell_map_fullscreen(struct shell_surface *shsurf)
2591{
Alex Wubd3354b2012-04-17 17:20:49 +08002592 shell_configure_fullscreen(shsurf);
Alex Wu4539b082012-03-01 12:57:46 +08002593}
2594
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04002595static void
Tiago Vignattifb2adba2013-06-12 15:43:21 -03002596set_xwayland(struct shell_surface *shsurf, int x, int y, uint32_t flags)
2597{
2598 /* XXX: using the same fields for transient type */
Rafael Antognolli03b16592013-12-03 15:35:42 -02002599 surface_clear_next_states(shsurf);
Tiago Vignattifb2adba2013-06-12 15:43:21 -03002600 shsurf->transient.x = x;
2601 shsurf->transient.y = y;
2602 shsurf->transient.flags = flags;
Philip Withnalldc4332f2013-11-25 18:01:38 +00002603
2604 shell_surface_set_parent(shsurf, NULL);
2605
Kristian Høgsbergc8f8dd82013-12-05 23:20:33 -08002606 shsurf->type = SHELL_SURFACE_XWAYLAND;
Kristian Høgsberg8bc525c2014-01-01 22:34:49 -08002607 shsurf->state_changed = true;
Tiago Vignattifb2adba2013-06-12 15:43:21 -03002608}
2609
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04002610static const struct weston_pointer_grab_interface popup_grab_interface;
Giulio Camuffo5085a752013-03-25 21:42:45 +01002611
2612static void
2613destroy_shell_seat(struct wl_listener *listener, void *data)
2614{
2615 struct shell_seat *shseat =
2616 container_of(listener,
2617 struct shell_seat, seat_destroy_listener);
2618 struct shell_surface *shsurf, *prev = NULL;
2619
2620 if (shseat->popup_grab.grab.interface == &popup_grab_interface) {
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04002621 weston_pointer_end_grab(shseat->popup_grab.grab.pointer);
Giulio Camuffo5085a752013-03-25 21:42:45 +01002622 shseat->popup_grab.client = NULL;
2623
2624 wl_list_for_each(shsurf, &shseat->popup_grab.surfaces_list, popup.grab_link) {
2625 shsurf->popup.shseat = NULL;
2626 if (prev) {
2627 wl_list_init(&prev->popup.grab_link);
2628 }
2629 prev = shsurf;
2630 }
2631 wl_list_init(&prev->popup.grab_link);
2632 }
2633
2634 wl_list_remove(&shseat->seat_destroy_listener.link);
2635 free(shseat);
2636}
2637
2638static struct shell_seat *
2639create_shell_seat(struct weston_seat *seat)
2640{
2641 struct shell_seat *shseat;
2642
2643 shseat = calloc(1, sizeof *shseat);
2644 if (!shseat) {
2645 weston_log("no memory to allocate shell seat\n");
2646 return NULL;
2647 }
2648
2649 shseat->seat = seat;
2650 wl_list_init(&shseat->popup_grab.surfaces_list);
2651
2652 shseat->seat_destroy_listener.notify = destroy_shell_seat;
2653 wl_signal_add(&seat->destroy_signal,
2654 &shseat->seat_destroy_listener);
2655
2656 return shseat;
2657}
2658
2659static struct shell_seat *
2660get_shell_seat(struct weston_seat *seat)
2661{
2662 struct wl_listener *listener;
2663
2664 listener = wl_signal_get(&seat->destroy_signal, destroy_shell_seat);
2665 if (listener == NULL)
2666 return create_shell_seat(seat);
2667
2668 return container_of(listener,
2669 struct shell_seat, seat_destroy_listener);
2670}
2671
Kristian Høgsbergb810eb52013-02-12 20:07:05 -05002672static void
Kristian Høgsberg6848c252013-05-08 22:02:59 -04002673popup_grab_focus(struct weston_pointer_grab *grab)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002674{
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04002675 struct weston_pointer *pointer = grab->pointer;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002676 struct weston_view *view;
Giulio Camuffo5085a752013-03-25 21:42:45 +01002677 struct shell_seat *shseat =
2678 container_of(grab, struct shell_seat, popup_grab.grab);
2679 struct wl_client *client = shseat->popup_grab.client;
Kristian Høgsberg6848c252013-05-08 22:02:59 -04002680 wl_fixed_t sx, sy;
2681
Jason Ekstranda7af7042013-10-12 22:38:11 -05002682 view = weston_compositor_pick_view(pointer->seat->compositor,
2683 pointer->x, pointer->y,
2684 &sx, &sy);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002685
Jason Ekstranda7af7042013-10-12 22:38:11 -05002686 if (view && view->surface->resource &&
2687 wl_resource_get_client(view->surface->resource) == client) {
2688 weston_pointer_set_focus(pointer, view, sx, sy);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002689 } else {
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04002690 weston_pointer_set_focus(pointer, NULL,
2691 wl_fixed_from_int(0),
2692 wl_fixed_from_int(0));
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002693 }
2694}
2695
2696static void
Giulio Camuffo1959ab82013-11-14 23:42:52 +01002697popup_grab_motion(struct weston_pointer_grab *grab, uint32_t time,
2698 wl_fixed_t x, wl_fixed_t y)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002699{
Kristian Høgsbergbe6403e2013-05-08 21:03:21 -04002700 struct weston_pointer *pointer = grab->pointer;
Neil Roberts96d790e2013-09-19 17:32:00 +01002701 struct wl_resource *resource;
Kristian Høgsbergbe6403e2013-05-08 21:03:21 -04002702 wl_fixed_t sx, sy;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002703
Giulio Camuffo1959ab82013-11-14 23:42:52 +01002704 weston_pointer_move(pointer, x, y);
2705
Neil Roberts96d790e2013-09-19 17:32:00 +01002706 wl_resource_for_each(resource, &pointer->focus_resource_list) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05002707 weston_view_from_global_fixed(pointer->focus,
2708 pointer->x, pointer->y,
2709 &sx, &sy);
Neil Roberts96d790e2013-09-19 17:32:00 +01002710 wl_pointer_send_motion(resource, time, sx, sy);
Kristian Høgsbergbe6403e2013-05-08 21:03:21 -04002711 }
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002712}
2713
2714static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04002715popup_grab_button(struct weston_pointer_grab *grab,
Daniel Stone4dbadb12012-05-30 16:31:51 +01002716 uint32_t time, uint32_t button, uint32_t state_w)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002717{
2718 struct wl_resource *resource;
Giulio Camuffo5085a752013-03-25 21:42:45 +01002719 struct shell_seat *shseat =
2720 container_of(grab, struct shell_seat, popup_grab.grab);
Rob Bradford880ebc72013-07-22 17:31:38 +01002721 struct wl_display *display = shseat->seat->compositor->wl_display;
Daniel Stone4dbadb12012-05-30 16:31:51 +01002722 enum wl_pointer_button_state state = state_w;
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04002723 uint32_t serial;
Neil Roberts96d790e2013-09-19 17:32:00 +01002724 struct wl_list *resource_list;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002725
Neil Roberts96d790e2013-09-19 17:32:00 +01002726 resource_list = &grab->pointer->focus_resource_list;
2727 if (!wl_list_empty(resource_list)) {
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04002728 serial = wl_display_get_serial(display);
Neil Roberts96d790e2013-09-19 17:32:00 +01002729 wl_resource_for_each(resource, resource_list) {
2730 wl_pointer_send_button(resource, serial,
2731 time, button, state);
2732 }
Daniel Stone4dbadb12012-05-30 16:31:51 +01002733 } else if (state == WL_POINTER_BUTTON_STATE_RELEASED &&
Giulio Camuffo5085a752013-03-25 21:42:45 +01002734 (shseat->popup_grab.initial_up ||
Kristian Høgsberge3148752013-05-06 23:19:49 -04002735 time - shseat->seat->pointer->grab_time > 500)) {
Kristian Høgsberg57e09072012-10-30 14:07:27 -04002736 popup_grab_end(grab->pointer);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002737 }
2738
Daniel Stone4dbadb12012-05-30 16:31:51 +01002739 if (state == WL_POINTER_BUTTON_STATE_RELEASED)
Giulio Camuffo5085a752013-03-25 21:42:45 +01002740 shseat->popup_grab.initial_up = 1;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002741}
2742
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02002743static void
2744popup_grab_cancel(struct weston_pointer_grab *grab)
2745{
2746 popup_grab_end(grab->pointer);
2747}
2748
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04002749static const struct weston_pointer_grab_interface popup_grab_interface = {
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002750 popup_grab_focus,
2751 popup_grab_motion,
2752 popup_grab_button,
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02002753 popup_grab_cancel,
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002754};
2755
2756static void
Rafael Antognollie2a34552013-12-03 15:35:45 -02002757shell_surface_send_popup_done(struct shell_surface *shsurf)
2758{
2759 if (shell_surface_is_wl_shell_surface(shsurf))
2760 wl_shell_surface_send_popup_done(shsurf->resource);
2761 else if (shell_surface_is_xdg_popup(shsurf))
2762 xdg_popup_send_popup_done(shsurf->resource,
2763 shsurf->popup.serial);
2764}
2765
2766static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04002767popup_grab_end(struct weston_pointer *pointer)
Kristian Høgsberg57e09072012-10-30 14:07:27 -04002768{
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04002769 struct weston_pointer_grab *grab = pointer->grab;
Giulio Camuffo5085a752013-03-25 21:42:45 +01002770 struct shell_seat *shseat =
2771 container_of(grab, struct shell_seat, popup_grab.grab);
2772 struct shell_surface *shsurf;
2773 struct shell_surface *prev = NULL;
Kristian Høgsberg57e09072012-10-30 14:07:27 -04002774
2775 if (pointer->grab->interface == &popup_grab_interface) {
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04002776 weston_pointer_end_grab(grab->pointer);
Giulio Camuffo5085a752013-03-25 21:42:45 +01002777 shseat->popup_grab.client = NULL;
Philipp Brüschweiler63e7be62013-04-15 21:09:54 +02002778 shseat->popup_grab.grab.interface = NULL;
2779 assert(!wl_list_empty(&shseat->popup_grab.surfaces_list));
Giulio Camuffo5085a752013-03-25 21:42:45 +01002780 /* Send the popup_done event to all the popups open */
2781 wl_list_for_each(shsurf, &shseat->popup_grab.surfaces_list, popup.grab_link) {
Rafael Antognollie2a34552013-12-03 15:35:45 -02002782 shell_surface_send_popup_done(shsurf);
Giulio Camuffo5085a752013-03-25 21:42:45 +01002783 shsurf->popup.shseat = NULL;
2784 if (prev) {
2785 wl_list_init(&prev->popup.grab_link);
2786 }
2787 prev = shsurf;
2788 }
2789 wl_list_init(&prev->popup.grab_link);
2790 wl_list_init(&shseat->popup_grab.surfaces_list);
2791 }
2792}
2793
2794static void
2795add_popup_grab(struct shell_surface *shsurf, struct shell_seat *shseat)
2796{
Kristian Høgsberge3148752013-05-06 23:19:49 -04002797 struct weston_seat *seat = shseat->seat;
Giulio Camuffo5085a752013-03-25 21:42:45 +01002798
2799 if (wl_list_empty(&shseat->popup_grab.surfaces_list)) {
Jason Ekstrand651f00e2013-06-14 10:07:54 -05002800 shseat->popup_grab.client = wl_resource_get_client(shsurf->resource);
Giulio Camuffo5085a752013-03-25 21:42:45 +01002801 shseat->popup_grab.grab.interface = &popup_grab_interface;
Giulio Camuffo1b4b61a2013-03-27 18:05:26 +01002802 /* We must make sure here that this popup was opened after
2803 * a mouse press, and not just by moving around with other
2804 * popups already open. */
Kristian Høgsberge3148752013-05-06 23:19:49 -04002805 if (shseat->seat->pointer->button_count > 0)
Giulio Camuffo1b4b61a2013-03-27 18:05:26 +01002806 shseat->popup_grab.initial_up = 0;
Giulio Camuffo5085a752013-03-25 21:42:45 +01002807
Rob Bradforddfe31052013-06-26 19:49:11 +01002808 wl_list_insert(&shseat->popup_grab.surfaces_list, &shsurf->popup.grab_link);
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04002809 weston_pointer_start_grab(seat->pointer, &shseat->popup_grab.grab);
Rob Bradforddfe31052013-06-26 19:49:11 +01002810 } else {
2811 wl_list_insert(&shseat->popup_grab.surfaces_list, &shsurf->popup.grab_link);
Giulio Camuffo5085a752013-03-25 21:42:45 +01002812 }
Giulio Camuffo5085a752013-03-25 21:42:45 +01002813}
2814
2815static void
2816remove_popup_grab(struct shell_surface *shsurf)
2817{
2818 struct shell_seat *shseat = shsurf->popup.shseat;
2819
2820 wl_list_remove(&shsurf->popup.grab_link);
2821 wl_list_init(&shsurf->popup.grab_link);
2822 if (wl_list_empty(&shseat->popup_grab.surfaces_list)) {
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04002823 weston_pointer_end_grab(shseat->popup_grab.grab.pointer);
Philipp Brüschweiler63e7be62013-04-15 21:09:54 +02002824 shseat->popup_grab.grab.interface = NULL;
Kristian Høgsberg57e09072012-10-30 14:07:27 -04002825 }
2826}
2827
2828static void
Kristian Høgsberg3730f362012-04-13 12:40:07 -04002829shell_map_popup(struct shell_surface *shsurf)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002830{
Giulio Camuffo5085a752013-03-25 21:42:45 +01002831 struct shell_seat *shseat = shsurf->popup.shseat;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002832 struct weston_view *parent_view = get_default_view(shsurf->parent);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002833
Jason Ekstranda7af7042013-10-12 22:38:11 -05002834 shsurf->surface->output = parent_view->output;
2835 shsurf->view->output = parent_view->output;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002836
Jason Ekstranda7af7042013-10-12 22:38:11 -05002837 weston_view_set_transform_parent(shsurf->view, parent_view);
2838 weston_view_set_position(shsurf->view, shsurf->popup.x, shsurf->popup.y);
2839 weston_view_update_transform(shsurf->view);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002840
Kristian Høgsberge3148752013-05-06 23:19:49 -04002841 if (shseat->seat->pointer->grab_serial == shsurf->popup.serial) {
Giulio Camuffo5085a752013-03-25 21:42:45 +01002842 add_popup_grab(shsurf, shseat);
Kristian Høgsberg3730f362012-04-13 12:40:07 -04002843 } else {
Rafael Antognollie2a34552013-12-03 15:35:45 -02002844 shell_surface_send_popup_done(shsurf);
Giulio Camuffo5085a752013-03-25 21:42:45 +01002845 shseat->popup_grab.client = NULL;
Kristian Høgsberg3730f362012-04-13 12:40:07 -04002846 }
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002847}
2848
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002849static const struct wl_shell_surface_interface shell_surface_implementation = {
Scott Moreauff1db4a2012-04-17 19:06:18 -06002850 shell_surface_pong,
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002851 shell_surface_move,
2852 shell_surface_resize,
2853 shell_surface_set_toplevel,
2854 shell_surface_set_transient,
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002855 shell_surface_set_fullscreen,
Juan Zhao96879df2012-02-07 08:45:41 +08002856 shell_surface_set_popup,
Kristian Høgsberge7afd912012-05-02 09:47:44 -04002857 shell_surface_set_maximized,
2858 shell_surface_set_title,
2859 shell_surface_set_class
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002860};
2861
2862static void
Tiago Vignattibc052c92012-04-19 16:18:18 +03002863destroy_shell_surface(struct shell_surface *shsurf)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002864{
Kristian Høgsberg9046d242014-01-10 00:25:30 -08002865 struct shell_surface *child, *next;
2866
Jason Ekstrand651f00e2013-06-14 10:07:54 -05002867 wl_signal_emit(&shsurf->destroy_signal, shsurf);
2868
Giulio Camuffo5085a752013-03-25 21:42:45 +01002869 if (!wl_list_empty(&shsurf->popup.grab_link)) {
2870 remove_popup_grab(shsurf);
2871 }
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002872
Alex Wubd3354b2012-04-17 17:20:49 +08002873 if (shsurf->fullscreen.type == WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER &&
Alexander Larssonf82b6ca2013-05-28 16:23:39 +02002874 shell_surface_is_top_fullscreen(shsurf))
2875 restore_output_mode (shsurf->fullscreen_output);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002876
Jason Ekstranda7af7042013-10-12 22:38:11 -05002877 if (shsurf->fullscreen.black_view)
2878 weston_surface_destroy(shsurf->fullscreen.black_view->surface);
Alex Wuaa08e2d2012-03-05 11:01:40 +08002879
Alex Wubd3354b2012-04-17 17:20:49 +08002880 /* As destroy_resource() use wl_list_for_each_safe(),
2881 * we can always remove the listener.
2882 */
2883 wl_list_remove(&shsurf->surface_destroy_listener.link);
2884 shsurf->surface->configure = NULL;
Scott Moreau9521d5e2012-04-19 13:06:17 -06002885 ping_timer_destroy(shsurf);
Scott Moreau976a0502013-03-07 10:15:17 -07002886 free(shsurf->title);
Alex Wubd3354b2012-04-17 17:20:49 +08002887
Jason Ekstranda7af7042013-10-12 22:38:11 -05002888 weston_view_destroy(shsurf->view);
2889
Philip Withnall648a4dd2013-11-25 18:01:44 +00002890 wl_list_remove(&shsurf->children_link);
Kristian Høgsberg9046d242014-01-10 00:25:30 -08002891 wl_list_for_each_safe(child, next, &shsurf->children_list, children_link) {
2892 wl_list_remove(&child->children_link);
2893 child->parent = NULL;
2894 }
Philip Withnall648a4dd2013-11-25 18:01:44 +00002895
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002896 wl_list_remove(&shsurf->link);
2897 free(shsurf);
2898}
2899
2900static void
Tiago Vignattibc052c92012-04-19 16:18:18 +03002901shell_destroy_shell_surface(struct wl_resource *resource)
2902{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05002903 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
Tiago Vignattibc052c92012-04-19 16:18:18 +03002904
2905 destroy_shell_surface(shsurf);
2906}
2907
2908static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04002909shell_handle_surface_destroy(struct wl_listener *listener, void *data)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002910{
2911 struct shell_surface *shsurf = container_of(listener,
2912 struct shell_surface,
2913 surface_destroy_listener);
2914
Jason Ekstrand651f00e2013-06-14 10:07:54 -05002915 if (shsurf->resource)
2916 wl_resource_destroy(shsurf->resource);
2917 else
Tiago Vignattibc052c92012-04-19 16:18:18 +03002918 destroy_shell_surface(shsurf);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002919}
2920
Kristian Høgsbergd8134452012-06-21 12:49:02 -04002921static void
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06002922shell_surface_configure(struct weston_surface *, int32_t, int32_t);
Zhang, Xiong Y31236932013-12-13 22:10:57 +02002923static void
2924shell_surface_output_destroyed(struct weston_surface *);
Kristian Høgsbergd8134452012-06-21 12:49:02 -04002925
Kristian Høgsberg1ef23132013-12-04 00:20:01 -08002926struct shell_surface *
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002927get_shell_surface(struct weston_surface *surface)
Pekka Paalanenec2b32f2011-11-28 15:12:34 +02002928{
Kristian Høgsbergd8134452012-06-21 12:49:02 -04002929 if (surface->configure == shell_surface_configure)
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01002930 return surface->configure_private;
Kristian Høgsbergd8134452012-06-21 12:49:02 -04002931 else
2932 return NULL;
Pekka Paalanenec2b32f2011-11-28 15:12:34 +02002933}
2934
Rafael Antognollie2a34552013-12-03 15:35:45 -02002935static struct shell_surface *
2936create_common_surface(void *shell, struct weston_surface *surface,
2937 const struct weston_shell_client *client)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002938{
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002939 struct shell_surface *shsurf;
2940
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03002941 if (surface->configure) {
Martin Minarik6d118362012-06-07 18:01:59 +02002942 weston_log("surface->configure already set\n");
Kristian Høgsberg45ba8692012-05-21 14:27:33 -04002943 return NULL;
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03002944 }
2945
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002946 shsurf = calloc(1, sizeof *shsurf);
2947 if (!shsurf) {
Martin Minarik6d118362012-06-07 18:01:59 +02002948 weston_log("no memory to allocate shell surface\n");
Kristian Høgsberg45ba8692012-05-21 14:27:33 -04002949 return NULL;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002950 }
2951
Jason Ekstranda7af7042013-10-12 22:38:11 -05002952 shsurf->view = weston_view_create(surface);
2953 if (!shsurf->view) {
2954 weston_log("no memory to allocate shell surface\n");
2955 free(shsurf);
2956 return NULL;
2957 }
2958
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03002959 surface->configure = shell_surface_configure;
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01002960 surface->configure_private = shsurf;
Zhang, Xiong Y31236932013-12-13 22:10:57 +02002961 surface->output_destroyed = shell_surface_output_destroyed;
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03002962
Tiago Vignattibc052c92012-04-19 16:18:18 +03002963 shsurf->shell = (struct desktop_shell *) shell;
Scott Moreauff1db4a2012-04-17 19:06:18 -06002964 shsurf->unresponsive = 0;
Alex Wu4539b082012-03-01 12:57:46 +08002965 shsurf->saved_position_valid = false;
Rafael Antognolli3c4e3f72013-12-03 15:35:46 -02002966 shsurf->saved_size_valid = false;
Alex Wu7bcb8bd2012-04-27 09:07:24 +08002967 shsurf->saved_rotation_valid = false;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002968 shsurf->surface = surface;
Alex Wu4539b082012-03-01 12:57:46 +08002969 shsurf->fullscreen.type = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT;
2970 shsurf->fullscreen.framerate = 0;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002971 shsurf->fullscreen.black_view = NULL;
Scott Moreauff1db4a2012-04-17 19:06:18 -06002972 shsurf->ping_timer = NULL;
Alex Wu4539b082012-03-01 12:57:46 +08002973 wl_list_init(&shsurf->fullscreen.transform.link);
2974
Jason Ekstrand651f00e2013-06-14 10:07:54 -05002975 wl_signal_init(&shsurf->destroy_signal);
Kristian Høgsberg27e30522012-04-11 23:18:23 -04002976 shsurf->surface_destroy_listener.notify = shell_handle_surface_destroy;
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05002977 wl_signal_add(&surface->destroy_signal,
Kristian Høgsberg27e30522012-04-11 23:18:23 -04002978 &shsurf->surface_destroy_listener);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002979
2980 /* init link so its safe to always remove it in destroy_shell_surface */
2981 wl_list_init(&shsurf->link);
Giulio Camuffo5085a752013-03-25 21:42:45 +01002982 wl_list_init(&shsurf->popup.grab_link);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002983
Pekka Paalanen460099f2012-01-20 16:48:25 +02002984 /* empty when not in use */
2985 wl_list_init(&shsurf->rotation.transform.link);
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05002986 weston_matrix_init(&shsurf->rotation.rotation);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002987
Jonas Ådahl62fcd042012-06-13 00:01:23 +02002988 wl_list_init(&shsurf->workspace_transform.link);
2989
Philip Withnall648a4dd2013-11-25 18:01:44 +00002990 wl_list_init(&shsurf->children_link);
2991 wl_list_init(&shsurf->children_list);
2992 shsurf->parent = NULL;
2993
Pekka Paalanen98262232011-12-01 10:42:22 +02002994 shsurf->type = SHELL_SURFACE_NONE;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002995
Kristian Høgsberga61ca062012-05-22 16:05:52 -04002996 shsurf->client = client;
2997
Kristian Høgsberg45ba8692012-05-21 14:27:33 -04002998 return shsurf;
Tiago Vignattibc052c92012-04-19 16:18:18 +03002999}
3000
Rafael Antognollie2a34552013-12-03 15:35:45 -02003001static struct shell_surface *
3002create_shell_surface(void *shell, struct weston_surface *surface,
3003 const struct weston_shell_client *client)
3004{
Kristian Høgsbergc8f8dd82013-12-05 23:20:33 -08003005 return create_common_surface(shell, surface, client);
Rafael Antognollie2a34552013-12-03 15:35:45 -02003006}
3007
Jason Ekstranda7af7042013-10-12 22:38:11 -05003008static struct weston_view *
3009get_primary_view(void *shell, struct shell_surface *shsurf)
3010{
3011 return shsurf->view;
3012}
3013
Tiago Vignattibc052c92012-04-19 16:18:18 +03003014static void
3015shell_get_shell_surface(struct wl_client *client,
3016 struct wl_resource *resource,
3017 uint32_t id,
3018 struct wl_resource *surface_resource)
3019{
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05003020 struct weston_surface *surface =
3021 wl_resource_get_user_data(surface_resource);
Jason Ekstrand651f00e2013-06-14 10:07:54 -05003022 struct desktop_shell *shell = wl_resource_get_user_data(resource);
Tiago Vignattibc052c92012-04-19 16:18:18 +03003023 struct shell_surface *shsurf;
3024
3025 if (get_shell_surface(surface)) {
3026 wl_resource_post_error(surface_resource,
Kristian Høgsberg9540ea62012-05-21 14:28:57 -04003027 WL_DISPLAY_ERROR_INVALID_OBJECT,
3028 "desktop_shell::get_shell_surface already requested");
Tiago Vignattibc052c92012-04-19 16:18:18 +03003029 return;
3030 }
3031
Kristian Høgsberga61ca062012-05-22 16:05:52 -04003032 shsurf = create_shell_surface(shell, surface, &shell_client);
Kristian Høgsberg9540ea62012-05-21 14:28:57 -04003033 if (!shsurf) {
3034 wl_resource_post_error(surface_resource,
3035 WL_DISPLAY_ERROR_INVALID_OBJECT,
3036 "surface->configure already set");
3037 return;
3038 }
Tiago Vignattibc052c92012-04-19 16:18:18 +03003039
Jason Ekstranda85118c2013-06-27 20:17:02 -05003040 shsurf->resource =
3041 wl_resource_create(client,
3042 &wl_shell_surface_interface, 1, id);
3043 wl_resource_set_implementation(shsurf->resource,
3044 &shell_surface_implementation,
3045 shsurf, shell_destroy_shell_surface);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003046}
3047
Rafael Antognollie2a34552013-12-03 15:35:45 -02003048static bool
3049shell_surface_is_wl_shell_surface(struct shell_surface *shsurf)
3050{
3051 return wl_resource_instance_of(shsurf->resource,
3052 &wl_shell_surface_interface,
3053 &shell_surface_implementation);
3054}
3055
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003056static const struct wl_shell_interface shell_implementation = {
Pekka Paalanen46229672011-11-29 15:49:31 +02003057 shell_get_shell_surface
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05003058};
3059
Rafael Antognollie2a34552013-12-03 15:35:45 -02003060/****************************
3061 * xdg-shell implementation */
3062
3063static void
3064xdg_surface_destroy(struct wl_client *client,
3065 struct wl_resource *resource)
3066{
3067 wl_resource_destroy(resource);
3068}
3069
3070static void
3071xdg_surface_pong(struct wl_client *client,
3072 struct wl_resource *resource,
3073 uint32_t serial)
3074{
3075 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
3076
3077 surface_pong(shsurf, serial);
3078}
3079
3080static void
3081xdg_surface_set_app_id(struct wl_client *client,
3082 struct wl_resource *resource,
3083 const char *app_id)
3084{
3085 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
3086
3087 free(shsurf->class);
3088 shsurf->class = strdup(app_id);
3089}
3090
3091static void
3092xdg_surface_set_title(struct wl_client *client,
3093 struct wl_resource *resource, const char *title)
3094{
3095 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
3096
3097 set_title(shsurf, title);
3098}
3099
3100static void
3101xdg_surface_move(struct wl_client *client, struct wl_resource *resource,
3102 struct wl_resource *seat_resource, uint32_t serial)
3103{
3104 common_surface_move(resource, seat_resource, serial);
3105}
3106
3107static void
3108xdg_surface_resize(struct wl_client *client, struct wl_resource *resource,
3109 struct wl_resource *seat_resource, uint32_t serial,
3110 uint32_t edges)
3111{
3112 common_surface_resize(resource, seat_resource, serial, edges);
3113}
3114
3115static void
3116xdg_surface_set_output(struct wl_client *client,
3117 struct wl_resource *resource,
3118 struct wl_resource *output_resource)
3119{
3120 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
3121 struct weston_output *output;
3122
3123 if (output_resource)
3124 output = wl_resource_get_user_data(output_resource);
3125 else
3126 output = NULL;
3127
Rafael Antognolli65f98d82013-12-03 15:35:47 -02003128 shsurf->recommended_output = output;
Rafael Antognollie2a34552013-12-03 15:35:45 -02003129}
3130
3131static void
3132xdg_surface_set_fullscreen(struct wl_client *client,
3133 struct wl_resource *resource)
3134{
3135 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
3136
3137 if (shsurf->type != SHELL_SURFACE_TOPLEVEL)
3138 return;
3139
Kristian Høgsberge960b3f2013-12-05 22:04:42 -08003140 if (!shsurf->next_state.fullscreen)
Rafael Antognollie2a34552013-12-03 15:35:45 -02003141 set_fullscreen(shsurf,
3142 WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
Rafael Antognolli65f98d82013-12-03 15:35:47 -02003143 0, shsurf->recommended_output);
Rafael Antognollie2a34552013-12-03 15:35:45 -02003144}
3145
3146static void
3147xdg_surface_unset_fullscreen(struct wl_client *client,
3148 struct wl_resource *resource)
3149{
3150 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
Rafael Antognolli3c4e3f72013-12-03 15:35:46 -02003151 int32_t width, height;
Rafael Antognollie2a34552013-12-03 15:35:45 -02003152
3153 if (shsurf->type != SHELL_SURFACE_TOPLEVEL)
3154 return;
3155
Rafael Antognolli3c4e3f72013-12-03 15:35:46 -02003156 if (!shsurf->next_state.fullscreen)
3157 return;
3158
Rafael Antognollie2a34552013-12-03 15:35:45 -02003159 shsurf->next_state.fullscreen = false;
3160 shsurf->state_changed = true;
Rafael Antognolli3c4e3f72013-12-03 15:35:46 -02003161
3162 if (shsurf->saved_size_valid) {
3163 width = shsurf->saved_width;
3164 height = shsurf->saved_height;
3165 shsurf->saved_size_valid = false;
3166 } else {
3167 width = shsurf->surface->width;
3168 height = shsurf->surface->height;
3169 }
3170
3171 shsurf->client->send_configure(shsurf->surface, 0, width, height);
Rafael Antognollie2a34552013-12-03 15:35:45 -02003172}
3173
3174static void
3175xdg_surface_set_maximized(struct wl_client *client,
3176 struct wl_resource *resource)
3177{
3178 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
3179
3180 if (shsurf->type != SHELL_SURFACE_TOPLEVEL)
3181 return;
3182
Kristian Høgsbergc2745b12013-12-05 22:00:40 -08003183 if (!shsurf->next_state.maximized)
Rafael Antognolli65f98d82013-12-03 15:35:47 -02003184 set_maximized(shsurf, NULL);
Rafael Antognollie2a34552013-12-03 15:35:45 -02003185}
3186
3187static void
3188xdg_surface_unset_maximized(struct wl_client *client,
3189 struct wl_resource *resource)
3190{
3191 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
Rafael Antognolli3c4e3f72013-12-03 15:35:46 -02003192 int32_t width, height;
Rafael Antognollie2a34552013-12-03 15:35:45 -02003193
3194 if (shsurf->type != SHELL_SURFACE_TOPLEVEL)
3195 return;
3196
Rafael Antognolli3c4e3f72013-12-03 15:35:46 -02003197 if (!shsurf->next_state.maximized)
3198 return;
3199
Rafael Antognollie2a34552013-12-03 15:35:45 -02003200 shsurf->next_state.maximized = false;
3201 shsurf->state_changed = true;
Rafael Antognolli3c4e3f72013-12-03 15:35:46 -02003202
3203 if (shsurf->saved_size_valid) {
3204 width = shsurf->saved_width;
3205 height = shsurf->saved_height;
3206 shsurf->saved_size_valid = false;
3207 } else {
3208 width = shsurf->surface->width;
3209 height = shsurf->surface->height;
3210 }
3211
3212 shsurf->client->send_configure(shsurf->surface, 0, width, height);
Rafael Antognollie2a34552013-12-03 15:35:45 -02003213}
3214
3215static const struct xdg_surface_interface xdg_surface_implementation = {
3216 xdg_surface_destroy,
3217 xdg_surface_set_transient_for,
3218 xdg_surface_set_title,
3219 xdg_surface_set_app_id,
3220 xdg_surface_pong,
3221 xdg_surface_move,
3222 xdg_surface_resize,
3223 xdg_surface_set_output,
3224 xdg_surface_set_fullscreen,
3225 xdg_surface_unset_fullscreen,
3226 xdg_surface_set_maximized,
3227 xdg_surface_unset_maximized,
3228 NULL /* set_minimized */
3229};
3230
3231static void
3232xdg_send_configure(struct weston_surface *surface,
3233 uint32_t edges, int32_t width, int32_t height)
3234{
3235 struct shell_surface *shsurf = get_shell_surface(surface);
3236
3237 xdg_surface_send_configure(shsurf->resource, edges, width, height);
3238}
3239
3240static const struct weston_shell_client xdg_client = {
3241 xdg_send_configure
3242};
3243
3244static void
3245xdg_use_unstable_version(struct wl_client *client,
3246 struct wl_resource *resource,
3247 int32_t version)
3248{
3249 if (version > 1) {
3250 wl_resource_post_error(resource,
3251 1,
3252 "xdg-shell:: version not implemented yet.");
3253 return;
3254 }
3255}
3256
3257static struct shell_surface *
3258create_xdg_surface(void *shell, struct weston_surface *surface,
3259 const struct weston_shell_client *client)
3260{
3261 struct shell_surface *shsurf;
Rafael Antognollie2a34552013-12-03 15:35:45 -02003262
Kristian Høgsbergc8f8dd82013-12-05 23:20:33 -08003263 shsurf = create_common_surface(shell, surface, client);
3264 shsurf->type = SHELL_SURFACE_TOPLEVEL;
Rafael Antognollie2a34552013-12-03 15:35:45 -02003265
3266 return shsurf;
3267}
3268
3269static void
3270xdg_get_xdg_surface(struct wl_client *client,
3271 struct wl_resource *resource,
3272 uint32_t id,
3273 struct wl_resource *surface_resource)
3274{
3275 struct weston_surface *surface =
3276 wl_resource_get_user_data(surface_resource);
3277 struct desktop_shell *shell = wl_resource_get_user_data(resource);
3278 struct shell_surface *shsurf;
3279
3280 if (get_shell_surface(surface)) {
3281 wl_resource_post_error(surface_resource,
3282 WL_DISPLAY_ERROR_INVALID_OBJECT,
3283 "desktop_shell::get_shell_surface already requested");
3284 return;
3285 }
3286
3287 shsurf = create_xdg_surface(shell, surface, &xdg_client);
3288 if (!shsurf) {
3289 wl_resource_post_error(surface_resource,
3290 WL_DISPLAY_ERROR_INVALID_OBJECT,
3291 "surface->configure already set");
3292 return;
3293 }
3294
3295 shsurf->resource =
3296 wl_resource_create(client,
3297 &xdg_surface_interface, 1, id);
3298 wl_resource_set_implementation(shsurf->resource,
3299 &xdg_surface_implementation,
3300 shsurf, shell_destroy_shell_surface);
3301}
3302
3303static bool
3304shell_surface_is_xdg_surface(struct shell_surface *shsurf)
3305{
3306 return wl_resource_instance_of(shsurf->resource,
3307 &xdg_surface_interface,
3308 &xdg_surface_implementation);
3309}
3310
3311/* xdg-popup implementation */
3312
3313static void
3314xdg_popup_destroy(struct wl_client *client,
3315 struct wl_resource *resource)
3316{
3317 wl_resource_destroy(resource);
3318}
3319
3320static void
3321xdg_popup_pong(struct wl_client *client,
3322 struct wl_resource *resource,
3323 uint32_t serial)
3324{
3325 struct shell_surface *shsurf = wl_resource_get_user_data(resource);
3326
3327 surface_pong(shsurf, serial);
3328}
3329
3330static const struct xdg_popup_interface xdg_popup_implementation = {
3331 xdg_popup_destroy,
3332 xdg_popup_pong
3333};
3334
3335static void
3336xdg_popup_send_configure(struct weston_surface *surface,
3337 uint32_t edges, int32_t width, int32_t height)
3338{
3339}
3340
3341static const struct weston_shell_client xdg_popup_client = {
3342 xdg_popup_send_configure
3343};
3344
3345static struct shell_surface *
3346create_xdg_popup(void *shell, struct weston_surface *surface,
3347 const struct weston_shell_client *client,
3348 struct weston_surface *parent,
3349 struct shell_seat *seat,
3350 uint32_t serial,
3351 int32_t x, int32_t y)
3352{
3353 struct shell_surface *shsurf;
Rafael Antognollie2a34552013-12-03 15:35:45 -02003354
Kristian Høgsbergc8f8dd82013-12-05 23:20:33 -08003355 shsurf = create_common_surface(shell, surface, client);
3356 shsurf->type = SHELL_SURFACE_POPUP;
Rafael Antognollie2a34552013-12-03 15:35:45 -02003357 shsurf->popup.shseat = seat;
3358 shsurf->popup.serial = serial;
3359 shsurf->popup.x = x;
3360 shsurf->popup.y = y;
3361 shell_surface_set_parent(shsurf, parent);
3362
3363 return shsurf;
3364}
3365
3366static void
3367xdg_get_xdg_popup(struct wl_client *client,
3368 struct wl_resource *resource,
3369 uint32_t id,
3370 struct wl_resource *surface_resource,
3371 struct wl_resource *parent_resource,
3372 struct wl_resource *seat_resource,
3373 uint32_t serial,
3374 int32_t x, int32_t y, uint32_t flags)
3375{
3376 struct weston_surface *surface =
3377 wl_resource_get_user_data(surface_resource);
3378 struct desktop_shell *shell = wl_resource_get_user_data(resource);
3379 struct shell_surface *shsurf;
3380 struct weston_surface *parent;
3381 struct shell_seat *seat;
3382
3383 if (get_shell_surface(surface)) {
3384 wl_resource_post_error(surface_resource,
3385 WL_DISPLAY_ERROR_INVALID_OBJECT,
3386 "desktop_shell::get_shell_surface already requested");
3387 return;
3388 }
3389
3390 if (!parent_resource) {
3391 wl_resource_post_error(surface_resource,
3392 WL_DISPLAY_ERROR_INVALID_OBJECT,
3393 "xdg_shell::get_xdg_popup requires a parent shell surface");
3394 }
3395
3396 parent = wl_resource_get_user_data(parent_resource);
3397 seat = get_shell_seat(wl_resource_get_user_data(seat_resource));;
3398
3399 shsurf = create_xdg_popup(shell, surface, &xdg_popup_client,
3400 parent, seat, serial, x, y);
3401 if (!shsurf) {
3402 wl_resource_post_error(surface_resource,
3403 WL_DISPLAY_ERROR_INVALID_OBJECT,
3404 "surface->configure already set");
3405 return;
3406 }
3407
3408 shsurf->resource =
3409 wl_resource_create(client,
3410 &xdg_popup_interface, 1, id);
3411 wl_resource_set_implementation(shsurf->resource,
3412 &xdg_popup_implementation,
3413 shsurf, shell_destroy_shell_surface);
3414}
3415
3416static bool
3417shell_surface_is_xdg_popup(struct shell_surface *shsurf)
3418{
3419 return wl_resource_instance_of(shsurf->resource,
3420 &xdg_popup_interface,
3421 &xdg_popup_implementation);
3422}
3423
3424static const struct xdg_shell_interface xdg_implementation = {
3425 xdg_use_unstable_version,
3426 xdg_get_xdg_surface,
3427 xdg_get_xdg_popup
3428};
3429
3430static int
3431xdg_shell_unversioned_dispatch(const void *implementation,
3432 void *_target, uint32_t opcode,
3433 const struct wl_message *message,
3434 union wl_argument *args)
3435{
3436 struct wl_resource *resource = _target;
3437 struct desktop_shell *shell = wl_resource_get_user_data(resource);
3438
3439 if (opcode != 0) {
3440 wl_resource_post_error(resource,
3441 WL_DISPLAY_ERROR_INVALID_OBJECT,
3442 "must call use_unstable_version first");
3443 return 0;
3444 }
3445
3446#define XDG_SERVER_VERSION 1
3447
Kristian Høgsberg8d344a02013-12-08 22:27:11 -08003448 static_assert(XDG_SERVER_VERSION == XDG_SHELL_VERSION_CURRENT,
3449 "shell implementation doesn't match protocol version");
3450
Rafael Antognollie2a34552013-12-03 15:35:45 -02003451 if (args[0].i != XDG_SERVER_VERSION) {
3452 wl_resource_post_error(resource,
3453 WL_DISPLAY_ERROR_INVALID_OBJECT,
3454 "incompatible version, server is %d "
3455 "client wants %d",
3456 XDG_SERVER_VERSION, args[0].i);
3457 return 0;
3458 }
3459
3460 wl_resource_set_implementation(resource, &xdg_implementation,
3461 shell, NULL);
3462
3463 return 1;
3464}
3465
3466/* end of xdg-shell implementation */
3467/***********************************/
3468
Kristian Høgsberg07937562011-04-12 17:25:42 -04003469static void
Ander Conselvan de Oliveira859e8852013-02-21 18:35:21 +02003470shell_fade(struct desktop_shell *shell, enum fade_type type);
3471
3472static int
3473screensaver_timeout(void *data)
3474{
3475 struct desktop_shell *shell = data;
3476
3477 shell_fade(shell, FADE_OUT);
3478
3479 return 1;
3480}
3481
3482static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05003483handle_screensaver_sigchld(struct weston_process *proc, int status)
Pekka Paalanen18027e52011-12-02 16:31:49 +02003484{
Ander Conselvan de Oliveira18639f82013-02-15 18:44:19 +02003485 struct desktop_shell *shell =
3486 container_of(proc, struct desktop_shell, screensaver.process);
Ander Conselvan de Oliveira18639f82013-02-15 18:44:19 +02003487
Pekka Paalanen18027e52011-12-02 16:31:49 +02003488 proc->pid = 0;
Ander Conselvan de Oliveira18639f82013-02-15 18:44:19 +02003489
3490 if (shell->locked)
Ander Conselvan de Oliveirab17537e2013-02-22 14:16:18 +02003491 weston_compositor_sleep(shell->compositor);
Pekka Paalanen18027e52011-12-02 16:31:49 +02003492}
3493
3494static void
Tiago Vignattibe143262012-04-16 17:31:41 +03003495launch_screensaver(struct desktop_shell *shell)
Pekka Paalanen77346a62011-11-30 16:26:35 +02003496{
3497 if (shell->screensaver.binding)
3498 return;
3499
Ander Conselvan de Oliveiradda9d782013-02-22 14:16:19 +02003500 if (!shell->screensaver.path) {
3501 weston_compositor_sleep(shell->compositor);
Pekka Paalanene955f1e2011-12-07 11:49:52 +02003502 return;
Ander Conselvan de Oliveiradda9d782013-02-22 14:16:19 +02003503 }
Pekka Paalanene955f1e2011-12-07 11:49:52 +02003504
Kristian Høgsberg32bed572012-03-01 17:11:36 -05003505 if (shell->screensaver.process.pid != 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02003506 weston_log("old screensaver still running\n");
Kristian Høgsberg32bed572012-03-01 17:11:36 -05003507 return;
3508 }
3509
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05003510 weston_client_launch(shell->compositor,
Pekka Paalanen18027e52011-12-02 16:31:49 +02003511 &shell->screensaver.process,
Pekka Paalanene955f1e2011-12-07 11:49:52 +02003512 shell->screensaver.path,
Pekka Paalanen18027e52011-12-02 16:31:49 +02003513 handle_screensaver_sigchld);
Pekka Paalanen77346a62011-11-30 16:26:35 +02003514}
3515
3516static void
Tiago Vignattibe143262012-04-16 17:31:41 +03003517terminate_screensaver(struct desktop_shell *shell)
Pekka Paalanen77346a62011-11-30 16:26:35 +02003518{
Pekka Paalanen18027e52011-12-02 16:31:49 +02003519 if (shell->screensaver.process.pid == 0)
3520 return;
3521
3522 kill(shell->screensaver.process.pid, SIGTERM);
Pekka Paalanen77346a62011-11-30 16:26:35 +02003523}
3524
3525static void
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06003526configure_static_view(struct weston_view *ev, struct weston_layer *layer)
Kristian Høgsberg962342c2012-06-26 16:29:50 -04003527{
Jason Ekstranda7af7042013-10-12 22:38:11 -05003528 struct weston_view *v, *next;
Kristian Høgsberg962342c2012-06-26 16:29:50 -04003529
Jason Ekstranda7af7042013-10-12 22:38:11 -05003530 wl_list_for_each_safe(v, next, &layer->view_list, layer_link) {
3531 if (v->output == ev->output && v != ev) {
3532 weston_view_unmap(v);
3533 v->surface->configure = NULL;
Kristian Høgsberg962342c2012-06-26 16:29:50 -04003534 }
3535 }
3536
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06003537 weston_view_set_position(ev, ev->output->x, ev->output->y);
Kristian Høgsberg962342c2012-06-26 16:29:50 -04003538
Jason Ekstranda7af7042013-10-12 22:38:11 -05003539 if (wl_list_empty(&ev->layer_link)) {
3540 wl_list_insert(&layer->view_list, &ev->layer_link);
3541 weston_compositor_schedule_repaint(ev->surface->compositor);
Kristian Høgsberg962342c2012-06-26 16:29:50 -04003542 }
3543}
3544
3545static void
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06003546background_configure(struct weston_surface *es, int32_t sx, int32_t sy)
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04003547{
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01003548 struct desktop_shell *shell = es->configure_private;
Jason Ekstranda7af7042013-10-12 22:38:11 -05003549 struct weston_view *view;
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04003550
Jason Ekstranda7af7042013-10-12 22:38:11 -05003551 view = container_of(es->views.next, struct weston_view, surface_link);
3552
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06003553 configure_static_view(view, &shell->background_layer);
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04003554}
3555
3556static void
Kristian Høgsberg75840622011-09-06 13:48:16 -04003557desktop_shell_set_background(struct wl_client *client,
3558 struct wl_resource *resource,
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01003559 struct wl_resource *output_resource,
Kristian Høgsberg75840622011-09-06 13:48:16 -04003560 struct wl_resource *surface_resource)
3561{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05003562 struct desktop_shell *shell = wl_resource_get_user_data(resource);
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05003563 struct weston_surface *surface =
3564 wl_resource_get_user_data(surface_resource);
Jason Ekstranda7af7042013-10-12 22:38:11 -05003565 struct weston_view *view, *next;
Kristian Høgsberg75840622011-09-06 13:48:16 -04003566
Kristian Høgsberg962342c2012-06-26 16:29:50 -04003567 if (surface->configure) {
3568 wl_resource_post_error(surface_resource,
3569 WL_DISPLAY_ERROR_INVALID_OBJECT,
3570 "surface role already assigned");
3571 return;
3572 }
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01003573
Jason Ekstranda7af7042013-10-12 22:38:11 -05003574 wl_list_for_each_safe(view, next, &surface->views, surface_link)
3575 weston_view_destroy(view);
3576 view = weston_view_create(surface);
3577
Kristian Høgsberg962342c2012-06-26 16:29:50 -04003578 surface->configure = background_configure;
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01003579 surface->configure_private = shell;
Jason Ekstranda0d2dde2013-06-14 10:08:01 -05003580 surface->output = wl_resource_get_user_data(output_resource);
Jason Ekstranda7af7042013-10-12 22:38:11 -05003581 view->output = surface->output;
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04003582 desktop_shell_send_configure(resource, 0,
Kristian Høgsberg0b5cd0c2012-03-04 21:57:37 -05003583 surface_resource,
Scott Moreau1bad5db2012-08-18 01:04:05 -06003584 surface->output->width,
3585 surface->output->height);
Kristian Høgsberg75840622011-09-06 13:48:16 -04003586}
3587
3588static void
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06003589panel_configure(struct weston_surface *es, int32_t sx, int32_t sy)
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04003590{
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01003591 struct desktop_shell *shell = es->configure_private;
Jason Ekstranda7af7042013-10-12 22:38:11 -05003592 struct weston_view *view;
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04003593
Jason Ekstranda7af7042013-10-12 22:38:11 -05003594 view = container_of(es->views.next, struct weston_view, surface_link);
3595
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06003596 configure_static_view(view, &shell->panel_layer);
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04003597}
3598
3599static void
Kristian Høgsberg75840622011-09-06 13:48:16 -04003600desktop_shell_set_panel(struct wl_client *client,
3601 struct wl_resource *resource,
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01003602 struct wl_resource *output_resource,
Kristian Høgsberg75840622011-09-06 13:48:16 -04003603 struct wl_resource *surface_resource)
3604{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05003605 struct desktop_shell *shell = wl_resource_get_user_data(resource);
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05003606 struct weston_surface *surface =
3607 wl_resource_get_user_data(surface_resource);
Jason Ekstranda7af7042013-10-12 22:38:11 -05003608 struct weston_view *view, *next;
Kristian Høgsberg75840622011-09-06 13:48:16 -04003609
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04003610 if (surface->configure) {
3611 wl_resource_post_error(surface_resource,
3612 WL_DISPLAY_ERROR_INVALID_OBJECT,
3613 "surface role already assigned");
3614 return;
3615 }
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01003616
Jason Ekstranda7af7042013-10-12 22:38:11 -05003617 wl_list_for_each_safe(view, next, &surface->views, surface_link)
3618 weston_view_destroy(view);
3619 view = weston_view_create(surface);
3620
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04003621 surface->configure = panel_configure;
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01003622 surface->configure_private = shell;
Jason Ekstranda0d2dde2013-06-14 10:08:01 -05003623 surface->output = wl_resource_get_user_data(output_resource);
Jason Ekstranda7af7042013-10-12 22:38:11 -05003624 view->output = surface->output;
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04003625 desktop_shell_send_configure(resource, 0,
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04003626 surface_resource,
Scott Moreau1bad5db2012-08-18 01:04:05 -06003627 surface->output->width,
3628 surface->output->height);
Kristian Høgsberg75840622011-09-06 13:48:16 -04003629}
3630
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02003631static void
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06003632lock_surface_configure(struct weston_surface *surface, int32_t sx, int32_t sy)
Kristian Høgsberg730c94d2012-06-26 21:44:35 -04003633{
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01003634 struct desktop_shell *shell = surface->configure_private;
Jason Ekstranda7af7042013-10-12 22:38:11 -05003635 struct weston_view *view;
3636
3637 view = container_of(surface->views.next, struct weston_view, surface_link);
Kristian Høgsberg730c94d2012-06-26 21:44:35 -04003638
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06003639 if (surface->width == 0)
Giulio Camuffo184df502013-02-21 11:29:21 +01003640 return;
3641
Jason Ekstranda7af7042013-10-12 22:38:11 -05003642 center_on_output(view, get_default_output(shell->compositor));
Kristian Høgsberg730c94d2012-06-26 21:44:35 -04003643
3644 if (!weston_surface_is_mapped(surface)) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05003645 wl_list_insert(&shell->lock_layer.view_list,
3646 &view->layer_link);
3647 weston_view_update_transform(view);
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02003648 shell_fade(shell, FADE_IN);
Kristian Høgsberg730c94d2012-06-26 21:44:35 -04003649 }
3650}
3651
3652static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04003653handle_lock_surface_destroy(struct wl_listener *listener, void *data)
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05003654{
Tiago Vignattibe143262012-04-16 17:31:41 +03003655 struct desktop_shell *shell =
3656 container_of(listener, struct desktop_shell, lock_surface_listener);
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05003657
Martin Minarik6d118362012-06-07 18:01:59 +02003658 weston_log("lock surface gone\n");
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05003659 shell->lock_surface = NULL;
3660}
3661
3662static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02003663desktop_shell_set_lock_surface(struct wl_client *client,
3664 struct wl_resource *resource,
3665 struct wl_resource *surface_resource)
3666{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05003667 struct desktop_shell *shell = wl_resource_get_user_data(resource);
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05003668 struct weston_surface *surface =
3669 wl_resource_get_user_data(surface_resource);
Pekka Paalanen98262232011-12-01 10:42:22 +02003670
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02003671 shell->prepare_event_sent = false;
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +02003672
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02003673 if (!shell->locked)
3674 return;
3675
Pekka Paalanen98262232011-12-01 10:42:22 +02003676 shell->lock_surface = surface;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02003677
Kristian Høgsberg27e30522012-04-11 23:18:23 -04003678 shell->lock_surface_listener.notify = handle_lock_surface_destroy;
Jason Ekstrand651f00e2013-06-14 10:07:54 -05003679 wl_signal_add(&surface->destroy_signal,
Kristian Høgsberg27e30522012-04-11 23:18:23 -04003680 &shell->lock_surface_listener);
Pekka Paalanen57da4a82011-11-23 16:42:16 +02003681
Kristian Høgsbergaa2ee8b2013-10-30 15:49:45 -07003682 weston_view_create(surface);
Kristian Høgsberg730c94d2012-06-26 21:44:35 -04003683 surface->configure = lock_surface_configure;
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01003684 surface->configure_private = shell;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02003685}
3686
3687static void
Tiago Vignattibe143262012-04-16 17:31:41 +03003688resume_desktop(struct desktop_shell *shell)
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02003689{
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04003690 struct workspace *ws = get_current_workspace(shell);
Pekka Paalanen77346a62011-11-30 16:26:35 +02003691
Pekka Paalanen77346a62011-11-30 16:26:35 +02003692 terminate_screensaver(shell);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02003693
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05003694 wl_list_remove(&shell->lock_layer.link);
3695 wl_list_insert(&shell->compositor->cursor_layer.link,
3696 &shell->fullscreen_layer.link);
3697 wl_list_insert(&shell->fullscreen_layer.link,
3698 &shell->panel_layer.link);
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02003699 if (shell->showing_input_panels) {
3700 wl_list_insert(&shell->panel_layer.link,
3701 &shell->input_panel_layer.link);
3702 wl_list_insert(&shell->input_panel_layer.link,
3703 &ws->layer.link);
3704 } else {
3705 wl_list_insert(&shell->panel_layer.link, &ws->layer.link);
3706 }
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02003707
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -04003708 restore_focus_state(shell, get_current_workspace(shell));
Jonas Ådahl04769742012-06-13 00:01:24 +02003709
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02003710 shell->locked = false;
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02003711 shell_fade(shell, FADE_IN);
Pekka Paalanenfc6d91a2012-02-10 15:33:10 +02003712 weston_compositor_damage_all(shell->compositor);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02003713}
3714
3715static void
3716desktop_shell_unlock(struct wl_client *client,
3717 struct wl_resource *resource)
3718{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05003719 struct desktop_shell *shell = wl_resource_get_user_data(resource);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02003720
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02003721 shell->prepare_event_sent = false;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02003722
3723 if (shell->locked)
3724 resume_desktop(shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02003725}
3726
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04003727static void
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03003728desktop_shell_set_grab_surface(struct wl_client *client,
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04003729 struct wl_resource *resource,
3730 struct wl_resource *surface_resource)
3731{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05003732 struct desktop_shell *shell = wl_resource_get_user_data(resource);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04003733
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05003734 shell->grab_surface = wl_resource_get_user_data(surface_resource);
Kristian Høgsberg48588f82013-10-24 15:51:35 -07003735 weston_view_create(shell->grab_surface);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04003736}
3737
Pekka Paalanen79346ab2013-05-22 18:03:09 +03003738static void
3739desktop_shell_desktop_ready(struct wl_client *client,
3740 struct wl_resource *resource)
3741{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05003742 struct desktop_shell *shell = wl_resource_get_user_data(resource);
Pekka Paalanen79346ab2013-05-22 18:03:09 +03003743
3744 shell_fade_startup(shell);
3745}
3746
Kristian Høgsberg75840622011-09-06 13:48:16 -04003747static const struct desktop_shell_interface desktop_shell_implementation = {
3748 desktop_shell_set_background,
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02003749 desktop_shell_set_panel,
3750 desktop_shell_set_lock_surface,
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04003751 desktop_shell_unlock,
Pekka Paalanen79346ab2013-05-22 18:03:09 +03003752 desktop_shell_set_grab_surface,
3753 desktop_shell_desktop_ready
Kristian Høgsberg75840622011-09-06 13:48:16 -04003754};
3755
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02003756static enum shell_surface_type
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05003757get_shell_surface_type(struct weston_surface *surface)
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02003758{
3759 struct shell_surface *shsurf;
3760
3761 shsurf = get_shell_surface(surface);
3762 if (!shsurf)
Pekka Paalanen98262232011-12-01 10:42:22 +02003763 return SHELL_SURFACE_NONE;
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02003764 return shsurf->type;
3765}
3766
Kristian Høgsberg75840622011-09-06 13:48:16 -04003767static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04003768move_binding(struct weston_seat *seat, uint32_t time, uint32_t button, void *data)
Kristian Høgsberg07937562011-04-12 17:25:42 -04003769{
Rafal Mielniczukb2917a22014-01-05 20:04:59 +01003770 struct weston_surface *focus;
Pekka Paalanen01388e22013-04-25 13:57:44 +03003771 struct weston_surface *surface;
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04003772 struct shell_surface *shsurf;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -05003773
Rafal Mielniczukb2917a22014-01-05 20:04:59 +01003774 if (seat->pointer->focus == NULL)
3775 return;
3776
3777 focus = seat->pointer->focus->surface;
3778
Pekka Paalanen01388e22013-04-25 13:57:44 +03003779 surface = weston_surface_get_main_surface(focus);
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01003780 if (surface == NULL)
3781 return;
Kristian Høgsberg07937562011-04-12 17:25:42 -04003782
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04003783 shsurf = get_shell_surface(surface);
Rafael Antognolli03b16592013-12-03 15:35:42 -02003784 if (shsurf == NULL || shsurf->state.fullscreen ||
3785 shsurf->state.maximized)
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04003786 return;
3787
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04003788 surface_move(shsurf, (struct weston_seat *) seat);
Kristian Høgsberg07937562011-04-12 17:25:42 -04003789}
3790
3791static void
Rafael Antognolliea997ac2013-12-03 15:35:48 -02003792maximize_binding(struct weston_seat *seat, uint32_t time, uint32_t button, void *data)
3793{
3794 struct weston_surface *focus = seat->pointer->focus->surface;
3795 struct weston_surface *surface;
3796 struct shell_surface *shsurf;
3797
3798 surface = weston_surface_get_main_surface(focus);
3799 if (surface == NULL)
3800 return;
3801
3802 shsurf = get_shell_surface(surface);
3803 if (shsurf == NULL)
3804 return;
3805
3806 if (!shell_surface_is_xdg_surface(shsurf))
3807 return;
3808
3809 if (shsurf->state.maximized)
3810 xdg_surface_send_request_unset_maximized(shsurf->resource);
3811 else
3812 xdg_surface_send_request_set_maximized(shsurf->resource);
3813}
3814
3815static void
3816fullscreen_binding(struct weston_seat *seat, uint32_t time, uint32_t button, void *data)
3817{
3818 struct weston_surface *focus = seat->pointer->focus->surface;
3819 struct weston_surface *surface;
3820 struct shell_surface *shsurf;
3821
3822 surface = weston_surface_get_main_surface(focus);
3823 if (surface == NULL)
3824 return;
3825
3826 shsurf = get_shell_surface(surface);
3827 if (shsurf == NULL)
3828 return;
3829
3830 if (!shell_surface_is_xdg_surface(shsurf))
3831 return;
3832
3833 if (shsurf->state.fullscreen)
3834 xdg_surface_send_request_unset_fullscreen(shsurf->resource);
3835 else
3836 xdg_surface_send_request_set_fullscreen(shsurf->resource);
3837}
3838
3839static void
Neil Robertsaba0f252013-10-03 16:43:05 +01003840touch_move_binding(struct weston_seat *seat, uint32_t time, void *data)
3841{
Kristian Høgsberg7ab139c2013-10-24 16:21:39 -07003842 struct weston_surface *focus = seat->touch->focus->surface;
Neil Robertsaba0f252013-10-03 16:43:05 +01003843 struct weston_surface *surface;
3844 struct shell_surface *shsurf;
3845
3846 surface = weston_surface_get_main_surface(focus);
3847 if (surface == NULL)
3848 return;
3849
3850 shsurf = get_shell_surface(surface);
Rafael Antognolli03b16592013-12-03 15:35:42 -02003851 if (shsurf == NULL || shsurf->state.fullscreen ||
3852 shsurf->state.maximized)
Neil Robertsaba0f252013-10-03 16:43:05 +01003853 return;
3854
3855 surface_touch_move(shsurf, (struct weston_seat *) seat);
3856}
3857
3858static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04003859resize_binding(struct weston_seat *seat, uint32_t time, uint32_t button, void *data)
Kristian Høgsberg07937562011-04-12 17:25:42 -04003860{
Rafal Mielniczukb2917a22014-01-05 20:04:59 +01003861 struct weston_surface *focus;
Pekka Paalanen01388e22013-04-25 13:57:44 +03003862 struct weston_surface *surface;
Kristian Høgsberg07937562011-04-12 17:25:42 -04003863 uint32_t edges = 0;
3864 int32_t x, y;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003865 struct shell_surface *shsurf;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -05003866
Rafal Mielniczukb2917a22014-01-05 20:04:59 +01003867 if (seat->pointer->focus == NULL)
3868 return;
3869
3870 focus = seat->pointer->focus->surface;
3871
Pekka Paalanen01388e22013-04-25 13:57:44 +03003872 surface = weston_surface_get_main_surface(focus);
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01003873 if (surface == NULL)
3874 return;
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02003875
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003876 shsurf = get_shell_surface(surface);
Rafael Antognolli03b16592013-12-03 15:35:42 -02003877 if (shsurf == NULL || shsurf->state.fullscreen ||
3878 shsurf->state.maximized)
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02003879 return;
3880
Jason Ekstranda7af7042013-10-12 22:38:11 -05003881 weston_view_from_global(shsurf->view,
3882 wl_fixed_to_int(seat->pointer->grab_x),
3883 wl_fixed_to_int(seat->pointer->grab_y),
3884 &x, &y);
Kristian Høgsberg07937562011-04-12 17:25:42 -04003885
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06003886 if (x < shsurf->surface->width / 3)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003887 edges |= WL_SHELL_SURFACE_RESIZE_LEFT;
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06003888 else if (x < 2 * shsurf->surface->width / 3)
Kristian Høgsberg07937562011-04-12 17:25:42 -04003889 edges |= 0;
3890 else
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003891 edges |= WL_SHELL_SURFACE_RESIZE_RIGHT;
Kristian Høgsberg07937562011-04-12 17:25:42 -04003892
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06003893 if (y < shsurf->surface->height / 3)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003894 edges |= WL_SHELL_SURFACE_RESIZE_TOP;
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06003895 else if (y < 2 * shsurf->surface->height / 3)
Kristian Høgsberg07937562011-04-12 17:25:42 -04003896 edges |= 0;
3897 else
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003898 edges |= WL_SHELL_SURFACE_RESIZE_BOTTOM;
Kristian Høgsberg07937562011-04-12 17:25:42 -04003899
Kristian Høgsbergc1693f22012-05-22 16:56:23 -04003900 surface_resize(shsurf, (struct weston_seat *) seat, edges);
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04003901}
3902
3903static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04003904surface_opacity_binding(struct weston_seat *seat, uint32_t time, uint32_t axis,
Daniel Stone0c1e46e2012-05-30 16:31:59 +01003905 wl_fixed_t value, void *data)
Scott Moreaua3aa9c92012-03-22 11:01:03 -06003906{
Jonas Ådahlb0b87ba2012-09-27 18:40:42 +02003907 float step = 0.005;
Scott Moreaua3aa9c92012-03-22 11:01:03 -06003908 struct shell_surface *shsurf;
Kristian Høgsberg7ab139c2013-10-24 16:21:39 -07003909 struct weston_surface *focus = seat->pointer->focus->surface;
Pekka Paalanen01388e22013-04-25 13:57:44 +03003910 struct weston_surface *surface;
Scott Moreaua3aa9c92012-03-22 11:01:03 -06003911
Pekka Paalanen01388e22013-04-25 13:57:44 +03003912 /* XXX: broken for windows containing sub-surfaces */
3913 surface = weston_surface_get_main_surface(focus);
Scott Moreaua3aa9c92012-03-22 11:01:03 -06003914 if (surface == NULL)
3915 return;
3916
3917 shsurf = get_shell_surface(surface);
3918 if (!shsurf)
3919 return;
3920
Jason Ekstranda7af7042013-10-12 22:38:11 -05003921 shsurf->view->alpha -= wl_fixed_to_double(value) * step;
Scott Moreaua3aa9c92012-03-22 11:01:03 -06003922
Jason Ekstranda7af7042013-10-12 22:38:11 -05003923 if (shsurf->view->alpha > 1.0)
3924 shsurf->view->alpha = 1.0;
3925 if (shsurf->view->alpha < step)
3926 shsurf->view->alpha = step;
Scott Moreaua3aa9c92012-03-22 11:01:03 -06003927
Jason Ekstranda7af7042013-10-12 22:38:11 -05003928 weston_view_geometry_dirty(shsurf->view);
Scott Moreaua3aa9c92012-03-22 11:01:03 -06003929 weston_surface_damage(surface);
3930}
3931
3932static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04003933do_zoom(struct weston_seat *seat, uint32_t time, uint32_t key, uint32_t axis,
Daniel Stone0c1e46e2012-05-30 16:31:59 +01003934 wl_fixed_t value)
Scott Moreauccbf29d2012-02-22 14:21:41 -07003935{
Daniel Stone37816df2012-05-16 18:45:18 +01003936 struct weston_seat *ws = (struct weston_seat *) seat;
3937 struct weston_compositor *compositor = ws->compositor;
Scott Moreauccbf29d2012-02-22 14:21:41 -07003938 struct weston_output *output;
Scott Moreaue6603982012-06-11 13:07:51 -06003939 float increment;
Scott Moreauccbf29d2012-02-22 14:21:41 -07003940
3941 wl_list_for_each(output, &compositor->output_list, link) {
3942 if (pixman_region32_contains_point(&output->region,
Daniel Stone37816df2012-05-16 18:45:18 +01003943 wl_fixed_to_double(seat->pointer->x),
3944 wl_fixed_to_double(seat->pointer->y),
Daniel Stone103db7f2012-05-08 17:17:55 +01003945 NULL)) {
Daniel Stone325fc2d2012-05-30 16:31:58 +01003946 if (key == KEY_PAGEUP)
Kristian Høgsberg9b68af02012-05-22 12:55:18 -04003947 increment = output->zoom.increment;
Daniel Stone325fc2d2012-05-30 16:31:58 +01003948 else if (key == KEY_PAGEDOWN)
Kristian Høgsberg9b68af02012-05-22 12:55:18 -04003949 increment = -output->zoom.increment;
3950 else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
Jonas Ådahlb0b87ba2012-09-27 18:40:42 +02003951 /* For every pixel zoom 20th of a step */
Daniel Stone0c1e46e2012-05-30 16:31:59 +01003952 increment = output->zoom.increment *
Jonas Ådahlb0b87ba2012-09-27 18:40:42 +02003953 -wl_fixed_to_double(value) / 20.0;
Kristian Høgsberg9b68af02012-05-22 12:55:18 -04003954 else
3955 increment = 0;
3956
Kristian Høgsberg9b68af02012-05-22 12:55:18 -04003957 output->zoom.level += increment;
Scott Moreauc6d7f602012-02-23 22:28:37 -07003958
Scott Moreaue6603982012-06-11 13:07:51 -06003959 if (output->zoom.level < 0.0)
Scott Moreau850ca422012-05-21 15:21:25 -06003960 output->zoom.level = 0.0;
Scott Moreaue6603982012-06-11 13:07:51 -06003961 else if (output->zoom.level > output->zoom.max_level)
3962 output->zoom.level = output->zoom.max_level;
Ville Syrjäläaa628d02012-11-16 11:48:47 +02003963 else if (!output->zoom.active) {
Giulio Camuffo412b0242013-11-14 23:42:51 +01003964 weston_output_activate_zoom(output);
Kristian Høgsberg79af73e2012-08-03 15:45:23 -04003965 }
Scott Moreauccbf29d2012-02-22 14:21:41 -07003966
Scott Moreaue6603982012-06-11 13:07:51 -06003967 output->zoom.spring_z.target = output->zoom.level;
Scott Moreauccbf29d2012-02-22 14:21:41 -07003968
Jason Ekstranda7af7042013-10-12 22:38:11 -05003969 weston_output_update_zoom(output);
Scott Moreauccbf29d2012-02-22 14:21:41 -07003970 }
3971 }
3972}
3973
Scott Moreauccbf29d2012-02-22 14:21:41 -07003974static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04003975zoom_axis_binding(struct weston_seat *seat, uint32_t time, uint32_t axis,
Daniel Stone0c1e46e2012-05-30 16:31:59 +01003976 wl_fixed_t value, void *data)
Daniel Stone325fc2d2012-05-30 16:31:58 +01003977{
3978 do_zoom(seat, time, 0, axis, value);
3979}
3980
3981static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04003982zoom_key_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
Daniel Stone325fc2d2012-05-30 16:31:58 +01003983 void *data)
3984{
3985 do_zoom(seat, time, key, 0, 0);
3986}
3987
3988static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04003989terminate_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
Daniel Stone325fc2d2012-05-30 16:31:58 +01003990 void *data)
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05003991{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05003992 struct weston_compositor *compositor = data;
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05003993
Daniel Stone325fc2d2012-05-30 16:31:58 +01003994 wl_display_terminate(compositor->wl_display);
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05003995}
3996
Emilio Pozuelo Monfort03251b62013-11-19 11:37:16 +01003997static void
Giulio Camuffo1959ab82013-11-14 23:42:52 +01003998rotate_grab_motion(struct weston_pointer_grab *grab, uint32_t time,
3999 wl_fixed_t x, wl_fixed_t y)
Pekka Paalanen460099f2012-01-20 16:48:25 +02004000{
4001 struct rotate_grab *rotate =
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004002 container_of(grab, struct rotate_grab, base.grab);
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04004003 struct weston_pointer *pointer = grab->pointer;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004004 struct shell_surface *shsurf = rotate->base.shsurf;
John Kåre Alsaker490d02a2012-09-30 02:57:21 +02004005 float cx, cy, dx, dy, cposx, cposy, dposx, dposy, r;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004006
Giulio Camuffo1959ab82013-11-14 23:42:52 +01004007 weston_pointer_move(pointer, x, y);
4008
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004009 if (!shsurf)
4010 return;
4011
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004012 cx = 0.5f * shsurf->surface->width;
4013 cy = 0.5f * shsurf->surface->height;
Pekka Paalanen460099f2012-01-20 16:48:25 +02004014
Daniel Stone37816df2012-05-16 18:45:18 +01004015 dx = wl_fixed_to_double(pointer->x) - rotate->center.x;
4016 dy = wl_fixed_to_double(pointer->y) - rotate->center.y;
Pekka Paalanen460099f2012-01-20 16:48:25 +02004017 r = sqrtf(dx * dx + dy * dy);
4018
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004019 wl_list_remove(&shsurf->rotation.transform.link);
Jason Ekstranda7af7042013-10-12 22:38:11 -05004020 weston_view_geometry_dirty(shsurf->view);
Pekka Paalanen460099f2012-01-20 16:48:25 +02004021
4022 if (r > 20.0f) {
Pekka Paalanen460099f2012-01-20 16:48:25 +02004023 struct weston_matrix *matrix =
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004024 &shsurf->rotation.transform.matrix;
Pekka Paalanen460099f2012-01-20 16:48:25 +02004025
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05004026 weston_matrix_init(&rotate->rotation);
Vasily Khoruzhick1bbf3722013-01-28 22:40:28 +03004027 weston_matrix_rotate_xy(&rotate->rotation, dx / r, dy / r);
Pekka Paalanen460099f2012-01-20 16:48:25 +02004028
4029 weston_matrix_init(matrix);
Pekka Paalanen7b3bd3d2012-01-30 14:16:34 +02004030 weston_matrix_translate(matrix, -cx, -cy, 0.0f);
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004031 weston_matrix_multiply(matrix, &shsurf->rotation.rotation);
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05004032 weston_matrix_multiply(matrix, &rotate->rotation);
Pekka Paalanen7b3bd3d2012-01-30 14:16:34 +02004033 weston_matrix_translate(matrix, cx, cy, 0.0f);
Pekka Paalanen460099f2012-01-20 16:48:25 +02004034
Pekka Paalanenbc0b7e72012-01-24 09:53:37 +02004035 wl_list_insert(
Jason Ekstranda7af7042013-10-12 22:38:11 -05004036 &shsurf->view->geometry.transformation_list,
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004037 &shsurf->rotation.transform.link);
Pekka Paalanen460099f2012-01-20 16:48:25 +02004038 } else {
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004039 wl_list_init(&shsurf->rotation.transform.link);
4040 weston_matrix_init(&shsurf->rotation.rotation);
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05004041 weston_matrix_init(&rotate->rotation);
Pekka Paalanen460099f2012-01-20 16:48:25 +02004042 }
Pekka Paalanenb45ac5e2012-02-09 15:58:44 +02004043
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01004044 /* We need to adjust the position of the surface
4045 * in case it was resized in a rotated state before */
Jason Ekstranda7af7042013-10-12 22:38:11 -05004046 cposx = shsurf->view->geometry.x + cx;
4047 cposy = shsurf->view->geometry.y + cy;
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01004048 dposx = rotate->center.x - cposx;
4049 dposy = rotate->center.y - cposy;
4050 if (dposx != 0.0f || dposy != 0.0f) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05004051 weston_view_set_position(shsurf->view,
4052 shsurf->view->geometry.x + dposx,
4053 shsurf->view->geometry.y + dposy);
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01004054 }
4055
Pekka Paalanenb45ac5e2012-02-09 15:58:44 +02004056 /* Repaint implies weston_surface_update_transform(), which
4057 * lazily applies the damage due to rotation update.
4058 */
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004059 weston_compositor_schedule_repaint(shsurf->surface->compositor);
Pekka Paalanen460099f2012-01-20 16:48:25 +02004060}
4061
4062static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04004063rotate_grab_button(struct weston_pointer_grab *grab,
4064 uint32_t time, uint32_t button, uint32_t state_w)
Pekka Paalanen460099f2012-01-20 16:48:25 +02004065{
4066 struct rotate_grab *rotate =
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004067 container_of(grab, struct rotate_grab, base.grab);
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04004068 struct weston_pointer *pointer = grab->pointer;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004069 struct shell_surface *shsurf = rotate->base.shsurf;
Daniel Stone4dbadb12012-05-30 16:31:51 +01004070 enum wl_pointer_button_state state = state_w;
Pekka Paalanen460099f2012-01-20 16:48:25 +02004071
Daniel Stone4dbadb12012-05-30 16:31:51 +01004072 if (pointer->button_count == 0 &&
4073 state == WL_POINTER_BUTTON_STATE_RELEASED) {
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03004074 if (shsurf)
4075 weston_matrix_multiply(&shsurf->rotation.rotation,
4076 &rotate->rotation);
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03004077 shell_grab_end(&rotate->base);
Pekka Paalanen460099f2012-01-20 16:48:25 +02004078 free(rotate);
4079 }
4080}
4081
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02004082static void
4083rotate_grab_cancel(struct weston_pointer_grab *grab)
4084{
4085 struct rotate_grab *rotate =
4086 container_of(grab, struct rotate_grab, base.grab);
4087
4088 shell_grab_end(&rotate->base);
4089 free(rotate);
4090}
4091
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04004092static const struct weston_pointer_grab_interface rotate_grab_interface = {
Pekka Paalanen460099f2012-01-20 16:48:25 +02004093 noop_grab_focus,
4094 rotate_grab_motion,
4095 rotate_grab_button,
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02004096 rotate_grab_cancel,
Pekka Paalanen460099f2012-01-20 16:48:25 +02004097};
4098
4099static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04004100surface_rotate(struct shell_surface *surface, struct weston_seat *seat)
Pekka Paalanen460099f2012-01-20 16:48:25 +02004101{
Pekka Paalanen460099f2012-01-20 16:48:25 +02004102 struct rotate_grab *rotate;
John Kåre Alsaker490d02a2012-09-30 02:57:21 +02004103 float dx, dy;
4104 float r;
Pekka Paalanen460099f2012-01-20 16:48:25 +02004105
Pekka Paalanen460099f2012-01-20 16:48:25 +02004106 rotate = malloc(sizeof *rotate);
4107 if (!rotate)
4108 return;
4109
Jason Ekstranda7af7042013-10-12 22:38:11 -05004110 weston_view_to_global_float(surface->view,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004111 surface->surface->width * 0.5f,
4112 surface->surface->height * 0.5f,
Jason Ekstranda7af7042013-10-12 22:38:11 -05004113 &rotate->center.x, &rotate->center.y);
Pekka Paalanen460099f2012-01-20 16:48:25 +02004114
Daniel Stone37816df2012-05-16 18:45:18 +01004115 dx = wl_fixed_to_double(seat->pointer->x) - rotate->center.x;
4116 dy = wl_fixed_to_double(seat->pointer->y) - rotate->center.y;
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05004117 r = sqrtf(dx * dx + dy * dy);
4118 if (r > 20.0f) {
4119 struct weston_matrix inverse;
4120
4121 weston_matrix_init(&inverse);
Vasily Khoruzhick1bbf3722013-01-28 22:40:28 +03004122 weston_matrix_rotate_xy(&inverse, dx / r, -dy / r);
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05004123 weston_matrix_multiply(&surface->rotation.rotation, &inverse);
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01004124
4125 weston_matrix_init(&rotate->rotation);
Vasily Khoruzhick1bbf3722013-01-28 22:40:28 +03004126 weston_matrix_rotate_xy(&rotate->rotation, dx / r, dy / r);
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05004127 } else {
4128 weston_matrix_init(&surface->rotation.rotation);
4129 weston_matrix_init(&rotate->rotation);
4130 }
4131
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03004132 shell_grab_start(&rotate->base, &rotate_grab_interface, surface,
4133 seat->pointer, DESKTOP_SHELL_CURSOR_ARROW);
Pekka Paalanen460099f2012-01-20 16:48:25 +02004134}
4135
4136static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04004137rotate_binding(struct weston_seat *seat, uint32_t time, uint32_t button,
Kristian Høgsberg0c369032013-02-14 21:31:44 -05004138 void *data)
4139{
Rafal Mielniczukb2917a22014-01-05 20:04:59 +01004140 struct weston_surface *focus;
Pekka Paalanen01388e22013-04-25 13:57:44 +03004141 struct weston_surface *base_surface;
Kristian Høgsberg0c369032013-02-14 21:31:44 -05004142 struct shell_surface *surface;
4143
Rafal Mielniczukb2917a22014-01-05 20:04:59 +01004144 if (seat->pointer->focus == NULL)
4145 return;
4146
4147 focus = seat->pointer->focus->surface;
4148
Pekka Paalanen01388e22013-04-25 13:57:44 +03004149 base_surface = weston_surface_get_main_surface(focus);
Kristian Høgsberg0c369032013-02-14 21:31:44 -05004150 if (base_surface == NULL)
4151 return;
4152
4153 surface = get_shell_surface(base_surface);
Rafael Antognolli03b16592013-12-03 15:35:42 -02004154 if (surface == NULL || surface->state.fullscreen ||
4155 surface->state.maximized)
Kristian Høgsberg0c369032013-02-14 21:31:44 -05004156 return;
4157
4158 surface_rotate(surface, seat);
4159}
4160
Philip Withnall83ffd9d2013-11-25 18:01:42 +00004161/* Move all fullscreen layers down to the current workspace in a non-reversible
4162 * manner. This should be used when implementing shell-wide overlays, such as
4163 * the alt-tab switcher, which need to de-promote fullscreen layers. */
Kristian Høgsberg1ef23132013-12-04 00:20:01 -08004164void
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04004165lower_fullscreen_layer(struct desktop_shell *shell)
4166{
4167 struct workspace *ws;
Jason Ekstranda7af7042013-10-12 22:38:11 -05004168 struct weston_view *view, *prev;
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04004169
4170 ws = get_current_workspace(shell);
Jason Ekstranda7af7042013-10-12 22:38:11 -05004171 wl_list_for_each_reverse_safe(view, prev,
4172 &shell->fullscreen_layer.view_list,
Philip Withnall83ffd9d2013-11-25 18:01:42 +00004173 layer_link) {
4174 wl_list_remove(&view->layer_link);
4175 wl_list_insert(&ws->layer.view_list, &view->layer_link);
4176 weston_view_damage_below(view);
4177 weston_surface_damage(view->surface);
4178 }
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04004179}
4180
Kristian Høgsberg1ef23132013-12-04 00:20:01 -08004181void
Tiago Vignattibe143262012-04-16 17:31:41 +03004182activate(struct desktop_shell *shell, struct weston_surface *es,
Daniel Stone37816df2012-05-16 18:45:18 +01004183 struct weston_seat *seat)
Kristian Høgsberg75840622011-09-06 13:48:16 -04004184{
Pekka Paalanen01388e22013-04-25 13:57:44 +03004185 struct weston_surface *main_surface;
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -04004186 struct focus_state *state;
Jonas Ådahl8538b222012-08-29 22:13:03 +02004187 struct workspace *ws;
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01004188 struct weston_surface *old_es;
Rafael Antognolli03b16592013-12-03 15:35:42 -02004189 struct shell_surface *shsurf;
Kristian Høgsberg75840622011-09-06 13:48:16 -04004190
Pekka Paalanen01388e22013-04-25 13:57:44 +03004191 main_surface = weston_surface_get_main_surface(es);
4192
Daniel Stone37816df2012-05-16 18:45:18 +01004193 weston_surface_activate(es, seat);
Kristian Høgsberg75840622011-09-06 13:48:16 -04004194
Jonas Ådahl8538b222012-08-29 22:13:03 +02004195 state = ensure_focus_state(shell, seat);
4196 if (state == NULL)
4197 return;
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -04004198
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01004199 old_es = state->keyboard_focus;
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -04004200 state->keyboard_focus = es;
4201 wl_list_remove(&state->surface_destroy_listener.link);
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05004202 wl_signal_add(&es->destroy_signal, &state->surface_destroy_listener);
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -04004203
Rafael Antognolli03b16592013-12-03 15:35:42 -02004204 shsurf = get_shell_surface(main_surface);
4205 if (shsurf->state.fullscreen)
4206 shell_configure_fullscreen(shsurf);
4207 else
Alexander Larssonf82b6ca2013-05-28 16:23:39 +02004208 restore_all_output_modes(shell->compositor);
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01004209
Philip Withnall83ffd9d2013-11-25 18:01:42 +00004210 if (shell->focus_animation_type != ANIMATION_NONE) {
4211 ws = get_current_workspace(shell);
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01004212 animate_focus_change(shell, ws, get_default_view(old_es), get_default_view(es));
Philip Withnall83ffd9d2013-11-25 18:01:42 +00004213 }
4214
4215 /* Update the surface’s layer. This brings it to the top of the stacking
4216 * order as appropriate. */
4217 shell_surface_update_layer(get_shell_surface(main_surface));
Kristian Høgsberg75840622011-09-06 13:48:16 -04004218}
4219
Alex Wu21858432012-04-01 20:13:08 +08004220/* no-op func for checking black surface */
4221static void
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004222black_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
Alex Wu21858432012-04-01 20:13:08 +08004223{
4224}
4225
Quentin Glidicc0d79ce2013-01-29 14:16:13 +01004226static bool
Alex Wu21858432012-04-01 20:13:08 +08004227is_black_surface (struct weston_surface *es, struct weston_surface **fs_surface)
4228{
4229 if (es->configure == black_surface_configure) {
4230 if (fs_surface)
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01004231 *fs_surface = (struct weston_surface *)es->configure_private;
Alex Wu21858432012-04-01 20:13:08 +08004232 return true;
4233 }
4234 return false;
4235}
4236
Kristian Høgsberg75840622011-09-06 13:48:16 -04004237static void
Neil Robertsa28c6932013-10-03 16:43:04 +01004238activate_binding(struct weston_seat *seat,
4239 struct desktop_shell *shell,
4240 struct weston_surface *focus)
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05004241{
Pekka Paalanen01388e22013-04-25 13:57:44 +03004242 struct weston_surface *main_surface;
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05004243
Alex Wu9c35e6b2012-03-05 14:13:13 +08004244 if (!focus)
4245 return;
4246
Pekka Paalanen01388e22013-04-25 13:57:44 +03004247 if (is_black_surface(focus, &main_surface))
4248 focus = main_surface;
Alex Wu4539b082012-03-01 12:57:46 +08004249
Pekka Paalanen01388e22013-04-25 13:57:44 +03004250 main_surface = weston_surface_get_main_surface(focus);
4251 if (get_shell_surface_type(main_surface) == SHELL_SURFACE_NONE)
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04004252 return;
Kristian Høgsberg85b2e4b2012-06-21 16:49:42 -04004253
Neil Robertsa28c6932013-10-03 16:43:04 +01004254 activate(shell, focus, seat);
4255}
4256
4257static void
4258click_to_activate_binding(struct weston_seat *seat, uint32_t time, uint32_t button,
4259 void *data)
4260{
4261 if (seat->pointer->grab != &seat->pointer->default_grab)
4262 return;
Kristian Høgsberg7c4f6cc2014-01-01 16:28:32 -08004263 if (seat->pointer->focus == NULL)
4264 return;
Neil Robertsa28c6932013-10-03 16:43:04 +01004265
Kristian Høgsberg7ab139c2013-10-24 16:21:39 -07004266 activate_binding(seat, data, seat->pointer->focus->surface);
Neil Robertsa28c6932013-10-03 16:43:04 +01004267}
4268
4269static void
4270touch_to_activate_binding(struct weston_seat *seat, uint32_t time, void *data)
4271{
4272 if (seat->touch->grab != &seat->touch->default_grab)
4273 return;
Kristian Høgsberg0ed67502014-01-02 23:00:11 -08004274 if (seat->touch->focus == NULL)
4275 return;
Neil Robertsa28c6932013-10-03 16:43:04 +01004276
Kristian Høgsberg7ab139c2013-10-24 16:21:39 -07004277 activate_binding(seat, data, seat->touch->focus->surface);
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05004278}
4279
4280static void
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004281lock(struct desktop_shell *shell)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04004282{
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04004283 struct workspace *ws = get_current_workspace(shell);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02004284
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004285 if (shell->locked) {
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02004286 weston_compositor_sleep(shell->compositor);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02004287 return;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004288 }
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02004289
4290 shell->locked = true;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02004291
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05004292 /* Hide all surfaces by removing the fullscreen, panel and
4293 * toplevel layers. This way nothing else can show or receive
4294 * input events while we are locked. */
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02004295
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05004296 wl_list_remove(&shell->panel_layer.link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05004297 wl_list_remove(&shell->fullscreen_layer.link);
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02004298 if (shell->showing_input_panels)
4299 wl_list_remove(&shell->input_panel_layer.link);
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04004300 wl_list_remove(&ws->layer.link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05004301 wl_list_insert(&shell->compositor->cursor_layer.link,
4302 &shell->lock_layer.link);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02004303
Pekka Paalanen77346a62011-11-30 16:26:35 +02004304 launch_screensaver(shell);
4305
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02004306 /* TODO: disable bindings that should not work while locked. */
4307
4308 /* All this must be undone in resume_desktop(). */
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02004309}
4310
4311static void
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004312unlock(struct desktop_shell *shell)
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02004313{
Pekka Paalanend81c2162011-11-16 13:47:34 +02004314 if (!shell->locked || shell->lock_surface) {
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02004315 shell_fade(shell, FADE_IN);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02004316 return;
4317 }
4318
4319 /* If desktop-shell client has gone away, unlock immediately. */
4320 if (!shell->child.desktop_shell) {
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02004321 resume_desktop(shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02004322 return;
4323 }
4324
4325 if (shell->prepare_event_sent)
4326 return;
4327
Kristian Høgsberg0b5cd0c2012-03-04 21:57:37 -05004328 desktop_shell_send_prepare_lock_surface(shell->child.desktop_shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02004329 shell->prepare_event_sent = true;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04004330}
4331
4332static void
Jason Ekstranda7af7042013-10-12 22:38:11 -05004333shell_fade_done(struct weston_view_animation *animation, void *data)
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004334{
4335 struct desktop_shell *shell = data;
4336
4337 shell->fade.animation = NULL;
4338
4339 switch (shell->fade.type) {
4340 case FADE_IN:
Jason Ekstranda7af7042013-10-12 22:38:11 -05004341 weston_surface_destroy(shell->fade.view->surface);
4342 shell->fade.view = NULL;
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004343 break;
4344 case FADE_OUT:
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004345 lock(shell);
4346 break;
Philip Withnall4a86a0a2013-11-25 18:01:32 +00004347 default:
4348 break;
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004349 }
4350}
4351
Jason Ekstranda7af7042013-10-12 22:38:11 -05004352static struct weston_view *
Pekka Paalanen79346ab2013-05-22 18:03:09 +03004353shell_fade_create_surface(struct desktop_shell *shell)
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004354{
4355 struct weston_compositor *compositor = shell->compositor;
4356 struct weston_surface *surface;
Jason Ekstranda7af7042013-10-12 22:38:11 -05004357 struct weston_view *view;
Pekka Paalanen79346ab2013-05-22 18:03:09 +03004358
4359 surface = weston_surface_create(compositor);
4360 if (!surface)
4361 return NULL;
4362
Jason Ekstranda7af7042013-10-12 22:38:11 -05004363 view = weston_view_create(surface);
4364 if (!view) {
4365 weston_surface_destroy(surface);
4366 return NULL;
4367 }
4368
Jason Ekstrand5c11a332013-12-04 20:32:03 -06004369 weston_surface_set_size(surface, 8192, 8192);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004370 weston_view_set_position(view, 0, 0);
Pekka Paalanen79346ab2013-05-22 18:03:09 +03004371 weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1.0);
Jason Ekstranda7af7042013-10-12 22:38:11 -05004372 wl_list_insert(&compositor->fade_layer.view_list,
4373 &view->layer_link);
Pekka Paalanen79346ab2013-05-22 18:03:09 +03004374 pixman_region32_init(&surface->input);
4375
Jason Ekstranda7af7042013-10-12 22:38:11 -05004376 return view;
Pekka Paalanen79346ab2013-05-22 18:03:09 +03004377}
4378
4379static void
4380shell_fade(struct desktop_shell *shell, enum fade_type type)
4381{
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004382 float tint;
4383
4384 switch (type) {
4385 case FADE_IN:
4386 tint = 0.0;
4387 break;
4388 case FADE_OUT:
4389 tint = 1.0;
4390 break;
4391 default:
4392 weston_log("shell: invalid fade type\n");
4393 return;
4394 }
4395
4396 shell->fade.type = type;
4397
Jason Ekstranda7af7042013-10-12 22:38:11 -05004398 if (shell->fade.view == NULL) {
4399 shell->fade.view = shell_fade_create_surface(shell);
4400 if (!shell->fade.view)
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004401 return;
4402
Jason Ekstranda7af7042013-10-12 22:38:11 -05004403 shell->fade.view->alpha = 1.0 - tint;
4404 weston_view_update_transform(shell->fade.view);
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004405 }
4406
4407 if (shell->fade.animation)
Kristian Høgsberg5281fb12013-06-17 10:10:28 -04004408 weston_fade_update(shell->fade.animation, tint);
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004409 else
4410 shell->fade.animation =
Jason Ekstranda7af7042013-10-12 22:38:11 -05004411 weston_fade_run(shell->fade.view,
Kristian Høgsberg5281fb12013-06-17 10:10:28 -04004412 1.0 - tint, tint, 300.0,
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004413 shell_fade_done, shell);
4414}
4415
4416static void
Pekka Paalanen79346ab2013-05-22 18:03:09 +03004417do_shell_fade_startup(void *data)
4418{
4419 struct desktop_shell *shell = data;
4420
Kristian Høgsberg724c8d92013-10-16 11:38:24 -07004421 if (shell->startup_animation_type == ANIMATION_FADE)
4422 shell_fade(shell, FADE_IN);
4423 else if (shell->startup_animation_type == ANIMATION_NONE) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05004424 weston_surface_destroy(shell->fade.view->surface);
4425 shell->fade.view = NULL;
Kristian Høgsberg724c8d92013-10-16 11:38:24 -07004426 }
Pekka Paalanen79346ab2013-05-22 18:03:09 +03004427}
4428
4429static void
4430shell_fade_startup(struct desktop_shell *shell)
4431{
4432 struct wl_event_loop *loop;
4433
4434 if (!shell->fade.startup_timer)
4435 return;
4436
4437 wl_event_source_remove(shell->fade.startup_timer);
4438 shell->fade.startup_timer = NULL;
4439
4440 loop = wl_display_get_event_loop(shell->compositor->wl_display);
4441 wl_event_loop_add_idle(loop, do_shell_fade_startup, shell);
4442}
4443
4444static int
4445fade_startup_timeout(void *data)
4446{
4447 struct desktop_shell *shell = data;
4448
4449 shell_fade_startup(shell);
4450 return 0;
4451}
4452
4453static void
4454shell_fade_init(struct desktop_shell *shell)
4455{
4456 /* Make compositor output all black, and wait for the desktop-shell
4457 * client to signal it is ready, then fade in. The timer triggers a
4458 * fade-in, in case the desktop-shell client takes too long.
4459 */
4460
4461 struct wl_event_loop *loop;
4462
Jason Ekstranda7af7042013-10-12 22:38:11 -05004463 if (shell->fade.view != NULL) {
Pekka Paalanen79346ab2013-05-22 18:03:09 +03004464 weston_log("%s: warning: fade surface already exists\n",
4465 __func__);
4466 return;
4467 }
4468
Jason Ekstranda7af7042013-10-12 22:38:11 -05004469 shell->fade.view = shell_fade_create_surface(shell);
4470 if (!shell->fade.view)
Pekka Paalanen79346ab2013-05-22 18:03:09 +03004471 return;
4472
Jason Ekstranda7af7042013-10-12 22:38:11 -05004473 weston_view_update_transform(shell->fade.view);
4474 weston_surface_damage(shell->fade.view->surface);
Pekka Paalanen79346ab2013-05-22 18:03:09 +03004475
4476 loop = wl_display_get_event_loop(shell->compositor->wl_display);
4477 shell->fade.startup_timer =
4478 wl_event_loop_add_timer(loop, fade_startup_timeout, shell);
4479 wl_event_source_timer_update(shell->fade.startup_timer, 15000);
4480}
4481
4482static void
Ander Conselvan de Oliveiraa4575632013-02-21 18:35:23 +02004483idle_handler(struct wl_listener *listener, void *data)
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004484{
4485 struct desktop_shell *shell =
Ander Conselvan de Oliveiraa4575632013-02-21 18:35:23 +02004486 container_of(listener, struct desktop_shell, idle_listener);
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004487
4488 shell_fade(shell, FADE_OUT);
4489 /* lock() is called from shell_fade_done() */
4490}
4491
4492static void
Ander Conselvan de Oliveiraa4575632013-02-21 18:35:23 +02004493wake_handler(struct wl_listener *listener, void *data)
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004494{
4495 struct desktop_shell *shell =
Ander Conselvan de Oliveiraa4575632013-02-21 18:35:23 +02004496 container_of(listener, struct desktop_shell, wake_listener);
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004497
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004498 unlock(shell);
4499}
4500
4501static void
Jason Ekstranda7af7042013-10-12 22:38:11 -05004502center_on_output(struct weston_view *view, struct weston_output *output)
Pekka Paalanen77346a62011-11-30 16:26:35 +02004503{
Giulio Camuffob8366642013-04-25 13:57:46 +03004504 int32_t surf_x, surf_y, width, height;
Ander Conselvan de Oliveira012b4c72012-11-27 17:03:42 +02004505 float x, y;
Pekka Paalanen77346a62011-11-30 16:26:35 +02004506
Jason Ekstranda7af7042013-10-12 22:38:11 -05004507 surface_subsurfaces_boundingbox(view->surface, &surf_x, &surf_y, &width, &height);
Giulio Camuffob8366642013-04-25 13:57:46 +03004508
4509 x = output->x + (output->width - width) / 2 - surf_x / 2;
4510 y = output->y + (output->height - height) / 2 - surf_y / 2;
Ander Conselvan de Oliveira012b4c72012-11-27 17:03:42 +02004511
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004512 weston_view_set_position(view, x, y);
Pekka Paalanen77346a62011-11-30 16:26:35 +02004513}
4514
4515static void
Jason Ekstranda7af7042013-10-12 22:38:11 -05004516weston_view_set_initial_position(struct weston_view *view,
4517 struct desktop_shell *shell)
Rob Bradfordac63e5b2012-08-13 14:07:52 +01004518{
4519 struct weston_compositor *compositor = shell->compositor;
4520 int ix = 0, iy = 0;
4521 int range_x, range_y;
4522 int dx, dy, x, y, panel_height;
4523 struct weston_output *output, *target_output = NULL;
4524 struct weston_seat *seat;
4525
4526 /* As a heuristic place the new window on the same output as the
4527 * pointer. Falling back to the output containing 0, 0.
4528 *
4529 * TODO: Do something clever for touch too?
4530 */
4531 wl_list_for_each(seat, &compositor->seat_list, link) {
Kristian Høgsberg2bf87622013-05-07 23:17:41 -04004532 if (seat->pointer) {
Kristian Høgsberge3148752013-05-06 23:19:49 -04004533 ix = wl_fixed_to_int(seat->pointer->x);
4534 iy = wl_fixed_to_int(seat->pointer->y);
Rob Bradfordac63e5b2012-08-13 14:07:52 +01004535 break;
4536 }
4537 }
4538
4539 wl_list_for_each(output, &compositor->output_list, link) {
4540 if (pixman_region32_contains_point(&output->region, ix, iy, NULL)) {
4541 target_output = output;
4542 break;
4543 }
4544 }
4545
4546 if (!target_output) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05004547 weston_view_set_position(view, 10 + random() % 400,
4548 10 + random() % 400);
Rob Bradfordac63e5b2012-08-13 14:07:52 +01004549 return;
4550 }
4551
4552 /* Valid range within output where the surface will still be onscreen.
4553 * If this is negative it means that the surface is bigger than
4554 * output.
4555 */
4556 panel_height = get_output_panel_height(shell, target_output);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004557 range_x = target_output->width - view->surface->width;
Scott Moreau1bad5db2012-08-18 01:04:05 -06004558 range_y = (target_output->height - panel_height) -
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004559 view->surface->height;
Rob Bradfordac63e5b2012-08-13 14:07:52 +01004560
Rob Bradford4cb88c72012-08-13 15:18:44 +01004561 if (range_x > 0)
Rob Bradfordac63e5b2012-08-13 14:07:52 +01004562 dx = random() % range_x;
Rob Bradfordac63e5b2012-08-13 14:07:52 +01004563 else
Rob Bradford4cb88c72012-08-13 15:18:44 +01004564 dx = 0;
4565
4566 if (range_y > 0)
Rob Bradfordac63e5b2012-08-13 14:07:52 +01004567 dy = panel_height + random() % range_y;
Rob Bradford4cb88c72012-08-13 15:18:44 +01004568 else
4569 dy = panel_height;
Rob Bradfordac63e5b2012-08-13 14:07:52 +01004570
4571 x = target_output->x + dx;
4572 y = target_output->y + dy;
4573
Jason Ekstranda7af7042013-10-12 22:38:11 -05004574 weston_view_set_position(view, x, y);
Rob Bradfordac63e5b2012-08-13 14:07:52 +01004575}
4576
4577static void
Jason Ekstranda7af7042013-10-12 22:38:11 -05004578map(struct desktop_shell *shell, struct shell_surface *shsurf,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004579 int32_t sx, int32_t sy)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04004580{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05004581 struct weston_compositor *compositor = shell->compositor;
Daniel Stoneb2104682012-05-30 16:31:56 +01004582 struct weston_seat *seat;
Juan Zhao96879df2012-02-07 08:45:41 +08004583 int panel_height = 0;
Giulio Camuffob8366642013-04-25 13:57:46 +03004584 int32_t surf_x, surf_y;
Pekka Paalanen57da4a82011-11-23 16:42:16 +02004585
Pekka Paalanen77346a62011-11-30 16:26:35 +02004586 /* initial positioning, see also configure() */
Jason Ekstranda7af7042013-10-12 22:38:11 -05004587 switch (shsurf->type) {
Rafael Antognollied207b42013-12-03 15:35:43 -02004588 case SHELL_SURFACE_TOPLEVEL:
Rafael Antognolli03b16592013-12-03 15:35:42 -02004589 if (shsurf->state.fullscreen) {
4590 center_on_output(shsurf->view, shsurf->fullscreen_output);
4591 shell_map_fullscreen(shsurf);
4592 } else if (shsurf->state.maximized) {
4593 /* use surface configure to set the geometry */
4594 panel_height = get_output_panel_height(shell, shsurf->output);
4595 surface_subsurfaces_boundingbox(shsurf->surface,
4596 &surf_x, &surf_y, NULL, NULL);
4597 weston_view_set_position(shsurf->view,
4598 shsurf->output->x - surf_x,
4599 shsurf->output->y +
4600 panel_height - surf_y);
Rafael Antognollied207b42013-12-03 15:35:43 -02004601 } else if (!shsurf->state.relative) {
Rafael Antognolli03b16592013-12-03 15:35:42 -02004602 weston_view_set_initial_position(shsurf->view, shell);
4603 }
Juan Zhao96879df2012-02-07 08:45:41 +08004604 break;
Tiago Vignatti0f997012012-02-10 16:17:23 +02004605 case SHELL_SURFACE_POPUP:
Kristian Høgsberg3730f362012-04-13 12:40:07 -04004606 shell_map_popup(shsurf);
Rob Bradforddb999382012-12-06 12:07:48 +00004607 break;
Ander Conselvan de Oliveirae9e05152012-02-15 17:02:56 +02004608 case SHELL_SURFACE_NONE:
Jason Ekstranda7af7042013-10-12 22:38:11 -05004609 weston_view_set_position(shsurf->view,
4610 shsurf->view->geometry.x + sx,
4611 shsurf->view->geometry.y + sy);
Tiago Vignatti0f997012012-02-10 16:17:23 +02004612 break;
Philip Withnall0f640e22013-11-25 18:01:31 +00004613 case SHELL_SURFACE_XWAYLAND:
Pekka Paalanen77346a62011-11-30 16:26:35 +02004614 default:
4615 ;
4616 }
Kristian Høgsberg75840622011-09-06 13:48:16 -04004617
Philip Withnalle1d75ae2013-11-25 18:01:41 +00004618 /* Surface stacking order, see also activate(). */
4619 shell_surface_update_layer(shsurf);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02004620
Jason Ekstranda7af7042013-10-12 22:38:11 -05004621 if (shsurf->type != SHELL_SURFACE_NONE) {
4622 weston_view_update_transform(shsurf->view);
Rafael Antognolli03b16592013-12-03 15:35:42 -02004623 if (shsurf->state.maximized) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05004624 shsurf->surface->output = shsurf->output;
4625 shsurf->view->output = shsurf->output;
4626 }
Ander Conselvan de Oliveirade56c312012-03-05 15:39:23 +02004627 }
Kristian Høgsberg2f88a402011-12-04 15:32:59 -05004628
Rafael Antognollied207b42013-12-03 15:35:43 -02004629 if ((shsurf->type == SHELL_SURFACE_XWAYLAND || shsurf->state.relative) &&
4630 shsurf->transient.flags == WL_SHELL_SURFACE_TRANSIENT_INACTIVE) {
4631 }
4632
Jason Ekstranda7af7042013-10-12 22:38:11 -05004633 switch (shsurf->type) {
Tiago Vignattifb2adba2013-06-12 15:43:21 -03004634 /* XXX: xwayland's using the same fields for transient type */
4635 case SHELL_SURFACE_XWAYLAND:
Tiago Vignatti99aeb1e2012-05-23 22:06:26 +03004636 if (shsurf->transient.flags ==
4637 WL_SHELL_SURFACE_TRANSIENT_INACTIVE)
4638 break;
4639 case SHELL_SURFACE_TOPLEVEL:
Rafael Antognollied207b42013-12-03 15:35:43 -02004640 if (shsurf->state.relative &&
4641 shsurf->transient.flags == WL_SHELL_SURFACE_TRANSIENT_INACTIVE)
4642 break;
Rafael Antognolliba5d2d72013-12-04 17:49:55 -02004643 if (shell->locked)
Rafael Antognollied207b42013-12-03 15:35:43 -02004644 break;
4645 wl_list_for_each(seat, &compositor->seat_list, link)
4646 activate(shell, shsurf->surface, seat);
Juan Zhao7bb92f02011-12-15 11:31:51 -05004647 break;
Philip Withnall0f640e22013-11-25 18:01:31 +00004648 case SHELL_SURFACE_POPUP:
4649 case SHELL_SURFACE_NONE:
Juan Zhao7bb92f02011-12-15 11:31:51 -05004650 default:
4651 break;
4652 }
4653
Rafael Antognolli03b16592013-12-03 15:35:42 -02004654 if (shsurf->type == SHELL_SURFACE_TOPLEVEL &&
4655 !shsurf->state.maximized && !shsurf->state.fullscreen)
Juan Zhaoe10d2792012-04-25 19:09:52 +08004656 {
4657 switch (shell->win_animation_type) {
4658 case ANIMATION_FADE:
Jason Ekstranda7af7042013-10-12 22:38:11 -05004659 weston_fade_run(shsurf->view, 0.0, 1.0, 300.0, NULL, NULL);
Juan Zhaoe10d2792012-04-25 19:09:52 +08004660 break;
4661 case ANIMATION_ZOOM:
Jason Ekstranda7af7042013-10-12 22:38:11 -05004662 weston_zoom_run(shsurf->view, 0.5, 1.0, NULL, NULL);
Juan Zhaoe10d2792012-04-25 19:09:52 +08004663 break;
Philip Withnall4a86a0a2013-11-25 18:01:32 +00004664 case ANIMATION_NONE:
Juan Zhaoe10d2792012-04-25 19:09:52 +08004665 default:
4666 break;
4667 }
4668 }
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05004669}
4670
4671static void
Tiago Vignattibe143262012-04-16 17:31:41 +03004672configure(struct desktop_shell *shell, struct weston_surface *surface,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004673 float x, float y)
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05004674{
Pekka Paalanen77346a62011-11-30 16:26:35 +02004675 struct shell_surface *shsurf;
Jason Ekstranda7af7042013-10-12 22:38:11 -05004676 struct weston_view *view;
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004677 int32_t mx, my, surf_x, surf_y;
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05004678
Pekka Paalanen77346a62011-11-30 16:26:35 +02004679 shsurf = get_shell_surface(surface);
Pekka Paalanen77346a62011-11-30 16:26:35 +02004680
Rafael Antognolli03b16592013-12-03 15:35:42 -02004681 if (shsurf->state.fullscreen)
Alex Wu4539b082012-03-01 12:57:46 +08004682 shell_configure_fullscreen(shsurf);
Rafael Antognolli03b16592013-12-03 15:35:42 -02004683 else if (shsurf->state.maximized) {
Alex Wu4539b082012-03-01 12:57:46 +08004684 /* setting x, y and using configure to change that geometry */
Giulio Camuffob8366642013-04-25 13:57:46 +03004685 surface_subsurfaces_boundingbox(shsurf->surface, &surf_x, &surf_y,
4686 NULL, NULL);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004687 mx = shsurf->output->x - surf_x;
4688 my = shsurf->output->y +
4689 get_output_panel_height(shell,shsurf->output) - surf_y;
4690 weston_view_set_position(shsurf->view, mx, my);
Rafael Antognolli03b16592013-12-03 15:35:42 -02004691 } else {
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004692 weston_view_set_position(shsurf->view, x, y);
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04004693 }
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05004694
Alex Wu4539b082012-03-01 12:57:46 +08004695 /* XXX: would a fullscreen surface need the same handling? */
Kristian Høgsberg6a8b5532012-02-16 23:43:59 -05004696 if (surface->output) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05004697 wl_list_for_each(view, &surface->views, surface_link)
4698 weston_view_update_transform(view);
Pekka Paalanen77346a62011-11-30 16:26:35 +02004699
Rafael Antognolli03b16592013-12-03 15:35:42 -02004700 if (shsurf->state.maximized)
Juan Zhao96879df2012-02-07 08:45:41 +08004701 surface->output = shsurf->output;
Pekka Paalanen77346a62011-11-30 16:26:35 +02004702 }
Kristian Høgsberg07937562011-04-12 17:25:42 -04004703}
4704
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03004705static void
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004706shell_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03004707{
Ander Conselvan de Oliveira7fb9f952012-03-27 17:36:42 +03004708 struct shell_surface *shsurf = get_shell_surface(es);
Tiago Vignattibe143262012-04-16 17:31:41 +03004709 struct desktop_shell *shell = shsurf->shell;
Giulio Camuffo184df502013-02-21 11:29:21 +01004710
Tiago Vignatti70e5c9c2012-05-07 15:23:07 +03004711 int type_changed = 0;
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03004712
Kristian Høgsberg8eb0f4f2013-06-17 10:33:14 -04004713 if (!weston_surface_is_mapped(es) &&
4714 !wl_list_empty(&shsurf->popup.grab_link)) {
Giulio Camuffo5085a752013-03-25 21:42:45 +01004715 remove_popup_grab(shsurf);
4716 }
4717
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004718 if (es->width == 0)
Giulio Camuffo184df502013-02-21 11:29:21 +01004719 return;
4720
Kristian Høgsbergc8f8dd82013-12-05 23:20:33 -08004721 if (shsurf->state_changed) {
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04004722 set_surface_type(shsurf);
Kristian Høgsbergf7e23d52012-04-27 17:51:59 -04004723 type_changed = 1;
4724 }
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04004725
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03004726 if (!weston_surface_is_mapped(es)) {
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004727 map(shell, shsurf, sx, sy);
Kristian Høgsbergf7e23d52012-04-27 17:51:59 -04004728 } else if (type_changed || sx != 0 || sy != 0 ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004729 shsurf->last_width != es->width ||
4730 shsurf->last_height != es->height) {
4731 shsurf->last_width = es->width;
4732 shsurf->last_height = es->height;
John Kåre Alsaker490d02a2012-09-30 02:57:21 +02004733 float from_x, from_y;
4734 float to_x, to_y;
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03004735
Jason Ekstranda7af7042013-10-12 22:38:11 -05004736 weston_view_to_global_float(shsurf->view, 0, 0, &from_x, &from_y);
4737 weston_view_to_global_float(shsurf->view, sx, sy, &to_x, &to_y);
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03004738 configure(shell, es,
Jason Ekstranda7af7042013-10-12 22:38:11 -05004739 shsurf->view->geometry.x + to_x - from_x,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004740 shsurf->view->geometry.y + to_y - from_y);
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03004741 }
4742}
4743
Zhang, Xiong Y31236932013-12-13 22:10:57 +02004744static void
4745shell_surface_output_destroyed(struct weston_surface *es)
4746{
4747 struct shell_surface *shsurf = get_shell_surface(es);
4748
4749 shsurf->saved_position_valid = false;
Ander Conselvan de Oliveirafc63fdd2013-12-13 22:10:58 +02004750 shsurf->next_state.maximized = false;
4751 shsurf->next_state.fullscreen = false;
4752 shsurf->state_changed = true;
Zhang, Xiong Y31236932013-12-13 22:10:57 +02004753}
4754
Tiago Vignattib7dbbd62012-09-25 17:57:01 +03004755static void launch_desktop_shell_process(void *data);
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02004756
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04004757static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05004758desktop_shell_sigchld(struct weston_process *process, int status)
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02004759{
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02004760 uint32_t time;
Tiago Vignattibe143262012-04-16 17:31:41 +03004761 struct desktop_shell *shell =
4762 container_of(process, struct desktop_shell, child.process);
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02004763
4764 shell->child.process.pid = 0;
4765 shell->child.client = NULL; /* already destroyed by wayland */
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02004766
4767 /* if desktop-shell dies more than 5 times in 30 seconds, give up */
4768 time = weston_compositor_get_time();
Kristian Høgsbergf03a6162012-01-17 11:07:42 -05004769 if (time - shell->child.deathstamp > 30000) {
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02004770 shell->child.deathstamp = time;
4771 shell->child.deathcount = 0;
4772 }
4773
4774 shell->child.deathcount++;
4775 if (shell->child.deathcount > 5) {
Emilio Pozuelo Monfort46ce7982013-11-20 13:22:29 +01004776 weston_log("%s died, giving up.\n", shell->client);
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02004777 return;
4778 }
4779
Emilio Pozuelo Monfort46ce7982013-11-20 13:22:29 +01004780 weston_log("%s died, respawning...\n", shell->client);
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02004781 launch_desktop_shell_process(shell);
Pekka Paalanen79346ab2013-05-22 18:03:09 +03004782 shell_fade_startup(shell);
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02004783}
4784
Tiago Vignattib7dbbd62012-09-25 17:57:01 +03004785static void
Ander Conselvan de Oliveira312ea4c2013-12-20 21:07:01 +02004786desktop_shell_client_destroy(struct wl_listener *listener, void *data)
4787{
4788 struct desktop_shell *shell;
4789
4790 shell = container_of(listener, struct desktop_shell,
4791 child.client_destroy_listener);
4792
4793 shell->child.client = NULL;
4794}
4795
4796static void
Tiago Vignattib7dbbd62012-09-25 17:57:01 +03004797launch_desktop_shell_process(void *data)
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02004798{
Tiago Vignattib7dbbd62012-09-25 17:57:01 +03004799 struct desktop_shell *shell = data;
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02004800
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05004801 shell->child.client = weston_client_launch(shell->compositor,
Pekka Paalanen409ef0a2011-12-02 15:30:21 +02004802 &shell->child.process,
Emilio Pozuelo Monfort46ce7982013-11-20 13:22:29 +01004803 shell->client,
Pekka Paalanen409ef0a2011-12-02 15:30:21 +02004804 desktop_shell_sigchld);
4805
4806 if (!shell->child.client)
Emilio Pozuelo Monfort46ce7982013-11-20 13:22:29 +01004807 weston_log("not able to start %s\n", shell->client);
Ander Conselvan de Oliveira312ea4c2013-12-20 21:07:01 +02004808
4809 shell->child.client_destroy_listener.notify =
4810 desktop_shell_client_destroy;
4811 wl_client_add_destroy_listener(shell->child.client,
4812 &shell->child.client_destroy_listener);
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02004813}
4814
4815static void
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04004816bind_shell(struct wl_client *client, void *data, uint32_t version, uint32_t id)
4817{
Tiago Vignattibe143262012-04-16 17:31:41 +03004818 struct desktop_shell *shell = data;
Jason Ekstranda85118c2013-06-27 20:17:02 -05004819 struct wl_resource *resource;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04004820
Jason Ekstranda85118c2013-06-27 20:17:02 -05004821 resource = wl_resource_create(client, &wl_shell_interface, 1, id);
4822 if (resource)
4823 wl_resource_set_implementation(resource, &shell_implementation,
4824 shell, NULL);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04004825}
4826
Kristian Høgsberg75840622011-09-06 13:48:16 -04004827static void
Rafael Antognollie2a34552013-12-03 15:35:45 -02004828bind_xdg_shell(struct wl_client *client, void *data, uint32_t version, uint32_t id)
4829{
4830 struct desktop_shell *shell = data;
4831 struct wl_resource *resource;
4832
4833 resource = wl_resource_create(client, &xdg_shell_interface, 1, id);
4834 if (resource)
4835 wl_resource_set_dispatcher(resource,
4836 xdg_shell_unversioned_dispatch,
4837 NULL, shell, NULL);
4838}
4839
4840static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02004841unbind_desktop_shell(struct wl_resource *resource)
4842{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05004843 struct desktop_shell *shell = wl_resource_get_user_data(resource);
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05004844
4845 if (shell->locked)
4846 resume_desktop(shell);
4847
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02004848 shell->child.desktop_shell = NULL;
4849 shell->prepare_event_sent = false;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02004850}
4851
4852static void
Kristian Høgsberg75840622011-09-06 13:48:16 -04004853bind_desktop_shell(struct wl_client *client,
4854 void *data, uint32_t version, uint32_t id)
4855{
Tiago Vignattibe143262012-04-16 17:31:41 +03004856 struct desktop_shell *shell = data;
Pekka Paalanenbbe60522011-11-03 14:11:33 +02004857 struct wl_resource *resource;
Kristian Høgsberg75840622011-09-06 13:48:16 -04004858
Jason Ekstranda85118c2013-06-27 20:17:02 -05004859 resource = wl_resource_create(client, &desktop_shell_interface,
4860 MIN(version, 2), id);
Pekka Paalanenbbe60522011-11-03 14:11:33 +02004861
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02004862 if (client == shell->child.client) {
Jason Ekstranda85118c2013-06-27 20:17:02 -05004863 wl_resource_set_implementation(resource,
4864 &desktop_shell_implementation,
4865 shell, unbind_desktop_shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02004866 shell->child.desktop_shell = resource;
Pekka Paalanen79346ab2013-05-22 18:03:09 +03004867
4868 if (version < 2)
4869 shell_fade_startup(shell);
4870
Pekka Paalanenbbe60522011-11-03 14:11:33 +02004871 return;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02004872 }
Pekka Paalanenbbe60522011-11-03 14:11:33 +02004873
4874 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
4875 "permission to bind desktop_shell denied");
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04004876 wl_resource_destroy(resource);
Kristian Høgsberg75840622011-09-06 13:48:16 -04004877}
4878
Pekka Paalanen6e168112011-11-24 11:34:05 +02004879static void
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004880screensaver_configure(struct weston_surface *surface, int32_t sx, int32_t sy)
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04004881{
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01004882 struct desktop_shell *shell = surface->configure_private;
Jason Ekstranda7af7042013-10-12 22:38:11 -05004883 struct weston_view *view;
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04004884
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06004885 if (surface->width == 0)
Giulio Camuffo184df502013-02-21 11:29:21 +01004886 return;
4887
Pekka Paalanen3a1d07d2012-12-20 14:02:13 +02004888 /* XXX: starting weston-screensaver beforehand does not work */
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04004889 if (!shell->locked)
4890 return;
4891
Jason Ekstranda7af7042013-10-12 22:38:11 -05004892 view = container_of(surface->views.next, struct weston_view, surface_link);
4893 center_on_output(view, surface->output);
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04004894
Jason Ekstranda7af7042013-10-12 22:38:11 -05004895 if (wl_list_empty(&view->layer_link)) {
4896 wl_list_insert(shell->lock_layer.view_list.prev,
4897 &view->layer_link);
4898 weston_view_update_transform(view);
Ander Conselvan de Oliveira859e8852013-02-21 18:35:21 +02004899 wl_event_source_timer_update(shell->screensaver.timer,
4900 shell->screensaver.duration);
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004901 shell_fade(shell, FADE_IN);
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04004902 }
4903}
4904
4905static void
Pekka Paalanen6e168112011-11-24 11:34:05 +02004906screensaver_set_surface(struct wl_client *client,
4907 struct wl_resource *resource,
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04004908 struct wl_resource *surface_resource,
Pekka Paalanen6e168112011-11-24 11:34:05 +02004909 struct wl_resource *output_resource)
4910{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05004911 struct desktop_shell *shell = wl_resource_get_user_data(resource);
Jason Ekstrand0f2ef7e2013-06-14 10:07:53 -05004912 struct weston_surface *surface =
4913 wl_resource_get_user_data(surface_resource);
Jason Ekstranda0d2dde2013-06-14 10:08:01 -05004914 struct weston_output *output = wl_resource_get_user_data(output_resource);
Jason Ekstranda7af7042013-10-12 22:38:11 -05004915 struct weston_view *view, *next;
4916
4917 /* Make sure we only have one view */
4918 wl_list_for_each_safe(view, next, &surface->views, surface_link)
4919 weston_view_destroy(view);
4920 weston_view_create(surface);
Pekka Paalanen6e168112011-11-24 11:34:05 +02004921
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04004922 surface->configure = screensaver_configure;
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01004923 surface->configure_private = shell;
Pekka Paalanen77346a62011-11-30 16:26:35 +02004924 surface->output = output;
Pekka Paalanen6e168112011-11-24 11:34:05 +02004925}
4926
4927static const struct screensaver_interface screensaver_implementation = {
4928 screensaver_set_surface
4929};
4930
4931static void
4932unbind_screensaver(struct wl_resource *resource)
4933{
Jason Ekstrand651f00e2013-06-14 10:07:54 -05004934 struct desktop_shell *shell = wl_resource_get_user_data(resource);
Pekka Paalanen6e168112011-11-24 11:34:05 +02004935
Pekka Paalanen77346a62011-11-30 16:26:35 +02004936 shell->screensaver.binding = NULL;
Pekka Paalanen6e168112011-11-24 11:34:05 +02004937}
4938
4939static void
4940bind_screensaver(struct wl_client *client,
4941 void *data, uint32_t version, uint32_t id)
4942{
Tiago Vignattibe143262012-04-16 17:31:41 +03004943 struct desktop_shell *shell = data;
Pekka Paalanen6e168112011-11-24 11:34:05 +02004944 struct wl_resource *resource;
4945
Jason Ekstranda85118c2013-06-27 20:17:02 -05004946 resource = wl_resource_create(client, &screensaver_interface, 1, id);
Pekka Paalanen6e168112011-11-24 11:34:05 +02004947
Pekka Paalanen77346a62011-11-30 16:26:35 +02004948 if (shell->screensaver.binding == NULL) {
Jason Ekstranda85118c2013-06-27 20:17:02 -05004949 wl_resource_set_implementation(resource,
4950 &screensaver_implementation,
4951 shell, unbind_screensaver);
Pekka Paalanen77346a62011-11-30 16:26:35 +02004952 shell->screensaver.binding = resource;
Pekka Paalanen6e168112011-11-24 11:34:05 +02004953 return;
4954 }
4955
4956 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
4957 "interface object already bound");
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04004958 wl_resource_destroy(resource);
Pekka Paalanen6e168112011-11-24 11:34:05 +02004959}
4960
Kristian Høgsberg07045392012-02-19 18:52:44 -05004961struct switcher {
Tiago Vignattibe143262012-04-16 17:31:41 +03004962 struct desktop_shell *shell;
Kristian Høgsberg07045392012-02-19 18:52:44 -05004963 struct weston_surface *current;
4964 struct wl_listener listener;
Kristian Høgsberg29139d42013-04-18 15:25:39 -04004965 struct weston_keyboard_grab grab;
Kristian Høgsberg07045392012-02-19 18:52:44 -05004966};
4967
4968static void
4969switcher_next(struct switcher *switcher)
4970{
Jason Ekstranda7af7042013-10-12 22:38:11 -05004971 struct weston_view *view;
Kristian Høgsberg07045392012-02-19 18:52:44 -05004972 struct weston_surface *first = NULL, *prev = NULL, *next = NULL;
Kristian Høgsberg32e56862012-04-02 22:18:58 -04004973 struct shell_surface *shsurf;
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04004974 struct workspace *ws = get_current_workspace(switcher->shell);
Kristian Høgsberg07045392012-02-19 18:52:44 -05004975
Jason Ekstranda7af7042013-10-12 22:38:11 -05004976 wl_list_for_each(view, &ws->layer.view_list, layer_link) {
Rafael Antognollied207b42013-12-03 15:35:43 -02004977 shsurf = get_shell_surface(view->surface);
Rafael Antognolli5031cbe2013-12-05 19:01:21 -02004978 if (shsurf &&
4979 shsurf->type == SHELL_SURFACE_TOPLEVEL &&
4980 shsurf->parent == NULL) {
Kristian Høgsberg07045392012-02-19 18:52:44 -05004981 if (first == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05004982 first = view->surface;
Kristian Høgsberg07045392012-02-19 18:52:44 -05004983 if (prev == switcher->current)
Jason Ekstranda7af7042013-10-12 22:38:11 -05004984 next = view->surface;
4985 prev = view->surface;
4986 view->alpha = 0.25;
4987 weston_view_geometry_dirty(view);
4988 weston_surface_damage(view->surface);
Kristian Høgsberg07045392012-02-19 18:52:44 -05004989 }
Alex Wu1659daa2012-04-01 20:13:09 +08004990
Jason Ekstranda7af7042013-10-12 22:38:11 -05004991 if (is_black_surface(view->surface, NULL)) {
4992 view->alpha = 0.25;
4993 weston_view_geometry_dirty(view);
4994 weston_surface_damage(view->surface);
Alex Wu1659daa2012-04-01 20:13:09 +08004995 }
Kristian Høgsberg07045392012-02-19 18:52:44 -05004996 }
4997
4998 if (next == NULL)
4999 next = first;
5000
Alex Wu07b26062012-03-12 16:06:01 +08005001 if (next == NULL)
5002 return;
5003
Kristian Høgsberg07045392012-02-19 18:52:44 -05005004 wl_list_remove(&switcher->listener.link);
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05005005 wl_signal_add(&next->destroy_signal, &switcher->listener);
Kristian Høgsberg07045392012-02-19 18:52:44 -05005006
5007 switcher->current = next;
Jason Ekstranda7af7042013-10-12 22:38:11 -05005008 wl_list_for_each(view, &next->views, surface_link)
5009 view->alpha = 1.0;
Alex Wu1659daa2012-04-01 20:13:09 +08005010
Kristian Høgsberg32e56862012-04-02 22:18:58 -04005011 shsurf = get_shell_surface(switcher->current);
Rafael Antognolli03b16592013-12-03 15:35:42 -02005012 if (shsurf && shsurf->state.fullscreen)
Jason Ekstranda7af7042013-10-12 22:38:11 -05005013 shsurf->fullscreen.black_view->alpha = 1.0;
Kristian Høgsberg07045392012-02-19 18:52:44 -05005014}
5015
5016static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04005017switcher_handle_surface_destroy(struct wl_listener *listener, void *data)
Kristian Høgsberg07045392012-02-19 18:52:44 -05005018{
5019 struct switcher *switcher =
5020 container_of(listener, struct switcher, listener);
5021
5022 switcher_next(switcher);
5023}
5024
5025static void
Daniel Stone351eb612012-05-31 15:27:47 -04005026switcher_destroy(struct switcher *switcher)
Kristian Høgsberg07045392012-02-19 18:52:44 -05005027{
Jason Ekstranda7af7042013-10-12 22:38:11 -05005028 struct weston_view *view;
Kristian Høgsberg29139d42013-04-18 15:25:39 -04005029 struct weston_keyboard *keyboard = switcher->grab.keyboard;
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04005030 struct workspace *ws = get_current_workspace(switcher->shell);
Kristian Høgsberg07045392012-02-19 18:52:44 -05005031
Jason Ekstranda7af7042013-10-12 22:38:11 -05005032 wl_list_for_each(view, &ws->layer.view_list, layer_link) {
Louis-Francis Ratté-Boulianneb482dbd2013-11-19 11:37:11 +01005033 if (is_focus_view(view))
5034 continue;
5035
Jason Ekstranda7af7042013-10-12 22:38:11 -05005036 view->alpha = 1.0;
5037 weston_surface_damage(view->surface);
Kristian Høgsberg07045392012-02-19 18:52:44 -05005038 }
5039
Alex Wu07b26062012-03-12 16:06:01 +08005040 if (switcher->current)
Daniel Stone37816df2012-05-16 18:45:18 +01005041 activate(switcher->shell, switcher->current,
5042 (struct weston_seat *) keyboard->seat);
Kristian Høgsberg07045392012-02-19 18:52:44 -05005043 wl_list_remove(&switcher->listener.link);
Kristian Høgsberg29139d42013-04-18 15:25:39 -04005044 weston_keyboard_end_grab(keyboard);
5045 if (keyboard->input_method_resource)
5046 keyboard->grab = &keyboard->input_method_grab;
Kristian Høgsberg07045392012-02-19 18:52:44 -05005047 free(switcher);
5048}
5049
5050static void
Kristian Høgsberg29139d42013-04-18 15:25:39 -04005051switcher_key(struct weston_keyboard_grab *grab,
Daniel Stonec9785ea2012-05-30 16:31:52 +01005052 uint32_t time, uint32_t key, uint32_t state_w)
Kristian Høgsberg07045392012-02-19 18:52:44 -05005053{
5054 struct switcher *switcher = container_of(grab, struct switcher, grab);
Daniel Stonec9785ea2012-05-30 16:31:52 +01005055 enum wl_keyboard_key_state state = state_w;
Daniel Stone351eb612012-05-31 15:27:47 -04005056
Daniel Stonec9785ea2012-05-30 16:31:52 +01005057 if (key == KEY_TAB && state == WL_KEYBOARD_KEY_STATE_PRESSED)
Daniel Stone351eb612012-05-31 15:27:47 -04005058 switcher_next(switcher);
5059}
5060
5061static void
Kristian Høgsberg29139d42013-04-18 15:25:39 -04005062switcher_modifier(struct weston_keyboard_grab *grab, uint32_t serial,
Daniel Stone351eb612012-05-31 15:27:47 -04005063 uint32_t mods_depressed, uint32_t mods_latched,
5064 uint32_t mods_locked, uint32_t group)
5065{
5066 struct switcher *switcher = container_of(grab, struct switcher, grab);
Daniel Stone37816df2012-05-16 18:45:18 +01005067 struct weston_seat *seat = (struct weston_seat *) grab->keyboard->seat;
Kristian Høgsberg07045392012-02-19 18:52:44 -05005068
Daniel Stone351eb612012-05-31 15:27:47 -04005069 if ((seat->modifier_state & switcher->shell->binding_modifier) == 0)
5070 switcher_destroy(switcher);
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04005071}
Kristian Høgsberg07045392012-02-19 18:52:44 -05005072
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02005073static void
5074switcher_cancel(struct weston_keyboard_grab *grab)
5075{
5076 struct switcher *switcher = container_of(grab, struct switcher, grab);
5077
5078 switcher_destroy(switcher);
5079}
5080
Kristian Høgsberg29139d42013-04-18 15:25:39 -04005081static const struct weston_keyboard_grab_interface switcher_grab = {
Daniel Stone351eb612012-05-31 15:27:47 -04005082 switcher_key,
5083 switcher_modifier,
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02005084 switcher_cancel,
Kristian Høgsberg07045392012-02-19 18:52:44 -05005085};
5086
5087static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04005088switcher_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
Daniel Stone325fc2d2012-05-30 16:31:58 +01005089 void *data)
Kristian Høgsberg07045392012-02-19 18:52:44 -05005090{
Tiago Vignattibe143262012-04-16 17:31:41 +03005091 struct desktop_shell *shell = data;
Kristian Høgsberg07045392012-02-19 18:52:44 -05005092 struct switcher *switcher;
5093
5094 switcher = malloc(sizeof *switcher);
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04005095 switcher->shell = shell;
Kristian Høgsberg07045392012-02-19 18:52:44 -05005096 switcher->current = NULL;
Kristian Høgsberg27e30522012-04-11 23:18:23 -04005097 switcher->listener.notify = switcher_handle_surface_destroy;
Kristian Høgsberg07045392012-02-19 18:52:44 -05005098 wl_list_init(&switcher->listener.link);
5099
Alexander Larssonf82b6ca2013-05-28 16:23:39 +02005100 restore_all_output_modes(shell->compositor);
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04005101 lower_fullscreen_layer(switcher->shell);
Kristian Høgsberg07045392012-02-19 18:52:44 -05005102 switcher->grab.interface = &switcher_grab;
Kristian Høgsberg29139d42013-04-18 15:25:39 -04005103 weston_keyboard_start_grab(seat->keyboard, &switcher->grab);
5104 weston_keyboard_set_focus(seat->keyboard, NULL);
Kristian Høgsberg07045392012-02-19 18:52:44 -05005105 switcher_next(switcher);
5106}
5107
Pekka Paalanen3c647232011-12-22 13:43:43 +02005108static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04005109backlight_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
Daniel Stone325fc2d2012-05-30 16:31:58 +01005110 void *data)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02005111{
5112 struct weston_compositor *compositor = data;
5113 struct weston_output *output;
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03005114 long backlight_new = 0;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02005115
5116 /* TODO: we're limiting to simple use cases, where we assume just
5117 * control on the primary display. We'd have to extend later if we
5118 * ever get support for setting backlights on random desktop LCD
5119 * panels though */
5120 output = get_default_output(compositor);
5121 if (!output)
5122 return;
5123
5124 if (!output->set_backlight)
5125 return;
5126
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03005127 if (key == KEY_F9 || key == KEY_BRIGHTNESSDOWN)
5128 backlight_new = output->backlight_current - 25;
5129 else if (key == KEY_F10 || key == KEY_BRIGHTNESSUP)
5130 backlight_new = output->backlight_current + 25;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02005131
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03005132 if (backlight_new < 5)
5133 backlight_new = 5;
5134 if (backlight_new > 255)
5135 backlight_new = 255;
5136
5137 output->backlight_current = backlight_new;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02005138 output->set_backlight(output, output->backlight_current);
5139}
5140
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005141struct debug_binding_grab {
Kristian Høgsberg29139d42013-04-18 15:25:39 -04005142 struct weston_keyboard_grab grab;
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005143 struct weston_seat *seat;
5144 uint32_t key[2];
5145 int key_released[2];
5146};
5147
5148static void
Kristian Høgsberg29139d42013-04-18 15:25:39 -04005149debug_binding_key(struct weston_keyboard_grab *grab, uint32_t time,
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005150 uint32_t key, uint32_t state)
5151{
5152 struct debug_binding_grab *db = (struct debug_binding_grab *) grab;
Rob Bradford880ebc72013-07-22 17:31:38 +01005153 struct weston_compositor *ec = db->seat->compositor;
5154 struct wl_display *display = ec->wl_display;
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005155 struct wl_resource *resource;
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005156 uint32_t serial;
5157 int send = 0, terminate = 0;
5158 int check_binding = 1;
5159 int i;
Neil Roberts96d790e2013-09-19 17:32:00 +01005160 struct wl_list *resource_list;
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005161
5162 if (state == WL_KEYBOARD_KEY_STATE_RELEASED) {
5163 /* Do not run bindings on key releases */
5164 check_binding = 0;
5165
5166 for (i = 0; i < 2; i++)
5167 if (key == db->key[i])
5168 db->key_released[i] = 1;
5169
5170 if (db->key_released[0] && db->key_released[1]) {
5171 /* All key releases been swalled so end the grab */
5172 terminate = 1;
5173 } else if (key != db->key[0] && key != db->key[1]) {
5174 /* Should not swallow release of other keys */
5175 send = 1;
5176 }
5177 } else if (key == db->key[0] && !db->key_released[0]) {
5178 /* Do not check bindings for the first press of the binding
5179 * key. This allows it to be used as a debug shortcut.
5180 * We still need to swallow this event. */
5181 check_binding = 0;
5182 } else if (db->key[1]) {
5183 /* If we already ran a binding don't process another one since
5184 * we can't keep track of all the binding keys that were
5185 * pressed in order to swallow the release events. */
5186 send = 1;
5187 check_binding = 0;
5188 }
5189
5190 if (check_binding) {
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005191 if (weston_compositor_run_debug_binding(ec, db->seat, time,
5192 key, state)) {
5193 /* We ran a binding so swallow the press and keep the
5194 * grab to swallow the released too. */
5195 send = 0;
5196 terminate = 0;
5197 db->key[1] = key;
5198 } else {
5199 /* Terminate the grab since the key pressed is not a
5200 * debug binding key. */
5201 send = 1;
5202 terminate = 1;
5203 }
5204 }
5205
5206 if (send) {
Neil Roberts96d790e2013-09-19 17:32:00 +01005207 serial = wl_display_next_serial(display);
5208 resource_list = &grab->keyboard->focus_resource_list;
5209 wl_resource_for_each(resource, resource_list) {
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005210 wl_keyboard_send_key(resource, serial, time, key, state);
5211 }
5212 }
5213
5214 if (terminate) {
Kristian Høgsberg29139d42013-04-18 15:25:39 -04005215 weston_keyboard_end_grab(grab->keyboard);
5216 if (grab->keyboard->input_method_resource)
5217 grab->keyboard->grab = &grab->keyboard->input_method_grab;
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005218 free(db);
5219 }
5220}
5221
5222static void
Kristian Høgsberg29139d42013-04-18 15:25:39 -04005223debug_binding_modifiers(struct weston_keyboard_grab *grab, uint32_t serial,
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005224 uint32_t mods_depressed, uint32_t mods_latched,
5225 uint32_t mods_locked, uint32_t group)
5226{
5227 struct wl_resource *resource;
Neil Roberts96d790e2013-09-19 17:32:00 +01005228 struct wl_list *resource_list;
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005229
Neil Roberts96d790e2013-09-19 17:32:00 +01005230 resource_list = &grab->keyboard->focus_resource_list;
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005231
Neil Roberts96d790e2013-09-19 17:32:00 +01005232 wl_resource_for_each(resource, resource_list) {
5233 wl_keyboard_send_modifiers(resource, serial, mods_depressed,
5234 mods_latched, mods_locked, group);
5235 }
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005236}
5237
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02005238static void
5239debug_binding_cancel(struct weston_keyboard_grab *grab)
5240{
5241 struct debug_binding_grab *db = (struct debug_binding_grab *) grab;
5242
5243 weston_keyboard_end_grab(grab->keyboard);
5244 free(db);
5245}
5246
Kristian Høgsberg29139d42013-04-18 15:25:39 -04005247struct weston_keyboard_grab_interface debug_binding_keyboard_grab = {
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005248 debug_binding_key,
Jonas Ådahl1ea343e2013-10-25 23:18:05 +02005249 debug_binding_modifiers,
5250 debug_binding_cancel,
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005251};
5252
5253static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04005254debug_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005255{
5256 struct debug_binding_grab *grab;
5257
5258 grab = calloc(1, sizeof *grab);
5259 if (!grab)
5260 return;
5261
5262 grab->seat = (struct weston_seat *) seat;
5263 grab->key[0] = key;
5264 grab->grab.interface = &debug_binding_keyboard_grab;
Kristian Høgsberg29139d42013-04-18 15:25:39 -04005265 weston_keyboard_start_grab(seat->keyboard, &grab->grab);
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005266}
5267
Kristian Høgsbergb41c0812012-03-04 14:53:40 -05005268static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04005269force_kill_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
Daniel Stone325fc2d2012-05-30 16:31:58 +01005270 void *data)
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04005271{
Kristian Høgsbergfe7aa902013-05-08 09:54:37 -04005272 struct weston_surface *focus_surface;
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04005273 struct wl_client *client;
Tiago Vignatti1d01b012012-09-27 17:48:36 +03005274 struct desktop_shell *shell = data;
5275 struct weston_compositor *compositor = shell->compositor;
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04005276 pid_t pid;
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04005277
Philipp Brüschweiler6cef0092012-08-13 21:27:27 +02005278 focus_surface = seat->keyboard->focus;
5279 if (!focus_surface)
5280 return;
5281
Tiago Vignatti1d01b012012-09-27 17:48:36 +03005282 wl_signal_emit(&compositor->kill_signal, focus_surface);
5283
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05005284 client = wl_resource_get_client(focus_surface->resource);
Tiago Vignatti920f1972012-09-27 17:48:35 +03005285 wl_client_get_credentials(client, &pid, NULL, NULL);
5286
5287 /* Skip clients that we launched ourselves (the credentials of
5288 * the socketpair is ours) */
5289 if (pid == getpid())
5290 return;
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04005291
Daniel Stone325fc2d2012-05-30 16:31:58 +01005292 kill(pid, SIGKILL);
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04005293}
5294
5295static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04005296workspace_up_binding(struct weston_seat *seat, uint32_t time,
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005297 uint32_t key, void *data)
5298{
5299 struct desktop_shell *shell = data;
5300 unsigned int new_index = shell->workspaces.current;
5301
Kristian Høgsbergce345b02012-06-25 21:35:29 -04005302 if (shell->locked)
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04005303 return;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005304 if (new_index != 0)
5305 new_index--;
5306
5307 change_workspace(shell, new_index);
5308}
5309
5310static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04005311workspace_down_binding(struct weston_seat *seat, uint32_t time,
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005312 uint32_t key, void *data)
5313{
5314 struct desktop_shell *shell = data;
5315 unsigned int new_index = shell->workspaces.current;
5316
Kristian Høgsbergce345b02012-06-25 21:35:29 -04005317 if (shell->locked)
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04005318 return;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005319 if (new_index < shell->workspaces.num - 1)
5320 new_index++;
5321
5322 change_workspace(shell, new_index);
5323}
5324
5325static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04005326workspace_f_binding(struct weston_seat *seat, uint32_t time,
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005327 uint32_t key, void *data)
5328{
5329 struct desktop_shell *shell = data;
5330 unsigned int new_index;
5331
Kristian Høgsbergce345b02012-06-25 21:35:29 -04005332 if (shell->locked)
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04005333 return;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005334 new_index = key - KEY_F1;
5335 if (new_index >= shell->workspaces.num)
5336 new_index = shell->workspaces.num - 1;
5337
5338 change_workspace(shell, new_index);
5339}
5340
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02005341static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04005342workspace_move_surface_up_binding(struct weston_seat *seat, uint32_t time,
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02005343 uint32_t key, void *data)
5344{
5345 struct desktop_shell *shell = data;
5346 unsigned int new_index = shell->workspaces.current;
5347
5348 if (shell->locked)
5349 return;
5350
5351 if (new_index != 0)
5352 new_index--;
5353
5354 take_surface_to_workspace_by_seat(shell, seat, new_index);
5355}
5356
5357static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04005358workspace_move_surface_down_binding(struct weston_seat *seat, uint32_t time,
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02005359 uint32_t key, void *data)
5360{
5361 struct desktop_shell *shell = data;
5362 unsigned int new_index = shell->workspaces.current;
5363
5364 if (shell->locked)
5365 return;
5366
5367 if (new_index < shell->workspaces.num - 1)
5368 new_index++;
5369
5370 take_surface_to_workspace_by_seat(shell, seat, new_index);
5371}
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005372
5373static void
Xiong Zhang6b481422013-10-23 13:58:32 +08005374handle_output_destroy(struct wl_listener *listener, void *data)
5375{
5376 struct shell_output *output_listener =
5377 container_of(listener, struct shell_output, destroy_listener);
5378
5379 wl_list_remove(&output_listener->destroy_listener.link);
5380 wl_list_remove(&output_listener->link);
5381 free(output_listener);
5382}
5383
5384static void
5385create_shell_output(struct desktop_shell *shell,
5386 struct weston_output *output)
5387{
5388 struct shell_output *shell_output;
5389
5390 shell_output = zalloc(sizeof *shell_output);
5391 if (shell_output == NULL)
5392 return;
5393
5394 shell_output->output = output;
5395 shell_output->shell = shell;
5396 shell_output->destroy_listener.notify = handle_output_destroy;
5397 wl_signal_add(&output->destroy_signal,
5398 &shell_output->destroy_listener);
Kristian Høgsberga3a0e182013-10-23 23:36:04 -07005399 wl_list_insert(shell->output_list.prev, &shell_output->link);
Xiong Zhang6b481422013-10-23 13:58:32 +08005400}
5401
5402static void
5403handle_output_create(struct wl_listener *listener, void *data)
5404{
5405 struct desktop_shell *shell =
5406 container_of(listener, struct desktop_shell, output_create_listener);
5407 struct weston_output *output = (struct weston_output *)data;
5408
5409 create_shell_output(shell, output);
5410}
5411
5412static void
5413setup_output_destroy_handler(struct weston_compositor *ec,
5414 struct desktop_shell *shell)
5415{
5416 struct weston_output *output;
5417
5418 wl_list_init(&shell->output_list);
5419 wl_list_for_each(output, &ec->output_list, link)
5420 create_shell_output(shell, output);
5421
5422 shell->output_create_listener.notify = handle_output_create;
5423 wl_signal_add(&ec->output_created_signal,
5424 &shell->output_create_listener);
5425}
5426
5427static void
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04005428shell_destroy(struct wl_listener *listener, void *data)
Pekka Paalanen3c647232011-12-22 13:43:43 +02005429{
Tiago Vignattibe143262012-04-16 17:31:41 +03005430 struct desktop_shell *shell =
5431 container_of(listener, struct desktop_shell, destroy_listener);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005432 struct workspace **ws;
Xiong Zhang6b481422013-10-23 13:58:32 +08005433 struct shell_output *shell_output, *tmp;
Pekka Paalanen3c647232011-12-22 13:43:43 +02005434
Kristian Høgsberg17bccae2014-01-16 16:46:28 -08005435 /* Force state to unlocked so we don't try to fade */
5436 shell->locked = false;
Pekka Paalanen9cf5cc82012-01-02 16:00:24 +02005437 if (shell->child.client)
5438 wl_client_destroy(shell->child.client);
5439
Ander Conselvan de Oliveiraa4575632013-02-21 18:35:23 +02005440 wl_list_remove(&shell->idle_listener.link);
5441 wl_list_remove(&shell->wake_listener.link);
Kristian Høgsberg677a5f52013-12-04 11:00:19 -08005442
5443 input_panel_destroy(shell);
Kristian Høgsberg88c16072012-05-16 08:04:19 -04005444
Xiong Zhang6b481422013-10-23 13:58:32 +08005445 wl_list_for_each_safe(shell_output, tmp, &shell->output_list, link) {
5446 wl_list_remove(&shell_output->destroy_listener.link);
5447 wl_list_remove(&shell_output->link);
5448 free(shell_output);
5449 }
5450
5451 wl_list_remove(&shell->output_create_listener.link);
5452
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005453 wl_array_for_each(ws, &shell->workspaces.array)
5454 workspace_destroy(*ws);
5455 wl_array_release(&shell->workspaces.array);
5456
Pekka Paalanen3c647232011-12-22 13:43:43 +02005457 free(shell->screensaver.path);
Emilio Pozuelo Monfort46ce7982013-11-20 13:22:29 +01005458 free(shell->client);
Pekka Paalanen3c647232011-12-22 13:43:43 +02005459 free(shell);
5460}
5461
Tiago Vignatti0b52d482012-04-20 18:54:25 +03005462static void
5463shell_add_bindings(struct weston_compositor *ec, struct desktop_shell *shell)
5464{
5465 uint32_t mod;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005466 int i, num_workspace_bindings;
Tiago Vignatti0b52d482012-04-20 18:54:25 +03005467
5468 /* fixed bindings */
Daniel Stone325fc2d2012-05-30 16:31:58 +01005469 weston_compositor_add_key_binding(ec, KEY_BACKSPACE,
5470 MODIFIER_CTRL | MODIFIER_ALT,
5471 terminate_binding, ec);
5472 weston_compositor_add_button_binding(ec, BTN_LEFT, 0,
5473 click_to_activate_binding,
5474 shell);
Neil Robertsa28c6932013-10-03 16:43:04 +01005475 weston_compositor_add_touch_binding(ec, 0,
5476 touch_to_activate_binding,
5477 shell);
Daniel Stone325fc2d2012-05-30 16:31:58 +01005478 weston_compositor_add_axis_binding(ec, WL_POINTER_AXIS_VERTICAL_SCROLL,
5479 MODIFIER_SUPER | MODIFIER_ALT,
5480 surface_opacity_binding, NULL);
5481 weston_compositor_add_axis_binding(ec, WL_POINTER_AXIS_VERTICAL_SCROLL,
5482 MODIFIER_SUPER, zoom_axis_binding,
5483 NULL);
Tiago Vignatti0b52d482012-04-20 18:54:25 +03005484
5485 /* configurable bindings */
5486 mod = shell->binding_modifier;
Daniel Stone325fc2d2012-05-30 16:31:58 +01005487 weston_compositor_add_key_binding(ec, KEY_PAGEUP, mod,
5488 zoom_key_binding, NULL);
5489 weston_compositor_add_key_binding(ec, KEY_PAGEDOWN, mod,
5490 zoom_key_binding, NULL);
Kristian Høgsberg211b5172014-01-11 13:10:21 -08005491 weston_compositor_add_key_binding(ec, KEY_M, mod | MODIFIER_SHIFT,
5492 maximize_binding, NULL);
5493 weston_compositor_add_key_binding(ec, KEY_F, mod | MODIFIER_SHIFT,
5494 fullscreen_binding, NULL);
Daniel Stone325fc2d2012-05-30 16:31:58 +01005495 weston_compositor_add_button_binding(ec, BTN_LEFT, mod, move_binding,
5496 shell);
Neil Robertsaba0f252013-10-03 16:43:05 +01005497 weston_compositor_add_touch_binding(ec, mod, touch_move_binding, shell);
Daniel Stone325fc2d2012-05-30 16:31:58 +01005498 weston_compositor_add_button_binding(ec, BTN_MIDDLE, mod,
5499 resize_binding, shell);
Pekka Paalanen7bb65102013-05-22 18:03:04 +03005500
5501 if (ec->capabilities & WESTON_CAP_ROTATION_ANY)
5502 weston_compositor_add_button_binding(ec, BTN_RIGHT, mod,
5503 rotate_binding, NULL);
5504
Daniel Stone325fc2d2012-05-30 16:31:58 +01005505 weston_compositor_add_key_binding(ec, KEY_TAB, mod, switcher_binding,
5506 shell);
5507 weston_compositor_add_key_binding(ec, KEY_F9, mod, backlight_binding,
5508 ec);
5509 weston_compositor_add_key_binding(ec, KEY_BRIGHTNESSDOWN, 0,
5510 backlight_binding, ec);
5511 weston_compositor_add_key_binding(ec, KEY_F10, mod, backlight_binding,
5512 ec);
5513 weston_compositor_add_key_binding(ec, KEY_BRIGHTNESSUP, 0,
5514 backlight_binding, ec);
Daniel Stone325fc2d2012-05-30 16:31:58 +01005515 weston_compositor_add_key_binding(ec, KEY_K, mod,
5516 force_kill_binding, shell);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005517 weston_compositor_add_key_binding(ec, KEY_UP, mod,
5518 workspace_up_binding, shell);
5519 weston_compositor_add_key_binding(ec, KEY_DOWN, mod,
5520 workspace_down_binding, shell);
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02005521 weston_compositor_add_key_binding(ec, KEY_UP, mod | MODIFIER_SHIFT,
5522 workspace_move_surface_up_binding,
5523 shell);
5524 weston_compositor_add_key_binding(ec, KEY_DOWN, mod | MODIFIER_SHIFT,
5525 workspace_move_surface_down_binding,
5526 shell);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005527
Kristian Høgsbergd56ab4e2014-01-16 16:51:52 -08005528 if (shell->exposay_modifier)
5529 weston_compositor_add_modifier_binding(ec, shell->exposay_modifier,
5530 exposay_binding, shell);
Daniel Stonedf8133b2013-11-19 11:37:14 +01005531
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005532 /* Add bindings for mod+F[1-6] for workspace 1 to 6. */
5533 if (shell->workspaces.num > 1) {
5534 num_workspace_bindings = shell->workspaces.num;
5535 if (num_workspace_bindings > 6)
5536 num_workspace_bindings = 6;
5537 for (i = 0; i < num_workspace_bindings; i++)
5538 weston_compositor_add_key_binding(ec, KEY_F1 + i, mod,
5539 workspace_f_binding,
5540 shell);
5541 }
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02005542
5543 /* Debug bindings */
5544 weston_compositor_add_key_binding(ec, KEY_SPACE, mod | MODIFIER_SHIFT,
5545 debug_binding, shell);
Tiago Vignatti0b52d482012-04-20 18:54:25 +03005546}
5547
Kristian Høgsberg1c562182011-05-02 22:09:20 -04005548WL_EXPORT int
Kristian Høgsbergcb4685b2013-02-20 15:37:49 -05005549module_init(struct weston_compositor *ec,
Ossama Othmana50e6e42013-05-14 09:48:26 -07005550 int *argc, char *argv[])
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05005551{
Kristian Høgsbergf4d2f232012-08-10 10:05:39 -04005552 struct weston_seat *seat;
Tiago Vignattibe143262012-04-16 17:31:41 +03005553 struct desktop_shell *shell;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005554 struct workspace **pws;
5555 unsigned int i;
Tiago Vignattib7dbbd62012-09-25 17:57:01 +03005556 struct wl_event_loop *loop;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04005557
Peter Huttererf3d62272013-08-08 11:57:05 +10005558 shell = zalloc(sizeof *shell);
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04005559 if (shell == NULL)
5560 return -1;
5561
Kristian Høgsberg75840622011-09-06 13:48:16 -04005562 shell->compositor = ec;
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04005563
5564 shell->destroy_listener.notify = shell_destroy;
5565 wl_signal_add(&ec->destroy_signal, &shell->destroy_listener);
Ander Conselvan de Oliveiraa4575632013-02-21 18:35:23 +02005566 shell->idle_listener.notify = idle_handler;
5567 wl_signal_add(&ec->idle_signal, &shell->idle_listener);
5568 shell->wake_listener.notify = wake_handler;
5569 wl_signal_add(&ec->wake_signal, &shell->wake_listener);
Kristian Høgsberg677a5f52013-12-04 11:00:19 -08005570
Scott Moreauff1db4a2012-04-17 19:06:18 -06005571 ec->ping_handler = ping_handler;
Kristian Høgsberg82a1d112012-07-19 14:02:00 -04005572 ec->shell_interface.shell = shell;
Tiago Vignattibc052c92012-04-19 16:18:18 +03005573 ec->shell_interface.create_shell_surface = create_shell_surface;
Jason Ekstranda7af7042013-10-12 22:38:11 -05005574 ec->shell_interface.get_primary_view = get_primary_view;
Tiago Vignattibc052c92012-04-19 16:18:18 +03005575 ec->shell_interface.set_toplevel = set_toplevel;
Tiago Vignatti491bac12012-05-18 16:37:43 -04005576 ec->shell_interface.set_transient = set_transient;
Kristian Høgsbergb810eb52013-02-12 20:07:05 -05005577 ec->shell_interface.set_fullscreen = set_fullscreen;
Tiago Vignattifb2adba2013-06-12 15:43:21 -03005578 ec->shell_interface.set_xwayland = set_xwayland;
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04005579 ec->shell_interface.move = surface_move;
Kristian Høgsbergc1693f22012-05-22 16:56:23 -04005580 ec->shell_interface.resize = surface_resize;
Giulio Camuffo62942ad2013-09-11 18:20:47 +02005581 ec->shell_interface.set_title = set_title;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05005582
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05005583 weston_layer_init(&shell->fullscreen_layer, &ec->cursor_layer.link);
5584 weston_layer_init(&shell->panel_layer, &shell->fullscreen_layer.link);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005585 weston_layer_init(&shell->background_layer, &shell->panel_layer.link);
5586 weston_layer_init(&shell->lock_layer, NULL);
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02005587 weston_layer_init(&shell->input_panel_layer, NULL);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005588
5589 wl_array_init(&shell->workspaces.array);
Jonas Ådahle9d22502012-08-29 22:13:01 +02005590 wl_list_init(&shell->workspaces.client_list);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05005591
Kristian Høgsberg677a5f52013-12-04 11:00:19 -08005592 if (input_panel_setup(shell) < 0)
5593 return -1;
5594
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04005595 shell_configuration(shell);
Pekka Paalanene955f1e2011-12-07 11:49:52 +02005596
Daniel Stonedf8133b2013-11-19 11:37:14 +01005597 shell->exposay.state_cur = EXPOSAY_LAYOUT_INACTIVE;
5598 shell->exposay.state_target = EXPOSAY_TARGET_CANCEL;
5599
Jonas Ådahle3cddce2012-06-13 00:01:22 +02005600 for (i = 0; i < shell->workspaces.num; i++) {
5601 pws = wl_array_add(&shell->workspaces.array, sizeof *pws);
5602 if (pws == NULL)
5603 return -1;
5604
5605 *pws = workspace_create();
5606 if (*pws == NULL)
5607 return -1;
5608 }
5609 activate_workspace(shell, 0);
5610
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02005611 wl_list_init(&shell->workspaces.anim_sticky_list);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02005612 wl_list_init(&shell->workspaces.animation.link);
5613 shell->workspaces.animation.frame = animate_workspace_change_frame;
5614
Kristian Høgsberg919cddb2013-07-08 19:03:57 -04005615 if (wl_global_create(ec->wl_display, &wl_shell_interface, 1,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04005616 shell, bind_shell) == NULL)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05005617 return -1;
5618
Rafael Antognollie2a34552013-12-03 15:35:45 -02005619 if (wl_global_create(ec->wl_display, &xdg_shell_interface, 1,
5620 shell, bind_xdg_shell) == NULL)
5621 return -1;
5622
Kristian Høgsberg919cddb2013-07-08 19:03:57 -04005623 if (wl_global_create(ec->wl_display,
5624 &desktop_shell_interface, 2,
5625 shell, bind_desktop_shell) == NULL)
Kristian Høgsberg75840622011-09-06 13:48:16 -04005626 return -1;
5627
Kristian Høgsberg919cddb2013-07-08 19:03:57 -04005628 if (wl_global_create(ec->wl_display, &screensaver_interface, 1,
5629 shell, bind_screensaver) == NULL)
Pekka Paalanen6e168112011-11-24 11:34:05 +02005630 return -1;
5631
Kristian Høgsberg919cddb2013-07-08 19:03:57 -04005632 if (wl_global_create(ec->wl_display, &workspace_manager_interface, 1,
5633 shell, bind_workspace_manager) == NULL)
Jonas Ådahle9d22502012-08-29 22:13:01 +02005634 return -1;
5635
Kristian Høgsbergf03a6162012-01-17 11:07:42 -05005636 shell->child.deathstamp = weston_compositor_get_time();
Tiago Vignattib7dbbd62012-09-25 17:57:01 +03005637
Xiong Zhang6b481422013-10-23 13:58:32 +08005638 setup_output_destroy_handler(ec, shell);
5639
Tiago Vignattib7dbbd62012-09-25 17:57:01 +03005640 loop = wl_display_get_event_loop(ec->wl_display);
5641 wl_event_loop_add_idle(loop, launch_desktop_shell_process, shell);
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02005642
Ander Conselvan de Oliveira859e8852013-02-21 18:35:21 +02005643 shell->screensaver.timer =
5644 wl_event_loop_add_timer(loop, screensaver_timeout, shell);
5645
Kristian Høgsbergf4d2f232012-08-10 10:05:39 -04005646 wl_list_for_each(seat, &ec->seat_list, link)
5647 create_pointer_focus_listener(seat);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04005648
Tiago Vignatti0b52d482012-04-20 18:54:25 +03005649 shell_add_bindings(ec, shell);
Kristian Høgsberg07937562011-04-12 17:25:42 -04005650
Pekka Paalanen79346ab2013-05-22 18:03:09 +03005651 shell_fade_init(shell);
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02005652
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05005653 return 0;
5654}