blob: b7ee57651e4fe9bcc674b28a0671c5cfab645535 [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.
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05004 *
5 * Permission to use, copy, modify, distribute, and sell this software and
6 * its documentation for any purpose is hereby granted without fee, provided
7 * that the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of the copyright holders not be used in
10 * advertising or publicity pertaining to distribution of the software
11 * without specific, written prior permission. The copyright holders make
12 * no representations about the suitability of this software for any
13 * purpose. It is provided "as is" without express or implied warranty.
14 *
15 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
16 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
20 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 */
23
24#include <stdlib.h>
Kristian Høgsberg75840622011-09-06 13:48:16 -040025#include <stdio.h>
Pekka Paalanen9ef3e012011-11-15 13:34:48 +020026#include <stdbool.h>
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050027#include <string.h>
28#include <unistd.h>
Kristian Høgsberg07937562011-04-12 17:25:42 -040029#include <linux/input.h>
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +020030#include <assert.h>
Pekka Paalanen18027e52011-12-02 16:31:49 +020031#include <signal.h>
Pekka Paalanen460099f2012-01-20 16:48:25 +020032#include <math.h>
Kristian Høgsberg92a57db2012-05-26 13:41:06 -040033#include <sys/types.h>
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050034
Pekka Paalanen50719bc2011-11-22 14:18:50 +020035#include <wayland-server.h>
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050036#include "compositor.h"
Kristian Høgsberg75840622011-09-06 13:48:16 -040037#include "desktop-shell-server-protocol.h"
Jan Arne Petersenffbb20f2013-01-16 21:26:55 +010038#include "input-method-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"
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050041
Jonas Ådahle3cddce2012-06-13 00:01:22 +020042#define DEFAULT_NUM_WORKSPACES 1
Jonas Ådahl62fcd042012-06-13 00:01:23 +020043#define DEFAULT_WORKSPACE_CHANGE_ANIMATION_LENGTH 200
Jonas Ådahle3cddce2012-06-13 00:01:22 +020044
Juan Zhaoe10d2792012-04-25 19:09:52 +080045enum animation_type {
46 ANIMATION_NONE,
47
48 ANIMATION_ZOOM,
49 ANIMATION_FADE
50};
51
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +020052enum fade_type {
53 FADE_IN,
54 FADE_OUT
55};
56
Jonas Ådahl04769742012-06-13 00:01:24 +020057struct focus_state {
58 struct weston_seat *seat;
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -040059 struct workspace *ws;
Jonas Ådahl04769742012-06-13 00:01:24 +020060 struct weston_surface *keyboard_focus;
61 struct wl_list link;
62 struct wl_listener seat_destroy_listener;
63 struct wl_listener surface_destroy_listener;
64};
65
Jonas Ådahle3cddce2012-06-13 00:01:22 +020066struct workspace {
67 struct weston_layer layer;
Jonas Ådahl04769742012-06-13 00:01:24 +020068
69 struct wl_list focus_list;
70 struct wl_listener seat_destroyed_listener;
Jonas Ådahle3cddce2012-06-13 00:01:22 +020071};
72
Philipp Brüschweiler88013572012-08-06 13:44:42 +020073struct input_panel_surface {
Jan Arne Petersenffbb20f2013-01-16 21:26:55 +010074 struct wl_resource resource;
75
76 struct desktop_shell *shell;
77
Philipp Brüschweiler88013572012-08-06 13:44:42 +020078 struct wl_list link;
79 struct weston_surface *surface;
Jan Arne Petersenffbb20f2013-01-16 21:26:55 +010080 struct wl_listener surface_destroy_listener;
Jan Arne Petersen14da96b2013-04-18 16:47:28 +020081
Jan Arne Petersen7cd29e12013-04-18 16:47:29 +020082 struct weston_output *output;
Jan Arne Petersen14da96b2013-04-18 16:47:28 +020083 uint32_t panel;
Philipp Brüschweiler88013572012-08-06 13:44:42 +020084};
85
Tiago Vignattibe143262012-04-16 17:31:41 +030086struct desktop_shell {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050087 struct weston_compositor *compositor;
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -040088
Ander Conselvan de Oliveiraa4575632013-02-21 18:35:23 +020089 struct wl_listener idle_listener;
90 struct wl_listener wake_listener;
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -040091 struct wl_listener destroy_listener;
Jan Arne Petersen42feced2012-06-21 21:52:17 +020092 struct wl_listener show_input_panel_listener;
93 struct wl_listener hide_input_panel_listener;
Jan Arne Petersen14da96b2013-04-18 16:47:28 +020094 struct wl_listener update_input_panel_listener;
Pekka Paalanen6cd281a2011-11-03 14:11:32 +020095
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -050096 struct weston_layer fullscreen_layer;
97 struct weston_layer panel_layer;
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -050098 struct weston_layer background_layer;
99 struct weston_layer lock_layer;
Philipp Brüschweiler711fda82012-08-09 18:50:43 +0200100 struct weston_layer input_panel_layer;
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -0500101
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400102 struct wl_listener pointer_focus_listener;
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300103 struct weston_surface *grab_surface;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400104
Pekka Paalanen6cd281a2011-11-03 14:11:32 +0200105 struct {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500106 struct weston_process process;
Pekka Paalanen6cd281a2011-11-03 14:11:32 +0200107 struct wl_client *client;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200108 struct wl_resource *desktop_shell;
Pekka Paalanen4d733ee2012-01-17 14:36:27 +0200109
110 unsigned deathcount;
111 uint32_t deathstamp;
Pekka Paalanen6cd281a2011-11-03 14:11:32 +0200112 } child;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200113
114 bool locked;
Philipp Brüschweiler711fda82012-08-09 18:50:43 +0200115 bool showing_input_panels;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200116 bool prepare_event_sent;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200117
Jan Arne Petersen14da96b2013-04-18 16:47:28 +0200118 struct {
119 struct weston_surface *surface;
120 pixman_box32_t cursor_rectangle;
121 } text_input;
122
Kristian Høgsberg730c94d2012-06-26 21:44:35 -0400123 struct weston_surface *lock_surface;
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500124 struct wl_listener lock_surface_listener;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100125
Pekka Paalanen77346a62011-11-30 16:26:35 +0200126 struct {
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200127 struct wl_array array;
128 unsigned int current;
129 unsigned int num;
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200130
Jonas Ådahle9d22502012-08-29 22:13:01 +0200131 struct wl_list client_list;
132
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200133 struct weston_animation animation;
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200134 struct wl_list anim_sticky_list;
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200135 int anim_dir;
136 uint32_t anim_timestamp;
137 double anim_current;
138 struct workspace *anim_from;
139 struct workspace *anim_to;
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200140 } workspaces;
141
142 struct {
Pekka Paalanen3c647232011-12-22 13:43:43 +0200143 char *path;
Pekka Paalanen7296e792011-12-07 16:22:00 +0200144 int duration;
Pekka Paalanen77346a62011-11-30 16:26:35 +0200145 struct wl_resource *binding;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500146 struct weston_process process;
Ander Conselvan de Oliveira859e8852013-02-21 18:35:21 +0200147 struct wl_event_source *timer;
Pekka Paalanen77346a62011-11-30 16:26:35 +0200148 } screensaver;
Kristian Høgsbergb41c0812012-03-04 14:53:40 -0500149
Jan Arne Petersen42feced2012-06-21 21:52:17 +0200150 struct {
151 struct wl_resource *binding;
152 struct wl_list surfaces;
153 } input_panel;
154
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +0200155 struct {
156 struct weston_surface *surface;
157 struct weston_surface_animation *animation;
158 enum fade_type type;
159 } fade;
160
Tiago Vignatti0b52d482012-04-20 18:54:25 +0300161 uint32_t binding_modifier;
Juan Zhaoe10d2792012-04-25 19:09:52 +0800162 enum animation_type win_animation_type;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400163};
164
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500165enum shell_surface_type {
Pekka Paalanen98262232011-12-01 10:42:22 +0200166 SHELL_SURFACE_NONE,
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500167 SHELL_SURFACE_TOPLEVEL,
168 SHELL_SURFACE_TRANSIENT,
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500169 SHELL_SURFACE_FULLSCREEN,
Juan Zhao96879df2012-02-07 08:45:41 +0800170 SHELL_SURFACE_MAXIMIZED,
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500171 SHELL_SURFACE_POPUP
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200172};
173
Scott Moreauff1db4a2012-04-17 19:06:18 -0600174struct ping_timer {
175 struct wl_event_source *source;
Scott Moreauff1db4a2012-04-17 19:06:18 -0600176 uint32_t serial;
177};
178
Pekka Paalanen56cdea92011-11-23 16:14:12 +0200179struct shell_surface {
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200180 struct wl_resource resource;
181
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500182 struct weston_surface *surface;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200183 struct wl_listener surface_destroy_listener;
Kristian Høgsberg8150b192012-06-27 10:22:58 -0400184 struct weston_surface *parent;
Tiago Vignattibe143262012-04-16 17:31:41 +0300185 struct desktop_shell *shell;
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200186
Kristian Høgsberg7f366e72012-04-27 17:20:01 -0400187 enum shell_surface_type type, next_type;
Kristian Høgsberge7afd912012-05-02 09:47:44 -0400188 char *title, *class;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500189 int32_t saved_x, saved_y;
Alex Wu4539b082012-03-01 12:57:46 +0800190 bool saved_position_valid;
Alex Wu7bcb8bd2012-04-27 09:07:24 +0800191 bool saved_rotation_valid;
Scott Moreauff1db4a2012-04-17 19:06:18 -0600192 int unresponsive;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100193
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500194 struct {
Pekka Paalanen460099f2012-01-20 16:48:25 +0200195 struct weston_transform transform;
Kristian Høgsberg765e27b2012-01-27 13:36:13 -0500196 struct weston_matrix rotation;
Pekka Paalanen460099f2012-01-20 16:48:25 +0200197 } rotation;
198
199 struct {
Giulio Camuffo5085a752013-03-25 21:42:45 +0100200 struct wl_list grab_link;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500201 int32_t x, y;
Giulio Camuffo5085a752013-03-25 21:42:45 +0100202 struct shell_seat *shseat;
Kristian Høgsberg3730f362012-04-13 12:40:07 -0400203 uint32_t serial;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500204 } popup;
205
Alex Wu4539b082012-03-01 12:57:46 +0800206 struct {
Tiago Vignatti52e598c2012-05-07 15:23:08 +0300207 int32_t x, y;
Tiago Vignatti491bac12012-05-18 16:37:43 -0400208 uint32_t flags;
Tiago Vignatti52e598c2012-05-07 15:23:08 +0300209 } transient;
210
211 struct {
Alex Wu4539b082012-03-01 12:57:46 +0800212 enum wl_shell_surface_fullscreen_method type;
213 struct weston_transform transform; /* matrix from x, y */
214 uint32_t framerate;
215 struct weston_surface *black_surface;
216 } fullscreen;
217
Scott Moreauff1db4a2012-04-17 19:06:18 -0600218 struct ping_timer *ping_timer;
219
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200220 struct weston_transform workspace_transform;
221
Kristian Høgsberg1cbf3262012-02-17 23:49:07 -0500222 struct weston_output *fullscreen_output;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500223 struct weston_output *output;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100224 struct wl_list link;
Kristian Høgsberga61ca062012-05-22 16:05:52 -0400225
226 const struct weston_shell_client *client;
Pekka Paalanen56cdea92011-11-23 16:14:12 +0200227};
228
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300229struct shell_grab {
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -0400230 struct weston_pointer_grab grab;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300231 struct shell_surface *shsurf;
232 struct wl_listener shsurf_destroy_listener;
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -0400233 struct weston_pointer *pointer;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300234};
235
236struct weston_move_grab {
237 struct shell_grab base;
Daniel Stone103db7f2012-05-08 17:17:55 +0100238 wl_fixed_t dx, dy;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500239};
240
Pekka Paalanen460099f2012-01-20 16:48:25 +0200241struct rotate_grab {
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300242 struct shell_grab base;
Kristian Høgsberg765e27b2012-01-27 13:36:13 -0500243 struct weston_matrix rotation;
Pekka Paalanen460099f2012-01-20 16:48:25 +0200244 struct {
John Kåre Alsaker490d02a2012-09-30 02:57:21 +0200245 float x;
246 float y;
Pekka Paalanen460099f2012-01-20 16:48:25 +0200247 } center;
248};
249
Giulio Camuffo5085a752013-03-25 21:42:45 +0100250struct shell_seat {
251 struct weston_seat *seat;
252 struct wl_listener seat_destroy_listener;
253
254 struct {
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -0400255 struct weston_pointer_grab grab;
Giulio Camuffo5085a752013-03-25 21:42:45 +0100256 struct wl_list surfaces_list;
257 struct wl_client *client;
258 int32_t initial_up;
259 } popup_grab;
260};
261
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400262static void
263activate(struct desktop_shell *shell, struct weston_surface *es,
264 struct weston_seat *seat);
265
266static struct workspace *
267get_current_workspace(struct desktop_shell *shell);
268
Alex Wubd3354b2012-04-17 17:20:49 +0800269static struct shell_surface *
270get_shell_surface(struct weston_surface *surface);
271
272static struct desktop_shell *
273shell_surface_get_shell(struct shell_surface *shsurf);
274
Kristian Høgsberg0c369032013-02-14 21:31:44 -0500275static void
276surface_rotate(struct shell_surface *surface, struct wl_seat *seat);
277
Alex Wubd3354b2012-04-17 17:20:49 +0800278static bool
279shell_surface_is_top_fullscreen(struct shell_surface *shsurf)
280{
281 struct desktop_shell *shell;
282 struct weston_surface *top_fs_es;
283
284 shell = shell_surface_get_shell(shsurf);
Quentin Glidicc0d79ce2013-01-29 14:16:13 +0100285
Alex Wubd3354b2012-04-17 17:20:49 +0800286 if (wl_list_empty(&shell->fullscreen_layer.surface_list))
287 return false;
288
289 top_fs_es = container_of(shell->fullscreen_layer.surface_list.next,
Quentin Glidicc0d79ce2013-01-29 14:16:13 +0100290 struct weston_surface,
Alex Wubd3354b2012-04-17 17:20:49 +0800291 layer_link);
292 return (shsurf == get_shell_surface(top_fs_es));
293}
294
Kristian Høgsberg6af8eb92012-01-25 16:57:11 -0500295static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400296destroy_shell_grab_shsurf(struct wl_listener *listener, void *data)
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300297{
298 struct shell_grab *grab;
299
300 grab = container_of(listener, struct shell_grab,
301 shsurf_destroy_listener);
302
303 grab->shsurf = NULL;
304}
305
306static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -0400307popup_grab_end(struct weston_pointer *pointer);
Kristian Høgsberg57e09072012-10-30 14:07:27 -0400308
309static void
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300310shell_grab_start(struct shell_grab *grab,
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -0400311 const struct weston_pointer_grab_interface *interface,
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300312 struct shell_surface *shsurf,
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -0400313 struct weston_pointer *pointer,
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300314 enum desktop_shell_cursor cursor)
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300315{
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300316 struct desktop_shell *shell = shsurf->shell;
317
Kristian Høgsberg57e09072012-10-30 14:07:27 -0400318 popup_grab_end(pointer);
319
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300320 grab->grab.interface = interface;
321 grab->shsurf = shsurf;
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400322 grab->shsurf_destroy_listener.notify = destroy_shell_grab_shsurf;
323 wl_signal_add(&shsurf->resource.destroy_signal,
324 &grab->shsurf_destroy_listener);
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300325
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300326 grab->pointer = pointer;
327 grab->grab.focus = &shsurf->surface->surface;
328
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -0400329 weston_pointer_start_grab(pointer, &grab->grab);
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300330 desktop_shell_send_grab_cursor(shell->child.desktop_shell, cursor);
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -0400331 weston_pointer_set_focus(pointer, &shell->grab_surface->surface,
332 wl_fixed_from_int(0), wl_fixed_from_int(0));
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300333}
334
335static void
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300336shell_grab_end(struct shell_grab *grab)
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300337{
Kristian Høgsberg47b5dca2012-06-07 18:08:04 -0400338 if (grab->shsurf)
339 wl_list_remove(&grab->shsurf_destroy_listener.link);
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300340
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -0400341 weston_pointer_end_grab(grab->pointer);
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300342}
343
344static void
Alex Wu4539b082012-03-01 12:57:46 +0800345center_on_output(struct weston_surface *surface,
346 struct weston_output *output);
347
Daniel Stone496ca172012-05-30 16:31:42 +0100348static enum weston_keyboard_modifier
Tiago Vignatti0b52d482012-04-20 18:54:25 +0300349get_modifier(char *modifier)
350{
351 if (!modifier)
352 return MODIFIER_SUPER;
353
354 if (!strcmp("ctrl", modifier))
355 return MODIFIER_CTRL;
356 else if (!strcmp("alt", modifier))
357 return MODIFIER_ALT;
358 else if (!strcmp("super", modifier))
359 return MODIFIER_SUPER;
360 else
361 return MODIFIER_SUPER;
362}
363
Juan Zhaoe10d2792012-04-25 19:09:52 +0800364static enum animation_type
365get_animation_type(char *animation)
366{
367 if (!animation)
368 return ANIMATION_NONE;
369
370 if (!strcmp("zoom", animation))
371 return ANIMATION_ZOOM;
372 else if (!strcmp("fade", animation))
373 return ANIMATION_FADE;
374 else
375 return ANIMATION_NONE;
376}
377
Alex Wu4539b082012-03-01 12:57:46 +0800378static void
Kristian Høgsbergcb4685b2013-02-20 15:37:49 -0500379shell_configuration(struct desktop_shell *shell, const char *config_file)
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200380{
Pekka Paalanen7296e792011-12-07 16:22:00 +0200381 char *path = NULL;
382 int duration = 60;
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200383 unsigned int num_workspaces = DEFAULT_NUM_WORKSPACES;
Tiago Vignatti0b52d482012-04-20 18:54:25 +0300384 char *modifier = NULL;
Juan Zhaoe10d2792012-04-25 19:09:52 +0800385 char *win_animation = NULL;
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200386
Kristian Høgsberga4e8b332012-04-20 16:48:21 -0400387 struct config_key shell_keys[] = {
Tiago Vignatti0b52d482012-04-20 18:54:25 +0300388 { "binding-modifier", CONFIG_KEY_STRING, &modifier },
Juan Zhaoe10d2792012-04-25 19:09:52 +0800389 { "animation", CONFIG_KEY_STRING, &win_animation},
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200390 { "num-workspaces",
391 CONFIG_KEY_UNSIGNED_INTEGER, &num_workspaces },
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200392 };
393
Kristian Høgsberga4e8b332012-04-20 16:48:21 -0400394 struct config_key saver_keys[] = {
395 { "path", CONFIG_KEY_STRING, &path },
396 { "duration", CONFIG_KEY_INTEGER, &duration },
397 };
398
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200399 struct config_section cs[] = {
Kristian Høgsberga4e8b332012-04-20 16:48:21 -0400400 { "shell", shell_keys, ARRAY_LENGTH(shell_keys), NULL },
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200401 { "screensaver", saver_keys, ARRAY_LENGTH(saver_keys), NULL },
402 };
403
Kristian Høgsberg6af8eb92012-01-25 16:57:11 -0500404 parse_config_file(config_file, cs, ARRAY_LENGTH(cs), shell);
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200405
Pekka Paalanen7296e792011-12-07 16:22:00 +0200406 shell->screensaver.path = path;
Ander Conselvan de Oliveira859e8852013-02-21 18:35:21 +0200407 shell->screensaver.duration = duration * 1000;
Tiago Vignatti0b52d482012-04-20 18:54:25 +0300408 shell->binding_modifier = get_modifier(modifier);
Juan Zhaoe10d2792012-04-25 19:09:52 +0800409 shell->win_animation_type = get_animation_type(win_animation);
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200410 shell->workspaces.num = num_workspaces > 0 ? num_workspaces : 1;
411}
412
413static void
Jonas Ådahl04769742012-06-13 00:01:24 +0200414focus_state_destroy(struct focus_state *state)
415{
416 wl_list_remove(&state->seat_destroy_listener.link);
417 wl_list_remove(&state->surface_destroy_listener.link);
418 free(state);
419}
420
421static void
422focus_state_seat_destroy(struct wl_listener *listener, void *data)
423{
424 struct focus_state *state = container_of(listener,
425 struct focus_state,
426 seat_destroy_listener);
427
428 wl_list_remove(&state->link);
429 focus_state_destroy(state);
430}
431
432static void
433focus_state_surface_destroy(struct wl_listener *listener, void *data)
434{
435 struct focus_state *state = container_of(listener,
436 struct focus_state,
Kristian Høgsbergb8e0d0f2012-07-31 10:30:26 -0400437 surface_destroy_listener);
Kristian Høgsberge3778222012-07-31 17:29:30 -0400438 struct desktop_shell *shell;
439 struct weston_surface *surface, *next;
Jonas Ådahl04769742012-06-13 00:01:24 +0200440
Kristian Høgsberge3778222012-07-31 17:29:30 -0400441 next = NULL;
442 wl_list_for_each(surface, &state->ws->layer.surface_list, layer_link) {
443 if (surface == state->keyboard_focus)
444 continue;
445
446 next = surface;
447 break;
448 }
449
450 if (next) {
451 shell = state->seat->compositor->shell_interface.shell;
452 activate(shell, next, state->seat);
453 } else {
454 wl_list_remove(&state->link);
455 focus_state_destroy(state);
456 }
Jonas Ådahl04769742012-06-13 00:01:24 +0200457}
458
459static struct focus_state *
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400460focus_state_create(struct weston_seat *seat, struct workspace *ws)
Jonas Ådahl04769742012-06-13 00:01:24 +0200461{
Jonas Ådahl04769742012-06-13 00:01:24 +0200462 struct focus_state *state;
Jonas Ådahl04769742012-06-13 00:01:24 +0200463
464 state = malloc(sizeof *state);
465 if (state == NULL)
466 return NULL;
467
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400468 state->ws = ws;
Jonas Ådahl04769742012-06-13 00:01:24 +0200469 state->seat = seat;
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400470 wl_list_insert(&ws->focus_list, &state->link);
Jonas Ådahl04769742012-06-13 00:01:24 +0200471
472 state->seat_destroy_listener.notify = focus_state_seat_destroy;
473 state->surface_destroy_listener.notify = focus_state_surface_destroy;
Kristian Høgsberg49124542013-05-06 22:27:40 -0400474 wl_signal_add(&seat->destroy_signal,
Jonas Ådahl04769742012-06-13 00:01:24 +0200475 &state->seat_destroy_listener);
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400476 wl_list_init(&state->surface_destroy_listener.link);
Jonas Ådahl04769742012-06-13 00:01:24 +0200477
478 return state;
479}
480
Jonas Ådahl8538b222012-08-29 22:13:03 +0200481static struct focus_state *
482ensure_focus_state(struct desktop_shell *shell, struct weston_seat *seat)
483{
484 struct workspace *ws = get_current_workspace(shell);
485 struct focus_state *state;
486
487 wl_list_for_each(state, &ws->focus_list, link)
488 if (state->seat == seat)
489 break;
490
491 if (&state->link == &ws->focus_list)
492 state = focus_state_create(seat, ws);
493
494 return state;
495}
496
Jonas Ådahl04769742012-06-13 00:01:24 +0200497static void
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400498restore_focus_state(struct desktop_shell *shell, struct workspace *ws)
Jonas Ådahl04769742012-06-13 00:01:24 +0200499{
500 struct focus_state *state, *next;
Jonas Ådahl56899442012-08-29 22:12:59 +0200501 struct wl_surface *surface;
Jonas Ådahl04769742012-06-13 00:01:24 +0200502
503 wl_list_for_each_safe(state, next, &ws->focus_list, link) {
Jonas Ådahl56899442012-08-29 22:12:59 +0200504 surface = state->keyboard_focus ?
505 &state->keyboard_focus->surface : NULL;
506
Kristian Høgsberg29139d42013-04-18 15:25:39 -0400507 weston_keyboard_set_focus(state->seat->seat.keyboard, surface);
Jonas Ådahl04769742012-06-13 00:01:24 +0200508 }
509}
510
511static void
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200512replace_focus_state(struct desktop_shell *shell, struct workspace *ws,
513 struct weston_seat *seat)
514{
515 struct focus_state *state;
516 struct wl_surface *surface;
517
518 wl_list_for_each(state, &ws->focus_list, link) {
519 if (state->seat == seat) {
520 surface = seat->seat.keyboard->focus;
521 state->keyboard_focus =
522 (struct weston_surface *) surface;
523 return;
524 }
525 }
526}
527
528static void
529drop_focus_state(struct desktop_shell *shell, struct workspace *ws,
530 struct weston_surface *surface)
531{
532 struct focus_state *state;
533
534 wl_list_for_each(state, &ws->focus_list, link)
535 if (state->keyboard_focus == surface)
536 state->keyboard_focus = NULL;
537}
538
539static void
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200540workspace_destroy(struct workspace *ws)
541{
Jonas Ådahl04769742012-06-13 00:01:24 +0200542 struct focus_state *state, *next;
543
544 wl_list_for_each_safe(state, next, &ws->focus_list, link)
545 focus_state_destroy(state);
546
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200547 free(ws);
548}
549
Jonas Ådahl04769742012-06-13 00:01:24 +0200550static void
551seat_destroyed(struct wl_listener *listener, void *data)
552{
553 struct weston_seat *seat = data;
554 struct focus_state *state, *next;
555 struct workspace *ws = container_of(listener,
556 struct workspace,
557 seat_destroyed_listener);
558
559 wl_list_for_each_safe(state, next, &ws->focus_list, link)
560 if (state->seat == seat)
561 wl_list_remove(&state->link);
562}
563
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200564static struct workspace *
565workspace_create(void)
566{
567 struct workspace *ws = malloc(sizeof *ws);
568 if (ws == NULL)
569 return NULL;
570
571 weston_layer_init(&ws->layer, NULL);
572
Jonas Ådahl04769742012-06-13 00:01:24 +0200573 wl_list_init(&ws->focus_list);
574 wl_list_init(&ws->seat_destroyed_listener.link);
575 ws->seat_destroyed_listener.notify = seat_destroyed;
576
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200577 return ws;
578}
579
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200580static int
581workspace_is_empty(struct workspace *ws)
582{
583 return wl_list_empty(&ws->layer.surface_list);
584}
585
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200586static struct workspace *
587get_workspace(struct desktop_shell *shell, unsigned int index)
588{
589 struct workspace **pws = shell->workspaces.array.data;
Philipp Brüschweiler067abf62012-09-01 16:03:05 +0200590 assert(index < shell->workspaces.num);
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200591 pws += index;
592 return *pws;
593}
594
595static struct workspace *
596get_current_workspace(struct desktop_shell *shell)
597{
598 return get_workspace(shell, shell->workspaces.current);
599}
600
601static void
602activate_workspace(struct desktop_shell *shell, unsigned int index)
603{
604 struct workspace *ws;
605
606 ws = get_workspace(shell, index);
607 wl_list_insert(&shell->panel_layer.link, &ws->layer.link);
608
609 shell->workspaces.current = index;
610}
611
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200612static unsigned int
613get_output_height(struct weston_output *output)
614{
615 return abs(output->region.extents.y1 - output->region.extents.y2);
616}
617
618static void
619surface_translate(struct weston_surface *surface, double d)
620{
621 struct shell_surface *shsurf = get_shell_surface(surface);
622 struct weston_transform *transform;
623
624 transform = &shsurf->workspace_transform;
625 if (wl_list_empty(&transform->link))
626 wl_list_insert(surface->geometry.transformation_list.prev,
627 &shsurf->workspace_transform.link);
628
629 weston_matrix_init(&shsurf->workspace_transform.matrix);
630 weston_matrix_translate(&shsurf->workspace_transform.matrix,
631 0.0, d, 0.0);
Pekka Paalanenc3ce7382013-03-08 14:56:49 +0200632 weston_surface_geometry_dirty(surface);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200633}
634
635static void
636workspace_translate_out(struct workspace *ws, double fraction)
637{
638 struct weston_surface *surface;
639 unsigned int height;
640 double d;
641
642 wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
643 height = get_output_height(surface->output);
644 d = height * fraction;
645
646 surface_translate(surface, d);
647 }
648}
649
650static void
651workspace_translate_in(struct workspace *ws, double fraction)
652{
653 struct weston_surface *surface;
654 unsigned int height;
655 double d;
656
657 wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
658 height = get_output_height(surface->output);
659
660 if (fraction > 0)
661 d = -(height - height * fraction);
662 else
663 d = height + height * fraction;
664
665 surface_translate(surface, d);
666 }
667}
668
669static void
Jonas Ådahle9d22502012-08-29 22:13:01 +0200670broadcast_current_workspace_state(struct desktop_shell *shell)
671{
672 struct wl_resource *resource;
673
674 wl_list_for_each(resource, &shell->workspaces.client_list, link)
675 workspace_manager_send_state(resource,
676 shell->workspaces.current,
677 shell->workspaces.num);
678}
679
680static void
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200681reverse_workspace_change_animation(struct desktop_shell *shell,
682 unsigned int index,
683 struct workspace *from,
684 struct workspace *to)
685{
686 shell->workspaces.current = index;
687
688 shell->workspaces.anim_to = to;
689 shell->workspaces.anim_from = from;
690 shell->workspaces.anim_dir = -1 * shell->workspaces.anim_dir;
691 shell->workspaces.anim_timestamp = 0;
692
Scott Moreau4272e632012-08-13 09:58:41 -0600693 weston_compositor_schedule_repaint(shell->compositor);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200694}
695
696static void
697workspace_deactivate_transforms(struct workspace *ws)
698{
699 struct weston_surface *surface;
700 struct shell_surface *shsurf;
701
702 wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
703 shsurf = get_shell_surface(surface);
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200704 if (!wl_list_empty(&shsurf->workspace_transform.link)) {
705 wl_list_remove(&shsurf->workspace_transform.link);
706 wl_list_init(&shsurf->workspace_transform.link);
707 }
Pekka Paalanenc3ce7382013-03-08 14:56:49 +0200708 weston_surface_geometry_dirty(surface);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200709 }
710}
711
712static void
713finish_workspace_change_animation(struct desktop_shell *shell,
714 struct workspace *from,
715 struct workspace *to)
716{
Scott Moreau4272e632012-08-13 09:58:41 -0600717 weston_compositor_schedule_repaint(shell->compositor);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200718
719 wl_list_remove(&shell->workspaces.animation.link);
720 workspace_deactivate_transforms(from);
721 workspace_deactivate_transforms(to);
722 shell->workspaces.anim_to = NULL;
723
724 wl_list_remove(&shell->workspaces.anim_from->layer.link);
725}
726
727static void
728animate_workspace_change_frame(struct weston_animation *animation,
729 struct weston_output *output, uint32_t msecs)
730{
731 struct desktop_shell *shell =
732 container_of(animation, struct desktop_shell,
733 workspaces.animation);
734 struct workspace *from = shell->workspaces.anim_from;
735 struct workspace *to = shell->workspaces.anim_to;
736 uint32_t t;
737 double x, y;
738
739 if (workspace_is_empty(from) && workspace_is_empty(to)) {
740 finish_workspace_change_animation(shell, from, to);
741 return;
742 }
743
744 if (shell->workspaces.anim_timestamp == 0) {
745 if (shell->workspaces.anim_current == 0.0)
746 shell->workspaces.anim_timestamp = msecs;
747 else
748 shell->workspaces.anim_timestamp =
749 msecs -
750 /* Invers of movement function 'y' below. */
751 (asin(1.0 - shell->workspaces.anim_current) *
752 DEFAULT_WORKSPACE_CHANGE_ANIMATION_LENGTH *
753 M_2_PI);
754 }
755
756 t = msecs - shell->workspaces.anim_timestamp;
757
758 /*
759 * x = [0, π/2]
760 * y(x) = sin(x)
761 */
762 x = t * (1.0/DEFAULT_WORKSPACE_CHANGE_ANIMATION_LENGTH) * M_PI_2;
763 y = sin(x);
764
765 if (t < DEFAULT_WORKSPACE_CHANGE_ANIMATION_LENGTH) {
Scott Moreau4272e632012-08-13 09:58:41 -0600766 weston_compositor_schedule_repaint(shell->compositor);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200767
768 workspace_translate_out(from, shell->workspaces.anim_dir * y);
769 workspace_translate_in(to, shell->workspaces.anim_dir * y);
770 shell->workspaces.anim_current = y;
771
Scott Moreau4272e632012-08-13 09:58:41 -0600772 weston_compositor_schedule_repaint(shell->compositor);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200773 }
Jonas Ådahl04769742012-06-13 00:01:24 +0200774 else
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200775 finish_workspace_change_animation(shell, from, to);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200776}
777
778static void
779animate_workspace_change(struct desktop_shell *shell,
780 unsigned int index,
781 struct workspace *from,
782 struct workspace *to)
783{
784 struct weston_output *output;
785
786 int dir;
787
788 if (index > shell->workspaces.current)
789 dir = -1;
790 else
791 dir = 1;
792
793 shell->workspaces.current = index;
794
795 shell->workspaces.anim_dir = dir;
796 shell->workspaces.anim_from = from;
797 shell->workspaces.anim_to = to;
798 shell->workspaces.anim_current = 0.0;
799 shell->workspaces.anim_timestamp = 0;
800
801 output = container_of(shell->compositor->output_list.next,
802 struct weston_output, link);
803 wl_list_insert(&output->animation_list,
804 &shell->workspaces.animation.link);
805
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200806 wl_list_insert(from->layer.link.prev, &to->layer.link);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200807
808 workspace_translate_in(to, 0);
809
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400810 restore_focus_state(shell, to);
Jonas Ådahl04769742012-06-13 00:01:24 +0200811
Scott Moreau4272e632012-08-13 09:58:41 -0600812 weston_compositor_schedule_repaint(shell->compositor);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200813}
814
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200815static void
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200816update_workspace(struct desktop_shell *shell, unsigned int index,
817 struct workspace *from, struct workspace *to)
818{
819 shell->workspaces.current = index;
820 wl_list_insert(&from->layer.link, &to->layer.link);
821 wl_list_remove(&from->layer.link);
822}
823
824static void
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200825change_workspace(struct desktop_shell *shell, unsigned int index)
826{
827 struct workspace *from;
828 struct workspace *to;
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200829
830 if (index == shell->workspaces.current)
831 return;
832
833 /* Don't change workspace when there is any fullscreen surfaces. */
834 if (!wl_list_empty(&shell->fullscreen_layer.surface_list))
835 return;
836
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200837 from = get_current_workspace(shell);
838 to = get_workspace(shell, index);
839
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200840 if (shell->workspaces.anim_from == to &&
841 shell->workspaces.anim_to == from) {
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200842 restore_focus_state(shell, to);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200843 reverse_workspace_change_animation(shell, index, from, to);
Jonas Ådahle9d22502012-08-29 22:13:01 +0200844 broadcast_current_workspace_state(shell);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200845 return;
846 }
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200847
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200848 if (shell->workspaces.anim_to != NULL)
849 finish_workspace_change_animation(shell,
850 shell->workspaces.anim_from,
851 shell->workspaces.anim_to);
852
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200853 restore_focus_state(shell, to);
Jonas Ådahl04769742012-06-13 00:01:24 +0200854
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200855 if (workspace_is_empty(to) && workspace_is_empty(from))
856 update_workspace(shell, index, from, to);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200857 else
858 animate_workspace_change(shell, index, from, to);
Jonas Ådahle9d22502012-08-29 22:13:01 +0200859
860 broadcast_current_workspace_state(shell);
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200861}
862
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200863static bool
864workspace_has_only(struct workspace *ws, struct weston_surface *surface)
865{
866 struct wl_list *list = &ws->layer.surface_list;
867 struct wl_list *e;
868
869 if (wl_list_empty(list))
870 return false;
871
872 e = list->next;
873
874 if (e->next != list)
875 return false;
876
877 return container_of(e, struct weston_surface, layer_link) == surface;
878}
879
880static void
Jonas Ådahle9d22502012-08-29 22:13:01 +0200881move_surface_to_workspace(struct desktop_shell *shell,
882 struct weston_surface *surface,
883 uint32_t workspace)
884{
885 struct workspace *from;
886 struct workspace *to;
887 struct weston_seat *seat;
888
889 if (workspace == shell->workspaces.current)
890 return;
891
Philipp Brüschweiler067abf62012-09-01 16:03:05 +0200892 if (workspace >= shell->workspaces.num)
893 workspace = shell->workspaces.num - 1;
894
Jonas Ådahle9d22502012-08-29 22:13:01 +0200895 from = get_current_workspace(shell);
896 to = get_workspace(shell, workspace);
897
898 wl_list_remove(&surface->layer_link);
899 wl_list_insert(&to->layer.surface_list, &surface->layer_link);
900
901 drop_focus_state(shell, from, surface);
902 wl_list_for_each(seat, &shell->compositor->seat_list, link)
903 if (seat->has_keyboard &&
Kristian Høgsberg29139d42013-04-18 15:25:39 -0400904 seat->keyboard.focus == &surface->surface)
905 weston_keyboard_set_focus(&seat->keyboard, NULL);
Jonas Ådahle9d22502012-08-29 22:13:01 +0200906
907 weston_surface_damage_below(surface);
908}
909
910static void
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200911take_surface_to_workspace_by_seat(struct desktop_shell *shell,
Jonas Ådahle9d22502012-08-29 22:13:01 +0200912 struct wl_seat *wl_seat,
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200913 unsigned int index)
914{
Jonas Ådahle9d22502012-08-29 22:13:01 +0200915 struct weston_seat *seat = (struct weston_seat *) wl_seat;
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200916 struct weston_surface *surface =
Jonas Ådahle9d22502012-08-29 22:13:01 +0200917 (struct weston_surface *) wl_seat->keyboard->focus;
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200918 struct shell_surface *shsurf;
919 struct workspace *from;
920 struct workspace *to;
Jonas Ådahl8538b222012-08-29 22:13:03 +0200921 struct focus_state *state;
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200922
923 if (surface == NULL ||
924 index == shell->workspaces.current)
925 return;
926
927 from = get_current_workspace(shell);
928 to = get_workspace(shell, index);
929
930 wl_list_remove(&surface->layer_link);
931 wl_list_insert(&to->layer.surface_list, &surface->layer_link);
932
Jonas Ådahle9d22502012-08-29 22:13:01 +0200933 replace_focus_state(shell, to, seat);
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200934 drop_focus_state(shell, from, surface);
935
936 if (shell->workspaces.anim_from == to &&
937 shell->workspaces.anim_to == from) {
Jonas Ådahle9d22502012-08-29 22:13:01 +0200938 wl_list_remove(&to->layer.link);
939 wl_list_insert(from->layer.link.prev, &to->layer.link);
940
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200941 reverse_workspace_change_animation(shell, index, from, to);
Jonas Ådahle9d22502012-08-29 22:13:01 +0200942 broadcast_current_workspace_state(shell);
943
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200944 return;
945 }
946
947 if (shell->workspaces.anim_to != NULL)
948 finish_workspace_change_animation(shell,
949 shell->workspaces.anim_from,
950 shell->workspaces.anim_to);
951
952 if (workspace_is_empty(from) &&
953 workspace_has_only(to, surface))
954 update_workspace(shell, index, from, to);
955 else {
956 shsurf = get_shell_surface(surface);
957 if (wl_list_empty(&shsurf->workspace_transform.link))
958 wl_list_insert(&shell->workspaces.anim_sticky_list,
959 &shsurf->workspace_transform.link);
960
961 animate_workspace_change(shell, index, from, to);
962 }
Jonas Ådahle9d22502012-08-29 22:13:01 +0200963
964 broadcast_current_workspace_state(shell);
Jonas Ådahl8538b222012-08-29 22:13:03 +0200965
966 state = ensure_focus_state(shell, seat);
967 if (state != NULL)
968 state->keyboard_focus = surface;
Jonas Ådahle9d22502012-08-29 22:13:01 +0200969}
970
971static void
972workspace_manager_move_surface(struct wl_client *client,
973 struct wl_resource *resource,
974 struct wl_resource *surface_resource,
975 uint32_t workspace)
976{
977 struct desktop_shell *shell = resource->data;
978 struct weston_surface *surface =
979 (struct weston_surface *) surface_resource;
980
981 move_surface_to_workspace(shell, surface, workspace);
982}
983
984static const struct workspace_manager_interface workspace_manager_implementation = {
985 workspace_manager_move_surface,
986};
987
988static void
989unbind_resource(struct wl_resource *resource)
990{
991 wl_list_remove(&resource->link);
992 free(resource);
993}
994
995static void
996bind_workspace_manager(struct wl_client *client,
997 void *data, uint32_t version, uint32_t id)
998{
999 struct desktop_shell *shell = data;
1000 struct wl_resource *resource;
1001
1002 resource = wl_client_add_object(client, &workspace_manager_interface,
1003 &workspace_manager_implementation,
1004 id, shell);
1005
1006 if (resource == NULL) {
1007 weston_log("couldn't add workspace manager object");
1008 return;
1009 }
1010
1011 resource->destroy = unbind_resource;
1012 wl_list_insert(&shell->workspaces.client_list, &resource->link);
1013
1014 workspace_manager_send_state(resource,
1015 shell->workspaces.current,
1016 shell->workspaces.num);
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02001017}
1018
Pekka Paalanen56cdea92011-11-23 16:14:12 +02001019static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001020noop_grab_focus(struct weston_pointer_grab *grab,
Daniel Stone103db7f2012-05-08 17:17:55 +01001021 struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y)
Kristian Høgsberg9ddb8262012-01-04 21:30:29 -05001022{
1023 grab->focus = NULL;
1024}
1025
1026static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001027move_grab_motion(struct weston_pointer_grab *grab,
Daniel Stone103db7f2012-05-08 17:17:55 +01001028 uint32_t time, wl_fixed_t x, wl_fixed_t y)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001029{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001030 struct weston_move_grab *move = (struct weston_move_grab *) grab;
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001031 struct weston_pointer *pointer = grab->pointer;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03001032 struct shell_surface *shsurf = move->base.shsurf;
1033 struct weston_surface *es;
Daniel Stone37816df2012-05-16 18:45:18 +01001034 int dx = wl_fixed_to_int(pointer->x + move->dx);
1035 int dy = wl_fixed_to_int(pointer->y + move->dy);
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03001036
1037 if (!shsurf)
1038 return;
1039
1040 es = shsurf->surface;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001041
Daniel Stone103db7f2012-05-08 17:17:55 +01001042 weston_surface_configure(es, dx, dy,
Pekka Paalanen60921e52012-01-25 15:55:43 +02001043 es->geometry.width, es->geometry.height);
Kristian Høgsberg6c6fb992012-06-21 12:06:22 -04001044
1045 weston_compositor_schedule_repaint(es->compositor);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001046}
1047
1048static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001049move_grab_button(struct weston_pointer_grab *grab,
Daniel Stone4dbadb12012-05-30 16:31:51 +01001050 uint32_t time, uint32_t button, uint32_t state_w)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001051{
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03001052 struct shell_grab *shell_grab = container_of(grab, struct shell_grab,
1053 grab);
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001054 struct weston_pointer *pointer = grab->pointer;
Daniel Stone4dbadb12012-05-30 16:31:51 +01001055 enum wl_pointer_button_state state = state_w;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001056
Daniel Stone4dbadb12012-05-30 16:31:51 +01001057 if (pointer->button_count == 0 &&
1058 state == WL_POINTER_BUTTON_STATE_RELEASED) {
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001059 shell_grab_end(shell_grab);
Kristian Høgsberg9ddb8262012-01-04 21:30:29 -05001060 free(grab);
1061 }
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001062}
1063
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001064static const struct weston_pointer_grab_interface move_grab_interface = {
Kristian Høgsberg9ddb8262012-01-04 21:30:29 -05001065 noop_grab_focus,
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001066 move_grab_motion,
1067 move_grab_button,
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001068};
1069
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001070static int
1071surface_move(struct shell_surface *shsurf, struct weston_seat *ws)
1072{
1073 struct weston_move_grab *move;
1074
1075 if (!shsurf)
1076 return -1;
1077
1078 if (shsurf->type == SHELL_SURFACE_FULLSCREEN)
1079 return 0;
1080
1081 move = malloc(sizeof *move);
1082 if (!move)
1083 return -1;
1084
1085 move->dx = wl_fixed_from_double(shsurf->surface->geometry.x) -
1086 ws->seat.pointer->grab_x;
1087 move->dy = wl_fixed_from_double(shsurf->surface->geometry.y) -
1088 ws->seat.pointer->grab_y;
1089
1090 shell_grab_start(&move->base, &move_grab_interface, shsurf,
1091 ws->seat.pointer, DESKTOP_SHELL_CURSOR_MOVE);
1092
1093 return 0;
1094}
1095
1096static void
1097shell_surface_move(struct wl_client *client, struct wl_resource *resource,
1098 struct wl_resource *seat_resource, uint32_t serial)
1099{
1100 struct weston_seat *ws = seat_resource->data;
1101 struct shell_surface *shsurf = resource->data;
1102
1103 if (ws->seat.pointer->button_count == 0 ||
1104 ws->seat.pointer->grab_serial != serial ||
1105 ws->seat.pointer->focus != &shsurf->surface->surface)
1106 return;
1107
1108 if (surface_move(shsurf, ws) < 0)
1109 wl_resource_post_no_memory(resource);
1110}
1111
1112struct weston_resize_grab {
1113 struct shell_grab base;
1114 uint32_t edges;
1115 int32_t width, height;
1116};
1117
1118static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001119resize_grab_motion(struct weston_pointer_grab *grab,
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001120 uint32_t time, wl_fixed_t x, wl_fixed_t y)
1121{
1122 struct weston_resize_grab *resize = (struct weston_resize_grab *) grab;
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001123 struct weston_pointer *pointer = grab->pointer;
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001124 struct shell_surface *shsurf = resize->base.shsurf;
1125 int32_t width, height;
1126 wl_fixed_t from_x, from_y;
1127 wl_fixed_t to_x, to_y;
1128
1129 if (!shsurf)
1130 return;
1131
1132 weston_surface_from_global_fixed(shsurf->surface,
1133 pointer->grab_x, pointer->grab_y,
1134 &from_x, &from_y);
1135 weston_surface_from_global_fixed(shsurf->surface,
1136 pointer->x, pointer->y, &to_x, &to_y);
1137
1138 width = resize->width;
1139 if (resize->edges & WL_SHELL_SURFACE_RESIZE_LEFT) {
1140 width += wl_fixed_to_int(from_x - to_x);
1141 } else if (resize->edges & WL_SHELL_SURFACE_RESIZE_RIGHT) {
1142 width += wl_fixed_to_int(to_x - from_x);
1143 }
1144
1145 height = resize->height;
1146 if (resize->edges & WL_SHELL_SURFACE_RESIZE_TOP) {
1147 height += wl_fixed_to_int(from_y - to_y);
1148 } else if (resize->edges & WL_SHELL_SURFACE_RESIZE_BOTTOM) {
1149 height += wl_fixed_to_int(to_y - from_y);
1150 }
1151
1152 shsurf->client->send_configure(shsurf->surface,
1153 resize->edges, width, height);
1154}
1155
1156static void
1157send_configure(struct weston_surface *surface,
1158 uint32_t edges, int32_t width, int32_t height)
1159{
1160 struct shell_surface *shsurf = get_shell_surface(surface);
1161
1162 wl_shell_surface_send_configure(&shsurf->resource,
1163 edges, width, height);
1164}
1165
1166static const struct weston_shell_client shell_client = {
1167 send_configure
1168};
1169
1170static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001171resize_grab_button(struct weston_pointer_grab *grab,
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001172 uint32_t time, uint32_t button, uint32_t state_w)
1173{
1174 struct weston_resize_grab *resize = (struct weston_resize_grab *) grab;
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001175 struct weston_pointer *pointer = grab->pointer;
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001176 enum wl_pointer_button_state state = state_w;
1177
1178 if (pointer->button_count == 0 &&
1179 state == WL_POINTER_BUTTON_STATE_RELEASED) {
1180 shell_grab_end(&resize->base);
1181 free(grab);
1182 }
1183}
1184
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001185static const struct weston_pointer_grab_interface resize_grab_interface = {
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001186 noop_grab_focus,
1187 resize_grab_motion,
1188 resize_grab_button,
1189};
1190
1191static int
1192surface_resize(struct shell_surface *shsurf,
1193 struct weston_seat *ws, uint32_t edges)
1194{
1195 struct weston_resize_grab *resize;
1196
Rafal Mielniczuk23c67592013-03-11 19:26:53 +01001197 if (shsurf->type == SHELL_SURFACE_FULLSCREEN ||
1198 shsurf->type == SHELL_SURFACE_MAXIMIZED)
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001199 return 0;
1200
1201 if (edges == 0 || edges > 15 ||
1202 (edges & 3) == 3 || (edges & 12) == 12)
1203 return 0;
1204
1205 resize = malloc(sizeof *resize);
1206 if (!resize)
1207 return -1;
1208
1209 resize->edges = edges;
1210 resize->width = shsurf->surface->geometry.width;
1211 resize->height = shsurf->surface->geometry.height;
1212
1213 shell_grab_start(&resize->base, &resize_grab_interface, shsurf,
1214 ws->seat.pointer, edges);
1215
1216 return 0;
1217}
1218
1219static void
1220shell_surface_resize(struct wl_client *client, struct wl_resource *resource,
1221 struct wl_resource *seat_resource, uint32_t serial,
1222 uint32_t edges)
1223{
1224 struct weston_seat *ws = seat_resource->data;
1225 struct shell_surface *shsurf = resource->data;
1226
1227 if (shsurf->type == SHELL_SURFACE_FULLSCREEN)
1228 return;
1229
1230 if (ws->seat.pointer->button_count == 0 ||
1231 ws->seat.pointer->grab_serial != serial ||
1232 ws->seat.pointer->focus != &shsurf->surface->surface)
1233 return;
1234
1235 if (surface_resize(shsurf, ws, edges) < 0)
1236 wl_resource_post_no_memory(resource);
1237}
1238
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001239static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001240busy_cursor_grab_focus(struct weston_pointer_grab *base,
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001241 struct wl_surface *surface, int32_t x, int32_t y)
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001242{
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001243 struct shell_grab *grab = (struct shell_grab *) base;
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001244
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001245 if (grab->grab.focus != surface) {
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001246 shell_grab_end(grab);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001247 free(grab);
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001248 }
1249}
1250
1251static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001252busy_cursor_grab_motion(struct weston_pointer_grab *grab,
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001253 uint32_t time, int32_t x, int32_t y)
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001254{
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001255}
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001256
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001257static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001258busy_cursor_grab_button(struct weston_pointer_grab *base,
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001259 uint32_t time, uint32_t button, uint32_t state)
1260{
Kristian Høgsbergbbe98392012-08-01 00:20:21 -04001261 struct shell_grab *grab = (struct shell_grab *) base;
1262 struct shell_surface *shsurf;
Quentin Glidicc0d79ce2013-01-29 14:16:13 +01001263 struct weston_surface *surface =
Kristian Høgsbergbbe98392012-08-01 00:20:21 -04001264 (struct weston_surface *) grab->grab.pointer->current;
1265 struct weston_seat *seat =
1266 (struct weston_seat *) grab->grab.pointer->seat;
1267
1268 shsurf = get_shell_surface(surface);
1269 if (shsurf && button == BTN_LEFT && state) {
1270 activate(shsurf->shell, shsurf->surface, seat);
1271 surface_move(shsurf, seat);
Kristian Høgsberg0c369032013-02-14 21:31:44 -05001272 } else if (shsurf && button == BTN_RIGHT && state) {
1273 activate(shsurf->shell, shsurf->surface, seat);
1274 surface_rotate(shsurf, &seat->seat);
Kristian Høgsbergbbe98392012-08-01 00:20:21 -04001275 }
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001276}
1277
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001278static const struct weston_pointer_grab_interface busy_cursor_grab_interface = {
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001279 busy_cursor_grab_focus,
1280 busy_cursor_grab_motion,
1281 busy_cursor_grab_button,
1282};
1283
1284static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001285set_busy_cursor(struct shell_surface *shsurf, struct weston_pointer *pointer)
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001286{
1287 struct shell_grab *grab;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001288
1289 grab = malloc(sizeof *grab);
1290 if (!grab)
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001291 return;
1292
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001293 shell_grab_start(grab, &busy_cursor_grab_interface, shsurf, pointer,
1294 DESKTOP_SHELL_CURSOR_BUSY);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001295}
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001296
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001297static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001298end_busy_cursor(struct shell_surface *shsurf, struct weston_pointer *pointer)
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001299{
1300 struct shell_grab *grab = (struct shell_grab *) pointer->grab;
1301
1302 if (grab->grab.interface == &busy_cursor_grab_interface) {
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001303 shell_grab_end(grab);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001304 free(grab);
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001305 }
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001306}
1307
Scott Moreau9521d5e2012-04-19 13:06:17 -06001308static void
1309ping_timer_destroy(struct shell_surface *shsurf)
1310{
1311 if (!shsurf || !shsurf->ping_timer)
1312 return;
1313
1314 if (shsurf->ping_timer->source)
1315 wl_event_source_remove(shsurf->ping_timer->source);
1316
1317 free(shsurf->ping_timer);
1318 shsurf->ping_timer = NULL;
1319}
1320
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001321static int
Scott Moreauff1db4a2012-04-17 19:06:18 -06001322ping_timeout_handler(void *data)
1323{
1324 struct shell_surface *shsurf = data;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001325 struct weston_seat *seat;
Scott Moreauff1db4a2012-04-17 19:06:18 -06001326
Scott Moreau9521d5e2012-04-19 13:06:17 -06001327 /* Client is not responding */
1328 shsurf->unresponsive = 1;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001329
1330 wl_list_for_each(seat, &shsurf->surface->compositor->seat_list, link)
1331 if (seat->seat.pointer->focus == &shsurf->surface->surface)
1332 set_busy_cursor(shsurf, seat->seat.pointer);
Scott Moreauff1db4a2012-04-17 19:06:18 -06001333
1334 return 1;
1335}
1336
1337static void
1338ping_handler(struct weston_surface *surface, uint32_t serial)
1339{
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001340 struct shell_surface *shsurf = get_shell_surface(surface);
Scott Moreauff1db4a2012-04-17 19:06:18 -06001341 struct wl_event_loop *loop;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001342 int ping_timeout = 200;
Scott Moreauff1db4a2012-04-17 19:06:18 -06001343
1344 if (!shsurf)
1345 return;
Kristian Høgsbergca535c12012-04-21 23:20:07 -04001346 if (!shsurf->resource.client)
1347 return;
Scott Moreauff1db4a2012-04-17 19:06:18 -06001348
Ander Conselvan de Oliveiraeac9a462012-07-16 14:15:48 +03001349 if (shsurf->surface == shsurf->shell->grab_surface)
1350 return;
1351
Scott Moreauff1db4a2012-04-17 19:06:18 -06001352 if (!shsurf->ping_timer) {
Ander Conselvan de Oliveirafb980892012-04-27 13:55:55 +03001353 shsurf->ping_timer = malloc(sizeof *shsurf->ping_timer);
Scott Moreauff1db4a2012-04-17 19:06:18 -06001354 if (!shsurf->ping_timer)
1355 return;
1356
1357 shsurf->ping_timer->serial = serial;
Scott Moreauff1db4a2012-04-17 19:06:18 -06001358 loop = wl_display_get_event_loop(surface->compositor->wl_display);
1359 shsurf->ping_timer->source =
1360 wl_event_loop_add_timer(loop, ping_timeout_handler, shsurf);
1361 wl_event_source_timer_update(shsurf->ping_timer->source, ping_timeout);
1362
1363 wl_shell_surface_send_ping(&shsurf->resource, serial);
1364 }
1365}
1366
1367static void
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001368handle_pointer_focus(struct wl_listener *listener, void *data)
1369{
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001370 struct weston_pointer *pointer = data;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001371 struct weston_surface *surface =
1372 (struct weston_surface *) pointer->focus;
1373 struct weston_compositor *compositor;
1374 struct shell_surface *shsurf;
1375 uint32_t serial;
1376
1377 if (!surface)
1378 return;
1379
1380 compositor = surface->compositor;
1381 shsurf = get_shell_surface(surface);
1382
Pekka Paalanen4e1f2ff2012-06-06 16:59:45 +03001383 if (shsurf && shsurf->unresponsive) {
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001384 set_busy_cursor(shsurf, pointer);
1385 } else {
1386 serial = wl_display_next_serial(compositor->wl_display);
1387 ping_handler(surface, serial);
1388 }
1389}
1390
1391static void
Kristian Høgsbergf4d2f232012-08-10 10:05:39 -04001392create_pointer_focus_listener(struct weston_seat *seat)
1393{
1394 struct wl_listener *listener;
1395
1396 if (!seat->seat.pointer)
1397 return;
1398
1399 listener = malloc(sizeof *listener);
1400 listener->notify = handle_pointer_focus;
1401 wl_signal_add(&seat->seat.pointer->focus_signal, listener);
1402}
1403
1404static void
Scott Moreauff1db4a2012-04-17 19:06:18 -06001405shell_surface_pong(struct wl_client *client, struct wl_resource *resource,
1406 uint32_t serial)
1407{
1408 struct shell_surface *shsurf = resource->data;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001409 struct desktop_shell *shell = shsurf->shell;
1410 struct weston_seat *seat;
1411 struct weston_compositor *ec = shsurf->surface->compositor;
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001412 struct weston_pointer *pointer;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001413 int was_unresponsive;
Scott Moreauff1db4a2012-04-17 19:06:18 -06001414
Kristian Høgsberg92374e12012-08-11 22:39:12 -04001415 if (shsurf->ping_timer == NULL)
1416 /* Just ignore unsolicited pong. */
1417 return;
1418
Scott Moreauff1db4a2012-04-17 19:06:18 -06001419 if (shsurf->ping_timer->serial == serial) {
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001420 was_unresponsive = shsurf->unresponsive;
Scott Moreauff1db4a2012-04-17 19:06:18 -06001421 shsurf->unresponsive = 0;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001422 if (was_unresponsive) {
1423 /* Received pong from previously unresponsive client */
1424 wl_list_for_each(seat, &ec->seat_list, link) {
1425 pointer = seat->seat.pointer;
1426 if (pointer->focus ==
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001427 &shell->grab_surface->surface &&
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001428 pointer->current ==
1429 &shsurf->surface->surface)
1430 end_busy_cursor(shsurf, pointer);
1431 }
1432 }
Scott Moreau9521d5e2012-04-19 13:06:17 -06001433 ping_timer_destroy(shsurf);
Scott Moreauff1db4a2012-04-17 19:06:18 -06001434 }
1435}
1436
Kristian Høgsberge7afd912012-05-02 09:47:44 -04001437static void
1438shell_surface_set_title(struct wl_client *client,
1439 struct wl_resource *resource, const char *title)
1440{
1441 struct shell_surface *shsurf = resource->data;
1442
1443 free(shsurf->title);
1444 shsurf->title = strdup(title);
1445}
1446
1447static void
1448shell_surface_set_class(struct wl_client *client,
1449 struct wl_resource *resource, const char *class)
1450{
1451 struct shell_surface *shsurf = resource->data;
1452
1453 free(shsurf->class);
1454 shsurf->class = strdup(class);
1455}
1456
Juan Zhao96879df2012-02-07 08:45:41 +08001457static struct weston_output *
1458get_default_output(struct weston_compositor *compositor)
1459{
1460 return container_of(compositor->output_list.next,
1461 struct weston_output, link);
1462}
1463
Alex Wu4539b082012-03-01 12:57:46 +08001464static void
1465shell_unset_fullscreen(struct shell_surface *shsurf)
1466{
Rafal Mielniczuk3e3862c2012-10-07 20:25:36 +02001467 struct workspace *ws;
Alex Wu4539b082012-03-01 12:57:46 +08001468 /* undo all fullscreen things here */
Alex Wubd3354b2012-04-17 17:20:49 +08001469 if (shsurf->fullscreen.type == WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER &&
1470 shell_surface_is_top_fullscreen(shsurf)) {
1471 weston_output_switch_mode(shsurf->fullscreen_output,
1472 shsurf->fullscreen_output->origin);
1473 }
Alex Wu4539b082012-03-01 12:57:46 +08001474 shsurf->fullscreen.type = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT;
1475 shsurf->fullscreen.framerate = 0;
1476 wl_list_remove(&shsurf->fullscreen.transform.link);
1477 wl_list_init(&shsurf->fullscreen.transform.link);
Alex Wubd3354b2012-04-17 17:20:49 +08001478 if (shsurf->fullscreen.black_surface)
1479 weston_surface_destroy(shsurf->fullscreen.black_surface);
Alex Wu4539b082012-03-01 12:57:46 +08001480 shsurf->fullscreen.black_surface = NULL;
1481 shsurf->fullscreen_output = NULL;
Alex Wu4539b082012-03-01 12:57:46 +08001482 weston_surface_set_position(shsurf->surface,
1483 shsurf->saved_x, shsurf->saved_y);
Alex Wu7bcb8bd2012-04-27 09:07:24 +08001484 if (shsurf->saved_rotation_valid) {
1485 wl_list_insert(&shsurf->surface->geometry.transformation_list,
1486 &shsurf->rotation.transform.link);
1487 shsurf->saved_rotation_valid = false;
1488 }
Rafal Mielniczuk3e3862c2012-10-07 20:25:36 +02001489
1490 ws = get_current_workspace(shsurf->shell);
1491 wl_list_remove(&shsurf->surface->layer_link);
1492 wl_list_insert(&ws->layer.surface_list, &shsurf->surface->layer_link);
Alex Wu4539b082012-03-01 12:57:46 +08001493}
1494
Rafal Mielniczukfffdcdd2013-03-11 19:26:54 +01001495static void
1496shell_unset_maximized(struct shell_surface *shsurf)
1497{
1498 struct workspace *ws;
1499 /* undo all maximized things here */
1500 shsurf->output = get_default_output(shsurf->surface->compositor);
1501 weston_surface_set_position(shsurf->surface,
1502 shsurf->saved_x,
1503 shsurf->saved_y);
1504
1505 if (shsurf->saved_rotation_valid) {
1506 wl_list_insert(&shsurf->surface->geometry.transformation_list,
1507 &shsurf->rotation.transform.link);
1508 shsurf->saved_rotation_valid = false;
1509 }
1510
1511 ws = get_current_workspace(shsurf->shell);
1512 wl_list_remove(&shsurf->surface->layer_link);
1513 wl_list_insert(&ws->layer.surface_list, &shsurf->surface->layer_link);
1514}
1515
Pekka Paalanen98262232011-12-01 10:42:22 +02001516static int
1517reset_shell_surface_type(struct shell_surface *surface)
1518{
1519 switch (surface->type) {
1520 case SHELL_SURFACE_FULLSCREEN:
Alex Wu4539b082012-03-01 12:57:46 +08001521 shell_unset_fullscreen(surface);
Pekka Paalanen98262232011-12-01 10:42:22 +02001522 break;
Juan Zhao96879df2012-02-07 08:45:41 +08001523 case SHELL_SURFACE_MAXIMIZED:
Rafal Mielniczukfffdcdd2013-03-11 19:26:54 +01001524 shell_unset_maximized(surface);
Juan Zhao96879df2012-02-07 08:45:41 +08001525 break;
Pekka Paalanen98262232011-12-01 10:42:22 +02001526 case SHELL_SURFACE_NONE:
1527 case SHELL_SURFACE_TOPLEVEL:
1528 case SHELL_SURFACE_TRANSIENT:
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001529 case SHELL_SURFACE_POPUP:
Pekka Paalanen98262232011-12-01 10:42:22 +02001530 break;
1531 }
1532
1533 surface->type = SHELL_SURFACE_NONE;
1534 return 0;
1535}
1536
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001537static void
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001538set_surface_type(struct shell_surface *shsurf)
1539{
1540 struct weston_surface *surface = shsurf->surface;
Kristian Høgsberg8150b192012-06-27 10:22:58 -04001541 struct weston_surface *pes = shsurf->parent;
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001542
1543 reset_shell_surface_type(shsurf);
1544
1545 shsurf->type = shsurf->next_type;
1546 shsurf->next_type = SHELL_SURFACE_NONE;
1547
1548 switch (shsurf->type) {
1549 case SHELL_SURFACE_TOPLEVEL:
1550 break;
1551 case SHELL_SURFACE_TRANSIENT:
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001552 weston_surface_set_position(surface,
Tiago Vignatti52e598c2012-05-07 15:23:08 +03001553 pes->geometry.x + shsurf->transient.x,
1554 pes->geometry.y + shsurf->transient.y);
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001555 break;
1556
1557 case SHELL_SURFACE_MAXIMIZED:
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001558 case SHELL_SURFACE_FULLSCREEN:
1559 shsurf->saved_x = surface->geometry.x;
1560 shsurf->saved_y = surface->geometry.y;
1561 shsurf->saved_position_valid = true;
1562
1563 if (!wl_list_empty(&shsurf->rotation.transform.link)) {
1564 wl_list_remove(&shsurf->rotation.transform.link);
1565 wl_list_init(&shsurf->rotation.transform.link);
Pekka Paalanenc3ce7382013-03-08 14:56:49 +02001566 weston_surface_geometry_dirty(shsurf->surface);
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001567 shsurf->saved_rotation_valid = true;
1568 }
1569 break;
1570
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001571 default:
1572 break;
1573 }
1574}
1575
1576static void
Tiago Vignattibc052c92012-04-19 16:18:18 +03001577set_toplevel(struct shell_surface *shsurf)
1578{
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001579 shsurf->next_type = SHELL_SURFACE_TOPLEVEL;
Tiago Vignattibc052c92012-04-19 16:18:18 +03001580}
1581
1582static void
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001583shell_surface_set_toplevel(struct wl_client *client,
1584 struct wl_resource *resource)
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001585{
Pekka Paalanen98262232011-12-01 10:42:22 +02001586 struct shell_surface *surface = resource->data;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001587
Tiago Vignattibc052c92012-04-19 16:18:18 +03001588 set_toplevel(surface);
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001589}
1590
1591static void
Tiago Vignatti491bac12012-05-18 16:37:43 -04001592set_transient(struct shell_surface *shsurf,
Kristian Høgsberg8150b192012-06-27 10:22:58 -04001593 struct weston_surface *parent, int x, int y, uint32_t flags)
Tiago Vignatti491bac12012-05-18 16:37:43 -04001594{
1595 /* assign to parents output */
Kristian Høgsberg8150b192012-06-27 10:22:58 -04001596 shsurf->parent = parent;
Tiago Vignatti491bac12012-05-18 16:37:43 -04001597 shsurf->transient.x = x;
1598 shsurf->transient.y = y;
1599 shsurf->transient.flags = flags;
1600 shsurf->next_type = SHELL_SURFACE_TRANSIENT;
1601}
1602
1603static void
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001604shell_surface_set_transient(struct wl_client *client,
1605 struct wl_resource *resource,
1606 struct wl_resource *parent_resource,
1607 int x, int y, uint32_t flags)
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001608{
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001609 struct shell_surface *shsurf = resource->data;
Kristian Høgsberg8150b192012-06-27 10:22:58 -04001610 struct weston_surface *parent = parent_resource->data;
Pekka Paalanen98262232011-12-01 10:42:22 +02001611
Kristian Høgsberg8150b192012-06-27 10:22:58 -04001612 set_transient(shsurf, parent, x, y, flags);
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001613}
1614
Tiago Vignattibe143262012-04-16 17:31:41 +03001615static struct desktop_shell *
Juan Zhao96879df2012-02-07 08:45:41 +08001616shell_surface_get_shell(struct shell_surface *shsurf)
Pekka Paalanenaf0e34c2011-12-02 10:59:17 +02001617{
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04001618 return shsurf->shell;
Juan Zhao96879df2012-02-07 08:45:41 +08001619}
1620
1621static int
Tiago Vignattibe143262012-04-16 17:31:41 +03001622get_output_panel_height(struct desktop_shell *shell,
1623 struct weston_output *output)
Juan Zhao96879df2012-02-07 08:45:41 +08001624{
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001625 struct weston_surface *surface;
Juan Zhao96879df2012-02-07 08:45:41 +08001626 int panel_height = 0;
1627
1628 if (!output)
1629 return 0;
1630
Juan Zhao4ab94682012-07-09 22:24:09 -07001631 wl_list_for_each(surface, &shell->panel_layer.surface_list, layer_link) {
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001632 if (surface->output == output) {
1633 panel_height = surface->geometry.height;
Juan Zhao96879df2012-02-07 08:45:41 +08001634 break;
1635 }
1636 }
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001637
Juan Zhao96879df2012-02-07 08:45:41 +08001638 return panel_height;
1639}
1640
1641static void
1642shell_surface_set_maximized(struct wl_client *client,
1643 struct wl_resource *resource,
1644 struct wl_resource *output_resource )
1645{
1646 struct shell_surface *shsurf = resource->data;
1647 struct weston_surface *es = shsurf->surface;
Tiago Vignattibe143262012-04-16 17:31:41 +03001648 struct desktop_shell *shell = NULL;
Juan Zhao96879df2012-02-07 08:45:41 +08001649 uint32_t edges = 0, panel_height = 0;
1650
1651 /* get the default output, if the client set it as NULL
1652 check whether the ouput is available */
1653 if (output_resource)
1654 shsurf->output = output_resource->data;
Kristian Høgsberg94de6802012-07-18 09:54:04 -04001655 else if (es->output)
1656 shsurf->output = es->output;
Juan Zhao96879df2012-02-07 08:45:41 +08001657 else
1658 shsurf->output = get_default_output(es->compositor);
1659
Tiago Vignattibe143262012-04-16 17:31:41 +03001660 shell = shell_surface_get_shell(shsurf);
Rob Bradford31b68622012-07-02 19:00:19 +01001661 panel_height = get_output_panel_height(shell, shsurf->output);
Juan Zhao96879df2012-02-07 08:45:41 +08001662 edges = WL_SHELL_SURFACE_RESIZE_TOP|WL_SHELL_SURFACE_RESIZE_LEFT;
Kristian Høgsberg0b5cd0c2012-03-04 21:57:37 -05001663
Kristian Høgsberga61ca062012-05-22 16:05:52 -04001664 shsurf->client->send_configure(shsurf->surface, edges,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001665 shsurf->output->width,
1666 shsurf->output->height - panel_height);
Juan Zhao96879df2012-02-07 08:45:41 +08001667
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001668 shsurf->next_type = SHELL_SURFACE_MAXIMIZED;
Pekka Paalanenaf0e34c2011-12-02 10:59:17 +02001669}
1670
Alex Wu21858432012-04-01 20:13:08 +08001671static void
Giulio Camuffo184df502013-02-21 11:29:21 +01001672black_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy, int32_t width, int32_t height);
Alex Wu21858432012-04-01 20:13:08 +08001673
Alex Wu4539b082012-03-01 12:57:46 +08001674static struct weston_surface *
1675create_black_surface(struct weston_compositor *ec,
Alex Wu21858432012-04-01 20:13:08 +08001676 struct weston_surface *fs_surface,
John Kåre Alsaker490d02a2012-09-30 02:57:21 +02001677 float x, float y, int w, int h)
Alex Wu4539b082012-03-01 12:57:46 +08001678{
1679 struct weston_surface *surface = NULL;
1680
1681 surface = weston_surface_create(ec);
1682 if (surface == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001683 weston_log("no memory\n");
Alex Wu4539b082012-03-01 12:57:46 +08001684 return NULL;
1685 }
1686
Alex Wu21858432012-04-01 20:13:08 +08001687 surface->configure = black_surface_configure;
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01001688 surface->configure_private = fs_surface;
Alex Wu4539b082012-03-01 12:57:46 +08001689 weston_surface_configure(surface, x, y, w, h);
1690 weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1);
Pekka Paalanen71f6f3b2012-10-10 12:49:26 +03001691 pixman_region32_fini(&surface->opaque);
Kristian Høgsberg61f00f52012-08-03 16:31:36 -04001692 pixman_region32_init_rect(&surface->opaque, 0, 0, w, h);
Jonas Ådahl33619a42013-01-15 21:25:55 +01001693 pixman_region32_fini(&surface->input);
1694 pixman_region32_init_rect(&surface->input, 0, 0, w, h);
Kristian Høgsberg61f00f52012-08-03 16:31:36 -04001695
Alex Wu4539b082012-03-01 12:57:46 +08001696 return surface;
1697}
1698
1699/* Create black surface and append it to the associated fullscreen surface.
1700 * Handle size dismatch and positioning according to the method. */
1701static void
1702shell_configure_fullscreen(struct shell_surface *shsurf)
1703{
1704 struct weston_output *output = shsurf->fullscreen_output;
1705 struct weston_surface *surface = shsurf->surface;
1706 struct weston_matrix *matrix;
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04001707 float scale, output_aspect, surface_aspect, x, y;
Alex Wu4539b082012-03-01 12:57:46 +08001708
Alex Wu4539b082012-03-01 12:57:46 +08001709 if (!shsurf->fullscreen.black_surface)
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05001710 shsurf->fullscreen.black_surface =
1711 create_black_surface(surface->compositor,
Alex Wu21858432012-04-01 20:13:08 +08001712 surface,
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05001713 output->x, output->y,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001714 output->width,
1715 output->height);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05001716
1717 wl_list_remove(&shsurf->fullscreen.black_surface->layer_link);
1718 wl_list_insert(&surface->layer_link,
1719 &shsurf->fullscreen.black_surface->layer_link);
Alex Wu4539b082012-03-01 12:57:46 +08001720 shsurf->fullscreen.black_surface->output = output;
1721
1722 switch (shsurf->fullscreen.type) {
1723 case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT:
Pekka Paalanende685b82012-12-04 15:58:12 +02001724 if (surface->buffer_ref.buffer)
Kristian Høgsberga08b5282012-07-20 15:30:36 -04001725 center_on_output(surface, shsurf->fullscreen_output);
Alex Wu4539b082012-03-01 12:57:46 +08001726 break;
1727 case WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE:
Rob Bradford9f3dd152013-02-12 11:53:47 +00001728 /* 1:1 mapping between surface and output dimensions */
1729 if (output->width == surface->geometry.width &&
1730 output->height == surface->geometry.height) {
1731 weston_surface_set_position(surface, output->x, output->y);
1732 break;
1733 }
1734
Alex Wu4539b082012-03-01 12:57:46 +08001735 matrix = &shsurf->fullscreen.transform.matrix;
1736 weston_matrix_init(matrix);
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04001737
Scott Moreau1bad5db2012-08-18 01:04:05 -06001738 output_aspect = (float) output->width /
1739 (float) output->height;
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04001740 surface_aspect = (float) surface->geometry.width /
1741 (float) surface->geometry.height;
1742 if (output_aspect < surface_aspect)
Scott Moreau1bad5db2012-08-18 01:04:05 -06001743 scale = (float) output->width /
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04001744 (float) surface->geometry.width;
1745 else
Scott Moreau1bad5db2012-08-18 01:04:05 -06001746 scale = (float) output->height /
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04001747 (float) surface->geometry.height;
1748
Alex Wu4539b082012-03-01 12:57:46 +08001749 weston_matrix_scale(matrix, scale, scale, 1);
1750 wl_list_remove(&shsurf->fullscreen.transform.link);
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04001751 wl_list_insert(&surface->geometry.transformation_list,
Alex Wu4539b082012-03-01 12:57:46 +08001752 &shsurf->fullscreen.transform.link);
Scott Moreau1bad5db2012-08-18 01:04:05 -06001753 x = output->x + (output->width - surface->geometry.width * scale) / 2;
1754 y = output->y + (output->height - surface->geometry.height * scale) / 2;
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04001755 weston_surface_set_position(surface, x, y);
1756
Alex Wu4539b082012-03-01 12:57:46 +08001757 break;
1758 case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER:
Alex Wubd3354b2012-04-17 17:20:49 +08001759 if (shell_surface_is_top_fullscreen(shsurf)) {
Quentin Glidicc0d79ce2013-01-29 14:16:13 +01001760 struct weston_mode mode = {0,
Alex Wubd3354b2012-04-17 17:20:49 +08001761 surface->geometry.width,
1762 surface->geometry.height,
1763 shsurf->fullscreen.framerate};
1764
1765 if (weston_output_switch_mode(output, &mode) == 0) {
Quentin Glidicc0d79ce2013-01-29 14:16:13 +01001766 weston_surface_configure(shsurf->fullscreen.black_surface,
Alex Wubd3354b2012-04-17 17:20:49 +08001767 output->x, output->y,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001768 output->width,
1769 output->height);
Alex Wubd3354b2012-04-17 17:20:49 +08001770 weston_surface_set_position(surface, output->x, output->y);
1771 break;
1772 }
1773 }
Alex Wu4539b082012-03-01 12:57:46 +08001774 break;
1775 case WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL:
1776 break;
1777 default:
1778 break;
1779 }
1780}
1781
1782/* make the fullscreen and black surface at the top */
1783static void
1784shell_stack_fullscreen(struct shell_surface *shsurf)
1785{
Alex Wubd3354b2012-04-17 17:20:49 +08001786 struct weston_output *output = shsurf->fullscreen_output;
Alex Wu4539b082012-03-01 12:57:46 +08001787 struct weston_surface *surface = shsurf->surface;
Tiago Vignattibe143262012-04-16 17:31:41 +03001788 struct desktop_shell *shell = shell_surface_get_shell(shsurf);
Alex Wu4539b082012-03-01 12:57:46 +08001789
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05001790 wl_list_remove(&surface->layer_link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05001791 wl_list_insert(&shell->fullscreen_layer.surface_list,
1792 &surface->layer_link);
Alex Wubd3354b2012-04-17 17:20:49 +08001793 weston_surface_damage(surface);
1794
1795 if (!shsurf->fullscreen.black_surface)
1796 shsurf->fullscreen.black_surface =
1797 create_black_surface(surface->compositor,
1798 surface,
1799 output->x, output->y,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001800 output->width,
1801 output->height);
Alex Wubd3354b2012-04-17 17:20:49 +08001802
1803 wl_list_remove(&shsurf->fullscreen.black_surface->layer_link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05001804 wl_list_insert(&surface->layer_link,
1805 &shsurf->fullscreen.black_surface->layer_link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05001806 weston_surface_damage(shsurf->fullscreen.black_surface);
Alex Wu4539b082012-03-01 12:57:46 +08001807}
1808
1809static void
1810shell_map_fullscreen(struct shell_surface *shsurf)
1811{
Alex Wu4539b082012-03-01 12:57:46 +08001812 shell_stack_fullscreen(shsurf);
Alex Wubd3354b2012-04-17 17:20:49 +08001813 shell_configure_fullscreen(shsurf);
Alex Wu4539b082012-03-01 12:57:46 +08001814}
1815
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001816static void
Kristian Høgsbergb810eb52013-02-12 20:07:05 -05001817set_fullscreen(struct shell_surface *shsurf,
1818 uint32_t method,
1819 uint32_t framerate,
1820 struct weston_output *output)
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001821{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001822 struct weston_surface *es = shsurf->surface;
Alex Wu4539b082012-03-01 12:57:46 +08001823
Kristian Høgsbergb810eb52013-02-12 20:07:05 -05001824 if (output)
1825 shsurf->output = output;
Kristian Høgsberg94de6802012-07-18 09:54:04 -04001826 else if (es->output)
1827 shsurf->output = es->output;
Alex Wu4539b082012-03-01 12:57:46 +08001828 else
1829 shsurf->output = get_default_output(es->compositor);
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001830
Alex Wu4539b082012-03-01 12:57:46 +08001831 shsurf->fullscreen_output = shsurf->output;
1832 shsurf->fullscreen.type = method;
1833 shsurf->fullscreen.framerate = framerate;
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001834 shsurf->next_type = SHELL_SURFACE_FULLSCREEN;
Alex Wu4539b082012-03-01 12:57:46 +08001835
Kristian Høgsberga61ca062012-05-22 16:05:52 -04001836 shsurf->client->send_configure(shsurf->surface, 0,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001837 shsurf->output->width,
1838 shsurf->output->height);
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001839}
1840
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001841static void
Kristian Høgsbergb810eb52013-02-12 20:07:05 -05001842shell_surface_set_fullscreen(struct wl_client *client,
1843 struct wl_resource *resource,
1844 uint32_t method,
1845 uint32_t framerate,
1846 struct wl_resource *output_resource)
1847{
1848 struct shell_surface *shsurf = resource->data;
1849 struct weston_output *output;
1850
1851 if (output_resource)
1852 output = output_resource->data;
1853 else
1854 output = NULL;
1855
1856 set_fullscreen(shsurf, method, framerate, output);
1857}
1858
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001859static const struct weston_pointer_grab_interface popup_grab_interface;
Giulio Camuffo5085a752013-03-25 21:42:45 +01001860
1861static void
1862destroy_shell_seat(struct wl_listener *listener, void *data)
1863{
1864 struct shell_seat *shseat =
1865 container_of(listener,
1866 struct shell_seat, seat_destroy_listener);
1867 struct shell_surface *shsurf, *prev = NULL;
1868
1869 if (shseat->popup_grab.grab.interface == &popup_grab_interface) {
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001870 weston_pointer_end_grab(shseat->popup_grab.grab.pointer);
Giulio Camuffo5085a752013-03-25 21:42:45 +01001871 shseat->popup_grab.client = NULL;
1872
1873 wl_list_for_each(shsurf, &shseat->popup_grab.surfaces_list, popup.grab_link) {
1874 shsurf->popup.shseat = NULL;
1875 if (prev) {
1876 wl_list_init(&prev->popup.grab_link);
1877 }
1878 prev = shsurf;
1879 }
1880 wl_list_init(&prev->popup.grab_link);
1881 }
1882
1883 wl_list_remove(&shseat->seat_destroy_listener.link);
1884 free(shseat);
1885}
1886
1887static struct shell_seat *
1888create_shell_seat(struct weston_seat *seat)
1889{
1890 struct shell_seat *shseat;
1891
1892 shseat = calloc(1, sizeof *shseat);
1893 if (!shseat) {
1894 weston_log("no memory to allocate shell seat\n");
1895 return NULL;
1896 }
1897
1898 shseat->seat = seat;
1899 wl_list_init(&shseat->popup_grab.surfaces_list);
1900
1901 shseat->seat_destroy_listener.notify = destroy_shell_seat;
1902 wl_signal_add(&seat->destroy_signal,
1903 &shseat->seat_destroy_listener);
1904
1905 return shseat;
1906}
1907
1908static struct shell_seat *
1909get_shell_seat(struct weston_seat *seat)
1910{
1911 struct wl_listener *listener;
1912
1913 listener = wl_signal_get(&seat->destroy_signal, destroy_shell_seat);
1914 if (listener == NULL)
1915 return create_shell_seat(seat);
1916
1917 return container_of(listener,
1918 struct shell_seat, seat_destroy_listener);
1919}
1920
Kristian Høgsbergb810eb52013-02-12 20:07:05 -05001921static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001922popup_grab_focus(struct weston_pointer_grab *grab,
Daniel Stone103db7f2012-05-08 17:17:55 +01001923 struct wl_surface *surface,
1924 wl_fixed_t x,
1925 wl_fixed_t y)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001926{
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001927 struct weston_pointer *pointer = grab->pointer;
Giulio Camuffo5085a752013-03-25 21:42:45 +01001928 struct shell_seat *shseat =
1929 container_of(grab, struct shell_seat, popup_grab.grab);
1930 struct wl_client *client = shseat->popup_grab.client;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001931
Pekka Paalanencb108432012-01-19 16:25:40 +02001932 if (surface && surface->resource.client == client) {
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001933 weston_pointer_set_focus(pointer, surface, x, y);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001934 grab->focus = surface;
1935 } else {
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001936 weston_pointer_set_focus(pointer, NULL,
1937 wl_fixed_from_int(0),
1938 wl_fixed_from_int(0));
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001939 grab->focus = NULL;
1940 }
1941}
1942
1943static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001944popup_grab_motion(struct weston_pointer_grab *grab,
Daniel Stone103db7f2012-05-08 17:17:55 +01001945 uint32_t time, wl_fixed_t sx, wl_fixed_t sy)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001946{
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001947 struct wl_resource *resource;
1948
Daniel Stone37816df2012-05-16 18:45:18 +01001949 resource = grab->pointer->focus_resource;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001950 if (resource)
Daniel Stone37816df2012-05-16 18:45:18 +01001951 wl_pointer_send_motion(resource, time, sx, sy);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001952}
1953
1954static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001955popup_grab_button(struct weston_pointer_grab *grab,
Daniel Stone4dbadb12012-05-30 16:31:51 +01001956 uint32_t time, uint32_t button, uint32_t state_w)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001957{
1958 struct wl_resource *resource;
Giulio Camuffo5085a752013-03-25 21:42:45 +01001959 struct shell_seat *shseat =
1960 container_of(grab, struct shell_seat, popup_grab.grab);
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001961 struct wl_display *display;
Daniel Stone4dbadb12012-05-30 16:31:51 +01001962 enum wl_pointer_button_state state = state_w;
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001963 uint32_t serial;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001964
Daniel Stone37816df2012-05-16 18:45:18 +01001965 resource = grab->pointer->focus_resource;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001966 if (resource) {
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001967 display = wl_client_get_display(resource->client);
1968 serial = wl_display_get_serial(display);
Daniel Stone37816df2012-05-16 18:45:18 +01001969 wl_pointer_send_button(resource, serial, time, button, state);
Daniel Stone4dbadb12012-05-30 16:31:51 +01001970 } else if (state == WL_POINTER_BUTTON_STATE_RELEASED &&
Giulio Camuffo5085a752013-03-25 21:42:45 +01001971 (shseat->popup_grab.initial_up ||
1972 time - shseat->seat->pointer.grab_time > 500)) {
Kristian Høgsberg57e09072012-10-30 14:07:27 -04001973 popup_grab_end(grab->pointer);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001974 }
1975
Daniel Stone4dbadb12012-05-30 16:31:51 +01001976 if (state == WL_POINTER_BUTTON_STATE_RELEASED)
Giulio Camuffo5085a752013-03-25 21:42:45 +01001977 shseat->popup_grab.initial_up = 1;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001978}
1979
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001980static const struct weston_pointer_grab_interface popup_grab_interface = {
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001981 popup_grab_focus,
1982 popup_grab_motion,
1983 popup_grab_button,
1984};
1985
1986static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001987popup_grab_end(struct weston_pointer *pointer)
Kristian Høgsberg57e09072012-10-30 14:07:27 -04001988{
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001989 struct weston_pointer_grab *grab = pointer->grab;
Giulio Camuffo5085a752013-03-25 21:42:45 +01001990 struct shell_seat *shseat =
1991 container_of(grab, struct shell_seat, popup_grab.grab);
1992 struct shell_surface *shsurf;
1993 struct shell_surface *prev = NULL;
Kristian Høgsberg57e09072012-10-30 14:07:27 -04001994
1995 if (pointer->grab->interface == &popup_grab_interface) {
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04001996 weston_pointer_end_grab(grab->pointer);
Giulio Camuffo5085a752013-03-25 21:42:45 +01001997 shseat->popup_grab.client = NULL;
Philipp Brüschweiler63e7be62013-04-15 21:09:54 +02001998 shseat->popup_grab.grab.interface = NULL;
1999 assert(!wl_list_empty(&shseat->popup_grab.surfaces_list));
Giulio Camuffo5085a752013-03-25 21:42:45 +01002000 /* Send the popup_done event to all the popups open */
2001 wl_list_for_each(shsurf, &shseat->popup_grab.surfaces_list, popup.grab_link) {
2002 wl_shell_surface_send_popup_done(&shsurf->resource);
2003 shsurf->popup.shseat = NULL;
2004 if (prev) {
2005 wl_list_init(&prev->popup.grab_link);
2006 }
2007 prev = shsurf;
2008 }
2009 wl_list_init(&prev->popup.grab_link);
2010 wl_list_init(&shseat->popup_grab.surfaces_list);
2011 }
2012}
2013
2014static void
2015add_popup_grab(struct shell_surface *shsurf, struct shell_seat *shseat)
2016{
2017 struct wl_seat *seat = &shseat->seat->seat;
2018
2019 if (wl_list_empty(&shseat->popup_grab.surfaces_list)) {
2020 shseat->popup_grab.client = shsurf->surface->surface.resource.client;
2021 shseat->popup_grab.grab.interface = &popup_grab_interface;
Giulio Camuffo1b4b61a2013-03-27 18:05:26 +01002022 /* We must make sure here that this popup was opened after
2023 * a mouse press, and not just by moving around with other
2024 * popups already open. */
2025 if (shseat->seat->pointer.button_count > 0)
2026 shseat->popup_grab.initial_up = 0;
Giulio Camuffo5085a752013-03-25 21:42:45 +01002027
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04002028 weston_pointer_start_grab(seat->pointer, &shseat->popup_grab.grab);
Giulio Camuffo5085a752013-03-25 21:42:45 +01002029 }
2030 wl_list_insert(&shseat->popup_grab.surfaces_list, &shsurf->popup.grab_link);
2031}
2032
2033static void
2034remove_popup_grab(struct shell_surface *shsurf)
2035{
2036 struct shell_seat *shseat = shsurf->popup.shseat;
2037
2038 wl_list_remove(&shsurf->popup.grab_link);
2039 wl_list_init(&shsurf->popup.grab_link);
2040 if (wl_list_empty(&shseat->popup_grab.surfaces_list)) {
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04002041 weston_pointer_end_grab(shseat->popup_grab.grab.pointer);
Philipp Brüschweiler63e7be62013-04-15 21:09:54 +02002042 shseat->popup_grab.grab.interface = NULL;
Kristian Høgsberg57e09072012-10-30 14:07:27 -04002043 }
2044}
2045
2046static void
Kristian Høgsberg3730f362012-04-13 12:40:07 -04002047shell_map_popup(struct shell_surface *shsurf)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002048{
Giulio Camuffo5085a752013-03-25 21:42:45 +01002049 struct shell_seat *shseat = shsurf->popup.shseat;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002050 struct weston_surface *es = shsurf->surface;
Kristian Høgsberg8150b192012-06-27 10:22:58 -04002051 struct weston_surface *parent = shsurf->parent;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002052
2053 es->output = parent->output;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002054
Pekka Paalanen483243f2013-03-08 14:56:50 +02002055 weston_surface_set_transform_parent(es, parent);
Jonas Ådahlb0b87ba2012-09-27 18:40:42 +02002056 weston_surface_set_position(es, shsurf->popup.x, shsurf->popup.y);
2057 weston_surface_update_transform(es);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002058
Giulio Camuffo5085a752013-03-25 21:42:45 +01002059 if (shseat->seat->pointer.grab_serial == shsurf->popup.serial) {
2060 add_popup_grab(shsurf, shseat);
Kristian Høgsberg3730f362012-04-13 12:40:07 -04002061 } else {
2062 wl_shell_surface_send_popup_done(&shsurf->resource);
Giulio Camuffo5085a752013-03-25 21:42:45 +01002063 shseat->popup_grab.client = NULL;
Kristian Høgsberg3730f362012-04-13 12:40:07 -04002064 }
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002065}
2066
2067static void
2068shell_surface_set_popup(struct wl_client *client,
2069 struct wl_resource *resource,
Daniel Stone37816df2012-05-16 18:45:18 +01002070 struct wl_resource *seat_resource,
Kristian Høgsberg3730f362012-04-13 12:40:07 -04002071 uint32_t serial,
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002072 struct wl_resource *parent_resource,
2073 int32_t x, int32_t y, uint32_t flags)
2074{
2075 struct shell_surface *shsurf = resource->data;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002076
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002077 shsurf->type = SHELL_SURFACE_POPUP;
2078 shsurf->parent = parent_resource->data;
Giulio Camuffo5085a752013-03-25 21:42:45 +01002079 shsurf->popup.shseat = get_shell_seat(seat_resource->data);
Kristian Høgsberg3730f362012-04-13 12:40:07 -04002080 shsurf->popup.serial = serial;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002081 shsurf->popup.x = x;
2082 shsurf->popup.y = y;
2083}
2084
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002085static const struct wl_shell_surface_interface shell_surface_implementation = {
Scott Moreauff1db4a2012-04-17 19:06:18 -06002086 shell_surface_pong,
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002087 shell_surface_move,
2088 shell_surface_resize,
2089 shell_surface_set_toplevel,
2090 shell_surface_set_transient,
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002091 shell_surface_set_fullscreen,
Juan Zhao96879df2012-02-07 08:45:41 +08002092 shell_surface_set_popup,
Kristian Høgsberge7afd912012-05-02 09:47:44 -04002093 shell_surface_set_maximized,
2094 shell_surface_set_title,
2095 shell_surface_set_class
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002096};
2097
2098static void
Tiago Vignattibc052c92012-04-19 16:18:18 +03002099destroy_shell_surface(struct shell_surface *shsurf)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002100{
Giulio Camuffo5085a752013-03-25 21:42:45 +01002101 if (!wl_list_empty(&shsurf->popup.grab_link)) {
2102 remove_popup_grab(shsurf);
2103 }
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002104
Alex Wubd3354b2012-04-17 17:20:49 +08002105 if (shsurf->fullscreen.type == WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER &&
2106 shell_surface_is_top_fullscreen(shsurf)) {
2107 weston_output_switch_mode(shsurf->fullscreen_output,
2108 shsurf->fullscreen_output->origin);
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03002109 }
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002110
Alex Wuaa08e2d2012-03-05 11:01:40 +08002111 if (shsurf->fullscreen.black_surface)
2112 weston_surface_destroy(shsurf->fullscreen.black_surface);
2113
Alex Wubd3354b2012-04-17 17:20:49 +08002114 /* As destroy_resource() use wl_list_for_each_safe(),
2115 * we can always remove the listener.
2116 */
2117 wl_list_remove(&shsurf->surface_destroy_listener.link);
2118 shsurf->surface->configure = NULL;
Scott Moreau9521d5e2012-04-19 13:06:17 -06002119 ping_timer_destroy(shsurf);
Scott Moreau976a0502013-03-07 10:15:17 -07002120 free(shsurf->title);
Alex Wubd3354b2012-04-17 17:20:49 +08002121
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002122 wl_list_remove(&shsurf->link);
2123 free(shsurf);
2124}
2125
2126static void
Tiago Vignattibc052c92012-04-19 16:18:18 +03002127shell_destroy_shell_surface(struct wl_resource *resource)
2128{
2129 struct shell_surface *shsurf = resource->data;
2130
2131 destroy_shell_surface(shsurf);
2132}
2133
2134static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04002135shell_handle_surface_destroy(struct wl_listener *listener, void *data)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002136{
2137 struct shell_surface *shsurf = container_of(listener,
2138 struct shell_surface,
2139 surface_destroy_listener);
2140
Kristian Høgsberg633b1452012-06-07 18:08:47 -04002141 if (shsurf->resource.client) {
Tiago Vignattibc052c92012-04-19 16:18:18 +03002142 wl_resource_destroy(&shsurf->resource);
Kristian Høgsberg633b1452012-06-07 18:08:47 -04002143 } else {
2144 wl_signal_emit(&shsurf->resource.destroy_signal,
2145 &shsurf->resource);
Tiago Vignattibc052c92012-04-19 16:18:18 +03002146 destroy_shell_surface(shsurf);
Kristian Høgsberg633b1452012-06-07 18:08:47 -04002147 }
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002148}
2149
Kristian Høgsbergd8134452012-06-21 12:49:02 -04002150static void
Giulio Camuffo184df502013-02-21 11:29:21 +01002151shell_surface_configure(struct weston_surface *, int32_t, int32_t, int32_t, int32_t);
Kristian Høgsbergd8134452012-06-21 12:49:02 -04002152
Pekka Paalanenec2b32f2011-11-28 15:12:34 +02002153static struct shell_surface *
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002154get_shell_surface(struct weston_surface *surface)
Pekka Paalanenec2b32f2011-11-28 15:12:34 +02002155{
Kristian Høgsbergd8134452012-06-21 12:49:02 -04002156 if (surface->configure == shell_surface_configure)
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01002157 return surface->configure_private;
Kristian Høgsbergd8134452012-06-21 12:49:02 -04002158 else
2159 return NULL;
Pekka Paalanenec2b32f2011-11-28 15:12:34 +02002160}
2161
Kristian Høgsberg45ba8692012-05-21 14:27:33 -04002162static struct shell_surface *
Kristian Høgsberga61ca062012-05-22 16:05:52 -04002163create_shell_surface(void *shell, struct weston_surface *surface,
2164 const struct weston_shell_client *client)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002165{
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002166 struct shell_surface *shsurf;
2167
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03002168 if (surface->configure) {
Martin Minarik6d118362012-06-07 18:01:59 +02002169 weston_log("surface->configure already set\n");
Kristian Høgsberg45ba8692012-05-21 14:27:33 -04002170 return NULL;
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03002171 }
2172
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002173 shsurf = calloc(1, sizeof *shsurf);
2174 if (!shsurf) {
Martin Minarik6d118362012-06-07 18:01:59 +02002175 weston_log("no memory to allocate shell surface\n");
Kristian Høgsberg45ba8692012-05-21 14:27:33 -04002176 return NULL;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002177 }
2178
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03002179 surface->configure = shell_surface_configure;
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01002180 surface->configure_private = shsurf;
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03002181
Tiago Vignattibc052c92012-04-19 16:18:18 +03002182 shsurf->shell = (struct desktop_shell *) shell;
Scott Moreauff1db4a2012-04-17 19:06:18 -06002183 shsurf->unresponsive = 0;
Alex Wu4539b082012-03-01 12:57:46 +08002184 shsurf->saved_position_valid = false;
Alex Wu7bcb8bd2012-04-27 09:07:24 +08002185 shsurf->saved_rotation_valid = false;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002186 shsurf->surface = surface;
Alex Wu4539b082012-03-01 12:57:46 +08002187 shsurf->fullscreen.type = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT;
2188 shsurf->fullscreen.framerate = 0;
2189 shsurf->fullscreen.black_surface = NULL;
Scott Moreauff1db4a2012-04-17 19:06:18 -06002190 shsurf->ping_timer = NULL;
Alex Wu4539b082012-03-01 12:57:46 +08002191 wl_list_init(&shsurf->fullscreen.transform.link);
2192
Tiago Vignattibc052c92012-04-19 16:18:18 +03002193 wl_signal_init(&shsurf->resource.destroy_signal);
Kristian Høgsberg27e30522012-04-11 23:18:23 -04002194 shsurf->surface_destroy_listener.notify = shell_handle_surface_destroy;
2195 wl_signal_add(&surface->surface.resource.destroy_signal,
2196 &shsurf->surface_destroy_listener);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002197
2198 /* init link so its safe to always remove it in destroy_shell_surface */
2199 wl_list_init(&shsurf->link);
Giulio Camuffo5085a752013-03-25 21:42:45 +01002200 wl_list_init(&shsurf->popup.grab_link);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002201
Pekka Paalanen460099f2012-01-20 16:48:25 +02002202 /* empty when not in use */
2203 wl_list_init(&shsurf->rotation.transform.link);
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05002204 weston_matrix_init(&shsurf->rotation.rotation);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002205
Jonas Ådahl62fcd042012-06-13 00:01:23 +02002206 wl_list_init(&shsurf->workspace_transform.link);
2207
Pekka Paalanen98262232011-12-01 10:42:22 +02002208 shsurf->type = SHELL_SURFACE_NONE;
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04002209 shsurf->next_type = SHELL_SURFACE_NONE;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002210
Kristian Høgsberga61ca062012-05-22 16:05:52 -04002211 shsurf->client = client;
2212
Kristian Høgsberg45ba8692012-05-21 14:27:33 -04002213 return shsurf;
Tiago Vignattibc052c92012-04-19 16:18:18 +03002214}
2215
2216static void
2217shell_get_shell_surface(struct wl_client *client,
2218 struct wl_resource *resource,
2219 uint32_t id,
2220 struct wl_resource *surface_resource)
2221{
2222 struct weston_surface *surface = surface_resource->data;
2223 struct desktop_shell *shell = resource->data;
2224 struct shell_surface *shsurf;
2225
2226 if (get_shell_surface(surface)) {
2227 wl_resource_post_error(surface_resource,
Kristian Høgsberg9540ea62012-05-21 14:28:57 -04002228 WL_DISPLAY_ERROR_INVALID_OBJECT,
2229 "desktop_shell::get_shell_surface already requested");
Tiago Vignattibc052c92012-04-19 16:18:18 +03002230 return;
2231 }
2232
Kristian Høgsberga61ca062012-05-22 16:05:52 -04002233 shsurf = create_shell_surface(shell, surface, &shell_client);
Kristian Høgsberg9540ea62012-05-21 14:28:57 -04002234 if (!shsurf) {
2235 wl_resource_post_error(surface_resource,
2236 WL_DISPLAY_ERROR_INVALID_OBJECT,
2237 "surface->configure already set");
2238 return;
2239 }
Tiago Vignattibc052c92012-04-19 16:18:18 +03002240
Kristian Høgsberg9540ea62012-05-21 14:28:57 -04002241 shsurf->resource.destroy = shell_destroy_shell_surface;
2242 shsurf->resource.object.id = id;
2243 shsurf->resource.object.interface = &wl_shell_surface_interface;
2244 shsurf->resource.object.implementation =
2245 (void (**)(void)) &shell_surface_implementation;
2246 shsurf->resource.data = shsurf;
Tiago Vignattibc052c92012-04-19 16:18:18 +03002247
Kristian Høgsberg9540ea62012-05-21 14:28:57 -04002248 wl_client_add_resource(client, &shsurf->resource);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002249}
2250
2251static const struct wl_shell_interface shell_implementation = {
Pekka Paalanen46229672011-11-29 15:49:31 +02002252 shell_get_shell_surface
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05002253};
2254
Kristian Høgsberg07937562011-04-12 17:25:42 -04002255static void
Ander Conselvan de Oliveira859e8852013-02-21 18:35:21 +02002256shell_fade(struct desktop_shell *shell, enum fade_type type);
2257
2258static int
2259screensaver_timeout(void *data)
2260{
2261 struct desktop_shell *shell = data;
2262
2263 shell_fade(shell, FADE_OUT);
2264
2265 return 1;
2266}
2267
2268static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002269handle_screensaver_sigchld(struct weston_process *proc, int status)
Pekka Paalanen18027e52011-12-02 16:31:49 +02002270{
Ander Conselvan de Oliveira18639f82013-02-15 18:44:19 +02002271 struct desktop_shell *shell =
2272 container_of(proc, struct desktop_shell, screensaver.process);
Ander Conselvan de Oliveira18639f82013-02-15 18:44:19 +02002273
Pekka Paalanen18027e52011-12-02 16:31:49 +02002274 proc->pid = 0;
Ander Conselvan de Oliveira18639f82013-02-15 18:44:19 +02002275
2276 if (shell->locked)
Ander Conselvan de Oliveirab17537e2013-02-22 14:16:18 +02002277 weston_compositor_sleep(shell->compositor);
Pekka Paalanen18027e52011-12-02 16:31:49 +02002278}
2279
2280static void
Tiago Vignattibe143262012-04-16 17:31:41 +03002281launch_screensaver(struct desktop_shell *shell)
Pekka Paalanen77346a62011-11-30 16:26:35 +02002282{
2283 if (shell->screensaver.binding)
2284 return;
2285
Ander Conselvan de Oliveiradda9d782013-02-22 14:16:19 +02002286 if (!shell->screensaver.path) {
2287 weston_compositor_sleep(shell->compositor);
Pekka Paalanene955f1e2011-12-07 11:49:52 +02002288 return;
Ander Conselvan de Oliveiradda9d782013-02-22 14:16:19 +02002289 }
Pekka Paalanene955f1e2011-12-07 11:49:52 +02002290
Kristian Høgsberg32bed572012-03-01 17:11:36 -05002291 if (shell->screensaver.process.pid != 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002292 weston_log("old screensaver still running\n");
Kristian Høgsberg32bed572012-03-01 17:11:36 -05002293 return;
2294 }
2295
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002296 weston_client_launch(shell->compositor,
Pekka Paalanen18027e52011-12-02 16:31:49 +02002297 &shell->screensaver.process,
Pekka Paalanene955f1e2011-12-07 11:49:52 +02002298 shell->screensaver.path,
Pekka Paalanen18027e52011-12-02 16:31:49 +02002299 handle_screensaver_sigchld);
Pekka Paalanen77346a62011-11-30 16:26:35 +02002300}
2301
2302static void
Tiago Vignattibe143262012-04-16 17:31:41 +03002303terminate_screensaver(struct desktop_shell *shell)
Pekka Paalanen77346a62011-11-30 16:26:35 +02002304{
Pekka Paalanen18027e52011-12-02 16:31:49 +02002305 if (shell->screensaver.process.pid == 0)
2306 return;
2307
2308 kill(shell->screensaver.process.pid, SIGTERM);
Pekka Paalanen77346a62011-11-30 16:26:35 +02002309}
2310
2311static void
Giulio Camuffo184df502013-02-21 11:29:21 +01002312configure_static_surface(struct weston_surface *es, struct weston_layer *layer, int32_t width, int32_t height)
Kristian Høgsberg962342c2012-06-26 16:29:50 -04002313{
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04002314 struct weston_surface *s, *next;
Kristian Høgsberg962342c2012-06-26 16:29:50 -04002315
Giulio Camuffo184df502013-02-21 11:29:21 +01002316 if (width == 0)
2317 return;
2318
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04002319 wl_list_for_each_safe(s, next, &layer->surface_list, layer_link) {
2320 if (s->output == es->output && s != es) {
2321 weston_surface_unmap(s);
Kristian Høgsberg962342c2012-06-26 16:29:50 -04002322 s->configure = NULL;
Kristian Høgsberg962342c2012-06-26 16:29:50 -04002323 }
2324 }
2325
Giulio Camuffo184df502013-02-21 11:29:21 +01002326 weston_surface_configure(es, es->output->x, es->output->y, width, height);
Kristian Høgsberg962342c2012-06-26 16:29:50 -04002327
2328 if (wl_list_empty(&es->layer_link)) {
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04002329 wl_list_insert(&layer->surface_list, &es->layer_link);
Kristian Høgsbergc7cd6262012-06-28 13:46:09 -04002330 weston_compositor_schedule_repaint(es->compositor);
Kristian Høgsberg962342c2012-06-26 16:29:50 -04002331 }
2332}
2333
2334static void
Giulio Camuffo184df502013-02-21 11:29:21 +01002335background_configure(struct weston_surface *es, int32_t sx, int32_t sy, int32_t width, int32_t height)
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04002336{
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01002337 struct desktop_shell *shell = es->configure_private;
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04002338
Giulio Camuffo184df502013-02-21 11:29:21 +01002339 configure_static_surface(es, &shell->background_layer, width, height);
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04002340}
2341
2342static void
Kristian Høgsberg75840622011-09-06 13:48:16 -04002343desktop_shell_set_background(struct wl_client *client,
2344 struct wl_resource *resource,
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01002345 struct wl_resource *output_resource,
Kristian Høgsberg75840622011-09-06 13:48:16 -04002346 struct wl_resource *surface_resource)
2347{
Kristian Høgsberg962342c2012-06-26 16:29:50 -04002348 struct desktop_shell *shell = resource->data;
2349 struct weston_surface *surface = surface_resource->data;
Kristian Høgsberg75840622011-09-06 13:48:16 -04002350
Kristian Høgsberg962342c2012-06-26 16:29:50 -04002351 if (surface->configure) {
2352 wl_resource_post_error(surface_resource,
2353 WL_DISPLAY_ERROR_INVALID_OBJECT,
2354 "surface role already assigned");
2355 return;
2356 }
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01002357
Kristian Høgsberg962342c2012-06-26 16:29:50 -04002358 surface->configure = background_configure;
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01002359 surface->configure_private = shell;
Kristian Høgsberg962342c2012-06-26 16:29:50 -04002360 surface->output = output_resource->data;
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04002361 desktop_shell_send_configure(resource, 0,
Kristian Høgsberg0b5cd0c2012-03-04 21:57:37 -05002362 surface_resource,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002363 surface->output->width,
2364 surface->output->height);
Kristian Høgsberg75840622011-09-06 13:48:16 -04002365}
2366
2367static void
Giulio Camuffo184df502013-02-21 11:29:21 +01002368panel_configure(struct weston_surface *es, int32_t sx, int32_t sy, int32_t width, int32_t height)
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04002369{
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01002370 struct desktop_shell *shell = es->configure_private;
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04002371
Giulio Camuffo184df502013-02-21 11:29:21 +01002372 configure_static_surface(es, &shell->panel_layer, width, height);
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04002373}
2374
2375static void
Kristian Høgsberg75840622011-09-06 13:48:16 -04002376desktop_shell_set_panel(struct wl_client *client,
2377 struct wl_resource *resource,
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01002378 struct wl_resource *output_resource,
Kristian Høgsberg75840622011-09-06 13:48:16 -04002379 struct wl_resource *surface_resource)
2380{
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04002381 struct desktop_shell *shell = resource->data;
2382 struct weston_surface *surface = surface_resource->data;
Kristian Høgsberg75840622011-09-06 13:48:16 -04002383
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04002384 if (surface->configure) {
2385 wl_resource_post_error(surface_resource,
2386 WL_DISPLAY_ERROR_INVALID_OBJECT,
2387 "surface role already assigned");
2388 return;
2389 }
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01002390
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04002391 surface->configure = panel_configure;
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01002392 surface->configure_private = shell;
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04002393 surface->output = output_resource->data;
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04002394 desktop_shell_send_configure(resource, 0,
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04002395 surface_resource,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002396 surface->output->width,
2397 surface->output->height);
Kristian Høgsberg75840622011-09-06 13:48:16 -04002398}
2399
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002400static void
Giulio Camuffo184df502013-02-21 11:29:21 +01002401lock_surface_configure(struct weston_surface *surface, int32_t sx, int32_t sy, int32_t width, int32_t height)
Kristian Høgsberg730c94d2012-06-26 21:44:35 -04002402{
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01002403 struct desktop_shell *shell = surface->configure_private;
Kristian Høgsberg730c94d2012-06-26 21:44:35 -04002404
Giulio Camuffo184df502013-02-21 11:29:21 +01002405 if (width == 0)
2406 return;
2407
Kristian Høgsberg730c94d2012-06-26 21:44:35 -04002408 center_on_output(surface, get_default_output(shell->compositor));
2409
2410 if (!weston_surface_is_mapped(surface)) {
2411 wl_list_insert(&shell->lock_layer.surface_list,
2412 &surface->layer_link);
Ander Conselvan de Oliveira231ba172012-09-14 16:12:04 +03002413 weston_surface_update_transform(surface);
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02002414 shell_fade(shell, FADE_IN);
Kristian Høgsberg730c94d2012-06-26 21:44:35 -04002415 }
2416}
2417
2418static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04002419handle_lock_surface_destroy(struct wl_listener *listener, void *data)
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05002420{
Tiago Vignattibe143262012-04-16 17:31:41 +03002421 struct desktop_shell *shell =
2422 container_of(listener, struct desktop_shell, lock_surface_listener);
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05002423
Martin Minarik6d118362012-06-07 18:01:59 +02002424 weston_log("lock surface gone\n");
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05002425 shell->lock_surface = NULL;
2426}
2427
2428static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002429desktop_shell_set_lock_surface(struct wl_client *client,
2430 struct wl_resource *resource,
2431 struct wl_resource *surface_resource)
2432{
Tiago Vignattibe143262012-04-16 17:31:41 +03002433 struct desktop_shell *shell = resource->data;
Kristian Høgsberg730c94d2012-06-26 21:44:35 -04002434 struct weston_surface *surface = surface_resource->data;
Pekka Paalanen98262232011-12-01 10:42:22 +02002435
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002436 shell->prepare_event_sent = false;
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +02002437
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002438 if (!shell->locked)
2439 return;
2440
Pekka Paalanen98262232011-12-01 10:42:22 +02002441 shell->lock_surface = surface;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002442
Kristian Høgsberg27e30522012-04-11 23:18:23 -04002443 shell->lock_surface_listener.notify = handle_lock_surface_destroy;
2444 wl_signal_add(&surface_resource->destroy_signal,
2445 &shell->lock_surface_listener);
Pekka Paalanen57da4a82011-11-23 16:42:16 +02002446
Kristian Høgsberg730c94d2012-06-26 21:44:35 -04002447 surface->configure = lock_surface_configure;
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01002448 surface->configure_private = shell;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002449}
2450
2451static void
Tiago Vignattibe143262012-04-16 17:31:41 +03002452resume_desktop(struct desktop_shell *shell)
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002453{
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04002454 struct workspace *ws = get_current_workspace(shell);
Pekka Paalanen77346a62011-11-30 16:26:35 +02002455
Pekka Paalanen77346a62011-11-30 16:26:35 +02002456 terminate_screensaver(shell);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002457
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002458 wl_list_remove(&shell->lock_layer.link);
2459 wl_list_insert(&shell->compositor->cursor_layer.link,
2460 &shell->fullscreen_layer.link);
2461 wl_list_insert(&shell->fullscreen_layer.link,
2462 &shell->panel_layer.link);
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02002463 if (shell->showing_input_panels) {
2464 wl_list_insert(&shell->panel_layer.link,
2465 &shell->input_panel_layer.link);
2466 wl_list_insert(&shell->input_panel_layer.link,
2467 &ws->layer.link);
2468 } else {
2469 wl_list_insert(&shell->panel_layer.link, &ws->layer.link);
2470 }
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002471
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -04002472 restore_focus_state(shell, get_current_workspace(shell));
Jonas Ådahl04769742012-06-13 00:01:24 +02002473
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002474 shell->locked = false;
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02002475 shell_fade(shell, FADE_IN);
Pekka Paalanenfc6d91a2012-02-10 15:33:10 +02002476 weston_compositor_damage_all(shell->compositor);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002477}
2478
2479static void
2480desktop_shell_unlock(struct wl_client *client,
2481 struct wl_resource *resource)
2482{
Tiago Vignattibe143262012-04-16 17:31:41 +03002483 struct desktop_shell *shell = resource->data;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002484
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002485 shell->prepare_event_sent = false;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002486
2487 if (shell->locked)
2488 resume_desktop(shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002489}
2490
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04002491static void
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03002492desktop_shell_set_grab_surface(struct wl_client *client,
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04002493 struct wl_resource *resource,
2494 struct wl_resource *surface_resource)
2495{
2496 struct desktop_shell *shell = resource->data;
2497
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03002498 shell->grab_surface = surface_resource->data;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04002499}
2500
Kristian Høgsberg75840622011-09-06 13:48:16 -04002501static const struct desktop_shell_interface desktop_shell_implementation = {
2502 desktop_shell_set_background,
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002503 desktop_shell_set_panel,
2504 desktop_shell_set_lock_surface,
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04002505 desktop_shell_unlock,
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03002506 desktop_shell_set_grab_surface
Kristian Høgsberg75840622011-09-06 13:48:16 -04002507};
2508
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02002509static enum shell_surface_type
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002510get_shell_surface_type(struct weston_surface *surface)
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02002511{
2512 struct shell_surface *shsurf;
2513
2514 shsurf = get_shell_surface(surface);
2515 if (!shsurf)
Pekka Paalanen98262232011-12-01 10:42:22 +02002516 return SHELL_SURFACE_NONE;
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02002517 return shsurf->type;
2518}
2519
Kristian Høgsberg75840622011-09-06 13:48:16 -04002520static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002521move_binding(struct wl_seat *seat, uint32_t time, uint32_t button, void *data)
Kristian Høgsberg07937562011-04-12 17:25:42 -04002522{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002523 struct weston_surface *surface =
Daniel Stone37816df2012-05-16 18:45:18 +01002524 (struct weston_surface *) seat->pointer->focus;
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04002525 struct shell_surface *shsurf;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -05002526
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01002527 if (surface == NULL)
2528 return;
Kristian Høgsberg07937562011-04-12 17:25:42 -04002529
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04002530 shsurf = get_shell_surface(surface);
Rafal Mielniczuk23c67592013-03-11 19:26:53 +01002531 if (shsurf == NULL || shsurf->type == SHELL_SURFACE_FULLSCREEN ||
2532 shsurf->type == SHELL_SURFACE_MAXIMIZED)
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04002533 return;
2534
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04002535 surface_move(shsurf, (struct weston_seat *) seat);
Kristian Høgsberg07937562011-04-12 17:25:42 -04002536}
2537
2538static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002539resize_binding(struct wl_seat *seat, uint32_t time, uint32_t button, void *data)
Kristian Høgsberg07937562011-04-12 17:25:42 -04002540{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002541 struct weston_surface *surface =
Daniel Stone37816df2012-05-16 18:45:18 +01002542 (struct weston_surface *) seat->pointer->focus;
Kristian Høgsberg07937562011-04-12 17:25:42 -04002543 uint32_t edges = 0;
2544 int32_t x, y;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002545 struct shell_surface *shsurf;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -05002546
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01002547 if (surface == NULL)
2548 return;
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02002549
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002550 shsurf = get_shell_surface(surface);
Rafal Mielniczuk23c67592013-03-11 19:26:53 +01002551 if (!shsurf || shsurf->type == SHELL_SURFACE_FULLSCREEN ||
2552 shsurf->type == SHELL_SURFACE_MAXIMIZED)
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02002553 return;
2554
Pekka Paalanen5c97ae72012-01-30 16:19:47 +02002555 weston_surface_from_global(surface,
Daniel Stone37816df2012-05-16 18:45:18 +01002556 wl_fixed_to_int(seat->pointer->grab_x),
2557 wl_fixed_to_int(seat->pointer->grab_y),
Daniel Stone103db7f2012-05-08 17:17:55 +01002558 &x, &y);
Kristian Høgsberg07937562011-04-12 17:25:42 -04002559
Pekka Paalanen60921e52012-01-25 15:55:43 +02002560 if (x < surface->geometry.width / 3)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002561 edges |= WL_SHELL_SURFACE_RESIZE_LEFT;
Pekka Paalanen60921e52012-01-25 15:55:43 +02002562 else if (x < 2 * surface->geometry.width / 3)
Kristian Høgsberg07937562011-04-12 17:25:42 -04002563 edges |= 0;
2564 else
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002565 edges |= WL_SHELL_SURFACE_RESIZE_RIGHT;
Kristian Høgsberg07937562011-04-12 17:25:42 -04002566
Pekka Paalanen60921e52012-01-25 15:55:43 +02002567 if (y < surface->geometry.height / 3)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002568 edges |= WL_SHELL_SURFACE_RESIZE_TOP;
Pekka Paalanen60921e52012-01-25 15:55:43 +02002569 else if (y < 2 * surface->geometry.height / 3)
Kristian Høgsberg07937562011-04-12 17:25:42 -04002570 edges |= 0;
2571 else
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002572 edges |= WL_SHELL_SURFACE_RESIZE_BOTTOM;
Kristian Høgsberg07937562011-04-12 17:25:42 -04002573
Kristian Høgsbergc1693f22012-05-22 16:56:23 -04002574 surface_resize(shsurf, (struct weston_seat *) seat, edges);
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04002575}
2576
2577static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002578surface_opacity_binding(struct wl_seat *seat, uint32_t time, uint32_t axis,
Daniel Stone0c1e46e2012-05-30 16:31:59 +01002579 wl_fixed_t value, void *data)
Scott Moreaua3aa9c92012-03-22 11:01:03 -06002580{
Jonas Ådahlb0b87ba2012-09-27 18:40:42 +02002581 float step = 0.005;
Scott Moreaua3aa9c92012-03-22 11:01:03 -06002582 struct shell_surface *shsurf;
2583 struct weston_surface *surface =
Daniel Stone37816df2012-05-16 18:45:18 +01002584 (struct weston_surface *) seat->pointer->focus;
Scott Moreaua3aa9c92012-03-22 11:01:03 -06002585
2586 if (surface == NULL)
2587 return;
2588
2589 shsurf = get_shell_surface(surface);
2590 if (!shsurf)
2591 return;
2592
Jonas Ådahlb0b87ba2012-09-27 18:40:42 +02002593 surface->alpha -= wl_fixed_to_double(value) * step;
Scott Moreaua3aa9c92012-03-22 11:01:03 -06002594
Scott Moreau02709af2012-05-22 01:54:10 -06002595 if (surface->alpha > 1.0)
2596 surface->alpha = 1.0;
Scott Moreaua3aa9c92012-03-22 11:01:03 -06002597 if (surface->alpha < step)
2598 surface->alpha = step;
2599
Pekka Paalanenc3ce7382013-03-08 14:56:49 +02002600 weston_surface_geometry_dirty(surface);
Scott Moreaua3aa9c92012-03-22 11:01:03 -06002601 weston_surface_damage(surface);
2602}
2603
2604static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002605do_zoom(struct wl_seat *seat, uint32_t time, uint32_t key, uint32_t axis,
Daniel Stone0c1e46e2012-05-30 16:31:59 +01002606 wl_fixed_t value)
Scott Moreauccbf29d2012-02-22 14:21:41 -07002607{
Daniel Stone37816df2012-05-16 18:45:18 +01002608 struct weston_seat *ws = (struct weston_seat *) seat;
2609 struct weston_compositor *compositor = ws->compositor;
Scott Moreauccbf29d2012-02-22 14:21:41 -07002610 struct weston_output *output;
Scott Moreaue6603982012-06-11 13:07:51 -06002611 float increment;
Scott Moreauccbf29d2012-02-22 14:21:41 -07002612
2613 wl_list_for_each(output, &compositor->output_list, link) {
2614 if (pixman_region32_contains_point(&output->region,
Daniel Stone37816df2012-05-16 18:45:18 +01002615 wl_fixed_to_double(seat->pointer->x),
2616 wl_fixed_to_double(seat->pointer->y),
Daniel Stone103db7f2012-05-08 17:17:55 +01002617 NULL)) {
Daniel Stone325fc2d2012-05-30 16:31:58 +01002618 if (key == KEY_PAGEUP)
Kristian Høgsberg9b68af02012-05-22 12:55:18 -04002619 increment = output->zoom.increment;
Daniel Stone325fc2d2012-05-30 16:31:58 +01002620 else if (key == KEY_PAGEDOWN)
Kristian Høgsberg9b68af02012-05-22 12:55:18 -04002621 increment = -output->zoom.increment;
2622 else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
Jonas Ådahlb0b87ba2012-09-27 18:40:42 +02002623 /* For every pixel zoom 20th of a step */
Daniel Stone0c1e46e2012-05-30 16:31:59 +01002624 increment = output->zoom.increment *
Jonas Ådahlb0b87ba2012-09-27 18:40:42 +02002625 -wl_fixed_to_double(value) / 20.0;
Kristian Høgsberg9b68af02012-05-22 12:55:18 -04002626 else
2627 increment = 0;
2628
Kristian Høgsberg9b68af02012-05-22 12:55:18 -04002629 output->zoom.level += increment;
Scott Moreauc6d7f602012-02-23 22:28:37 -07002630
Scott Moreaue6603982012-06-11 13:07:51 -06002631 if (output->zoom.level < 0.0)
Scott Moreau850ca422012-05-21 15:21:25 -06002632 output->zoom.level = 0.0;
Scott Moreaue6603982012-06-11 13:07:51 -06002633 else if (output->zoom.level > output->zoom.max_level)
2634 output->zoom.level = output->zoom.max_level;
Ville Syrjäläaa628d02012-11-16 11:48:47 +02002635 else if (!output->zoom.active) {
Scott Moreaue6603982012-06-11 13:07:51 -06002636 output->zoom.active = 1;
Kristian Høgsberg79af73e2012-08-03 15:45:23 -04002637 output->disable_planes++;
2638 }
Scott Moreauccbf29d2012-02-22 14:21:41 -07002639
Scott Moreaue6603982012-06-11 13:07:51 -06002640 output->zoom.spring_z.target = output->zoom.level;
Scott Moreauccbf29d2012-02-22 14:21:41 -07002641
Scott Moreau8dacaab2012-06-17 18:10:58 -06002642 weston_output_update_zoom(output, output->zoom.type);
Scott Moreauccbf29d2012-02-22 14:21:41 -07002643 }
2644 }
2645}
2646
Scott Moreauccbf29d2012-02-22 14:21:41 -07002647static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002648zoom_axis_binding(struct wl_seat *seat, uint32_t time, uint32_t axis,
Daniel Stone0c1e46e2012-05-30 16:31:59 +01002649 wl_fixed_t value, void *data)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002650{
2651 do_zoom(seat, time, 0, axis, value);
2652}
2653
2654static void
2655zoom_key_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
2656 void *data)
2657{
2658 do_zoom(seat, time, key, 0, 0);
2659}
2660
2661static void
2662terminate_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
2663 void *data)
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05002664{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002665 struct weston_compositor *compositor = data;
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05002666
Daniel Stone325fc2d2012-05-30 16:31:58 +01002667 wl_display_terminate(compositor->wl_display);
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05002668}
2669
2670static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04002671rotate_grab_motion(struct weston_pointer_grab *grab,
Daniel Stone103db7f2012-05-08 17:17:55 +01002672 uint32_t time, wl_fixed_t x, wl_fixed_t y)
Pekka Paalanen460099f2012-01-20 16:48:25 +02002673{
2674 struct rotate_grab *rotate =
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002675 container_of(grab, struct rotate_grab, base.grab);
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04002676 struct weston_pointer *pointer = grab->pointer;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002677 struct shell_surface *shsurf = rotate->base.shsurf;
2678 struct weston_surface *surface;
John Kåre Alsaker490d02a2012-09-30 02:57:21 +02002679 float cx, cy, dx, dy, cposx, cposy, dposx, dposy, r;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002680
2681 if (!shsurf)
2682 return;
2683
2684 surface = shsurf->surface;
2685
2686 cx = 0.5f * surface->geometry.width;
2687 cy = 0.5f * surface->geometry.height;
Pekka Paalanen460099f2012-01-20 16:48:25 +02002688
Daniel Stone37816df2012-05-16 18:45:18 +01002689 dx = wl_fixed_to_double(pointer->x) - rotate->center.x;
2690 dy = wl_fixed_to_double(pointer->y) - rotate->center.y;
Pekka Paalanen460099f2012-01-20 16:48:25 +02002691 r = sqrtf(dx * dx + dy * dy);
2692
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002693 wl_list_remove(&shsurf->rotation.transform.link);
Pekka Paalanenc3ce7382013-03-08 14:56:49 +02002694 weston_surface_geometry_dirty(shsurf->surface);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002695
2696 if (r > 20.0f) {
Pekka Paalanen460099f2012-01-20 16:48:25 +02002697 struct weston_matrix *matrix =
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002698 &shsurf->rotation.transform.matrix;
Pekka Paalanen460099f2012-01-20 16:48:25 +02002699
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05002700 weston_matrix_init(&rotate->rotation);
Vasily Khoruzhick1bbf3722013-01-28 22:40:28 +03002701 weston_matrix_rotate_xy(&rotate->rotation, dx / r, dy / r);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002702
2703 weston_matrix_init(matrix);
Pekka Paalanen7b3bd3d2012-01-30 14:16:34 +02002704 weston_matrix_translate(matrix, -cx, -cy, 0.0f);
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002705 weston_matrix_multiply(matrix, &shsurf->rotation.rotation);
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05002706 weston_matrix_multiply(matrix, &rotate->rotation);
Pekka Paalanen7b3bd3d2012-01-30 14:16:34 +02002707 weston_matrix_translate(matrix, cx, cy, 0.0f);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002708
Pekka Paalanenbc0b7e72012-01-24 09:53:37 +02002709 wl_list_insert(
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002710 &shsurf->surface->geometry.transformation_list,
2711 &shsurf->rotation.transform.link);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002712 } else {
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002713 wl_list_init(&shsurf->rotation.transform.link);
2714 weston_matrix_init(&shsurf->rotation.rotation);
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05002715 weston_matrix_init(&rotate->rotation);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002716 }
Pekka Paalanenb45ac5e2012-02-09 15:58:44 +02002717
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01002718 /* We need to adjust the position of the surface
2719 * in case it was resized in a rotated state before */
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002720 cposx = surface->geometry.x + cx;
2721 cposy = surface->geometry.y + cy;
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01002722 dposx = rotate->center.x - cposx;
2723 dposy = rotate->center.y - cposy;
2724 if (dposx != 0.0f || dposy != 0.0f) {
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002725 weston_surface_set_position(surface,
2726 surface->geometry.x + dposx,
2727 surface->geometry.y + dposy);
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01002728 }
2729
Pekka Paalanenb45ac5e2012-02-09 15:58:44 +02002730 /* Repaint implies weston_surface_update_transform(), which
2731 * lazily applies the damage due to rotation update.
2732 */
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002733 weston_compositor_schedule_repaint(shsurf->surface->compositor);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002734}
2735
2736static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04002737rotate_grab_button(struct weston_pointer_grab *grab,
2738 uint32_t time, uint32_t button, uint32_t state_w)
Pekka Paalanen460099f2012-01-20 16:48:25 +02002739{
2740 struct rotate_grab *rotate =
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002741 container_of(grab, struct rotate_grab, base.grab);
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04002742 struct weston_pointer *pointer = grab->pointer;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002743 struct shell_surface *shsurf = rotate->base.shsurf;
Daniel Stone4dbadb12012-05-30 16:31:51 +01002744 enum wl_pointer_button_state state = state_w;
Pekka Paalanen460099f2012-01-20 16:48:25 +02002745
Daniel Stone4dbadb12012-05-30 16:31:51 +01002746 if (pointer->button_count == 0 &&
2747 state == WL_POINTER_BUTTON_STATE_RELEASED) {
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002748 if (shsurf)
2749 weston_matrix_multiply(&shsurf->rotation.rotation,
2750 &rotate->rotation);
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03002751 shell_grab_end(&rotate->base);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002752 free(rotate);
2753 }
2754}
2755
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -04002756static const struct weston_pointer_grab_interface rotate_grab_interface = {
Pekka Paalanen460099f2012-01-20 16:48:25 +02002757 noop_grab_focus,
2758 rotate_grab_motion,
2759 rotate_grab_button,
2760};
2761
2762static void
Kristian Høgsberg0c369032013-02-14 21:31:44 -05002763surface_rotate(struct shell_surface *surface, struct wl_seat *seat)
Pekka Paalanen460099f2012-01-20 16:48:25 +02002764{
Pekka Paalanen460099f2012-01-20 16:48:25 +02002765 struct rotate_grab *rotate;
John Kåre Alsaker490d02a2012-09-30 02:57:21 +02002766 float dx, dy;
2767 float r;
Pekka Paalanen460099f2012-01-20 16:48:25 +02002768
Pekka Paalanen460099f2012-01-20 16:48:25 +02002769 rotate = malloc(sizeof *rotate);
2770 if (!rotate)
2771 return;
2772
Kristian Høgsbergb2af93e2012-06-07 20:10:23 -04002773 weston_surface_to_global_float(surface->surface,
2774 surface->surface->geometry.width / 2,
2775 surface->surface->geometry.height / 2,
2776 &rotate->center.x, &rotate->center.y);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002777
Daniel Stone37816df2012-05-16 18:45:18 +01002778 dx = wl_fixed_to_double(seat->pointer->x) - rotate->center.x;
2779 dy = wl_fixed_to_double(seat->pointer->y) - rotate->center.y;
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05002780 r = sqrtf(dx * dx + dy * dy);
2781 if (r > 20.0f) {
2782 struct weston_matrix inverse;
2783
2784 weston_matrix_init(&inverse);
Vasily Khoruzhick1bbf3722013-01-28 22:40:28 +03002785 weston_matrix_rotate_xy(&inverse, dx / r, -dy / r);
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05002786 weston_matrix_multiply(&surface->rotation.rotation, &inverse);
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01002787
2788 weston_matrix_init(&rotate->rotation);
Vasily Khoruzhick1bbf3722013-01-28 22:40:28 +03002789 weston_matrix_rotate_xy(&rotate->rotation, dx / r, dy / r);
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05002790 } else {
2791 weston_matrix_init(&surface->rotation.rotation);
2792 weston_matrix_init(&rotate->rotation);
2793 }
2794
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03002795 shell_grab_start(&rotate->base, &rotate_grab_interface, surface,
2796 seat->pointer, DESKTOP_SHELL_CURSOR_ARROW);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002797}
2798
2799static void
Kristian Høgsberg0c369032013-02-14 21:31:44 -05002800rotate_binding(struct wl_seat *seat, uint32_t time, uint32_t button,
2801 void *data)
2802{
2803 struct weston_surface *base_surface =
2804 (struct weston_surface *) seat->pointer->focus;
2805 struct shell_surface *surface;
2806
2807 if (base_surface == NULL)
2808 return;
2809
2810 surface = get_shell_surface(base_surface);
Rafal Mielniczuk23c67592013-03-11 19:26:53 +01002811 if (!surface || surface->type == SHELL_SURFACE_FULLSCREEN ||
2812 surface->type == SHELL_SURFACE_MAXIMIZED)
Kristian Høgsberg0c369032013-02-14 21:31:44 -05002813 return;
2814
2815 surface_rotate(surface, seat);
2816}
2817
2818static void
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04002819lower_fullscreen_layer(struct desktop_shell *shell)
2820{
2821 struct workspace *ws;
2822 struct weston_surface *surface, *prev;
2823
2824 ws = get_current_workspace(shell);
2825 wl_list_for_each_reverse_safe(surface, prev,
2826 &shell->fullscreen_layer.surface_list,
2827 layer_link)
2828 weston_surface_restack(surface, &ws->layer.surface_list);
2829}
2830
2831static void
Tiago Vignattibe143262012-04-16 17:31:41 +03002832activate(struct desktop_shell *shell, struct weston_surface *es,
Daniel Stone37816df2012-05-16 18:45:18 +01002833 struct weston_seat *seat)
Kristian Høgsberg75840622011-09-06 13:48:16 -04002834{
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -04002835 struct focus_state *state;
Jonas Ådahl8538b222012-08-29 22:13:03 +02002836 struct workspace *ws;
Kristian Høgsberg75840622011-09-06 13:48:16 -04002837
Daniel Stone37816df2012-05-16 18:45:18 +01002838 weston_surface_activate(es, seat);
Kristian Høgsberg75840622011-09-06 13:48:16 -04002839
Jonas Ådahl8538b222012-08-29 22:13:03 +02002840 state = ensure_focus_state(shell, seat);
2841 if (state == NULL)
2842 return;
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -04002843
2844 state->keyboard_focus = es;
2845 wl_list_remove(&state->surface_destroy_listener.link);
2846 wl_signal_add(&es->surface.resource.destroy_signal,
2847 &state->surface_destroy_listener);
2848
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02002849 switch (get_shell_surface_type(es)) {
Alex Wu4539b082012-03-01 12:57:46 +08002850 case SHELL_SURFACE_FULLSCREEN:
2851 /* should on top of panels */
Alex Wu21858432012-04-01 20:13:08 +08002852 shell_stack_fullscreen(get_shell_surface(es));
Alex Wubd3354b2012-04-17 17:20:49 +08002853 shell_configure_fullscreen(get_shell_surface(es));
Alex Wu4539b082012-03-01 12:57:46 +08002854 break;
Pekka Paalanen57da4a82011-11-23 16:42:16 +02002855 default:
Jonas Ådahle3cddce2012-06-13 00:01:22 +02002856 ws = get_current_workspace(shell);
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04002857 weston_surface_restack(es, &ws->layer.surface_list);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002858 break;
Kristian Høgsberg75840622011-09-06 13:48:16 -04002859 }
2860}
2861
Alex Wu21858432012-04-01 20:13:08 +08002862/* no-op func for checking black surface */
2863static void
Giulio Camuffo184df502013-02-21 11:29:21 +01002864black_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy, int32_t width, int32_t height)
Alex Wu21858432012-04-01 20:13:08 +08002865{
2866}
2867
Quentin Glidicc0d79ce2013-01-29 14:16:13 +01002868static bool
Alex Wu21858432012-04-01 20:13:08 +08002869is_black_surface (struct weston_surface *es, struct weston_surface **fs_surface)
2870{
2871 if (es->configure == black_surface_configure) {
2872 if (fs_surface)
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01002873 *fs_surface = (struct weston_surface *)es->configure_private;
Alex Wu21858432012-04-01 20:13:08 +08002874 return true;
2875 }
2876 return false;
2877}
2878
Kristian Høgsberg75840622011-09-06 13:48:16 -04002879static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002880click_to_activate_binding(struct wl_seat *seat, uint32_t time, uint32_t button,
Daniel Stone4dbadb12012-05-30 16:31:51 +01002881 void *data)
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05002882{
Daniel Stone37816df2012-05-16 18:45:18 +01002883 struct weston_seat *ws = (struct weston_seat *) seat;
Tiago Vignattibe143262012-04-16 17:31:41 +03002884 struct desktop_shell *shell = data;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002885 struct weston_surface *focus;
Alex Wu4539b082012-03-01 12:57:46 +08002886 struct weston_surface *upper;
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05002887
Daniel Stone37816df2012-05-16 18:45:18 +01002888 focus = (struct weston_surface *) seat->pointer->focus;
Alex Wu9c35e6b2012-03-05 14:13:13 +08002889 if (!focus)
2890 return;
2891
Alex Wu21858432012-04-01 20:13:08 +08002892 if (is_black_surface(focus, &upper))
Alex Wu4539b082012-03-01 12:57:46 +08002893 focus = upper;
Alex Wu4539b082012-03-01 12:57:46 +08002894
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04002895 if (get_shell_surface_type(focus) == SHELL_SURFACE_NONE)
2896 return;
Kristian Høgsberg85b2e4b2012-06-21 16:49:42 -04002897
Daniel Stone325fc2d2012-05-30 16:31:58 +01002898 if (seat->pointer->grab == &seat->pointer->default_grab)
Daniel Stone37816df2012-05-16 18:45:18 +01002899 activate(shell, focus, ws);
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05002900}
2901
2902static void
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02002903lock(struct desktop_shell *shell)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04002904{
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04002905 struct workspace *ws = get_current_workspace(shell);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002906
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002907 if (shell->locked) {
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02002908 weston_compositor_sleep(shell->compositor);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002909 return;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002910 }
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002911
2912 shell->locked = true;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002913
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002914 /* Hide all surfaces by removing the fullscreen, panel and
2915 * toplevel layers. This way nothing else can show or receive
2916 * input events while we are locked. */
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002917
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002918 wl_list_remove(&shell->panel_layer.link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002919 wl_list_remove(&shell->fullscreen_layer.link);
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02002920 if (shell->showing_input_panels)
2921 wl_list_remove(&shell->input_panel_layer.link);
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04002922 wl_list_remove(&ws->layer.link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002923 wl_list_insert(&shell->compositor->cursor_layer.link,
2924 &shell->lock_layer.link);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002925
Pekka Paalanen77346a62011-11-30 16:26:35 +02002926 launch_screensaver(shell);
2927
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002928 /* TODO: disable bindings that should not work while locked. */
2929
2930 /* All this must be undone in resume_desktop(). */
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002931}
2932
2933static void
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02002934unlock(struct desktop_shell *shell)
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002935{
Pekka Paalanend81c2162011-11-16 13:47:34 +02002936 if (!shell->locked || shell->lock_surface) {
Ander Conselvan de Oliveira87524b62013-02-21 18:35:22 +02002937 shell_fade(shell, FADE_IN);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002938 return;
2939 }
2940
2941 /* If desktop-shell client has gone away, unlock immediately. */
2942 if (!shell->child.desktop_shell) {
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002943 resume_desktop(shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002944 return;
2945 }
2946
2947 if (shell->prepare_event_sent)
2948 return;
2949
Kristian Høgsberg0b5cd0c2012-03-04 21:57:37 -05002950 desktop_shell_send_prepare_lock_surface(shell->child.desktop_shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002951 shell->prepare_event_sent = true;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04002952}
2953
2954static void
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02002955shell_fade_done(struct weston_surface_animation *animation, void *data)
2956{
2957 struct desktop_shell *shell = data;
2958
2959 shell->fade.animation = NULL;
2960
2961 switch (shell->fade.type) {
2962 case FADE_IN:
2963 weston_surface_destroy(shell->fade.surface);
2964 shell->fade.surface = NULL;
2965 break;
2966 case FADE_OUT:
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02002967 lock(shell);
2968 break;
2969 }
2970}
2971
2972static void
2973shell_fade(struct desktop_shell *shell, enum fade_type type)
2974{
2975 struct weston_compositor *compositor = shell->compositor;
2976 struct weston_surface *surface;
2977 float tint;
2978
2979 switch (type) {
2980 case FADE_IN:
2981 tint = 0.0;
2982 break;
2983 case FADE_OUT:
2984 tint = 1.0;
2985 break;
2986 default:
2987 weston_log("shell: invalid fade type\n");
2988 return;
2989 }
2990
2991 shell->fade.type = type;
2992
2993 if (shell->fade.surface == NULL) {
2994 surface = weston_surface_create(compositor);
2995 if (!surface)
2996 return;
2997
2998 weston_surface_configure(surface, 0, 0, 8192, 8192);
2999 weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1.0);
3000 surface->alpha = 1.0 - tint;
3001 wl_list_insert(&compositor->fade_layer.surface_list,
3002 &surface->layer_link);
3003 weston_surface_update_transform(surface);
3004 shell->fade.surface = surface;
3005 pixman_region32_init(&surface->input);
3006 }
3007
3008 if (shell->fade.animation)
3009 weston_fade_update(shell->fade.animation,
3010 shell->fade.surface->alpha, tint, 30.0);
3011 else
3012 shell->fade.animation =
3013 weston_fade_run(shell->fade.surface,
3014 1.0 - tint, tint, 30.0,
3015 shell_fade_done, shell);
3016}
3017
3018static void
Ander Conselvan de Oliveiraa4575632013-02-21 18:35:23 +02003019idle_handler(struct wl_listener *listener, void *data)
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02003020{
3021 struct desktop_shell *shell =
Ander Conselvan de Oliveiraa4575632013-02-21 18:35:23 +02003022 container_of(listener, struct desktop_shell, idle_listener);
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02003023
3024 shell_fade(shell, FADE_OUT);
3025 /* lock() is called from shell_fade_done() */
3026}
3027
3028static void
Ander Conselvan de Oliveiraa4575632013-02-21 18:35:23 +02003029wake_handler(struct wl_listener *listener, void *data)
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02003030{
3031 struct desktop_shell *shell =
Ander Conselvan de Oliveiraa4575632013-02-21 18:35:23 +02003032 container_of(listener, struct desktop_shell, wake_listener);
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02003033
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02003034 unlock(shell);
3035}
3036
3037static void
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003038show_input_panels(struct wl_listener *listener, void *data)
3039{
3040 struct desktop_shell *shell =
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02003041 container_of(listener, struct desktop_shell,
3042 show_input_panel_listener);
Philipp Brüschweiler88013572012-08-06 13:44:42 +02003043 struct input_panel_surface *surface, *next;
3044 struct weston_surface *ws;
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003045
Jan Arne Petersen14da96b2013-04-18 16:47:28 +02003046 shell->text_input.surface = (struct weston_surface*)data;
3047
Jan Arne Petersen451a9712013-02-11 15:10:11 +01003048 if (shell->showing_input_panels)
3049 return;
3050
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02003051 shell->showing_input_panels = true;
3052
Jan Arne Petersencf18a322012-11-07 15:32:54 +01003053 if (!shell->locked)
3054 wl_list_insert(&shell->panel_layer.link,
3055 &shell->input_panel_layer.link);
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02003056
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04003057 wl_list_for_each_safe(surface, next,
Philipp Brüschweiler88013572012-08-06 13:44:42 +02003058 &shell->input_panel.surfaces, link) {
3059 ws = surface->surface;
Jan Arne Petersen7cd29e12013-04-18 16:47:29 +02003060 if (!ws->buffer_ref.buffer)
Jan Arne Petersen14da96b2013-04-18 16:47:28 +02003061 continue;
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02003062 wl_list_insert(&shell->input_panel_layer.surface_list,
Philipp Brüschweiler88013572012-08-06 13:44:42 +02003063 &ws->layer_link);
Pekka Paalanenc3ce7382013-03-08 14:56:49 +02003064 weston_surface_geometry_dirty(ws);
Ander Conselvan de Oliveira231ba172012-09-14 16:12:04 +03003065 weston_surface_update_transform(ws);
Philipp Brüschweiler88013572012-08-06 13:44:42 +02003066 weston_surface_damage(ws);
3067 weston_slide_run(ws, ws->geometry.height, 0, NULL, NULL);
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003068 }
3069}
3070
3071static void
3072hide_input_panels(struct wl_listener *listener, void *data)
3073{
3074 struct desktop_shell *shell =
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02003075 container_of(listener, struct desktop_shell,
3076 hide_input_panel_listener);
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04003077 struct weston_surface *surface, *next;
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003078
Jan Arne Petersen61381972013-01-31 15:52:21 +01003079 if (!shell->showing_input_panels)
3080 return;
3081
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02003082 shell->showing_input_panels = false;
3083
Jan Arne Petersen82ec9092012-12-03 15:36:02 +01003084 if (!shell->locked)
3085 wl_list_remove(&shell->input_panel_layer.link);
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02003086
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04003087 wl_list_for_each_safe(surface, next,
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02003088 &shell->input_panel_layer.surface_list, layer_link)
3089 weston_surface_unmap(surface);
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003090}
3091
3092static void
Jan Arne Petersen14da96b2013-04-18 16:47:28 +02003093update_input_panels(struct wl_listener *listener, void *data)
3094{
3095 struct desktop_shell *shell =
3096 container_of(listener, struct desktop_shell,
3097 update_input_panel_listener);
3098
3099 memcpy(&shell->text_input.cursor_rectangle, data, sizeof(pixman_box32_t));
3100}
3101
3102static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05003103center_on_output(struct weston_surface *surface, struct weston_output *output)
Pekka Paalanen77346a62011-11-30 16:26:35 +02003104{
Ander Conselvan de Oliveira012b4c72012-11-27 17:03:42 +02003105 int32_t width = weston_surface_buffer_width(surface);
3106 int32_t height = weston_surface_buffer_height(surface);
3107 float x, y;
Pekka Paalanen77346a62011-11-30 16:26:35 +02003108
Ander Conselvan de Oliveira012b4c72012-11-27 17:03:42 +02003109 x = output->x + (output->width - width) / 2;
3110 y = output->y + (output->height - height) / 2;
3111
3112 weston_surface_configure(surface, x, y, width, height);
Pekka Paalanen77346a62011-11-30 16:26:35 +02003113}
3114
3115static void
Rob Bradfordac63e5b2012-08-13 14:07:52 +01003116weston_surface_set_initial_position (struct weston_surface *surface,
3117 struct desktop_shell *shell)
3118{
3119 struct weston_compositor *compositor = shell->compositor;
3120 int ix = 0, iy = 0;
3121 int range_x, range_y;
3122 int dx, dy, x, y, panel_height;
3123 struct weston_output *output, *target_output = NULL;
3124 struct weston_seat *seat;
3125
3126 /* As a heuristic place the new window on the same output as the
3127 * pointer. Falling back to the output containing 0, 0.
3128 *
3129 * TODO: Do something clever for touch too?
3130 */
3131 wl_list_for_each(seat, &compositor->seat_list, link) {
3132 if (seat->has_pointer) {
3133 ix = wl_fixed_to_int(seat->pointer.x);
3134 iy = wl_fixed_to_int(seat->pointer.y);
3135 break;
3136 }
3137 }
3138
3139 wl_list_for_each(output, &compositor->output_list, link) {
3140 if (pixman_region32_contains_point(&output->region, ix, iy, NULL)) {
3141 target_output = output;
3142 break;
3143 }
3144 }
3145
3146 if (!target_output) {
3147 weston_surface_set_position(surface, 10 + random() % 400,
3148 10 + random() % 400);
3149 return;
3150 }
3151
3152 /* Valid range within output where the surface will still be onscreen.
3153 * If this is negative it means that the surface is bigger than
3154 * output.
3155 */
3156 panel_height = get_output_panel_height(shell, target_output);
Scott Moreau1bad5db2012-08-18 01:04:05 -06003157 range_x = target_output->width - surface->geometry.width;
3158 range_y = (target_output->height - panel_height) -
Rob Bradfordac63e5b2012-08-13 14:07:52 +01003159 surface->geometry.height;
3160
Rob Bradford4cb88c72012-08-13 15:18:44 +01003161 if (range_x > 0)
Rob Bradfordac63e5b2012-08-13 14:07:52 +01003162 dx = random() % range_x;
Rob Bradfordac63e5b2012-08-13 14:07:52 +01003163 else
Rob Bradford4cb88c72012-08-13 15:18:44 +01003164 dx = 0;
3165
3166 if (range_y > 0)
Rob Bradfordac63e5b2012-08-13 14:07:52 +01003167 dy = panel_height + random() % range_y;
Rob Bradford4cb88c72012-08-13 15:18:44 +01003168 else
3169 dy = panel_height;
Rob Bradfordac63e5b2012-08-13 14:07:52 +01003170
3171 x = target_output->x + dx;
3172 y = target_output->y + dy;
3173
3174 weston_surface_set_position (surface, x, y);
3175}
3176
3177static void
Tiago Vignattibe143262012-04-16 17:31:41 +03003178map(struct desktop_shell *shell, struct weston_surface *surface,
Ander Conselvan de Oliveirae9e05152012-02-15 17:02:56 +02003179 int32_t width, int32_t height, int32_t sx, int32_t sy)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04003180{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05003181 struct weston_compositor *compositor = shell->compositor;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003182 struct shell_surface *shsurf = get_shell_surface(surface);
3183 enum shell_surface_type surface_type = shsurf->type;
Kristian Høgsberg60c49542012-03-05 20:51:34 -05003184 struct weston_surface *parent;
Daniel Stoneb2104682012-05-30 16:31:56 +01003185 struct weston_seat *seat;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003186 struct workspace *ws;
Juan Zhao96879df2012-02-07 08:45:41 +08003187 int panel_height = 0;
Pekka Paalanen57da4a82011-11-23 16:42:16 +02003188
Pekka Paalanen60921e52012-01-25 15:55:43 +02003189 surface->geometry.width = width;
3190 surface->geometry.height = height;
Pekka Paalanenc3ce7382013-03-08 14:56:49 +02003191 weston_surface_geometry_dirty(surface);
Pekka Paalanen77346a62011-11-30 16:26:35 +02003192
3193 /* initial positioning, see also configure() */
3194 switch (surface_type) {
3195 case SHELL_SURFACE_TOPLEVEL:
Rob Bradfordac63e5b2012-08-13 14:07:52 +01003196 weston_surface_set_initial_position(surface, shell);
Pekka Paalanen77346a62011-11-30 16:26:35 +02003197 break;
Alex Wu4539b082012-03-01 12:57:46 +08003198 case SHELL_SURFACE_FULLSCREEN:
Kristian Høgsberge4d3a2b2012-07-09 21:43:22 -04003199 center_on_output(surface, shsurf->fullscreen_output);
Alex Wu4539b082012-03-01 12:57:46 +08003200 shell_map_fullscreen(shsurf);
3201 break;
Juan Zhao96879df2012-02-07 08:45:41 +08003202 case SHELL_SURFACE_MAXIMIZED:
Alex Wu4539b082012-03-01 12:57:46 +08003203 /* use surface configure to set the geometry */
Juan Zhao96879df2012-02-07 08:45:41 +08003204 panel_height = get_output_panel_height(shell,surface->output);
Rob Bradford31b68622012-07-02 19:00:19 +01003205 weston_surface_set_position(surface, shsurf->output->x,
3206 shsurf->output->y + panel_height);
Juan Zhao96879df2012-02-07 08:45:41 +08003207 break;
Tiago Vignatti0f997012012-02-10 16:17:23 +02003208 case SHELL_SURFACE_POPUP:
Kristian Høgsberg3730f362012-04-13 12:40:07 -04003209 shell_map_popup(shsurf);
Rob Bradforddb999382012-12-06 12:07:48 +00003210 break;
Ander Conselvan de Oliveirae9e05152012-02-15 17:02:56 +02003211 case SHELL_SURFACE_NONE:
3212 weston_surface_set_position(surface,
3213 surface->geometry.x + sx,
3214 surface->geometry.y + sy);
Tiago Vignatti0f997012012-02-10 16:17:23 +02003215 break;
Pekka Paalanen77346a62011-11-30 16:26:35 +02003216 default:
3217 ;
3218 }
Kristian Høgsberg75840622011-09-06 13:48:16 -04003219
Pekka Paalanend3dd6e12011-11-16 13:47:33 +02003220 /* surface stacking order, see also activate() */
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02003221 switch (surface_type) {
Kristian Høgsberg60c49542012-03-05 20:51:34 -05003222 case SHELL_SURFACE_POPUP:
3223 case SHELL_SURFACE_TRANSIENT:
Kristian Høgsberg8150b192012-06-27 10:22:58 -04003224 parent = shsurf->parent;
Kristian Høgsberg60c49542012-03-05 20:51:34 -05003225 wl_list_insert(parent->layer_link.prev, &surface->layer_link);
3226 break;
Alex Wu4539b082012-03-01 12:57:46 +08003227 case SHELL_SURFACE_FULLSCREEN:
Ander Conselvan de Oliveiraa1ff53b2012-02-15 17:02:54 +02003228 case SHELL_SURFACE_NONE:
3229 break;
Pekka Paalanen57da4a82011-11-23 16:42:16 +02003230 default:
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003231 ws = get_current_workspace(shell);
3232 wl_list_insert(&ws->layer.surface_list, &surface->layer_link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05003233 break;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02003234 }
3235
Ander Conselvan de Oliveirade56c312012-03-05 15:39:23 +02003236 if (surface_type != SHELL_SURFACE_NONE) {
Ander Conselvan de Oliveira231ba172012-09-14 16:12:04 +03003237 weston_surface_update_transform(surface);
Ander Conselvan de Oliveirade56c312012-03-05 15:39:23 +02003238 if (surface_type == SHELL_SURFACE_MAXIMIZED)
3239 surface->output = shsurf->output;
3240 }
Kristian Høgsberg2f88a402011-12-04 15:32:59 -05003241
Juan Zhao7bb92f02011-12-15 11:31:51 -05003242 switch (surface_type) {
Juan Zhao7bb92f02011-12-15 11:31:51 -05003243 case SHELL_SURFACE_TRANSIENT:
Tiago Vignatti99aeb1e2012-05-23 22:06:26 +03003244 if (shsurf->transient.flags ==
3245 WL_SHELL_SURFACE_TRANSIENT_INACTIVE)
3246 break;
3247 case SHELL_SURFACE_TOPLEVEL:
Juan Zhao7bb92f02011-12-15 11:31:51 -05003248 case SHELL_SURFACE_FULLSCREEN:
Juan Zhao96879df2012-02-07 08:45:41 +08003249 case SHELL_SURFACE_MAXIMIZED:
Daniel Stoneb2104682012-05-30 16:31:56 +01003250 if (!shell->locked) {
3251 wl_list_for_each(seat, &compositor->seat_list, link)
3252 activate(shell, surface, seat);
3253 }
Juan Zhao7bb92f02011-12-15 11:31:51 -05003254 break;
3255 default:
3256 break;
3257 }
3258
Kristian Høgsberg2f88a402011-12-04 15:32:59 -05003259 if (surface_type == SHELL_SURFACE_TOPLEVEL)
Juan Zhaoe10d2792012-04-25 19:09:52 +08003260 {
3261 switch (shell->win_animation_type) {
3262 case ANIMATION_FADE:
Ander Conselvan de Oliveiraee416052013-02-21 18:35:17 +02003263 weston_fade_run(surface, 0.0, 1.0, 200.0, NULL, NULL);
Juan Zhaoe10d2792012-04-25 19:09:52 +08003264 break;
3265 case ANIMATION_ZOOM:
3266 weston_zoom_run(surface, 0.8, 1.0, NULL, NULL);
3267 break;
3268 default:
3269 break;
3270 }
3271 }
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05003272}
3273
3274static void
Tiago Vignattibe143262012-04-16 17:31:41 +03003275configure(struct desktop_shell *shell, struct weston_surface *surface,
John Kåre Alsaker490d02a2012-09-30 02:57:21 +02003276 float x, float y, int32_t width, int32_t height)
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05003277{
Pekka Paalanen77346a62011-11-30 16:26:35 +02003278 enum shell_surface_type surface_type = SHELL_SURFACE_NONE;
3279 struct shell_surface *shsurf;
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05003280
Pekka Paalanen77346a62011-11-30 16:26:35 +02003281 shsurf = get_shell_surface(surface);
3282 if (shsurf)
3283 surface_type = shsurf->type;
3284
Pekka Paalanenc3ce7382013-03-08 14:56:49 +02003285 weston_surface_configure(surface, x, y, width, height);
Pekka Paalanen77346a62011-11-30 16:26:35 +02003286
3287 switch (surface_type) {
Alex Wu4539b082012-03-01 12:57:46 +08003288 case SHELL_SURFACE_FULLSCREEN:
Alex Wubd3354b2012-04-17 17:20:49 +08003289 shell_stack_fullscreen(shsurf);
Alex Wu4539b082012-03-01 12:57:46 +08003290 shell_configure_fullscreen(shsurf);
Alex Wu4539b082012-03-01 12:57:46 +08003291 break;
Juan Zhao96879df2012-02-07 08:45:41 +08003292 case SHELL_SURFACE_MAXIMIZED:
Alex Wu4539b082012-03-01 12:57:46 +08003293 /* setting x, y and using configure to change that geometry */
Kristian Høgsberg6a8b5532012-02-16 23:43:59 -05003294 surface->geometry.x = surface->output->x;
3295 surface->geometry.y = surface->output->y +
3296 get_output_panel_height(shell,surface->output);
Juan Zhao96879df2012-02-07 08:45:41 +08003297 break;
Alex Wu4539b082012-03-01 12:57:46 +08003298 case SHELL_SURFACE_TOPLEVEL:
3299 break;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -05003300 default:
3301 break;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04003302 }
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05003303
Alex Wu4539b082012-03-01 12:57:46 +08003304 /* XXX: would a fullscreen surface need the same handling? */
Kristian Høgsberg6a8b5532012-02-16 23:43:59 -05003305 if (surface->output) {
Ander Conselvan de Oliveira231ba172012-09-14 16:12:04 +03003306 weston_surface_update_transform(surface);
Pekka Paalanen77346a62011-11-30 16:26:35 +02003307
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04003308 if (surface_type == SHELL_SURFACE_MAXIMIZED)
Juan Zhao96879df2012-02-07 08:45:41 +08003309 surface->output = shsurf->output;
Pekka Paalanen77346a62011-11-30 16:26:35 +02003310 }
Kristian Høgsberg07937562011-04-12 17:25:42 -04003311}
3312
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03003313static void
Giulio Camuffo184df502013-02-21 11:29:21 +01003314shell_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy, int32_t width, int32_t height)
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03003315{
Ander Conselvan de Oliveira7fb9f952012-03-27 17:36:42 +03003316 struct shell_surface *shsurf = get_shell_surface(es);
Tiago Vignattibe143262012-04-16 17:31:41 +03003317 struct desktop_shell *shell = shsurf->shell;
Giulio Camuffo184df502013-02-21 11:29:21 +01003318
Tiago Vignatti70e5c9c2012-05-07 15:23:07 +03003319 int type_changed = 0;
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03003320
Giulio Camuffo5085a752013-03-25 21:42:45 +01003321 if (!weston_surface_is_mapped(es) && !wl_list_empty(&shsurf->popup.grab_link)) {
3322 remove_popup_grab(shsurf);
3323 }
3324
Giulio Camuffo184df502013-02-21 11:29:21 +01003325 if (width == 0)
3326 return;
3327
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04003328 if (shsurf->next_type != SHELL_SURFACE_NONE &&
Kristian Høgsbergf7e23d52012-04-27 17:51:59 -04003329 shsurf->type != shsurf->next_type) {
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04003330 set_surface_type(shsurf);
Kristian Høgsbergf7e23d52012-04-27 17:51:59 -04003331 type_changed = 1;
3332 }
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04003333
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03003334 if (!weston_surface_is_mapped(es)) {
Ander Conselvan de Oliveira012b4c72012-11-27 17:03:42 +02003335 map(shell, es, width, height, sx, sy);
Kristian Høgsbergf7e23d52012-04-27 17:51:59 -04003336 } else if (type_changed || sx != 0 || sy != 0 ||
Ander Conselvan de Oliveira012b4c72012-11-27 17:03:42 +02003337 es->geometry.width != width ||
3338 es->geometry.height != height) {
John Kåre Alsaker490d02a2012-09-30 02:57:21 +02003339 float from_x, from_y;
3340 float to_x, to_y;
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03003341
3342 weston_surface_to_global_float(es, 0, 0, &from_x, &from_y);
3343 weston_surface_to_global_float(es, sx, sy, &to_x, &to_y);
3344 configure(shell, es,
3345 es->geometry.x + to_x - from_x,
3346 es->geometry.y + to_y - from_y,
Ander Conselvan de Oliveira012b4c72012-11-27 17:03:42 +02003347 width, height);
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03003348 }
3349}
3350
Tiago Vignattib7dbbd62012-09-25 17:57:01 +03003351static void launch_desktop_shell_process(void *data);
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02003352
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04003353static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05003354desktop_shell_sigchld(struct weston_process *process, int status)
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02003355{
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02003356 uint32_t time;
Tiago Vignattibe143262012-04-16 17:31:41 +03003357 struct desktop_shell *shell =
3358 container_of(process, struct desktop_shell, child.process);
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02003359
3360 shell->child.process.pid = 0;
3361 shell->child.client = NULL; /* already destroyed by wayland */
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02003362
3363 /* if desktop-shell dies more than 5 times in 30 seconds, give up */
3364 time = weston_compositor_get_time();
Kristian Høgsbergf03a6162012-01-17 11:07:42 -05003365 if (time - shell->child.deathstamp > 30000) {
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02003366 shell->child.deathstamp = time;
3367 shell->child.deathcount = 0;
3368 }
3369
3370 shell->child.deathcount++;
3371 if (shell->child.deathcount > 5) {
Martin Minarik6d118362012-06-07 18:01:59 +02003372 weston_log("weston-desktop-shell died, giving up.\n");
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02003373 return;
3374 }
3375
Martin Minarik6d118362012-06-07 18:01:59 +02003376 weston_log("weston-desktop-shell died, respawning...\n");
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02003377 launch_desktop_shell_process(shell);
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02003378}
3379
Tiago Vignattib7dbbd62012-09-25 17:57:01 +03003380static void
3381launch_desktop_shell_process(void *data)
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02003382{
Tiago Vignattib7dbbd62012-09-25 17:57:01 +03003383 struct desktop_shell *shell = data;
Kristian Høgsberg9724b512012-01-03 14:35:49 -05003384 const char *shell_exe = LIBEXECDIR "/weston-desktop-shell";
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02003385
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05003386 shell->child.client = weston_client_launch(shell->compositor,
Pekka Paalanen409ef0a2011-12-02 15:30:21 +02003387 &shell->child.process,
3388 shell_exe,
3389 desktop_shell_sigchld);
3390
3391 if (!shell->child.client)
Tiago Vignattib7dbbd62012-09-25 17:57:01 +03003392 weston_log("not able to start %s\n", shell_exe);
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02003393}
3394
3395static void
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04003396bind_shell(struct wl_client *client, void *data, uint32_t version, uint32_t id)
3397{
Tiago Vignattibe143262012-04-16 17:31:41 +03003398 struct desktop_shell *shell = data;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04003399
3400 wl_client_add_object(client, &wl_shell_interface,
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003401 &shell_implementation, id, shell);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04003402}
3403
Kristian Høgsberg75840622011-09-06 13:48:16 -04003404static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02003405unbind_desktop_shell(struct wl_resource *resource)
3406{
Tiago Vignattibe143262012-04-16 17:31:41 +03003407 struct desktop_shell *shell = resource->data;
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05003408
3409 if (shell->locked)
3410 resume_desktop(shell);
3411
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02003412 shell->child.desktop_shell = NULL;
3413 shell->prepare_event_sent = false;
3414 free(resource);
3415}
3416
3417static void
Kristian Høgsberg75840622011-09-06 13:48:16 -04003418bind_desktop_shell(struct wl_client *client,
3419 void *data, uint32_t version, uint32_t id)
3420{
Tiago Vignattibe143262012-04-16 17:31:41 +03003421 struct desktop_shell *shell = data;
Pekka Paalanenbbe60522011-11-03 14:11:33 +02003422 struct wl_resource *resource;
Kristian Høgsberg75840622011-09-06 13:48:16 -04003423
Pekka Paalanenbbe60522011-11-03 14:11:33 +02003424 resource = wl_client_add_object(client, &desktop_shell_interface,
3425 &desktop_shell_implementation,
3426 id, shell);
3427
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02003428 if (client == shell->child.client) {
3429 resource->destroy = unbind_desktop_shell;
3430 shell->child.desktop_shell = resource;
Pekka Paalanenbbe60522011-11-03 14:11:33 +02003431 return;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02003432 }
Pekka Paalanenbbe60522011-11-03 14:11:33 +02003433
3434 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
3435 "permission to bind desktop_shell denied");
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04003436 wl_resource_destroy(resource);
Kristian Høgsberg75840622011-09-06 13:48:16 -04003437}
3438
Pekka Paalanen6e168112011-11-24 11:34:05 +02003439static void
Giulio Camuffo184df502013-02-21 11:29:21 +01003440screensaver_configure(struct weston_surface *surface, int32_t sx, int32_t sy, int32_t width, int32_t height)
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04003441{
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01003442 struct desktop_shell *shell = surface->configure_private;
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04003443
Giulio Camuffo184df502013-02-21 11:29:21 +01003444 if (width == 0)
3445 return;
3446
Pekka Paalanen3a1d07d2012-12-20 14:02:13 +02003447 /* XXX: starting weston-screensaver beforehand does not work */
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04003448 if (!shell->locked)
3449 return;
3450
3451 center_on_output(surface, surface->output);
3452
3453 if (wl_list_empty(&surface->layer_link)) {
3454 wl_list_insert(shell->lock_layer.surface_list.prev,
3455 &surface->layer_link);
Ander Conselvan de Oliveira231ba172012-09-14 16:12:04 +03003456 weston_surface_update_transform(surface);
Ander Conselvan de Oliveira859e8852013-02-21 18:35:21 +02003457 wl_event_source_timer_update(shell->screensaver.timer,
3458 shell->screensaver.duration);
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02003459 shell_fade(shell, FADE_IN);
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04003460 }
3461}
3462
3463static void
Pekka Paalanen6e168112011-11-24 11:34:05 +02003464screensaver_set_surface(struct wl_client *client,
3465 struct wl_resource *resource,
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04003466 struct wl_resource *surface_resource,
Pekka Paalanen6e168112011-11-24 11:34:05 +02003467 struct wl_resource *output_resource)
3468{
Tiago Vignattibe143262012-04-16 17:31:41 +03003469 struct desktop_shell *shell = resource->data;
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04003470 struct weston_surface *surface = surface_resource->data;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05003471 struct weston_output *output = output_resource->data;
Pekka Paalanen6e168112011-11-24 11:34:05 +02003472
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04003473 surface->configure = screensaver_configure;
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01003474 surface->configure_private = shell;
Pekka Paalanen77346a62011-11-30 16:26:35 +02003475 surface->output = output;
Pekka Paalanen6e168112011-11-24 11:34:05 +02003476}
3477
3478static const struct screensaver_interface screensaver_implementation = {
3479 screensaver_set_surface
3480};
3481
3482static void
3483unbind_screensaver(struct wl_resource *resource)
3484{
Tiago Vignattibe143262012-04-16 17:31:41 +03003485 struct desktop_shell *shell = resource->data;
Pekka Paalanen6e168112011-11-24 11:34:05 +02003486
Pekka Paalanen77346a62011-11-30 16:26:35 +02003487 shell->screensaver.binding = NULL;
Pekka Paalanen6e168112011-11-24 11:34:05 +02003488 free(resource);
3489}
3490
3491static void
3492bind_screensaver(struct wl_client *client,
3493 void *data, uint32_t version, uint32_t id)
3494{
Tiago Vignattibe143262012-04-16 17:31:41 +03003495 struct desktop_shell *shell = data;
Pekka Paalanen6e168112011-11-24 11:34:05 +02003496 struct wl_resource *resource;
3497
3498 resource = wl_client_add_object(client, &screensaver_interface,
3499 &screensaver_implementation,
3500 id, shell);
3501
Pekka Paalanen77346a62011-11-30 16:26:35 +02003502 if (shell->screensaver.binding == NULL) {
Pekka Paalanen6e168112011-11-24 11:34:05 +02003503 resource->destroy = unbind_screensaver;
Pekka Paalanen77346a62011-11-30 16:26:35 +02003504 shell->screensaver.binding = resource;
Pekka Paalanen6e168112011-11-24 11:34:05 +02003505 return;
3506 }
3507
3508 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
3509 "interface object already bound");
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04003510 wl_resource_destroy(resource);
Pekka Paalanen6e168112011-11-24 11:34:05 +02003511}
3512
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003513static void
Giulio Camuffo184df502013-02-21 11:29:21 +01003514input_panel_configure(struct weston_surface *surface, int32_t sx, int32_t sy, int32_t width, int32_t height)
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04003515{
Jan Arne Petersen14da96b2013-04-18 16:47:28 +02003516 struct input_panel_surface *ip_surface = surface->configure_private;
3517 struct desktop_shell *shell = ip_surface->shell;
Jan Arne Petersenaf7b6c92013-01-16 21:26:53 +01003518 struct weston_mode *mode;
Jan Arne Petersenaf7b6c92013-01-16 21:26:53 +01003519 float x, y;
Jan Arne Petersen14da96b2013-04-18 16:47:28 +02003520 uint32_t show_surface = 0;
Jan Arne Petersenaf7b6c92013-01-16 21:26:53 +01003521
Giulio Camuffo184df502013-02-21 11:29:21 +01003522 if (width == 0)
3523 return;
3524
Jan Arne Petersen14da96b2013-04-18 16:47:28 +02003525 if (!weston_surface_is_mapped(surface)) {
3526 if (!shell->showing_input_panels)
3527 return;
3528
Jan Arne Petersen14da96b2013-04-18 16:47:28 +02003529 show_surface = 1;
3530 }
Jan Arne Petersenaf7b6c92013-01-16 21:26:53 +01003531
Jan Arne Petersen7cd29e12013-04-18 16:47:29 +02003532 fprintf(stderr, "%s panel: %d, output: %p\n", __FUNCTION__, ip_surface->panel, ip_surface->output);
Jan Arne Petersen14da96b2013-04-18 16:47:28 +02003533
3534 if (ip_surface->panel) {
3535 x = shell->text_input.surface->geometry.x + shell->text_input.cursor_rectangle.x2;
3536 y = shell->text_input.surface->geometry.y + shell->text_input.cursor_rectangle.y2;
3537 } else {
Jan Arne Petersen7cd29e12013-04-18 16:47:29 +02003538 mode = ip_surface->output->current;
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04003539
Jan Arne Petersen7cd29e12013-04-18 16:47:29 +02003540 x = ip_surface->output->x + (mode->width - width) / 2;
3541 y = ip_surface->output->y + mode->height - height;
3542 }
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04003543
3544 weston_surface_configure(surface,
Jan Arne Petersen14da96b2013-04-18 16:47:28 +02003545 x, y,
Ander Conselvan de Oliveira012b4c72012-11-27 17:03:42 +02003546 width, height);
Jan Arne Petersen14da96b2013-04-18 16:47:28 +02003547
3548 if (show_surface) {
Jan Arne Petersen7cd29e12013-04-18 16:47:29 +02003549 wl_list_insert(&shell->input_panel_layer.surface_list,
3550 &surface->layer_link);
3551 weston_surface_update_transform(surface);
Jan Arne Petersen14da96b2013-04-18 16:47:28 +02003552 weston_surface_damage(surface);
3553 weston_slide_run(surface, surface->geometry.height, 0, NULL, NULL);
3554 }
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04003555}
3556
3557static void
Jan Arne Petersenffbb20f2013-01-16 21:26:55 +01003558destroy_input_panel_surface(struct input_panel_surface *input_panel_surface)
Philipp Brüschweiler88013572012-08-06 13:44:42 +02003559{
Jan Arne Petersenffbb20f2013-01-16 21:26:55 +01003560 wl_list_remove(&input_panel_surface->surface_destroy_listener.link);
Philipp Brüschweiler88013572012-08-06 13:44:42 +02003561 wl_list_remove(&input_panel_surface->link);
3562
Jan Arne Petersenffbb20f2013-01-16 21:26:55 +01003563 input_panel_surface->surface->configure = NULL;
3564
Philipp Brüschweiler88013572012-08-06 13:44:42 +02003565 free(input_panel_surface);
3566}
3567
Jan Arne Petersenffbb20f2013-01-16 21:26:55 +01003568static struct input_panel_surface *
3569get_input_panel_surface(struct weston_surface *surface)
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003570{
Jan Arne Petersenffbb20f2013-01-16 21:26:55 +01003571 if (surface->configure == input_panel_configure) {
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01003572 return surface->configure_private;
Jan Arne Petersenffbb20f2013-01-16 21:26:55 +01003573 } else {
3574 return NULL;
3575 }
3576}
3577
3578static void
3579input_panel_handle_surface_destroy(struct wl_listener *listener, void *data)
3580{
3581 struct input_panel_surface *ipsurface = container_of(listener,
3582 struct input_panel_surface,
3583 surface_destroy_listener);
3584
3585 if (ipsurface->resource.client) {
3586 wl_resource_destroy(&ipsurface->resource);
3587 } else {
3588 wl_signal_emit(&ipsurface->resource.destroy_signal,
3589 &ipsurface->resource);
3590 destroy_input_panel_surface(ipsurface);
3591 }
3592}
3593static struct input_panel_surface *
3594create_input_panel_surface(struct desktop_shell *shell,
3595 struct weston_surface *surface)
3596{
Philipp Brüschweiler88013572012-08-06 13:44:42 +02003597 struct input_panel_surface *input_panel_surface;
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003598
Jan Arne Petersenffbb20f2013-01-16 21:26:55 +01003599 input_panel_surface = calloc(1, sizeof *input_panel_surface);
3600 if (!input_panel_surface)
3601 return NULL;
3602
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04003603 surface->configure = input_panel_configure;
Giulio Camuffo7fe01b12013-03-28 18:02:42 +01003604 surface->configure_private = input_panel_surface;
Philipp Brüschweiler88013572012-08-06 13:44:42 +02003605
Jan Arne Petersenffbb20f2013-01-16 21:26:55 +01003606 input_panel_surface->shell = shell;
Philipp Brüschweiler88013572012-08-06 13:44:42 +02003607
3608 input_panel_surface->surface = surface;
Philipp Brüschweiler88013572012-08-06 13:44:42 +02003609
Jan Arne Petersenffbb20f2013-01-16 21:26:55 +01003610 wl_signal_init(&input_panel_surface->resource.destroy_signal);
3611 input_panel_surface->surface_destroy_listener.notify = input_panel_handle_surface_destroy;
3612 wl_signal_add(&surface->surface.resource.destroy_signal,
3613 &input_panel_surface->surface_destroy_listener);
3614
3615 wl_list_init(&input_panel_surface->link);
3616
3617 return input_panel_surface;
3618}
3619
3620static void
3621input_panel_surface_set_toplevel(struct wl_client *client,
3622 struct wl_resource *resource,
Jan Arne Petersen7cd29e12013-04-18 16:47:29 +02003623 struct wl_resource *output_resource,
Jan Arne Petersenffbb20f2013-01-16 21:26:55 +01003624 uint32_t position)
3625{
3626 struct input_panel_surface *input_panel_surface = resource->data;
3627 struct desktop_shell *shell = input_panel_surface->shell;
Philipp Brüschweiler88013572012-08-06 13:44:42 +02003628
3629 wl_list_insert(&shell->input_panel.surfaces,
3630 &input_panel_surface->link);
Jan Arne Petersen14da96b2013-04-18 16:47:28 +02003631
Jan Arne Petersen7cd29e12013-04-18 16:47:29 +02003632 input_panel_surface->output = output_resource->data;
Jan Arne Petersen14da96b2013-04-18 16:47:28 +02003633 input_panel_surface->panel = 0;
Jan Arne Petersen7cd29e12013-04-18 16:47:29 +02003634
3635 fprintf(stderr, "%s panel: %d, output: %p\n", __FUNCTION__,
3636 input_panel_surface->panel,
3637 input_panel_surface->output);
Jan Arne Petersen14da96b2013-04-18 16:47:28 +02003638}
3639
3640static void
Jan Arne Petersen70d942b2013-04-18 16:47:37 +02003641input_panel_surface_set_overlay_panel(struct wl_client *client,
3642 struct wl_resource *resource)
Jan Arne Petersen14da96b2013-04-18 16:47:28 +02003643{
3644 struct input_panel_surface *input_panel_surface = resource->data;
3645 struct desktop_shell *shell = input_panel_surface->shell;
3646
3647 wl_list_insert(&shell->input_panel.surfaces,
3648 &input_panel_surface->link);
3649
3650 input_panel_surface->panel = 1;
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003651}
3652
Jan Arne Petersencc75ec12013-04-18 16:47:39 +02003653static const struct wl_input_panel_surface_interface input_panel_surface_implementation = {
Jan Arne Petersen14da96b2013-04-18 16:47:28 +02003654 input_panel_surface_set_toplevel,
Jan Arne Petersen70d942b2013-04-18 16:47:37 +02003655 input_panel_surface_set_overlay_panel
Jan Arne Petersenffbb20f2013-01-16 21:26:55 +01003656};
3657
3658static void
3659destroy_input_panel_surface_resource(struct wl_resource *resource)
3660{
3661 struct input_panel_surface *ipsurf = resource->data;
3662
3663 destroy_input_panel_surface(ipsurf);
3664}
3665
3666static void
3667input_panel_get_input_panel_surface(struct wl_client *client,
3668 struct wl_resource *resource,
3669 uint32_t id,
3670 struct wl_resource *surface_resource)
3671{
3672 struct weston_surface *surface = surface_resource->data;
3673 struct desktop_shell *shell = resource->data;
3674 struct input_panel_surface *ipsurf;
3675
3676 if (get_input_panel_surface(surface)) {
3677 wl_resource_post_error(surface_resource,
3678 WL_DISPLAY_ERROR_INVALID_OBJECT,
Jan Arne Petersencc75ec12013-04-18 16:47:39 +02003679 "wl_input_panel::get_input_panel_surface already requested");
Jan Arne Petersenffbb20f2013-01-16 21:26:55 +01003680 return;
3681 }
3682
3683 ipsurf = create_input_panel_surface(shell, surface);
3684 if (!ipsurf) {
3685 wl_resource_post_error(surface_resource,
3686 WL_DISPLAY_ERROR_INVALID_OBJECT,
3687 "surface->configure already set");
3688 return;
3689 }
3690
3691 ipsurf->resource.destroy = destroy_input_panel_surface_resource;
3692 ipsurf->resource.object.id = id;
Jan Arne Petersencc75ec12013-04-18 16:47:39 +02003693 ipsurf->resource.object.interface = &wl_input_panel_surface_interface;
Jan Arne Petersenffbb20f2013-01-16 21:26:55 +01003694 ipsurf->resource.object.implementation =
3695 (void (**)(void)) &input_panel_surface_implementation;
3696 ipsurf->resource.data = ipsurf;
3697
3698 wl_client_add_resource(client, &ipsurf->resource);
3699}
3700
Jan Arne Petersencc75ec12013-04-18 16:47:39 +02003701static const struct wl_input_panel_interface input_panel_implementation = {
Jan Arne Petersenffbb20f2013-01-16 21:26:55 +01003702 input_panel_get_input_panel_surface
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003703};
3704
3705static void
3706unbind_input_panel(struct wl_resource *resource)
3707{
3708 struct desktop_shell *shell = resource->data;
3709
3710 shell->input_panel.binding = NULL;
3711 free(resource);
3712}
3713
3714static void
3715bind_input_panel(struct wl_client *client,
3716 void *data, uint32_t version, uint32_t id)
3717{
3718 struct desktop_shell *shell = data;
3719 struct wl_resource *resource;
3720
Jan Arne Petersencc75ec12013-04-18 16:47:39 +02003721 resource = wl_client_add_object(client, &wl_input_panel_interface,
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003722 &input_panel_implementation,
3723 id, shell);
3724
3725 if (shell->input_panel.binding == NULL) {
3726 resource->destroy = unbind_input_panel;
3727 shell->input_panel.binding = resource;
3728 return;
3729 }
3730
3731 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
3732 "interface object already bound");
3733 wl_resource_destroy(resource);
3734}
3735
Kristian Høgsberg07045392012-02-19 18:52:44 -05003736struct switcher {
Tiago Vignattibe143262012-04-16 17:31:41 +03003737 struct desktop_shell *shell;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003738 struct weston_surface *current;
3739 struct wl_listener listener;
Kristian Høgsberg29139d42013-04-18 15:25:39 -04003740 struct weston_keyboard_grab grab;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003741};
3742
3743static void
3744switcher_next(struct switcher *switcher)
3745{
Kristian Høgsberg07045392012-02-19 18:52:44 -05003746 struct weston_surface *surface;
3747 struct weston_surface *first = NULL, *prev = NULL, *next = NULL;
Kristian Høgsberg32e56862012-04-02 22:18:58 -04003748 struct shell_surface *shsurf;
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04003749 struct workspace *ws = get_current_workspace(switcher->shell);
Kristian Høgsberg07045392012-02-19 18:52:44 -05003750
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04003751 wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
Kristian Høgsberg07045392012-02-19 18:52:44 -05003752 switch (get_shell_surface_type(surface)) {
3753 case SHELL_SURFACE_TOPLEVEL:
3754 case SHELL_SURFACE_FULLSCREEN:
3755 case SHELL_SURFACE_MAXIMIZED:
3756 if (first == NULL)
3757 first = surface;
3758 if (prev == switcher->current)
3759 next = surface;
3760 prev = surface;
Scott Moreau02709af2012-05-22 01:54:10 -06003761 surface->alpha = 0.25;
Pekka Paalanenc3ce7382013-03-08 14:56:49 +02003762 weston_surface_geometry_dirty(surface);
Kristian Høgsberg07045392012-02-19 18:52:44 -05003763 weston_surface_damage(surface);
3764 break;
3765 default:
3766 break;
3767 }
Alex Wu1659daa2012-04-01 20:13:09 +08003768
3769 if (is_black_surface(surface, NULL)) {
Scott Moreau02709af2012-05-22 01:54:10 -06003770 surface->alpha = 0.25;
Pekka Paalanenc3ce7382013-03-08 14:56:49 +02003771 weston_surface_geometry_dirty(surface);
Alex Wu1659daa2012-04-01 20:13:09 +08003772 weston_surface_damage(surface);
3773 }
Kristian Høgsberg07045392012-02-19 18:52:44 -05003774 }
3775
3776 if (next == NULL)
3777 next = first;
3778
Alex Wu07b26062012-03-12 16:06:01 +08003779 if (next == NULL)
3780 return;
3781
Kristian Høgsberg07045392012-02-19 18:52:44 -05003782 wl_list_remove(&switcher->listener.link);
Kristian Høgsberg27e30522012-04-11 23:18:23 -04003783 wl_signal_add(&next->surface.resource.destroy_signal,
3784 &switcher->listener);
Kristian Høgsberg07045392012-02-19 18:52:44 -05003785
3786 switcher->current = next;
Kristian Høgsberga416fa12012-05-21 14:06:52 -04003787 next->alpha = 1.0;
Alex Wu1659daa2012-04-01 20:13:09 +08003788
Kristian Høgsberg32e56862012-04-02 22:18:58 -04003789 shsurf = get_shell_surface(switcher->current);
3790 if (shsurf && shsurf->type ==SHELL_SURFACE_FULLSCREEN)
Kristian Høgsberga416fa12012-05-21 14:06:52 -04003791 shsurf->fullscreen.black_surface->alpha = 1.0;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003792}
3793
3794static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04003795switcher_handle_surface_destroy(struct wl_listener *listener, void *data)
Kristian Høgsberg07045392012-02-19 18:52:44 -05003796{
3797 struct switcher *switcher =
3798 container_of(listener, struct switcher, listener);
3799
3800 switcher_next(switcher);
3801}
3802
3803static void
Daniel Stone351eb612012-05-31 15:27:47 -04003804switcher_destroy(struct switcher *switcher)
Kristian Høgsberg07045392012-02-19 18:52:44 -05003805{
Kristian Høgsberg07045392012-02-19 18:52:44 -05003806 struct weston_surface *surface;
Kristian Høgsberg29139d42013-04-18 15:25:39 -04003807 struct weston_keyboard *keyboard = switcher->grab.keyboard;
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04003808 struct workspace *ws = get_current_workspace(switcher->shell);
Kristian Høgsberg07045392012-02-19 18:52:44 -05003809
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04003810 wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
Kristian Høgsberga416fa12012-05-21 14:06:52 -04003811 surface->alpha = 1.0;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003812 weston_surface_damage(surface);
3813 }
3814
Alex Wu07b26062012-03-12 16:06:01 +08003815 if (switcher->current)
Daniel Stone37816df2012-05-16 18:45:18 +01003816 activate(switcher->shell, switcher->current,
3817 (struct weston_seat *) keyboard->seat);
Kristian Høgsberg07045392012-02-19 18:52:44 -05003818 wl_list_remove(&switcher->listener.link);
Kristian Høgsberg29139d42013-04-18 15:25:39 -04003819 weston_keyboard_end_grab(keyboard);
3820 if (keyboard->input_method_resource)
3821 keyboard->grab = &keyboard->input_method_grab;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003822 free(switcher);
3823}
3824
3825static void
Kristian Høgsberg29139d42013-04-18 15:25:39 -04003826switcher_key(struct weston_keyboard_grab *grab,
Daniel Stonec9785ea2012-05-30 16:31:52 +01003827 uint32_t time, uint32_t key, uint32_t state_w)
Kristian Høgsberg07045392012-02-19 18:52:44 -05003828{
3829 struct switcher *switcher = container_of(grab, struct switcher, grab);
Daniel Stonec9785ea2012-05-30 16:31:52 +01003830 enum wl_keyboard_key_state state = state_w;
Daniel Stone351eb612012-05-31 15:27:47 -04003831
Daniel Stonec9785ea2012-05-30 16:31:52 +01003832 if (key == KEY_TAB && state == WL_KEYBOARD_KEY_STATE_PRESSED)
Daniel Stone351eb612012-05-31 15:27:47 -04003833 switcher_next(switcher);
3834}
3835
3836static void
Kristian Høgsberg29139d42013-04-18 15:25:39 -04003837switcher_modifier(struct weston_keyboard_grab *grab, uint32_t serial,
Daniel Stone351eb612012-05-31 15:27:47 -04003838 uint32_t mods_depressed, uint32_t mods_latched,
3839 uint32_t mods_locked, uint32_t group)
3840{
3841 struct switcher *switcher = container_of(grab, struct switcher, grab);
Daniel Stone37816df2012-05-16 18:45:18 +01003842 struct weston_seat *seat = (struct weston_seat *) grab->keyboard->seat;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003843
Daniel Stone351eb612012-05-31 15:27:47 -04003844 if ((seat->modifier_state & switcher->shell->binding_modifier) == 0)
3845 switcher_destroy(switcher);
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04003846}
Kristian Høgsberg07045392012-02-19 18:52:44 -05003847
Kristian Høgsberg29139d42013-04-18 15:25:39 -04003848static const struct weston_keyboard_grab_interface switcher_grab = {
Daniel Stone351eb612012-05-31 15:27:47 -04003849 switcher_key,
3850 switcher_modifier,
Kristian Høgsberg07045392012-02-19 18:52:44 -05003851};
3852
3853static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01003854switcher_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
3855 void *data)
Kristian Høgsberg07045392012-02-19 18:52:44 -05003856{
Tiago Vignattibe143262012-04-16 17:31:41 +03003857 struct desktop_shell *shell = data;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003858 struct switcher *switcher;
3859
3860 switcher = malloc(sizeof *switcher);
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04003861 switcher->shell = shell;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003862 switcher->current = NULL;
Kristian Høgsberg27e30522012-04-11 23:18:23 -04003863 switcher->listener.notify = switcher_handle_surface_destroy;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003864 wl_list_init(&switcher->listener.link);
3865
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04003866 lower_fullscreen_layer(switcher->shell);
Kristian Høgsberg07045392012-02-19 18:52:44 -05003867 switcher->grab.interface = &switcher_grab;
Kristian Høgsberg29139d42013-04-18 15:25:39 -04003868 weston_keyboard_start_grab(seat->keyboard, &switcher->grab);
3869 weston_keyboard_set_focus(seat->keyboard, NULL);
Kristian Høgsberg07045392012-02-19 18:52:44 -05003870 switcher_next(switcher);
3871}
3872
Pekka Paalanen3c647232011-12-22 13:43:43 +02003873static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01003874backlight_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
3875 void *data)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003876{
3877 struct weston_compositor *compositor = data;
3878 struct weston_output *output;
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03003879 long backlight_new = 0;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003880
3881 /* TODO: we're limiting to simple use cases, where we assume just
3882 * control on the primary display. We'd have to extend later if we
3883 * ever get support for setting backlights on random desktop LCD
3884 * panels though */
3885 output = get_default_output(compositor);
3886 if (!output)
3887 return;
3888
3889 if (!output->set_backlight)
3890 return;
3891
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03003892 if (key == KEY_F9 || key == KEY_BRIGHTNESSDOWN)
3893 backlight_new = output->backlight_current - 25;
3894 else if (key == KEY_F10 || key == KEY_BRIGHTNESSUP)
3895 backlight_new = output->backlight_current + 25;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003896
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03003897 if (backlight_new < 5)
3898 backlight_new = 5;
3899 if (backlight_new > 255)
3900 backlight_new = 255;
3901
3902 output->backlight_current = backlight_new;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003903 output->set_backlight(output, output->backlight_current);
3904}
3905
3906static void
Pekka Paalanen07c91f82012-08-30 16:47:21 -05003907fan_debug_repaint_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
3908 void *data)
3909{
3910 struct desktop_shell *shell = data;
3911 struct weston_compositor *compositor = shell->compositor;
3912 compositor->fan_debug = !compositor->fan_debug;
3913 weston_compositor_damage_all(compositor);
3914}
3915
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02003916struct debug_binding_grab {
Kristian Høgsberg29139d42013-04-18 15:25:39 -04003917 struct weston_keyboard_grab grab;
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02003918 struct weston_seat *seat;
3919 uint32_t key[2];
3920 int key_released[2];
3921};
3922
3923static void
Kristian Høgsberg29139d42013-04-18 15:25:39 -04003924debug_binding_key(struct weston_keyboard_grab *grab, uint32_t time,
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02003925 uint32_t key, uint32_t state)
3926{
3927 struct debug_binding_grab *db = (struct debug_binding_grab *) grab;
3928 struct wl_resource *resource;
3929 struct wl_display *display;
3930 uint32_t serial;
3931 int send = 0, terminate = 0;
3932 int check_binding = 1;
3933 int i;
3934
3935 if (state == WL_KEYBOARD_KEY_STATE_RELEASED) {
3936 /* Do not run bindings on key releases */
3937 check_binding = 0;
3938
3939 for (i = 0; i < 2; i++)
3940 if (key == db->key[i])
3941 db->key_released[i] = 1;
3942
3943 if (db->key_released[0] && db->key_released[1]) {
3944 /* All key releases been swalled so end the grab */
3945 terminate = 1;
3946 } else if (key != db->key[0] && key != db->key[1]) {
3947 /* Should not swallow release of other keys */
3948 send = 1;
3949 }
3950 } else if (key == db->key[0] && !db->key_released[0]) {
3951 /* Do not check bindings for the first press of the binding
3952 * key. This allows it to be used as a debug shortcut.
3953 * We still need to swallow this event. */
3954 check_binding = 0;
3955 } else if (db->key[1]) {
3956 /* If we already ran a binding don't process another one since
3957 * we can't keep track of all the binding keys that were
3958 * pressed in order to swallow the release events. */
3959 send = 1;
3960 check_binding = 0;
3961 }
3962
3963 if (check_binding) {
3964 struct weston_compositor *ec = db->seat->compositor;
3965
3966 if (weston_compositor_run_debug_binding(ec, db->seat, time,
3967 key, state)) {
3968 /* We ran a binding so swallow the press and keep the
3969 * grab to swallow the released too. */
3970 send = 0;
3971 terminate = 0;
3972 db->key[1] = key;
3973 } else {
3974 /* Terminate the grab since the key pressed is not a
3975 * debug binding key. */
3976 send = 1;
3977 terminate = 1;
3978 }
3979 }
3980
3981 if (send) {
3982 resource = grab->keyboard->focus_resource;
3983
3984 if (resource) {
3985 display = wl_client_get_display(resource->client);
3986 serial = wl_display_next_serial(display);
3987 wl_keyboard_send_key(resource, serial, time, key, state);
3988 }
3989 }
3990
3991 if (terminate) {
Kristian Høgsberg29139d42013-04-18 15:25:39 -04003992 weston_keyboard_end_grab(grab->keyboard);
3993 if (grab->keyboard->input_method_resource)
3994 grab->keyboard->grab = &grab->keyboard->input_method_grab;
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02003995 free(db);
3996 }
3997}
3998
3999static void
Kristian Høgsberg29139d42013-04-18 15:25:39 -04004000debug_binding_modifiers(struct weston_keyboard_grab *grab, uint32_t serial,
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02004001 uint32_t mods_depressed, uint32_t mods_latched,
4002 uint32_t mods_locked, uint32_t group)
4003{
4004 struct wl_resource *resource;
4005
4006 resource = grab->keyboard->focus_resource;
4007 if (!resource)
4008 return;
4009
4010 wl_keyboard_send_modifiers(resource, serial, mods_depressed,
4011 mods_latched, mods_locked, group);
4012}
4013
Kristian Høgsberg29139d42013-04-18 15:25:39 -04004014struct weston_keyboard_grab_interface debug_binding_keyboard_grab = {
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02004015 debug_binding_key,
4016 debug_binding_modifiers
4017};
4018
4019static void
4020debug_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
4021{
4022 struct debug_binding_grab *grab;
4023
4024 grab = calloc(1, sizeof *grab);
4025 if (!grab)
4026 return;
4027
4028 grab->seat = (struct weston_seat *) seat;
4029 grab->key[0] = key;
4030 grab->grab.interface = &debug_binding_keyboard_grab;
Kristian Høgsberg29139d42013-04-18 15:25:39 -04004031 weston_keyboard_start_grab(seat->keyboard, &grab->grab);
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02004032}
4033
Kristian Høgsbergb41c0812012-03-04 14:53:40 -05004034static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01004035force_kill_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
4036 void *data)
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04004037{
Philipp Brüschweiler6cef0092012-08-13 21:27:27 +02004038 struct wl_surface *focus_surface;
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04004039 struct wl_client *client;
Tiago Vignatti1d01b012012-09-27 17:48:36 +03004040 struct desktop_shell *shell = data;
4041 struct weston_compositor *compositor = shell->compositor;
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04004042 pid_t pid;
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04004043
Philipp Brüschweiler6cef0092012-08-13 21:27:27 +02004044 focus_surface = seat->keyboard->focus;
4045 if (!focus_surface)
4046 return;
4047
Tiago Vignatti1d01b012012-09-27 17:48:36 +03004048 wl_signal_emit(&compositor->kill_signal, focus_surface);
4049
Philipp Brüschweiler6cef0092012-08-13 21:27:27 +02004050 client = focus_surface->resource.client;
Tiago Vignatti920f1972012-09-27 17:48:35 +03004051 wl_client_get_credentials(client, &pid, NULL, NULL);
4052
4053 /* Skip clients that we launched ourselves (the credentials of
4054 * the socketpair is ours) */
4055 if (pid == getpid())
4056 return;
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04004057
Daniel Stone325fc2d2012-05-30 16:31:58 +01004058 kill(pid, SIGKILL);
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04004059}
4060
4061static void
Jonas Ådahle3cddce2012-06-13 00:01:22 +02004062workspace_up_binding(struct wl_seat *seat, uint32_t time,
4063 uint32_t key, void *data)
4064{
4065 struct desktop_shell *shell = data;
4066 unsigned int new_index = shell->workspaces.current;
4067
Kristian Høgsbergce345b02012-06-25 21:35:29 -04004068 if (shell->locked)
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04004069 return;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02004070 if (new_index != 0)
4071 new_index--;
4072
4073 change_workspace(shell, new_index);
4074}
4075
4076static void
4077workspace_down_binding(struct wl_seat *seat, uint32_t time,
4078 uint32_t key, void *data)
4079{
4080 struct desktop_shell *shell = data;
4081 unsigned int new_index = shell->workspaces.current;
4082
Kristian Høgsbergce345b02012-06-25 21:35:29 -04004083 if (shell->locked)
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04004084 return;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02004085 if (new_index < shell->workspaces.num - 1)
4086 new_index++;
4087
4088 change_workspace(shell, new_index);
4089}
4090
4091static void
4092workspace_f_binding(struct wl_seat *seat, uint32_t time,
4093 uint32_t key, void *data)
4094{
4095 struct desktop_shell *shell = data;
4096 unsigned int new_index;
4097
Kristian Høgsbergce345b02012-06-25 21:35:29 -04004098 if (shell->locked)
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04004099 return;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02004100 new_index = key - KEY_F1;
4101 if (new_index >= shell->workspaces.num)
4102 new_index = shell->workspaces.num - 1;
4103
4104 change_workspace(shell, new_index);
4105}
4106
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02004107static void
4108workspace_move_surface_up_binding(struct wl_seat *seat, uint32_t time,
4109 uint32_t key, void *data)
4110{
4111 struct desktop_shell *shell = data;
4112 unsigned int new_index = shell->workspaces.current;
4113
4114 if (shell->locked)
4115 return;
4116
4117 if (new_index != 0)
4118 new_index--;
4119
4120 take_surface_to_workspace_by_seat(shell, seat, new_index);
4121}
4122
4123static void
4124workspace_move_surface_down_binding(struct wl_seat *seat, uint32_t time,
4125 uint32_t key, void *data)
4126{
4127 struct desktop_shell *shell = data;
4128 unsigned int new_index = shell->workspaces.current;
4129
4130 if (shell->locked)
4131 return;
4132
4133 if (new_index < shell->workspaces.num - 1)
4134 new_index++;
4135
4136 take_surface_to_workspace_by_seat(shell, seat, new_index);
4137}
Jonas Ådahle3cddce2012-06-13 00:01:22 +02004138
4139static void
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04004140shell_destroy(struct wl_listener *listener, void *data)
Pekka Paalanen3c647232011-12-22 13:43:43 +02004141{
Tiago Vignattibe143262012-04-16 17:31:41 +03004142 struct desktop_shell *shell =
4143 container_of(listener, struct desktop_shell, destroy_listener);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02004144 struct workspace **ws;
Pekka Paalanen3c647232011-12-22 13:43:43 +02004145
Pekka Paalanen9cf5cc82012-01-02 16:00:24 +02004146 if (shell->child.client)
4147 wl_client_destroy(shell->child.client);
4148
Ander Conselvan de Oliveiraa4575632013-02-21 18:35:23 +02004149 wl_list_remove(&shell->idle_listener.link);
4150 wl_list_remove(&shell->wake_listener.link);
Jan Arne Petersen42feced2012-06-21 21:52:17 +02004151 wl_list_remove(&shell->show_input_panel_listener.link);
4152 wl_list_remove(&shell->hide_input_panel_listener.link);
Kristian Høgsberg88c16072012-05-16 08:04:19 -04004153
Jonas Ådahle3cddce2012-06-13 00:01:22 +02004154 wl_array_for_each(ws, &shell->workspaces.array)
4155 workspace_destroy(*ws);
4156 wl_array_release(&shell->workspaces.array);
4157
Pekka Paalanen3c647232011-12-22 13:43:43 +02004158 free(shell->screensaver.path);
4159 free(shell);
4160}
4161
Tiago Vignatti0b52d482012-04-20 18:54:25 +03004162static void
4163shell_add_bindings(struct weston_compositor *ec, struct desktop_shell *shell)
4164{
4165 uint32_t mod;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02004166 int i, num_workspace_bindings;
Tiago Vignatti0b52d482012-04-20 18:54:25 +03004167
4168 /* fixed bindings */
Daniel Stone325fc2d2012-05-30 16:31:58 +01004169 weston_compositor_add_key_binding(ec, KEY_BACKSPACE,
4170 MODIFIER_CTRL | MODIFIER_ALT,
4171 terminate_binding, ec);
4172 weston_compositor_add_button_binding(ec, BTN_LEFT, 0,
4173 click_to_activate_binding,
4174 shell);
4175 weston_compositor_add_axis_binding(ec, WL_POINTER_AXIS_VERTICAL_SCROLL,
4176 MODIFIER_SUPER | MODIFIER_ALT,
4177 surface_opacity_binding, NULL);
4178 weston_compositor_add_axis_binding(ec, WL_POINTER_AXIS_VERTICAL_SCROLL,
4179 MODIFIER_SUPER, zoom_axis_binding,
4180 NULL);
Tiago Vignatti0b52d482012-04-20 18:54:25 +03004181
4182 /* configurable bindings */
4183 mod = shell->binding_modifier;
Daniel Stone325fc2d2012-05-30 16:31:58 +01004184 weston_compositor_add_key_binding(ec, KEY_PAGEUP, mod,
4185 zoom_key_binding, NULL);
4186 weston_compositor_add_key_binding(ec, KEY_PAGEDOWN, mod,
4187 zoom_key_binding, NULL);
4188 weston_compositor_add_button_binding(ec, BTN_LEFT, mod, move_binding,
4189 shell);
4190 weston_compositor_add_button_binding(ec, BTN_MIDDLE, mod,
4191 resize_binding, shell);
4192 weston_compositor_add_button_binding(ec, BTN_RIGHT, mod,
4193 rotate_binding, NULL);
4194 weston_compositor_add_key_binding(ec, KEY_TAB, mod, switcher_binding,
4195 shell);
4196 weston_compositor_add_key_binding(ec, KEY_F9, mod, backlight_binding,
4197 ec);
4198 weston_compositor_add_key_binding(ec, KEY_BRIGHTNESSDOWN, 0,
4199 backlight_binding, ec);
4200 weston_compositor_add_key_binding(ec, KEY_F10, mod, backlight_binding,
4201 ec);
4202 weston_compositor_add_key_binding(ec, KEY_BRIGHTNESSUP, 0,
4203 backlight_binding, ec);
Daniel Stone325fc2d2012-05-30 16:31:58 +01004204 weston_compositor_add_key_binding(ec, KEY_K, mod,
4205 force_kill_binding, shell);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02004206 weston_compositor_add_key_binding(ec, KEY_UP, mod,
4207 workspace_up_binding, shell);
4208 weston_compositor_add_key_binding(ec, KEY_DOWN, mod,
4209 workspace_down_binding, shell);
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02004210 weston_compositor_add_key_binding(ec, KEY_UP, mod | MODIFIER_SHIFT,
4211 workspace_move_surface_up_binding,
4212 shell);
4213 weston_compositor_add_key_binding(ec, KEY_DOWN, mod | MODIFIER_SHIFT,
4214 workspace_move_surface_down_binding,
4215 shell);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02004216
4217 /* Add bindings for mod+F[1-6] for workspace 1 to 6. */
4218 if (shell->workspaces.num > 1) {
4219 num_workspace_bindings = shell->workspaces.num;
4220 if (num_workspace_bindings > 6)
4221 num_workspace_bindings = 6;
4222 for (i = 0; i < num_workspace_bindings; i++)
4223 weston_compositor_add_key_binding(ec, KEY_F1 + i, mod,
4224 workspace_f_binding,
4225 shell);
4226 }
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02004227
4228 /* Debug bindings */
4229 weston_compositor_add_key_binding(ec, KEY_SPACE, mod | MODIFIER_SHIFT,
4230 debug_binding, shell);
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02004231 weston_compositor_add_debug_binding(ec, KEY_F,
4232 fan_debug_repaint_binding, shell);
Tiago Vignatti0b52d482012-04-20 18:54:25 +03004233}
4234
Kristian Høgsberg1c562182011-05-02 22:09:20 -04004235WL_EXPORT int
Kristian Høgsbergcb4685b2013-02-20 15:37:49 -05004236module_init(struct weston_compositor *ec,
4237 int *argc, char *argv[], const char *config_file)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05004238{
Kristian Høgsbergf4d2f232012-08-10 10:05:39 -04004239 struct weston_seat *seat;
Tiago Vignattibe143262012-04-16 17:31:41 +03004240 struct desktop_shell *shell;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02004241 struct workspace **pws;
4242 unsigned int i;
Tiago Vignattib7dbbd62012-09-25 17:57:01 +03004243 struct wl_event_loop *loop;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04004244
4245 shell = malloc(sizeof *shell);
4246 if (shell == NULL)
4247 return -1;
4248
Kristian Høgsbergf0d91162011-10-11 22:44:23 -04004249 memset(shell, 0, sizeof *shell);
Kristian Høgsberg75840622011-09-06 13:48:16 -04004250 shell->compositor = ec;
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04004251
4252 shell->destroy_listener.notify = shell_destroy;
4253 wl_signal_add(&ec->destroy_signal, &shell->destroy_listener);
Ander Conselvan de Oliveiraa4575632013-02-21 18:35:23 +02004254 shell->idle_listener.notify = idle_handler;
4255 wl_signal_add(&ec->idle_signal, &shell->idle_listener);
4256 shell->wake_listener.notify = wake_handler;
4257 wl_signal_add(&ec->wake_signal, &shell->wake_listener);
Jan Arne Petersen42feced2012-06-21 21:52:17 +02004258 shell->show_input_panel_listener.notify = show_input_panels;
4259 wl_signal_add(&ec->show_input_panel_signal, &shell->show_input_panel_listener);
4260 shell->hide_input_panel_listener.notify = hide_input_panels;
4261 wl_signal_add(&ec->hide_input_panel_signal, &shell->hide_input_panel_listener);
Jan Arne Petersen14da96b2013-04-18 16:47:28 +02004262 shell->update_input_panel_listener.notify = update_input_panels;
4263 wl_signal_add(&ec->update_input_panel_signal, &shell->update_input_panel_listener);
Scott Moreauff1db4a2012-04-17 19:06:18 -06004264 ec->ping_handler = ping_handler;
Kristian Høgsberg82a1d112012-07-19 14:02:00 -04004265 ec->shell_interface.shell = shell;
Tiago Vignattibc052c92012-04-19 16:18:18 +03004266 ec->shell_interface.create_shell_surface = create_shell_surface;
4267 ec->shell_interface.set_toplevel = set_toplevel;
Tiago Vignatti491bac12012-05-18 16:37:43 -04004268 ec->shell_interface.set_transient = set_transient;
Kristian Høgsbergb810eb52013-02-12 20:07:05 -05004269 ec->shell_interface.set_fullscreen = set_fullscreen;
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04004270 ec->shell_interface.move = surface_move;
Kristian Høgsbergc1693f22012-05-22 16:56:23 -04004271 ec->shell_interface.resize = surface_resize;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05004272
Jan Arne Petersen42feced2012-06-21 21:52:17 +02004273 wl_list_init(&shell->input_panel.surfaces);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02004274
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05004275 weston_layer_init(&shell->fullscreen_layer, &ec->cursor_layer.link);
4276 weston_layer_init(&shell->panel_layer, &shell->fullscreen_layer.link);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02004277 weston_layer_init(&shell->background_layer, &shell->panel_layer.link);
4278 weston_layer_init(&shell->lock_layer, NULL);
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02004279 weston_layer_init(&shell->input_panel_layer, NULL);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02004280
4281 wl_array_init(&shell->workspaces.array);
Jonas Ådahle9d22502012-08-29 22:13:01 +02004282 wl_list_init(&shell->workspaces.client_list);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05004283
Kristian Høgsbergcb4685b2013-02-20 15:37:49 -05004284 shell_configuration(shell, config_file);
Pekka Paalanene955f1e2011-12-07 11:49:52 +02004285
Jonas Ådahle3cddce2012-06-13 00:01:22 +02004286 for (i = 0; i < shell->workspaces.num; i++) {
4287 pws = wl_array_add(&shell->workspaces.array, sizeof *pws);
4288 if (pws == NULL)
4289 return -1;
4290
4291 *pws = workspace_create();
4292 if (*pws == NULL)
4293 return -1;
4294 }
4295 activate_workspace(shell, 0);
4296
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02004297 wl_list_init(&shell->workspaces.anim_sticky_list);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02004298 wl_list_init(&shell->workspaces.animation.link);
4299 shell->workspaces.animation.frame = animate_workspace_change_frame;
4300
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04004301 if (wl_display_add_global(ec->wl_display, &wl_shell_interface,
4302 shell, bind_shell) == NULL)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05004303 return -1;
4304
Kristian Høgsberg75840622011-09-06 13:48:16 -04004305 if (wl_display_add_global(ec->wl_display,
4306 &desktop_shell_interface,
4307 shell, bind_desktop_shell) == NULL)
4308 return -1;
4309
Pekka Paalanen6e168112011-11-24 11:34:05 +02004310 if (wl_display_add_global(ec->wl_display, &screensaver_interface,
4311 shell, bind_screensaver) == NULL)
4312 return -1;
4313
Jan Arne Petersencc75ec12013-04-18 16:47:39 +02004314 if (wl_display_add_global(ec->wl_display, &wl_input_panel_interface,
Jan Arne Petersen42feced2012-06-21 21:52:17 +02004315 shell, bind_input_panel) == NULL)
4316 return -1;
4317
Jonas Ådahle9d22502012-08-29 22:13:01 +02004318 if (wl_display_add_global(ec->wl_display, &workspace_manager_interface,
4319 shell, bind_workspace_manager) == NULL)
4320 return -1;
4321
Kristian Høgsbergf03a6162012-01-17 11:07:42 -05004322 shell->child.deathstamp = weston_compositor_get_time();
Tiago Vignattib7dbbd62012-09-25 17:57:01 +03004323
4324 loop = wl_display_get_event_loop(ec->wl_display);
4325 wl_event_loop_add_idle(loop, launch_desktop_shell_process, shell);
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02004326
Ander Conselvan de Oliveira859e8852013-02-21 18:35:21 +02004327 shell->screensaver.timer =
4328 wl_event_loop_add_timer(loop, screensaver_timeout, shell);
4329
Kristian Høgsbergf4d2f232012-08-10 10:05:39 -04004330 wl_list_for_each(seat, &ec->seat_list, link)
4331 create_pointer_focus_listener(seat);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04004332
Tiago Vignatti0b52d482012-04-20 18:54:25 +03004333 shell_add_bindings(ec, shell);
Kristian Høgsberg07937562011-04-12 17:25:42 -04004334
Ander Conselvan de Oliveira19d10ef2013-02-21 18:35:20 +02004335 shell_fade(shell, FADE_IN);
4336
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05004337 return 0;
4338}