blob: 6821836593c458e67356f8ae1207127fe6be988c [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"
Pekka Paalanene955f1e2011-12-07 11:49:52 +020038#include "../shared/config-parser.h"
Martin Minarik6d118362012-06-07 18:01:59 +020039#include "log.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
Tiago Vignattibe143262012-04-16 17:31:41 +030067struct desktop_shell {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050068 struct weston_compositor *compositor;
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -040069
70 struct wl_listener lock_listener;
71 struct wl_listener unlock_listener;
72 struct wl_listener destroy_listener;
Jan Arne Petersen42feced2012-06-21 21:52:17 +020073 struct wl_listener show_input_panel_listener;
74 struct wl_listener hide_input_panel_listener;
Pekka Paalanen6cd281a2011-11-03 14:11:32 +020075
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -050076 struct weston_layer fullscreen_layer;
77 struct weston_layer panel_layer;
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -050078 struct weston_layer background_layer;
79 struct weston_layer lock_layer;
80
Kristian Høgsbergd56bd902012-06-05 09:58:51 -040081 struct wl_listener pointer_focus_listener;
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +030082 struct weston_surface *grab_surface;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -040083
Pekka Paalanen6cd281a2011-11-03 14:11:32 +020084 struct {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050085 struct weston_process process;
Pekka Paalanen6cd281a2011-11-03 14:11:32 +020086 struct wl_client *client;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +020087 struct wl_resource *desktop_shell;
Pekka Paalanen4d733ee2012-01-17 14:36:27 +020088
89 unsigned deathcount;
90 uint32_t deathstamp;
Pekka Paalanen6cd281a2011-11-03 14:11:32 +020091 } child;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +020092
93 bool locked;
94 bool prepare_event_sent;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +020095
Kristian Høgsberg730c94d2012-06-26 21:44:35 -040096 struct weston_surface *lock_surface;
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -050097 struct wl_listener lock_surface_listener;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +010098
Pekka Paalanen77346a62011-11-30 16:26:35 +020099 struct {
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200100 struct wl_array array;
101 unsigned int current;
102 unsigned int num;
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200103
104 struct weston_animation animation;
105 int anim_dir;
106 uint32_t anim_timestamp;
107 double anim_current;
108 struct workspace *anim_from;
109 struct workspace *anim_to;
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200110 } workspaces;
111
112 struct {
Pekka Paalanen3c647232011-12-22 13:43:43 +0200113 char *path;
Pekka Paalanen7296e792011-12-07 16:22:00 +0200114 int duration;
Pekka Paalanen77346a62011-11-30 16:26:35 +0200115 struct wl_resource *binding;
116 struct wl_list surfaces;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500117 struct weston_process process;
Pekka Paalanen77346a62011-11-30 16:26:35 +0200118 } screensaver;
Kristian Høgsbergb41c0812012-03-04 14:53:40 -0500119
Jan Arne Petersen42feced2012-06-21 21:52:17 +0200120 struct {
121 struct wl_resource *binding;
122 struct wl_list surfaces;
123 } input_panel;
124
Tiago Vignatti0b52d482012-04-20 18:54:25 +0300125 uint32_t binding_modifier;
Juan Zhaoe10d2792012-04-25 19:09:52 +0800126 enum animation_type win_animation_type;
Kristian Høgsbergb41c0812012-03-04 14:53:40 -0500127 struct weston_surface *debug_repaint_surface;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400128};
129
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500130enum shell_surface_type {
Pekka Paalanen98262232011-12-01 10:42:22 +0200131 SHELL_SURFACE_NONE,
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500132 SHELL_SURFACE_TOPLEVEL,
133 SHELL_SURFACE_TRANSIENT,
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500134 SHELL_SURFACE_FULLSCREEN,
Juan Zhao96879df2012-02-07 08:45:41 +0800135 SHELL_SURFACE_MAXIMIZED,
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500136 SHELL_SURFACE_POPUP
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200137};
138
Scott Moreauff1db4a2012-04-17 19:06:18 -0600139struct ping_timer {
140 struct wl_event_source *source;
Scott Moreauff1db4a2012-04-17 19:06:18 -0600141 uint32_t serial;
142};
143
Pekka Paalanen56cdea92011-11-23 16:14:12 +0200144struct shell_surface {
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200145 struct wl_resource resource;
146
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500147 struct weston_surface *surface;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200148 struct wl_listener surface_destroy_listener;
Kristian Høgsberg8150b192012-06-27 10:22:58 -0400149 struct weston_surface *parent;
Tiago Vignattibe143262012-04-16 17:31:41 +0300150 struct desktop_shell *shell;
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200151
Kristian Høgsberg7f366e72012-04-27 17:20:01 -0400152 enum shell_surface_type type, next_type;
Kristian Høgsberge7afd912012-05-02 09:47:44 -0400153 char *title, *class;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500154 int32_t saved_x, saved_y;
Alex Wu4539b082012-03-01 12:57:46 +0800155 bool saved_position_valid;
Alex Wu7bcb8bd2012-04-27 09:07:24 +0800156 bool saved_rotation_valid;
Scott Moreauff1db4a2012-04-17 19:06:18 -0600157 int unresponsive;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100158
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500159 struct {
Pekka Paalanen460099f2012-01-20 16:48:25 +0200160 struct weston_transform transform;
Kristian Høgsberg765e27b2012-01-27 13:36:13 -0500161 struct weston_matrix rotation;
Pekka Paalanen460099f2012-01-20 16:48:25 +0200162 } rotation;
163
164 struct {
Scott Moreau447013d2012-02-18 05:05:29 -0700165 struct wl_pointer_grab grab;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500166 int32_t x, y;
Pekka Paalanen938269a2012-02-07 14:19:01 +0200167 struct weston_transform parent_transform;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500168 int32_t initial_up;
Daniel Stone37816df2012-05-16 18:45:18 +0100169 struct wl_seat *seat;
Kristian Høgsberg3730f362012-04-13 12:40:07 -0400170 uint32_t serial;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500171 } popup;
172
Alex Wu4539b082012-03-01 12:57:46 +0800173 struct {
Tiago Vignatti52e598c2012-05-07 15:23:08 +0300174 int32_t x, y;
Tiago Vignatti491bac12012-05-18 16:37:43 -0400175 uint32_t flags;
Tiago Vignatti52e598c2012-05-07 15:23:08 +0300176 } transient;
177
178 struct {
Alex Wu4539b082012-03-01 12:57:46 +0800179 enum wl_shell_surface_fullscreen_method type;
180 struct weston_transform transform; /* matrix from x, y */
181 uint32_t framerate;
182 struct weston_surface *black_surface;
183 } fullscreen;
184
Scott Moreauff1db4a2012-04-17 19:06:18 -0600185 struct ping_timer *ping_timer;
186
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200187 struct weston_transform workspace_transform;
188
Kristian Høgsberg1cbf3262012-02-17 23:49:07 -0500189 struct weston_output *fullscreen_output;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500190 struct weston_output *output;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100191 struct wl_list link;
Kristian Høgsberga61ca062012-05-22 16:05:52 -0400192
193 const struct weston_shell_client *client;
Pekka Paalanen56cdea92011-11-23 16:14:12 +0200194};
195
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300196struct shell_grab {
Scott Moreau447013d2012-02-18 05:05:29 -0700197 struct wl_pointer_grab grab;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300198 struct shell_surface *shsurf;
199 struct wl_listener shsurf_destroy_listener;
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300200 struct wl_pointer *pointer;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300201};
202
203struct weston_move_grab {
204 struct shell_grab base;
Daniel Stone103db7f2012-05-08 17:17:55 +0100205 wl_fixed_t dx, dy;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500206};
207
Pekka Paalanen460099f2012-01-20 16:48:25 +0200208struct rotate_grab {
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300209 struct shell_grab base;
Kristian Høgsberg765e27b2012-01-27 13:36:13 -0500210 struct weston_matrix rotation;
Pekka Paalanen460099f2012-01-20 16:48:25 +0200211 struct {
Kristian Høgsbergb2af93e2012-06-07 20:10:23 -0400212 GLfloat x;
213 GLfloat y;
Pekka Paalanen460099f2012-01-20 16:48:25 +0200214 } center;
215};
216
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400217static void
218activate(struct desktop_shell *shell, struct weston_surface *es,
219 struct weston_seat *seat);
220
221static struct workspace *
222get_current_workspace(struct desktop_shell *shell);
223
Alex Wubd3354b2012-04-17 17:20:49 +0800224static struct shell_surface *
225get_shell_surface(struct weston_surface *surface);
226
227static struct desktop_shell *
228shell_surface_get_shell(struct shell_surface *shsurf);
229
230static bool
231shell_surface_is_top_fullscreen(struct shell_surface *shsurf)
232{
233 struct desktop_shell *shell;
234 struct weston_surface *top_fs_es;
235
236 shell = shell_surface_get_shell(shsurf);
237
238 if (wl_list_empty(&shell->fullscreen_layer.surface_list))
239 return false;
240
241 top_fs_es = container_of(shell->fullscreen_layer.surface_list.next,
242 struct weston_surface,
243 layer_link);
244 return (shsurf == get_shell_surface(top_fs_es));
245}
246
Kristian Høgsberg6af8eb92012-01-25 16:57:11 -0500247static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400248destroy_shell_grab_shsurf(struct wl_listener *listener, void *data)
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300249{
250 struct shell_grab *grab;
251
252 grab = container_of(listener, struct shell_grab,
253 shsurf_destroy_listener);
254
255 grab->shsurf = NULL;
256}
257
258static void
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300259shell_grab_start(struct shell_grab *grab,
260 const struct wl_pointer_grab_interface *interface,
261 struct shell_surface *shsurf,
262 struct wl_pointer *pointer,
263 enum desktop_shell_cursor cursor)
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300264{
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300265 struct desktop_shell *shell = shsurf->shell;
266
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300267 grab->grab.interface = interface;
268 grab->shsurf = shsurf;
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400269 grab->shsurf_destroy_listener.notify = destroy_shell_grab_shsurf;
270 wl_signal_add(&shsurf->resource.destroy_signal,
271 &grab->shsurf_destroy_listener);
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300272
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300273 grab->pointer = pointer;
274 grab->grab.focus = &shsurf->surface->surface;
275
276 wl_pointer_start_grab(pointer, &grab->grab);
277 desktop_shell_send_grab_cursor(shell->child.desktop_shell, cursor);
278 wl_pointer_set_focus(pointer, &shell->grab_surface->surface,
279 wl_fixed_from_int(0), wl_fixed_from_int(0));
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300280}
281
282static void
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300283shell_grab_end(struct shell_grab *grab)
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300284{
Kristian Høgsberg47b5dca2012-06-07 18:08:04 -0400285 if (grab->shsurf)
286 wl_list_remove(&grab->shsurf_destroy_listener.link);
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300287
288 wl_pointer_end_grab(grab->pointer);
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300289}
290
291static void
Alex Wu4539b082012-03-01 12:57:46 +0800292center_on_output(struct weston_surface *surface,
293 struct weston_output *output);
294
Daniel Stone496ca172012-05-30 16:31:42 +0100295static enum weston_keyboard_modifier
Tiago Vignatti0b52d482012-04-20 18:54:25 +0300296get_modifier(char *modifier)
297{
298 if (!modifier)
299 return MODIFIER_SUPER;
300
301 if (!strcmp("ctrl", modifier))
302 return MODIFIER_CTRL;
303 else if (!strcmp("alt", modifier))
304 return MODIFIER_ALT;
305 else if (!strcmp("super", modifier))
306 return MODIFIER_SUPER;
307 else
308 return MODIFIER_SUPER;
309}
310
Juan Zhaoe10d2792012-04-25 19:09:52 +0800311static enum animation_type
312get_animation_type(char *animation)
313{
314 if (!animation)
315 return ANIMATION_NONE;
316
317 if (!strcmp("zoom", animation))
318 return ANIMATION_ZOOM;
319 else if (!strcmp("fade", animation))
320 return ANIMATION_FADE;
321 else
322 return ANIMATION_NONE;
323}
324
Alex Wu4539b082012-03-01 12:57:46 +0800325static void
Tiago Vignattibe143262012-04-16 17:31:41 +0300326shell_configuration(struct desktop_shell *shell)
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200327{
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200328 char *config_file;
Pekka Paalanen7296e792011-12-07 16:22:00 +0200329 char *path = NULL;
330 int duration = 60;
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200331 unsigned int num_workspaces = DEFAULT_NUM_WORKSPACES;
Tiago Vignatti0b52d482012-04-20 18:54:25 +0300332 char *modifier = NULL;
Juan Zhaoe10d2792012-04-25 19:09:52 +0800333 char *win_animation = NULL;
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200334
Kristian Høgsberga4e8b332012-04-20 16:48:21 -0400335 struct config_key shell_keys[] = {
Tiago Vignatti0b52d482012-04-20 18:54:25 +0300336 { "binding-modifier", CONFIG_KEY_STRING, &modifier },
Juan Zhaoe10d2792012-04-25 19:09:52 +0800337 { "animation", CONFIG_KEY_STRING, &win_animation},
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200338 { "num-workspaces",
339 CONFIG_KEY_UNSIGNED_INTEGER, &num_workspaces },
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200340 };
341
Kristian Høgsberga4e8b332012-04-20 16:48:21 -0400342 struct config_key saver_keys[] = {
343 { "path", CONFIG_KEY_STRING, &path },
344 { "duration", CONFIG_KEY_INTEGER, &duration },
345 };
346
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200347 struct config_section cs[] = {
Kristian Høgsberga4e8b332012-04-20 16:48:21 -0400348 { "shell", shell_keys, ARRAY_LENGTH(shell_keys), NULL },
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200349 { "screensaver", saver_keys, ARRAY_LENGTH(saver_keys), NULL },
350 };
351
Tiago Vignatti9a206c42012-03-21 19:49:18 +0200352 config_file = config_file_path("weston.ini");
Kristian Høgsberg6af8eb92012-01-25 16:57:11 -0500353 parse_config_file(config_file, cs, ARRAY_LENGTH(cs), shell);
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200354 free(config_file);
355
Pekka Paalanen7296e792011-12-07 16:22:00 +0200356 shell->screensaver.path = path;
357 shell->screensaver.duration = duration;
Tiago Vignatti0b52d482012-04-20 18:54:25 +0300358 shell->binding_modifier = get_modifier(modifier);
Juan Zhaoe10d2792012-04-25 19:09:52 +0800359 shell->win_animation_type = get_animation_type(win_animation);
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200360 shell->workspaces.num = num_workspaces > 0 ? num_workspaces : 1;
361}
362
363static void
Jonas Ådahl04769742012-06-13 00:01:24 +0200364focus_state_destroy(struct focus_state *state)
365{
366 wl_list_remove(&state->seat_destroy_listener.link);
367 wl_list_remove(&state->surface_destroy_listener.link);
368 free(state);
369}
370
371static void
372focus_state_seat_destroy(struct wl_listener *listener, void *data)
373{
374 struct focus_state *state = container_of(listener,
375 struct focus_state,
376 seat_destroy_listener);
377
378 wl_list_remove(&state->link);
379 focus_state_destroy(state);
380}
381
382static void
383focus_state_surface_destroy(struct wl_listener *listener, void *data)
384{
385 struct focus_state *state = container_of(listener,
386 struct focus_state,
Kristian Høgsbergb8e0d0f2012-07-31 10:30:26 -0400387 surface_destroy_listener);
Kristian Høgsberge3778222012-07-31 17:29:30 -0400388 struct desktop_shell *shell;
389 struct weston_surface *surface, *next;
Jonas Ådahl04769742012-06-13 00:01:24 +0200390
Kristian Høgsberge3778222012-07-31 17:29:30 -0400391 next = NULL;
392 wl_list_for_each(surface, &state->ws->layer.surface_list, layer_link) {
393 if (surface == state->keyboard_focus)
394 continue;
395
396 next = surface;
397 break;
398 }
399
400 if (next) {
401 shell = state->seat->compositor->shell_interface.shell;
402 activate(shell, next, state->seat);
403 } else {
404 wl_list_remove(&state->link);
405 focus_state_destroy(state);
406 }
Jonas Ådahl04769742012-06-13 00:01:24 +0200407}
408
409static struct focus_state *
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400410focus_state_create(struct weston_seat *seat, struct workspace *ws)
Jonas Ådahl04769742012-06-13 00:01:24 +0200411{
Jonas Ådahl04769742012-06-13 00:01:24 +0200412 struct focus_state *state;
Jonas Ådahl04769742012-06-13 00:01:24 +0200413
414 state = malloc(sizeof *state);
415 if (state == NULL)
416 return NULL;
417
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400418 state->ws = ws;
Jonas Ådahl04769742012-06-13 00:01:24 +0200419 state->seat = seat;
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400420 wl_list_insert(&ws->focus_list, &state->link);
Jonas Ådahl04769742012-06-13 00:01:24 +0200421
422 state->seat_destroy_listener.notify = focus_state_seat_destroy;
423 state->surface_destroy_listener.notify = focus_state_surface_destroy;
424 wl_signal_add(&seat->seat.destroy_signal,
425 &state->seat_destroy_listener);
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400426 wl_list_init(&state->surface_destroy_listener.link);
Jonas Ådahl04769742012-06-13 00:01:24 +0200427
428 return state;
429}
430
431static void
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400432restore_focus_state(struct desktop_shell *shell, struct workspace *ws)
Jonas Ådahl04769742012-06-13 00:01:24 +0200433{
434 struct focus_state *state, *next;
435
436 wl_list_for_each_safe(state, next, &ws->focus_list, link) {
437 if (state->keyboard_focus)
438 wl_keyboard_set_focus(state->seat->seat.keyboard,
439 &state->keyboard_focus->surface);
Jonas Ådahl04769742012-06-13 00:01:24 +0200440 }
441}
442
443static void
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200444workspace_destroy(struct workspace *ws)
445{
Jonas Ådahl04769742012-06-13 00:01:24 +0200446 struct focus_state *state, *next;
447
448 wl_list_for_each_safe(state, next, &ws->focus_list, link)
449 focus_state_destroy(state);
450
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200451 free(ws);
452}
453
Jonas Ådahl04769742012-06-13 00:01:24 +0200454static void
455seat_destroyed(struct wl_listener *listener, void *data)
456{
457 struct weston_seat *seat = data;
458 struct focus_state *state, *next;
459 struct workspace *ws = container_of(listener,
460 struct workspace,
461 seat_destroyed_listener);
462
463 wl_list_for_each_safe(state, next, &ws->focus_list, link)
464 if (state->seat == seat)
465 wl_list_remove(&state->link);
466}
467
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200468static struct workspace *
469workspace_create(void)
470{
471 struct workspace *ws = malloc(sizeof *ws);
472 if (ws == NULL)
473 return NULL;
474
475 weston_layer_init(&ws->layer, NULL);
476
Jonas Ådahl04769742012-06-13 00:01:24 +0200477 wl_list_init(&ws->focus_list);
478 wl_list_init(&ws->seat_destroyed_listener.link);
479 ws->seat_destroyed_listener.notify = seat_destroyed;
480
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200481 return ws;
482}
483
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200484static int
485workspace_is_empty(struct workspace *ws)
486{
487 return wl_list_empty(&ws->layer.surface_list);
488}
489
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200490static struct workspace *
491get_workspace(struct desktop_shell *shell, unsigned int index)
492{
493 struct workspace **pws = shell->workspaces.array.data;
494 pws += index;
495 return *pws;
496}
497
498static struct workspace *
499get_current_workspace(struct desktop_shell *shell)
500{
501 return get_workspace(shell, shell->workspaces.current);
502}
503
504static void
505activate_workspace(struct desktop_shell *shell, unsigned int index)
506{
507 struct workspace *ws;
508
509 ws = get_workspace(shell, index);
510 wl_list_insert(&shell->panel_layer.link, &ws->layer.link);
511
512 shell->workspaces.current = index;
513}
514
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200515static unsigned int
516get_output_height(struct weston_output *output)
517{
518 return abs(output->region.extents.y1 - output->region.extents.y2);
519}
520
521static void
522surface_translate(struct weston_surface *surface, double d)
523{
524 struct shell_surface *shsurf = get_shell_surface(surface);
525 struct weston_transform *transform;
526
527 transform = &shsurf->workspace_transform;
528 if (wl_list_empty(&transform->link))
529 wl_list_insert(surface->geometry.transformation_list.prev,
530 &shsurf->workspace_transform.link);
531
532 weston_matrix_init(&shsurf->workspace_transform.matrix);
533 weston_matrix_translate(&shsurf->workspace_transform.matrix,
534 0.0, d, 0.0);
535 surface->geometry.dirty = 1;
536}
537
538static void
539workspace_translate_out(struct workspace *ws, double fraction)
540{
541 struct weston_surface *surface;
542 unsigned int height;
543 double d;
544
545 wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
546 height = get_output_height(surface->output);
547 d = height * fraction;
548
549 surface_translate(surface, d);
550 }
551}
552
553static void
554workspace_translate_in(struct workspace *ws, double fraction)
555{
556 struct weston_surface *surface;
557 unsigned int height;
558 double d;
559
560 wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
561 height = get_output_height(surface->output);
562
563 if (fraction > 0)
564 d = -(height - height * fraction);
565 else
566 d = height + height * fraction;
567
568 surface_translate(surface, d);
569 }
570}
571
572static void
573workspace_damage_all_surfaces(struct workspace *ws)
574{
575 struct weston_surface *surface;
576
577 wl_list_for_each(surface, &ws->layer.surface_list, layer_link)
578 weston_surface_damage(surface);
579}
580
581static void
582reverse_workspace_change_animation(struct desktop_shell *shell,
583 unsigned int index,
584 struct workspace *from,
585 struct workspace *to)
586{
587 shell->workspaces.current = index;
588
589 shell->workspaces.anim_to = to;
590 shell->workspaces.anim_from = from;
591 shell->workspaces.anim_dir = -1 * shell->workspaces.anim_dir;
592 shell->workspaces.anim_timestamp = 0;
593
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400594 restore_focus_state(shell, to);
Jonas Ådahl04769742012-06-13 00:01:24 +0200595
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200596 workspace_damage_all_surfaces(from);
597 workspace_damage_all_surfaces(to);
598}
599
600static void
601workspace_deactivate_transforms(struct workspace *ws)
602{
603 struct weston_surface *surface;
604 struct shell_surface *shsurf;
605
606 wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
607 shsurf = get_shell_surface(surface);
608 wl_list_remove(&shsurf->workspace_transform.link);
609 wl_list_init(&shsurf->workspace_transform.link);
610 shsurf->surface->geometry.dirty = 1;
611 }
612}
613
614static void
615finish_workspace_change_animation(struct desktop_shell *shell,
616 struct workspace *from,
617 struct workspace *to)
618{
619 workspace_damage_all_surfaces(from);
620 workspace_damage_all_surfaces(to);
621
622 wl_list_remove(&shell->workspaces.animation.link);
623 workspace_deactivate_transforms(from);
624 workspace_deactivate_transforms(to);
625 shell->workspaces.anim_to = NULL;
626
627 wl_list_remove(&shell->workspaces.anim_from->layer.link);
628}
629
630static void
631animate_workspace_change_frame(struct weston_animation *animation,
632 struct weston_output *output, uint32_t msecs)
633{
634 struct desktop_shell *shell =
635 container_of(animation, struct desktop_shell,
636 workspaces.animation);
637 struct workspace *from = shell->workspaces.anim_from;
638 struct workspace *to = shell->workspaces.anim_to;
639 uint32_t t;
640 double x, y;
641
642 if (workspace_is_empty(from) && workspace_is_empty(to)) {
643 finish_workspace_change_animation(shell, from, to);
644 return;
645 }
646
647 if (shell->workspaces.anim_timestamp == 0) {
648 if (shell->workspaces.anim_current == 0.0)
649 shell->workspaces.anim_timestamp = msecs;
650 else
651 shell->workspaces.anim_timestamp =
652 msecs -
653 /* Invers of movement function 'y' below. */
654 (asin(1.0 - shell->workspaces.anim_current) *
655 DEFAULT_WORKSPACE_CHANGE_ANIMATION_LENGTH *
656 M_2_PI);
657 }
658
659 t = msecs - shell->workspaces.anim_timestamp;
660
661 /*
662 * x = [0, π/2]
663 * y(x) = sin(x)
664 */
665 x = t * (1.0/DEFAULT_WORKSPACE_CHANGE_ANIMATION_LENGTH) * M_PI_2;
666 y = sin(x);
667
668 if (t < DEFAULT_WORKSPACE_CHANGE_ANIMATION_LENGTH) {
669 workspace_damage_all_surfaces(from);
670 workspace_damage_all_surfaces(to);
671
672 workspace_translate_out(from, shell->workspaces.anim_dir * y);
673 workspace_translate_in(to, shell->workspaces.anim_dir * y);
674 shell->workspaces.anim_current = y;
675
676 workspace_damage_all_surfaces(from);
677 workspace_damage_all_surfaces(to);
678 }
Jonas Ådahl04769742012-06-13 00:01:24 +0200679 else
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200680 finish_workspace_change_animation(shell, from, to);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200681}
682
683static void
684animate_workspace_change(struct desktop_shell *shell,
685 unsigned int index,
686 struct workspace *from,
687 struct workspace *to)
688{
689 struct weston_output *output;
690
691 int dir;
692
693 if (index > shell->workspaces.current)
694 dir = -1;
695 else
696 dir = 1;
697
698 shell->workspaces.current = index;
699
700 shell->workspaces.anim_dir = dir;
701 shell->workspaces.anim_from = from;
702 shell->workspaces.anim_to = to;
703 shell->workspaces.anim_current = 0.0;
704 shell->workspaces.anim_timestamp = 0;
705
706 output = container_of(shell->compositor->output_list.next,
707 struct weston_output, link);
708 wl_list_insert(&output->animation_list,
709 &shell->workspaces.animation.link);
710
711 wl_list_insert(&from->layer.link, &to->layer.link);
712
713 workspace_translate_in(to, 0);
714
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400715 restore_focus_state(shell, to);
Jonas Ådahl04769742012-06-13 00:01:24 +0200716
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200717 workspace_damage_all_surfaces(from);
718 workspace_damage_all_surfaces(to);
719}
720
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200721static void
722change_workspace(struct desktop_shell *shell, unsigned int index)
723{
724 struct workspace *from;
725 struct workspace *to;
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200726
727 if (index == shell->workspaces.current)
728 return;
729
730 /* Don't change workspace when there is any fullscreen surfaces. */
731 if (!wl_list_empty(&shell->fullscreen_layer.surface_list))
732 return;
733
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200734 from = get_current_workspace(shell);
735 to = get_workspace(shell, index);
736
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200737 if (shell->workspaces.anim_from == to &&
738 shell->workspaces.anim_to == from) {
739 reverse_workspace_change_animation(shell, index, from, to);
740 return;
741 }
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200742
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200743 if (shell->workspaces.anim_to != NULL)
744 finish_workspace_change_animation(shell,
745 shell->workspaces.anim_from,
746 shell->workspaces.anim_to);
747
748 if (workspace_is_empty(to) && workspace_is_empty(from)) {
749 shell->workspaces.current = index;
750 wl_list_insert(&from->layer.link, &to->layer.link);
751 wl_list_remove(&from->layer.link);
Jonas Ådahl04769742012-06-13 00:01:24 +0200752
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400753 restore_focus_state(shell, to);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200754 }
755 else
756 animate_workspace_change(shell, index, from, to);
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200757}
758
Pekka Paalanen56cdea92011-11-23 16:14:12 +0200759static void
Kristian Høgsbergeae5de72012-04-11 22:42:15 -0400760noop_grab_focus(struct wl_pointer_grab *grab,
Daniel Stone103db7f2012-05-08 17:17:55 +0100761 struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y)
Kristian Høgsberg9ddb8262012-01-04 21:30:29 -0500762{
763 grab->focus = NULL;
764}
765
766static void
Scott Moreau447013d2012-02-18 05:05:29 -0700767move_grab_motion(struct wl_pointer_grab *grab,
Daniel Stone103db7f2012-05-08 17:17:55 +0100768 uint32_t time, wl_fixed_t x, wl_fixed_t y)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500769{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500770 struct weston_move_grab *move = (struct weston_move_grab *) grab;
Daniel Stone37816df2012-05-16 18:45:18 +0100771 struct wl_pointer *pointer = grab->pointer;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300772 struct shell_surface *shsurf = move->base.shsurf;
773 struct weston_surface *es;
Daniel Stone37816df2012-05-16 18:45:18 +0100774 int dx = wl_fixed_to_int(pointer->x + move->dx);
775 int dy = wl_fixed_to_int(pointer->y + move->dy);
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300776
777 if (!shsurf)
778 return;
779
780 es = shsurf->surface;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500781
Daniel Stone103db7f2012-05-08 17:17:55 +0100782 weston_surface_configure(es, dx, dy,
Pekka Paalanen60921e52012-01-25 15:55:43 +0200783 es->geometry.width, es->geometry.height);
Kristian Høgsberg6c6fb992012-06-21 12:06:22 -0400784
785 weston_compositor_schedule_repaint(es->compositor);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500786}
787
788static void
Scott Moreau447013d2012-02-18 05:05:29 -0700789move_grab_button(struct wl_pointer_grab *grab,
Daniel Stone4dbadb12012-05-30 16:31:51 +0100790 uint32_t time, uint32_t button, uint32_t state_w)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500791{
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300792 struct shell_grab *shell_grab = container_of(grab, struct shell_grab,
793 grab);
Daniel Stone37816df2012-05-16 18:45:18 +0100794 struct wl_pointer *pointer = grab->pointer;
Daniel Stone4dbadb12012-05-30 16:31:51 +0100795 enum wl_pointer_button_state state = state_w;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500796
Daniel Stone4dbadb12012-05-30 16:31:51 +0100797 if (pointer->button_count == 0 &&
798 state == WL_POINTER_BUTTON_STATE_RELEASED) {
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300799 shell_grab_end(shell_grab);
Kristian Høgsberg9ddb8262012-01-04 21:30:29 -0500800 free(grab);
801 }
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500802}
803
Scott Moreau447013d2012-02-18 05:05:29 -0700804static const struct wl_pointer_grab_interface move_grab_interface = {
Kristian Høgsberg9ddb8262012-01-04 21:30:29 -0500805 noop_grab_focus,
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500806 move_grab_motion,
807 move_grab_button,
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500808};
809
Scott Moreauc3e54eb2012-04-17 19:06:20 -0600810static void
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400811busy_cursor_grab_focus(struct wl_pointer_grab *base,
812 struct wl_surface *surface, int32_t x, int32_t y)
Scott Moreauc3e54eb2012-04-17 19:06:20 -0600813{
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400814 struct shell_grab *grab = (struct shell_grab *) base;
Scott Moreauc3e54eb2012-04-17 19:06:20 -0600815
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400816 if (grab->grab.focus != surface) {
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300817 shell_grab_end(grab);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400818 free(grab);
Scott Moreauc3e54eb2012-04-17 19:06:20 -0600819 }
820}
821
822static void
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400823busy_cursor_grab_motion(struct wl_pointer_grab *grab,
824 uint32_t time, int32_t x, int32_t y)
Scott Moreauc3e54eb2012-04-17 19:06:20 -0600825{
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400826}
Scott Moreauc3e54eb2012-04-17 19:06:20 -0600827
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400828static void
829busy_cursor_grab_button(struct wl_pointer_grab *grab,
830 uint32_t time, uint32_t button, uint32_t state)
831{
832}
833
834static const struct wl_pointer_grab_interface busy_cursor_grab_interface = {
835 busy_cursor_grab_focus,
836 busy_cursor_grab_motion,
837 busy_cursor_grab_button,
838};
839
840static void
841set_busy_cursor(struct shell_surface *shsurf, struct wl_pointer *pointer)
842{
843 struct shell_grab *grab;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400844
845 grab = malloc(sizeof *grab);
846 if (!grab)
Scott Moreauc3e54eb2012-04-17 19:06:20 -0600847 return;
848
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300849 shell_grab_start(grab, &busy_cursor_grab_interface, shsurf, pointer,
850 DESKTOP_SHELL_CURSOR_BUSY);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400851}
Scott Moreauc3e54eb2012-04-17 19:06:20 -0600852
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400853static void
854end_busy_cursor(struct shell_surface *shsurf, struct wl_pointer *pointer)
855{
856 struct shell_grab *grab = (struct shell_grab *) pointer->grab;
857
858 if (grab->grab.interface == &busy_cursor_grab_interface) {
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300859 shell_grab_end(grab);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400860 free(grab);
Scott Moreauc3e54eb2012-04-17 19:06:20 -0600861 }
Scott Moreauc3e54eb2012-04-17 19:06:20 -0600862}
863
Scott Moreau9521d5e2012-04-19 13:06:17 -0600864static void
865ping_timer_destroy(struct shell_surface *shsurf)
866{
867 if (!shsurf || !shsurf->ping_timer)
868 return;
869
870 if (shsurf->ping_timer->source)
871 wl_event_source_remove(shsurf->ping_timer->source);
872
873 free(shsurf->ping_timer);
874 shsurf->ping_timer = NULL;
875}
876
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400877static int
Scott Moreauff1db4a2012-04-17 19:06:18 -0600878ping_timeout_handler(void *data)
879{
880 struct shell_surface *shsurf = data;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400881 struct weston_seat *seat;
Scott Moreauff1db4a2012-04-17 19:06:18 -0600882
Scott Moreau9521d5e2012-04-19 13:06:17 -0600883 /* Client is not responding */
884 shsurf->unresponsive = 1;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400885
886 wl_list_for_each(seat, &shsurf->surface->compositor->seat_list, link)
887 if (seat->seat.pointer->focus == &shsurf->surface->surface)
888 set_busy_cursor(shsurf, seat->seat.pointer);
Scott Moreauff1db4a2012-04-17 19:06:18 -0600889
890 return 1;
891}
892
893static void
894ping_handler(struct weston_surface *surface, uint32_t serial)
895{
Kristian Høgsbergb71302e2012-05-10 12:28:35 -0400896 struct shell_surface *shsurf = get_shell_surface(surface);
Scott Moreauff1db4a2012-04-17 19:06:18 -0600897 struct wl_event_loop *loop;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400898 int ping_timeout = 200;
Scott Moreauff1db4a2012-04-17 19:06:18 -0600899
900 if (!shsurf)
901 return;
Kristian Høgsbergca535c12012-04-21 23:20:07 -0400902 if (!shsurf->resource.client)
903 return;
Scott Moreauff1db4a2012-04-17 19:06:18 -0600904
Ander Conselvan de Oliveiraeac9a462012-07-16 14:15:48 +0300905 if (shsurf->surface == shsurf->shell->grab_surface)
906 return;
907
Scott Moreauff1db4a2012-04-17 19:06:18 -0600908 if (!shsurf->ping_timer) {
Ander Conselvan de Oliveirafb980892012-04-27 13:55:55 +0300909 shsurf->ping_timer = malloc(sizeof *shsurf->ping_timer);
Scott Moreauff1db4a2012-04-17 19:06:18 -0600910 if (!shsurf->ping_timer)
911 return;
912
913 shsurf->ping_timer->serial = serial;
Scott Moreauff1db4a2012-04-17 19:06:18 -0600914 loop = wl_display_get_event_loop(surface->compositor->wl_display);
915 shsurf->ping_timer->source =
916 wl_event_loop_add_timer(loop, ping_timeout_handler, shsurf);
917 wl_event_source_timer_update(shsurf->ping_timer->source, ping_timeout);
918
919 wl_shell_surface_send_ping(&shsurf->resource, serial);
920 }
921}
922
923static void
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400924handle_pointer_focus(struct wl_listener *listener, void *data)
925{
926 struct wl_pointer *pointer = data;
927 struct weston_surface *surface =
928 (struct weston_surface *) pointer->focus;
929 struct weston_compositor *compositor;
930 struct shell_surface *shsurf;
931 uint32_t serial;
932
933 if (!surface)
934 return;
935
936 compositor = surface->compositor;
937 shsurf = get_shell_surface(surface);
938
Pekka Paalanen4e1f2ff2012-06-06 16:59:45 +0300939 if (shsurf && shsurf->unresponsive) {
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400940 set_busy_cursor(shsurf, pointer);
941 } else {
942 serial = wl_display_next_serial(compositor->wl_display);
943 ping_handler(surface, serial);
944 }
945}
946
947static void
Scott Moreauff1db4a2012-04-17 19:06:18 -0600948shell_surface_pong(struct wl_client *client, struct wl_resource *resource,
949 uint32_t serial)
950{
951 struct shell_surface *shsurf = resource->data;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400952 struct desktop_shell *shell = shsurf->shell;
953 struct weston_seat *seat;
954 struct weston_compositor *ec = shsurf->surface->compositor;
955 struct wl_pointer *pointer;
956 int was_unresponsive;
Scott Moreauff1db4a2012-04-17 19:06:18 -0600957
Scott Moreauff1db4a2012-04-17 19:06:18 -0600958 if (shsurf->ping_timer->serial == serial) {
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400959 was_unresponsive = shsurf->unresponsive;
Scott Moreauff1db4a2012-04-17 19:06:18 -0600960 shsurf->unresponsive = 0;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400961 if (was_unresponsive) {
962 /* Received pong from previously unresponsive client */
963 wl_list_for_each(seat, &ec->seat_list, link) {
964 pointer = seat->seat.pointer;
965 if (pointer->focus ==
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300966 &shell->grab_surface->surface &&
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400967 pointer->current ==
968 &shsurf->surface->surface)
969 end_busy_cursor(shsurf, pointer);
970 }
971 }
Scott Moreau9521d5e2012-04-19 13:06:17 -0600972 ping_timer_destroy(shsurf);
Scott Moreauff1db4a2012-04-17 19:06:18 -0600973 }
974}
975
Kristian Høgsberge7afd912012-05-02 09:47:44 -0400976static void
977shell_surface_set_title(struct wl_client *client,
978 struct wl_resource *resource, const char *title)
979{
980 struct shell_surface *shsurf = resource->data;
981
982 free(shsurf->title);
983 shsurf->title = strdup(title);
984}
985
986static void
987shell_surface_set_class(struct wl_client *client,
988 struct wl_resource *resource, const char *class)
989{
990 struct shell_surface *shsurf = resource->data;
991
992 free(shsurf->class);
993 shsurf->class = strdup(class);
994}
995
Scott Moreauff1db4a2012-04-17 19:06:18 -0600996static int
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -0400997surface_move(struct shell_surface *shsurf, struct weston_seat *ws)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500998{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500999 struct weston_move_grab *move;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03001000
1001 if (!shsurf)
1002 return -1;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001003
Ander Conselvan de Oliveira00d17bb2012-06-28 18:08:06 +03001004 if (shsurf->type == SHELL_SURFACE_FULLSCREEN)
1005 return 0;
1006
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001007 move = malloc(sizeof *move);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001008 if (!move)
1009 return -1;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001010
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04001011 move->dx = wl_fixed_from_double(shsurf->surface->geometry.x) -
Daniel Stone37816df2012-05-16 18:45:18 +01001012 ws->seat.pointer->grab_x;
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04001013 move->dy = wl_fixed_from_double(shsurf->surface->geometry.y) -
Daniel Stone37816df2012-05-16 18:45:18 +01001014 ws->seat.pointer->grab_y;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001015
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001016 shell_grab_start(&move->base, &move_grab_interface, shsurf,
1017 ws->seat.pointer, DESKTOP_SHELL_CURSOR_MOVE);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001018
1019 return 0;
1020}
1021
1022static void
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001023shell_surface_move(struct wl_client *client, struct wl_resource *resource,
Daniel Stone37816df2012-05-16 18:45:18 +01001024 struct wl_resource *seat_resource, uint32_t serial)
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001025{
Daniel Stone37816df2012-05-16 18:45:18 +01001026 struct weston_seat *ws = seat_resource->data;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001027 struct shell_surface *shsurf = resource->data;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001028
Daniel Stone37816df2012-05-16 18:45:18 +01001029 if (ws->seat.pointer->button_count == 0 ||
1030 ws->seat.pointer->grab_serial != serial ||
1031 ws->seat.pointer->focus != &shsurf->surface->surface)
Kristian Høgsberg9ddb8262012-01-04 21:30:29 -05001032 return;
1033
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04001034 if (surface_move(shsurf, ws) < 0)
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -04001035 wl_resource_post_no_memory(resource);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001036}
1037
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001038struct weston_resize_grab {
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03001039 struct shell_grab base;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001040 uint32_t edges;
Pekka Paalanen5c97ae72012-01-30 16:19:47 +02001041 int32_t width, height;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001042};
1043
1044static void
Scott Moreau447013d2012-02-18 05:05:29 -07001045resize_grab_motion(struct wl_pointer_grab *grab,
Daniel Stone103db7f2012-05-08 17:17:55 +01001046 uint32_t time, wl_fixed_t x, wl_fixed_t y)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001047{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001048 struct weston_resize_grab *resize = (struct weston_resize_grab *) grab;
Daniel Stone37816df2012-05-16 18:45:18 +01001049 struct wl_pointer *pointer = grab->pointer;
Kristian Høgsberga61ca062012-05-22 16:05:52 -04001050 struct shell_surface *shsurf = resize->base.shsurf;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001051 int32_t width, height;
Daniel Stone103db7f2012-05-08 17:17:55 +01001052 wl_fixed_t from_x, from_y;
1053 wl_fixed_t to_x, to_y;
Pekka Paalanen5c97ae72012-01-30 16:19:47 +02001054
Kristian Høgsberga61ca062012-05-22 16:05:52 -04001055 if (!shsurf)
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03001056 return;
1057
Kristian Høgsberga61ca062012-05-22 16:05:52 -04001058 weston_surface_from_global_fixed(shsurf->surface,
Daniel Stone37816df2012-05-16 18:45:18 +01001059 pointer->grab_x, pointer->grab_y,
Daniel Stone103db7f2012-05-08 17:17:55 +01001060 &from_x, &from_y);
Kristian Høgsberga61ca062012-05-22 16:05:52 -04001061 weston_surface_from_global_fixed(shsurf->surface,
Daniel Stone37816df2012-05-16 18:45:18 +01001062 pointer->x, pointer->y, &to_x, &to_y);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001063
Daniel Stone103db7f2012-05-08 17:17:55 +01001064 width = resize->width;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001065 if (resize->edges & WL_SHELL_SURFACE_RESIZE_LEFT) {
Daniel Stone103db7f2012-05-08 17:17:55 +01001066 width += wl_fixed_to_int(from_x - to_x);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001067 } else if (resize->edges & WL_SHELL_SURFACE_RESIZE_RIGHT) {
Daniel Stone103db7f2012-05-08 17:17:55 +01001068 width += wl_fixed_to_int(to_x - from_x);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001069 }
1070
Daniel Stone103db7f2012-05-08 17:17:55 +01001071 height = resize->height;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001072 if (resize->edges & WL_SHELL_SURFACE_RESIZE_TOP) {
Daniel Stone103db7f2012-05-08 17:17:55 +01001073 height += wl_fixed_to_int(from_y - to_y);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001074 } else if (resize->edges & WL_SHELL_SURFACE_RESIZE_BOTTOM) {
Daniel Stone103db7f2012-05-08 17:17:55 +01001075 height += wl_fixed_to_int(to_y - from_y);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001076 }
1077
Kristian Høgsberga61ca062012-05-22 16:05:52 -04001078 shsurf->client->send_configure(shsurf->surface,
1079 resize->edges, width, height);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001080}
1081
1082static void
Kristian Høgsberga61ca062012-05-22 16:05:52 -04001083send_configure(struct weston_surface *surface,
1084 uint32_t edges, int32_t width, int32_t height)
1085{
1086 struct shell_surface *shsurf = get_shell_surface(surface);
1087
1088 wl_shell_surface_send_configure(&shsurf->resource,
1089 edges, width, height);
1090}
1091
1092static const struct weston_shell_client shell_client = {
1093 send_configure
1094};
1095
1096static void
Scott Moreau447013d2012-02-18 05:05:29 -07001097resize_grab_button(struct wl_pointer_grab *grab,
Daniel Stone4dbadb12012-05-30 16:31:51 +01001098 uint32_t time, uint32_t button, uint32_t state_w)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001099{
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03001100 struct weston_resize_grab *resize = (struct weston_resize_grab *) grab;
Daniel Stone37816df2012-05-16 18:45:18 +01001101 struct wl_pointer *pointer = grab->pointer;
Daniel Stone4dbadb12012-05-30 16:31:51 +01001102 enum wl_pointer_button_state state = state_w;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001103
Daniel Stone4dbadb12012-05-30 16:31:51 +01001104 if (pointer->button_count == 0 &&
1105 state == WL_POINTER_BUTTON_STATE_RELEASED) {
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001106 shell_grab_end(&resize->base);
Kristian Høgsberg9ddb8262012-01-04 21:30:29 -05001107 free(grab);
1108 }
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001109}
1110
Scott Moreau447013d2012-02-18 05:05:29 -07001111static const struct wl_pointer_grab_interface resize_grab_interface = {
Kristian Høgsberg9ddb8262012-01-04 21:30:29 -05001112 noop_grab_focus,
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001113 resize_grab_motion,
1114 resize_grab_button,
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001115};
1116
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001117static int
Kristian Høgsbergc1693f22012-05-22 16:56:23 -04001118surface_resize(struct shell_surface *shsurf,
1119 struct weston_seat *ws, uint32_t edges)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001120{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001121 struct weston_resize_grab *resize;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001122
Alex Wu4539b082012-03-01 12:57:46 +08001123 if (shsurf->type == SHELL_SURFACE_FULLSCREEN)
1124 return 0;
Kristian Høgsberg0ce24572011-01-28 15:18:33 -05001125
Pekka Paalanen5c97ae72012-01-30 16:19:47 +02001126 if (edges == 0 || edges > 15 ||
1127 (edges & 3) == 3 || (edges & 12) == 12)
1128 return 0;
1129
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001130 resize = malloc(sizeof *resize);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001131 if (!resize)
1132 return -1;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001133
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001134 resize->edges = edges;
Pekka Paalanen5c97ae72012-01-30 16:19:47 +02001135 resize->width = shsurf->surface->geometry.width;
1136 resize->height = shsurf->surface->geometry.height;
Kristian Høgsberg904055a2011-08-18 17:55:30 -04001137
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001138 shell_grab_start(&resize->base, &resize_grab_interface, shsurf,
1139 ws->seat.pointer, edges);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001140
1141 return 0;
1142}
1143
1144static void
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001145shell_surface_resize(struct wl_client *client, struct wl_resource *resource,
Daniel Stone37816df2012-05-16 18:45:18 +01001146 struct wl_resource *seat_resource, uint32_t serial,
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001147 uint32_t edges)
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001148{
Daniel Stone37816df2012-05-16 18:45:18 +01001149 struct weston_seat *ws = seat_resource->data;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001150 struct shell_surface *shsurf = resource->data;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001151
Alex Wu4539b082012-03-01 12:57:46 +08001152 if (shsurf->type == SHELL_SURFACE_FULLSCREEN)
1153 return;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001154
Daniel Stone37816df2012-05-16 18:45:18 +01001155 if (ws->seat.pointer->button_count == 0 ||
1156 ws->seat.pointer->grab_serial != serial ||
1157 ws->seat.pointer->focus != &shsurf->surface->surface)
Kristian Høgsberg9ddb8262012-01-04 21:30:29 -05001158 return;
1159
Kristian Høgsbergc1693f22012-05-22 16:56:23 -04001160 if (surface_resize(shsurf, ws, edges) < 0)
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -04001161 wl_resource_post_no_memory(resource);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001162}
1163
Juan Zhao96879df2012-02-07 08:45:41 +08001164static struct weston_output *
1165get_default_output(struct weston_compositor *compositor)
1166{
1167 return container_of(compositor->output_list.next,
1168 struct weston_output, link);
1169}
1170
Alex Wu4539b082012-03-01 12:57:46 +08001171static void
1172shell_unset_fullscreen(struct shell_surface *shsurf)
1173{
1174 /* undo all fullscreen things here */
Alex Wubd3354b2012-04-17 17:20:49 +08001175 if (shsurf->fullscreen.type == WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER &&
1176 shell_surface_is_top_fullscreen(shsurf)) {
1177 weston_output_switch_mode(shsurf->fullscreen_output,
1178 shsurf->fullscreen_output->origin);
1179 }
Alex Wu4539b082012-03-01 12:57:46 +08001180 shsurf->fullscreen.type = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT;
1181 shsurf->fullscreen.framerate = 0;
1182 wl_list_remove(&shsurf->fullscreen.transform.link);
1183 wl_list_init(&shsurf->fullscreen.transform.link);
Alex Wubd3354b2012-04-17 17:20:49 +08001184 if (shsurf->fullscreen.black_surface)
1185 weston_surface_destroy(shsurf->fullscreen.black_surface);
Alex Wu4539b082012-03-01 12:57:46 +08001186 shsurf->fullscreen.black_surface = NULL;
1187 shsurf->fullscreen_output = NULL;
Alex Wu4539b082012-03-01 12:57:46 +08001188 weston_surface_set_position(shsurf->surface,
1189 shsurf->saved_x, shsurf->saved_y);
Alex Wu7bcb8bd2012-04-27 09:07:24 +08001190 if (shsurf->saved_rotation_valid) {
1191 wl_list_insert(&shsurf->surface->geometry.transformation_list,
1192 &shsurf->rotation.transform.link);
1193 shsurf->saved_rotation_valid = false;
1194 }
Alex Wu4539b082012-03-01 12:57:46 +08001195}
1196
Pekka Paalanen98262232011-12-01 10:42:22 +02001197static int
1198reset_shell_surface_type(struct shell_surface *surface)
1199{
1200 switch (surface->type) {
1201 case SHELL_SURFACE_FULLSCREEN:
Alex Wu4539b082012-03-01 12:57:46 +08001202 shell_unset_fullscreen(surface);
Pekka Paalanen98262232011-12-01 10:42:22 +02001203 break;
Juan Zhao96879df2012-02-07 08:45:41 +08001204 case SHELL_SURFACE_MAXIMIZED:
1205 surface->output = get_default_output(surface->surface->compositor);
1206 weston_surface_set_position(surface->surface,
1207 surface->saved_x,
1208 surface->saved_y);
1209 break;
Pekka Paalanen98262232011-12-01 10:42:22 +02001210 case SHELL_SURFACE_NONE:
1211 case SHELL_SURFACE_TOPLEVEL:
1212 case SHELL_SURFACE_TRANSIENT:
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001213 case SHELL_SURFACE_POPUP:
Pekka Paalanen98262232011-12-01 10:42:22 +02001214 break;
1215 }
1216
1217 surface->type = SHELL_SURFACE_NONE;
1218 return 0;
1219}
1220
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001221static void
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001222set_surface_type(struct shell_surface *shsurf)
1223{
1224 struct weston_surface *surface = shsurf->surface;
Kristian Høgsberg8150b192012-06-27 10:22:58 -04001225 struct weston_surface *pes = shsurf->parent;
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001226
1227 reset_shell_surface_type(shsurf);
1228
1229 shsurf->type = shsurf->next_type;
1230 shsurf->next_type = SHELL_SURFACE_NONE;
1231
1232 switch (shsurf->type) {
1233 case SHELL_SURFACE_TOPLEVEL:
1234 break;
1235 case SHELL_SURFACE_TRANSIENT:
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001236 weston_surface_set_position(surface,
Tiago Vignatti52e598c2012-05-07 15:23:08 +03001237 pes->geometry.x + shsurf->transient.x,
1238 pes->geometry.y + shsurf->transient.y);
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001239 break;
1240
1241 case SHELL_SURFACE_MAXIMIZED:
1242 shsurf->saved_x = surface->geometry.x;
1243 shsurf->saved_y = surface->geometry.y;
1244 shsurf->saved_position_valid = true;
1245 break;
1246
1247 case SHELL_SURFACE_FULLSCREEN:
1248 shsurf->saved_x = surface->geometry.x;
1249 shsurf->saved_y = surface->geometry.y;
1250 shsurf->saved_position_valid = true;
1251
1252 if (!wl_list_empty(&shsurf->rotation.transform.link)) {
1253 wl_list_remove(&shsurf->rotation.transform.link);
1254 wl_list_init(&shsurf->rotation.transform.link);
1255 shsurf->surface->geometry.dirty = 1;
1256 shsurf->saved_rotation_valid = true;
1257 }
1258 break;
1259
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001260 default:
1261 break;
1262 }
1263}
1264
1265static void
Tiago Vignattibc052c92012-04-19 16:18:18 +03001266set_toplevel(struct shell_surface *shsurf)
1267{
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001268 shsurf->next_type = SHELL_SURFACE_TOPLEVEL;
Tiago Vignattibc052c92012-04-19 16:18:18 +03001269}
1270
1271static void
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001272shell_surface_set_toplevel(struct wl_client *client,
1273 struct wl_resource *resource)
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001274{
Pekka Paalanen98262232011-12-01 10:42:22 +02001275 struct shell_surface *surface = resource->data;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001276
Tiago Vignattibc052c92012-04-19 16:18:18 +03001277 set_toplevel(surface);
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001278}
1279
1280static void
Tiago Vignatti491bac12012-05-18 16:37:43 -04001281set_transient(struct shell_surface *shsurf,
Kristian Høgsberg8150b192012-06-27 10:22:58 -04001282 struct weston_surface *parent, int x, int y, uint32_t flags)
Tiago Vignatti491bac12012-05-18 16:37:43 -04001283{
1284 /* assign to parents output */
Kristian Høgsberg8150b192012-06-27 10:22:58 -04001285 shsurf->parent = parent;
Tiago Vignatti491bac12012-05-18 16:37:43 -04001286 shsurf->transient.x = x;
1287 shsurf->transient.y = y;
1288 shsurf->transient.flags = flags;
1289 shsurf->next_type = SHELL_SURFACE_TRANSIENT;
1290}
1291
1292static void
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001293shell_surface_set_transient(struct wl_client *client,
1294 struct wl_resource *resource,
1295 struct wl_resource *parent_resource,
1296 int x, int y, uint32_t flags)
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001297{
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001298 struct shell_surface *shsurf = resource->data;
Kristian Høgsberg8150b192012-06-27 10:22:58 -04001299 struct weston_surface *parent = parent_resource->data;
Pekka Paalanen98262232011-12-01 10:42:22 +02001300
Kristian Høgsberg8150b192012-06-27 10:22:58 -04001301 set_transient(shsurf, parent, x, y, flags);
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001302}
1303
Tiago Vignattibe143262012-04-16 17:31:41 +03001304static struct desktop_shell *
Juan Zhao96879df2012-02-07 08:45:41 +08001305shell_surface_get_shell(struct shell_surface *shsurf)
Pekka Paalanenaf0e34c2011-12-02 10:59:17 +02001306{
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04001307 return shsurf->shell;
Juan Zhao96879df2012-02-07 08:45:41 +08001308}
1309
1310static int
Tiago Vignattibe143262012-04-16 17:31:41 +03001311get_output_panel_height(struct desktop_shell *shell,
1312 struct weston_output *output)
Juan Zhao96879df2012-02-07 08:45:41 +08001313{
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001314 struct weston_surface *surface;
Juan Zhao96879df2012-02-07 08:45:41 +08001315 int panel_height = 0;
1316
1317 if (!output)
1318 return 0;
1319
Juan Zhao4ab94682012-07-09 22:24:09 -07001320 wl_list_for_each(surface, &shell->panel_layer.surface_list, layer_link) {
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001321 if (surface->output == output) {
1322 panel_height = surface->geometry.height;
Juan Zhao96879df2012-02-07 08:45:41 +08001323 break;
1324 }
1325 }
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001326
Juan Zhao96879df2012-02-07 08:45:41 +08001327 return panel_height;
1328}
1329
1330static void
1331shell_surface_set_maximized(struct wl_client *client,
1332 struct wl_resource *resource,
1333 struct wl_resource *output_resource )
1334{
1335 struct shell_surface *shsurf = resource->data;
1336 struct weston_surface *es = shsurf->surface;
Tiago Vignattibe143262012-04-16 17:31:41 +03001337 struct desktop_shell *shell = NULL;
Juan Zhao96879df2012-02-07 08:45:41 +08001338 uint32_t edges = 0, panel_height = 0;
1339
1340 /* get the default output, if the client set it as NULL
1341 check whether the ouput is available */
1342 if (output_resource)
1343 shsurf->output = output_resource->data;
Kristian Høgsberg94de6802012-07-18 09:54:04 -04001344 else if (es->output)
1345 shsurf->output = es->output;
Juan Zhao96879df2012-02-07 08:45:41 +08001346 else
1347 shsurf->output = get_default_output(es->compositor);
1348
Tiago Vignattibe143262012-04-16 17:31:41 +03001349 shell = shell_surface_get_shell(shsurf);
Rob Bradford31b68622012-07-02 19:00:19 +01001350 panel_height = get_output_panel_height(shell, shsurf->output);
Juan Zhao96879df2012-02-07 08:45:41 +08001351 edges = WL_SHELL_SURFACE_RESIZE_TOP|WL_SHELL_SURFACE_RESIZE_LEFT;
Kristian Høgsberg0b5cd0c2012-03-04 21:57:37 -05001352
Kristian Høgsberga61ca062012-05-22 16:05:52 -04001353 shsurf->client->send_configure(shsurf->surface, edges,
Rob Bradford31b68622012-07-02 19:00:19 +01001354 shsurf->output->current->width,
1355 shsurf->output->current->height - panel_height);
Juan Zhao96879df2012-02-07 08:45:41 +08001356
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001357 shsurf->next_type = SHELL_SURFACE_MAXIMIZED;
Pekka Paalanenaf0e34c2011-12-02 10:59:17 +02001358}
1359
Alex Wu21858432012-04-01 20:13:08 +08001360static void
1361black_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy);
1362
Alex Wu4539b082012-03-01 12:57:46 +08001363static struct weston_surface *
1364create_black_surface(struct weston_compositor *ec,
Alex Wu21858432012-04-01 20:13:08 +08001365 struct weston_surface *fs_surface,
Alex Wu4539b082012-03-01 12:57:46 +08001366 GLfloat x, GLfloat y, int w, int h)
1367{
1368 struct weston_surface *surface = NULL;
1369
1370 surface = weston_surface_create(ec);
1371 if (surface == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001372 weston_log("no memory\n");
Alex Wu4539b082012-03-01 12:57:46 +08001373 return NULL;
1374 }
1375
Alex Wu21858432012-04-01 20:13:08 +08001376 surface->configure = black_surface_configure;
1377 surface->private = fs_surface;
Alex Wu4539b082012-03-01 12:57:46 +08001378 weston_surface_configure(surface, x, y, w, h);
1379 weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1);
1380 return surface;
1381}
1382
1383/* Create black surface and append it to the associated fullscreen surface.
1384 * Handle size dismatch and positioning according to the method. */
1385static void
1386shell_configure_fullscreen(struct shell_surface *shsurf)
1387{
1388 struct weston_output *output = shsurf->fullscreen_output;
1389 struct weston_surface *surface = shsurf->surface;
1390 struct weston_matrix *matrix;
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04001391 float scale, output_aspect, surface_aspect, x, y;
Alex Wu4539b082012-03-01 12:57:46 +08001392
Alex Wu4539b082012-03-01 12:57:46 +08001393 if (!shsurf->fullscreen.black_surface)
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05001394 shsurf->fullscreen.black_surface =
1395 create_black_surface(surface->compositor,
Alex Wu21858432012-04-01 20:13:08 +08001396 surface,
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05001397 output->x, output->y,
1398 output->current->width,
1399 output->current->height);
1400
1401 wl_list_remove(&shsurf->fullscreen.black_surface->layer_link);
1402 wl_list_insert(&surface->layer_link,
1403 &shsurf->fullscreen.black_surface->layer_link);
Alex Wu4539b082012-03-01 12:57:46 +08001404 shsurf->fullscreen.black_surface->output = output;
1405
1406 switch (shsurf->fullscreen.type) {
1407 case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT:
Kristian Høgsberga08b5282012-07-20 15:30:36 -04001408 if (surface->buffer)
1409 center_on_output(surface, shsurf->fullscreen_output);
Alex Wu4539b082012-03-01 12:57:46 +08001410 break;
1411 case WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE:
1412 matrix = &shsurf->fullscreen.transform.matrix;
1413 weston_matrix_init(matrix);
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04001414
1415 output_aspect = (float) output->current->width /
1416 (float) output->current->height;
1417 surface_aspect = (float) surface->geometry.width /
1418 (float) surface->geometry.height;
1419 if (output_aspect < surface_aspect)
1420 scale = (float) output->current->width /
1421 (float) surface->geometry.width;
1422 else
1423 scale = (float) output->current->height /
1424 (float) surface->geometry.height;
1425
Alex Wu4539b082012-03-01 12:57:46 +08001426 weston_matrix_scale(matrix, scale, scale, 1);
1427 wl_list_remove(&shsurf->fullscreen.transform.link);
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04001428 wl_list_insert(&surface->geometry.transformation_list,
Alex Wu4539b082012-03-01 12:57:46 +08001429 &shsurf->fullscreen.transform.link);
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04001430 x = output->x + (output->current->width - surface->geometry.width * scale) / 2;
1431 y = output->y + (output->current->height - surface->geometry.height * scale) / 2;
1432 weston_surface_set_position(surface, x, y);
1433
Alex Wu4539b082012-03-01 12:57:46 +08001434 break;
1435 case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER:
Alex Wubd3354b2012-04-17 17:20:49 +08001436 if (shell_surface_is_top_fullscreen(shsurf)) {
1437 struct weston_mode mode = {0,
1438 surface->geometry.width,
1439 surface->geometry.height,
1440 shsurf->fullscreen.framerate};
1441
1442 if (weston_output_switch_mode(output, &mode) == 0) {
1443 weston_surface_configure(shsurf->fullscreen.black_surface,
1444 output->x, output->y,
1445 output->current->width,
1446 output->current->height);
1447 weston_surface_set_position(surface, output->x, output->y);
1448 break;
1449 }
1450 }
Alex Wu4539b082012-03-01 12:57:46 +08001451 break;
1452 case WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL:
1453 break;
1454 default:
1455 break;
1456 }
1457}
1458
1459/* make the fullscreen and black surface at the top */
1460static void
1461shell_stack_fullscreen(struct shell_surface *shsurf)
1462{
Alex Wubd3354b2012-04-17 17:20:49 +08001463 struct weston_output *output = shsurf->fullscreen_output;
Alex Wu4539b082012-03-01 12:57:46 +08001464 struct weston_surface *surface = shsurf->surface;
Tiago Vignattibe143262012-04-16 17:31:41 +03001465 struct desktop_shell *shell = shell_surface_get_shell(shsurf);
Alex Wu4539b082012-03-01 12:57:46 +08001466
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05001467 wl_list_remove(&surface->layer_link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05001468 wl_list_insert(&shell->fullscreen_layer.surface_list,
1469 &surface->layer_link);
Alex Wubd3354b2012-04-17 17:20:49 +08001470 weston_surface_damage(surface);
1471
1472 if (!shsurf->fullscreen.black_surface)
1473 shsurf->fullscreen.black_surface =
1474 create_black_surface(surface->compositor,
1475 surface,
1476 output->x, output->y,
1477 output->current->width,
1478 output->current->height);
1479
1480 wl_list_remove(&shsurf->fullscreen.black_surface->layer_link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05001481 wl_list_insert(&surface->layer_link,
1482 &shsurf->fullscreen.black_surface->layer_link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05001483 weston_surface_damage(shsurf->fullscreen.black_surface);
Alex Wu4539b082012-03-01 12:57:46 +08001484}
1485
1486static void
1487shell_map_fullscreen(struct shell_surface *shsurf)
1488{
Alex Wu4539b082012-03-01 12:57:46 +08001489 shell_stack_fullscreen(shsurf);
Alex Wubd3354b2012-04-17 17:20:49 +08001490 shell_configure_fullscreen(shsurf);
Alex Wu4539b082012-03-01 12:57:46 +08001491}
1492
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001493static void
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001494shell_surface_set_fullscreen(struct wl_client *client,
Kristian Høgsbergf856fd22012-02-16 15:58:14 -05001495 struct wl_resource *resource,
1496 uint32_t method,
1497 uint32_t framerate,
1498 struct wl_resource *output_resource)
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001499{
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001500 struct shell_surface *shsurf = resource->data;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001501 struct weston_surface *es = shsurf->surface;
Alex Wu4539b082012-03-01 12:57:46 +08001502
1503 if (output_resource)
1504 shsurf->output = output_resource->data;
Kristian Høgsberg94de6802012-07-18 09:54:04 -04001505 else if (es->output)
1506 shsurf->output = es->output;
Alex Wu4539b082012-03-01 12:57:46 +08001507 else
1508 shsurf->output = get_default_output(es->compositor);
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001509
Alex Wu4539b082012-03-01 12:57:46 +08001510 shsurf->fullscreen_output = shsurf->output;
1511 shsurf->fullscreen.type = method;
1512 shsurf->fullscreen.framerate = framerate;
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001513 shsurf->next_type = SHELL_SURFACE_FULLSCREEN;
Alex Wu4539b082012-03-01 12:57:46 +08001514
Kristian Høgsberga61ca062012-05-22 16:05:52 -04001515 shsurf->client->send_configure(shsurf->surface, 0,
1516 shsurf->output->current->width,
1517 shsurf->output->current->height);
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001518}
1519
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001520static void
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001521popup_grab_focus(struct wl_pointer_grab *grab,
Daniel Stone103db7f2012-05-08 17:17:55 +01001522 struct wl_surface *surface,
1523 wl_fixed_t x,
1524 wl_fixed_t y)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001525{
Daniel Stone37816df2012-05-16 18:45:18 +01001526 struct wl_pointer *pointer = grab->pointer;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001527 struct shell_surface *priv =
1528 container_of(grab, struct shell_surface, popup.grab);
1529 struct wl_client *client = priv->surface->surface.resource.client;
1530
Pekka Paalanencb108432012-01-19 16:25:40 +02001531 if (surface && surface->resource.client == client) {
Daniel Stone37816df2012-05-16 18:45:18 +01001532 wl_pointer_set_focus(pointer, surface, x, y);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001533 grab->focus = surface;
1534 } else {
Daniel Stone37816df2012-05-16 18:45:18 +01001535 wl_pointer_set_focus(pointer, NULL,
1536 wl_fixed_from_int(0),
1537 wl_fixed_from_int(0));
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001538 grab->focus = NULL;
1539 }
1540}
1541
1542static void
Scott Moreau447013d2012-02-18 05:05:29 -07001543popup_grab_motion(struct wl_pointer_grab *grab,
Daniel Stone103db7f2012-05-08 17:17:55 +01001544 uint32_t time, wl_fixed_t sx, wl_fixed_t sy)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001545{
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001546 struct wl_resource *resource;
1547
Daniel Stone37816df2012-05-16 18:45:18 +01001548 resource = grab->pointer->focus_resource;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001549 if (resource)
Daniel Stone37816df2012-05-16 18:45:18 +01001550 wl_pointer_send_motion(resource, time, sx, sy);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001551}
1552
1553static void
Scott Moreau447013d2012-02-18 05:05:29 -07001554popup_grab_button(struct wl_pointer_grab *grab,
Daniel Stone4dbadb12012-05-30 16:31:51 +01001555 uint32_t time, uint32_t button, uint32_t state_w)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001556{
1557 struct wl_resource *resource;
1558 struct shell_surface *shsurf =
1559 container_of(grab, struct shell_surface, popup.grab);
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001560 struct wl_display *display;
Daniel Stone4dbadb12012-05-30 16:31:51 +01001561 enum wl_pointer_button_state state = state_w;
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001562 uint32_t serial;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001563
Daniel Stone37816df2012-05-16 18:45:18 +01001564 resource = grab->pointer->focus_resource;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001565 if (resource) {
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001566 display = wl_client_get_display(resource->client);
1567 serial = wl_display_get_serial(display);
Daniel Stone37816df2012-05-16 18:45:18 +01001568 wl_pointer_send_button(resource, serial, time, button, state);
Daniel Stone4dbadb12012-05-30 16:31:51 +01001569 } else if (state == WL_POINTER_BUTTON_STATE_RELEASED &&
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001570 (shsurf->popup.initial_up ||
Daniel Stone37816df2012-05-16 18:45:18 +01001571 time - shsurf->popup.seat->pointer->grab_time > 500)) {
Kristian Høgsberg0b5cd0c2012-03-04 21:57:37 -05001572 wl_shell_surface_send_popup_done(&shsurf->resource);
Daniel Stone37816df2012-05-16 18:45:18 +01001573 wl_pointer_end_grab(grab->pointer);
1574 shsurf->popup.grab.pointer = NULL;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001575 }
1576
Daniel Stone4dbadb12012-05-30 16:31:51 +01001577 if (state == WL_POINTER_BUTTON_STATE_RELEASED)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001578 shsurf->popup.initial_up = 1;
1579}
1580
Scott Moreau447013d2012-02-18 05:05:29 -07001581static const struct wl_pointer_grab_interface popup_grab_interface = {
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001582 popup_grab_focus,
1583 popup_grab_motion,
1584 popup_grab_button,
1585};
1586
1587static void
Kristian Høgsberg3730f362012-04-13 12:40:07 -04001588shell_map_popup(struct shell_surface *shsurf)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001589{
Daniel Stone37816df2012-05-16 18:45:18 +01001590 struct wl_seat *seat = shsurf->popup.seat;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001591 struct weston_surface *es = shsurf->surface;
Kristian Høgsberg8150b192012-06-27 10:22:58 -04001592 struct weston_surface *parent = shsurf->parent;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001593
1594 es->output = parent->output;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001595 shsurf->popup.grab.interface = &popup_grab_interface;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001596
Pekka Paalanen938269a2012-02-07 14:19:01 +02001597 weston_surface_update_transform(parent);
1598 if (parent->transform.enabled) {
1599 shsurf->popup.parent_transform.matrix =
1600 parent->transform.matrix;
1601 } else {
1602 /* construct x, y translation matrix */
1603 weston_matrix_init(&shsurf->popup.parent_transform.matrix);
1604 shsurf->popup.parent_transform.matrix.d[12] =
1605 parent->geometry.x;
1606 shsurf->popup.parent_transform.matrix.d[13] =
1607 parent->geometry.y;
1608 }
1609 wl_list_insert(es->geometry.transformation_list.prev,
1610 &shsurf->popup.parent_transform.link);
Pekka Paalanen8fb8d3b2012-02-13 13:03:59 +02001611 weston_surface_set_position(es, shsurf->popup.x, shsurf->popup.y);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001612
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001613 shsurf->popup.initial_up = 0;
1614
Kristian Høgsberg3730f362012-04-13 12:40:07 -04001615 /* We don't require the grab to still be active, but if another
1616 * grab has started in the meantime, we end the popup now. */
Daniel Stone37816df2012-05-16 18:45:18 +01001617 if (seat->pointer->grab_serial == shsurf->popup.serial) {
1618 wl_pointer_start_grab(seat->pointer, &shsurf->popup.grab);
Kristian Høgsberg3730f362012-04-13 12:40:07 -04001619 } else {
1620 wl_shell_surface_send_popup_done(&shsurf->resource);
1621 }
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001622}
1623
1624static void
1625shell_surface_set_popup(struct wl_client *client,
1626 struct wl_resource *resource,
Daniel Stone37816df2012-05-16 18:45:18 +01001627 struct wl_resource *seat_resource,
Kristian Høgsberg3730f362012-04-13 12:40:07 -04001628 uint32_t serial,
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001629 struct wl_resource *parent_resource,
1630 int32_t x, int32_t y, uint32_t flags)
1631{
1632 struct shell_surface *shsurf = resource->data;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001633
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001634 shsurf->type = SHELL_SURFACE_POPUP;
1635 shsurf->parent = parent_resource->data;
Daniel Stone37816df2012-05-16 18:45:18 +01001636 shsurf->popup.seat = seat_resource->data;
Kristian Høgsberg3730f362012-04-13 12:40:07 -04001637 shsurf->popup.serial = serial;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001638 shsurf->popup.x = x;
1639 shsurf->popup.y = y;
1640}
1641
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001642static const struct wl_shell_surface_interface shell_surface_implementation = {
Scott Moreauff1db4a2012-04-17 19:06:18 -06001643 shell_surface_pong,
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001644 shell_surface_move,
1645 shell_surface_resize,
1646 shell_surface_set_toplevel,
1647 shell_surface_set_transient,
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001648 shell_surface_set_fullscreen,
Juan Zhao96879df2012-02-07 08:45:41 +08001649 shell_surface_set_popup,
Kristian Høgsberge7afd912012-05-02 09:47:44 -04001650 shell_surface_set_maximized,
1651 shell_surface_set_title,
1652 shell_surface_set_class
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001653};
1654
1655static void
Tiago Vignattibc052c92012-04-19 16:18:18 +03001656destroy_shell_surface(struct shell_surface *shsurf)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001657{
Daniel Stone37816df2012-05-16 18:45:18 +01001658 if (shsurf->popup.grab.pointer)
1659 wl_pointer_end_grab(shsurf->popup.grab.pointer);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001660
Alex Wubd3354b2012-04-17 17:20:49 +08001661 if (shsurf->fullscreen.type == WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER &&
1662 shell_surface_is_top_fullscreen(shsurf)) {
1663 weston_output_switch_mode(shsurf->fullscreen_output,
1664 shsurf->fullscreen_output->origin);
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03001665 }
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001666
Alex Wuaa08e2d2012-03-05 11:01:40 +08001667 if (shsurf->fullscreen.black_surface)
1668 weston_surface_destroy(shsurf->fullscreen.black_surface);
1669
Alex Wubd3354b2012-04-17 17:20:49 +08001670 /* As destroy_resource() use wl_list_for_each_safe(),
1671 * we can always remove the listener.
1672 */
1673 wl_list_remove(&shsurf->surface_destroy_listener.link);
1674 shsurf->surface->configure = NULL;
Scott Moreau9521d5e2012-04-19 13:06:17 -06001675 ping_timer_destroy(shsurf);
Alex Wubd3354b2012-04-17 17:20:49 +08001676
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001677 wl_list_remove(&shsurf->link);
1678 free(shsurf);
1679}
1680
1681static void
Tiago Vignattibc052c92012-04-19 16:18:18 +03001682shell_destroy_shell_surface(struct wl_resource *resource)
1683{
1684 struct shell_surface *shsurf = resource->data;
1685
1686 destroy_shell_surface(shsurf);
1687}
1688
1689static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001690shell_handle_surface_destroy(struct wl_listener *listener, void *data)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001691{
1692 struct shell_surface *shsurf = container_of(listener,
1693 struct shell_surface,
1694 surface_destroy_listener);
1695
Kristian Høgsberg633b1452012-06-07 18:08:47 -04001696 if (shsurf->resource.client) {
Tiago Vignattibc052c92012-04-19 16:18:18 +03001697 wl_resource_destroy(&shsurf->resource);
Kristian Høgsberg633b1452012-06-07 18:08:47 -04001698 } else {
1699 wl_signal_emit(&shsurf->resource.destroy_signal,
1700 &shsurf->resource);
Tiago Vignattibc052c92012-04-19 16:18:18 +03001701 destroy_shell_surface(shsurf);
Kristian Høgsberg633b1452012-06-07 18:08:47 -04001702 }
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001703}
1704
Kristian Høgsbergd8134452012-06-21 12:49:02 -04001705static void
1706shell_surface_configure(struct weston_surface *, int32_t, int32_t);
1707
Pekka Paalanenec2b32f2011-11-28 15:12:34 +02001708static struct shell_surface *
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001709get_shell_surface(struct weston_surface *surface)
Pekka Paalanenec2b32f2011-11-28 15:12:34 +02001710{
Kristian Høgsbergd8134452012-06-21 12:49:02 -04001711 if (surface->configure == shell_surface_configure)
1712 return surface->private;
1713 else
1714 return NULL;
Pekka Paalanenec2b32f2011-11-28 15:12:34 +02001715}
1716
Kristian Høgsberg45ba8692012-05-21 14:27:33 -04001717static struct shell_surface *
Kristian Høgsberga61ca062012-05-22 16:05:52 -04001718create_shell_surface(void *shell, struct weston_surface *surface,
1719 const struct weston_shell_client *client)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001720{
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001721 struct shell_surface *shsurf;
1722
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03001723 if (surface->configure) {
Martin Minarik6d118362012-06-07 18:01:59 +02001724 weston_log("surface->configure already set\n");
Kristian Høgsberg45ba8692012-05-21 14:27:33 -04001725 return NULL;
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03001726 }
1727
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001728 shsurf = calloc(1, sizeof *shsurf);
1729 if (!shsurf) {
Martin Minarik6d118362012-06-07 18:01:59 +02001730 weston_log("no memory to allocate shell surface\n");
Kristian Høgsberg45ba8692012-05-21 14:27:33 -04001731 return NULL;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001732 }
1733
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03001734 surface->configure = shell_surface_configure;
Kristian Høgsbergd8134452012-06-21 12:49:02 -04001735 surface->private = shsurf;
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03001736
Tiago Vignattibc052c92012-04-19 16:18:18 +03001737 shsurf->shell = (struct desktop_shell *) shell;
Scott Moreauff1db4a2012-04-17 19:06:18 -06001738 shsurf->unresponsive = 0;
Alex Wu4539b082012-03-01 12:57:46 +08001739 shsurf->saved_position_valid = false;
Alex Wu7bcb8bd2012-04-27 09:07:24 +08001740 shsurf->saved_rotation_valid = false;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001741 shsurf->surface = surface;
Alex Wu4539b082012-03-01 12:57:46 +08001742 shsurf->fullscreen.type = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT;
1743 shsurf->fullscreen.framerate = 0;
1744 shsurf->fullscreen.black_surface = NULL;
Scott Moreauff1db4a2012-04-17 19:06:18 -06001745 shsurf->ping_timer = NULL;
Alex Wu4539b082012-03-01 12:57:46 +08001746 wl_list_init(&shsurf->fullscreen.transform.link);
1747
Tiago Vignattibc052c92012-04-19 16:18:18 +03001748 wl_signal_init(&shsurf->resource.destroy_signal);
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001749 shsurf->surface_destroy_listener.notify = shell_handle_surface_destroy;
1750 wl_signal_add(&surface->surface.resource.destroy_signal,
1751 &shsurf->surface_destroy_listener);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001752
1753 /* init link so its safe to always remove it in destroy_shell_surface */
1754 wl_list_init(&shsurf->link);
1755
Pekka Paalanen460099f2012-01-20 16:48:25 +02001756 /* empty when not in use */
1757 wl_list_init(&shsurf->rotation.transform.link);
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05001758 weston_matrix_init(&shsurf->rotation.rotation);
Pekka Paalanen460099f2012-01-20 16:48:25 +02001759
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001760 wl_list_init(&shsurf->workspace_transform.link);
1761
Pekka Paalanen98262232011-12-01 10:42:22 +02001762 shsurf->type = SHELL_SURFACE_NONE;
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001763 shsurf->next_type = SHELL_SURFACE_NONE;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001764
Kristian Høgsberga61ca062012-05-22 16:05:52 -04001765 shsurf->client = client;
1766
Kristian Høgsberg45ba8692012-05-21 14:27:33 -04001767 return shsurf;
Tiago Vignattibc052c92012-04-19 16:18:18 +03001768}
1769
1770static void
1771shell_get_shell_surface(struct wl_client *client,
1772 struct wl_resource *resource,
1773 uint32_t id,
1774 struct wl_resource *surface_resource)
1775{
1776 struct weston_surface *surface = surface_resource->data;
1777 struct desktop_shell *shell = resource->data;
1778 struct shell_surface *shsurf;
1779
1780 if (get_shell_surface(surface)) {
1781 wl_resource_post_error(surface_resource,
Kristian Høgsberg9540ea62012-05-21 14:28:57 -04001782 WL_DISPLAY_ERROR_INVALID_OBJECT,
1783 "desktop_shell::get_shell_surface already requested");
Tiago Vignattibc052c92012-04-19 16:18:18 +03001784 return;
1785 }
1786
Kristian Høgsberga61ca062012-05-22 16:05:52 -04001787 shsurf = create_shell_surface(shell, surface, &shell_client);
Kristian Høgsberg9540ea62012-05-21 14:28:57 -04001788 if (!shsurf) {
1789 wl_resource_post_error(surface_resource,
1790 WL_DISPLAY_ERROR_INVALID_OBJECT,
1791 "surface->configure already set");
1792 return;
1793 }
Tiago Vignattibc052c92012-04-19 16:18:18 +03001794
Kristian Høgsberg9540ea62012-05-21 14:28:57 -04001795 shsurf->resource.destroy = shell_destroy_shell_surface;
1796 shsurf->resource.object.id = id;
1797 shsurf->resource.object.interface = &wl_shell_surface_interface;
1798 shsurf->resource.object.implementation =
1799 (void (**)(void)) &shell_surface_implementation;
1800 shsurf->resource.data = shsurf;
Tiago Vignattibc052c92012-04-19 16:18:18 +03001801
Kristian Høgsberg9540ea62012-05-21 14:28:57 -04001802 wl_client_add_resource(client, &shsurf->resource);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001803}
1804
1805static const struct wl_shell_interface shell_implementation = {
Pekka Paalanen46229672011-11-29 15:49:31 +02001806 shell_get_shell_surface
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001807};
1808
Kristian Høgsberg07937562011-04-12 17:25:42 -04001809static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001810handle_screensaver_sigchld(struct weston_process *proc, int status)
Pekka Paalanen18027e52011-12-02 16:31:49 +02001811{
1812 proc->pid = 0;
1813}
1814
1815static void
Tiago Vignattibe143262012-04-16 17:31:41 +03001816launch_screensaver(struct desktop_shell *shell)
Pekka Paalanen77346a62011-11-30 16:26:35 +02001817{
1818 if (shell->screensaver.binding)
1819 return;
1820
Pekka Paalanene955f1e2011-12-07 11:49:52 +02001821 if (!shell->screensaver.path)
1822 return;
1823
Kristian Høgsberg32bed572012-03-01 17:11:36 -05001824 if (shell->screensaver.process.pid != 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001825 weston_log("old screensaver still running\n");
Kristian Høgsberg32bed572012-03-01 17:11:36 -05001826 return;
1827 }
1828
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001829 weston_client_launch(shell->compositor,
Pekka Paalanen18027e52011-12-02 16:31:49 +02001830 &shell->screensaver.process,
Pekka Paalanene955f1e2011-12-07 11:49:52 +02001831 shell->screensaver.path,
Pekka Paalanen18027e52011-12-02 16:31:49 +02001832 handle_screensaver_sigchld);
Pekka Paalanen77346a62011-11-30 16:26:35 +02001833}
1834
1835static void
Tiago Vignattibe143262012-04-16 17:31:41 +03001836terminate_screensaver(struct desktop_shell *shell)
Pekka Paalanen77346a62011-11-30 16:26:35 +02001837{
Pekka Paalanen18027e52011-12-02 16:31:49 +02001838 if (shell->screensaver.process.pid == 0)
1839 return;
1840
1841 kill(shell->screensaver.process.pid, SIGTERM);
Pekka Paalanen77346a62011-11-30 16:26:35 +02001842}
1843
1844static void
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001845configure_static_surface(struct weston_surface *es, struct weston_layer *layer)
Kristian Høgsberg962342c2012-06-26 16:29:50 -04001846{
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001847 struct weston_surface *s, *next;
Kristian Høgsberg962342c2012-06-26 16:29:50 -04001848
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001849 wl_list_for_each_safe(s, next, &layer->surface_list, layer_link) {
1850 if (s->output == es->output && s != es) {
1851 weston_surface_unmap(s);
Kristian Høgsberg962342c2012-06-26 16:29:50 -04001852 s->configure = NULL;
Kristian Høgsberg962342c2012-06-26 16:29:50 -04001853 }
1854 }
1855
1856 weston_surface_configure(es, es->output->x, es->output->y,
1857 es->buffer->width, es->buffer->height);
1858
1859 if (wl_list_empty(&es->layer_link)) {
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001860 wl_list_insert(&layer->surface_list, &es->layer_link);
Kristian Høgsbergc7cd6262012-06-28 13:46:09 -04001861 weston_compositor_schedule_repaint(es->compositor);
Kristian Høgsberg962342c2012-06-26 16:29:50 -04001862 }
1863}
1864
1865static void
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001866background_configure(struct weston_surface *es, int32_t sx, int32_t sy)
1867{
1868 struct desktop_shell *shell = es->private;
1869
1870 configure_static_surface(es, &shell->background_layer);
1871}
1872
1873static void
Kristian Høgsberg75840622011-09-06 13:48:16 -04001874desktop_shell_set_background(struct wl_client *client,
1875 struct wl_resource *resource,
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01001876 struct wl_resource *output_resource,
Kristian Høgsberg75840622011-09-06 13:48:16 -04001877 struct wl_resource *surface_resource)
1878{
Kristian Høgsberg962342c2012-06-26 16:29:50 -04001879 struct desktop_shell *shell = resource->data;
1880 struct weston_surface *surface = surface_resource->data;
Kristian Høgsberg75840622011-09-06 13:48:16 -04001881
Kristian Høgsberg962342c2012-06-26 16:29:50 -04001882 if (surface->configure) {
1883 wl_resource_post_error(surface_resource,
1884 WL_DISPLAY_ERROR_INVALID_OBJECT,
1885 "surface role already assigned");
1886 return;
1887 }
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01001888
Kristian Høgsberg962342c2012-06-26 16:29:50 -04001889 surface->configure = background_configure;
1890 surface->private = shell;
1891 surface->output = output_resource->data;
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001892 desktop_shell_send_configure(resource, 0,
Kristian Høgsberg0b5cd0c2012-03-04 21:57:37 -05001893 surface_resource,
Kristian Høgsberg962342c2012-06-26 16:29:50 -04001894 surface->output->current->width,
1895 surface->output->current->height);
Kristian Høgsberg75840622011-09-06 13:48:16 -04001896}
1897
1898static void
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001899panel_configure(struct weston_surface *es, int32_t sx, int32_t sy)
1900{
1901 struct desktop_shell *shell = es->private;
1902
1903 configure_static_surface(es, &shell->panel_layer);
1904}
1905
1906static void
Kristian Høgsberg75840622011-09-06 13:48:16 -04001907desktop_shell_set_panel(struct wl_client *client,
1908 struct wl_resource *resource,
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01001909 struct wl_resource *output_resource,
Kristian Høgsberg75840622011-09-06 13:48:16 -04001910 struct wl_resource *surface_resource)
1911{
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001912 struct desktop_shell *shell = resource->data;
1913 struct weston_surface *surface = surface_resource->data;
Kristian Høgsberg75840622011-09-06 13:48:16 -04001914
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001915 if (surface->configure) {
1916 wl_resource_post_error(surface_resource,
1917 WL_DISPLAY_ERROR_INVALID_OBJECT,
1918 "surface role already assigned");
1919 return;
1920 }
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01001921
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001922 surface->configure = panel_configure;
1923 surface->private = shell;
1924 surface->output = output_resource->data;
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001925 desktop_shell_send_configure(resource, 0,
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001926 surface_resource,
1927 surface->output->current->width,
1928 surface->output->current->height);
Kristian Høgsberg75840622011-09-06 13:48:16 -04001929}
1930
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001931static void
Kristian Høgsberg730c94d2012-06-26 21:44:35 -04001932lock_surface_configure(struct weston_surface *surface, int32_t sx, int32_t sy)
1933{
1934 struct desktop_shell *shell = surface->private;
1935
1936 center_on_output(surface, get_default_output(shell->compositor));
1937
1938 if (!weston_surface_is_mapped(surface)) {
1939 wl_list_insert(&shell->lock_layer.surface_list,
1940 &surface->layer_link);
1941 weston_surface_assign_output(surface);
1942 weston_compositor_wake(shell->compositor);
1943 }
1944}
1945
1946static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001947handle_lock_surface_destroy(struct wl_listener *listener, void *data)
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001948{
Tiago Vignattibe143262012-04-16 17:31:41 +03001949 struct desktop_shell *shell =
1950 container_of(listener, struct desktop_shell, lock_surface_listener);
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001951
Martin Minarik6d118362012-06-07 18:01:59 +02001952 weston_log("lock surface gone\n");
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001953 shell->lock_surface = NULL;
1954}
1955
1956static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001957desktop_shell_set_lock_surface(struct wl_client *client,
1958 struct wl_resource *resource,
1959 struct wl_resource *surface_resource)
1960{
Tiago Vignattibe143262012-04-16 17:31:41 +03001961 struct desktop_shell *shell = resource->data;
Kristian Høgsberg730c94d2012-06-26 21:44:35 -04001962 struct weston_surface *surface = surface_resource->data;
Pekka Paalanen98262232011-12-01 10:42:22 +02001963
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001964 shell->prepare_event_sent = false;
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +02001965
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001966 if (!shell->locked)
1967 return;
1968
Pekka Paalanen98262232011-12-01 10:42:22 +02001969 shell->lock_surface = surface;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001970
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001971 shell->lock_surface_listener.notify = handle_lock_surface_destroy;
1972 wl_signal_add(&surface_resource->destroy_signal,
1973 &shell->lock_surface_listener);
Pekka Paalanen57da4a82011-11-23 16:42:16 +02001974
Kristian Høgsberg730c94d2012-06-26 21:44:35 -04001975 surface->configure = lock_surface_configure;
1976 surface->private = shell;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001977}
1978
1979static void
Tiago Vignattibe143262012-04-16 17:31:41 +03001980resume_desktop(struct desktop_shell *shell)
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001981{
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04001982 struct weston_surface *surface;
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04001983 struct workspace *ws = get_current_workspace(shell);
Pekka Paalanen77346a62011-11-30 16:26:35 +02001984
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04001985 wl_list_for_each(surface, &shell->screensaver.surfaces, link)
1986 weston_surface_unmap(surface);
Pekka Paalanen77346a62011-11-30 16:26:35 +02001987
1988 terminate_screensaver(shell);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001989
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05001990 wl_list_remove(&shell->lock_layer.link);
1991 wl_list_insert(&shell->compositor->cursor_layer.link,
1992 &shell->fullscreen_layer.link);
1993 wl_list_insert(&shell->fullscreen_layer.link,
1994 &shell->panel_layer.link);
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04001995 wl_list_insert(&shell->panel_layer.link, &ws->layer.link);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001996
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -04001997 restore_focus_state(shell, get_current_workspace(shell));
Jonas Ådahl04769742012-06-13 00:01:24 +02001998
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02001999 shell->locked = false;
Pekka Paalanen7296e792011-12-07 16:22:00 +02002000 shell->compositor->idle_time = shell->compositor->option_idle_time;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002001 weston_compositor_wake(shell->compositor);
Pekka Paalanenfc6d91a2012-02-10 15:33:10 +02002002 weston_compositor_damage_all(shell->compositor);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002003}
2004
2005static void
2006desktop_shell_unlock(struct wl_client *client,
2007 struct wl_resource *resource)
2008{
Tiago Vignattibe143262012-04-16 17:31:41 +03002009 struct desktop_shell *shell = resource->data;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002010
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002011 shell->prepare_event_sent = false;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002012
2013 if (shell->locked)
2014 resume_desktop(shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002015}
2016
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04002017static void
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03002018desktop_shell_set_grab_surface(struct wl_client *client,
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04002019 struct wl_resource *resource,
2020 struct wl_resource *surface_resource)
2021{
2022 struct desktop_shell *shell = resource->data;
2023
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03002024 shell->grab_surface = surface_resource->data;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04002025}
2026
Kristian Høgsberg75840622011-09-06 13:48:16 -04002027static const struct desktop_shell_interface desktop_shell_implementation = {
2028 desktop_shell_set_background,
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002029 desktop_shell_set_panel,
2030 desktop_shell_set_lock_surface,
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04002031 desktop_shell_unlock,
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03002032 desktop_shell_set_grab_surface
Kristian Høgsberg75840622011-09-06 13:48:16 -04002033};
2034
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02002035static enum shell_surface_type
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002036get_shell_surface_type(struct weston_surface *surface)
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02002037{
2038 struct shell_surface *shsurf;
2039
2040 shsurf = get_shell_surface(surface);
2041 if (!shsurf)
Pekka Paalanen98262232011-12-01 10:42:22 +02002042 return SHELL_SURFACE_NONE;
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02002043 return shsurf->type;
2044}
2045
Kristian Høgsberg75840622011-09-06 13:48:16 -04002046static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002047move_binding(struct wl_seat *seat, uint32_t time, uint32_t button, void *data)
Kristian Høgsberg07937562011-04-12 17:25:42 -04002048{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002049 struct weston_surface *surface =
Daniel Stone37816df2012-05-16 18:45:18 +01002050 (struct weston_surface *) seat->pointer->focus;
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04002051 struct shell_surface *shsurf;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -05002052
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01002053 if (surface == NULL)
2054 return;
Kristian Høgsberg07937562011-04-12 17:25:42 -04002055
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04002056 shsurf = get_shell_surface(surface);
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04002057 if (shsurf == NULL || shsurf->type == SHELL_SURFACE_FULLSCREEN)
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04002058 return;
2059
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04002060 surface_move(shsurf, (struct weston_seat *) seat);
Kristian Høgsberg07937562011-04-12 17:25:42 -04002061}
2062
2063static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002064resize_binding(struct wl_seat *seat, uint32_t time, uint32_t button, void *data)
Kristian Høgsberg07937562011-04-12 17:25:42 -04002065{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002066 struct weston_surface *surface =
Daniel Stone37816df2012-05-16 18:45:18 +01002067 (struct weston_surface *) seat->pointer->focus;
Kristian Høgsberg07937562011-04-12 17:25:42 -04002068 uint32_t edges = 0;
2069 int32_t x, y;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002070 struct shell_surface *shsurf;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -05002071
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01002072 if (surface == NULL)
2073 return;
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02002074
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002075 shsurf = get_shell_surface(surface);
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04002076 if (!shsurf || shsurf->type == SHELL_SURFACE_FULLSCREEN)
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02002077 return;
2078
Pekka Paalanen5c97ae72012-01-30 16:19:47 +02002079 weston_surface_from_global(surface,
Daniel Stone37816df2012-05-16 18:45:18 +01002080 wl_fixed_to_int(seat->pointer->grab_x),
2081 wl_fixed_to_int(seat->pointer->grab_y),
Daniel Stone103db7f2012-05-08 17:17:55 +01002082 &x, &y);
Kristian Høgsberg07937562011-04-12 17:25:42 -04002083
Pekka Paalanen60921e52012-01-25 15:55:43 +02002084 if (x < surface->geometry.width / 3)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002085 edges |= WL_SHELL_SURFACE_RESIZE_LEFT;
Pekka Paalanen60921e52012-01-25 15:55:43 +02002086 else if (x < 2 * surface->geometry.width / 3)
Kristian Høgsberg07937562011-04-12 17:25:42 -04002087 edges |= 0;
2088 else
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002089 edges |= WL_SHELL_SURFACE_RESIZE_RIGHT;
Kristian Høgsberg07937562011-04-12 17:25:42 -04002090
Pekka Paalanen60921e52012-01-25 15:55:43 +02002091 if (y < surface->geometry.height / 3)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002092 edges |= WL_SHELL_SURFACE_RESIZE_TOP;
Pekka Paalanen60921e52012-01-25 15:55:43 +02002093 else if (y < 2 * surface->geometry.height / 3)
Kristian Høgsberg07937562011-04-12 17:25:42 -04002094 edges |= 0;
2095 else
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002096 edges |= WL_SHELL_SURFACE_RESIZE_BOTTOM;
Kristian Høgsberg07937562011-04-12 17:25:42 -04002097
Kristian Høgsbergc1693f22012-05-22 16:56:23 -04002098 surface_resize(shsurf, (struct weston_seat *) seat, edges);
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04002099}
2100
2101static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002102surface_opacity_binding(struct wl_seat *seat, uint32_t time, uint32_t axis,
Daniel Stone0c1e46e2012-05-30 16:31:59 +01002103 wl_fixed_t value, void *data)
Scott Moreaua3aa9c92012-03-22 11:01:03 -06002104{
Scott Moreau02709af2012-05-22 01:54:10 -06002105 float step = 0.05;
Scott Moreaua3aa9c92012-03-22 11:01:03 -06002106 struct shell_surface *shsurf;
2107 struct weston_surface *surface =
Daniel Stone37816df2012-05-16 18:45:18 +01002108 (struct weston_surface *) seat->pointer->focus;
Scott Moreaua3aa9c92012-03-22 11:01:03 -06002109
2110 if (surface == NULL)
2111 return;
2112
2113 shsurf = get_shell_surface(surface);
2114 if (!shsurf)
2115 return;
2116
Daniel Stone0c1e46e2012-05-30 16:31:59 +01002117 surface->alpha += wl_fixed_to_double(value) * step;
Scott Moreaua3aa9c92012-03-22 11:01:03 -06002118
Scott Moreau02709af2012-05-22 01:54:10 -06002119 if (surface->alpha > 1.0)
2120 surface->alpha = 1.0;
Scott Moreaua3aa9c92012-03-22 11:01:03 -06002121 if (surface->alpha < step)
2122 surface->alpha = step;
2123
2124 surface->geometry.dirty = 1;
2125 weston_surface_damage(surface);
2126}
2127
2128static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002129do_zoom(struct wl_seat *seat, uint32_t time, uint32_t key, uint32_t axis,
Daniel Stone0c1e46e2012-05-30 16:31:59 +01002130 wl_fixed_t value)
Scott Moreauccbf29d2012-02-22 14:21:41 -07002131{
Daniel Stone37816df2012-05-16 18:45:18 +01002132 struct weston_seat *ws = (struct weston_seat *) seat;
2133 struct weston_compositor *compositor = ws->compositor;
Scott Moreauccbf29d2012-02-22 14:21:41 -07002134 struct weston_output *output;
Scott Moreaue6603982012-06-11 13:07:51 -06002135 float increment;
Scott Moreauccbf29d2012-02-22 14:21:41 -07002136
2137 wl_list_for_each(output, &compositor->output_list, link) {
2138 if (pixman_region32_contains_point(&output->region,
Daniel Stone37816df2012-05-16 18:45:18 +01002139 wl_fixed_to_double(seat->pointer->x),
2140 wl_fixed_to_double(seat->pointer->y),
Daniel Stone103db7f2012-05-08 17:17:55 +01002141 NULL)) {
Daniel Stone325fc2d2012-05-30 16:31:58 +01002142 if (key == KEY_PAGEUP)
Kristian Høgsberg9b68af02012-05-22 12:55:18 -04002143 increment = output->zoom.increment;
Daniel Stone325fc2d2012-05-30 16:31:58 +01002144 else if (key == KEY_PAGEDOWN)
Kristian Høgsberg9b68af02012-05-22 12:55:18 -04002145 increment = -output->zoom.increment;
2146 else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
Daniel Stone0c1e46e2012-05-30 16:31:59 +01002147 increment = output->zoom.increment *
2148 wl_fixed_to_double(value);
Kristian Høgsberg9b68af02012-05-22 12:55:18 -04002149 else
2150 increment = 0;
2151
Kristian Høgsberg9b68af02012-05-22 12:55:18 -04002152 output->zoom.level += increment;
Scott Moreauc6d7f602012-02-23 22:28:37 -07002153
Scott Moreaue6603982012-06-11 13:07:51 -06002154 if (output->zoom.level < 0.0)
Scott Moreau850ca422012-05-21 15:21:25 -06002155 output->zoom.level = 0.0;
Scott Moreaue6603982012-06-11 13:07:51 -06002156 else if (output->zoom.level > output->zoom.max_level)
2157 output->zoom.level = output->zoom.max_level;
2158 else
2159 output->zoom.active = 1;
Scott Moreauccbf29d2012-02-22 14:21:41 -07002160
Scott Moreaue6603982012-06-11 13:07:51 -06002161 output->zoom.spring_z.target = output->zoom.level;
Scott Moreauccbf29d2012-02-22 14:21:41 -07002162
Scott Moreau8dacaab2012-06-17 18:10:58 -06002163 weston_output_update_zoom(output, output->zoom.type);
Scott Moreauccbf29d2012-02-22 14:21:41 -07002164 }
2165 }
2166}
2167
Scott Moreauccbf29d2012-02-22 14:21:41 -07002168static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002169zoom_axis_binding(struct wl_seat *seat, uint32_t time, uint32_t axis,
Daniel Stone0c1e46e2012-05-30 16:31:59 +01002170 wl_fixed_t value, void *data)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002171{
2172 do_zoom(seat, time, 0, axis, value);
2173}
2174
2175static void
2176zoom_key_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
2177 void *data)
2178{
2179 do_zoom(seat, time, key, 0, 0);
2180}
2181
2182static void
2183terminate_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
2184 void *data)
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05002185{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002186 struct weston_compositor *compositor = data;
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05002187
Daniel Stone325fc2d2012-05-30 16:31:58 +01002188 wl_display_terminate(compositor->wl_display);
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05002189}
2190
2191static void
Scott Moreau447013d2012-02-18 05:05:29 -07002192rotate_grab_motion(struct wl_pointer_grab *grab,
Daniel Stone103db7f2012-05-08 17:17:55 +01002193 uint32_t time, wl_fixed_t x, wl_fixed_t y)
Pekka Paalanen460099f2012-01-20 16:48:25 +02002194{
2195 struct rotate_grab *rotate =
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002196 container_of(grab, struct rotate_grab, base.grab);
Daniel Stone37816df2012-05-16 18:45:18 +01002197 struct wl_pointer *pointer = grab->pointer;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002198 struct shell_surface *shsurf = rotate->base.shsurf;
2199 struct weston_surface *surface;
2200 GLfloat cx, cy, dx, dy, cposx, cposy, dposx, dposy, r;
2201
2202 if (!shsurf)
2203 return;
2204
2205 surface = shsurf->surface;
2206
2207 cx = 0.5f * surface->geometry.width;
2208 cy = 0.5f * surface->geometry.height;
Pekka Paalanen460099f2012-01-20 16:48:25 +02002209
Daniel Stone37816df2012-05-16 18:45:18 +01002210 dx = wl_fixed_to_double(pointer->x) - rotate->center.x;
2211 dy = wl_fixed_to_double(pointer->y) - rotate->center.y;
Pekka Paalanen460099f2012-01-20 16:48:25 +02002212 r = sqrtf(dx * dx + dy * dy);
2213
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002214 wl_list_remove(&shsurf->rotation.transform.link);
2215 shsurf->surface->geometry.dirty = 1;
Pekka Paalanen460099f2012-01-20 16:48:25 +02002216
2217 if (r > 20.0f) {
Pekka Paalanen460099f2012-01-20 16:48:25 +02002218 struct weston_matrix *matrix =
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002219 &shsurf->rotation.transform.matrix;
Pekka Paalanen460099f2012-01-20 16:48:25 +02002220
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05002221 weston_matrix_init(&rotate->rotation);
2222 rotate->rotation.d[0] = dx / r;
2223 rotate->rotation.d[4] = -dy / r;
2224 rotate->rotation.d[1] = -rotate->rotation.d[4];
2225 rotate->rotation.d[5] = rotate->rotation.d[0];
Pekka Paalanen460099f2012-01-20 16:48:25 +02002226
2227 weston_matrix_init(matrix);
Pekka Paalanen7b3bd3d2012-01-30 14:16:34 +02002228 weston_matrix_translate(matrix, -cx, -cy, 0.0f);
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002229 weston_matrix_multiply(matrix, &shsurf->rotation.rotation);
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05002230 weston_matrix_multiply(matrix, &rotate->rotation);
Pekka Paalanen7b3bd3d2012-01-30 14:16:34 +02002231 weston_matrix_translate(matrix, cx, cy, 0.0f);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002232
Pekka Paalanenbc0b7e72012-01-24 09:53:37 +02002233 wl_list_insert(
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002234 &shsurf->surface->geometry.transformation_list,
2235 &shsurf->rotation.transform.link);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002236 } else {
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002237 wl_list_init(&shsurf->rotation.transform.link);
2238 weston_matrix_init(&shsurf->rotation.rotation);
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05002239 weston_matrix_init(&rotate->rotation);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002240 }
Pekka Paalanenb45ac5e2012-02-09 15:58:44 +02002241
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01002242 /* We need to adjust the position of the surface
2243 * in case it was resized in a rotated state before */
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002244 cposx = surface->geometry.x + cx;
2245 cposy = surface->geometry.y + cy;
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01002246 dposx = rotate->center.x - cposx;
2247 dposy = rotate->center.y - cposy;
2248 if (dposx != 0.0f || dposy != 0.0f) {
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002249 weston_surface_set_position(surface,
2250 surface->geometry.x + dposx,
2251 surface->geometry.y + dposy);
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01002252 }
2253
Pekka Paalanenb45ac5e2012-02-09 15:58:44 +02002254 /* Repaint implies weston_surface_update_transform(), which
2255 * lazily applies the damage due to rotation update.
2256 */
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002257 weston_compositor_schedule_repaint(shsurf->surface->compositor);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002258}
2259
2260static void
Scott Moreau447013d2012-02-18 05:05:29 -07002261rotate_grab_button(struct wl_pointer_grab *grab,
Daniel Stone4dbadb12012-05-30 16:31:51 +01002262 uint32_t time, uint32_t button, uint32_t state_w)
Pekka Paalanen460099f2012-01-20 16:48:25 +02002263{
2264 struct rotate_grab *rotate =
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002265 container_of(grab, struct rotate_grab, base.grab);
Daniel Stone37816df2012-05-16 18:45:18 +01002266 struct wl_pointer *pointer = grab->pointer;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002267 struct shell_surface *shsurf = rotate->base.shsurf;
Daniel Stone4dbadb12012-05-30 16:31:51 +01002268 enum wl_pointer_button_state state = state_w;
Pekka Paalanen460099f2012-01-20 16:48:25 +02002269
Daniel Stone4dbadb12012-05-30 16:31:51 +01002270 if (pointer->button_count == 0 &&
2271 state == WL_POINTER_BUTTON_STATE_RELEASED) {
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002272 if (shsurf)
2273 weston_matrix_multiply(&shsurf->rotation.rotation,
2274 &rotate->rotation);
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03002275 shell_grab_end(&rotate->base);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002276 free(rotate);
2277 }
2278}
2279
Scott Moreau447013d2012-02-18 05:05:29 -07002280static const struct wl_pointer_grab_interface rotate_grab_interface = {
Pekka Paalanen460099f2012-01-20 16:48:25 +02002281 noop_grab_focus,
2282 rotate_grab_motion,
2283 rotate_grab_button,
2284};
2285
2286static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002287rotate_binding(struct wl_seat *seat, uint32_t time, uint32_t button,
Daniel Stonee5a01202012-05-04 11:21:57 +01002288 void *data)
Pekka Paalanen460099f2012-01-20 16:48:25 +02002289{
2290 struct weston_surface *base_surface =
Daniel Stone37816df2012-05-16 18:45:18 +01002291 (struct weston_surface *) seat->pointer->focus;
Pekka Paalanen460099f2012-01-20 16:48:25 +02002292 struct shell_surface *surface;
2293 struct rotate_grab *rotate;
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01002294 GLfloat dx, dy;
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05002295 GLfloat r;
Pekka Paalanen460099f2012-01-20 16:48:25 +02002296
2297 if (base_surface == NULL)
2298 return;
2299
2300 surface = get_shell_surface(base_surface);
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04002301 if (!surface || surface->type == SHELL_SURFACE_FULLSCREEN)
Pekka Paalanen460099f2012-01-20 16:48:25 +02002302 return;
2303
Pekka Paalanen460099f2012-01-20 16:48:25 +02002304 rotate = malloc(sizeof *rotate);
2305 if (!rotate)
2306 return;
2307
Kristian Høgsbergb2af93e2012-06-07 20:10:23 -04002308 weston_surface_to_global_float(surface->surface,
2309 surface->surface->geometry.width / 2,
2310 surface->surface->geometry.height / 2,
2311 &rotate->center.x, &rotate->center.y);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002312
Daniel Stone37816df2012-05-16 18:45:18 +01002313 dx = wl_fixed_to_double(seat->pointer->x) - rotate->center.x;
2314 dy = wl_fixed_to_double(seat->pointer->y) - rotate->center.y;
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05002315 r = sqrtf(dx * dx + dy * dy);
2316 if (r > 20.0f) {
2317 struct weston_matrix inverse;
2318
2319 weston_matrix_init(&inverse);
2320 inverse.d[0] = dx / r;
2321 inverse.d[4] = dy / r;
2322 inverse.d[1] = -inverse.d[4];
2323 inverse.d[5] = inverse.d[0];
2324 weston_matrix_multiply(&surface->rotation.rotation, &inverse);
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01002325
2326 weston_matrix_init(&rotate->rotation);
2327 rotate->rotation.d[0] = dx / r;
2328 rotate->rotation.d[4] = -dy / r;
2329 rotate->rotation.d[1] = -rotate->rotation.d[4];
2330 rotate->rotation.d[5] = rotate->rotation.d[0];
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05002331 } else {
2332 weston_matrix_init(&surface->rotation.rotation);
2333 weston_matrix_init(&rotate->rotation);
2334 }
2335
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03002336 shell_grab_start(&rotate->base, &rotate_grab_interface, surface,
2337 seat->pointer, DESKTOP_SHELL_CURSOR_ARROW);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002338}
2339
2340static void
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04002341lower_fullscreen_layer(struct desktop_shell *shell)
2342{
2343 struct workspace *ws;
2344 struct weston_surface *surface, *prev;
2345
2346 ws = get_current_workspace(shell);
2347 wl_list_for_each_reverse_safe(surface, prev,
2348 &shell->fullscreen_layer.surface_list,
2349 layer_link)
2350 weston_surface_restack(surface, &ws->layer.surface_list);
2351}
2352
2353static void
Tiago Vignattibe143262012-04-16 17:31:41 +03002354activate(struct desktop_shell *shell, struct weston_surface *es,
Daniel Stone37816df2012-05-16 18:45:18 +01002355 struct weston_seat *seat)
Kristian Høgsberg75840622011-09-06 13:48:16 -04002356{
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -04002357 struct workspace *ws = get_current_workspace(shell);
2358 struct focus_state *state;
Kristian Høgsberg75840622011-09-06 13:48:16 -04002359
Daniel Stone37816df2012-05-16 18:45:18 +01002360 weston_surface_activate(es, seat);
Kristian Høgsberg75840622011-09-06 13:48:16 -04002361
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -04002362 wl_list_for_each(state, &ws->focus_list, link)
2363 if (state->seat == seat)
2364 break;
2365
2366 if (&state->link == &ws->focus_list) {
2367 state = focus_state_create(seat, ws);
2368 if (state == NULL)
2369 return;
2370 }
2371
2372 state->keyboard_focus = es;
2373 wl_list_remove(&state->surface_destroy_listener.link);
2374 wl_signal_add(&es->surface.resource.destroy_signal,
2375 &state->surface_destroy_listener);
2376
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02002377 switch (get_shell_surface_type(es)) {
Alex Wu4539b082012-03-01 12:57:46 +08002378 case SHELL_SURFACE_FULLSCREEN:
2379 /* should on top of panels */
Alex Wu21858432012-04-01 20:13:08 +08002380 shell_stack_fullscreen(get_shell_surface(es));
Alex Wubd3354b2012-04-17 17:20:49 +08002381 shell_configure_fullscreen(get_shell_surface(es));
Alex Wu4539b082012-03-01 12:57:46 +08002382 break;
Pekka Paalanen57da4a82011-11-23 16:42:16 +02002383 default:
Jonas Ådahle3cddce2012-06-13 00:01:22 +02002384 ws = get_current_workspace(shell);
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04002385 lower_fullscreen_layer(shell);
2386 weston_surface_restack(es, &ws->layer.surface_list);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002387 break;
Kristian Høgsberg75840622011-09-06 13:48:16 -04002388 }
2389}
2390
Alex Wu21858432012-04-01 20:13:08 +08002391/* no-op func for checking black surface */
2392static void
2393black_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
2394{
2395}
2396
2397static bool
2398is_black_surface (struct weston_surface *es, struct weston_surface **fs_surface)
2399{
2400 if (es->configure == black_surface_configure) {
2401 if (fs_surface)
2402 *fs_surface = (struct weston_surface *)es->private;
2403 return true;
2404 }
2405 return false;
2406}
2407
Kristian Høgsberg75840622011-09-06 13:48:16 -04002408static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002409click_to_activate_binding(struct wl_seat *seat, uint32_t time, uint32_t button,
Daniel Stone4dbadb12012-05-30 16:31:51 +01002410 void *data)
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05002411{
Daniel Stone37816df2012-05-16 18:45:18 +01002412 struct weston_seat *ws = (struct weston_seat *) seat;
Tiago Vignattibe143262012-04-16 17:31:41 +03002413 struct desktop_shell *shell = data;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002414 struct weston_surface *focus;
Alex Wu4539b082012-03-01 12:57:46 +08002415 struct weston_surface *upper;
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05002416
Daniel Stone37816df2012-05-16 18:45:18 +01002417 focus = (struct weston_surface *) seat->pointer->focus;
Alex Wu9c35e6b2012-03-05 14:13:13 +08002418 if (!focus)
2419 return;
2420
Alex Wu21858432012-04-01 20:13:08 +08002421 if (is_black_surface(focus, &upper))
Alex Wu4539b082012-03-01 12:57:46 +08002422 focus = upper;
Alex Wu4539b082012-03-01 12:57:46 +08002423
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04002424 if (get_shell_surface_type(focus) == SHELL_SURFACE_NONE)
2425 return;
Kristian Høgsberg85b2e4b2012-06-21 16:49:42 -04002426
Daniel Stone325fc2d2012-05-30 16:31:58 +01002427 if (seat->pointer->grab == &seat->pointer->default_grab)
Daniel Stone37816df2012-05-16 18:45:18 +01002428 activate(shell, focus, ws);
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05002429}
2430
2431static void
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04002432lock(struct wl_listener *listener, void *data)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04002433{
Tiago Vignattibe143262012-04-16 17:31:41 +03002434 struct desktop_shell *shell =
2435 container_of(listener, struct desktop_shell, lock_listener);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002436 struct weston_output *output;
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04002437 struct workspace *ws = get_current_workspace(shell);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002438
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002439 if (shell->locked) {
2440 wl_list_for_each(output, &shell->compositor->output_list, link)
2441 /* TODO: find a way to jump to other DPMS levels */
2442 if (output->set_dpms)
2443 output->set_dpms(output, WESTON_DPMS_STANDBY);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002444 return;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002445 }
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002446
2447 shell->locked = true;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002448
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002449 /* Hide all surfaces by removing the fullscreen, panel and
2450 * toplevel layers. This way nothing else can show or receive
2451 * input events while we are locked. */
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002452
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002453 wl_list_remove(&shell->panel_layer.link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002454 wl_list_remove(&shell->fullscreen_layer.link);
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04002455 wl_list_remove(&ws->layer.link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002456 wl_list_insert(&shell->compositor->cursor_layer.link,
2457 &shell->lock_layer.link);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002458
Pekka Paalanen77346a62011-11-30 16:26:35 +02002459 launch_screensaver(shell);
2460
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002461 /* TODO: disable bindings that should not work while locked. */
2462
2463 /* All this must be undone in resume_desktop(). */
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002464}
2465
2466static void
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04002467unlock(struct wl_listener *listener, void *data)
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002468{
Tiago Vignattibe143262012-04-16 17:31:41 +03002469 struct desktop_shell *shell =
2470 container_of(listener, struct desktop_shell, unlock_listener);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002471
Pekka Paalanend81c2162011-11-16 13:47:34 +02002472 if (!shell->locked || shell->lock_surface) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002473 weston_compositor_wake(shell->compositor);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002474 return;
2475 }
2476
2477 /* If desktop-shell client has gone away, unlock immediately. */
2478 if (!shell->child.desktop_shell) {
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002479 resume_desktop(shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002480 return;
2481 }
2482
2483 if (shell->prepare_event_sent)
2484 return;
2485
Kristian Høgsberg0b5cd0c2012-03-04 21:57:37 -05002486 desktop_shell_send_prepare_lock_surface(shell->child.desktop_shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002487 shell->prepare_event_sent = true;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04002488}
2489
2490static void
Jan Arne Petersen42feced2012-06-21 21:52:17 +02002491show_input_panels(struct wl_listener *listener, void *data)
2492{
2493 struct desktop_shell *shell =
2494 container_of(listener, struct desktop_shell, show_input_panel_listener);
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04002495 struct weston_surface *surface, *next;
Jan Arne Petersen42feced2012-06-21 21:52:17 +02002496
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04002497 wl_list_for_each_safe(surface, next,
2498 &shell->input_panel.surfaces, layer_link) {
2499 wl_list_remove(&surface->layer_link);
2500 wl_list_insert(&shell->panel_layer.surface_list,
2501 &surface->layer_link);
2502 weston_surface_assign_output(surface);
2503 weston_surface_damage(surface);
2504 weston_slide_run(surface,
2505 surface->geometry.height, 0, NULL, NULL);
Jan Arne Petersen42feced2012-06-21 21:52:17 +02002506 }
2507}
2508
2509static void
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04002510input_panel_configure(struct weston_surface *surface, int32_t sx, int32_t sy);
2511
2512static void
Jan Arne Petersen42feced2012-06-21 21:52:17 +02002513hide_input_panels(struct wl_listener *listener, void *data)
2514{
2515 struct desktop_shell *shell =
2516 container_of(listener, struct desktop_shell, hide_input_panel_listener);
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04002517 struct weston_surface *surface, *next;
Jan Arne Petersen42feced2012-06-21 21:52:17 +02002518
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04002519 wl_list_for_each_safe(surface, next,
2520 &shell->panel_layer.surface_list, layer_link)
2521 if (surface->configure == input_panel_configure) {
2522 weston_surface_unmap(surface);
2523 wl_list_insert(&shell->input_panel.surfaces,
2524 &surface->layer_link);
2525 }
Jan Arne Petersen42feced2012-06-21 21:52:17 +02002526}
2527
2528static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002529center_on_output(struct weston_surface *surface, struct weston_output *output)
Pekka Paalanen77346a62011-11-30 16:26:35 +02002530{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002531 struct weston_mode *mode = output->current;
Kristian Høgsberg730c94d2012-06-26 21:44:35 -04002532 GLfloat x = (mode->width - surface->buffer->width) / 2;
2533 GLfloat y = (mode->height - surface->buffer->height) / 2;
Pekka Paalanen77346a62011-11-30 16:26:35 +02002534
Kristian Høgsberg730c94d2012-06-26 21:44:35 -04002535 weston_surface_configure(surface, output->x + x, output->y + y,
2536 surface->buffer->width,
2537 surface->buffer->height);
Pekka Paalanen77346a62011-11-30 16:26:35 +02002538}
2539
2540static void
Tiago Vignattibe143262012-04-16 17:31:41 +03002541map(struct desktop_shell *shell, struct weston_surface *surface,
Ander Conselvan de Oliveirae9e05152012-02-15 17:02:56 +02002542 int32_t width, int32_t height, int32_t sx, int32_t sy)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04002543{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002544 struct weston_compositor *compositor = shell->compositor;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02002545 struct shell_surface *shsurf = get_shell_surface(surface);
2546 enum shell_surface_type surface_type = shsurf->type;
Kristian Høgsberg60c49542012-03-05 20:51:34 -05002547 struct weston_surface *parent;
Daniel Stoneb2104682012-05-30 16:31:56 +01002548 struct weston_seat *seat;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02002549 struct workspace *ws;
Juan Zhao96879df2012-02-07 08:45:41 +08002550 int panel_height = 0;
Pekka Paalanen57da4a82011-11-23 16:42:16 +02002551
Pekka Paalanen60921e52012-01-25 15:55:43 +02002552 surface->geometry.width = width;
2553 surface->geometry.height = height;
2554 surface->geometry.dirty = 1;
Pekka Paalanen77346a62011-11-30 16:26:35 +02002555
2556 /* initial positioning, see also configure() */
2557 switch (surface_type) {
2558 case SHELL_SURFACE_TOPLEVEL:
Pekka Paalanen8fb8d3b2012-02-13 13:03:59 +02002559 weston_surface_set_position(surface, 10 + random() % 400,
2560 10 + random() % 400);
Pekka Paalanen77346a62011-11-30 16:26:35 +02002561 break;
Alex Wu4539b082012-03-01 12:57:46 +08002562 case SHELL_SURFACE_FULLSCREEN:
Kristian Høgsberge4d3a2b2012-07-09 21:43:22 -04002563 center_on_output(surface, shsurf->fullscreen_output);
Alex Wu4539b082012-03-01 12:57:46 +08002564 shell_map_fullscreen(shsurf);
2565 break;
Juan Zhao96879df2012-02-07 08:45:41 +08002566 case SHELL_SURFACE_MAXIMIZED:
Alex Wu4539b082012-03-01 12:57:46 +08002567 /* use surface configure to set the geometry */
Juan Zhao96879df2012-02-07 08:45:41 +08002568 panel_height = get_output_panel_height(shell,surface->output);
Rob Bradford31b68622012-07-02 19:00:19 +01002569 weston_surface_set_position(surface, shsurf->output->x,
2570 shsurf->output->y + panel_height);
Juan Zhao96879df2012-02-07 08:45:41 +08002571 break;
Tiago Vignatti0f997012012-02-10 16:17:23 +02002572 case SHELL_SURFACE_POPUP:
Kristian Høgsberg3730f362012-04-13 12:40:07 -04002573 shell_map_popup(shsurf);
Ander Conselvan de Oliveirae9e05152012-02-15 17:02:56 +02002574 case SHELL_SURFACE_NONE:
2575 weston_surface_set_position(surface,
2576 surface->geometry.x + sx,
2577 surface->geometry.y + sy);
Tiago Vignatti0f997012012-02-10 16:17:23 +02002578 break;
Pekka Paalanen77346a62011-11-30 16:26:35 +02002579 default:
2580 ;
2581 }
Kristian Høgsberg75840622011-09-06 13:48:16 -04002582
Pekka Paalanend3dd6e12011-11-16 13:47:33 +02002583 /* surface stacking order, see also activate() */
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02002584 switch (surface_type) {
Kristian Høgsberg60c49542012-03-05 20:51:34 -05002585 case SHELL_SURFACE_POPUP:
2586 case SHELL_SURFACE_TRANSIENT:
Kristian Høgsberg8150b192012-06-27 10:22:58 -04002587 parent = shsurf->parent;
Kristian Høgsberg60c49542012-03-05 20:51:34 -05002588 wl_list_insert(parent->layer_link.prev, &surface->layer_link);
2589 break;
Alex Wu4539b082012-03-01 12:57:46 +08002590 case SHELL_SURFACE_FULLSCREEN:
Ander Conselvan de Oliveiraa1ff53b2012-02-15 17:02:54 +02002591 case SHELL_SURFACE_NONE:
2592 break;
Pekka Paalanen57da4a82011-11-23 16:42:16 +02002593 default:
Jonas Ådahle3cddce2012-06-13 00:01:22 +02002594 ws = get_current_workspace(shell);
2595 wl_list_insert(&ws->layer.surface_list, &surface->layer_link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002596 break;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002597 }
2598
Ander Conselvan de Oliveirade56c312012-03-05 15:39:23 +02002599 if (surface_type != SHELL_SURFACE_NONE) {
2600 weston_surface_assign_output(surface);
Ander Conselvan de Oliveirade56c312012-03-05 15:39:23 +02002601 if (surface_type == SHELL_SURFACE_MAXIMIZED)
2602 surface->output = shsurf->output;
2603 }
Kristian Høgsberg2f88a402011-12-04 15:32:59 -05002604
Juan Zhao7bb92f02011-12-15 11:31:51 -05002605 switch (surface_type) {
Juan Zhao7bb92f02011-12-15 11:31:51 -05002606 case SHELL_SURFACE_TRANSIENT:
Tiago Vignatti99aeb1e2012-05-23 22:06:26 +03002607 if (shsurf->transient.flags ==
2608 WL_SHELL_SURFACE_TRANSIENT_INACTIVE)
2609 break;
2610 case SHELL_SURFACE_TOPLEVEL:
Juan Zhao7bb92f02011-12-15 11:31:51 -05002611 case SHELL_SURFACE_FULLSCREEN:
Juan Zhao96879df2012-02-07 08:45:41 +08002612 case SHELL_SURFACE_MAXIMIZED:
Daniel Stoneb2104682012-05-30 16:31:56 +01002613 if (!shell->locked) {
2614 wl_list_for_each(seat, &compositor->seat_list, link)
2615 activate(shell, surface, seat);
2616 }
Juan Zhao7bb92f02011-12-15 11:31:51 -05002617 break;
2618 default:
2619 break;
2620 }
2621
Kristian Høgsberg2f88a402011-12-04 15:32:59 -05002622 if (surface_type == SHELL_SURFACE_TOPLEVEL)
Juan Zhaoe10d2792012-04-25 19:09:52 +08002623 {
2624 switch (shell->win_animation_type) {
2625 case ANIMATION_FADE:
2626 weston_fade_run(surface, NULL, NULL);
2627 break;
2628 case ANIMATION_ZOOM:
2629 weston_zoom_run(surface, 0.8, 1.0, NULL, NULL);
2630 break;
2631 default:
2632 break;
2633 }
2634 }
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05002635}
2636
2637static void
Tiago Vignattibe143262012-04-16 17:31:41 +03002638configure(struct desktop_shell *shell, struct weston_surface *surface,
Pekka Paalanenddae03c2012-02-06 14:54:20 +02002639 GLfloat x, GLfloat y, int32_t width, int32_t height)
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05002640{
Pekka Paalanen77346a62011-11-30 16:26:35 +02002641 enum shell_surface_type surface_type = SHELL_SURFACE_NONE;
2642 struct shell_surface *shsurf;
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05002643
Pekka Paalanen77346a62011-11-30 16:26:35 +02002644 shsurf = get_shell_surface(surface);
2645 if (shsurf)
2646 surface_type = shsurf->type;
2647
Kristian Høgsberg6a8b5532012-02-16 23:43:59 -05002648 surface->geometry.x = x;
2649 surface->geometry.y = y;
Pekka Paalanen60921e52012-01-25 15:55:43 +02002650 surface->geometry.width = width;
2651 surface->geometry.height = height;
2652 surface->geometry.dirty = 1;
Pekka Paalanen77346a62011-11-30 16:26:35 +02002653
2654 switch (surface_type) {
Alex Wu4539b082012-03-01 12:57:46 +08002655 case SHELL_SURFACE_FULLSCREEN:
Alex Wubd3354b2012-04-17 17:20:49 +08002656 shell_stack_fullscreen(shsurf);
Alex Wu4539b082012-03-01 12:57:46 +08002657 shell_configure_fullscreen(shsurf);
Alex Wu4539b082012-03-01 12:57:46 +08002658 break;
Juan Zhao96879df2012-02-07 08:45:41 +08002659 case SHELL_SURFACE_MAXIMIZED:
Alex Wu4539b082012-03-01 12:57:46 +08002660 /* setting x, y and using configure to change that geometry */
Kristian Høgsberg6a8b5532012-02-16 23:43:59 -05002661 surface->geometry.x = surface->output->x;
2662 surface->geometry.y = surface->output->y +
2663 get_output_panel_height(shell,surface->output);
Juan Zhao96879df2012-02-07 08:45:41 +08002664 break;
Alex Wu4539b082012-03-01 12:57:46 +08002665 case SHELL_SURFACE_TOPLEVEL:
2666 break;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -05002667 default:
2668 break;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04002669 }
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05002670
Alex Wu4539b082012-03-01 12:57:46 +08002671 /* XXX: would a fullscreen surface need the same handling? */
Kristian Høgsberg6a8b5532012-02-16 23:43:59 -05002672 if (surface->output) {
Pekka Paalanenf07cb5d2012-02-10 13:34:36 +02002673 weston_surface_assign_output(surface);
Pekka Paalanen77346a62011-11-30 16:26:35 +02002674
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04002675 if (surface_type == SHELL_SURFACE_MAXIMIZED)
Juan Zhao96879df2012-02-07 08:45:41 +08002676 surface->output = shsurf->output;
Pekka Paalanen77346a62011-11-30 16:26:35 +02002677 }
Kristian Høgsberg07937562011-04-12 17:25:42 -04002678}
2679
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03002680static void
2681shell_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
2682{
Ander Conselvan de Oliveira7fb9f952012-03-27 17:36:42 +03002683 struct shell_surface *shsurf = get_shell_surface(es);
Tiago Vignattibe143262012-04-16 17:31:41 +03002684 struct desktop_shell *shell = shsurf->shell;
Tiago Vignatti70e5c9c2012-05-07 15:23:07 +03002685 int type_changed = 0;
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03002686
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04002687 if (shsurf->next_type != SHELL_SURFACE_NONE &&
Kristian Høgsbergf7e23d52012-04-27 17:51:59 -04002688 shsurf->type != shsurf->next_type) {
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04002689 set_surface_type(shsurf);
Kristian Høgsbergf7e23d52012-04-27 17:51:59 -04002690 type_changed = 1;
2691 }
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04002692
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03002693 if (!weston_surface_is_mapped(es)) {
2694 map(shell, es, es->buffer->width, es->buffer->height, sx, sy);
Kristian Høgsbergf7e23d52012-04-27 17:51:59 -04002695 } else if (type_changed || sx != 0 || sy != 0 ||
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03002696 es->geometry.width != es->buffer->width ||
2697 es->geometry.height != es->buffer->height) {
2698 GLfloat from_x, from_y;
2699 GLfloat to_x, to_y;
2700
2701 weston_surface_to_global_float(es, 0, 0, &from_x, &from_y);
2702 weston_surface_to_global_float(es, sx, sy, &to_x, &to_y);
2703 configure(shell, es,
2704 es->geometry.x + to_x - from_x,
2705 es->geometry.y + to_y - from_y,
2706 es->buffer->width, es->buffer->height);
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03002707 }
2708}
2709
Tiago Vignattibe143262012-04-16 17:31:41 +03002710static int launch_desktop_shell_process(struct desktop_shell *shell);
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02002711
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04002712static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002713desktop_shell_sigchld(struct weston_process *process, int status)
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02002714{
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02002715 uint32_t time;
Tiago Vignattibe143262012-04-16 17:31:41 +03002716 struct desktop_shell *shell =
2717 container_of(process, struct desktop_shell, child.process);
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02002718
2719 shell->child.process.pid = 0;
2720 shell->child.client = NULL; /* already destroyed by wayland */
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02002721
2722 /* if desktop-shell dies more than 5 times in 30 seconds, give up */
2723 time = weston_compositor_get_time();
Kristian Høgsbergf03a6162012-01-17 11:07:42 -05002724 if (time - shell->child.deathstamp > 30000) {
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02002725 shell->child.deathstamp = time;
2726 shell->child.deathcount = 0;
2727 }
2728
2729 shell->child.deathcount++;
2730 if (shell->child.deathcount > 5) {
Martin Minarik6d118362012-06-07 18:01:59 +02002731 weston_log("weston-desktop-shell died, giving up.\n");
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02002732 return;
2733 }
2734
Martin Minarik6d118362012-06-07 18:01:59 +02002735 weston_log("weston-desktop-shell died, respawning...\n");
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02002736 launch_desktop_shell_process(shell);
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02002737}
2738
2739static int
Tiago Vignattibe143262012-04-16 17:31:41 +03002740launch_desktop_shell_process(struct desktop_shell *shell)
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02002741{
Kristian Høgsberg9724b512012-01-03 14:35:49 -05002742 const char *shell_exe = LIBEXECDIR "/weston-desktop-shell";
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02002743
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002744 shell->child.client = weston_client_launch(shell->compositor,
Pekka Paalanen409ef0a2011-12-02 15:30:21 +02002745 &shell->child.process,
2746 shell_exe,
2747 desktop_shell_sigchld);
2748
2749 if (!shell->child.client)
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02002750 return -1;
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02002751 return 0;
2752}
2753
2754static void
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04002755bind_shell(struct wl_client *client, void *data, uint32_t version, uint32_t id)
2756{
Tiago Vignattibe143262012-04-16 17:31:41 +03002757 struct desktop_shell *shell = data;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04002758
2759 wl_client_add_object(client, &wl_shell_interface,
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002760 &shell_implementation, id, shell);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04002761}
2762
Kristian Høgsberg75840622011-09-06 13:48:16 -04002763static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002764unbind_desktop_shell(struct wl_resource *resource)
2765{
Tiago Vignattibe143262012-04-16 17:31:41 +03002766 struct desktop_shell *shell = resource->data;
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05002767
2768 if (shell->locked)
2769 resume_desktop(shell);
2770
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002771 shell->child.desktop_shell = NULL;
2772 shell->prepare_event_sent = false;
2773 free(resource);
2774}
2775
2776static void
Kristian Høgsberg75840622011-09-06 13:48:16 -04002777bind_desktop_shell(struct wl_client *client,
2778 void *data, uint32_t version, uint32_t id)
2779{
Tiago Vignattibe143262012-04-16 17:31:41 +03002780 struct desktop_shell *shell = data;
Pekka Paalanenbbe60522011-11-03 14:11:33 +02002781 struct wl_resource *resource;
Kristian Høgsberg75840622011-09-06 13:48:16 -04002782
Pekka Paalanenbbe60522011-11-03 14:11:33 +02002783 resource = wl_client_add_object(client, &desktop_shell_interface,
2784 &desktop_shell_implementation,
2785 id, shell);
2786
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002787 if (client == shell->child.client) {
2788 resource->destroy = unbind_desktop_shell;
2789 shell->child.desktop_shell = resource;
Pekka Paalanenbbe60522011-11-03 14:11:33 +02002790 return;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002791 }
Pekka Paalanenbbe60522011-11-03 14:11:33 +02002792
2793 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
2794 "permission to bind desktop_shell denied");
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04002795 wl_resource_destroy(resource);
Kristian Høgsberg75840622011-09-06 13:48:16 -04002796}
2797
Pekka Paalanen6e168112011-11-24 11:34:05 +02002798static void
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04002799screensaver_configure(struct weston_surface *surface, int32_t sx, int32_t sy)
2800{
2801 struct desktop_shell *shell = surface->private;
2802
2803 if (!shell->locked)
2804 return;
2805
2806 center_on_output(surface, surface->output);
2807
2808 if (wl_list_empty(&surface->layer_link)) {
2809 wl_list_insert(shell->lock_layer.surface_list.prev,
2810 &surface->layer_link);
2811 weston_surface_assign_output(surface);
2812 shell->compositor->idle_time = shell->screensaver.duration;
2813 weston_compositor_wake(shell->compositor);
2814 shell->compositor->state = WESTON_COMPOSITOR_IDLE;
2815 }
2816}
2817
2818static void
Pekka Paalanen6e168112011-11-24 11:34:05 +02002819screensaver_set_surface(struct wl_client *client,
2820 struct wl_resource *resource,
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04002821 struct wl_resource *surface_resource,
Pekka Paalanen6e168112011-11-24 11:34:05 +02002822 struct wl_resource *output_resource)
2823{
Tiago Vignattibe143262012-04-16 17:31:41 +03002824 struct desktop_shell *shell = resource->data;
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04002825 struct weston_surface *surface = surface_resource->data;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002826 struct weston_output *output = output_resource->data;
Pekka Paalanen6e168112011-11-24 11:34:05 +02002827
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04002828 surface->configure = screensaver_configure;
2829 surface->private = shell;
Pekka Paalanen77346a62011-11-30 16:26:35 +02002830 surface->output = output;
Pekka Paalanen6e168112011-11-24 11:34:05 +02002831}
2832
2833static const struct screensaver_interface screensaver_implementation = {
2834 screensaver_set_surface
2835};
2836
2837static void
2838unbind_screensaver(struct wl_resource *resource)
2839{
Tiago Vignattibe143262012-04-16 17:31:41 +03002840 struct desktop_shell *shell = resource->data;
Pekka Paalanen6e168112011-11-24 11:34:05 +02002841
Pekka Paalanen77346a62011-11-30 16:26:35 +02002842 shell->screensaver.binding = NULL;
Pekka Paalanen6e168112011-11-24 11:34:05 +02002843 free(resource);
2844}
2845
2846static void
2847bind_screensaver(struct wl_client *client,
2848 void *data, uint32_t version, uint32_t id)
2849{
Tiago Vignattibe143262012-04-16 17:31:41 +03002850 struct desktop_shell *shell = data;
Pekka Paalanen6e168112011-11-24 11:34:05 +02002851 struct wl_resource *resource;
2852
2853 resource = wl_client_add_object(client, &screensaver_interface,
2854 &screensaver_implementation,
2855 id, shell);
2856
Pekka Paalanen77346a62011-11-30 16:26:35 +02002857 if (shell->screensaver.binding == NULL) {
Pekka Paalanen6e168112011-11-24 11:34:05 +02002858 resource->destroy = unbind_screensaver;
Pekka Paalanen77346a62011-11-30 16:26:35 +02002859 shell->screensaver.binding = resource;
Pekka Paalanen6e168112011-11-24 11:34:05 +02002860 return;
2861 }
2862
2863 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
2864 "interface object already bound");
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04002865 wl_resource_destroy(resource);
Pekka Paalanen6e168112011-11-24 11:34:05 +02002866}
2867
Jan Arne Petersen42feced2012-06-21 21:52:17 +02002868static void
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04002869input_panel_configure(struct weston_surface *surface, int32_t sx, int32_t sy)
2870{
2871 struct weston_mode *mode = surface->output->current;
2872 GLfloat x = (mode->width - surface->buffer->width) / 2;
2873 GLfloat y = mode->height - surface->buffer->height;
2874
2875 /* Don't map the input panel here, wait for
2876 * show_input_panels signal. */
2877
2878 weston_surface_configure(surface,
2879 surface->output->x + x,
2880 surface->output->y + y,
2881 surface->buffer->width,
2882 surface->buffer->height);
2883}
2884
2885static void
Jan Arne Petersen42feced2012-06-21 21:52:17 +02002886input_panel_set_surface(struct wl_client *client,
2887 struct wl_resource *resource,
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04002888 struct wl_resource *surface_resource,
Jan Arne Petersen42feced2012-06-21 21:52:17 +02002889 struct wl_resource *output_resource)
2890{
2891 struct desktop_shell *shell = resource->data;
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04002892 struct weston_surface *surface = surface_resource->data;
Jan Arne Petersen42feced2012-06-21 21:52:17 +02002893 struct weston_output *output = output_resource->data;
2894
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04002895 surface->configure = input_panel_configure;
2896 surface->private = shell;
Jan Arne Petersen42feced2012-06-21 21:52:17 +02002897 surface->output = output;
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04002898 wl_list_insert(shell->input_panel.surfaces.prev, &surface->layer_link);
Jan Arne Petersen42feced2012-06-21 21:52:17 +02002899}
2900
2901static const struct input_panel_interface input_panel_implementation = {
2902 input_panel_set_surface
2903};
2904
2905static void
2906unbind_input_panel(struct wl_resource *resource)
2907{
2908 struct desktop_shell *shell = resource->data;
2909
2910 shell->input_panel.binding = NULL;
2911 free(resource);
2912}
2913
2914static void
2915bind_input_panel(struct wl_client *client,
2916 void *data, uint32_t version, uint32_t id)
2917{
2918 struct desktop_shell *shell = data;
2919 struct wl_resource *resource;
2920
2921 resource = wl_client_add_object(client, &input_panel_interface,
2922 &input_panel_implementation,
2923 id, shell);
2924
2925 if (shell->input_panel.binding == NULL) {
2926 resource->destroy = unbind_input_panel;
2927 shell->input_panel.binding = resource;
2928 return;
2929 }
2930
2931 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
2932 "interface object already bound");
2933 wl_resource_destroy(resource);
2934}
2935
Kristian Høgsberg07045392012-02-19 18:52:44 -05002936struct switcher {
Tiago Vignattibe143262012-04-16 17:31:41 +03002937 struct desktop_shell *shell;
Kristian Høgsberg07045392012-02-19 18:52:44 -05002938 struct weston_surface *current;
2939 struct wl_listener listener;
2940 struct wl_keyboard_grab grab;
2941};
2942
2943static void
2944switcher_next(struct switcher *switcher)
2945{
Kristian Høgsberg07045392012-02-19 18:52:44 -05002946 struct weston_surface *surface;
2947 struct weston_surface *first = NULL, *prev = NULL, *next = NULL;
Kristian Høgsberg32e56862012-04-02 22:18:58 -04002948 struct shell_surface *shsurf;
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04002949 struct workspace *ws = get_current_workspace(switcher->shell);
Kristian Høgsberg07045392012-02-19 18:52:44 -05002950
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04002951 wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
Kristian Høgsberg07045392012-02-19 18:52:44 -05002952 switch (get_shell_surface_type(surface)) {
2953 case SHELL_SURFACE_TOPLEVEL:
2954 case SHELL_SURFACE_FULLSCREEN:
2955 case SHELL_SURFACE_MAXIMIZED:
2956 if (first == NULL)
2957 first = surface;
2958 if (prev == switcher->current)
2959 next = surface;
2960 prev = surface;
Scott Moreau02709af2012-05-22 01:54:10 -06002961 surface->alpha = 0.25;
Kristian Høgsbergcacb7cd2012-02-28 09:20:21 -05002962 surface->geometry.dirty = 1;
Kristian Høgsberg07045392012-02-19 18:52:44 -05002963 weston_surface_damage(surface);
2964 break;
2965 default:
2966 break;
2967 }
Alex Wu1659daa2012-04-01 20:13:09 +08002968
2969 if (is_black_surface(surface, NULL)) {
Scott Moreau02709af2012-05-22 01:54:10 -06002970 surface->alpha = 0.25;
Alex Wu1659daa2012-04-01 20:13:09 +08002971 surface->geometry.dirty = 1;
2972 weston_surface_damage(surface);
2973 }
Kristian Høgsberg07045392012-02-19 18:52:44 -05002974 }
2975
2976 if (next == NULL)
2977 next = first;
2978
Alex Wu07b26062012-03-12 16:06:01 +08002979 if (next == NULL)
2980 return;
2981
Kristian Høgsberg07045392012-02-19 18:52:44 -05002982 wl_list_remove(&switcher->listener.link);
Kristian Høgsberg27e30522012-04-11 23:18:23 -04002983 wl_signal_add(&next->surface.resource.destroy_signal,
2984 &switcher->listener);
Kristian Høgsberg07045392012-02-19 18:52:44 -05002985
2986 switcher->current = next;
Kristian Høgsberga416fa12012-05-21 14:06:52 -04002987 next->alpha = 1.0;
Alex Wu1659daa2012-04-01 20:13:09 +08002988
Kristian Høgsberg32e56862012-04-02 22:18:58 -04002989 shsurf = get_shell_surface(switcher->current);
2990 if (shsurf && shsurf->type ==SHELL_SURFACE_FULLSCREEN)
Kristian Høgsberga416fa12012-05-21 14:06:52 -04002991 shsurf->fullscreen.black_surface->alpha = 1.0;
Kristian Høgsberg07045392012-02-19 18:52:44 -05002992}
2993
2994static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04002995switcher_handle_surface_destroy(struct wl_listener *listener, void *data)
Kristian Høgsberg07045392012-02-19 18:52:44 -05002996{
2997 struct switcher *switcher =
2998 container_of(listener, struct switcher, listener);
2999
3000 switcher_next(switcher);
3001}
3002
3003static void
Daniel Stone351eb612012-05-31 15:27:47 -04003004switcher_destroy(struct switcher *switcher)
Kristian Høgsberg07045392012-02-19 18:52:44 -05003005{
Kristian Høgsberg07045392012-02-19 18:52:44 -05003006 struct weston_surface *surface;
Daniel Stone37816df2012-05-16 18:45:18 +01003007 struct wl_keyboard *keyboard = switcher->grab.keyboard;
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04003008 struct workspace *ws = get_current_workspace(switcher->shell);
Kristian Høgsberg07045392012-02-19 18:52:44 -05003009
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04003010 wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
Kristian Høgsberga416fa12012-05-21 14:06:52 -04003011 surface->alpha = 1.0;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003012 weston_surface_damage(surface);
3013 }
3014
Alex Wu07b26062012-03-12 16:06:01 +08003015 if (switcher->current)
Daniel Stone37816df2012-05-16 18:45:18 +01003016 activate(switcher->shell, switcher->current,
3017 (struct weston_seat *) keyboard->seat);
Kristian Høgsberg07045392012-02-19 18:52:44 -05003018 wl_list_remove(&switcher->listener.link);
Daniel Stone37816df2012-05-16 18:45:18 +01003019 wl_keyboard_end_grab(keyboard);
Kristian Høgsberg07045392012-02-19 18:52:44 -05003020 free(switcher);
3021}
3022
3023static void
3024switcher_key(struct wl_keyboard_grab *grab,
Daniel Stonec9785ea2012-05-30 16:31:52 +01003025 uint32_t time, uint32_t key, uint32_t state_w)
Kristian Høgsberg07045392012-02-19 18:52:44 -05003026{
3027 struct switcher *switcher = container_of(grab, struct switcher, grab);
Daniel Stonec9785ea2012-05-30 16:31:52 +01003028 enum wl_keyboard_key_state state = state_w;
Daniel Stone351eb612012-05-31 15:27:47 -04003029
Daniel Stonec9785ea2012-05-30 16:31:52 +01003030 if (key == KEY_TAB && state == WL_KEYBOARD_KEY_STATE_PRESSED)
Daniel Stone351eb612012-05-31 15:27:47 -04003031 switcher_next(switcher);
3032}
3033
3034static void
3035switcher_modifier(struct wl_keyboard_grab *grab, uint32_t serial,
3036 uint32_t mods_depressed, uint32_t mods_latched,
3037 uint32_t mods_locked, uint32_t group)
3038{
3039 struct switcher *switcher = container_of(grab, struct switcher, grab);
Daniel Stone37816df2012-05-16 18:45:18 +01003040 struct weston_seat *seat = (struct weston_seat *) grab->keyboard->seat;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003041
Daniel Stone351eb612012-05-31 15:27:47 -04003042 if ((seat->modifier_state & switcher->shell->binding_modifier) == 0)
3043 switcher_destroy(switcher);
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04003044}
Kristian Høgsberg07045392012-02-19 18:52:44 -05003045
3046static const struct wl_keyboard_grab_interface switcher_grab = {
Daniel Stone351eb612012-05-31 15:27:47 -04003047 switcher_key,
3048 switcher_modifier,
Kristian Høgsberg07045392012-02-19 18:52:44 -05003049};
3050
3051static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01003052switcher_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
3053 void *data)
Kristian Høgsberg07045392012-02-19 18:52:44 -05003054{
Tiago Vignattibe143262012-04-16 17:31:41 +03003055 struct desktop_shell *shell = data;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003056 struct switcher *switcher;
3057
3058 switcher = malloc(sizeof *switcher);
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04003059 switcher->shell = shell;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003060 switcher->current = NULL;
Kristian Høgsberg27e30522012-04-11 23:18:23 -04003061 switcher->listener.notify = switcher_handle_surface_destroy;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003062 wl_list_init(&switcher->listener.link);
3063
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04003064 lower_fullscreen_layer(switcher->shell);
Kristian Høgsberg07045392012-02-19 18:52:44 -05003065 switcher->grab.interface = &switcher_grab;
Daniel Stone37816df2012-05-16 18:45:18 +01003066 wl_keyboard_start_grab(seat->keyboard, &switcher->grab);
3067 wl_keyboard_set_focus(seat->keyboard, NULL);
Kristian Høgsberg07045392012-02-19 18:52:44 -05003068 switcher_next(switcher);
3069}
3070
Pekka Paalanen3c647232011-12-22 13:43:43 +02003071static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01003072backlight_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
3073 void *data)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003074{
3075 struct weston_compositor *compositor = data;
3076 struct weston_output *output;
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03003077 long backlight_new = 0;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003078
3079 /* TODO: we're limiting to simple use cases, where we assume just
3080 * control on the primary display. We'd have to extend later if we
3081 * ever get support for setting backlights on random desktop LCD
3082 * panels though */
3083 output = get_default_output(compositor);
3084 if (!output)
3085 return;
3086
3087 if (!output->set_backlight)
3088 return;
3089
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03003090 if (key == KEY_F9 || key == KEY_BRIGHTNESSDOWN)
3091 backlight_new = output->backlight_current - 25;
3092 else if (key == KEY_F10 || key == KEY_BRIGHTNESSUP)
3093 backlight_new = output->backlight_current + 25;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003094
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03003095 if (backlight_new < 5)
3096 backlight_new = 5;
3097 if (backlight_new > 255)
3098 backlight_new = 255;
3099
3100 output->backlight_current = backlight_new;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003101 output->set_backlight(output, output->backlight_current);
3102}
3103
3104static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01003105debug_repaint_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
3106 void *data)
Kristian Høgsbergb41c0812012-03-04 14:53:40 -05003107{
Tiago Vignattibe143262012-04-16 17:31:41 +03003108 struct desktop_shell *shell = data;
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04003109 struct weston_compositor *compositor = shell->compositor;
Kristian Høgsbergb41c0812012-03-04 14:53:40 -05003110 struct weston_surface *surface;
3111
3112 if (shell->debug_repaint_surface) {
3113 weston_surface_destroy(shell->debug_repaint_surface);
3114 shell->debug_repaint_surface = NULL;
3115 } else {
3116 surface = weston_surface_create(compositor);
3117 weston_surface_set_color(surface, 1.0, 0.0, 0.0, 0.2);
3118 weston_surface_configure(surface, 0, 0, 8192, 8192);
3119 wl_list_insert(&compositor->fade_layer.surface_list,
3120 &surface->layer_link);
3121 weston_surface_assign_output(surface);
3122 pixman_region32_init(&surface->input);
3123
3124 /* Here's the dirty little trick that makes the
3125 * repaint debugging work: we force an
3126 * update_transform first to update dependent state
3127 * and clear the geometry.dirty bit. Then we clear
3128 * the surface damage so it only gets repainted
3129 * piecewise as we repaint other things. */
3130
3131 weston_surface_update_transform(surface);
3132 pixman_region32_fini(&surface->damage);
3133 pixman_region32_init(&surface->damage);
3134 shell->debug_repaint_surface = surface;
3135 }
3136}
3137
3138static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01003139force_kill_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
3140 void *data)
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04003141{
3142 struct wl_client *client;
3143 pid_t pid;
3144 uid_t uid;
3145 gid_t gid;
3146
Daniel Stone325fc2d2012-05-30 16:31:58 +01003147 client = seat->keyboard->focus->resource.client;
3148 wl_client_get_credentials(client, &pid, &uid, &gid);
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04003149
Daniel Stone325fc2d2012-05-30 16:31:58 +01003150 kill(pid, SIGKILL);
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04003151}
3152
3153static void
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003154workspace_up_binding(struct wl_seat *seat, uint32_t time,
3155 uint32_t key, void *data)
3156{
3157 struct desktop_shell *shell = data;
3158 unsigned int new_index = shell->workspaces.current;
3159
Kristian Høgsbergce345b02012-06-25 21:35:29 -04003160 if (shell->locked)
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04003161 return;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003162 if (new_index != 0)
3163 new_index--;
3164
3165 change_workspace(shell, new_index);
3166}
3167
3168static void
3169workspace_down_binding(struct wl_seat *seat, uint32_t time,
3170 uint32_t key, void *data)
3171{
3172 struct desktop_shell *shell = data;
3173 unsigned int new_index = shell->workspaces.current;
3174
Kristian Høgsbergce345b02012-06-25 21:35:29 -04003175 if (shell->locked)
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04003176 return;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003177 if (new_index < shell->workspaces.num - 1)
3178 new_index++;
3179
3180 change_workspace(shell, new_index);
3181}
3182
3183static void
3184workspace_f_binding(struct wl_seat *seat, uint32_t time,
3185 uint32_t key, void *data)
3186{
3187 struct desktop_shell *shell = data;
3188 unsigned int new_index;
3189
Kristian Høgsbergce345b02012-06-25 21:35:29 -04003190 if (shell->locked)
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04003191 return;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003192 new_index = key - KEY_F1;
3193 if (new_index >= shell->workspaces.num)
3194 new_index = shell->workspaces.num - 1;
3195
3196 change_workspace(shell, new_index);
3197}
3198
3199
3200static void
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04003201shell_destroy(struct wl_listener *listener, void *data)
Pekka Paalanen3c647232011-12-22 13:43:43 +02003202{
Tiago Vignattibe143262012-04-16 17:31:41 +03003203 struct desktop_shell *shell =
3204 container_of(listener, struct desktop_shell, destroy_listener);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003205 struct workspace **ws;
Pekka Paalanen3c647232011-12-22 13:43:43 +02003206
Pekka Paalanen9cf5cc82012-01-02 16:00:24 +02003207 if (shell->child.client)
3208 wl_client_destroy(shell->child.client);
3209
Kristian Høgsberg88c16072012-05-16 08:04:19 -04003210 wl_list_remove(&shell->lock_listener.link);
3211 wl_list_remove(&shell->unlock_listener.link);
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003212 wl_list_remove(&shell->show_input_panel_listener.link);
3213 wl_list_remove(&shell->hide_input_panel_listener.link);
Kristian Høgsberg88c16072012-05-16 08:04:19 -04003214
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003215 wl_array_for_each(ws, &shell->workspaces.array)
3216 workspace_destroy(*ws);
3217 wl_array_release(&shell->workspaces.array);
3218
Pekka Paalanen3c647232011-12-22 13:43:43 +02003219 free(shell->screensaver.path);
3220 free(shell);
3221}
3222
Tiago Vignatti0b52d482012-04-20 18:54:25 +03003223static void
3224shell_add_bindings(struct weston_compositor *ec, struct desktop_shell *shell)
3225{
3226 uint32_t mod;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003227 int i, num_workspace_bindings;
Tiago Vignatti0b52d482012-04-20 18:54:25 +03003228
3229 /* fixed bindings */
Daniel Stone325fc2d2012-05-30 16:31:58 +01003230 weston_compositor_add_key_binding(ec, KEY_BACKSPACE,
3231 MODIFIER_CTRL | MODIFIER_ALT,
3232 terminate_binding, ec);
3233 weston_compositor_add_button_binding(ec, BTN_LEFT, 0,
3234 click_to_activate_binding,
3235 shell);
3236 weston_compositor_add_axis_binding(ec, WL_POINTER_AXIS_VERTICAL_SCROLL,
3237 MODIFIER_SUPER | MODIFIER_ALT,
3238 surface_opacity_binding, NULL);
3239 weston_compositor_add_axis_binding(ec, WL_POINTER_AXIS_VERTICAL_SCROLL,
3240 MODIFIER_SUPER, zoom_axis_binding,
3241 NULL);
Tiago Vignatti0b52d482012-04-20 18:54:25 +03003242
3243 /* configurable bindings */
3244 mod = shell->binding_modifier;
Daniel Stone325fc2d2012-05-30 16:31:58 +01003245 weston_compositor_add_key_binding(ec, KEY_PAGEUP, mod,
3246 zoom_key_binding, NULL);
3247 weston_compositor_add_key_binding(ec, KEY_PAGEDOWN, mod,
3248 zoom_key_binding, NULL);
3249 weston_compositor_add_button_binding(ec, BTN_LEFT, mod, move_binding,
3250 shell);
3251 weston_compositor_add_button_binding(ec, BTN_MIDDLE, mod,
3252 resize_binding, shell);
3253 weston_compositor_add_button_binding(ec, BTN_RIGHT, mod,
3254 rotate_binding, NULL);
3255 weston_compositor_add_key_binding(ec, KEY_TAB, mod, switcher_binding,
3256 shell);
3257 weston_compositor_add_key_binding(ec, KEY_F9, mod, backlight_binding,
3258 ec);
3259 weston_compositor_add_key_binding(ec, KEY_BRIGHTNESSDOWN, 0,
3260 backlight_binding, ec);
3261 weston_compositor_add_key_binding(ec, KEY_F10, mod, backlight_binding,
3262 ec);
3263 weston_compositor_add_key_binding(ec, KEY_BRIGHTNESSUP, 0,
3264 backlight_binding, ec);
Kristian Høgsberg73694c82012-06-28 14:13:10 -04003265 weston_compositor_add_key_binding(ec, KEY_SPACE, mod | MODIFIER_SHIFT,
Daniel Stone325fc2d2012-05-30 16:31:58 +01003266 debug_repaint_binding, shell);
3267 weston_compositor_add_key_binding(ec, KEY_K, mod,
3268 force_kill_binding, shell);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003269 weston_compositor_add_key_binding(ec, KEY_UP, mod,
3270 workspace_up_binding, shell);
3271 weston_compositor_add_key_binding(ec, KEY_DOWN, mod,
3272 workspace_down_binding, shell);
3273
3274 /* Add bindings for mod+F[1-6] for workspace 1 to 6. */
3275 if (shell->workspaces.num > 1) {
3276 num_workspace_bindings = shell->workspaces.num;
3277 if (num_workspace_bindings > 6)
3278 num_workspace_bindings = 6;
3279 for (i = 0; i < num_workspace_bindings; i++)
3280 weston_compositor_add_key_binding(ec, KEY_F1 + i, mod,
3281 workspace_f_binding,
3282 shell);
3283 }
Tiago Vignatti0b52d482012-04-20 18:54:25 +03003284}
3285
Kristian Høgsberg6c709a32011-05-06 14:52:41 -04003286int
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05003287shell_init(struct weston_compositor *ec);
Kristian Høgsberg6c709a32011-05-06 14:52:41 -04003288
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003289WL_EXPORT int
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05003290shell_init(struct weston_compositor *ec)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05003291{
Tiago Vignattibe143262012-04-16 17:31:41 +03003292 struct desktop_shell *shell;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003293 struct workspace **pws;
3294 unsigned int i;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04003295
3296 shell = malloc(sizeof *shell);
3297 if (shell == NULL)
3298 return -1;
3299
Kristian Høgsbergf0d91162011-10-11 22:44:23 -04003300 memset(shell, 0, sizeof *shell);
Kristian Høgsberg75840622011-09-06 13:48:16 -04003301 shell->compositor = ec;
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04003302
3303 shell->destroy_listener.notify = shell_destroy;
3304 wl_signal_add(&ec->destroy_signal, &shell->destroy_listener);
3305 shell->lock_listener.notify = lock;
3306 wl_signal_add(&ec->lock_signal, &shell->lock_listener);
3307 shell->unlock_listener.notify = unlock;
3308 wl_signal_add(&ec->unlock_signal, &shell->unlock_listener);
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003309 shell->show_input_panel_listener.notify = show_input_panels;
3310 wl_signal_add(&ec->show_input_panel_signal, &shell->show_input_panel_listener);
3311 shell->hide_input_panel_listener.notify = hide_input_panels;
3312 wl_signal_add(&ec->hide_input_panel_signal, &shell->hide_input_panel_listener);
Scott Moreauff1db4a2012-04-17 19:06:18 -06003313 ec->ping_handler = ping_handler;
Kristian Høgsberg82a1d112012-07-19 14:02:00 -04003314 ec->shell_interface.shell = shell;
Tiago Vignattibc052c92012-04-19 16:18:18 +03003315 ec->shell_interface.create_shell_surface = create_shell_surface;
3316 ec->shell_interface.set_toplevel = set_toplevel;
Tiago Vignatti491bac12012-05-18 16:37:43 -04003317 ec->shell_interface.set_transient = set_transient;
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04003318 ec->shell_interface.move = surface_move;
Kristian Høgsbergc1693f22012-05-22 16:56:23 -04003319 ec->shell_interface.resize = surface_resize;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05003320
Pekka Paalanen77346a62011-11-30 16:26:35 +02003321 wl_list_init(&shell->screensaver.surfaces);
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003322 wl_list_init(&shell->input_panel.surfaces);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02003323
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05003324 weston_layer_init(&shell->fullscreen_layer, &ec->cursor_layer.link);
3325 weston_layer_init(&shell->panel_layer, &shell->fullscreen_layer.link);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003326 weston_layer_init(&shell->background_layer, &shell->panel_layer.link);
3327 weston_layer_init(&shell->lock_layer, NULL);
3328
3329 wl_array_init(&shell->workspaces.array);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05003330
Kristian Høgsberg6af8eb92012-01-25 16:57:11 -05003331 shell_configuration(shell);
Pekka Paalanene955f1e2011-12-07 11:49:52 +02003332
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003333 for (i = 0; i < shell->workspaces.num; i++) {
3334 pws = wl_array_add(&shell->workspaces.array, sizeof *pws);
3335 if (pws == NULL)
3336 return -1;
3337
3338 *pws = workspace_create();
3339 if (*pws == NULL)
3340 return -1;
3341 }
3342 activate_workspace(shell, 0);
3343
Jonas Ådahl62fcd042012-06-13 00:01:23 +02003344 wl_list_init(&shell->workspaces.animation.link);
3345 shell->workspaces.animation.frame = animate_workspace_change_frame;
3346
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04003347 if (wl_display_add_global(ec->wl_display, &wl_shell_interface,
3348 shell, bind_shell) == NULL)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05003349 return -1;
3350
Kristian Høgsberg75840622011-09-06 13:48:16 -04003351 if (wl_display_add_global(ec->wl_display,
3352 &desktop_shell_interface,
3353 shell, bind_desktop_shell) == NULL)
3354 return -1;
3355
Pekka Paalanen6e168112011-11-24 11:34:05 +02003356 if (wl_display_add_global(ec->wl_display, &screensaver_interface,
3357 shell, bind_screensaver) == NULL)
3358 return -1;
3359
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003360 if (wl_display_add_global(ec->wl_display, &input_panel_interface,
3361 shell, bind_input_panel) == NULL)
3362 return -1;
3363
Kristian Høgsbergf03a6162012-01-17 11:07:42 -05003364 shell->child.deathstamp = weston_compositor_get_time();
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02003365 if (launch_desktop_shell_process(shell) != 0)
3366 return -1;
3367
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04003368 shell->pointer_focus_listener.notify = handle_pointer_focus;
Pekka Paalanen43e1ba82012-06-07 15:07:06 +03003369 if (ec->seat->seat.pointer)
3370 wl_signal_add(&ec->seat->seat.pointer->focus_signal,
3371 &shell->pointer_focus_listener);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04003372
Tiago Vignatti0b52d482012-04-20 18:54:25 +03003373 shell_add_bindings(ec, shell);
Kristian Høgsberg07937562011-04-12 17:25:42 -04003374
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05003375 return 0;
3376}