blob: 6610927f6b58a17a6e78ae243f4c12c3093ad3de [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"
Jonas Ådahle9d22502012-08-29 22:13:01 +020038#include "workspaces-server-protocol.h"
Pekka Paalanene955f1e2011-12-07 11:49:52 +020039#include "../shared/config-parser.h"
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050040
Jonas Ådahle3cddce2012-06-13 00:01:22 +020041#define DEFAULT_NUM_WORKSPACES 1
Jonas Ådahl62fcd042012-06-13 00:01:23 +020042#define DEFAULT_WORKSPACE_CHANGE_ANIMATION_LENGTH 200
Jonas Ådahle3cddce2012-06-13 00:01:22 +020043
Juan Zhaoe10d2792012-04-25 19:09:52 +080044enum animation_type {
45 ANIMATION_NONE,
46
47 ANIMATION_ZOOM,
48 ANIMATION_FADE
49};
50
Jonas Ådahl04769742012-06-13 00:01:24 +020051struct focus_state {
52 struct weston_seat *seat;
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -040053 struct workspace *ws;
Jonas Ådahl04769742012-06-13 00:01:24 +020054 struct weston_surface *keyboard_focus;
55 struct wl_list link;
56 struct wl_listener seat_destroy_listener;
57 struct wl_listener surface_destroy_listener;
58};
59
Jonas Ådahle3cddce2012-06-13 00:01:22 +020060struct workspace {
61 struct weston_layer layer;
Jonas Ådahl04769742012-06-13 00:01:24 +020062
63 struct wl_list focus_list;
64 struct wl_listener seat_destroyed_listener;
Jonas Ådahle3cddce2012-06-13 00:01:22 +020065};
66
Philipp Brüschweiler88013572012-08-06 13:44:42 +020067struct input_panel_surface {
68 struct wl_list link;
69 struct weston_surface *surface;
70 struct wl_listener listener;
71};
72
Tiago Vignattibe143262012-04-16 17:31:41 +030073struct desktop_shell {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050074 struct weston_compositor *compositor;
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -040075
76 struct wl_listener lock_listener;
77 struct wl_listener unlock_listener;
78 struct wl_listener destroy_listener;
Jan Arne Petersen42feced2012-06-21 21:52:17 +020079 struct wl_listener show_input_panel_listener;
80 struct wl_listener hide_input_panel_listener;
Pekka Paalanen6cd281a2011-11-03 14:11:32 +020081
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -050082 struct weston_layer fullscreen_layer;
83 struct weston_layer panel_layer;
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -050084 struct weston_layer background_layer;
85 struct weston_layer lock_layer;
Philipp Brüschweiler711fda82012-08-09 18:50:43 +020086 struct weston_layer input_panel_layer;
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -050087
Kristian Høgsbergd56bd902012-06-05 09:58:51 -040088 struct wl_listener pointer_focus_listener;
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +030089 struct weston_surface *grab_surface;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -040090
Pekka Paalanen6cd281a2011-11-03 14:11:32 +020091 struct {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050092 struct weston_process process;
Pekka Paalanen6cd281a2011-11-03 14:11:32 +020093 struct wl_client *client;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +020094 struct wl_resource *desktop_shell;
Pekka Paalanen4d733ee2012-01-17 14:36:27 +020095
96 unsigned deathcount;
97 uint32_t deathstamp;
Pekka Paalanen6cd281a2011-11-03 14:11:32 +020098 } child;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +020099
100 bool locked;
Philipp Brüschweiler711fda82012-08-09 18:50:43 +0200101 bool showing_input_panels;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200102 bool prepare_event_sent;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200103
Kristian Høgsberg730c94d2012-06-26 21:44:35 -0400104 struct weston_surface *lock_surface;
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500105 struct wl_listener lock_surface_listener;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100106
Pekka Paalanen77346a62011-11-30 16:26:35 +0200107 struct {
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200108 struct wl_array array;
109 unsigned int current;
110 unsigned int num;
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200111
Jonas Ådahle9d22502012-08-29 22:13:01 +0200112 struct wl_list client_list;
113
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200114 struct weston_animation animation;
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200115 struct wl_list anim_sticky_list;
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200116 int anim_dir;
117 uint32_t anim_timestamp;
118 double anim_current;
119 struct workspace *anim_from;
120 struct workspace *anim_to;
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200121 } workspaces;
122
123 struct {
Pekka Paalanen3c647232011-12-22 13:43:43 +0200124 char *path;
Pekka Paalanen7296e792011-12-07 16:22:00 +0200125 int duration;
Pekka Paalanen77346a62011-11-30 16:26:35 +0200126 struct wl_resource *binding;
127 struct wl_list surfaces;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500128 struct weston_process process;
Pekka Paalanen77346a62011-11-30 16:26:35 +0200129 } screensaver;
Kristian Høgsbergb41c0812012-03-04 14:53:40 -0500130
Jan Arne Petersen42feced2012-06-21 21:52:17 +0200131 struct {
132 struct wl_resource *binding;
133 struct wl_list surfaces;
134 } input_panel;
135
Tiago Vignatti0b52d482012-04-20 18:54:25 +0300136 uint32_t binding_modifier;
Juan Zhaoe10d2792012-04-25 19:09:52 +0800137 enum animation_type win_animation_type;
Kristian Høgsbergb41c0812012-03-04 14:53:40 -0500138 struct weston_surface *debug_repaint_surface;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400139};
140
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500141enum shell_surface_type {
Pekka Paalanen98262232011-12-01 10:42:22 +0200142 SHELL_SURFACE_NONE,
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500143 SHELL_SURFACE_TOPLEVEL,
144 SHELL_SURFACE_TRANSIENT,
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500145 SHELL_SURFACE_FULLSCREEN,
Juan Zhao96879df2012-02-07 08:45:41 +0800146 SHELL_SURFACE_MAXIMIZED,
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500147 SHELL_SURFACE_POPUP
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200148};
149
Scott Moreauff1db4a2012-04-17 19:06:18 -0600150struct ping_timer {
151 struct wl_event_source *source;
Scott Moreauff1db4a2012-04-17 19:06:18 -0600152 uint32_t serial;
153};
154
Pekka Paalanen56cdea92011-11-23 16:14:12 +0200155struct shell_surface {
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200156 struct wl_resource resource;
157
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500158 struct weston_surface *surface;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200159 struct wl_listener surface_destroy_listener;
Kristian Høgsberg8150b192012-06-27 10:22:58 -0400160 struct weston_surface *parent;
Tiago Vignattibe143262012-04-16 17:31:41 +0300161 struct desktop_shell *shell;
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200162
Kristian Høgsberg7f366e72012-04-27 17:20:01 -0400163 enum shell_surface_type type, next_type;
Kristian Høgsberge7afd912012-05-02 09:47:44 -0400164 char *title, *class;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500165 int32_t saved_x, saved_y;
Alex Wu4539b082012-03-01 12:57:46 +0800166 bool saved_position_valid;
Alex Wu7bcb8bd2012-04-27 09:07:24 +0800167 bool saved_rotation_valid;
Scott Moreauff1db4a2012-04-17 19:06:18 -0600168 int unresponsive;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100169
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500170 struct {
Pekka Paalanen460099f2012-01-20 16:48:25 +0200171 struct weston_transform transform;
Kristian Høgsberg765e27b2012-01-27 13:36:13 -0500172 struct weston_matrix rotation;
Pekka Paalanen460099f2012-01-20 16:48:25 +0200173 } rotation;
174
175 struct {
Scott Moreau447013d2012-02-18 05:05:29 -0700176 struct wl_pointer_grab grab;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500177 int32_t x, y;
Pekka Paalanen938269a2012-02-07 14:19:01 +0200178 struct weston_transform parent_transform;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500179 int32_t initial_up;
Daniel Stone37816df2012-05-16 18:45:18 +0100180 struct wl_seat *seat;
Kristian Høgsberg3730f362012-04-13 12:40:07 -0400181 uint32_t serial;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500182 } popup;
183
Alex Wu4539b082012-03-01 12:57:46 +0800184 struct {
Tiago Vignatti52e598c2012-05-07 15:23:08 +0300185 int32_t x, y;
Tiago Vignatti491bac12012-05-18 16:37:43 -0400186 uint32_t flags;
Tiago Vignatti52e598c2012-05-07 15:23:08 +0300187 } transient;
188
189 struct {
Alex Wu4539b082012-03-01 12:57:46 +0800190 enum wl_shell_surface_fullscreen_method type;
191 struct weston_transform transform; /* matrix from x, y */
192 uint32_t framerate;
193 struct weston_surface *black_surface;
194 } fullscreen;
195
Scott Moreauff1db4a2012-04-17 19:06:18 -0600196 struct ping_timer *ping_timer;
197
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200198 struct weston_transform workspace_transform;
199
Kristian Høgsberg1cbf3262012-02-17 23:49:07 -0500200 struct weston_output *fullscreen_output;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500201 struct weston_output *output;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100202 struct wl_list link;
Kristian Høgsberga61ca062012-05-22 16:05:52 -0400203
204 const struct weston_shell_client *client;
Pekka Paalanen56cdea92011-11-23 16:14:12 +0200205};
206
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300207struct shell_grab {
Scott Moreau447013d2012-02-18 05:05:29 -0700208 struct wl_pointer_grab grab;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300209 struct shell_surface *shsurf;
210 struct wl_listener shsurf_destroy_listener;
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300211 struct wl_pointer *pointer;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300212};
213
214struct weston_move_grab {
215 struct shell_grab base;
Daniel Stone103db7f2012-05-08 17:17:55 +0100216 wl_fixed_t dx, dy;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500217};
218
Pekka Paalanen460099f2012-01-20 16:48:25 +0200219struct rotate_grab {
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300220 struct shell_grab base;
Kristian Høgsberg765e27b2012-01-27 13:36:13 -0500221 struct weston_matrix rotation;
Pekka Paalanen460099f2012-01-20 16:48:25 +0200222 struct {
Kristian Høgsbergb2af93e2012-06-07 20:10:23 -0400223 GLfloat x;
224 GLfloat y;
Pekka Paalanen460099f2012-01-20 16:48:25 +0200225 } center;
226};
227
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400228static void
229activate(struct desktop_shell *shell, struct weston_surface *es,
230 struct weston_seat *seat);
231
232static struct workspace *
233get_current_workspace(struct desktop_shell *shell);
234
Alex Wubd3354b2012-04-17 17:20:49 +0800235static struct shell_surface *
236get_shell_surface(struct weston_surface *surface);
237
238static struct desktop_shell *
239shell_surface_get_shell(struct shell_surface *shsurf);
240
241static bool
242shell_surface_is_top_fullscreen(struct shell_surface *shsurf)
243{
244 struct desktop_shell *shell;
245 struct weston_surface *top_fs_es;
246
247 shell = shell_surface_get_shell(shsurf);
248
249 if (wl_list_empty(&shell->fullscreen_layer.surface_list))
250 return false;
251
252 top_fs_es = container_of(shell->fullscreen_layer.surface_list.next,
253 struct weston_surface,
254 layer_link);
255 return (shsurf == get_shell_surface(top_fs_es));
256}
257
Kristian Høgsberg6af8eb92012-01-25 16:57:11 -0500258static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400259destroy_shell_grab_shsurf(struct wl_listener *listener, void *data)
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300260{
261 struct shell_grab *grab;
262
263 grab = container_of(listener, struct shell_grab,
264 shsurf_destroy_listener);
265
266 grab->shsurf = NULL;
267}
268
269static void
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300270shell_grab_start(struct shell_grab *grab,
271 const struct wl_pointer_grab_interface *interface,
272 struct shell_surface *shsurf,
273 struct wl_pointer *pointer,
274 enum desktop_shell_cursor cursor)
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300275{
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300276 struct desktop_shell *shell = shsurf->shell;
277
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300278 grab->grab.interface = interface;
279 grab->shsurf = shsurf;
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400280 grab->shsurf_destroy_listener.notify = destroy_shell_grab_shsurf;
281 wl_signal_add(&shsurf->resource.destroy_signal,
282 &grab->shsurf_destroy_listener);
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300283
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300284 grab->pointer = pointer;
285 grab->grab.focus = &shsurf->surface->surface;
286
287 wl_pointer_start_grab(pointer, &grab->grab);
288 desktop_shell_send_grab_cursor(shell->child.desktop_shell, cursor);
289 wl_pointer_set_focus(pointer, &shell->grab_surface->surface,
290 wl_fixed_from_int(0), wl_fixed_from_int(0));
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300291}
292
293static void
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300294shell_grab_end(struct shell_grab *grab)
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300295{
Kristian Høgsberg47b5dca2012-06-07 18:08:04 -0400296 if (grab->shsurf)
297 wl_list_remove(&grab->shsurf_destroy_listener.link);
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300298
299 wl_pointer_end_grab(grab->pointer);
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300300}
301
302static void
Alex Wu4539b082012-03-01 12:57:46 +0800303center_on_output(struct weston_surface *surface,
304 struct weston_output *output);
305
Daniel Stone496ca172012-05-30 16:31:42 +0100306static enum weston_keyboard_modifier
Tiago Vignatti0b52d482012-04-20 18:54:25 +0300307get_modifier(char *modifier)
308{
309 if (!modifier)
310 return MODIFIER_SUPER;
311
312 if (!strcmp("ctrl", modifier))
313 return MODIFIER_CTRL;
314 else if (!strcmp("alt", modifier))
315 return MODIFIER_ALT;
316 else if (!strcmp("super", modifier))
317 return MODIFIER_SUPER;
318 else
319 return MODIFIER_SUPER;
320}
321
Juan Zhaoe10d2792012-04-25 19:09:52 +0800322static enum animation_type
323get_animation_type(char *animation)
324{
325 if (!animation)
326 return ANIMATION_NONE;
327
328 if (!strcmp("zoom", animation))
329 return ANIMATION_ZOOM;
330 else if (!strcmp("fade", animation))
331 return ANIMATION_FADE;
332 else
333 return ANIMATION_NONE;
334}
335
Alex Wu4539b082012-03-01 12:57:46 +0800336static void
Tiago Vignattibe143262012-04-16 17:31:41 +0300337shell_configuration(struct desktop_shell *shell)
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200338{
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200339 char *config_file;
Pekka Paalanen7296e792011-12-07 16:22:00 +0200340 char *path = NULL;
341 int duration = 60;
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200342 unsigned int num_workspaces = DEFAULT_NUM_WORKSPACES;
Tiago Vignatti0b52d482012-04-20 18:54:25 +0300343 char *modifier = NULL;
Juan Zhaoe10d2792012-04-25 19:09:52 +0800344 char *win_animation = NULL;
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200345
Kristian Høgsberga4e8b332012-04-20 16:48:21 -0400346 struct config_key shell_keys[] = {
Tiago Vignatti0b52d482012-04-20 18:54:25 +0300347 { "binding-modifier", CONFIG_KEY_STRING, &modifier },
Juan Zhaoe10d2792012-04-25 19:09:52 +0800348 { "animation", CONFIG_KEY_STRING, &win_animation},
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200349 { "num-workspaces",
350 CONFIG_KEY_UNSIGNED_INTEGER, &num_workspaces },
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200351 };
352
Kristian Høgsberga4e8b332012-04-20 16:48:21 -0400353 struct config_key saver_keys[] = {
354 { "path", CONFIG_KEY_STRING, &path },
355 { "duration", CONFIG_KEY_INTEGER, &duration },
356 };
357
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200358 struct config_section cs[] = {
Kristian Høgsberga4e8b332012-04-20 16:48:21 -0400359 { "shell", shell_keys, ARRAY_LENGTH(shell_keys), NULL },
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200360 { "screensaver", saver_keys, ARRAY_LENGTH(saver_keys), NULL },
361 };
362
Tiago Vignatti9a206c42012-03-21 19:49:18 +0200363 config_file = config_file_path("weston.ini");
Kristian Høgsberg6af8eb92012-01-25 16:57:11 -0500364 parse_config_file(config_file, cs, ARRAY_LENGTH(cs), shell);
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200365 free(config_file);
366
Pekka Paalanen7296e792011-12-07 16:22:00 +0200367 shell->screensaver.path = path;
368 shell->screensaver.duration = duration;
Tiago Vignatti0b52d482012-04-20 18:54:25 +0300369 shell->binding_modifier = get_modifier(modifier);
Juan Zhaoe10d2792012-04-25 19:09:52 +0800370 shell->win_animation_type = get_animation_type(win_animation);
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200371 shell->workspaces.num = num_workspaces > 0 ? num_workspaces : 1;
372}
373
374static void
Jonas Ådahl04769742012-06-13 00:01:24 +0200375focus_state_destroy(struct focus_state *state)
376{
377 wl_list_remove(&state->seat_destroy_listener.link);
378 wl_list_remove(&state->surface_destroy_listener.link);
379 free(state);
380}
381
382static void
383focus_state_seat_destroy(struct wl_listener *listener, void *data)
384{
385 struct focus_state *state = container_of(listener,
386 struct focus_state,
387 seat_destroy_listener);
388
389 wl_list_remove(&state->link);
390 focus_state_destroy(state);
391}
392
393static void
394focus_state_surface_destroy(struct wl_listener *listener, void *data)
395{
396 struct focus_state *state = container_of(listener,
397 struct focus_state,
Kristian Høgsbergb8e0d0f2012-07-31 10:30:26 -0400398 surface_destroy_listener);
Kristian Høgsberge3778222012-07-31 17:29:30 -0400399 struct desktop_shell *shell;
400 struct weston_surface *surface, *next;
Jonas Ådahl04769742012-06-13 00:01:24 +0200401
Kristian Høgsberge3778222012-07-31 17:29:30 -0400402 next = NULL;
403 wl_list_for_each(surface, &state->ws->layer.surface_list, layer_link) {
404 if (surface == state->keyboard_focus)
405 continue;
406
407 next = surface;
408 break;
409 }
410
411 if (next) {
412 shell = state->seat->compositor->shell_interface.shell;
413 activate(shell, next, state->seat);
414 } else {
415 wl_list_remove(&state->link);
416 focus_state_destroy(state);
417 }
Jonas Ådahl04769742012-06-13 00:01:24 +0200418}
419
420static struct focus_state *
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400421focus_state_create(struct weston_seat *seat, struct workspace *ws)
Jonas Ådahl04769742012-06-13 00:01:24 +0200422{
Jonas Ådahl04769742012-06-13 00:01:24 +0200423 struct focus_state *state;
Jonas Ådahl04769742012-06-13 00:01:24 +0200424
425 state = malloc(sizeof *state);
426 if (state == NULL)
427 return NULL;
428
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400429 state->ws = ws;
Jonas Ådahl04769742012-06-13 00:01:24 +0200430 state->seat = seat;
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400431 wl_list_insert(&ws->focus_list, &state->link);
Jonas Ådahl04769742012-06-13 00:01:24 +0200432
433 state->seat_destroy_listener.notify = focus_state_seat_destroy;
434 state->surface_destroy_listener.notify = focus_state_surface_destroy;
435 wl_signal_add(&seat->seat.destroy_signal,
436 &state->seat_destroy_listener);
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400437 wl_list_init(&state->surface_destroy_listener.link);
Jonas Ådahl04769742012-06-13 00:01:24 +0200438
439 return state;
440}
441
Jonas Ådahl8538b222012-08-29 22:13:03 +0200442static struct focus_state *
443ensure_focus_state(struct desktop_shell *shell, struct weston_seat *seat)
444{
445 struct workspace *ws = get_current_workspace(shell);
446 struct focus_state *state;
447
448 wl_list_for_each(state, &ws->focus_list, link)
449 if (state->seat == seat)
450 break;
451
452 if (&state->link == &ws->focus_list)
453 state = focus_state_create(seat, ws);
454
455 return state;
456}
457
Jonas Ådahl04769742012-06-13 00:01:24 +0200458static void
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400459restore_focus_state(struct desktop_shell *shell, struct workspace *ws)
Jonas Ådahl04769742012-06-13 00:01:24 +0200460{
461 struct focus_state *state, *next;
Jonas Ådahl56899442012-08-29 22:12:59 +0200462 struct wl_surface *surface;
Jonas Ådahl04769742012-06-13 00:01:24 +0200463
464 wl_list_for_each_safe(state, next, &ws->focus_list, link) {
Jonas Ådahl56899442012-08-29 22:12:59 +0200465 surface = state->keyboard_focus ?
466 &state->keyboard_focus->surface : NULL;
467
468 wl_keyboard_set_focus(state->seat->seat.keyboard, surface);
Jonas Ådahl04769742012-06-13 00:01:24 +0200469 }
470}
471
472static void
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200473replace_focus_state(struct desktop_shell *shell, struct workspace *ws,
474 struct weston_seat *seat)
475{
476 struct focus_state *state;
477 struct wl_surface *surface;
478
479 wl_list_for_each(state, &ws->focus_list, link) {
480 if (state->seat == seat) {
481 surface = seat->seat.keyboard->focus;
482 state->keyboard_focus =
483 (struct weston_surface *) surface;
484 return;
485 }
486 }
487}
488
489static void
490drop_focus_state(struct desktop_shell *shell, struct workspace *ws,
491 struct weston_surface *surface)
492{
493 struct focus_state *state;
494
495 wl_list_for_each(state, &ws->focus_list, link)
496 if (state->keyboard_focus == surface)
497 state->keyboard_focus = NULL;
498}
499
500static void
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200501workspace_destroy(struct workspace *ws)
502{
Jonas Ådahl04769742012-06-13 00:01:24 +0200503 struct focus_state *state, *next;
504
505 wl_list_for_each_safe(state, next, &ws->focus_list, link)
506 focus_state_destroy(state);
507
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200508 free(ws);
509}
510
Jonas Ådahl04769742012-06-13 00:01:24 +0200511static void
512seat_destroyed(struct wl_listener *listener, void *data)
513{
514 struct weston_seat *seat = data;
515 struct focus_state *state, *next;
516 struct workspace *ws = container_of(listener,
517 struct workspace,
518 seat_destroyed_listener);
519
520 wl_list_for_each_safe(state, next, &ws->focus_list, link)
521 if (state->seat == seat)
522 wl_list_remove(&state->link);
523}
524
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200525static struct workspace *
526workspace_create(void)
527{
528 struct workspace *ws = malloc(sizeof *ws);
529 if (ws == NULL)
530 return NULL;
531
532 weston_layer_init(&ws->layer, NULL);
533
Jonas Ådahl04769742012-06-13 00:01:24 +0200534 wl_list_init(&ws->focus_list);
535 wl_list_init(&ws->seat_destroyed_listener.link);
536 ws->seat_destroyed_listener.notify = seat_destroyed;
537
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200538 return ws;
539}
540
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200541static int
542workspace_is_empty(struct workspace *ws)
543{
544 return wl_list_empty(&ws->layer.surface_list);
545}
546
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200547static struct workspace *
548get_workspace(struct desktop_shell *shell, unsigned int index)
549{
550 struct workspace **pws = shell->workspaces.array.data;
551 pws += index;
552 return *pws;
553}
554
555static struct workspace *
556get_current_workspace(struct desktop_shell *shell)
557{
558 return get_workspace(shell, shell->workspaces.current);
559}
560
561static void
562activate_workspace(struct desktop_shell *shell, unsigned int index)
563{
564 struct workspace *ws;
565
566 ws = get_workspace(shell, index);
567 wl_list_insert(&shell->panel_layer.link, &ws->layer.link);
568
569 shell->workspaces.current = index;
570}
571
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200572static unsigned int
573get_output_height(struct weston_output *output)
574{
575 return abs(output->region.extents.y1 - output->region.extents.y2);
576}
577
578static void
579surface_translate(struct weston_surface *surface, double d)
580{
581 struct shell_surface *shsurf = get_shell_surface(surface);
582 struct weston_transform *transform;
583
584 transform = &shsurf->workspace_transform;
585 if (wl_list_empty(&transform->link))
586 wl_list_insert(surface->geometry.transformation_list.prev,
587 &shsurf->workspace_transform.link);
588
589 weston_matrix_init(&shsurf->workspace_transform.matrix);
590 weston_matrix_translate(&shsurf->workspace_transform.matrix,
591 0.0, d, 0.0);
592 surface->geometry.dirty = 1;
593}
594
595static void
596workspace_translate_out(struct workspace *ws, double fraction)
597{
598 struct weston_surface *surface;
599 unsigned int height;
600 double d;
601
602 wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
603 height = get_output_height(surface->output);
604 d = height * fraction;
605
606 surface_translate(surface, d);
607 }
608}
609
610static void
611workspace_translate_in(struct workspace *ws, double fraction)
612{
613 struct weston_surface *surface;
614 unsigned int height;
615 double d;
616
617 wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
618 height = get_output_height(surface->output);
619
620 if (fraction > 0)
621 d = -(height - height * fraction);
622 else
623 d = height + height * fraction;
624
625 surface_translate(surface, d);
626 }
627}
628
629static void
Jonas Ådahle9d22502012-08-29 22:13:01 +0200630broadcast_current_workspace_state(struct desktop_shell *shell)
631{
632 struct wl_resource *resource;
633
634 wl_list_for_each(resource, &shell->workspaces.client_list, link)
635 workspace_manager_send_state(resource,
636 shell->workspaces.current,
637 shell->workspaces.num);
638}
639
640static void
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200641reverse_workspace_change_animation(struct desktop_shell *shell,
642 unsigned int index,
643 struct workspace *from,
644 struct workspace *to)
645{
646 shell->workspaces.current = index;
647
648 shell->workspaces.anim_to = to;
649 shell->workspaces.anim_from = from;
650 shell->workspaces.anim_dir = -1 * shell->workspaces.anim_dir;
651 shell->workspaces.anim_timestamp = 0;
652
Scott Moreau4272e632012-08-13 09:58:41 -0600653 weston_compositor_schedule_repaint(shell->compositor);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200654}
655
656static void
657workspace_deactivate_transforms(struct workspace *ws)
658{
659 struct weston_surface *surface;
660 struct shell_surface *shsurf;
661
662 wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
663 shsurf = get_shell_surface(surface);
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200664 if (!wl_list_empty(&shsurf->workspace_transform.link)) {
665 wl_list_remove(&shsurf->workspace_transform.link);
666 wl_list_init(&shsurf->workspace_transform.link);
667 }
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200668 shsurf->surface->geometry.dirty = 1;
669 }
670}
671
672static void
673finish_workspace_change_animation(struct desktop_shell *shell,
674 struct workspace *from,
675 struct workspace *to)
676{
Scott Moreau4272e632012-08-13 09:58:41 -0600677 weston_compositor_schedule_repaint(shell->compositor);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200678
679 wl_list_remove(&shell->workspaces.animation.link);
680 workspace_deactivate_transforms(from);
681 workspace_deactivate_transforms(to);
682 shell->workspaces.anim_to = NULL;
683
684 wl_list_remove(&shell->workspaces.anim_from->layer.link);
685}
686
687static void
688animate_workspace_change_frame(struct weston_animation *animation,
689 struct weston_output *output, uint32_t msecs)
690{
691 struct desktop_shell *shell =
692 container_of(animation, struct desktop_shell,
693 workspaces.animation);
694 struct workspace *from = shell->workspaces.anim_from;
695 struct workspace *to = shell->workspaces.anim_to;
696 uint32_t t;
697 double x, y;
698
699 if (workspace_is_empty(from) && workspace_is_empty(to)) {
700 finish_workspace_change_animation(shell, from, to);
701 return;
702 }
703
704 if (shell->workspaces.anim_timestamp == 0) {
705 if (shell->workspaces.anim_current == 0.0)
706 shell->workspaces.anim_timestamp = msecs;
707 else
708 shell->workspaces.anim_timestamp =
709 msecs -
710 /* Invers of movement function 'y' below. */
711 (asin(1.0 - shell->workspaces.anim_current) *
712 DEFAULT_WORKSPACE_CHANGE_ANIMATION_LENGTH *
713 M_2_PI);
714 }
715
716 t = msecs - shell->workspaces.anim_timestamp;
717
718 /*
719 * x = [0, π/2]
720 * y(x) = sin(x)
721 */
722 x = t * (1.0/DEFAULT_WORKSPACE_CHANGE_ANIMATION_LENGTH) * M_PI_2;
723 y = sin(x);
724
725 if (t < DEFAULT_WORKSPACE_CHANGE_ANIMATION_LENGTH) {
Scott Moreau4272e632012-08-13 09:58:41 -0600726 weston_compositor_schedule_repaint(shell->compositor);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200727
728 workspace_translate_out(from, shell->workspaces.anim_dir * y);
729 workspace_translate_in(to, shell->workspaces.anim_dir * y);
730 shell->workspaces.anim_current = y;
731
Scott Moreau4272e632012-08-13 09:58:41 -0600732 weston_compositor_schedule_repaint(shell->compositor);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200733 }
Jonas Ådahl04769742012-06-13 00:01:24 +0200734 else
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200735 finish_workspace_change_animation(shell, from, to);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200736}
737
738static void
739animate_workspace_change(struct desktop_shell *shell,
740 unsigned int index,
741 struct workspace *from,
742 struct workspace *to)
743{
744 struct weston_output *output;
745
746 int dir;
747
748 if (index > shell->workspaces.current)
749 dir = -1;
750 else
751 dir = 1;
752
753 shell->workspaces.current = index;
754
755 shell->workspaces.anim_dir = dir;
756 shell->workspaces.anim_from = from;
757 shell->workspaces.anim_to = to;
758 shell->workspaces.anim_current = 0.0;
759 shell->workspaces.anim_timestamp = 0;
760
761 output = container_of(shell->compositor->output_list.next,
762 struct weston_output, link);
763 wl_list_insert(&output->animation_list,
764 &shell->workspaces.animation.link);
765
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200766 wl_list_insert(from->layer.link.prev, &to->layer.link);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200767
768 workspace_translate_in(to, 0);
769
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400770 restore_focus_state(shell, to);
Jonas Ådahl04769742012-06-13 00:01:24 +0200771
Scott Moreau4272e632012-08-13 09:58:41 -0600772 weston_compositor_schedule_repaint(shell->compositor);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200773}
774
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200775static void
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200776update_workspace(struct desktop_shell *shell, unsigned int index,
777 struct workspace *from, struct workspace *to)
778{
779 shell->workspaces.current = index;
780 wl_list_insert(&from->layer.link, &to->layer.link);
781 wl_list_remove(&from->layer.link);
782}
783
784static void
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200785change_workspace(struct desktop_shell *shell, unsigned int index)
786{
787 struct workspace *from;
788 struct workspace *to;
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200789
790 if (index == shell->workspaces.current)
791 return;
792
793 /* Don't change workspace when there is any fullscreen surfaces. */
794 if (!wl_list_empty(&shell->fullscreen_layer.surface_list))
795 return;
796
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200797 from = get_current_workspace(shell);
798 to = get_workspace(shell, index);
799
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200800 if (shell->workspaces.anim_from == to &&
801 shell->workspaces.anim_to == from) {
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200802 restore_focus_state(shell, to);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200803 reverse_workspace_change_animation(shell, index, from, to);
Jonas Ådahle9d22502012-08-29 22:13:01 +0200804 broadcast_current_workspace_state(shell);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200805 return;
806 }
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200807
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200808 if (shell->workspaces.anim_to != NULL)
809 finish_workspace_change_animation(shell,
810 shell->workspaces.anim_from,
811 shell->workspaces.anim_to);
812
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200813 restore_focus_state(shell, to);
Jonas Ådahl04769742012-06-13 00:01:24 +0200814
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200815 if (workspace_is_empty(to) && workspace_is_empty(from))
816 update_workspace(shell, index, from, to);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200817 else
818 animate_workspace_change(shell, index, from, to);
Jonas Ådahle9d22502012-08-29 22:13:01 +0200819
820 broadcast_current_workspace_state(shell);
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200821}
822
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200823static bool
824workspace_has_only(struct workspace *ws, struct weston_surface *surface)
825{
826 struct wl_list *list = &ws->layer.surface_list;
827 struct wl_list *e;
828
829 if (wl_list_empty(list))
830 return false;
831
832 e = list->next;
833
834 if (e->next != list)
835 return false;
836
837 return container_of(e, struct weston_surface, layer_link) == surface;
838}
839
840static void
Jonas Ådahle9d22502012-08-29 22:13:01 +0200841move_surface_to_workspace(struct desktop_shell *shell,
842 struct weston_surface *surface,
843 uint32_t workspace)
844{
845 struct workspace *from;
846 struct workspace *to;
847 struct weston_seat *seat;
848
849 if (workspace == shell->workspaces.current)
850 return;
851
852 from = get_current_workspace(shell);
853 to = get_workspace(shell, workspace);
854
855 wl_list_remove(&surface->layer_link);
856 wl_list_insert(&to->layer.surface_list, &surface->layer_link);
857
858 drop_focus_state(shell, from, surface);
859 wl_list_for_each(seat, &shell->compositor->seat_list, link)
860 if (seat->has_keyboard &&
861 seat->keyboard.focus == &surface->surface)
862 wl_keyboard_set_focus(&seat->keyboard, NULL);
863
864 weston_surface_damage_below(surface);
865}
866
867static void
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200868take_surface_to_workspace_by_seat(struct desktop_shell *shell,
Jonas Ådahle9d22502012-08-29 22:13:01 +0200869 struct wl_seat *wl_seat,
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200870 unsigned int index)
871{
Jonas Ådahle9d22502012-08-29 22:13:01 +0200872 struct weston_seat *seat = (struct weston_seat *) wl_seat;
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200873 struct weston_surface *surface =
Jonas Ådahle9d22502012-08-29 22:13:01 +0200874 (struct weston_surface *) wl_seat->keyboard->focus;
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200875 struct shell_surface *shsurf;
876 struct workspace *from;
877 struct workspace *to;
Jonas Ådahl8538b222012-08-29 22:13:03 +0200878 struct focus_state *state;
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200879
880 if (surface == NULL ||
881 index == shell->workspaces.current)
882 return;
883
884 from = get_current_workspace(shell);
885 to = get_workspace(shell, index);
886
887 wl_list_remove(&surface->layer_link);
888 wl_list_insert(&to->layer.surface_list, &surface->layer_link);
889
Jonas Ådahle9d22502012-08-29 22:13:01 +0200890 replace_focus_state(shell, to, seat);
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200891 drop_focus_state(shell, from, surface);
892
893 if (shell->workspaces.anim_from == to &&
894 shell->workspaces.anim_to == from) {
Jonas Ådahle9d22502012-08-29 22:13:01 +0200895 wl_list_remove(&to->layer.link);
896 wl_list_insert(from->layer.link.prev, &to->layer.link);
897
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200898 reverse_workspace_change_animation(shell, index, from, to);
Jonas Ådahle9d22502012-08-29 22:13:01 +0200899 broadcast_current_workspace_state(shell);
900
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200901 return;
902 }
903
904 if (shell->workspaces.anim_to != NULL)
905 finish_workspace_change_animation(shell,
906 shell->workspaces.anim_from,
907 shell->workspaces.anim_to);
908
909 if (workspace_is_empty(from) &&
910 workspace_has_only(to, surface))
911 update_workspace(shell, index, from, to);
912 else {
913 shsurf = get_shell_surface(surface);
914 if (wl_list_empty(&shsurf->workspace_transform.link))
915 wl_list_insert(&shell->workspaces.anim_sticky_list,
916 &shsurf->workspace_transform.link);
917
918 animate_workspace_change(shell, index, from, to);
919 }
Jonas Ådahle9d22502012-08-29 22:13:01 +0200920
921 broadcast_current_workspace_state(shell);
Jonas Ådahl8538b222012-08-29 22:13:03 +0200922
923 state = ensure_focus_state(shell, seat);
924 if (state != NULL)
925 state->keyboard_focus = surface;
Jonas Ådahle9d22502012-08-29 22:13:01 +0200926}
927
928static void
929workspace_manager_move_surface(struct wl_client *client,
930 struct wl_resource *resource,
931 struct wl_resource *surface_resource,
932 uint32_t workspace)
933{
934 struct desktop_shell *shell = resource->data;
935 struct weston_surface *surface =
936 (struct weston_surface *) surface_resource;
937
938 move_surface_to_workspace(shell, surface, workspace);
939}
940
941static const struct workspace_manager_interface workspace_manager_implementation = {
942 workspace_manager_move_surface,
943};
944
945static void
946unbind_resource(struct wl_resource *resource)
947{
948 wl_list_remove(&resource->link);
949 free(resource);
950}
951
952static void
953bind_workspace_manager(struct wl_client *client,
954 void *data, uint32_t version, uint32_t id)
955{
956 struct desktop_shell *shell = data;
957 struct wl_resource *resource;
958
959 resource = wl_client_add_object(client, &workspace_manager_interface,
960 &workspace_manager_implementation,
961 id, shell);
962
963 if (resource == NULL) {
964 weston_log("couldn't add workspace manager object");
965 return;
966 }
967
968 resource->destroy = unbind_resource;
969 wl_list_insert(&shell->workspaces.client_list, &resource->link);
970
971 workspace_manager_send_state(resource,
972 shell->workspaces.current,
973 shell->workspaces.num);
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200974}
975
Pekka Paalanen56cdea92011-11-23 16:14:12 +0200976static void
Kristian Høgsbergeae5de72012-04-11 22:42:15 -0400977noop_grab_focus(struct wl_pointer_grab *grab,
Daniel Stone103db7f2012-05-08 17:17:55 +0100978 struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y)
Kristian Høgsberg9ddb8262012-01-04 21:30:29 -0500979{
980 grab->focus = NULL;
981}
982
983static void
Scott Moreau447013d2012-02-18 05:05:29 -0700984move_grab_motion(struct wl_pointer_grab *grab,
Daniel Stone103db7f2012-05-08 17:17:55 +0100985 uint32_t time, wl_fixed_t x, wl_fixed_t y)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500986{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500987 struct weston_move_grab *move = (struct weston_move_grab *) grab;
Daniel Stone37816df2012-05-16 18:45:18 +0100988 struct wl_pointer *pointer = grab->pointer;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300989 struct shell_surface *shsurf = move->base.shsurf;
990 struct weston_surface *es;
Daniel Stone37816df2012-05-16 18:45:18 +0100991 int dx = wl_fixed_to_int(pointer->x + move->dx);
992 int dy = wl_fixed_to_int(pointer->y + move->dy);
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300993
994 if (!shsurf)
995 return;
996
997 es = shsurf->surface;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500998
Daniel Stone103db7f2012-05-08 17:17:55 +0100999 weston_surface_configure(es, dx, dy,
Pekka Paalanen60921e52012-01-25 15:55:43 +02001000 es->geometry.width, es->geometry.height);
Kristian Høgsberg6c6fb992012-06-21 12:06:22 -04001001
1002 weston_compositor_schedule_repaint(es->compositor);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001003}
1004
1005static void
Scott Moreau447013d2012-02-18 05:05:29 -07001006move_grab_button(struct wl_pointer_grab *grab,
Daniel Stone4dbadb12012-05-30 16:31:51 +01001007 uint32_t time, uint32_t button, uint32_t state_w)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001008{
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03001009 struct shell_grab *shell_grab = container_of(grab, struct shell_grab,
1010 grab);
Daniel Stone37816df2012-05-16 18:45:18 +01001011 struct wl_pointer *pointer = grab->pointer;
Daniel Stone4dbadb12012-05-30 16:31:51 +01001012 enum wl_pointer_button_state state = state_w;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001013
Daniel Stone4dbadb12012-05-30 16:31:51 +01001014 if (pointer->button_count == 0 &&
1015 state == WL_POINTER_BUTTON_STATE_RELEASED) {
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001016 shell_grab_end(shell_grab);
Kristian Høgsberg9ddb8262012-01-04 21:30:29 -05001017 free(grab);
1018 }
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001019}
1020
Scott Moreau447013d2012-02-18 05:05:29 -07001021static const struct wl_pointer_grab_interface move_grab_interface = {
Kristian Høgsberg9ddb8262012-01-04 21:30:29 -05001022 noop_grab_focus,
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001023 move_grab_motion,
1024 move_grab_button,
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001025};
1026
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -04001027static int
1028surface_move(struct shell_surface *shsurf, struct weston_seat *ws)
1029{
1030 struct weston_move_grab *move;
1031
1032 if (!shsurf)
1033 return -1;
1034
1035 if (shsurf->type == SHELL_SURFACE_FULLSCREEN)
1036 return 0;
1037
1038 move = malloc(sizeof *move);
1039 if (!move)
1040 return -1;
1041
1042 move->dx = wl_fixed_from_double(shsurf->surface->geometry.x) -
1043 ws->seat.pointer->grab_x;
1044 move->dy = wl_fixed_from_double(shsurf->surface->geometry.y) -
1045 ws->seat.pointer->grab_y;
1046
1047 shell_grab_start(&move->base, &move_grab_interface, shsurf,
1048 ws->seat.pointer, DESKTOP_SHELL_CURSOR_MOVE);
1049
1050 return 0;
1051}
1052
1053static void
1054shell_surface_move(struct wl_client *client, struct wl_resource *resource,
1055 struct wl_resource *seat_resource, uint32_t serial)
1056{
1057 struct weston_seat *ws = seat_resource->data;
1058 struct shell_surface *shsurf = resource->data;
1059
1060 if (ws->seat.pointer->button_count == 0 ||
1061 ws->seat.pointer->grab_serial != serial ||
1062 ws->seat.pointer->focus != &shsurf->surface->surface)
1063 return;
1064
1065 if (surface_move(shsurf, ws) < 0)
1066 wl_resource_post_no_memory(resource);
1067}
1068
1069struct weston_resize_grab {
1070 struct shell_grab base;
1071 uint32_t edges;
1072 int32_t width, height;
1073};
1074
1075static void
1076resize_grab_motion(struct wl_pointer_grab *grab,
1077 uint32_t time, wl_fixed_t x, wl_fixed_t y)
1078{
1079 struct weston_resize_grab *resize = (struct weston_resize_grab *) grab;
1080 struct wl_pointer *pointer = grab->pointer;
1081 struct shell_surface *shsurf = resize->base.shsurf;
1082 int32_t width, height;
1083 wl_fixed_t from_x, from_y;
1084 wl_fixed_t to_x, to_y;
1085
1086 if (!shsurf)
1087 return;
1088
1089 weston_surface_from_global_fixed(shsurf->surface,
1090 pointer->grab_x, pointer->grab_y,
1091 &from_x, &from_y);
1092 weston_surface_from_global_fixed(shsurf->surface,
1093 pointer->x, pointer->y, &to_x, &to_y);
1094
1095 width = resize->width;
1096 if (resize->edges & WL_SHELL_SURFACE_RESIZE_LEFT) {
1097 width += wl_fixed_to_int(from_x - to_x);
1098 } else if (resize->edges & WL_SHELL_SURFACE_RESIZE_RIGHT) {
1099 width += wl_fixed_to_int(to_x - from_x);
1100 }
1101
1102 height = resize->height;
1103 if (resize->edges & WL_SHELL_SURFACE_RESIZE_TOP) {
1104 height += wl_fixed_to_int(from_y - to_y);
1105 } else if (resize->edges & WL_SHELL_SURFACE_RESIZE_BOTTOM) {
1106 height += wl_fixed_to_int(to_y - from_y);
1107 }
1108
1109 shsurf->client->send_configure(shsurf->surface,
1110 resize->edges, width, height);
1111}
1112
1113static void
1114send_configure(struct weston_surface *surface,
1115 uint32_t edges, int32_t width, int32_t height)
1116{
1117 struct shell_surface *shsurf = get_shell_surface(surface);
1118
1119 wl_shell_surface_send_configure(&shsurf->resource,
1120 edges, width, height);
1121}
1122
1123static const struct weston_shell_client shell_client = {
1124 send_configure
1125};
1126
1127static void
1128resize_grab_button(struct wl_pointer_grab *grab,
1129 uint32_t time, uint32_t button, uint32_t state_w)
1130{
1131 struct weston_resize_grab *resize = (struct weston_resize_grab *) grab;
1132 struct wl_pointer *pointer = grab->pointer;
1133 enum wl_pointer_button_state state = state_w;
1134
1135 if (pointer->button_count == 0 &&
1136 state == WL_POINTER_BUTTON_STATE_RELEASED) {
1137 shell_grab_end(&resize->base);
1138 free(grab);
1139 }
1140}
1141
1142static const struct wl_pointer_grab_interface resize_grab_interface = {
1143 noop_grab_focus,
1144 resize_grab_motion,
1145 resize_grab_button,
1146};
1147
1148static int
1149surface_resize(struct shell_surface *shsurf,
1150 struct weston_seat *ws, uint32_t edges)
1151{
1152 struct weston_resize_grab *resize;
1153
1154 if (shsurf->type == SHELL_SURFACE_FULLSCREEN)
1155 return 0;
1156
1157 if (edges == 0 || edges > 15 ||
1158 (edges & 3) == 3 || (edges & 12) == 12)
1159 return 0;
1160
1161 resize = malloc(sizeof *resize);
1162 if (!resize)
1163 return -1;
1164
1165 resize->edges = edges;
1166 resize->width = shsurf->surface->geometry.width;
1167 resize->height = shsurf->surface->geometry.height;
1168
1169 shell_grab_start(&resize->base, &resize_grab_interface, shsurf,
1170 ws->seat.pointer, edges);
1171
1172 return 0;
1173}
1174
1175static void
1176shell_surface_resize(struct wl_client *client, struct wl_resource *resource,
1177 struct wl_resource *seat_resource, uint32_t serial,
1178 uint32_t edges)
1179{
1180 struct weston_seat *ws = seat_resource->data;
1181 struct shell_surface *shsurf = resource->data;
1182
1183 if (shsurf->type == SHELL_SURFACE_FULLSCREEN)
1184 return;
1185
1186 if (ws->seat.pointer->button_count == 0 ||
1187 ws->seat.pointer->grab_serial != serial ||
1188 ws->seat.pointer->focus != &shsurf->surface->surface)
1189 return;
1190
1191 if (surface_resize(shsurf, ws, edges) < 0)
1192 wl_resource_post_no_memory(resource);
1193}
1194
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001195static void
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001196busy_cursor_grab_focus(struct wl_pointer_grab *base,
1197 struct wl_surface *surface, int32_t x, int32_t y)
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001198{
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001199 struct shell_grab *grab = (struct shell_grab *) base;
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001200
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001201 if (grab->grab.focus != surface) {
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001202 shell_grab_end(grab);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001203 free(grab);
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001204 }
1205}
1206
1207static void
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001208busy_cursor_grab_motion(struct wl_pointer_grab *grab,
1209 uint32_t time, int32_t x, int32_t y)
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001210{
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001211}
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001212
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001213static void
Kristian Høgsbergbbe98392012-08-01 00:20:21 -04001214busy_cursor_grab_button(struct wl_pointer_grab *base,
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001215 uint32_t time, uint32_t button, uint32_t state)
1216{
Kristian Høgsbergbbe98392012-08-01 00:20:21 -04001217 struct shell_grab *grab = (struct shell_grab *) base;
1218 struct shell_surface *shsurf;
1219 struct weston_surface *surface =
1220 (struct weston_surface *) grab->grab.pointer->current;
1221 struct weston_seat *seat =
1222 (struct weston_seat *) grab->grab.pointer->seat;
1223
1224 shsurf = get_shell_surface(surface);
1225 if (shsurf && button == BTN_LEFT && state) {
1226 activate(shsurf->shell, shsurf->surface, seat);
1227 surface_move(shsurf, seat);
1228 }
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001229}
1230
1231static const struct wl_pointer_grab_interface busy_cursor_grab_interface = {
1232 busy_cursor_grab_focus,
1233 busy_cursor_grab_motion,
1234 busy_cursor_grab_button,
1235};
1236
1237static void
1238set_busy_cursor(struct shell_surface *shsurf, struct wl_pointer *pointer)
1239{
1240 struct shell_grab *grab;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001241
1242 grab = malloc(sizeof *grab);
1243 if (!grab)
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001244 return;
1245
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001246 shell_grab_start(grab, &busy_cursor_grab_interface, shsurf, pointer,
1247 DESKTOP_SHELL_CURSOR_BUSY);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001248}
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001249
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001250static void
1251end_busy_cursor(struct shell_surface *shsurf, struct wl_pointer *pointer)
1252{
1253 struct shell_grab *grab = (struct shell_grab *) pointer->grab;
1254
1255 if (grab->grab.interface == &busy_cursor_grab_interface) {
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001256 shell_grab_end(grab);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001257 free(grab);
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001258 }
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001259}
1260
Scott Moreau9521d5e2012-04-19 13:06:17 -06001261static void
1262ping_timer_destroy(struct shell_surface *shsurf)
1263{
1264 if (!shsurf || !shsurf->ping_timer)
1265 return;
1266
1267 if (shsurf->ping_timer->source)
1268 wl_event_source_remove(shsurf->ping_timer->source);
1269
1270 free(shsurf->ping_timer);
1271 shsurf->ping_timer = NULL;
1272}
1273
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001274static int
Scott Moreauff1db4a2012-04-17 19:06:18 -06001275ping_timeout_handler(void *data)
1276{
1277 struct shell_surface *shsurf = data;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001278 struct weston_seat *seat;
Scott Moreauff1db4a2012-04-17 19:06:18 -06001279
Scott Moreau9521d5e2012-04-19 13:06:17 -06001280 /* Client is not responding */
1281 shsurf->unresponsive = 1;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001282
1283 wl_list_for_each(seat, &shsurf->surface->compositor->seat_list, link)
1284 if (seat->seat.pointer->focus == &shsurf->surface->surface)
1285 set_busy_cursor(shsurf, seat->seat.pointer);
Scott Moreauff1db4a2012-04-17 19:06:18 -06001286
1287 return 1;
1288}
1289
1290static void
1291ping_handler(struct weston_surface *surface, uint32_t serial)
1292{
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001293 struct shell_surface *shsurf = get_shell_surface(surface);
Scott Moreauff1db4a2012-04-17 19:06:18 -06001294 struct wl_event_loop *loop;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001295 int ping_timeout = 200;
Scott Moreauff1db4a2012-04-17 19:06:18 -06001296
1297 if (!shsurf)
1298 return;
Kristian Høgsbergca535c12012-04-21 23:20:07 -04001299 if (!shsurf->resource.client)
1300 return;
Scott Moreauff1db4a2012-04-17 19:06:18 -06001301
Ander Conselvan de Oliveiraeac9a462012-07-16 14:15:48 +03001302 if (shsurf->surface == shsurf->shell->grab_surface)
1303 return;
1304
Scott Moreauff1db4a2012-04-17 19:06:18 -06001305 if (!shsurf->ping_timer) {
Ander Conselvan de Oliveirafb980892012-04-27 13:55:55 +03001306 shsurf->ping_timer = malloc(sizeof *shsurf->ping_timer);
Scott Moreauff1db4a2012-04-17 19:06:18 -06001307 if (!shsurf->ping_timer)
1308 return;
1309
1310 shsurf->ping_timer->serial = serial;
Scott Moreauff1db4a2012-04-17 19:06:18 -06001311 loop = wl_display_get_event_loop(surface->compositor->wl_display);
1312 shsurf->ping_timer->source =
1313 wl_event_loop_add_timer(loop, ping_timeout_handler, shsurf);
1314 wl_event_source_timer_update(shsurf->ping_timer->source, ping_timeout);
1315
1316 wl_shell_surface_send_ping(&shsurf->resource, serial);
1317 }
1318}
1319
1320static void
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001321handle_pointer_focus(struct wl_listener *listener, void *data)
1322{
1323 struct wl_pointer *pointer = data;
1324 struct weston_surface *surface =
1325 (struct weston_surface *) pointer->focus;
1326 struct weston_compositor *compositor;
1327 struct shell_surface *shsurf;
1328 uint32_t serial;
1329
1330 if (!surface)
1331 return;
1332
1333 compositor = surface->compositor;
1334 shsurf = get_shell_surface(surface);
1335
Pekka Paalanen4e1f2ff2012-06-06 16:59:45 +03001336 if (shsurf && shsurf->unresponsive) {
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001337 set_busy_cursor(shsurf, pointer);
1338 } else {
1339 serial = wl_display_next_serial(compositor->wl_display);
1340 ping_handler(surface, serial);
1341 }
1342}
1343
1344static void
Kristian Høgsbergf4d2f232012-08-10 10:05:39 -04001345create_pointer_focus_listener(struct weston_seat *seat)
1346{
1347 struct wl_listener *listener;
1348
1349 if (!seat->seat.pointer)
1350 return;
1351
1352 listener = malloc(sizeof *listener);
1353 listener->notify = handle_pointer_focus;
1354 wl_signal_add(&seat->seat.pointer->focus_signal, listener);
1355}
1356
1357static void
Scott Moreauff1db4a2012-04-17 19:06:18 -06001358shell_surface_pong(struct wl_client *client, struct wl_resource *resource,
1359 uint32_t serial)
1360{
1361 struct shell_surface *shsurf = resource->data;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001362 struct desktop_shell *shell = shsurf->shell;
1363 struct weston_seat *seat;
1364 struct weston_compositor *ec = shsurf->surface->compositor;
1365 struct wl_pointer *pointer;
1366 int was_unresponsive;
Scott Moreauff1db4a2012-04-17 19:06:18 -06001367
Kristian Høgsberg92374e12012-08-11 22:39:12 -04001368 if (shsurf->ping_timer == NULL)
1369 /* Just ignore unsolicited pong. */
1370 return;
1371
Scott Moreauff1db4a2012-04-17 19:06:18 -06001372 if (shsurf->ping_timer->serial == serial) {
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001373 was_unresponsive = shsurf->unresponsive;
Scott Moreauff1db4a2012-04-17 19:06:18 -06001374 shsurf->unresponsive = 0;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001375 if (was_unresponsive) {
1376 /* Received pong from previously unresponsive client */
1377 wl_list_for_each(seat, &ec->seat_list, link) {
1378 pointer = seat->seat.pointer;
1379 if (pointer->focus ==
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001380 &shell->grab_surface->surface &&
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001381 pointer->current ==
1382 &shsurf->surface->surface)
1383 end_busy_cursor(shsurf, pointer);
1384 }
1385 }
Scott Moreau9521d5e2012-04-19 13:06:17 -06001386 ping_timer_destroy(shsurf);
Scott Moreauff1db4a2012-04-17 19:06:18 -06001387 }
1388}
1389
Kristian Høgsberge7afd912012-05-02 09:47:44 -04001390static void
1391shell_surface_set_title(struct wl_client *client,
1392 struct wl_resource *resource, const char *title)
1393{
1394 struct shell_surface *shsurf = resource->data;
1395
1396 free(shsurf->title);
1397 shsurf->title = strdup(title);
1398}
1399
1400static void
1401shell_surface_set_class(struct wl_client *client,
1402 struct wl_resource *resource, const char *class)
1403{
1404 struct shell_surface *shsurf = resource->data;
1405
1406 free(shsurf->class);
1407 shsurf->class = strdup(class);
1408}
1409
Juan Zhao96879df2012-02-07 08:45:41 +08001410static struct weston_output *
1411get_default_output(struct weston_compositor *compositor)
1412{
1413 return container_of(compositor->output_list.next,
1414 struct weston_output, link);
1415}
1416
Alex Wu4539b082012-03-01 12:57:46 +08001417static void
1418shell_unset_fullscreen(struct shell_surface *shsurf)
1419{
1420 /* undo all fullscreen things here */
Alex Wubd3354b2012-04-17 17:20:49 +08001421 if (shsurf->fullscreen.type == WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER &&
1422 shell_surface_is_top_fullscreen(shsurf)) {
1423 weston_output_switch_mode(shsurf->fullscreen_output,
1424 shsurf->fullscreen_output->origin);
1425 }
Alex Wu4539b082012-03-01 12:57:46 +08001426 shsurf->fullscreen.type = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT;
1427 shsurf->fullscreen.framerate = 0;
1428 wl_list_remove(&shsurf->fullscreen.transform.link);
1429 wl_list_init(&shsurf->fullscreen.transform.link);
Alex Wubd3354b2012-04-17 17:20:49 +08001430 if (shsurf->fullscreen.black_surface)
1431 weston_surface_destroy(shsurf->fullscreen.black_surface);
Alex Wu4539b082012-03-01 12:57:46 +08001432 shsurf->fullscreen.black_surface = NULL;
1433 shsurf->fullscreen_output = NULL;
Alex Wu4539b082012-03-01 12:57:46 +08001434 weston_surface_set_position(shsurf->surface,
1435 shsurf->saved_x, shsurf->saved_y);
Alex Wu7bcb8bd2012-04-27 09:07:24 +08001436 if (shsurf->saved_rotation_valid) {
1437 wl_list_insert(&shsurf->surface->geometry.transformation_list,
1438 &shsurf->rotation.transform.link);
1439 shsurf->saved_rotation_valid = false;
1440 }
Alex Wu4539b082012-03-01 12:57:46 +08001441}
1442
Pekka Paalanen98262232011-12-01 10:42:22 +02001443static int
1444reset_shell_surface_type(struct shell_surface *surface)
1445{
1446 switch (surface->type) {
1447 case SHELL_SURFACE_FULLSCREEN:
Alex Wu4539b082012-03-01 12:57:46 +08001448 shell_unset_fullscreen(surface);
Pekka Paalanen98262232011-12-01 10:42:22 +02001449 break;
Juan Zhao96879df2012-02-07 08:45:41 +08001450 case SHELL_SURFACE_MAXIMIZED:
1451 surface->output = get_default_output(surface->surface->compositor);
1452 weston_surface_set_position(surface->surface,
1453 surface->saved_x,
1454 surface->saved_y);
1455 break;
Pekka Paalanen98262232011-12-01 10:42:22 +02001456 case SHELL_SURFACE_NONE:
1457 case SHELL_SURFACE_TOPLEVEL:
1458 case SHELL_SURFACE_TRANSIENT:
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001459 case SHELL_SURFACE_POPUP:
Pekka Paalanen98262232011-12-01 10:42:22 +02001460 break;
1461 }
1462
1463 surface->type = SHELL_SURFACE_NONE;
1464 return 0;
1465}
1466
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001467static void
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001468set_surface_type(struct shell_surface *shsurf)
1469{
1470 struct weston_surface *surface = shsurf->surface;
Kristian Høgsberg8150b192012-06-27 10:22:58 -04001471 struct weston_surface *pes = shsurf->parent;
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001472
1473 reset_shell_surface_type(shsurf);
1474
1475 shsurf->type = shsurf->next_type;
1476 shsurf->next_type = SHELL_SURFACE_NONE;
1477
1478 switch (shsurf->type) {
1479 case SHELL_SURFACE_TOPLEVEL:
1480 break;
1481 case SHELL_SURFACE_TRANSIENT:
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001482 weston_surface_set_position(surface,
Tiago Vignatti52e598c2012-05-07 15:23:08 +03001483 pes->geometry.x + shsurf->transient.x,
1484 pes->geometry.y + shsurf->transient.y);
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001485 break;
1486
1487 case SHELL_SURFACE_MAXIMIZED:
1488 shsurf->saved_x = surface->geometry.x;
1489 shsurf->saved_y = surface->geometry.y;
1490 shsurf->saved_position_valid = true;
1491 break;
1492
1493 case SHELL_SURFACE_FULLSCREEN:
1494 shsurf->saved_x = surface->geometry.x;
1495 shsurf->saved_y = surface->geometry.y;
1496 shsurf->saved_position_valid = true;
1497
1498 if (!wl_list_empty(&shsurf->rotation.transform.link)) {
1499 wl_list_remove(&shsurf->rotation.transform.link);
1500 wl_list_init(&shsurf->rotation.transform.link);
1501 shsurf->surface->geometry.dirty = 1;
1502 shsurf->saved_rotation_valid = true;
1503 }
1504 break;
1505
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001506 default:
1507 break;
1508 }
1509}
1510
1511static void
Tiago Vignattibc052c92012-04-19 16:18:18 +03001512set_toplevel(struct shell_surface *shsurf)
1513{
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001514 shsurf->next_type = SHELL_SURFACE_TOPLEVEL;
Tiago Vignattibc052c92012-04-19 16:18:18 +03001515}
1516
1517static void
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001518shell_surface_set_toplevel(struct wl_client *client,
1519 struct wl_resource *resource)
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001520{
Pekka Paalanen98262232011-12-01 10:42:22 +02001521 struct shell_surface *surface = resource->data;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001522
Tiago Vignattibc052c92012-04-19 16:18:18 +03001523 set_toplevel(surface);
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001524}
1525
1526static void
Tiago Vignatti491bac12012-05-18 16:37:43 -04001527set_transient(struct shell_surface *shsurf,
Kristian Høgsberg8150b192012-06-27 10:22:58 -04001528 struct weston_surface *parent, int x, int y, uint32_t flags)
Tiago Vignatti491bac12012-05-18 16:37:43 -04001529{
1530 /* assign to parents output */
Kristian Høgsberg8150b192012-06-27 10:22:58 -04001531 shsurf->parent = parent;
Tiago Vignatti491bac12012-05-18 16:37:43 -04001532 shsurf->transient.x = x;
1533 shsurf->transient.y = y;
1534 shsurf->transient.flags = flags;
1535 shsurf->next_type = SHELL_SURFACE_TRANSIENT;
1536}
1537
1538static void
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001539shell_surface_set_transient(struct wl_client *client,
1540 struct wl_resource *resource,
1541 struct wl_resource *parent_resource,
1542 int x, int y, uint32_t flags)
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001543{
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001544 struct shell_surface *shsurf = resource->data;
Kristian Høgsberg8150b192012-06-27 10:22:58 -04001545 struct weston_surface *parent = parent_resource->data;
Pekka Paalanen98262232011-12-01 10:42:22 +02001546
Kristian Høgsberg8150b192012-06-27 10:22:58 -04001547 set_transient(shsurf, parent, x, y, flags);
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001548}
1549
Tiago Vignattibe143262012-04-16 17:31:41 +03001550static struct desktop_shell *
Juan Zhao96879df2012-02-07 08:45:41 +08001551shell_surface_get_shell(struct shell_surface *shsurf)
Pekka Paalanenaf0e34c2011-12-02 10:59:17 +02001552{
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04001553 return shsurf->shell;
Juan Zhao96879df2012-02-07 08:45:41 +08001554}
1555
1556static int
Tiago Vignattibe143262012-04-16 17:31:41 +03001557get_output_panel_height(struct desktop_shell *shell,
1558 struct weston_output *output)
Juan Zhao96879df2012-02-07 08:45:41 +08001559{
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001560 struct weston_surface *surface;
Juan Zhao96879df2012-02-07 08:45:41 +08001561 int panel_height = 0;
1562
1563 if (!output)
1564 return 0;
1565
Juan Zhao4ab94682012-07-09 22:24:09 -07001566 wl_list_for_each(surface, &shell->panel_layer.surface_list, layer_link) {
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001567 if (surface->output == output) {
1568 panel_height = surface->geometry.height;
Juan Zhao96879df2012-02-07 08:45:41 +08001569 break;
1570 }
1571 }
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001572
Juan Zhao96879df2012-02-07 08:45:41 +08001573 return panel_height;
1574}
1575
1576static void
1577shell_surface_set_maximized(struct wl_client *client,
1578 struct wl_resource *resource,
1579 struct wl_resource *output_resource )
1580{
1581 struct shell_surface *shsurf = resource->data;
1582 struct weston_surface *es = shsurf->surface;
Tiago Vignattibe143262012-04-16 17:31:41 +03001583 struct desktop_shell *shell = NULL;
Juan Zhao96879df2012-02-07 08:45:41 +08001584 uint32_t edges = 0, panel_height = 0;
1585
1586 /* get the default output, if the client set it as NULL
1587 check whether the ouput is available */
1588 if (output_resource)
1589 shsurf->output = output_resource->data;
Kristian Høgsberg94de6802012-07-18 09:54:04 -04001590 else if (es->output)
1591 shsurf->output = es->output;
Juan Zhao96879df2012-02-07 08:45:41 +08001592 else
1593 shsurf->output = get_default_output(es->compositor);
1594
Tiago Vignattibe143262012-04-16 17:31:41 +03001595 shell = shell_surface_get_shell(shsurf);
Rob Bradford31b68622012-07-02 19:00:19 +01001596 panel_height = get_output_panel_height(shell, shsurf->output);
Juan Zhao96879df2012-02-07 08:45:41 +08001597 edges = WL_SHELL_SURFACE_RESIZE_TOP|WL_SHELL_SURFACE_RESIZE_LEFT;
Kristian Høgsberg0b5cd0c2012-03-04 21:57:37 -05001598
Kristian Høgsberga61ca062012-05-22 16:05:52 -04001599 shsurf->client->send_configure(shsurf->surface, edges,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001600 shsurf->output->width,
1601 shsurf->output->height - panel_height);
Juan Zhao96879df2012-02-07 08:45:41 +08001602
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001603 shsurf->next_type = SHELL_SURFACE_MAXIMIZED;
Pekka Paalanenaf0e34c2011-12-02 10:59:17 +02001604}
1605
Alex Wu21858432012-04-01 20:13:08 +08001606static void
1607black_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy);
1608
Alex Wu4539b082012-03-01 12:57:46 +08001609static struct weston_surface *
1610create_black_surface(struct weston_compositor *ec,
Alex Wu21858432012-04-01 20:13:08 +08001611 struct weston_surface *fs_surface,
Alex Wu4539b082012-03-01 12:57:46 +08001612 GLfloat x, GLfloat y, int w, int h)
1613{
1614 struct weston_surface *surface = NULL;
1615
1616 surface = weston_surface_create(ec);
1617 if (surface == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001618 weston_log("no memory\n");
Alex Wu4539b082012-03-01 12:57:46 +08001619 return NULL;
1620 }
1621
Alex Wu21858432012-04-01 20:13:08 +08001622 surface->configure = black_surface_configure;
1623 surface->private = fs_surface;
Alex Wu4539b082012-03-01 12:57:46 +08001624 weston_surface_configure(surface, x, y, w, h);
1625 weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1);
Kristian Høgsberg61f00f52012-08-03 16:31:36 -04001626 pixman_region32_init_rect(&surface->opaque, 0, 0, w, h);
1627
Alex Wu4539b082012-03-01 12:57:46 +08001628 return surface;
1629}
1630
1631/* Create black surface and append it to the associated fullscreen surface.
1632 * Handle size dismatch and positioning according to the method. */
1633static void
1634shell_configure_fullscreen(struct shell_surface *shsurf)
1635{
1636 struct weston_output *output = shsurf->fullscreen_output;
1637 struct weston_surface *surface = shsurf->surface;
1638 struct weston_matrix *matrix;
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04001639 float scale, output_aspect, surface_aspect, x, y;
Alex Wu4539b082012-03-01 12:57:46 +08001640
Alex Wu4539b082012-03-01 12:57:46 +08001641 if (!shsurf->fullscreen.black_surface)
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05001642 shsurf->fullscreen.black_surface =
1643 create_black_surface(surface->compositor,
Alex Wu21858432012-04-01 20:13:08 +08001644 surface,
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05001645 output->x, output->y,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001646 output->width,
1647 output->height);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05001648
1649 wl_list_remove(&shsurf->fullscreen.black_surface->layer_link);
1650 wl_list_insert(&surface->layer_link,
1651 &shsurf->fullscreen.black_surface->layer_link);
Alex Wu4539b082012-03-01 12:57:46 +08001652 shsurf->fullscreen.black_surface->output = output;
1653
1654 switch (shsurf->fullscreen.type) {
1655 case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT:
Kristian Høgsberga08b5282012-07-20 15:30:36 -04001656 if (surface->buffer)
1657 center_on_output(surface, shsurf->fullscreen_output);
Alex Wu4539b082012-03-01 12:57:46 +08001658 break;
1659 case WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE:
1660 matrix = &shsurf->fullscreen.transform.matrix;
1661 weston_matrix_init(matrix);
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04001662
Scott Moreau1bad5db2012-08-18 01:04:05 -06001663 output_aspect = (float) output->width /
1664 (float) output->height;
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04001665 surface_aspect = (float) surface->geometry.width /
1666 (float) surface->geometry.height;
1667 if (output_aspect < surface_aspect)
Scott Moreau1bad5db2012-08-18 01:04:05 -06001668 scale = (float) output->width /
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04001669 (float) surface->geometry.width;
1670 else
Scott Moreau1bad5db2012-08-18 01:04:05 -06001671 scale = (float) output->height /
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04001672 (float) surface->geometry.height;
1673
Alex Wu4539b082012-03-01 12:57:46 +08001674 weston_matrix_scale(matrix, scale, scale, 1);
1675 wl_list_remove(&shsurf->fullscreen.transform.link);
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04001676 wl_list_insert(&surface->geometry.transformation_list,
Alex Wu4539b082012-03-01 12:57:46 +08001677 &shsurf->fullscreen.transform.link);
Scott Moreau1bad5db2012-08-18 01:04:05 -06001678 x = output->x + (output->width - surface->geometry.width * scale) / 2;
1679 y = output->y + (output->height - surface->geometry.height * scale) / 2;
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04001680 weston_surface_set_position(surface, x, y);
1681
Alex Wu4539b082012-03-01 12:57:46 +08001682 break;
1683 case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER:
Alex Wubd3354b2012-04-17 17:20:49 +08001684 if (shell_surface_is_top_fullscreen(shsurf)) {
1685 struct weston_mode mode = {0,
1686 surface->geometry.width,
1687 surface->geometry.height,
1688 shsurf->fullscreen.framerate};
1689
1690 if (weston_output_switch_mode(output, &mode) == 0) {
1691 weston_surface_configure(shsurf->fullscreen.black_surface,
1692 output->x, output->y,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001693 output->width,
1694 output->height);
Alex Wubd3354b2012-04-17 17:20:49 +08001695 weston_surface_set_position(surface, output->x, output->y);
1696 break;
1697 }
1698 }
Alex Wu4539b082012-03-01 12:57:46 +08001699 break;
1700 case WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL:
1701 break;
1702 default:
1703 break;
1704 }
1705}
1706
1707/* make the fullscreen and black surface at the top */
1708static void
1709shell_stack_fullscreen(struct shell_surface *shsurf)
1710{
Alex Wubd3354b2012-04-17 17:20:49 +08001711 struct weston_output *output = shsurf->fullscreen_output;
Alex Wu4539b082012-03-01 12:57:46 +08001712 struct weston_surface *surface = shsurf->surface;
Tiago Vignattibe143262012-04-16 17:31:41 +03001713 struct desktop_shell *shell = shell_surface_get_shell(shsurf);
Alex Wu4539b082012-03-01 12:57:46 +08001714
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05001715 wl_list_remove(&surface->layer_link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05001716 wl_list_insert(&shell->fullscreen_layer.surface_list,
1717 &surface->layer_link);
Alex Wubd3354b2012-04-17 17:20:49 +08001718 weston_surface_damage(surface);
1719
1720 if (!shsurf->fullscreen.black_surface)
1721 shsurf->fullscreen.black_surface =
1722 create_black_surface(surface->compositor,
1723 surface,
1724 output->x, output->y,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001725 output->width,
1726 output->height);
Alex Wubd3354b2012-04-17 17:20:49 +08001727
1728 wl_list_remove(&shsurf->fullscreen.black_surface->layer_link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05001729 wl_list_insert(&surface->layer_link,
1730 &shsurf->fullscreen.black_surface->layer_link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05001731 weston_surface_damage(shsurf->fullscreen.black_surface);
Alex Wu4539b082012-03-01 12:57:46 +08001732}
1733
1734static void
1735shell_map_fullscreen(struct shell_surface *shsurf)
1736{
Alex Wu4539b082012-03-01 12:57:46 +08001737 shell_stack_fullscreen(shsurf);
Alex Wubd3354b2012-04-17 17:20:49 +08001738 shell_configure_fullscreen(shsurf);
Alex Wu4539b082012-03-01 12:57:46 +08001739}
1740
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001741static void
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001742shell_surface_set_fullscreen(struct wl_client *client,
Kristian Høgsbergf856fd22012-02-16 15:58:14 -05001743 struct wl_resource *resource,
1744 uint32_t method,
1745 uint32_t framerate,
1746 struct wl_resource *output_resource)
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001747{
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001748 struct shell_surface *shsurf = resource->data;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001749 struct weston_surface *es = shsurf->surface;
Alex Wu4539b082012-03-01 12:57:46 +08001750
1751 if (output_resource)
1752 shsurf->output = output_resource->data;
Kristian Høgsberg94de6802012-07-18 09:54:04 -04001753 else if (es->output)
1754 shsurf->output = es->output;
Alex Wu4539b082012-03-01 12:57:46 +08001755 else
1756 shsurf->output = get_default_output(es->compositor);
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001757
Alex Wu4539b082012-03-01 12:57:46 +08001758 shsurf->fullscreen_output = shsurf->output;
1759 shsurf->fullscreen.type = method;
1760 shsurf->fullscreen.framerate = framerate;
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001761 shsurf->next_type = SHELL_SURFACE_FULLSCREEN;
Alex Wu4539b082012-03-01 12:57:46 +08001762
Kristian Høgsberga61ca062012-05-22 16:05:52 -04001763 shsurf->client->send_configure(shsurf->surface, 0,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001764 shsurf->output->width,
1765 shsurf->output->height);
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001766}
1767
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001768static void
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001769popup_grab_focus(struct wl_pointer_grab *grab,
Daniel Stone103db7f2012-05-08 17:17:55 +01001770 struct wl_surface *surface,
1771 wl_fixed_t x,
1772 wl_fixed_t y)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001773{
Daniel Stone37816df2012-05-16 18:45:18 +01001774 struct wl_pointer *pointer = grab->pointer;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001775 struct shell_surface *priv =
1776 container_of(grab, struct shell_surface, popup.grab);
1777 struct wl_client *client = priv->surface->surface.resource.client;
1778
Pekka Paalanencb108432012-01-19 16:25:40 +02001779 if (surface && surface->resource.client == client) {
Daniel Stone37816df2012-05-16 18:45:18 +01001780 wl_pointer_set_focus(pointer, surface, x, y);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001781 grab->focus = surface;
1782 } else {
Daniel Stone37816df2012-05-16 18:45:18 +01001783 wl_pointer_set_focus(pointer, NULL,
1784 wl_fixed_from_int(0),
1785 wl_fixed_from_int(0));
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001786 grab->focus = NULL;
1787 }
1788}
1789
1790static void
Scott Moreau447013d2012-02-18 05:05:29 -07001791popup_grab_motion(struct wl_pointer_grab *grab,
Daniel Stone103db7f2012-05-08 17:17:55 +01001792 uint32_t time, wl_fixed_t sx, wl_fixed_t sy)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001793{
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001794 struct wl_resource *resource;
1795
Daniel Stone37816df2012-05-16 18:45:18 +01001796 resource = grab->pointer->focus_resource;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001797 if (resource)
Daniel Stone37816df2012-05-16 18:45:18 +01001798 wl_pointer_send_motion(resource, time, sx, sy);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001799}
1800
1801static void
Scott Moreau447013d2012-02-18 05:05:29 -07001802popup_grab_button(struct wl_pointer_grab *grab,
Daniel Stone4dbadb12012-05-30 16:31:51 +01001803 uint32_t time, uint32_t button, uint32_t state_w)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001804{
1805 struct wl_resource *resource;
1806 struct shell_surface *shsurf =
1807 container_of(grab, struct shell_surface, popup.grab);
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001808 struct wl_display *display;
Daniel Stone4dbadb12012-05-30 16:31:51 +01001809 enum wl_pointer_button_state state = state_w;
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001810 uint32_t serial;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001811
Daniel Stone37816df2012-05-16 18:45:18 +01001812 resource = grab->pointer->focus_resource;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001813 if (resource) {
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001814 display = wl_client_get_display(resource->client);
1815 serial = wl_display_get_serial(display);
Daniel Stone37816df2012-05-16 18:45:18 +01001816 wl_pointer_send_button(resource, serial, time, button, state);
Daniel Stone4dbadb12012-05-30 16:31:51 +01001817 } else if (state == WL_POINTER_BUTTON_STATE_RELEASED &&
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001818 (shsurf->popup.initial_up ||
Daniel Stone37816df2012-05-16 18:45:18 +01001819 time - shsurf->popup.seat->pointer->grab_time > 500)) {
Kristian Høgsberg0b5cd0c2012-03-04 21:57:37 -05001820 wl_shell_surface_send_popup_done(&shsurf->resource);
Daniel Stone37816df2012-05-16 18:45:18 +01001821 wl_pointer_end_grab(grab->pointer);
1822 shsurf->popup.grab.pointer = NULL;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001823 }
1824
Daniel Stone4dbadb12012-05-30 16:31:51 +01001825 if (state == WL_POINTER_BUTTON_STATE_RELEASED)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001826 shsurf->popup.initial_up = 1;
1827}
1828
Scott Moreau447013d2012-02-18 05:05:29 -07001829static const struct wl_pointer_grab_interface popup_grab_interface = {
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001830 popup_grab_focus,
1831 popup_grab_motion,
1832 popup_grab_button,
1833};
1834
1835static void
Kristian Høgsberg3730f362012-04-13 12:40:07 -04001836shell_map_popup(struct shell_surface *shsurf)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001837{
Daniel Stone37816df2012-05-16 18:45:18 +01001838 struct wl_seat *seat = shsurf->popup.seat;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001839 struct weston_surface *es = shsurf->surface;
Kristian Høgsberg8150b192012-06-27 10:22:58 -04001840 struct weston_surface *parent = shsurf->parent;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001841
1842 es->output = parent->output;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001843 shsurf->popup.grab.interface = &popup_grab_interface;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001844
Pekka Paalanen938269a2012-02-07 14:19:01 +02001845 weston_surface_update_transform(parent);
1846 if (parent->transform.enabled) {
1847 shsurf->popup.parent_transform.matrix =
1848 parent->transform.matrix;
1849 } else {
1850 /* construct x, y translation matrix */
1851 weston_matrix_init(&shsurf->popup.parent_transform.matrix);
1852 shsurf->popup.parent_transform.matrix.d[12] =
1853 parent->geometry.x;
1854 shsurf->popup.parent_transform.matrix.d[13] =
1855 parent->geometry.y;
1856 }
1857 wl_list_insert(es->geometry.transformation_list.prev,
1858 &shsurf->popup.parent_transform.link);
Pekka Paalanen8fb8d3b2012-02-13 13:03:59 +02001859 weston_surface_set_position(es, shsurf->popup.x, shsurf->popup.y);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001860
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001861 shsurf->popup.initial_up = 0;
1862
Kristian Høgsberg3730f362012-04-13 12:40:07 -04001863 /* We don't require the grab to still be active, but if another
1864 * grab has started in the meantime, we end the popup now. */
Daniel Stone37816df2012-05-16 18:45:18 +01001865 if (seat->pointer->grab_serial == shsurf->popup.serial) {
1866 wl_pointer_start_grab(seat->pointer, &shsurf->popup.grab);
Kristian Høgsberg3730f362012-04-13 12:40:07 -04001867 } else {
1868 wl_shell_surface_send_popup_done(&shsurf->resource);
1869 }
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001870}
1871
1872static void
1873shell_surface_set_popup(struct wl_client *client,
1874 struct wl_resource *resource,
Daniel Stone37816df2012-05-16 18:45:18 +01001875 struct wl_resource *seat_resource,
Kristian Høgsberg3730f362012-04-13 12:40:07 -04001876 uint32_t serial,
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001877 struct wl_resource *parent_resource,
1878 int32_t x, int32_t y, uint32_t flags)
1879{
1880 struct shell_surface *shsurf = resource->data;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001881
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001882 shsurf->type = SHELL_SURFACE_POPUP;
1883 shsurf->parent = parent_resource->data;
Daniel Stone37816df2012-05-16 18:45:18 +01001884 shsurf->popup.seat = seat_resource->data;
Kristian Høgsberg3730f362012-04-13 12:40:07 -04001885 shsurf->popup.serial = serial;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001886 shsurf->popup.x = x;
1887 shsurf->popup.y = y;
1888}
1889
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001890static const struct wl_shell_surface_interface shell_surface_implementation = {
Scott Moreauff1db4a2012-04-17 19:06:18 -06001891 shell_surface_pong,
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001892 shell_surface_move,
1893 shell_surface_resize,
1894 shell_surface_set_toplevel,
1895 shell_surface_set_transient,
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001896 shell_surface_set_fullscreen,
Juan Zhao96879df2012-02-07 08:45:41 +08001897 shell_surface_set_popup,
Kristian Høgsberge7afd912012-05-02 09:47:44 -04001898 shell_surface_set_maximized,
1899 shell_surface_set_title,
1900 shell_surface_set_class
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001901};
1902
1903static void
Tiago Vignattibc052c92012-04-19 16:18:18 +03001904destroy_shell_surface(struct shell_surface *shsurf)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001905{
Daniel Stone37816df2012-05-16 18:45:18 +01001906 if (shsurf->popup.grab.pointer)
1907 wl_pointer_end_grab(shsurf->popup.grab.pointer);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001908
Alex Wubd3354b2012-04-17 17:20:49 +08001909 if (shsurf->fullscreen.type == WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER &&
1910 shell_surface_is_top_fullscreen(shsurf)) {
1911 weston_output_switch_mode(shsurf->fullscreen_output,
1912 shsurf->fullscreen_output->origin);
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03001913 }
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001914
Alex Wuaa08e2d2012-03-05 11:01:40 +08001915 if (shsurf->fullscreen.black_surface)
1916 weston_surface_destroy(shsurf->fullscreen.black_surface);
1917
Alex Wubd3354b2012-04-17 17:20:49 +08001918 /* As destroy_resource() use wl_list_for_each_safe(),
1919 * we can always remove the listener.
1920 */
1921 wl_list_remove(&shsurf->surface_destroy_listener.link);
1922 shsurf->surface->configure = NULL;
Scott Moreau9521d5e2012-04-19 13:06:17 -06001923 ping_timer_destroy(shsurf);
Alex Wubd3354b2012-04-17 17:20:49 +08001924
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001925 wl_list_remove(&shsurf->link);
1926 free(shsurf);
1927}
1928
1929static void
Tiago Vignattibc052c92012-04-19 16:18:18 +03001930shell_destroy_shell_surface(struct wl_resource *resource)
1931{
1932 struct shell_surface *shsurf = resource->data;
1933
1934 destroy_shell_surface(shsurf);
1935}
1936
1937static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001938shell_handle_surface_destroy(struct wl_listener *listener, void *data)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001939{
1940 struct shell_surface *shsurf = container_of(listener,
1941 struct shell_surface,
1942 surface_destroy_listener);
1943
Kristian Høgsberg633b1452012-06-07 18:08:47 -04001944 if (shsurf->resource.client) {
Tiago Vignattibc052c92012-04-19 16:18:18 +03001945 wl_resource_destroy(&shsurf->resource);
Kristian Høgsberg633b1452012-06-07 18:08:47 -04001946 } else {
1947 wl_signal_emit(&shsurf->resource.destroy_signal,
1948 &shsurf->resource);
Tiago Vignattibc052c92012-04-19 16:18:18 +03001949 destroy_shell_surface(shsurf);
Kristian Høgsberg633b1452012-06-07 18:08:47 -04001950 }
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001951}
1952
Kristian Høgsbergd8134452012-06-21 12:49:02 -04001953static void
1954shell_surface_configure(struct weston_surface *, int32_t, int32_t);
1955
Pekka Paalanenec2b32f2011-11-28 15:12:34 +02001956static struct shell_surface *
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001957get_shell_surface(struct weston_surface *surface)
Pekka Paalanenec2b32f2011-11-28 15:12:34 +02001958{
Kristian Høgsbergd8134452012-06-21 12:49:02 -04001959 if (surface->configure == shell_surface_configure)
1960 return surface->private;
1961 else
1962 return NULL;
Pekka Paalanenec2b32f2011-11-28 15:12:34 +02001963}
1964
Kristian Høgsberg45ba8692012-05-21 14:27:33 -04001965static struct shell_surface *
Kristian Høgsberga61ca062012-05-22 16:05:52 -04001966create_shell_surface(void *shell, struct weston_surface *surface,
1967 const struct weston_shell_client *client)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001968{
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001969 struct shell_surface *shsurf;
1970
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03001971 if (surface->configure) {
Martin Minarik6d118362012-06-07 18:01:59 +02001972 weston_log("surface->configure already set\n");
Kristian Høgsberg45ba8692012-05-21 14:27:33 -04001973 return NULL;
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03001974 }
1975
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001976 shsurf = calloc(1, sizeof *shsurf);
1977 if (!shsurf) {
Martin Minarik6d118362012-06-07 18:01:59 +02001978 weston_log("no memory to allocate shell surface\n");
Kristian Høgsberg45ba8692012-05-21 14:27:33 -04001979 return NULL;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001980 }
1981
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03001982 surface->configure = shell_surface_configure;
Kristian Høgsbergd8134452012-06-21 12:49:02 -04001983 surface->private = shsurf;
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03001984
Tiago Vignattibc052c92012-04-19 16:18:18 +03001985 shsurf->shell = (struct desktop_shell *) shell;
Scott Moreauff1db4a2012-04-17 19:06:18 -06001986 shsurf->unresponsive = 0;
Alex Wu4539b082012-03-01 12:57:46 +08001987 shsurf->saved_position_valid = false;
Alex Wu7bcb8bd2012-04-27 09:07:24 +08001988 shsurf->saved_rotation_valid = false;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001989 shsurf->surface = surface;
Alex Wu4539b082012-03-01 12:57:46 +08001990 shsurf->fullscreen.type = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT;
1991 shsurf->fullscreen.framerate = 0;
1992 shsurf->fullscreen.black_surface = NULL;
Scott Moreauff1db4a2012-04-17 19:06:18 -06001993 shsurf->ping_timer = NULL;
Alex Wu4539b082012-03-01 12:57:46 +08001994 wl_list_init(&shsurf->fullscreen.transform.link);
1995
Tiago Vignattibc052c92012-04-19 16:18:18 +03001996 wl_signal_init(&shsurf->resource.destroy_signal);
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001997 shsurf->surface_destroy_listener.notify = shell_handle_surface_destroy;
1998 wl_signal_add(&surface->surface.resource.destroy_signal,
1999 &shsurf->surface_destroy_listener);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002000
2001 /* init link so its safe to always remove it in destroy_shell_surface */
2002 wl_list_init(&shsurf->link);
2003
Pekka Paalanen460099f2012-01-20 16:48:25 +02002004 /* empty when not in use */
2005 wl_list_init(&shsurf->rotation.transform.link);
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05002006 weston_matrix_init(&shsurf->rotation.rotation);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002007
Jonas Ådahl62fcd042012-06-13 00:01:23 +02002008 wl_list_init(&shsurf->workspace_transform.link);
2009
Pekka Paalanen98262232011-12-01 10:42:22 +02002010 shsurf->type = SHELL_SURFACE_NONE;
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04002011 shsurf->next_type = SHELL_SURFACE_NONE;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002012
Kristian Høgsberga61ca062012-05-22 16:05:52 -04002013 shsurf->client = client;
2014
Kristian Høgsberg45ba8692012-05-21 14:27:33 -04002015 return shsurf;
Tiago Vignattibc052c92012-04-19 16:18:18 +03002016}
2017
2018static void
2019shell_get_shell_surface(struct wl_client *client,
2020 struct wl_resource *resource,
2021 uint32_t id,
2022 struct wl_resource *surface_resource)
2023{
2024 struct weston_surface *surface = surface_resource->data;
2025 struct desktop_shell *shell = resource->data;
2026 struct shell_surface *shsurf;
2027
2028 if (get_shell_surface(surface)) {
2029 wl_resource_post_error(surface_resource,
Kristian Høgsberg9540ea62012-05-21 14:28:57 -04002030 WL_DISPLAY_ERROR_INVALID_OBJECT,
2031 "desktop_shell::get_shell_surface already requested");
Tiago Vignattibc052c92012-04-19 16:18:18 +03002032 return;
2033 }
2034
Kristian Høgsberga61ca062012-05-22 16:05:52 -04002035 shsurf = create_shell_surface(shell, surface, &shell_client);
Kristian Høgsberg9540ea62012-05-21 14:28:57 -04002036 if (!shsurf) {
2037 wl_resource_post_error(surface_resource,
2038 WL_DISPLAY_ERROR_INVALID_OBJECT,
2039 "surface->configure already set");
2040 return;
2041 }
Tiago Vignattibc052c92012-04-19 16:18:18 +03002042
Kristian Høgsberg9540ea62012-05-21 14:28:57 -04002043 shsurf->resource.destroy = shell_destroy_shell_surface;
2044 shsurf->resource.object.id = id;
2045 shsurf->resource.object.interface = &wl_shell_surface_interface;
2046 shsurf->resource.object.implementation =
2047 (void (**)(void)) &shell_surface_implementation;
2048 shsurf->resource.data = shsurf;
Tiago Vignattibc052c92012-04-19 16:18:18 +03002049
Kristian Høgsberg9540ea62012-05-21 14:28:57 -04002050 wl_client_add_resource(client, &shsurf->resource);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002051}
2052
2053static const struct wl_shell_interface shell_implementation = {
Pekka Paalanen46229672011-11-29 15:49:31 +02002054 shell_get_shell_surface
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05002055};
2056
Kristian Høgsberg07937562011-04-12 17:25:42 -04002057static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002058handle_screensaver_sigchld(struct weston_process *proc, int status)
Pekka Paalanen18027e52011-12-02 16:31:49 +02002059{
2060 proc->pid = 0;
2061}
2062
2063static void
Tiago Vignattibe143262012-04-16 17:31:41 +03002064launch_screensaver(struct desktop_shell *shell)
Pekka Paalanen77346a62011-11-30 16:26:35 +02002065{
2066 if (shell->screensaver.binding)
2067 return;
2068
Pekka Paalanene955f1e2011-12-07 11:49:52 +02002069 if (!shell->screensaver.path)
2070 return;
2071
Kristian Høgsberg32bed572012-03-01 17:11:36 -05002072 if (shell->screensaver.process.pid != 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002073 weston_log("old screensaver still running\n");
Kristian Høgsberg32bed572012-03-01 17:11:36 -05002074 return;
2075 }
2076
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002077 weston_client_launch(shell->compositor,
Pekka Paalanen18027e52011-12-02 16:31:49 +02002078 &shell->screensaver.process,
Pekka Paalanene955f1e2011-12-07 11:49:52 +02002079 shell->screensaver.path,
Pekka Paalanen18027e52011-12-02 16:31:49 +02002080 handle_screensaver_sigchld);
Pekka Paalanen77346a62011-11-30 16:26:35 +02002081}
2082
2083static void
Tiago Vignattibe143262012-04-16 17:31:41 +03002084terminate_screensaver(struct desktop_shell *shell)
Pekka Paalanen77346a62011-11-30 16:26:35 +02002085{
Pekka Paalanen18027e52011-12-02 16:31:49 +02002086 if (shell->screensaver.process.pid == 0)
2087 return;
2088
2089 kill(shell->screensaver.process.pid, SIGTERM);
Pekka Paalanen77346a62011-11-30 16:26:35 +02002090}
2091
2092static void
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04002093configure_static_surface(struct weston_surface *es, struct weston_layer *layer)
Kristian Høgsberg962342c2012-06-26 16:29:50 -04002094{
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04002095 struct weston_surface *s, *next;
Kristian Høgsberg962342c2012-06-26 16:29:50 -04002096
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04002097 wl_list_for_each_safe(s, next, &layer->surface_list, layer_link) {
2098 if (s->output == es->output && s != es) {
2099 weston_surface_unmap(s);
Kristian Høgsberg962342c2012-06-26 16:29:50 -04002100 s->configure = NULL;
Kristian Høgsberg962342c2012-06-26 16:29:50 -04002101 }
2102 }
2103
2104 weston_surface_configure(es, es->output->x, es->output->y,
2105 es->buffer->width, es->buffer->height);
2106
2107 if (wl_list_empty(&es->layer_link)) {
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04002108 wl_list_insert(&layer->surface_list, &es->layer_link);
Kristian Høgsbergc7cd6262012-06-28 13:46:09 -04002109 weston_compositor_schedule_repaint(es->compositor);
Kristian Høgsberg962342c2012-06-26 16:29:50 -04002110 }
2111}
2112
2113static void
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04002114background_configure(struct weston_surface *es, int32_t sx, int32_t sy)
2115{
2116 struct desktop_shell *shell = es->private;
2117
2118 configure_static_surface(es, &shell->background_layer);
2119}
2120
2121static void
Kristian Høgsberg75840622011-09-06 13:48:16 -04002122desktop_shell_set_background(struct wl_client *client,
2123 struct wl_resource *resource,
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01002124 struct wl_resource *output_resource,
Kristian Høgsberg75840622011-09-06 13:48:16 -04002125 struct wl_resource *surface_resource)
2126{
Kristian Høgsberg962342c2012-06-26 16:29:50 -04002127 struct desktop_shell *shell = resource->data;
2128 struct weston_surface *surface = surface_resource->data;
Kristian Høgsberg75840622011-09-06 13:48:16 -04002129
Kristian Høgsberg962342c2012-06-26 16:29:50 -04002130 if (surface->configure) {
2131 wl_resource_post_error(surface_resource,
2132 WL_DISPLAY_ERROR_INVALID_OBJECT,
2133 "surface role already assigned");
2134 return;
2135 }
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01002136
Kristian Høgsberg962342c2012-06-26 16:29:50 -04002137 surface->configure = background_configure;
2138 surface->private = shell;
2139 surface->output = output_resource->data;
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04002140 desktop_shell_send_configure(resource, 0,
Kristian Høgsberg0b5cd0c2012-03-04 21:57:37 -05002141 surface_resource,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002142 surface->output->width,
2143 surface->output->height);
Kristian Høgsberg75840622011-09-06 13:48:16 -04002144}
2145
2146static void
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04002147panel_configure(struct weston_surface *es, int32_t sx, int32_t sy)
2148{
2149 struct desktop_shell *shell = es->private;
2150
2151 configure_static_surface(es, &shell->panel_layer);
2152}
2153
2154static void
Kristian Høgsberg75840622011-09-06 13:48:16 -04002155desktop_shell_set_panel(struct wl_client *client,
2156 struct wl_resource *resource,
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01002157 struct wl_resource *output_resource,
Kristian Høgsberg75840622011-09-06 13:48:16 -04002158 struct wl_resource *surface_resource)
2159{
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04002160 struct desktop_shell *shell = resource->data;
2161 struct weston_surface *surface = surface_resource->data;
Kristian Høgsberg75840622011-09-06 13:48:16 -04002162
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04002163 if (surface->configure) {
2164 wl_resource_post_error(surface_resource,
2165 WL_DISPLAY_ERROR_INVALID_OBJECT,
2166 "surface role already assigned");
2167 return;
2168 }
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01002169
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04002170 surface->configure = panel_configure;
2171 surface->private = shell;
2172 surface->output = output_resource->data;
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04002173 desktop_shell_send_configure(resource, 0,
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04002174 surface_resource,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002175 surface->output->width,
2176 surface->output->height);
Kristian Høgsberg75840622011-09-06 13:48:16 -04002177}
2178
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002179static void
Kristian Høgsberg730c94d2012-06-26 21:44:35 -04002180lock_surface_configure(struct weston_surface *surface, int32_t sx, int32_t sy)
2181{
2182 struct desktop_shell *shell = surface->private;
2183
2184 center_on_output(surface, get_default_output(shell->compositor));
2185
2186 if (!weston_surface_is_mapped(surface)) {
2187 wl_list_insert(&shell->lock_layer.surface_list,
2188 &surface->layer_link);
2189 weston_surface_assign_output(surface);
2190 weston_compositor_wake(shell->compositor);
2191 }
2192}
2193
2194static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04002195handle_lock_surface_destroy(struct wl_listener *listener, void *data)
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05002196{
Tiago Vignattibe143262012-04-16 17:31:41 +03002197 struct desktop_shell *shell =
2198 container_of(listener, struct desktop_shell, lock_surface_listener);
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05002199
Martin Minarik6d118362012-06-07 18:01:59 +02002200 weston_log("lock surface gone\n");
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05002201 shell->lock_surface = NULL;
2202}
2203
2204static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002205desktop_shell_set_lock_surface(struct wl_client *client,
2206 struct wl_resource *resource,
2207 struct wl_resource *surface_resource)
2208{
Tiago Vignattibe143262012-04-16 17:31:41 +03002209 struct desktop_shell *shell = resource->data;
Kristian Høgsberg730c94d2012-06-26 21:44:35 -04002210 struct weston_surface *surface = surface_resource->data;
Pekka Paalanen98262232011-12-01 10:42:22 +02002211
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002212 shell->prepare_event_sent = false;
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +02002213
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002214 if (!shell->locked)
2215 return;
2216
Pekka Paalanen98262232011-12-01 10:42:22 +02002217 shell->lock_surface = surface;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002218
Kristian Høgsberg27e30522012-04-11 23:18:23 -04002219 shell->lock_surface_listener.notify = handle_lock_surface_destroy;
2220 wl_signal_add(&surface_resource->destroy_signal,
2221 &shell->lock_surface_listener);
Pekka Paalanen57da4a82011-11-23 16:42:16 +02002222
Kristian Høgsberg730c94d2012-06-26 21:44:35 -04002223 surface->configure = lock_surface_configure;
2224 surface->private = shell;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002225}
2226
2227static void
Tiago Vignattibe143262012-04-16 17:31:41 +03002228resume_desktop(struct desktop_shell *shell)
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002229{
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04002230 struct weston_surface *surface;
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04002231 struct workspace *ws = get_current_workspace(shell);
Pekka Paalanen77346a62011-11-30 16:26:35 +02002232
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04002233 wl_list_for_each(surface, &shell->screensaver.surfaces, link)
2234 weston_surface_unmap(surface);
Pekka Paalanen77346a62011-11-30 16:26:35 +02002235
2236 terminate_screensaver(shell);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002237
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002238 wl_list_remove(&shell->lock_layer.link);
2239 wl_list_insert(&shell->compositor->cursor_layer.link,
2240 &shell->fullscreen_layer.link);
2241 wl_list_insert(&shell->fullscreen_layer.link,
2242 &shell->panel_layer.link);
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02002243 if (shell->showing_input_panels) {
2244 wl_list_insert(&shell->panel_layer.link,
2245 &shell->input_panel_layer.link);
2246 wl_list_insert(&shell->input_panel_layer.link,
2247 &ws->layer.link);
2248 } else {
2249 wl_list_insert(&shell->panel_layer.link, &ws->layer.link);
2250 }
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002251
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -04002252 restore_focus_state(shell, get_current_workspace(shell));
Jonas Ådahl04769742012-06-13 00:01:24 +02002253
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002254 shell->locked = false;
Pekka Paalanen7296e792011-12-07 16:22:00 +02002255 shell->compositor->idle_time = shell->compositor->option_idle_time;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002256 weston_compositor_wake(shell->compositor);
Pekka Paalanenfc6d91a2012-02-10 15:33:10 +02002257 weston_compositor_damage_all(shell->compositor);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002258}
2259
2260static void
2261desktop_shell_unlock(struct wl_client *client,
2262 struct wl_resource *resource)
2263{
Tiago Vignattibe143262012-04-16 17:31:41 +03002264 struct desktop_shell *shell = resource->data;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002265
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002266 shell->prepare_event_sent = false;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002267
2268 if (shell->locked)
2269 resume_desktop(shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002270}
2271
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04002272static void
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03002273desktop_shell_set_grab_surface(struct wl_client *client,
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04002274 struct wl_resource *resource,
2275 struct wl_resource *surface_resource)
2276{
2277 struct desktop_shell *shell = resource->data;
2278
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03002279 shell->grab_surface = surface_resource->data;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04002280}
2281
Kristian Høgsberg75840622011-09-06 13:48:16 -04002282static const struct desktop_shell_interface desktop_shell_implementation = {
2283 desktop_shell_set_background,
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002284 desktop_shell_set_panel,
2285 desktop_shell_set_lock_surface,
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04002286 desktop_shell_unlock,
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03002287 desktop_shell_set_grab_surface
Kristian Høgsberg75840622011-09-06 13:48:16 -04002288};
2289
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02002290static enum shell_surface_type
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002291get_shell_surface_type(struct weston_surface *surface)
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02002292{
2293 struct shell_surface *shsurf;
2294
2295 shsurf = get_shell_surface(surface);
2296 if (!shsurf)
Pekka Paalanen98262232011-12-01 10:42:22 +02002297 return SHELL_SURFACE_NONE;
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02002298 return shsurf->type;
2299}
2300
Kristian Høgsberg75840622011-09-06 13:48:16 -04002301static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002302move_binding(struct wl_seat *seat, uint32_t time, uint32_t button, void *data)
Kristian Høgsberg07937562011-04-12 17:25:42 -04002303{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002304 struct weston_surface *surface =
Daniel Stone37816df2012-05-16 18:45:18 +01002305 (struct weston_surface *) seat->pointer->focus;
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04002306 struct shell_surface *shsurf;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -05002307
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01002308 if (surface == NULL)
2309 return;
Kristian Høgsberg07937562011-04-12 17:25:42 -04002310
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04002311 shsurf = get_shell_surface(surface);
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04002312 if (shsurf == NULL || shsurf->type == SHELL_SURFACE_FULLSCREEN)
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04002313 return;
2314
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04002315 surface_move(shsurf, (struct weston_seat *) seat);
Kristian Høgsberg07937562011-04-12 17:25:42 -04002316}
2317
2318static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002319resize_binding(struct wl_seat *seat, uint32_t time, uint32_t button, void *data)
Kristian Høgsberg07937562011-04-12 17:25:42 -04002320{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002321 struct weston_surface *surface =
Daniel Stone37816df2012-05-16 18:45:18 +01002322 (struct weston_surface *) seat->pointer->focus;
Kristian Høgsberg07937562011-04-12 17:25:42 -04002323 uint32_t edges = 0;
2324 int32_t x, y;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002325 struct shell_surface *shsurf;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -05002326
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01002327 if (surface == NULL)
2328 return;
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02002329
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002330 shsurf = get_shell_surface(surface);
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04002331 if (!shsurf || shsurf->type == SHELL_SURFACE_FULLSCREEN)
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02002332 return;
2333
Pekka Paalanen5c97ae72012-01-30 16:19:47 +02002334 weston_surface_from_global(surface,
Daniel Stone37816df2012-05-16 18:45:18 +01002335 wl_fixed_to_int(seat->pointer->grab_x),
2336 wl_fixed_to_int(seat->pointer->grab_y),
Daniel Stone103db7f2012-05-08 17:17:55 +01002337 &x, &y);
Kristian Høgsberg07937562011-04-12 17:25:42 -04002338
Pekka Paalanen60921e52012-01-25 15:55:43 +02002339 if (x < surface->geometry.width / 3)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002340 edges |= WL_SHELL_SURFACE_RESIZE_LEFT;
Pekka Paalanen60921e52012-01-25 15:55:43 +02002341 else if (x < 2 * surface->geometry.width / 3)
Kristian Høgsberg07937562011-04-12 17:25:42 -04002342 edges |= 0;
2343 else
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002344 edges |= WL_SHELL_SURFACE_RESIZE_RIGHT;
Kristian Høgsberg07937562011-04-12 17:25:42 -04002345
Pekka Paalanen60921e52012-01-25 15:55:43 +02002346 if (y < surface->geometry.height / 3)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002347 edges |= WL_SHELL_SURFACE_RESIZE_TOP;
Pekka Paalanen60921e52012-01-25 15:55:43 +02002348 else if (y < 2 * surface->geometry.height / 3)
Kristian Høgsberg07937562011-04-12 17:25:42 -04002349 edges |= 0;
2350 else
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002351 edges |= WL_SHELL_SURFACE_RESIZE_BOTTOM;
Kristian Høgsberg07937562011-04-12 17:25:42 -04002352
Kristian Høgsbergc1693f22012-05-22 16:56:23 -04002353 surface_resize(shsurf, (struct weston_seat *) seat, edges);
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04002354}
2355
2356static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002357surface_opacity_binding(struct wl_seat *seat, uint32_t time, uint32_t axis,
Daniel Stone0c1e46e2012-05-30 16:31:59 +01002358 wl_fixed_t value, void *data)
Scott Moreaua3aa9c92012-03-22 11:01:03 -06002359{
Scott Moreau02709af2012-05-22 01:54:10 -06002360 float step = 0.05;
Scott Moreaua3aa9c92012-03-22 11:01:03 -06002361 struct shell_surface *shsurf;
2362 struct weston_surface *surface =
Daniel Stone37816df2012-05-16 18:45:18 +01002363 (struct weston_surface *) seat->pointer->focus;
Scott Moreaua3aa9c92012-03-22 11:01:03 -06002364
2365 if (surface == NULL)
2366 return;
2367
2368 shsurf = get_shell_surface(surface);
2369 if (!shsurf)
2370 return;
2371
Daniel Stone0c1e46e2012-05-30 16:31:59 +01002372 surface->alpha += wl_fixed_to_double(value) * step;
Scott Moreaua3aa9c92012-03-22 11:01:03 -06002373
Scott Moreau02709af2012-05-22 01:54:10 -06002374 if (surface->alpha > 1.0)
2375 surface->alpha = 1.0;
Scott Moreaua3aa9c92012-03-22 11:01:03 -06002376 if (surface->alpha < step)
2377 surface->alpha = step;
2378
2379 surface->geometry.dirty = 1;
2380 weston_surface_damage(surface);
2381}
2382
2383static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002384do_zoom(struct wl_seat *seat, uint32_t time, uint32_t key, uint32_t axis,
Daniel Stone0c1e46e2012-05-30 16:31:59 +01002385 wl_fixed_t value)
Scott Moreauccbf29d2012-02-22 14:21:41 -07002386{
Daniel Stone37816df2012-05-16 18:45:18 +01002387 struct weston_seat *ws = (struct weston_seat *) seat;
2388 struct weston_compositor *compositor = ws->compositor;
Scott Moreauccbf29d2012-02-22 14:21:41 -07002389 struct weston_output *output;
Scott Moreaue6603982012-06-11 13:07:51 -06002390 float increment;
Scott Moreauccbf29d2012-02-22 14:21:41 -07002391
2392 wl_list_for_each(output, &compositor->output_list, link) {
2393 if (pixman_region32_contains_point(&output->region,
Daniel Stone37816df2012-05-16 18:45:18 +01002394 wl_fixed_to_double(seat->pointer->x),
2395 wl_fixed_to_double(seat->pointer->y),
Daniel Stone103db7f2012-05-08 17:17:55 +01002396 NULL)) {
Daniel Stone325fc2d2012-05-30 16:31:58 +01002397 if (key == KEY_PAGEUP)
Kristian Høgsberg9b68af02012-05-22 12:55:18 -04002398 increment = output->zoom.increment;
Daniel Stone325fc2d2012-05-30 16:31:58 +01002399 else if (key == KEY_PAGEDOWN)
Kristian Høgsberg9b68af02012-05-22 12:55:18 -04002400 increment = -output->zoom.increment;
2401 else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
Daniel Stone0c1e46e2012-05-30 16:31:59 +01002402 increment = output->zoom.increment *
2403 wl_fixed_to_double(value);
Kristian Høgsberg9b68af02012-05-22 12:55:18 -04002404 else
2405 increment = 0;
2406
Kristian Høgsberg9b68af02012-05-22 12:55:18 -04002407 output->zoom.level += increment;
Scott Moreauc6d7f602012-02-23 22:28:37 -07002408
Scott Moreaue6603982012-06-11 13:07:51 -06002409 if (output->zoom.level < 0.0)
Scott Moreau850ca422012-05-21 15:21:25 -06002410 output->zoom.level = 0.0;
Scott Moreaue6603982012-06-11 13:07:51 -06002411 else if (output->zoom.level > output->zoom.max_level)
2412 output->zoom.level = output->zoom.max_level;
Kristian Høgsberg79af73e2012-08-03 15:45:23 -04002413 else {
Scott Moreaue6603982012-06-11 13:07:51 -06002414 output->zoom.active = 1;
Kristian Høgsberg79af73e2012-08-03 15:45:23 -04002415 output->disable_planes++;
2416 }
Scott Moreauccbf29d2012-02-22 14:21:41 -07002417
Scott Moreaue6603982012-06-11 13:07:51 -06002418 output->zoom.spring_z.target = output->zoom.level;
Scott Moreauccbf29d2012-02-22 14:21:41 -07002419
Scott Moreau8dacaab2012-06-17 18:10:58 -06002420 weston_output_update_zoom(output, output->zoom.type);
Scott Moreauccbf29d2012-02-22 14:21:41 -07002421 }
2422 }
2423}
2424
Scott Moreauccbf29d2012-02-22 14:21:41 -07002425static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002426zoom_axis_binding(struct wl_seat *seat, uint32_t time, uint32_t axis,
Daniel Stone0c1e46e2012-05-30 16:31:59 +01002427 wl_fixed_t value, void *data)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002428{
2429 do_zoom(seat, time, 0, axis, value);
2430}
2431
2432static void
2433zoom_key_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
2434 void *data)
2435{
2436 do_zoom(seat, time, key, 0, 0);
2437}
2438
2439static void
2440terminate_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
2441 void *data)
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05002442{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002443 struct weston_compositor *compositor = data;
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05002444
Daniel Stone325fc2d2012-05-30 16:31:58 +01002445 wl_display_terminate(compositor->wl_display);
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05002446}
2447
2448static void
Scott Moreau447013d2012-02-18 05:05:29 -07002449rotate_grab_motion(struct wl_pointer_grab *grab,
Daniel Stone103db7f2012-05-08 17:17:55 +01002450 uint32_t time, wl_fixed_t x, wl_fixed_t y)
Pekka Paalanen460099f2012-01-20 16:48:25 +02002451{
2452 struct rotate_grab *rotate =
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002453 container_of(grab, struct rotate_grab, base.grab);
Daniel Stone37816df2012-05-16 18:45:18 +01002454 struct wl_pointer *pointer = grab->pointer;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002455 struct shell_surface *shsurf = rotate->base.shsurf;
2456 struct weston_surface *surface;
2457 GLfloat cx, cy, dx, dy, cposx, cposy, dposx, dposy, r;
2458
2459 if (!shsurf)
2460 return;
2461
2462 surface = shsurf->surface;
2463
2464 cx = 0.5f * surface->geometry.width;
2465 cy = 0.5f * surface->geometry.height;
Pekka Paalanen460099f2012-01-20 16:48:25 +02002466
Daniel Stone37816df2012-05-16 18:45:18 +01002467 dx = wl_fixed_to_double(pointer->x) - rotate->center.x;
2468 dy = wl_fixed_to_double(pointer->y) - rotate->center.y;
Pekka Paalanen460099f2012-01-20 16:48:25 +02002469 r = sqrtf(dx * dx + dy * dy);
2470
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002471 wl_list_remove(&shsurf->rotation.transform.link);
2472 shsurf->surface->geometry.dirty = 1;
Pekka Paalanen460099f2012-01-20 16:48:25 +02002473
2474 if (r > 20.0f) {
Pekka Paalanen460099f2012-01-20 16:48:25 +02002475 struct weston_matrix *matrix =
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002476 &shsurf->rotation.transform.matrix;
Pekka Paalanen460099f2012-01-20 16:48:25 +02002477
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05002478 weston_matrix_init(&rotate->rotation);
2479 rotate->rotation.d[0] = dx / r;
2480 rotate->rotation.d[4] = -dy / r;
2481 rotate->rotation.d[1] = -rotate->rotation.d[4];
2482 rotate->rotation.d[5] = rotate->rotation.d[0];
Pekka Paalanen460099f2012-01-20 16:48:25 +02002483
2484 weston_matrix_init(matrix);
Pekka Paalanen7b3bd3d2012-01-30 14:16:34 +02002485 weston_matrix_translate(matrix, -cx, -cy, 0.0f);
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002486 weston_matrix_multiply(matrix, &shsurf->rotation.rotation);
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05002487 weston_matrix_multiply(matrix, &rotate->rotation);
Pekka Paalanen7b3bd3d2012-01-30 14:16:34 +02002488 weston_matrix_translate(matrix, cx, cy, 0.0f);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002489
Pekka Paalanenbc0b7e72012-01-24 09:53:37 +02002490 wl_list_insert(
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002491 &shsurf->surface->geometry.transformation_list,
2492 &shsurf->rotation.transform.link);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002493 } else {
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002494 wl_list_init(&shsurf->rotation.transform.link);
2495 weston_matrix_init(&shsurf->rotation.rotation);
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05002496 weston_matrix_init(&rotate->rotation);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002497 }
Pekka Paalanenb45ac5e2012-02-09 15:58:44 +02002498
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01002499 /* We need to adjust the position of the surface
2500 * in case it was resized in a rotated state before */
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002501 cposx = surface->geometry.x + cx;
2502 cposy = surface->geometry.y + cy;
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01002503 dposx = rotate->center.x - cposx;
2504 dposy = rotate->center.y - cposy;
2505 if (dposx != 0.0f || dposy != 0.0f) {
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002506 weston_surface_set_position(surface,
2507 surface->geometry.x + dposx,
2508 surface->geometry.y + dposy);
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01002509 }
2510
Pekka Paalanenb45ac5e2012-02-09 15:58:44 +02002511 /* Repaint implies weston_surface_update_transform(), which
2512 * lazily applies the damage due to rotation update.
2513 */
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002514 weston_compositor_schedule_repaint(shsurf->surface->compositor);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002515}
2516
2517static void
Scott Moreau447013d2012-02-18 05:05:29 -07002518rotate_grab_button(struct wl_pointer_grab *grab,
Daniel Stone4dbadb12012-05-30 16:31:51 +01002519 uint32_t time, uint32_t button, uint32_t state_w)
Pekka Paalanen460099f2012-01-20 16:48:25 +02002520{
2521 struct rotate_grab *rotate =
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002522 container_of(grab, struct rotate_grab, base.grab);
Daniel Stone37816df2012-05-16 18:45:18 +01002523 struct wl_pointer *pointer = grab->pointer;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002524 struct shell_surface *shsurf = rotate->base.shsurf;
Daniel Stone4dbadb12012-05-30 16:31:51 +01002525 enum wl_pointer_button_state state = state_w;
Pekka Paalanen460099f2012-01-20 16:48:25 +02002526
Daniel Stone4dbadb12012-05-30 16:31:51 +01002527 if (pointer->button_count == 0 &&
2528 state == WL_POINTER_BUTTON_STATE_RELEASED) {
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002529 if (shsurf)
2530 weston_matrix_multiply(&shsurf->rotation.rotation,
2531 &rotate->rotation);
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03002532 shell_grab_end(&rotate->base);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002533 free(rotate);
2534 }
2535}
2536
Scott Moreau447013d2012-02-18 05:05:29 -07002537static const struct wl_pointer_grab_interface rotate_grab_interface = {
Pekka Paalanen460099f2012-01-20 16:48:25 +02002538 noop_grab_focus,
2539 rotate_grab_motion,
2540 rotate_grab_button,
2541};
2542
2543static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002544rotate_binding(struct wl_seat *seat, uint32_t time, uint32_t button,
Daniel Stonee5a01202012-05-04 11:21:57 +01002545 void *data)
Pekka Paalanen460099f2012-01-20 16:48:25 +02002546{
2547 struct weston_surface *base_surface =
Daniel Stone37816df2012-05-16 18:45:18 +01002548 (struct weston_surface *) seat->pointer->focus;
Pekka Paalanen460099f2012-01-20 16:48:25 +02002549 struct shell_surface *surface;
2550 struct rotate_grab *rotate;
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01002551 GLfloat dx, dy;
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05002552 GLfloat r;
Pekka Paalanen460099f2012-01-20 16:48:25 +02002553
2554 if (base_surface == NULL)
2555 return;
2556
2557 surface = get_shell_surface(base_surface);
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04002558 if (!surface || surface->type == SHELL_SURFACE_FULLSCREEN)
Pekka Paalanen460099f2012-01-20 16:48:25 +02002559 return;
2560
Pekka Paalanen460099f2012-01-20 16:48:25 +02002561 rotate = malloc(sizeof *rotate);
2562 if (!rotate)
2563 return;
2564
Kristian Høgsbergb2af93e2012-06-07 20:10:23 -04002565 weston_surface_to_global_float(surface->surface,
2566 surface->surface->geometry.width / 2,
2567 surface->surface->geometry.height / 2,
2568 &rotate->center.x, &rotate->center.y);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002569
Daniel Stone37816df2012-05-16 18:45:18 +01002570 dx = wl_fixed_to_double(seat->pointer->x) - rotate->center.x;
2571 dy = wl_fixed_to_double(seat->pointer->y) - rotate->center.y;
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05002572 r = sqrtf(dx * dx + dy * dy);
2573 if (r > 20.0f) {
2574 struct weston_matrix inverse;
2575
2576 weston_matrix_init(&inverse);
2577 inverse.d[0] = dx / r;
2578 inverse.d[4] = dy / r;
2579 inverse.d[1] = -inverse.d[4];
2580 inverse.d[5] = inverse.d[0];
2581 weston_matrix_multiply(&surface->rotation.rotation, &inverse);
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01002582
2583 weston_matrix_init(&rotate->rotation);
2584 rotate->rotation.d[0] = dx / r;
2585 rotate->rotation.d[4] = -dy / r;
2586 rotate->rotation.d[1] = -rotate->rotation.d[4];
2587 rotate->rotation.d[5] = rotate->rotation.d[0];
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05002588 } else {
2589 weston_matrix_init(&surface->rotation.rotation);
2590 weston_matrix_init(&rotate->rotation);
2591 }
2592
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03002593 shell_grab_start(&rotate->base, &rotate_grab_interface, surface,
2594 seat->pointer, DESKTOP_SHELL_CURSOR_ARROW);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002595}
2596
2597static void
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04002598lower_fullscreen_layer(struct desktop_shell *shell)
2599{
2600 struct workspace *ws;
2601 struct weston_surface *surface, *prev;
2602
2603 ws = get_current_workspace(shell);
2604 wl_list_for_each_reverse_safe(surface, prev,
2605 &shell->fullscreen_layer.surface_list,
2606 layer_link)
2607 weston_surface_restack(surface, &ws->layer.surface_list);
2608}
2609
2610static void
Tiago Vignattibe143262012-04-16 17:31:41 +03002611activate(struct desktop_shell *shell, struct weston_surface *es,
Daniel Stone37816df2012-05-16 18:45:18 +01002612 struct weston_seat *seat)
Kristian Høgsberg75840622011-09-06 13:48:16 -04002613{
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -04002614 struct focus_state *state;
Jonas Ådahl8538b222012-08-29 22:13:03 +02002615 struct workspace *ws;
Kristian Høgsberg75840622011-09-06 13:48:16 -04002616
Daniel Stone37816df2012-05-16 18:45:18 +01002617 weston_surface_activate(es, seat);
Kristian Høgsberg75840622011-09-06 13:48:16 -04002618
Jonas Ådahl8538b222012-08-29 22:13:03 +02002619 state = ensure_focus_state(shell, seat);
2620 if (state == NULL)
2621 return;
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -04002622
2623 state->keyboard_focus = es;
2624 wl_list_remove(&state->surface_destroy_listener.link);
2625 wl_signal_add(&es->surface.resource.destroy_signal,
2626 &state->surface_destroy_listener);
2627
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02002628 switch (get_shell_surface_type(es)) {
Alex Wu4539b082012-03-01 12:57:46 +08002629 case SHELL_SURFACE_FULLSCREEN:
2630 /* should on top of panels */
Alex Wu21858432012-04-01 20:13:08 +08002631 shell_stack_fullscreen(get_shell_surface(es));
Alex Wubd3354b2012-04-17 17:20:49 +08002632 shell_configure_fullscreen(get_shell_surface(es));
Alex Wu4539b082012-03-01 12:57:46 +08002633 break;
Pekka Paalanen57da4a82011-11-23 16:42:16 +02002634 default:
Jonas Ådahle3cddce2012-06-13 00:01:22 +02002635 ws = get_current_workspace(shell);
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04002636 lower_fullscreen_layer(shell);
2637 weston_surface_restack(es, &ws->layer.surface_list);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002638 break;
Kristian Høgsberg75840622011-09-06 13:48:16 -04002639 }
2640}
2641
Alex Wu21858432012-04-01 20:13:08 +08002642/* no-op func for checking black surface */
2643static void
2644black_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
2645{
2646}
2647
2648static bool
2649is_black_surface (struct weston_surface *es, struct weston_surface **fs_surface)
2650{
2651 if (es->configure == black_surface_configure) {
2652 if (fs_surface)
2653 *fs_surface = (struct weston_surface *)es->private;
2654 return true;
2655 }
2656 return false;
2657}
2658
Kristian Høgsberg75840622011-09-06 13:48:16 -04002659static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002660click_to_activate_binding(struct wl_seat *seat, uint32_t time, uint32_t button,
Daniel Stone4dbadb12012-05-30 16:31:51 +01002661 void *data)
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05002662{
Daniel Stone37816df2012-05-16 18:45:18 +01002663 struct weston_seat *ws = (struct weston_seat *) seat;
Tiago Vignattibe143262012-04-16 17:31:41 +03002664 struct desktop_shell *shell = data;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002665 struct weston_surface *focus;
Alex Wu4539b082012-03-01 12:57:46 +08002666 struct weston_surface *upper;
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05002667
Daniel Stone37816df2012-05-16 18:45:18 +01002668 focus = (struct weston_surface *) seat->pointer->focus;
Alex Wu9c35e6b2012-03-05 14:13:13 +08002669 if (!focus)
2670 return;
2671
Alex Wu21858432012-04-01 20:13:08 +08002672 if (is_black_surface(focus, &upper))
Alex Wu4539b082012-03-01 12:57:46 +08002673 focus = upper;
Alex Wu4539b082012-03-01 12:57:46 +08002674
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04002675 if (get_shell_surface_type(focus) == SHELL_SURFACE_NONE)
2676 return;
Kristian Høgsberg85b2e4b2012-06-21 16:49:42 -04002677
Daniel Stone325fc2d2012-05-30 16:31:58 +01002678 if (seat->pointer->grab == &seat->pointer->default_grab)
Daniel Stone37816df2012-05-16 18:45:18 +01002679 activate(shell, focus, ws);
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05002680}
2681
2682static void
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04002683lock(struct wl_listener *listener, void *data)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04002684{
Tiago Vignattibe143262012-04-16 17:31:41 +03002685 struct desktop_shell *shell =
2686 container_of(listener, struct desktop_shell, lock_listener);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002687 struct weston_output *output;
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04002688 struct workspace *ws = get_current_workspace(shell);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002689
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002690 if (shell->locked) {
2691 wl_list_for_each(output, &shell->compositor->output_list, link)
2692 /* TODO: find a way to jump to other DPMS levels */
2693 if (output->set_dpms)
2694 output->set_dpms(output, WESTON_DPMS_STANDBY);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002695 return;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002696 }
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002697
2698 shell->locked = true;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002699
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002700 /* Hide all surfaces by removing the fullscreen, panel and
2701 * toplevel layers. This way nothing else can show or receive
2702 * input events while we are locked. */
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002703
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002704 wl_list_remove(&shell->panel_layer.link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002705 wl_list_remove(&shell->fullscreen_layer.link);
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02002706 if (shell->showing_input_panels)
2707 wl_list_remove(&shell->input_panel_layer.link);
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04002708 wl_list_remove(&ws->layer.link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002709 wl_list_insert(&shell->compositor->cursor_layer.link,
2710 &shell->lock_layer.link);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002711
Pekka Paalanen77346a62011-11-30 16:26:35 +02002712 launch_screensaver(shell);
2713
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002714 /* TODO: disable bindings that should not work while locked. */
2715
2716 /* All this must be undone in resume_desktop(). */
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002717}
2718
2719static void
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04002720unlock(struct wl_listener *listener, void *data)
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002721{
Tiago Vignattibe143262012-04-16 17:31:41 +03002722 struct desktop_shell *shell =
2723 container_of(listener, struct desktop_shell, unlock_listener);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002724
Pekka Paalanend81c2162011-11-16 13:47:34 +02002725 if (!shell->locked || shell->lock_surface) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002726 weston_compositor_wake(shell->compositor);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002727 return;
2728 }
2729
2730 /* If desktop-shell client has gone away, unlock immediately. */
2731 if (!shell->child.desktop_shell) {
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002732 resume_desktop(shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002733 return;
2734 }
2735
2736 if (shell->prepare_event_sent)
2737 return;
2738
Kristian Høgsberg0b5cd0c2012-03-04 21:57:37 -05002739 desktop_shell_send_prepare_lock_surface(shell->child.desktop_shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002740 shell->prepare_event_sent = true;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04002741}
2742
2743static void
Jan Arne Petersen42feced2012-06-21 21:52:17 +02002744show_input_panels(struct wl_listener *listener, void *data)
2745{
2746 struct desktop_shell *shell =
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02002747 container_of(listener, struct desktop_shell,
2748 show_input_panel_listener);
Philipp Brüschweiler88013572012-08-06 13:44:42 +02002749 struct input_panel_surface *surface, *next;
2750 struct weston_surface *ws;
Jan Arne Petersen42feced2012-06-21 21:52:17 +02002751
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02002752 shell->showing_input_panels = true;
2753
2754 wl_list_insert(&shell->panel_layer.link,
2755 &shell->input_panel_layer.link);
2756
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04002757 wl_list_for_each_safe(surface, next,
Philipp Brüschweiler88013572012-08-06 13:44:42 +02002758 &shell->input_panel.surfaces, link) {
2759 ws = surface->surface;
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02002760 wl_list_insert(&shell->input_panel_layer.surface_list,
Philipp Brüschweiler88013572012-08-06 13:44:42 +02002761 &ws->layer_link);
2762 weston_surface_assign_output(ws);
2763 weston_surface_damage(ws);
2764 weston_slide_run(ws, ws->geometry.height, 0, NULL, NULL);
Jan Arne Petersen42feced2012-06-21 21:52:17 +02002765 }
2766}
2767
2768static void
2769hide_input_panels(struct wl_listener *listener, void *data)
2770{
2771 struct desktop_shell *shell =
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02002772 container_of(listener, struct desktop_shell,
2773 hide_input_panel_listener);
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04002774 struct weston_surface *surface, *next;
Jan Arne Petersen42feced2012-06-21 21:52:17 +02002775
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02002776 shell->showing_input_panels = false;
2777
2778 wl_list_remove(&shell->input_panel_layer.link);
2779
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04002780 wl_list_for_each_safe(surface, next,
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02002781 &shell->input_panel_layer.surface_list, layer_link)
2782 weston_surface_unmap(surface);
Jan Arne Petersen42feced2012-06-21 21:52:17 +02002783}
2784
2785static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002786center_on_output(struct weston_surface *surface, struct weston_output *output)
Pekka Paalanen77346a62011-11-30 16:26:35 +02002787{
Scott Moreau1bad5db2012-08-18 01:04:05 -06002788 GLfloat x = (output->width - surface->buffer->width) / 2;
2789 GLfloat y = (output->height - surface->buffer->height) / 2;
Pekka Paalanen77346a62011-11-30 16:26:35 +02002790
Kristian Høgsberg730c94d2012-06-26 21:44:35 -04002791 weston_surface_configure(surface, output->x + x, output->y + y,
2792 surface->buffer->width,
2793 surface->buffer->height);
Pekka Paalanen77346a62011-11-30 16:26:35 +02002794}
2795
2796static void
Rob Bradfordac63e5b2012-08-13 14:07:52 +01002797weston_surface_set_initial_position (struct weston_surface *surface,
2798 struct desktop_shell *shell)
2799{
2800 struct weston_compositor *compositor = shell->compositor;
2801 int ix = 0, iy = 0;
2802 int range_x, range_y;
2803 int dx, dy, x, y, panel_height;
2804 struct weston_output *output, *target_output = NULL;
2805 struct weston_seat *seat;
2806
2807 /* As a heuristic place the new window on the same output as the
2808 * pointer. Falling back to the output containing 0, 0.
2809 *
2810 * TODO: Do something clever for touch too?
2811 */
2812 wl_list_for_each(seat, &compositor->seat_list, link) {
2813 if (seat->has_pointer) {
2814 ix = wl_fixed_to_int(seat->pointer.x);
2815 iy = wl_fixed_to_int(seat->pointer.y);
2816 break;
2817 }
2818 }
2819
2820 wl_list_for_each(output, &compositor->output_list, link) {
2821 if (pixman_region32_contains_point(&output->region, ix, iy, NULL)) {
2822 target_output = output;
2823 break;
2824 }
2825 }
2826
2827 if (!target_output) {
2828 weston_surface_set_position(surface, 10 + random() % 400,
2829 10 + random() % 400);
2830 return;
2831 }
2832
2833 /* Valid range within output where the surface will still be onscreen.
2834 * If this is negative it means that the surface is bigger than
2835 * output.
2836 */
2837 panel_height = get_output_panel_height(shell, target_output);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002838 range_x = target_output->width - surface->geometry.width;
2839 range_y = (target_output->height - panel_height) -
Rob Bradfordac63e5b2012-08-13 14:07:52 +01002840 surface->geometry.height;
2841
Rob Bradford4cb88c72012-08-13 15:18:44 +01002842 if (range_x > 0)
Rob Bradfordac63e5b2012-08-13 14:07:52 +01002843 dx = random() % range_x;
Rob Bradfordac63e5b2012-08-13 14:07:52 +01002844 else
Rob Bradford4cb88c72012-08-13 15:18:44 +01002845 dx = 0;
2846
2847 if (range_y > 0)
Rob Bradfordac63e5b2012-08-13 14:07:52 +01002848 dy = panel_height + random() % range_y;
Rob Bradford4cb88c72012-08-13 15:18:44 +01002849 else
2850 dy = panel_height;
Rob Bradfordac63e5b2012-08-13 14:07:52 +01002851
2852 x = target_output->x + dx;
2853 y = target_output->y + dy;
2854
2855 weston_surface_set_position (surface, x, y);
2856}
2857
2858static void
Tiago Vignattibe143262012-04-16 17:31:41 +03002859map(struct desktop_shell *shell, struct weston_surface *surface,
Ander Conselvan de Oliveirae9e05152012-02-15 17:02:56 +02002860 int32_t width, int32_t height, int32_t sx, int32_t sy)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04002861{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002862 struct weston_compositor *compositor = shell->compositor;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02002863 struct shell_surface *shsurf = get_shell_surface(surface);
2864 enum shell_surface_type surface_type = shsurf->type;
Kristian Høgsberg60c49542012-03-05 20:51:34 -05002865 struct weston_surface *parent;
Daniel Stoneb2104682012-05-30 16:31:56 +01002866 struct weston_seat *seat;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02002867 struct workspace *ws;
Juan Zhao96879df2012-02-07 08:45:41 +08002868 int panel_height = 0;
Pekka Paalanen57da4a82011-11-23 16:42:16 +02002869
Pekka Paalanen60921e52012-01-25 15:55:43 +02002870 surface->geometry.width = width;
2871 surface->geometry.height = height;
2872 surface->geometry.dirty = 1;
Pekka Paalanen77346a62011-11-30 16:26:35 +02002873
2874 /* initial positioning, see also configure() */
2875 switch (surface_type) {
2876 case SHELL_SURFACE_TOPLEVEL:
Rob Bradfordac63e5b2012-08-13 14:07:52 +01002877 weston_surface_set_initial_position(surface, shell);
Pekka Paalanen77346a62011-11-30 16:26:35 +02002878 break;
Alex Wu4539b082012-03-01 12:57:46 +08002879 case SHELL_SURFACE_FULLSCREEN:
Kristian Høgsberge4d3a2b2012-07-09 21:43:22 -04002880 center_on_output(surface, shsurf->fullscreen_output);
Alex Wu4539b082012-03-01 12:57:46 +08002881 shell_map_fullscreen(shsurf);
2882 break;
Juan Zhao96879df2012-02-07 08:45:41 +08002883 case SHELL_SURFACE_MAXIMIZED:
Alex Wu4539b082012-03-01 12:57:46 +08002884 /* use surface configure to set the geometry */
Juan Zhao96879df2012-02-07 08:45:41 +08002885 panel_height = get_output_panel_height(shell,surface->output);
Rob Bradford31b68622012-07-02 19:00:19 +01002886 weston_surface_set_position(surface, shsurf->output->x,
2887 shsurf->output->y + panel_height);
Juan Zhao96879df2012-02-07 08:45:41 +08002888 break;
Tiago Vignatti0f997012012-02-10 16:17:23 +02002889 case SHELL_SURFACE_POPUP:
Kristian Høgsberg3730f362012-04-13 12:40:07 -04002890 shell_map_popup(shsurf);
Ander Conselvan de Oliveirae9e05152012-02-15 17:02:56 +02002891 case SHELL_SURFACE_NONE:
2892 weston_surface_set_position(surface,
2893 surface->geometry.x + sx,
2894 surface->geometry.y + sy);
Tiago Vignatti0f997012012-02-10 16:17:23 +02002895 break;
Pekka Paalanen77346a62011-11-30 16:26:35 +02002896 default:
2897 ;
2898 }
Kristian Høgsberg75840622011-09-06 13:48:16 -04002899
Pekka Paalanend3dd6e12011-11-16 13:47:33 +02002900 /* surface stacking order, see also activate() */
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02002901 switch (surface_type) {
Kristian Høgsberg60c49542012-03-05 20:51:34 -05002902 case SHELL_SURFACE_POPUP:
2903 case SHELL_SURFACE_TRANSIENT:
Kristian Høgsberg8150b192012-06-27 10:22:58 -04002904 parent = shsurf->parent;
Kristian Høgsberg60c49542012-03-05 20:51:34 -05002905 wl_list_insert(parent->layer_link.prev, &surface->layer_link);
2906 break;
Alex Wu4539b082012-03-01 12:57:46 +08002907 case SHELL_SURFACE_FULLSCREEN:
Ander Conselvan de Oliveiraa1ff53b2012-02-15 17:02:54 +02002908 case SHELL_SURFACE_NONE:
2909 break;
Pekka Paalanen57da4a82011-11-23 16:42:16 +02002910 default:
Jonas Ådahle3cddce2012-06-13 00:01:22 +02002911 ws = get_current_workspace(shell);
2912 wl_list_insert(&ws->layer.surface_list, &surface->layer_link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002913 break;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002914 }
2915
Ander Conselvan de Oliveirade56c312012-03-05 15:39:23 +02002916 if (surface_type != SHELL_SURFACE_NONE) {
2917 weston_surface_assign_output(surface);
Ander Conselvan de Oliveirade56c312012-03-05 15:39:23 +02002918 if (surface_type == SHELL_SURFACE_MAXIMIZED)
2919 surface->output = shsurf->output;
2920 }
Kristian Høgsberg2f88a402011-12-04 15:32:59 -05002921
Juan Zhao7bb92f02011-12-15 11:31:51 -05002922 switch (surface_type) {
Juan Zhao7bb92f02011-12-15 11:31:51 -05002923 case SHELL_SURFACE_TRANSIENT:
Tiago Vignatti99aeb1e2012-05-23 22:06:26 +03002924 if (shsurf->transient.flags ==
2925 WL_SHELL_SURFACE_TRANSIENT_INACTIVE)
2926 break;
2927 case SHELL_SURFACE_TOPLEVEL:
Juan Zhao7bb92f02011-12-15 11:31:51 -05002928 case SHELL_SURFACE_FULLSCREEN:
Juan Zhao96879df2012-02-07 08:45:41 +08002929 case SHELL_SURFACE_MAXIMIZED:
Daniel Stoneb2104682012-05-30 16:31:56 +01002930 if (!shell->locked) {
2931 wl_list_for_each(seat, &compositor->seat_list, link)
2932 activate(shell, surface, seat);
2933 }
Juan Zhao7bb92f02011-12-15 11:31:51 -05002934 break;
2935 default:
2936 break;
2937 }
2938
Kristian Høgsberg2f88a402011-12-04 15:32:59 -05002939 if (surface_type == SHELL_SURFACE_TOPLEVEL)
Juan Zhaoe10d2792012-04-25 19:09:52 +08002940 {
2941 switch (shell->win_animation_type) {
2942 case ANIMATION_FADE:
2943 weston_fade_run(surface, NULL, NULL);
2944 break;
2945 case ANIMATION_ZOOM:
2946 weston_zoom_run(surface, 0.8, 1.0, NULL, NULL);
2947 break;
2948 default:
2949 break;
2950 }
2951 }
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05002952}
2953
2954static void
Tiago Vignattibe143262012-04-16 17:31:41 +03002955configure(struct desktop_shell *shell, struct weston_surface *surface,
Pekka Paalanenddae03c2012-02-06 14:54:20 +02002956 GLfloat x, GLfloat y, int32_t width, int32_t height)
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05002957{
Pekka Paalanen77346a62011-11-30 16:26:35 +02002958 enum shell_surface_type surface_type = SHELL_SURFACE_NONE;
2959 struct shell_surface *shsurf;
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05002960
Pekka Paalanen77346a62011-11-30 16:26:35 +02002961 shsurf = get_shell_surface(surface);
2962 if (shsurf)
2963 surface_type = shsurf->type;
2964
Kristian Høgsberg6a8b5532012-02-16 23:43:59 -05002965 surface->geometry.x = x;
2966 surface->geometry.y = y;
Pekka Paalanen60921e52012-01-25 15:55:43 +02002967 surface->geometry.width = width;
2968 surface->geometry.height = height;
2969 surface->geometry.dirty = 1;
Pekka Paalanen77346a62011-11-30 16:26:35 +02002970
2971 switch (surface_type) {
Alex Wu4539b082012-03-01 12:57:46 +08002972 case SHELL_SURFACE_FULLSCREEN:
Alex Wubd3354b2012-04-17 17:20:49 +08002973 shell_stack_fullscreen(shsurf);
Alex Wu4539b082012-03-01 12:57:46 +08002974 shell_configure_fullscreen(shsurf);
Alex Wu4539b082012-03-01 12:57:46 +08002975 break;
Juan Zhao96879df2012-02-07 08:45:41 +08002976 case SHELL_SURFACE_MAXIMIZED:
Alex Wu4539b082012-03-01 12:57:46 +08002977 /* setting x, y and using configure to change that geometry */
Kristian Høgsberg6a8b5532012-02-16 23:43:59 -05002978 surface->geometry.x = surface->output->x;
2979 surface->geometry.y = surface->output->y +
2980 get_output_panel_height(shell,surface->output);
Juan Zhao96879df2012-02-07 08:45:41 +08002981 break;
Alex Wu4539b082012-03-01 12:57:46 +08002982 case SHELL_SURFACE_TOPLEVEL:
2983 break;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -05002984 default:
2985 break;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04002986 }
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05002987
Alex Wu4539b082012-03-01 12:57:46 +08002988 /* XXX: would a fullscreen surface need the same handling? */
Kristian Høgsberg6a8b5532012-02-16 23:43:59 -05002989 if (surface->output) {
Pekka Paalanenf07cb5d2012-02-10 13:34:36 +02002990 weston_surface_assign_output(surface);
Pekka Paalanen77346a62011-11-30 16:26:35 +02002991
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04002992 if (surface_type == SHELL_SURFACE_MAXIMIZED)
Juan Zhao96879df2012-02-07 08:45:41 +08002993 surface->output = shsurf->output;
Pekka Paalanen77346a62011-11-30 16:26:35 +02002994 }
Kristian Høgsberg07937562011-04-12 17:25:42 -04002995}
2996
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03002997static void
2998shell_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
2999{
Ander Conselvan de Oliveira7fb9f952012-03-27 17:36:42 +03003000 struct shell_surface *shsurf = get_shell_surface(es);
Tiago Vignattibe143262012-04-16 17:31:41 +03003001 struct desktop_shell *shell = shsurf->shell;
Tiago Vignatti70e5c9c2012-05-07 15:23:07 +03003002 int type_changed = 0;
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03003003
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04003004 if (shsurf->next_type != SHELL_SURFACE_NONE &&
Kristian Høgsbergf7e23d52012-04-27 17:51:59 -04003005 shsurf->type != shsurf->next_type) {
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04003006 set_surface_type(shsurf);
Kristian Høgsbergf7e23d52012-04-27 17:51:59 -04003007 type_changed = 1;
3008 }
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04003009
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03003010 if (!weston_surface_is_mapped(es)) {
3011 map(shell, es, es->buffer->width, es->buffer->height, sx, sy);
Kristian Høgsbergf7e23d52012-04-27 17:51:59 -04003012 } else if (type_changed || sx != 0 || sy != 0 ||
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03003013 es->geometry.width != es->buffer->width ||
3014 es->geometry.height != es->buffer->height) {
3015 GLfloat from_x, from_y;
3016 GLfloat to_x, to_y;
3017
3018 weston_surface_to_global_float(es, 0, 0, &from_x, &from_y);
3019 weston_surface_to_global_float(es, sx, sy, &to_x, &to_y);
3020 configure(shell, es,
3021 es->geometry.x + to_x - from_x,
3022 es->geometry.y + to_y - from_y,
3023 es->buffer->width, es->buffer->height);
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03003024 }
3025}
3026
Tiago Vignattibe143262012-04-16 17:31:41 +03003027static int launch_desktop_shell_process(struct desktop_shell *shell);
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02003028
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04003029static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05003030desktop_shell_sigchld(struct weston_process *process, int status)
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02003031{
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02003032 uint32_t time;
Tiago Vignattibe143262012-04-16 17:31:41 +03003033 struct desktop_shell *shell =
3034 container_of(process, struct desktop_shell, child.process);
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02003035
3036 shell->child.process.pid = 0;
3037 shell->child.client = NULL; /* already destroyed by wayland */
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02003038
3039 /* if desktop-shell dies more than 5 times in 30 seconds, give up */
3040 time = weston_compositor_get_time();
Kristian Høgsbergf03a6162012-01-17 11:07:42 -05003041 if (time - shell->child.deathstamp > 30000) {
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02003042 shell->child.deathstamp = time;
3043 shell->child.deathcount = 0;
3044 }
3045
3046 shell->child.deathcount++;
3047 if (shell->child.deathcount > 5) {
Martin Minarik6d118362012-06-07 18:01:59 +02003048 weston_log("weston-desktop-shell died, giving up.\n");
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02003049 return;
3050 }
3051
Martin Minarik6d118362012-06-07 18:01:59 +02003052 weston_log("weston-desktop-shell died, respawning...\n");
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02003053 launch_desktop_shell_process(shell);
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02003054}
3055
3056static int
Tiago Vignattibe143262012-04-16 17:31:41 +03003057launch_desktop_shell_process(struct desktop_shell *shell)
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02003058{
Kristian Høgsberg9724b512012-01-03 14:35:49 -05003059 const char *shell_exe = LIBEXECDIR "/weston-desktop-shell";
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02003060
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05003061 shell->child.client = weston_client_launch(shell->compositor,
Pekka Paalanen409ef0a2011-12-02 15:30:21 +02003062 &shell->child.process,
3063 shell_exe,
3064 desktop_shell_sigchld);
3065
3066 if (!shell->child.client)
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02003067 return -1;
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02003068 return 0;
3069}
3070
3071static void
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04003072bind_shell(struct wl_client *client, void *data, uint32_t version, uint32_t id)
3073{
Tiago Vignattibe143262012-04-16 17:31:41 +03003074 struct desktop_shell *shell = data;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04003075
3076 wl_client_add_object(client, &wl_shell_interface,
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003077 &shell_implementation, id, shell);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04003078}
3079
Kristian Høgsberg75840622011-09-06 13:48:16 -04003080static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02003081unbind_desktop_shell(struct wl_resource *resource)
3082{
Tiago Vignattibe143262012-04-16 17:31:41 +03003083 struct desktop_shell *shell = resource->data;
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05003084
3085 if (shell->locked)
3086 resume_desktop(shell);
3087
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02003088 shell->child.desktop_shell = NULL;
3089 shell->prepare_event_sent = false;
3090 free(resource);
3091}
3092
3093static void
Kristian Høgsberg75840622011-09-06 13:48:16 -04003094bind_desktop_shell(struct wl_client *client,
3095 void *data, uint32_t version, uint32_t id)
3096{
Tiago Vignattibe143262012-04-16 17:31:41 +03003097 struct desktop_shell *shell = data;
Pekka Paalanenbbe60522011-11-03 14:11:33 +02003098 struct wl_resource *resource;
Kristian Høgsberg75840622011-09-06 13:48:16 -04003099
Pekka Paalanenbbe60522011-11-03 14:11:33 +02003100 resource = wl_client_add_object(client, &desktop_shell_interface,
3101 &desktop_shell_implementation,
3102 id, shell);
3103
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02003104 if (client == shell->child.client) {
3105 resource->destroy = unbind_desktop_shell;
3106 shell->child.desktop_shell = resource;
Pekka Paalanenbbe60522011-11-03 14:11:33 +02003107 return;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02003108 }
Pekka Paalanenbbe60522011-11-03 14:11:33 +02003109
3110 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
3111 "permission to bind desktop_shell denied");
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04003112 wl_resource_destroy(resource);
Kristian Høgsberg75840622011-09-06 13:48:16 -04003113}
3114
Pekka Paalanen6e168112011-11-24 11:34:05 +02003115static void
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04003116screensaver_configure(struct weston_surface *surface, int32_t sx, int32_t sy)
3117{
3118 struct desktop_shell *shell = surface->private;
3119
3120 if (!shell->locked)
3121 return;
3122
3123 center_on_output(surface, surface->output);
3124
3125 if (wl_list_empty(&surface->layer_link)) {
3126 wl_list_insert(shell->lock_layer.surface_list.prev,
3127 &surface->layer_link);
3128 weston_surface_assign_output(surface);
3129 shell->compositor->idle_time = shell->screensaver.duration;
3130 weston_compositor_wake(shell->compositor);
3131 shell->compositor->state = WESTON_COMPOSITOR_IDLE;
3132 }
3133}
3134
3135static void
Pekka Paalanen6e168112011-11-24 11:34:05 +02003136screensaver_set_surface(struct wl_client *client,
3137 struct wl_resource *resource,
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04003138 struct wl_resource *surface_resource,
Pekka Paalanen6e168112011-11-24 11:34:05 +02003139 struct wl_resource *output_resource)
3140{
Tiago Vignattibe143262012-04-16 17:31:41 +03003141 struct desktop_shell *shell = resource->data;
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04003142 struct weston_surface *surface = surface_resource->data;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05003143 struct weston_output *output = output_resource->data;
Pekka Paalanen6e168112011-11-24 11:34:05 +02003144
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04003145 surface->configure = screensaver_configure;
3146 surface->private = shell;
Pekka Paalanen77346a62011-11-30 16:26:35 +02003147 surface->output = output;
Pekka Paalanen6e168112011-11-24 11:34:05 +02003148}
3149
3150static const struct screensaver_interface screensaver_implementation = {
3151 screensaver_set_surface
3152};
3153
3154static void
3155unbind_screensaver(struct wl_resource *resource)
3156{
Tiago Vignattibe143262012-04-16 17:31:41 +03003157 struct desktop_shell *shell = resource->data;
Pekka Paalanen6e168112011-11-24 11:34:05 +02003158
Pekka Paalanen77346a62011-11-30 16:26:35 +02003159 shell->screensaver.binding = NULL;
Pekka Paalanen6e168112011-11-24 11:34:05 +02003160 free(resource);
3161}
3162
3163static void
3164bind_screensaver(struct wl_client *client,
3165 void *data, uint32_t version, uint32_t id)
3166{
Tiago Vignattibe143262012-04-16 17:31:41 +03003167 struct desktop_shell *shell = data;
Pekka Paalanen6e168112011-11-24 11:34:05 +02003168 struct wl_resource *resource;
3169
3170 resource = wl_client_add_object(client, &screensaver_interface,
3171 &screensaver_implementation,
3172 id, shell);
3173
Pekka Paalanen77346a62011-11-30 16:26:35 +02003174 if (shell->screensaver.binding == NULL) {
Pekka Paalanen6e168112011-11-24 11:34:05 +02003175 resource->destroy = unbind_screensaver;
Pekka Paalanen77346a62011-11-30 16:26:35 +02003176 shell->screensaver.binding = resource;
Pekka Paalanen6e168112011-11-24 11:34:05 +02003177 return;
3178 }
3179
3180 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
3181 "interface object already bound");
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04003182 wl_resource_destroy(resource);
Pekka Paalanen6e168112011-11-24 11:34:05 +02003183}
3184
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003185static void
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04003186input_panel_configure(struct weston_surface *surface, int32_t sx, int32_t sy)
3187{
3188 struct weston_mode *mode = surface->output->current;
3189 GLfloat x = (mode->width - surface->buffer->width) / 2;
3190 GLfloat y = mode->height - surface->buffer->height;
3191
3192 /* Don't map the input panel here, wait for
3193 * show_input_panels signal. */
3194
3195 weston_surface_configure(surface,
3196 surface->output->x + x,
3197 surface->output->y + y,
3198 surface->buffer->width,
3199 surface->buffer->height);
3200}
3201
3202static void
Philipp Brüschweiler88013572012-08-06 13:44:42 +02003203destroy_input_panel_surface(struct wl_listener *listener,
3204 void *data)
3205{
3206 struct input_panel_surface *input_panel_surface =
3207 container_of(listener, struct input_panel_surface, listener);
3208
3209 wl_list_remove(&listener->link);
3210 wl_list_remove(&input_panel_surface->link);
3211
3212 free(input_panel_surface);
3213}
3214
3215static void
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003216input_panel_set_surface(struct wl_client *client,
3217 struct wl_resource *resource,
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04003218 struct wl_resource *surface_resource,
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003219 struct wl_resource *output_resource)
3220{
3221 struct desktop_shell *shell = resource->data;
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04003222 struct weston_surface *surface = surface_resource->data;
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003223 struct weston_output *output = output_resource->data;
Philipp Brüschweiler88013572012-08-06 13:44:42 +02003224 struct input_panel_surface *input_panel_surface;
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003225
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04003226 surface->configure = input_panel_configure;
3227 surface->private = shell;
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003228 surface->output = output;
Philipp Brüschweiler88013572012-08-06 13:44:42 +02003229
3230 input_panel_surface = malloc(sizeof *input_panel_surface);
3231 if (!input_panel_surface) {
3232 wl_resource_post_no_memory(resource);
3233 return;
3234 }
3235
3236 input_panel_surface->surface = surface;
3237 input_panel_surface->listener.notify = destroy_input_panel_surface;
3238
3239 wl_signal_add(&surface_resource->destroy_signal,
3240 &input_panel_surface->listener);
3241
3242 wl_list_insert(&shell->input_panel.surfaces,
3243 &input_panel_surface->link);
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003244}
3245
3246static const struct input_panel_interface input_panel_implementation = {
3247 input_panel_set_surface
3248};
3249
3250static void
3251unbind_input_panel(struct wl_resource *resource)
3252{
3253 struct desktop_shell *shell = resource->data;
3254
3255 shell->input_panel.binding = NULL;
3256 free(resource);
3257}
3258
3259static void
3260bind_input_panel(struct wl_client *client,
3261 void *data, uint32_t version, uint32_t id)
3262{
3263 struct desktop_shell *shell = data;
3264 struct wl_resource *resource;
3265
3266 resource = wl_client_add_object(client, &input_panel_interface,
3267 &input_panel_implementation,
3268 id, shell);
3269
3270 if (shell->input_panel.binding == NULL) {
3271 resource->destroy = unbind_input_panel;
3272 shell->input_panel.binding = resource;
3273 return;
3274 }
3275
3276 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
3277 "interface object already bound");
3278 wl_resource_destroy(resource);
3279}
3280
Kristian Høgsberg07045392012-02-19 18:52:44 -05003281struct switcher {
Tiago Vignattibe143262012-04-16 17:31:41 +03003282 struct desktop_shell *shell;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003283 struct weston_surface *current;
3284 struct wl_listener listener;
3285 struct wl_keyboard_grab grab;
3286};
3287
3288static void
3289switcher_next(struct switcher *switcher)
3290{
Kristian Høgsberg07045392012-02-19 18:52:44 -05003291 struct weston_surface *surface;
3292 struct weston_surface *first = NULL, *prev = NULL, *next = NULL;
Kristian Høgsberg32e56862012-04-02 22:18:58 -04003293 struct shell_surface *shsurf;
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04003294 struct workspace *ws = get_current_workspace(switcher->shell);
Kristian Høgsberg07045392012-02-19 18:52:44 -05003295
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04003296 wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
Kristian Høgsberg07045392012-02-19 18:52:44 -05003297 switch (get_shell_surface_type(surface)) {
3298 case SHELL_SURFACE_TOPLEVEL:
3299 case SHELL_SURFACE_FULLSCREEN:
3300 case SHELL_SURFACE_MAXIMIZED:
3301 if (first == NULL)
3302 first = surface;
3303 if (prev == switcher->current)
3304 next = surface;
3305 prev = surface;
Scott Moreau02709af2012-05-22 01:54:10 -06003306 surface->alpha = 0.25;
Kristian Høgsbergcacb7cd2012-02-28 09:20:21 -05003307 surface->geometry.dirty = 1;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003308 weston_surface_damage(surface);
3309 break;
3310 default:
3311 break;
3312 }
Alex Wu1659daa2012-04-01 20:13:09 +08003313
3314 if (is_black_surface(surface, NULL)) {
Scott Moreau02709af2012-05-22 01:54:10 -06003315 surface->alpha = 0.25;
Alex Wu1659daa2012-04-01 20:13:09 +08003316 surface->geometry.dirty = 1;
3317 weston_surface_damage(surface);
3318 }
Kristian Høgsberg07045392012-02-19 18:52:44 -05003319 }
3320
3321 if (next == NULL)
3322 next = first;
3323
Alex Wu07b26062012-03-12 16:06:01 +08003324 if (next == NULL)
3325 return;
3326
Kristian Høgsberg07045392012-02-19 18:52:44 -05003327 wl_list_remove(&switcher->listener.link);
Kristian Høgsberg27e30522012-04-11 23:18:23 -04003328 wl_signal_add(&next->surface.resource.destroy_signal,
3329 &switcher->listener);
Kristian Høgsberg07045392012-02-19 18:52:44 -05003330
3331 switcher->current = next;
Kristian Høgsberga416fa12012-05-21 14:06:52 -04003332 next->alpha = 1.0;
Alex Wu1659daa2012-04-01 20:13:09 +08003333
Kristian Høgsberg32e56862012-04-02 22:18:58 -04003334 shsurf = get_shell_surface(switcher->current);
3335 if (shsurf && shsurf->type ==SHELL_SURFACE_FULLSCREEN)
Kristian Høgsberga416fa12012-05-21 14:06:52 -04003336 shsurf->fullscreen.black_surface->alpha = 1.0;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003337}
3338
3339static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04003340switcher_handle_surface_destroy(struct wl_listener *listener, void *data)
Kristian Høgsberg07045392012-02-19 18:52:44 -05003341{
3342 struct switcher *switcher =
3343 container_of(listener, struct switcher, listener);
3344
3345 switcher_next(switcher);
3346}
3347
3348static void
Daniel Stone351eb612012-05-31 15:27:47 -04003349switcher_destroy(struct switcher *switcher)
Kristian Høgsberg07045392012-02-19 18:52:44 -05003350{
Kristian Høgsberg07045392012-02-19 18:52:44 -05003351 struct weston_surface *surface;
Daniel Stone37816df2012-05-16 18:45:18 +01003352 struct wl_keyboard *keyboard = switcher->grab.keyboard;
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04003353 struct workspace *ws = get_current_workspace(switcher->shell);
Kristian Høgsberg07045392012-02-19 18:52:44 -05003354
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04003355 wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
Kristian Høgsberga416fa12012-05-21 14:06:52 -04003356 surface->alpha = 1.0;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003357 weston_surface_damage(surface);
3358 }
3359
Alex Wu07b26062012-03-12 16:06:01 +08003360 if (switcher->current)
Daniel Stone37816df2012-05-16 18:45:18 +01003361 activate(switcher->shell, switcher->current,
3362 (struct weston_seat *) keyboard->seat);
Kristian Høgsberg07045392012-02-19 18:52:44 -05003363 wl_list_remove(&switcher->listener.link);
Daniel Stone37816df2012-05-16 18:45:18 +01003364 wl_keyboard_end_grab(keyboard);
Kristian Høgsberg07045392012-02-19 18:52:44 -05003365 free(switcher);
3366}
3367
3368static void
3369switcher_key(struct wl_keyboard_grab *grab,
Daniel Stonec9785ea2012-05-30 16:31:52 +01003370 uint32_t time, uint32_t key, uint32_t state_w)
Kristian Høgsberg07045392012-02-19 18:52:44 -05003371{
3372 struct switcher *switcher = container_of(grab, struct switcher, grab);
Daniel Stonec9785ea2012-05-30 16:31:52 +01003373 enum wl_keyboard_key_state state = state_w;
Daniel Stone351eb612012-05-31 15:27:47 -04003374
Daniel Stonec9785ea2012-05-30 16:31:52 +01003375 if (key == KEY_TAB && state == WL_KEYBOARD_KEY_STATE_PRESSED)
Daniel Stone351eb612012-05-31 15:27:47 -04003376 switcher_next(switcher);
3377}
3378
3379static void
3380switcher_modifier(struct wl_keyboard_grab *grab, uint32_t serial,
3381 uint32_t mods_depressed, uint32_t mods_latched,
3382 uint32_t mods_locked, uint32_t group)
3383{
3384 struct switcher *switcher = container_of(grab, struct switcher, grab);
Daniel Stone37816df2012-05-16 18:45:18 +01003385 struct weston_seat *seat = (struct weston_seat *) grab->keyboard->seat;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003386
Daniel Stone351eb612012-05-31 15:27:47 -04003387 if ((seat->modifier_state & switcher->shell->binding_modifier) == 0)
3388 switcher_destroy(switcher);
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04003389}
Kristian Høgsberg07045392012-02-19 18:52:44 -05003390
3391static const struct wl_keyboard_grab_interface switcher_grab = {
Daniel Stone351eb612012-05-31 15:27:47 -04003392 switcher_key,
3393 switcher_modifier,
Kristian Høgsberg07045392012-02-19 18:52:44 -05003394};
3395
3396static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01003397switcher_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
3398 void *data)
Kristian Høgsberg07045392012-02-19 18:52:44 -05003399{
Tiago Vignattibe143262012-04-16 17:31:41 +03003400 struct desktop_shell *shell = data;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003401 struct switcher *switcher;
3402
3403 switcher = malloc(sizeof *switcher);
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04003404 switcher->shell = shell;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003405 switcher->current = NULL;
Kristian Høgsberg27e30522012-04-11 23:18:23 -04003406 switcher->listener.notify = switcher_handle_surface_destroy;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003407 wl_list_init(&switcher->listener.link);
3408
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04003409 lower_fullscreen_layer(switcher->shell);
Kristian Høgsberg07045392012-02-19 18:52:44 -05003410 switcher->grab.interface = &switcher_grab;
Daniel Stone37816df2012-05-16 18:45:18 +01003411 wl_keyboard_start_grab(seat->keyboard, &switcher->grab);
3412 wl_keyboard_set_focus(seat->keyboard, NULL);
Kristian Høgsberg07045392012-02-19 18:52:44 -05003413 switcher_next(switcher);
3414}
3415
Pekka Paalanen3c647232011-12-22 13:43:43 +02003416static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01003417backlight_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
3418 void *data)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003419{
3420 struct weston_compositor *compositor = data;
3421 struct weston_output *output;
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03003422 long backlight_new = 0;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003423
3424 /* TODO: we're limiting to simple use cases, where we assume just
3425 * control on the primary display. We'd have to extend later if we
3426 * ever get support for setting backlights on random desktop LCD
3427 * panels though */
3428 output = get_default_output(compositor);
3429 if (!output)
3430 return;
3431
3432 if (!output->set_backlight)
3433 return;
3434
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03003435 if (key == KEY_F9 || key == KEY_BRIGHTNESSDOWN)
3436 backlight_new = output->backlight_current - 25;
3437 else if (key == KEY_F10 || key == KEY_BRIGHTNESSUP)
3438 backlight_new = output->backlight_current + 25;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003439
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03003440 if (backlight_new < 5)
3441 backlight_new = 5;
3442 if (backlight_new > 255)
3443 backlight_new = 255;
3444
3445 output->backlight_current = backlight_new;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003446 output->set_backlight(output, output->backlight_current);
3447}
3448
3449static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01003450debug_repaint_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
3451 void *data)
Kristian Høgsbergb41c0812012-03-04 14:53:40 -05003452{
Tiago Vignattibe143262012-04-16 17:31:41 +03003453 struct desktop_shell *shell = data;
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04003454 struct weston_compositor *compositor = shell->compositor;
Kristian Høgsbergb41c0812012-03-04 14:53:40 -05003455 struct weston_surface *surface;
Ander Conselvan de Oliveira383b6712012-08-09 16:44:59 +03003456 struct weston_plane plane;
Kristian Høgsbergb41c0812012-03-04 14:53:40 -05003457
3458 if (shell->debug_repaint_surface) {
3459 weston_surface_destroy(shell->debug_repaint_surface);
3460 shell->debug_repaint_surface = NULL;
3461 } else {
3462 surface = weston_surface_create(compositor);
3463 weston_surface_set_color(surface, 1.0, 0.0, 0.0, 0.2);
3464 weston_surface_configure(surface, 0, 0, 8192, 8192);
3465 wl_list_insert(&compositor->fade_layer.surface_list,
3466 &surface->layer_link);
3467 weston_surface_assign_output(surface);
3468 pixman_region32_init(&surface->input);
3469
3470 /* Here's the dirty little trick that makes the
Ander Conselvan de Oliveira383b6712012-08-09 16:44:59 +03003471 * repaint debugging work: we move the surface to a
3472 * different plane and force an update_transform to
3473 * update dependent state and clear the
3474 * geometry.dirty bit. This way the call to
3475 * damage_below() in update_transform() does not
3476 * add damage to the primary plane. */
Kristian Høgsbergb41c0812012-03-04 14:53:40 -05003477
Ander Conselvan de Oliveira383b6712012-08-09 16:44:59 +03003478 weston_plane_init(&plane, 0, 0);
3479 surface->plane = &plane;
Kristian Høgsbergb41c0812012-03-04 14:53:40 -05003480 weston_surface_update_transform(surface);
Kristian Høgsbergb41c0812012-03-04 14:53:40 -05003481 shell->debug_repaint_surface = surface;
Ander Conselvan de Oliveira383b6712012-08-09 16:44:59 +03003482 surface->plane = &compositor->primary_plane;
3483 weston_plane_release(&plane);
Kristian Høgsbergb41c0812012-03-04 14:53:40 -05003484 }
3485}
3486
Pekka Paalanen07c91f82012-08-30 16:47:21 -05003487
3488static void
3489fan_debug_repaint_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
3490 void *data)
3491{
3492 struct desktop_shell *shell = data;
3493 struct weston_compositor *compositor = shell->compositor;
3494 compositor->fan_debug = !compositor->fan_debug;
3495 weston_compositor_damage_all(compositor);
3496}
3497
Kristian Høgsbergb41c0812012-03-04 14:53:40 -05003498static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01003499force_kill_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
3500 void *data)
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04003501{
Philipp Brüschweiler6cef0092012-08-13 21:27:27 +02003502 struct wl_surface *focus_surface;
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04003503 struct wl_client *client;
3504 pid_t pid;
3505 uid_t uid;
3506 gid_t gid;
3507
Philipp Brüschweiler6cef0092012-08-13 21:27:27 +02003508 focus_surface = seat->keyboard->focus;
3509 if (!focus_surface)
3510 return;
3511
3512 client = focus_surface->resource.client;
Daniel Stone325fc2d2012-05-30 16:31:58 +01003513 wl_client_get_credentials(client, &pid, &uid, &gid);
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04003514
Daniel Stone325fc2d2012-05-30 16:31:58 +01003515 kill(pid, SIGKILL);
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04003516}
3517
3518static void
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003519workspace_up_binding(struct wl_seat *seat, uint32_t time,
3520 uint32_t key, void *data)
3521{
3522 struct desktop_shell *shell = data;
3523 unsigned int new_index = shell->workspaces.current;
3524
Kristian Høgsbergce345b02012-06-25 21:35:29 -04003525 if (shell->locked)
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04003526 return;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003527 if (new_index != 0)
3528 new_index--;
3529
3530 change_workspace(shell, new_index);
3531}
3532
3533static void
3534workspace_down_binding(struct wl_seat *seat, uint32_t time,
3535 uint32_t key, void *data)
3536{
3537 struct desktop_shell *shell = data;
3538 unsigned int new_index = shell->workspaces.current;
3539
Kristian Høgsbergce345b02012-06-25 21:35:29 -04003540 if (shell->locked)
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04003541 return;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003542 if (new_index < shell->workspaces.num - 1)
3543 new_index++;
3544
3545 change_workspace(shell, new_index);
3546}
3547
3548static void
3549workspace_f_binding(struct wl_seat *seat, uint32_t time,
3550 uint32_t key, void *data)
3551{
3552 struct desktop_shell *shell = data;
3553 unsigned int new_index;
3554
Kristian Høgsbergce345b02012-06-25 21:35:29 -04003555 if (shell->locked)
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04003556 return;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003557 new_index = key - KEY_F1;
3558 if (new_index >= shell->workspaces.num)
3559 new_index = shell->workspaces.num - 1;
3560
3561 change_workspace(shell, new_index);
3562}
3563
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02003564static void
3565workspace_move_surface_up_binding(struct wl_seat *seat, uint32_t time,
3566 uint32_t key, void *data)
3567{
3568 struct desktop_shell *shell = data;
3569 unsigned int new_index = shell->workspaces.current;
3570
3571 if (shell->locked)
3572 return;
3573
3574 if (new_index != 0)
3575 new_index--;
3576
3577 take_surface_to_workspace_by_seat(shell, seat, new_index);
3578}
3579
3580static void
3581workspace_move_surface_down_binding(struct wl_seat *seat, uint32_t time,
3582 uint32_t key, void *data)
3583{
3584 struct desktop_shell *shell = data;
3585 unsigned int new_index = shell->workspaces.current;
3586
3587 if (shell->locked)
3588 return;
3589
3590 if (new_index < shell->workspaces.num - 1)
3591 new_index++;
3592
3593 take_surface_to_workspace_by_seat(shell, seat, new_index);
3594}
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003595
3596static void
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04003597shell_destroy(struct wl_listener *listener, void *data)
Pekka Paalanen3c647232011-12-22 13:43:43 +02003598{
Tiago Vignattibe143262012-04-16 17:31:41 +03003599 struct desktop_shell *shell =
3600 container_of(listener, struct desktop_shell, destroy_listener);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003601 struct workspace **ws;
Pekka Paalanen3c647232011-12-22 13:43:43 +02003602
Pekka Paalanen9cf5cc82012-01-02 16:00:24 +02003603 if (shell->child.client)
3604 wl_client_destroy(shell->child.client);
3605
Kristian Høgsberg88c16072012-05-16 08:04:19 -04003606 wl_list_remove(&shell->lock_listener.link);
3607 wl_list_remove(&shell->unlock_listener.link);
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003608 wl_list_remove(&shell->show_input_panel_listener.link);
3609 wl_list_remove(&shell->hide_input_panel_listener.link);
Kristian Høgsberg88c16072012-05-16 08:04:19 -04003610
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003611 wl_array_for_each(ws, &shell->workspaces.array)
3612 workspace_destroy(*ws);
3613 wl_array_release(&shell->workspaces.array);
3614
Pekka Paalanen3c647232011-12-22 13:43:43 +02003615 free(shell->screensaver.path);
3616 free(shell);
3617}
3618
Tiago Vignatti0b52d482012-04-20 18:54:25 +03003619static void
3620shell_add_bindings(struct weston_compositor *ec, struct desktop_shell *shell)
3621{
3622 uint32_t mod;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003623 int i, num_workspace_bindings;
Tiago Vignatti0b52d482012-04-20 18:54:25 +03003624
3625 /* fixed bindings */
Daniel Stone325fc2d2012-05-30 16:31:58 +01003626 weston_compositor_add_key_binding(ec, KEY_BACKSPACE,
3627 MODIFIER_CTRL | MODIFIER_ALT,
3628 terminate_binding, ec);
3629 weston_compositor_add_button_binding(ec, BTN_LEFT, 0,
3630 click_to_activate_binding,
3631 shell);
3632 weston_compositor_add_axis_binding(ec, WL_POINTER_AXIS_VERTICAL_SCROLL,
3633 MODIFIER_SUPER | MODIFIER_ALT,
3634 surface_opacity_binding, NULL);
3635 weston_compositor_add_axis_binding(ec, WL_POINTER_AXIS_VERTICAL_SCROLL,
3636 MODIFIER_SUPER, zoom_axis_binding,
3637 NULL);
Tiago Vignatti0b52d482012-04-20 18:54:25 +03003638
3639 /* configurable bindings */
3640 mod = shell->binding_modifier;
Daniel Stone325fc2d2012-05-30 16:31:58 +01003641 weston_compositor_add_key_binding(ec, KEY_PAGEUP, mod,
3642 zoom_key_binding, NULL);
3643 weston_compositor_add_key_binding(ec, KEY_PAGEDOWN, mod,
3644 zoom_key_binding, NULL);
3645 weston_compositor_add_button_binding(ec, BTN_LEFT, mod, move_binding,
3646 shell);
3647 weston_compositor_add_button_binding(ec, BTN_MIDDLE, mod,
3648 resize_binding, shell);
3649 weston_compositor_add_button_binding(ec, BTN_RIGHT, mod,
3650 rotate_binding, NULL);
3651 weston_compositor_add_key_binding(ec, KEY_TAB, mod, switcher_binding,
3652 shell);
3653 weston_compositor_add_key_binding(ec, KEY_F9, mod, backlight_binding,
3654 ec);
3655 weston_compositor_add_key_binding(ec, KEY_BRIGHTNESSDOWN, 0,
3656 backlight_binding, ec);
3657 weston_compositor_add_key_binding(ec, KEY_F10, mod, backlight_binding,
3658 ec);
3659 weston_compositor_add_key_binding(ec, KEY_BRIGHTNESSUP, 0,
3660 backlight_binding, ec);
Kristian Høgsberg73694c82012-06-28 14:13:10 -04003661 weston_compositor_add_key_binding(ec, KEY_SPACE, mod | MODIFIER_SHIFT,
Daniel Stone325fc2d2012-05-30 16:31:58 +01003662 debug_repaint_binding, shell);
Pekka Paalanen07c91f82012-08-30 16:47:21 -05003663 weston_compositor_add_key_binding(ec, KEY_SPACE, mod | MODIFIER_ALT,
3664 fan_debug_repaint_binding, shell);
Daniel Stone325fc2d2012-05-30 16:31:58 +01003665 weston_compositor_add_key_binding(ec, KEY_K, mod,
3666 force_kill_binding, shell);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003667 weston_compositor_add_key_binding(ec, KEY_UP, mod,
3668 workspace_up_binding, shell);
3669 weston_compositor_add_key_binding(ec, KEY_DOWN, mod,
3670 workspace_down_binding, shell);
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02003671 weston_compositor_add_key_binding(ec, KEY_UP, mod | MODIFIER_SHIFT,
3672 workspace_move_surface_up_binding,
3673 shell);
3674 weston_compositor_add_key_binding(ec, KEY_DOWN, mod | MODIFIER_SHIFT,
3675 workspace_move_surface_down_binding,
3676 shell);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003677
3678 /* Add bindings for mod+F[1-6] for workspace 1 to 6. */
3679 if (shell->workspaces.num > 1) {
3680 num_workspace_bindings = shell->workspaces.num;
3681 if (num_workspace_bindings > 6)
3682 num_workspace_bindings = 6;
3683 for (i = 0; i < num_workspace_bindings; i++)
3684 weston_compositor_add_key_binding(ec, KEY_F1 + i, mod,
3685 workspace_f_binding,
3686 shell);
3687 }
Tiago Vignatti0b52d482012-04-20 18:54:25 +03003688}
3689
Kristian Høgsberg6c709a32011-05-06 14:52:41 -04003690int
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05003691shell_init(struct weston_compositor *ec);
Kristian Høgsberg6c709a32011-05-06 14:52:41 -04003692
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003693WL_EXPORT int
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05003694shell_init(struct weston_compositor *ec)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05003695{
Kristian Høgsbergf4d2f232012-08-10 10:05:39 -04003696 struct weston_seat *seat;
Tiago Vignattibe143262012-04-16 17:31:41 +03003697 struct desktop_shell *shell;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003698 struct workspace **pws;
3699 unsigned int i;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04003700
3701 shell = malloc(sizeof *shell);
3702 if (shell == NULL)
3703 return -1;
3704
Kristian Høgsbergf0d91162011-10-11 22:44:23 -04003705 memset(shell, 0, sizeof *shell);
Kristian Høgsberg75840622011-09-06 13:48:16 -04003706 shell->compositor = ec;
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04003707
3708 shell->destroy_listener.notify = shell_destroy;
3709 wl_signal_add(&ec->destroy_signal, &shell->destroy_listener);
3710 shell->lock_listener.notify = lock;
3711 wl_signal_add(&ec->lock_signal, &shell->lock_listener);
3712 shell->unlock_listener.notify = unlock;
3713 wl_signal_add(&ec->unlock_signal, &shell->unlock_listener);
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003714 shell->show_input_panel_listener.notify = show_input_panels;
3715 wl_signal_add(&ec->show_input_panel_signal, &shell->show_input_panel_listener);
3716 shell->hide_input_panel_listener.notify = hide_input_panels;
3717 wl_signal_add(&ec->hide_input_panel_signal, &shell->hide_input_panel_listener);
Scott Moreauff1db4a2012-04-17 19:06:18 -06003718 ec->ping_handler = ping_handler;
Kristian Høgsberg82a1d112012-07-19 14:02:00 -04003719 ec->shell_interface.shell = shell;
Tiago Vignattibc052c92012-04-19 16:18:18 +03003720 ec->shell_interface.create_shell_surface = create_shell_surface;
3721 ec->shell_interface.set_toplevel = set_toplevel;
Tiago Vignatti491bac12012-05-18 16:37:43 -04003722 ec->shell_interface.set_transient = set_transient;
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04003723 ec->shell_interface.move = surface_move;
Kristian Høgsbergc1693f22012-05-22 16:56:23 -04003724 ec->shell_interface.resize = surface_resize;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05003725
Pekka Paalanen77346a62011-11-30 16:26:35 +02003726 wl_list_init(&shell->screensaver.surfaces);
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003727 wl_list_init(&shell->input_panel.surfaces);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02003728
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05003729 weston_layer_init(&shell->fullscreen_layer, &ec->cursor_layer.link);
3730 weston_layer_init(&shell->panel_layer, &shell->fullscreen_layer.link);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003731 weston_layer_init(&shell->background_layer, &shell->panel_layer.link);
3732 weston_layer_init(&shell->lock_layer, NULL);
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02003733 weston_layer_init(&shell->input_panel_layer, NULL);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003734
3735 wl_array_init(&shell->workspaces.array);
Jonas Ådahle9d22502012-08-29 22:13:01 +02003736 wl_list_init(&shell->workspaces.client_list);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05003737
Kristian Høgsberg6af8eb92012-01-25 16:57:11 -05003738 shell_configuration(shell);
Pekka Paalanene955f1e2011-12-07 11:49:52 +02003739
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003740 for (i = 0; i < shell->workspaces.num; i++) {
3741 pws = wl_array_add(&shell->workspaces.array, sizeof *pws);
3742 if (pws == NULL)
3743 return -1;
3744
3745 *pws = workspace_create();
3746 if (*pws == NULL)
3747 return -1;
3748 }
3749 activate_workspace(shell, 0);
3750
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02003751 wl_list_init(&shell->workspaces.anim_sticky_list);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02003752 wl_list_init(&shell->workspaces.animation.link);
3753 shell->workspaces.animation.frame = animate_workspace_change_frame;
3754
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04003755 if (wl_display_add_global(ec->wl_display, &wl_shell_interface,
3756 shell, bind_shell) == NULL)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05003757 return -1;
3758
Kristian Høgsberg75840622011-09-06 13:48:16 -04003759 if (wl_display_add_global(ec->wl_display,
3760 &desktop_shell_interface,
3761 shell, bind_desktop_shell) == NULL)
3762 return -1;
3763
Pekka Paalanen6e168112011-11-24 11:34:05 +02003764 if (wl_display_add_global(ec->wl_display, &screensaver_interface,
3765 shell, bind_screensaver) == NULL)
3766 return -1;
3767
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003768 if (wl_display_add_global(ec->wl_display, &input_panel_interface,
3769 shell, bind_input_panel) == NULL)
3770 return -1;
3771
Jonas Ådahle9d22502012-08-29 22:13:01 +02003772 if (wl_display_add_global(ec->wl_display, &workspace_manager_interface,
3773 shell, bind_workspace_manager) == NULL)
3774 return -1;
3775
Kristian Høgsbergf03a6162012-01-17 11:07:42 -05003776 shell->child.deathstamp = weston_compositor_get_time();
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02003777 if (launch_desktop_shell_process(shell) != 0)
3778 return -1;
3779
Kristian Høgsbergf4d2f232012-08-10 10:05:39 -04003780 wl_list_for_each(seat, &ec->seat_list, link)
3781 create_pointer_focus_listener(seat);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04003782
Tiago Vignatti0b52d482012-04-20 18:54:25 +03003783 shell_add_bindings(ec, shell);
Kristian Høgsberg07937562011-04-12 17:25:42 -04003784
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05003785 return 0;
3786}