blob: f995f03d95e38ff92e8d39929849520a9d54a87d [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;
53 struct weston_surface *keyboard_focus;
54 struct wl_list link;
55 struct wl_listener seat_destroy_listener;
56 struct wl_listener surface_destroy_listener;
57};
58
Jonas Ådahle3cddce2012-06-13 00:01:22 +020059struct workspace {
60 struct weston_layer layer;
Jonas Ådahl04769742012-06-13 00:01:24 +020061
62 struct wl_list focus_list;
63 struct wl_listener seat_destroyed_listener;
Jonas Ådahle3cddce2012-06-13 00:01:22 +020064};
65
Tiago Vignattibe143262012-04-16 17:31:41 +030066struct desktop_shell {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050067 struct weston_compositor *compositor;
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -040068
69 struct wl_listener lock_listener;
70 struct wl_listener unlock_listener;
71 struct wl_listener destroy_listener;
Jan Arne Petersen42feced2012-06-21 21:52:17 +020072 struct wl_listener show_input_panel_listener;
73 struct wl_listener hide_input_panel_listener;
Pekka Paalanen6cd281a2011-11-03 14:11:32 +020074
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -050075 struct weston_layer fullscreen_layer;
76 struct weston_layer panel_layer;
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -050077 struct weston_layer background_layer;
78 struct weston_layer lock_layer;
79
Kristian Høgsbergd56bd902012-06-05 09:58:51 -040080 struct wl_listener pointer_focus_listener;
81 struct weston_surface *busy_surface;
82
Pekka Paalanen6cd281a2011-11-03 14:11:32 +020083 struct {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050084 struct weston_process process;
Pekka Paalanen6cd281a2011-11-03 14:11:32 +020085 struct wl_client *client;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +020086 struct wl_resource *desktop_shell;
Pekka Paalanen4d733ee2012-01-17 14:36:27 +020087
88 unsigned deathcount;
89 uint32_t deathstamp;
Pekka Paalanen6cd281a2011-11-03 14:11:32 +020090 } child;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +020091
92 bool locked;
93 bool prepare_event_sent;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +020094
Pekka Paalanen068ae942011-11-28 14:11:15 +020095 struct shell_surface *lock_surface;
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -050096 struct wl_listener lock_surface_listener;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +010097
Pekka Paalanen77346a62011-11-30 16:26:35 +020098 struct {
Jonas Ådahle3cddce2012-06-13 00:01:22 +020099 struct wl_array array;
100 unsigned int current;
101 unsigned int num;
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200102
103 struct weston_animation animation;
104 int anim_dir;
105 uint32_t anim_timestamp;
106 double anim_current;
107 struct workspace *anim_from;
108 struct workspace *anim_to;
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200109 } workspaces;
110
111 struct {
Pekka Paalanen3c647232011-12-22 13:43:43 +0200112 char *path;
Pekka Paalanen7296e792011-12-07 16:22:00 +0200113 int duration;
Pekka Paalanen77346a62011-11-30 16:26:35 +0200114 struct wl_resource *binding;
115 struct wl_list surfaces;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500116 struct weston_process process;
Pekka Paalanen77346a62011-11-30 16:26:35 +0200117 } screensaver;
Kristian Høgsbergb41c0812012-03-04 14:53:40 -0500118
Jan Arne Petersen42feced2012-06-21 21:52:17 +0200119 struct {
120 struct wl_resource *binding;
121 struct wl_list surfaces;
122 } input_panel;
123
Tiago Vignatti0b52d482012-04-20 18:54:25 +0300124 uint32_t binding_modifier;
Juan Zhaoe10d2792012-04-25 19:09:52 +0800125 enum animation_type win_animation_type;
Kristian Høgsbergb41c0812012-03-04 14:53:40 -0500126 struct weston_surface *debug_repaint_surface;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400127};
128
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500129enum shell_surface_type {
Pekka Paalanen98262232011-12-01 10:42:22 +0200130 SHELL_SURFACE_NONE,
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500131
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200132 SHELL_SURFACE_LOCK,
Pekka Paalanen77346a62011-11-30 16:26:35 +0200133 SHELL_SURFACE_SCREENSAVER,
Jan Arne Petersen42feced2012-06-21 21:52:17 +0200134 SHELL_SURFACE_INPUT_PANEL,
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500135
136 SHELL_SURFACE_TOPLEVEL,
137 SHELL_SURFACE_TRANSIENT,
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500138 SHELL_SURFACE_FULLSCREEN,
Juan Zhao96879df2012-02-07 08:45:41 +0800139 SHELL_SURFACE_MAXIMIZED,
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500140 SHELL_SURFACE_POPUP
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200141};
142
Scott Moreauff1db4a2012-04-17 19:06:18 -0600143struct ping_timer {
144 struct wl_event_source *source;
Scott Moreauff1db4a2012-04-17 19:06:18 -0600145 uint32_t serial;
146};
147
Pekka Paalanen56cdea92011-11-23 16:14:12 +0200148struct shell_surface {
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200149 struct wl_resource resource;
150
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500151 struct weston_surface *surface;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200152 struct wl_listener surface_destroy_listener;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500153 struct shell_surface *parent;
Tiago Vignattibe143262012-04-16 17:31:41 +0300154 struct desktop_shell *shell;
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200155
Kristian Høgsberg7f366e72012-04-27 17:20:01 -0400156 enum shell_surface_type type, next_type;
Kristian Høgsberge7afd912012-05-02 09:47:44 -0400157 char *title, *class;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500158 int32_t saved_x, saved_y;
Alex Wu4539b082012-03-01 12:57:46 +0800159 bool saved_position_valid;
Alex Wu7bcb8bd2012-04-27 09:07:24 +0800160 bool saved_rotation_valid;
Scott Moreauff1db4a2012-04-17 19:06:18 -0600161 int unresponsive;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100162
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500163 struct {
Pekka Paalanen460099f2012-01-20 16:48:25 +0200164 struct weston_transform transform;
Kristian Høgsberg765e27b2012-01-27 13:36:13 -0500165 struct weston_matrix rotation;
Pekka Paalanen460099f2012-01-20 16:48:25 +0200166 } rotation;
167
168 struct {
Scott Moreau447013d2012-02-18 05:05:29 -0700169 struct wl_pointer_grab grab;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500170 int32_t x, y;
Pekka Paalanen938269a2012-02-07 14:19:01 +0200171 struct weston_transform parent_transform;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500172 int32_t initial_up;
Daniel Stone37816df2012-05-16 18:45:18 +0100173 struct wl_seat *seat;
Kristian Høgsberg3730f362012-04-13 12:40:07 -0400174 uint32_t serial;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500175 } popup;
176
Alex Wu4539b082012-03-01 12:57:46 +0800177 struct {
Tiago Vignatti52e598c2012-05-07 15:23:08 +0300178 int32_t x, y;
Tiago Vignatti491bac12012-05-18 16:37:43 -0400179 uint32_t flags;
Tiago Vignatti52e598c2012-05-07 15:23:08 +0300180 } transient;
181
182 struct {
Alex Wu4539b082012-03-01 12:57:46 +0800183 enum wl_shell_surface_fullscreen_method type;
184 struct weston_transform transform; /* matrix from x, y */
185 uint32_t framerate;
186 struct weston_surface *black_surface;
187 } fullscreen;
188
Scott Moreauff1db4a2012-04-17 19:06:18 -0600189 struct ping_timer *ping_timer;
190
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200191 struct weston_transform workspace_transform;
192
Jonas Ådahl04769742012-06-13 00:01:24 +0200193 struct focus_state *focus_state;
194
Kristian Høgsberg1cbf3262012-02-17 23:49:07 -0500195 struct weston_output *fullscreen_output;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500196 struct weston_output *output;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100197 struct wl_list link;
Kristian Høgsberga61ca062012-05-22 16:05:52 -0400198
199 const struct weston_shell_client *client;
Pekka Paalanen56cdea92011-11-23 16:14:12 +0200200};
201
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300202struct shell_grab {
Scott Moreau447013d2012-02-18 05:05:29 -0700203 struct wl_pointer_grab grab;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300204 struct shell_surface *shsurf;
205 struct wl_listener shsurf_destroy_listener;
206};
207
208struct weston_move_grab {
209 struct shell_grab base;
Daniel Stone103db7f2012-05-08 17:17:55 +0100210 wl_fixed_t dx, dy;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500211};
212
Pekka Paalanen460099f2012-01-20 16:48:25 +0200213struct rotate_grab {
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300214 struct shell_grab base;
Kristian Høgsberg765e27b2012-01-27 13:36:13 -0500215 struct weston_matrix rotation;
Pekka Paalanen460099f2012-01-20 16:48:25 +0200216 struct {
Kristian Høgsbergb2af93e2012-06-07 20:10:23 -0400217 GLfloat x;
218 GLfloat y;
Pekka Paalanen460099f2012-01-20 16:48:25 +0200219 } center;
220};
221
Alex Wubd3354b2012-04-17 17:20:49 +0800222static struct shell_surface *
223get_shell_surface(struct weston_surface *surface);
224
225static struct desktop_shell *
226shell_surface_get_shell(struct shell_surface *shsurf);
227
228static bool
229shell_surface_is_top_fullscreen(struct shell_surface *shsurf)
230{
231 struct desktop_shell *shell;
232 struct weston_surface *top_fs_es;
233
234 shell = shell_surface_get_shell(shsurf);
235
236 if (wl_list_empty(&shell->fullscreen_layer.surface_list))
237 return false;
238
239 top_fs_es = container_of(shell->fullscreen_layer.surface_list.next,
240 struct weston_surface,
241 layer_link);
242 return (shsurf == get_shell_surface(top_fs_es));
243}
244
Kristian Høgsberg6af8eb92012-01-25 16:57:11 -0500245static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400246destroy_shell_grab_shsurf(struct wl_listener *listener, void *data)
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300247{
248 struct shell_grab *grab;
249
250 grab = container_of(listener, struct shell_grab,
251 shsurf_destroy_listener);
252
253 grab->shsurf = NULL;
254}
255
256static void
257shell_grab_init(struct shell_grab *grab,
258 const struct wl_pointer_grab_interface *interface,
259 struct shell_surface *shsurf)
260{
261 grab->grab.interface = interface;
262 grab->shsurf = shsurf;
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400263 grab->shsurf_destroy_listener.notify = destroy_shell_grab_shsurf;
264 wl_signal_add(&shsurf->resource.destroy_signal,
265 &grab->shsurf_destroy_listener);
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300266
267}
268
269static void
270shell_grab_finish(struct shell_grab *grab)
271{
Kristian Høgsberg47b5dca2012-06-07 18:08:04 -0400272 if (grab->shsurf)
273 wl_list_remove(&grab->shsurf_destroy_listener.link);
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300274}
275
276static void
Alex Wu4539b082012-03-01 12:57:46 +0800277center_on_output(struct weston_surface *surface,
278 struct weston_output *output);
279
Daniel Stone496ca172012-05-30 16:31:42 +0100280static enum weston_keyboard_modifier
Tiago Vignatti0b52d482012-04-20 18:54:25 +0300281get_modifier(char *modifier)
282{
283 if (!modifier)
284 return MODIFIER_SUPER;
285
286 if (!strcmp("ctrl", modifier))
287 return MODIFIER_CTRL;
288 else if (!strcmp("alt", modifier))
289 return MODIFIER_ALT;
290 else if (!strcmp("super", modifier))
291 return MODIFIER_SUPER;
292 else
293 return MODIFIER_SUPER;
294}
295
Juan Zhaoe10d2792012-04-25 19:09:52 +0800296static enum animation_type
297get_animation_type(char *animation)
298{
299 if (!animation)
300 return ANIMATION_NONE;
301
302 if (!strcmp("zoom", animation))
303 return ANIMATION_ZOOM;
304 else if (!strcmp("fade", animation))
305 return ANIMATION_FADE;
306 else
307 return ANIMATION_NONE;
308}
309
Alex Wu4539b082012-03-01 12:57:46 +0800310static void
Tiago Vignattibe143262012-04-16 17:31:41 +0300311shell_configuration(struct desktop_shell *shell)
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200312{
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200313 char *config_file;
Pekka Paalanen7296e792011-12-07 16:22:00 +0200314 char *path = NULL;
315 int duration = 60;
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200316 unsigned int num_workspaces = DEFAULT_NUM_WORKSPACES;
Tiago Vignatti0b52d482012-04-20 18:54:25 +0300317 char *modifier = NULL;
Juan Zhaoe10d2792012-04-25 19:09:52 +0800318 char *win_animation = NULL;
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200319
Kristian Høgsberga4e8b332012-04-20 16:48:21 -0400320 struct config_key shell_keys[] = {
Tiago Vignatti0b52d482012-04-20 18:54:25 +0300321 { "binding-modifier", CONFIG_KEY_STRING, &modifier },
Juan Zhaoe10d2792012-04-25 19:09:52 +0800322 { "animation", CONFIG_KEY_STRING, &win_animation},
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200323 { "num-workspaces",
324 CONFIG_KEY_UNSIGNED_INTEGER, &num_workspaces },
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200325 };
326
Kristian Høgsberga4e8b332012-04-20 16:48:21 -0400327 struct config_key saver_keys[] = {
328 { "path", CONFIG_KEY_STRING, &path },
329 { "duration", CONFIG_KEY_INTEGER, &duration },
330 };
331
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200332 struct config_section cs[] = {
Kristian Høgsberga4e8b332012-04-20 16:48:21 -0400333 { "shell", shell_keys, ARRAY_LENGTH(shell_keys), NULL },
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200334 { "screensaver", saver_keys, ARRAY_LENGTH(saver_keys), NULL },
335 };
336
Tiago Vignatti9a206c42012-03-21 19:49:18 +0200337 config_file = config_file_path("weston.ini");
Kristian Høgsberg6af8eb92012-01-25 16:57:11 -0500338 parse_config_file(config_file, cs, ARRAY_LENGTH(cs), shell);
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200339 free(config_file);
340
Pekka Paalanen7296e792011-12-07 16:22:00 +0200341 shell->screensaver.path = path;
342 shell->screensaver.duration = duration;
Tiago Vignatti0b52d482012-04-20 18:54:25 +0300343 shell->binding_modifier = get_modifier(modifier);
Juan Zhaoe10d2792012-04-25 19:09:52 +0800344 shell->win_animation_type = get_animation_type(win_animation);
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200345 shell->workspaces.num = num_workspaces > 0 ? num_workspaces : 1;
346}
347
348static void
Jonas Ådahl04769742012-06-13 00:01:24 +0200349focus_state_destroy(struct focus_state *state)
350{
351 wl_list_remove(&state->seat_destroy_listener.link);
352 wl_list_remove(&state->surface_destroy_listener.link);
353 free(state);
354}
355
356static void
357focus_state_seat_destroy(struct wl_listener *listener, void *data)
358{
359 struct focus_state *state = container_of(listener,
360 struct focus_state,
361 seat_destroy_listener);
362
363 wl_list_remove(&state->link);
364 focus_state_destroy(state);
365}
366
367static void
368focus_state_surface_destroy(struct wl_listener *listener, void *data)
369{
370 struct focus_state *state = container_of(listener,
371 struct focus_state,
372 seat_destroy_listener);
373
374 wl_list_remove(&state->link);
375 focus_state_destroy(state);
376}
377
378static struct focus_state *
379focus_state_create(struct weston_seat *seat)
380{
381 struct wl_keyboard *keyboard = seat->seat.keyboard;
382 struct focus_state *state;
383 struct wl_surface *surface;
384 struct shell_surface *shsurf;
385
386 state = malloc(sizeof *state);
387 if (state == NULL)
388 return NULL;
389
390 surface = keyboard->focus;
391 shsurf = get_shell_surface((struct weston_surface *)keyboard->focus);
392 shsurf->focus_state = state;
393
394 state->seat = seat;
395 state->keyboard_focus = shsurf->surface;
396 wl_list_init(&state->link);
397
398 state->seat_destroy_listener.notify = focus_state_seat_destroy;
399 state->surface_destroy_listener.notify = focus_state_surface_destroy;
400 wl_signal_add(&seat->seat.destroy_signal,
401 &state->seat_destroy_listener);
402 wl_signal_add(&surface->resource.destroy_signal,
403 &state->surface_destroy_listener);
404
405 return state;
406}
407
408static void
409pop_focus_state(struct desktop_shell *shell, struct workspace *ws)
410{
411 struct focus_state *state, *next;
412
413 wl_list_for_each_safe(state, next, &ws->focus_list, link) {
414 if (state->keyboard_focus)
415 wl_keyboard_set_focus(state->seat->seat.keyboard,
416 &state->keyboard_focus->surface);
417
418 focus_state_destroy(state);
419 }
420 wl_list_init(&ws->focus_list);
421}
422
423static void
424push_focus_state(struct desktop_shell *shell, struct workspace *ws)
425{
426 struct weston_seat *seat;
427 struct focus_state *state;
428 struct wl_keyboard *keyboard;
429
430 wl_list_for_each(seat, &shell->compositor->seat_list, link) {
431 keyboard = seat->seat.keyboard;
432 if (keyboard && keyboard->focus) {
433 state = focus_state_create(seat);
434 if (state == NULL)
435 return;
436
437 wl_list_insert(&ws->focus_list, &state->link);
438
439 wl_keyboard_set_focus(seat->seat.keyboard, NULL);
440 }
441 }
442}
443
444static void
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200445workspace_destroy(struct workspace *ws)
446{
Jonas Ådahl04769742012-06-13 00:01:24 +0200447 struct focus_state *state, *next;
448
449 wl_list_for_each_safe(state, next, &ws->focus_list, link)
450 focus_state_destroy(state);
451
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200452 free(ws);
453}
454
Jonas Ådahl04769742012-06-13 00:01:24 +0200455static void
456seat_destroyed(struct wl_listener *listener, void *data)
457{
458 struct weston_seat *seat = data;
459 struct focus_state *state, *next;
460 struct workspace *ws = container_of(listener,
461 struct workspace,
462 seat_destroyed_listener);
463
464 wl_list_for_each_safe(state, next, &ws->focus_list, link)
465 if (state->seat == seat)
466 wl_list_remove(&state->link);
467}
468
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200469static struct workspace *
470workspace_create(void)
471{
472 struct workspace *ws = malloc(sizeof *ws);
473 if (ws == NULL)
474 return NULL;
475
476 weston_layer_init(&ws->layer, NULL);
477
Jonas Ådahl04769742012-06-13 00:01:24 +0200478 wl_list_init(&ws->focus_list);
479 wl_list_init(&ws->seat_destroyed_listener.link);
480 ws->seat_destroyed_listener.notify = seat_destroyed;
481
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200482 return ws;
483}
484
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200485static int
486workspace_is_empty(struct workspace *ws)
487{
488 return wl_list_empty(&ws->layer.surface_list);
489}
490
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200491static struct workspace *
492get_workspace(struct desktop_shell *shell, unsigned int index)
493{
494 struct workspace **pws = shell->workspaces.array.data;
495 pws += index;
496 return *pws;
497}
498
499static struct workspace *
500get_current_workspace(struct desktop_shell *shell)
501{
502 return get_workspace(shell, shell->workspaces.current);
503}
504
505static void
506activate_workspace(struct desktop_shell *shell, unsigned int index)
507{
508 struct workspace *ws;
509
510 ws = get_workspace(shell, index);
511 wl_list_insert(&shell->panel_layer.link, &ws->layer.link);
512
513 shell->workspaces.current = index;
514}
515
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200516static unsigned int
517get_output_height(struct weston_output *output)
518{
519 return abs(output->region.extents.y1 - output->region.extents.y2);
520}
521
522static void
523surface_translate(struct weston_surface *surface, double d)
524{
525 struct shell_surface *shsurf = get_shell_surface(surface);
526 struct weston_transform *transform;
527
528 transform = &shsurf->workspace_transform;
529 if (wl_list_empty(&transform->link))
530 wl_list_insert(surface->geometry.transformation_list.prev,
531 &shsurf->workspace_transform.link);
532
533 weston_matrix_init(&shsurf->workspace_transform.matrix);
534 weston_matrix_translate(&shsurf->workspace_transform.matrix,
535 0.0, d, 0.0);
536 surface->geometry.dirty = 1;
537}
538
539static void
540workspace_translate_out(struct workspace *ws, double fraction)
541{
542 struct weston_surface *surface;
543 unsigned int height;
544 double d;
545
546 wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
547 height = get_output_height(surface->output);
548 d = height * fraction;
549
550 surface_translate(surface, d);
551 }
552}
553
554static void
555workspace_translate_in(struct workspace *ws, double fraction)
556{
557 struct weston_surface *surface;
558 unsigned int height;
559 double d;
560
561 wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
562 height = get_output_height(surface->output);
563
564 if (fraction > 0)
565 d = -(height - height * fraction);
566 else
567 d = height + height * fraction;
568
569 surface_translate(surface, d);
570 }
571}
572
573static void
574workspace_damage_all_surfaces(struct workspace *ws)
575{
576 struct weston_surface *surface;
577
578 wl_list_for_each(surface, &ws->layer.surface_list, layer_link)
579 weston_surface_damage(surface);
580}
581
582static void
583reverse_workspace_change_animation(struct desktop_shell *shell,
584 unsigned int index,
585 struct workspace *from,
586 struct workspace *to)
587{
588 shell->workspaces.current = index;
589
590 shell->workspaces.anim_to = to;
591 shell->workspaces.anim_from = from;
592 shell->workspaces.anim_dir = -1 * shell->workspaces.anim_dir;
593 shell->workspaces.anim_timestamp = 0;
594
Jonas Ådahl04769742012-06-13 00:01:24 +0200595 push_focus_state(shell, from);
596 pop_focus_state(shell, to);
597
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200598 workspace_damage_all_surfaces(from);
599 workspace_damage_all_surfaces(to);
600}
601
602static void
603workspace_deactivate_transforms(struct workspace *ws)
604{
605 struct weston_surface *surface;
606 struct shell_surface *shsurf;
607
608 wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
609 shsurf = get_shell_surface(surface);
610 wl_list_remove(&shsurf->workspace_transform.link);
611 wl_list_init(&shsurf->workspace_transform.link);
612 shsurf->surface->geometry.dirty = 1;
613 }
614}
615
616static void
617finish_workspace_change_animation(struct desktop_shell *shell,
618 struct workspace *from,
619 struct workspace *to)
620{
621 workspace_damage_all_surfaces(from);
622 workspace_damage_all_surfaces(to);
623
624 wl_list_remove(&shell->workspaces.animation.link);
625 workspace_deactivate_transforms(from);
626 workspace_deactivate_transforms(to);
627 shell->workspaces.anim_to = NULL;
628
629 wl_list_remove(&shell->workspaces.anim_from->layer.link);
630}
631
632static void
633animate_workspace_change_frame(struct weston_animation *animation,
634 struct weston_output *output, uint32_t msecs)
635{
636 struct desktop_shell *shell =
637 container_of(animation, struct desktop_shell,
638 workspaces.animation);
639 struct workspace *from = shell->workspaces.anim_from;
640 struct workspace *to = shell->workspaces.anim_to;
641 uint32_t t;
642 double x, y;
643
644 if (workspace_is_empty(from) && workspace_is_empty(to)) {
645 finish_workspace_change_animation(shell, from, to);
646 return;
647 }
648
649 if (shell->workspaces.anim_timestamp == 0) {
650 if (shell->workspaces.anim_current == 0.0)
651 shell->workspaces.anim_timestamp = msecs;
652 else
653 shell->workspaces.anim_timestamp =
654 msecs -
655 /* Invers of movement function 'y' below. */
656 (asin(1.0 - shell->workspaces.anim_current) *
657 DEFAULT_WORKSPACE_CHANGE_ANIMATION_LENGTH *
658 M_2_PI);
659 }
660
661 t = msecs - shell->workspaces.anim_timestamp;
662
663 /*
664 * x = [0, π/2]
665 * y(x) = sin(x)
666 */
667 x = t * (1.0/DEFAULT_WORKSPACE_CHANGE_ANIMATION_LENGTH) * M_PI_2;
668 y = sin(x);
669
670 if (t < DEFAULT_WORKSPACE_CHANGE_ANIMATION_LENGTH) {
671 workspace_damage_all_surfaces(from);
672 workspace_damage_all_surfaces(to);
673
674 workspace_translate_out(from, shell->workspaces.anim_dir * y);
675 workspace_translate_in(to, shell->workspaces.anim_dir * y);
676 shell->workspaces.anim_current = y;
677
678 workspace_damage_all_surfaces(from);
679 workspace_damage_all_surfaces(to);
680 }
Jonas Ådahl04769742012-06-13 00:01:24 +0200681 else
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200682 finish_workspace_change_animation(shell, from, to);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200683}
684
685static void
686animate_workspace_change(struct desktop_shell *shell,
687 unsigned int index,
688 struct workspace *from,
689 struct workspace *to)
690{
691 struct weston_output *output;
692
693 int dir;
694
695 if (index > shell->workspaces.current)
696 dir = -1;
697 else
698 dir = 1;
699
700 shell->workspaces.current = index;
701
702 shell->workspaces.anim_dir = dir;
703 shell->workspaces.anim_from = from;
704 shell->workspaces.anim_to = to;
705 shell->workspaces.anim_current = 0.0;
706 shell->workspaces.anim_timestamp = 0;
707
708 output = container_of(shell->compositor->output_list.next,
709 struct weston_output, link);
710 wl_list_insert(&output->animation_list,
711 &shell->workspaces.animation.link);
712
713 wl_list_insert(&from->layer.link, &to->layer.link);
714
715 workspace_translate_in(to, 0);
716
Jonas Ådahl04769742012-06-13 00:01:24 +0200717 push_focus_state(shell, from);
718 pop_focus_state(shell, to);
719
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200720 workspace_damage_all_surfaces(from);
721 workspace_damage_all_surfaces(to);
722}
723
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200724static void
725change_workspace(struct desktop_shell *shell, unsigned int index)
726{
727 struct workspace *from;
728 struct workspace *to;
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200729
730 if (index == shell->workspaces.current)
731 return;
732
733 /* Don't change workspace when there is any fullscreen surfaces. */
734 if (!wl_list_empty(&shell->fullscreen_layer.surface_list))
735 return;
736
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200737 from = get_current_workspace(shell);
738 to = get_workspace(shell, index);
739
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200740 if (shell->workspaces.anim_from == to &&
741 shell->workspaces.anim_to == from) {
742 reverse_workspace_change_animation(shell, index, from, to);
743 return;
744 }
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200745
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200746 if (shell->workspaces.anim_to != NULL)
747 finish_workspace_change_animation(shell,
748 shell->workspaces.anim_from,
749 shell->workspaces.anim_to);
750
751 if (workspace_is_empty(to) && workspace_is_empty(from)) {
752 shell->workspaces.current = index;
753 wl_list_insert(&from->layer.link, &to->layer.link);
754 wl_list_remove(&from->layer.link);
Jonas Ådahl04769742012-06-13 00:01:24 +0200755
756 push_focus_state(shell, from);
757 pop_focus_state(shell, to);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200758 }
759 else
760 animate_workspace_change(shell, index, from, to);
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200761}
762
Pekka Paalanen56cdea92011-11-23 16:14:12 +0200763static void
Kristian Høgsbergeae5de72012-04-11 22:42:15 -0400764noop_grab_focus(struct wl_pointer_grab *grab,
Daniel Stone103db7f2012-05-08 17:17:55 +0100765 struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y)
Kristian Høgsberg9ddb8262012-01-04 21:30:29 -0500766{
767 grab->focus = NULL;
768}
769
770static void
Scott Moreau447013d2012-02-18 05:05:29 -0700771move_grab_motion(struct wl_pointer_grab *grab,
Daniel Stone103db7f2012-05-08 17:17:55 +0100772 uint32_t time, wl_fixed_t x, wl_fixed_t y)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500773{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500774 struct weston_move_grab *move = (struct weston_move_grab *) grab;
Daniel Stone37816df2012-05-16 18:45:18 +0100775 struct wl_pointer *pointer = grab->pointer;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300776 struct shell_surface *shsurf = move->base.shsurf;
777 struct weston_surface *es;
Daniel Stone37816df2012-05-16 18:45:18 +0100778 int dx = wl_fixed_to_int(pointer->x + move->dx);
779 int dy = wl_fixed_to_int(pointer->y + move->dy);
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300780
781 if (!shsurf)
782 return;
783
784 es = shsurf->surface;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500785
Daniel Stone103db7f2012-05-08 17:17:55 +0100786 weston_surface_configure(es, dx, dy,
Pekka Paalanen60921e52012-01-25 15:55:43 +0200787 es->geometry.width, es->geometry.height);
Kristian Høgsberg6c6fb992012-06-21 12:06:22 -0400788
789 weston_compositor_schedule_repaint(es->compositor);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500790}
791
792static void
Scott Moreau447013d2012-02-18 05:05:29 -0700793move_grab_button(struct wl_pointer_grab *grab,
Daniel Stone4dbadb12012-05-30 16:31:51 +0100794 uint32_t time, uint32_t button, uint32_t state_w)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500795{
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300796 struct shell_grab *shell_grab = container_of(grab, struct shell_grab,
797 grab);
Daniel Stone37816df2012-05-16 18:45:18 +0100798 struct wl_pointer *pointer = grab->pointer;
Daniel Stone4dbadb12012-05-30 16:31:51 +0100799 enum wl_pointer_button_state state = state_w;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500800
Daniel Stone4dbadb12012-05-30 16:31:51 +0100801 if (pointer->button_count == 0 &&
802 state == WL_POINTER_BUTTON_STATE_RELEASED) {
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300803 shell_grab_finish(shell_grab);
Daniel Stone37816df2012-05-16 18:45:18 +0100804 wl_pointer_end_grab(pointer);
Kristian Høgsberg9ddb8262012-01-04 21:30:29 -0500805 free(grab);
806 }
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500807}
808
Scott Moreau447013d2012-02-18 05:05:29 -0700809static const struct wl_pointer_grab_interface move_grab_interface = {
Kristian Høgsberg9ddb8262012-01-04 21:30:29 -0500810 noop_grab_focus,
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500811 move_grab_motion,
812 move_grab_button,
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500813};
814
Scott Moreauc3e54eb2012-04-17 19:06:20 -0600815static void
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400816busy_cursor_grab_focus(struct wl_pointer_grab *base,
817 struct wl_surface *surface, int32_t x, int32_t y)
Scott Moreauc3e54eb2012-04-17 19:06:20 -0600818{
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400819 struct shell_grab *grab = (struct shell_grab *) base;
820 struct wl_pointer *pointer = base->pointer;
Scott Moreauc3e54eb2012-04-17 19:06:20 -0600821
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400822 if (grab->grab.focus != surface) {
823 shell_grab_finish(grab);
824 wl_pointer_end_grab(pointer);
825 free(grab);
Scott Moreauc3e54eb2012-04-17 19:06:20 -0600826 }
827}
828
829static void
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400830busy_cursor_grab_motion(struct wl_pointer_grab *grab,
831 uint32_t time, int32_t x, int32_t y)
Scott Moreauc3e54eb2012-04-17 19:06:20 -0600832{
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400833}
Scott Moreauc3e54eb2012-04-17 19:06:20 -0600834
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400835static void
836busy_cursor_grab_button(struct wl_pointer_grab *grab,
837 uint32_t time, uint32_t button, uint32_t state)
838{
839}
840
841static const struct wl_pointer_grab_interface busy_cursor_grab_interface = {
842 busy_cursor_grab_focus,
843 busy_cursor_grab_motion,
844 busy_cursor_grab_button,
845};
846
847static void
848set_busy_cursor(struct shell_surface *shsurf, struct wl_pointer *pointer)
849{
850 struct shell_grab *grab;
851 struct desktop_shell *shell = shsurf->shell;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400852
853 grab = malloc(sizeof *grab);
854 if (!grab)
Scott Moreauc3e54eb2012-04-17 19:06:20 -0600855 return;
856
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400857 shell_grab_init(grab, &busy_cursor_grab_interface, shsurf);
858 grab->grab.focus = &shsurf->surface->surface;
859 wl_pointer_start_grab(pointer, &grab->grab);
860 wl_pointer_set_focus(pointer, &shell->busy_surface->surface, 0, 0);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400861}
Scott Moreauc3e54eb2012-04-17 19:06:20 -0600862
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400863static void
864end_busy_cursor(struct shell_surface *shsurf, struct wl_pointer *pointer)
865{
866 struct shell_grab *grab = (struct shell_grab *) pointer->grab;
867
868 if (grab->grab.interface == &busy_cursor_grab_interface) {
869 shell_grab_finish(grab);
870 wl_pointer_end_grab(pointer);
871 free(grab);
Scott Moreauc3e54eb2012-04-17 19:06:20 -0600872 }
Scott Moreauc3e54eb2012-04-17 19:06:20 -0600873}
874
Scott Moreau9521d5e2012-04-19 13:06:17 -0600875static void
876ping_timer_destroy(struct shell_surface *shsurf)
877{
878 if (!shsurf || !shsurf->ping_timer)
879 return;
880
881 if (shsurf->ping_timer->source)
882 wl_event_source_remove(shsurf->ping_timer->source);
883
884 free(shsurf->ping_timer);
885 shsurf->ping_timer = NULL;
886}
887
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400888static int
Scott Moreauff1db4a2012-04-17 19:06:18 -0600889ping_timeout_handler(void *data)
890{
891 struct shell_surface *shsurf = data;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400892 struct weston_seat *seat;
Scott Moreauff1db4a2012-04-17 19:06:18 -0600893
Scott Moreau9521d5e2012-04-19 13:06:17 -0600894 /* Client is not responding */
895 shsurf->unresponsive = 1;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400896
897 wl_list_for_each(seat, &shsurf->surface->compositor->seat_list, link)
898 if (seat->seat.pointer->focus == &shsurf->surface->surface)
899 set_busy_cursor(shsurf, seat->seat.pointer);
Scott Moreauff1db4a2012-04-17 19:06:18 -0600900
901 return 1;
902}
903
904static void
905ping_handler(struct weston_surface *surface, uint32_t serial)
906{
Kristian Høgsbergb71302e2012-05-10 12:28:35 -0400907 struct shell_surface *shsurf = get_shell_surface(surface);
Scott Moreauff1db4a2012-04-17 19:06:18 -0600908 struct wl_event_loop *loop;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400909 int ping_timeout = 200;
Scott Moreauff1db4a2012-04-17 19:06:18 -0600910
911 if (!shsurf)
912 return;
Kristian Høgsbergca535c12012-04-21 23:20:07 -0400913 if (!shsurf->resource.client)
914 return;
Scott Moreauff1db4a2012-04-17 19:06:18 -0600915
916 if (!shsurf->ping_timer) {
Ander Conselvan de Oliveirafb980892012-04-27 13:55:55 +0300917 shsurf->ping_timer = malloc(sizeof *shsurf->ping_timer);
Scott Moreauff1db4a2012-04-17 19:06:18 -0600918 if (!shsurf->ping_timer)
919 return;
920
921 shsurf->ping_timer->serial = serial;
Scott Moreauff1db4a2012-04-17 19:06:18 -0600922 loop = wl_display_get_event_loop(surface->compositor->wl_display);
923 shsurf->ping_timer->source =
924 wl_event_loop_add_timer(loop, ping_timeout_handler, shsurf);
925 wl_event_source_timer_update(shsurf->ping_timer->source, ping_timeout);
926
927 wl_shell_surface_send_ping(&shsurf->resource, serial);
928 }
929}
930
931static void
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400932handle_pointer_focus(struct wl_listener *listener, void *data)
933{
934 struct wl_pointer *pointer = data;
935 struct weston_surface *surface =
936 (struct weston_surface *) pointer->focus;
937 struct weston_compositor *compositor;
938 struct shell_surface *shsurf;
939 uint32_t serial;
940
941 if (!surface)
942 return;
943
944 compositor = surface->compositor;
945 shsurf = get_shell_surface(surface);
946
Pekka Paalanen4e1f2ff2012-06-06 16:59:45 +0300947 if (shsurf && shsurf->unresponsive) {
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400948 set_busy_cursor(shsurf, pointer);
949 } else {
950 serial = wl_display_next_serial(compositor->wl_display);
951 ping_handler(surface, serial);
952 }
953}
954
955static void
Scott Moreauff1db4a2012-04-17 19:06:18 -0600956shell_surface_pong(struct wl_client *client, struct wl_resource *resource,
957 uint32_t serial)
958{
959 struct shell_surface *shsurf = resource->data;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400960 struct desktop_shell *shell = shsurf->shell;
961 struct weston_seat *seat;
962 struct weston_compositor *ec = shsurf->surface->compositor;
963 struct wl_pointer *pointer;
964 int was_unresponsive;
Scott Moreauff1db4a2012-04-17 19:06:18 -0600965
Scott Moreauff1db4a2012-04-17 19:06:18 -0600966 if (shsurf->ping_timer->serial == serial) {
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400967 was_unresponsive = shsurf->unresponsive;
Scott Moreauff1db4a2012-04-17 19:06:18 -0600968 shsurf->unresponsive = 0;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400969 if (was_unresponsive) {
970 /* Received pong from previously unresponsive client */
971 wl_list_for_each(seat, &ec->seat_list, link) {
972 pointer = seat->seat.pointer;
973 if (pointer->focus ==
974 &shell->busy_surface->surface &&
975 pointer->current ==
976 &shsurf->surface->surface)
977 end_busy_cursor(shsurf, pointer);
978 }
979 }
Scott Moreau9521d5e2012-04-19 13:06:17 -0600980 ping_timer_destroy(shsurf);
Scott Moreauff1db4a2012-04-17 19:06:18 -0600981 }
982}
983
Kristian Høgsberge7afd912012-05-02 09:47:44 -0400984static void
985shell_surface_set_title(struct wl_client *client,
986 struct wl_resource *resource, const char *title)
987{
988 struct shell_surface *shsurf = resource->data;
989
990 free(shsurf->title);
991 shsurf->title = strdup(title);
992}
993
994static void
995shell_surface_set_class(struct wl_client *client,
996 struct wl_resource *resource, const char *class)
997{
998 struct shell_surface *shsurf = resource->data;
999
1000 free(shsurf->class);
1001 shsurf->class = strdup(class);
1002}
1003
Scott Moreauff1db4a2012-04-17 19:06:18 -06001004static int
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04001005surface_move(struct shell_surface *shsurf, struct weston_seat *ws)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001006{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001007 struct weston_move_grab *move;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03001008
1009 if (!shsurf)
1010 return -1;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001011
1012 move = malloc(sizeof *move);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001013 if (!move)
1014 return -1;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001015
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03001016 shell_grab_init(&move->base, &move_grab_interface, shsurf);
1017
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04001018 move->dx = wl_fixed_from_double(shsurf->surface->geometry.x) -
Daniel Stone37816df2012-05-16 18:45:18 +01001019 ws->seat.pointer->grab_x;
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04001020 move->dy = wl_fixed_from_double(shsurf->surface->geometry.y) -
Daniel Stone37816df2012-05-16 18:45:18 +01001021 ws->seat.pointer->grab_y;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001022
Daniel Stone37816df2012-05-16 18:45:18 +01001023 wl_pointer_start_grab(ws->seat.pointer, &move->base.grab);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001024
Daniel Stone37816df2012-05-16 18:45:18 +01001025 wl_pointer_set_focus(ws->seat.pointer, NULL,
1026 wl_fixed_from_int(0),
1027 wl_fixed_from_int(0));
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001028
1029 return 0;
1030}
1031
1032static void
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001033shell_surface_move(struct wl_client *client, struct wl_resource *resource,
Daniel Stone37816df2012-05-16 18:45:18 +01001034 struct wl_resource *seat_resource, uint32_t serial)
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001035{
Daniel Stone37816df2012-05-16 18:45:18 +01001036 struct weston_seat *ws = seat_resource->data;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001037 struct shell_surface *shsurf = resource->data;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001038
Daniel Stone37816df2012-05-16 18:45:18 +01001039 if (ws->seat.pointer->button_count == 0 ||
1040 ws->seat.pointer->grab_serial != serial ||
1041 ws->seat.pointer->focus != &shsurf->surface->surface)
Kristian Høgsberg9ddb8262012-01-04 21:30:29 -05001042 return;
1043
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04001044 if (surface_move(shsurf, ws) < 0)
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -04001045 wl_resource_post_no_memory(resource);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001046}
1047
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001048struct weston_resize_grab {
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03001049 struct shell_grab base;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001050 uint32_t edges;
Pekka Paalanen5c97ae72012-01-30 16:19:47 +02001051 int32_t width, height;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001052};
1053
1054static void
Scott Moreau447013d2012-02-18 05:05:29 -07001055resize_grab_motion(struct wl_pointer_grab *grab,
Daniel Stone103db7f2012-05-08 17:17:55 +01001056 uint32_t time, wl_fixed_t x, wl_fixed_t y)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001057{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001058 struct weston_resize_grab *resize = (struct weston_resize_grab *) grab;
Daniel Stone37816df2012-05-16 18:45:18 +01001059 struct wl_pointer *pointer = grab->pointer;
Kristian Høgsberga61ca062012-05-22 16:05:52 -04001060 struct shell_surface *shsurf = resize->base.shsurf;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001061 int32_t width, height;
Daniel Stone103db7f2012-05-08 17:17:55 +01001062 wl_fixed_t from_x, from_y;
1063 wl_fixed_t to_x, to_y;
Pekka Paalanen5c97ae72012-01-30 16:19:47 +02001064
Kristian Høgsberga61ca062012-05-22 16:05:52 -04001065 if (!shsurf)
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03001066 return;
1067
Kristian Høgsberga61ca062012-05-22 16:05:52 -04001068 weston_surface_from_global_fixed(shsurf->surface,
Daniel Stone37816df2012-05-16 18:45:18 +01001069 pointer->grab_x, pointer->grab_y,
Daniel Stone103db7f2012-05-08 17:17:55 +01001070 &from_x, &from_y);
Kristian Høgsberga61ca062012-05-22 16:05:52 -04001071 weston_surface_from_global_fixed(shsurf->surface,
Daniel Stone37816df2012-05-16 18:45:18 +01001072 pointer->x, pointer->y, &to_x, &to_y);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001073
Daniel Stone103db7f2012-05-08 17:17:55 +01001074 width = resize->width;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001075 if (resize->edges & WL_SHELL_SURFACE_RESIZE_LEFT) {
Daniel Stone103db7f2012-05-08 17:17:55 +01001076 width += wl_fixed_to_int(from_x - to_x);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001077 } else if (resize->edges & WL_SHELL_SURFACE_RESIZE_RIGHT) {
Daniel Stone103db7f2012-05-08 17:17:55 +01001078 width += wl_fixed_to_int(to_x - from_x);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001079 }
1080
Daniel Stone103db7f2012-05-08 17:17:55 +01001081 height = resize->height;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001082 if (resize->edges & WL_SHELL_SURFACE_RESIZE_TOP) {
Daniel Stone103db7f2012-05-08 17:17:55 +01001083 height += wl_fixed_to_int(from_y - to_y);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001084 } else if (resize->edges & WL_SHELL_SURFACE_RESIZE_BOTTOM) {
Daniel Stone103db7f2012-05-08 17:17:55 +01001085 height += wl_fixed_to_int(to_y - from_y);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001086 }
1087
Kristian Høgsberga61ca062012-05-22 16:05:52 -04001088 shsurf->client->send_configure(shsurf->surface,
1089 resize->edges, width, height);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001090}
1091
1092static void
Kristian Høgsberga61ca062012-05-22 16:05:52 -04001093send_configure(struct weston_surface *surface,
1094 uint32_t edges, int32_t width, int32_t height)
1095{
1096 struct shell_surface *shsurf = get_shell_surface(surface);
1097
1098 wl_shell_surface_send_configure(&shsurf->resource,
1099 edges, width, height);
1100}
1101
1102static const struct weston_shell_client shell_client = {
1103 send_configure
1104};
1105
1106static void
Scott Moreau447013d2012-02-18 05:05:29 -07001107resize_grab_button(struct wl_pointer_grab *grab,
Daniel Stone4dbadb12012-05-30 16:31:51 +01001108 uint32_t time, uint32_t button, uint32_t state_w)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001109{
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03001110 struct weston_resize_grab *resize = (struct weston_resize_grab *) grab;
Daniel Stone37816df2012-05-16 18:45:18 +01001111 struct wl_pointer *pointer = grab->pointer;
Daniel Stone4dbadb12012-05-30 16:31:51 +01001112 enum wl_pointer_button_state state = state_w;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001113
Daniel Stone4dbadb12012-05-30 16:31:51 +01001114 if (pointer->button_count == 0 &&
1115 state == WL_POINTER_BUTTON_STATE_RELEASED) {
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03001116 shell_grab_finish(&resize->base);
Daniel Stone37816df2012-05-16 18:45:18 +01001117 wl_pointer_end_grab(pointer);
Kristian Høgsberg9ddb8262012-01-04 21:30:29 -05001118 free(grab);
1119 }
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001120}
1121
Scott Moreau447013d2012-02-18 05:05:29 -07001122static const struct wl_pointer_grab_interface resize_grab_interface = {
Kristian Høgsberg9ddb8262012-01-04 21:30:29 -05001123 noop_grab_focus,
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001124 resize_grab_motion,
1125 resize_grab_button,
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001126};
1127
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001128static int
Kristian Høgsbergc1693f22012-05-22 16:56:23 -04001129surface_resize(struct shell_surface *shsurf,
1130 struct weston_seat *ws, uint32_t edges)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001131{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001132 struct weston_resize_grab *resize;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001133
Alex Wu4539b082012-03-01 12:57:46 +08001134 if (shsurf->type == SHELL_SURFACE_FULLSCREEN)
1135 return 0;
Kristian Høgsberg0ce24572011-01-28 15:18:33 -05001136
Pekka Paalanen5c97ae72012-01-30 16:19:47 +02001137 if (edges == 0 || edges > 15 ||
1138 (edges & 3) == 3 || (edges & 12) == 12)
1139 return 0;
1140
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001141 resize = malloc(sizeof *resize);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001142 if (!resize)
1143 return -1;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001144
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03001145 shell_grab_init(&resize->base, &resize_grab_interface, shsurf);
1146
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001147 resize->edges = edges;
Pekka Paalanen5c97ae72012-01-30 16:19:47 +02001148 resize->width = shsurf->surface->geometry.width;
1149 resize->height = shsurf->surface->geometry.height;
Kristian Høgsberg904055a2011-08-18 17:55:30 -04001150
Daniel Stone37816df2012-05-16 18:45:18 +01001151 wl_pointer_start_grab(ws->seat.pointer, &resize->base.grab);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001152
Daniel Stone37816df2012-05-16 18:45:18 +01001153 wl_pointer_set_focus(ws->seat.pointer, NULL,
1154 wl_fixed_from_int(0),
1155 wl_fixed_from_int(0));
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001156
1157 return 0;
1158}
1159
1160static void
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001161shell_surface_resize(struct wl_client *client, struct wl_resource *resource,
Daniel Stone37816df2012-05-16 18:45:18 +01001162 struct wl_resource *seat_resource, uint32_t serial,
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001163 uint32_t edges)
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001164{
Daniel Stone37816df2012-05-16 18:45:18 +01001165 struct weston_seat *ws = seat_resource->data;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001166 struct shell_surface *shsurf = resource->data;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001167
Alex Wu4539b082012-03-01 12:57:46 +08001168 if (shsurf->type == SHELL_SURFACE_FULLSCREEN)
1169 return;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001170
Daniel Stone37816df2012-05-16 18:45:18 +01001171 if (ws->seat.pointer->button_count == 0 ||
1172 ws->seat.pointer->grab_serial != serial ||
1173 ws->seat.pointer->focus != &shsurf->surface->surface)
Kristian Høgsberg9ddb8262012-01-04 21:30:29 -05001174 return;
1175
Kristian Høgsbergc1693f22012-05-22 16:56:23 -04001176 if (surface_resize(shsurf, ws, edges) < 0)
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -04001177 wl_resource_post_no_memory(resource);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001178}
1179
Juan Zhao96879df2012-02-07 08:45:41 +08001180static struct weston_output *
1181get_default_output(struct weston_compositor *compositor)
1182{
1183 return container_of(compositor->output_list.next,
1184 struct weston_output, link);
1185}
1186
Alex Wu4539b082012-03-01 12:57:46 +08001187static void
1188shell_unset_fullscreen(struct shell_surface *shsurf)
1189{
1190 /* undo all fullscreen things here */
Alex Wubd3354b2012-04-17 17:20:49 +08001191 if (shsurf->fullscreen.type == WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER &&
1192 shell_surface_is_top_fullscreen(shsurf)) {
1193 weston_output_switch_mode(shsurf->fullscreen_output,
1194 shsurf->fullscreen_output->origin);
1195 }
Alex Wu4539b082012-03-01 12:57:46 +08001196 shsurf->fullscreen.type = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT;
1197 shsurf->fullscreen.framerate = 0;
1198 wl_list_remove(&shsurf->fullscreen.transform.link);
1199 wl_list_init(&shsurf->fullscreen.transform.link);
Alex Wubd3354b2012-04-17 17:20:49 +08001200 if (shsurf->fullscreen.black_surface)
1201 weston_surface_destroy(shsurf->fullscreen.black_surface);
Alex Wu4539b082012-03-01 12:57:46 +08001202 shsurf->fullscreen.black_surface = NULL;
1203 shsurf->fullscreen_output = NULL;
Alex Wu4539b082012-03-01 12:57:46 +08001204 weston_surface_set_position(shsurf->surface,
1205 shsurf->saved_x, shsurf->saved_y);
Alex Wu7bcb8bd2012-04-27 09:07:24 +08001206 if (shsurf->saved_rotation_valid) {
1207 wl_list_insert(&shsurf->surface->geometry.transformation_list,
1208 &shsurf->rotation.transform.link);
1209 shsurf->saved_rotation_valid = false;
1210 }
Alex Wu4539b082012-03-01 12:57:46 +08001211}
1212
Pekka Paalanen98262232011-12-01 10:42:22 +02001213static int
1214reset_shell_surface_type(struct shell_surface *surface)
1215{
1216 switch (surface->type) {
1217 case SHELL_SURFACE_FULLSCREEN:
Alex Wu4539b082012-03-01 12:57:46 +08001218 shell_unset_fullscreen(surface);
Pekka Paalanen98262232011-12-01 10:42:22 +02001219 break;
Juan Zhao96879df2012-02-07 08:45:41 +08001220 case SHELL_SURFACE_MAXIMIZED:
1221 surface->output = get_default_output(surface->surface->compositor);
1222 weston_surface_set_position(surface->surface,
1223 surface->saved_x,
1224 surface->saved_y);
1225 break;
Jan Arne Petersen42feced2012-06-21 21:52:17 +02001226 case SHELL_SURFACE_INPUT_PANEL:
Pekka Paalanen98262232011-12-01 10:42:22 +02001227 wl_list_remove(&surface->link);
1228 wl_list_init(&surface->link);
1229 break;
Pekka Paalanen77346a62011-11-30 16:26:35 +02001230 case SHELL_SURFACE_SCREENSAVER:
Pekka Paalanen98262232011-12-01 10:42:22 +02001231 case SHELL_SURFACE_LOCK:
1232 wl_resource_post_error(&surface->resource,
1233 WL_DISPLAY_ERROR_INVALID_METHOD,
Pekka Paalanen77346a62011-11-30 16:26:35 +02001234 "cannot reassign surface type");
Pekka Paalanen98262232011-12-01 10:42:22 +02001235 return -1;
1236 case SHELL_SURFACE_NONE:
1237 case SHELL_SURFACE_TOPLEVEL:
1238 case SHELL_SURFACE_TRANSIENT:
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001239 case SHELL_SURFACE_POPUP:
Pekka Paalanen98262232011-12-01 10:42:22 +02001240 break;
1241 }
1242
1243 surface->type = SHELL_SURFACE_NONE;
1244 return 0;
1245}
1246
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001247static void
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001248set_surface_type(struct shell_surface *shsurf)
1249{
1250 struct weston_surface *surface = shsurf->surface;
1251 struct shell_surface *pshsurf = shsurf->parent;
1252 struct weston_surface *pes;
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001253
1254 reset_shell_surface_type(shsurf);
1255
1256 shsurf->type = shsurf->next_type;
1257 shsurf->next_type = SHELL_SURFACE_NONE;
1258
1259 switch (shsurf->type) {
1260 case SHELL_SURFACE_TOPLEVEL:
1261 break;
1262 case SHELL_SURFACE_TRANSIENT:
1263 pes = pshsurf->surface;
1264 weston_surface_set_position(surface,
Tiago Vignatti52e598c2012-05-07 15:23:08 +03001265 pes->geometry.x + shsurf->transient.x,
1266 pes->geometry.y + shsurf->transient.y);
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001267 break;
1268
1269 case SHELL_SURFACE_MAXIMIZED:
1270 shsurf->saved_x = surface->geometry.x;
1271 shsurf->saved_y = surface->geometry.y;
1272 shsurf->saved_position_valid = true;
1273 break;
1274
1275 case SHELL_SURFACE_FULLSCREEN:
1276 shsurf->saved_x = surface->geometry.x;
1277 shsurf->saved_y = surface->geometry.y;
1278 shsurf->saved_position_valid = true;
1279
1280 if (!wl_list_empty(&shsurf->rotation.transform.link)) {
1281 wl_list_remove(&shsurf->rotation.transform.link);
1282 wl_list_init(&shsurf->rotation.transform.link);
1283 shsurf->surface->geometry.dirty = 1;
1284 shsurf->saved_rotation_valid = true;
1285 }
1286 break;
1287
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001288 default:
1289 break;
1290 }
1291}
1292
1293static void
Tiago Vignattibc052c92012-04-19 16:18:18 +03001294set_toplevel(struct shell_surface *shsurf)
1295{
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001296 shsurf->next_type = SHELL_SURFACE_TOPLEVEL;
Tiago Vignattibc052c92012-04-19 16:18:18 +03001297}
1298
1299static void
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001300shell_surface_set_toplevel(struct wl_client *client,
1301 struct wl_resource *resource)
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001302{
Pekka Paalanen98262232011-12-01 10:42:22 +02001303 struct shell_surface *surface = resource->data;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001304
Tiago Vignattibc052c92012-04-19 16:18:18 +03001305 set_toplevel(surface);
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001306}
1307
1308static void
Tiago Vignatti491bac12012-05-18 16:37:43 -04001309set_transient(struct shell_surface *shsurf,
1310 struct shell_surface *pshsurf, int x, int y, uint32_t flags)
1311{
1312 /* assign to parents output */
1313 shsurf->parent = pshsurf;
1314 shsurf->transient.x = x;
1315 shsurf->transient.y = y;
1316 shsurf->transient.flags = flags;
1317 shsurf->next_type = SHELL_SURFACE_TRANSIENT;
1318}
1319
1320static void
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001321shell_surface_set_transient(struct wl_client *client,
1322 struct wl_resource *resource,
1323 struct wl_resource *parent_resource,
1324 int x, int y, uint32_t flags)
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001325{
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001326 struct shell_surface *shsurf = resource->data;
Tiago Vignatti491bac12012-05-18 16:37:43 -04001327 struct shell_surface *pshsurf = parent_resource->data;
Pekka Paalanen98262232011-12-01 10:42:22 +02001328
Tiago Vignatti491bac12012-05-18 16:37:43 -04001329 set_transient(shsurf, pshsurf, x, y, flags);
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001330}
1331
Tiago Vignattibe143262012-04-16 17:31:41 +03001332static struct desktop_shell *
Juan Zhao96879df2012-02-07 08:45:41 +08001333shell_surface_get_shell(struct shell_surface *shsurf)
Pekka Paalanenaf0e34c2011-12-02 10:59:17 +02001334{
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04001335 return shsurf->shell;
Juan Zhao96879df2012-02-07 08:45:41 +08001336}
1337
1338static int
Tiago Vignattibe143262012-04-16 17:31:41 +03001339get_output_panel_height(struct desktop_shell *shell,
1340 struct weston_output *output)
Juan Zhao96879df2012-02-07 08:45:41 +08001341{
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001342 struct weston_surface *surface;
Juan Zhao96879df2012-02-07 08:45:41 +08001343 int panel_height = 0;
1344
1345 if (!output)
1346 return 0;
1347
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001348 wl_list_for_each(surface, &shell->panel_layer.surface_list, link) {
1349 if (surface->output == output) {
1350 panel_height = surface->geometry.height;
Juan Zhao96879df2012-02-07 08:45:41 +08001351 break;
1352 }
1353 }
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001354
Juan Zhao96879df2012-02-07 08:45:41 +08001355 return panel_height;
1356}
1357
1358static void
1359shell_surface_set_maximized(struct wl_client *client,
1360 struct wl_resource *resource,
1361 struct wl_resource *output_resource )
1362{
1363 struct shell_surface *shsurf = resource->data;
1364 struct weston_surface *es = shsurf->surface;
Tiago Vignattibe143262012-04-16 17:31:41 +03001365 struct desktop_shell *shell = NULL;
Juan Zhao96879df2012-02-07 08:45:41 +08001366 uint32_t edges = 0, panel_height = 0;
1367
1368 /* get the default output, if the client set it as NULL
1369 check whether the ouput is available */
1370 if (output_resource)
1371 shsurf->output = output_resource->data;
1372 else
1373 shsurf->output = get_default_output(es->compositor);
1374
Tiago Vignattibe143262012-04-16 17:31:41 +03001375 shell = shell_surface_get_shell(shsurf);
1376 panel_height = get_output_panel_height(shell, es->output);
Juan Zhao96879df2012-02-07 08:45:41 +08001377 edges = WL_SHELL_SURFACE_RESIZE_TOP|WL_SHELL_SURFACE_RESIZE_LEFT;
Kristian Høgsberg0b5cd0c2012-03-04 21:57:37 -05001378
Kristian Høgsberga61ca062012-05-22 16:05:52 -04001379 shsurf->client->send_configure(shsurf->surface, edges,
1380 es->output->current->width,
1381 es->output->current->height - panel_height);
Juan Zhao96879df2012-02-07 08:45:41 +08001382
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001383 shsurf->next_type = SHELL_SURFACE_MAXIMIZED;
Pekka Paalanenaf0e34c2011-12-02 10:59:17 +02001384}
1385
Alex Wu21858432012-04-01 20:13:08 +08001386static void
1387black_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy);
1388
Alex Wu4539b082012-03-01 12:57:46 +08001389static struct weston_surface *
1390create_black_surface(struct weston_compositor *ec,
Alex Wu21858432012-04-01 20:13:08 +08001391 struct weston_surface *fs_surface,
Alex Wu4539b082012-03-01 12:57:46 +08001392 GLfloat x, GLfloat y, int w, int h)
1393{
1394 struct weston_surface *surface = NULL;
1395
1396 surface = weston_surface_create(ec);
1397 if (surface == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001398 weston_log("no memory\n");
Alex Wu4539b082012-03-01 12:57:46 +08001399 return NULL;
1400 }
1401
Alex Wu21858432012-04-01 20:13:08 +08001402 surface->configure = black_surface_configure;
1403 surface->private = fs_surface;
Alex Wu4539b082012-03-01 12:57:46 +08001404 weston_surface_configure(surface, x, y, w, h);
1405 weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1);
1406 return surface;
1407}
1408
1409/* Create black surface and append it to the associated fullscreen surface.
1410 * Handle size dismatch and positioning according to the method. */
1411static void
1412shell_configure_fullscreen(struct shell_surface *shsurf)
1413{
1414 struct weston_output *output = shsurf->fullscreen_output;
1415 struct weston_surface *surface = shsurf->surface;
1416 struct weston_matrix *matrix;
1417 float scale;
1418
1419 center_on_output(surface, output);
1420
1421 if (!shsurf->fullscreen.black_surface)
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05001422 shsurf->fullscreen.black_surface =
1423 create_black_surface(surface->compositor,
Alex Wu21858432012-04-01 20:13:08 +08001424 surface,
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05001425 output->x, output->y,
1426 output->current->width,
1427 output->current->height);
1428
1429 wl_list_remove(&shsurf->fullscreen.black_surface->layer_link);
1430 wl_list_insert(&surface->layer_link,
1431 &shsurf->fullscreen.black_surface->layer_link);
Alex Wu4539b082012-03-01 12:57:46 +08001432 shsurf->fullscreen.black_surface->output = output;
1433
1434 switch (shsurf->fullscreen.type) {
1435 case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT:
1436 break;
1437 case WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE:
1438 matrix = &shsurf->fullscreen.transform.matrix;
1439 weston_matrix_init(matrix);
1440 scale = (float)output->current->width/(float)surface->geometry.width;
1441 weston_matrix_scale(matrix, scale, scale, 1);
1442 wl_list_remove(&shsurf->fullscreen.transform.link);
1443 wl_list_insert(surface->geometry.transformation_list.prev,
1444 &shsurf->fullscreen.transform.link);
1445 weston_surface_set_position(surface, output->x, output->y);
1446 break;
1447 case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER:
Alex Wubd3354b2012-04-17 17:20:49 +08001448 if (shell_surface_is_top_fullscreen(shsurf)) {
1449 struct weston_mode mode = {0,
1450 surface->geometry.width,
1451 surface->geometry.height,
1452 shsurf->fullscreen.framerate};
1453
1454 if (weston_output_switch_mode(output, &mode) == 0) {
1455 weston_surface_configure(shsurf->fullscreen.black_surface,
1456 output->x, output->y,
1457 output->current->width,
1458 output->current->height);
1459 weston_surface_set_position(surface, output->x, output->y);
1460 break;
1461 }
1462 }
Alex Wu4539b082012-03-01 12:57:46 +08001463 break;
1464 case WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL:
1465 break;
1466 default:
1467 break;
1468 }
1469}
1470
1471/* make the fullscreen and black surface at the top */
1472static void
1473shell_stack_fullscreen(struct shell_surface *shsurf)
1474{
Alex Wubd3354b2012-04-17 17:20:49 +08001475 struct weston_output *output = shsurf->fullscreen_output;
Alex Wu4539b082012-03-01 12:57:46 +08001476 struct weston_surface *surface = shsurf->surface;
Tiago Vignattibe143262012-04-16 17:31:41 +03001477 struct desktop_shell *shell = shell_surface_get_shell(shsurf);
Alex Wu4539b082012-03-01 12:57:46 +08001478
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05001479 wl_list_remove(&surface->layer_link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05001480 wl_list_insert(&shell->fullscreen_layer.surface_list,
1481 &surface->layer_link);
Alex Wubd3354b2012-04-17 17:20:49 +08001482 weston_surface_damage(surface);
1483
1484 if (!shsurf->fullscreen.black_surface)
1485 shsurf->fullscreen.black_surface =
1486 create_black_surface(surface->compositor,
1487 surface,
1488 output->x, output->y,
1489 output->current->width,
1490 output->current->height);
1491
1492 wl_list_remove(&shsurf->fullscreen.black_surface->layer_link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05001493 wl_list_insert(&surface->layer_link,
1494 &shsurf->fullscreen.black_surface->layer_link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05001495 weston_surface_damage(shsurf->fullscreen.black_surface);
Alex Wu4539b082012-03-01 12:57:46 +08001496}
1497
1498static void
1499shell_map_fullscreen(struct shell_surface *shsurf)
1500{
Alex Wu4539b082012-03-01 12:57:46 +08001501 shell_stack_fullscreen(shsurf);
Alex Wubd3354b2012-04-17 17:20:49 +08001502 shell_configure_fullscreen(shsurf);
Alex Wu4539b082012-03-01 12:57:46 +08001503}
1504
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001505static void
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001506shell_surface_set_fullscreen(struct wl_client *client,
Kristian Høgsbergf856fd22012-02-16 15:58:14 -05001507 struct wl_resource *resource,
1508 uint32_t method,
1509 uint32_t framerate,
1510 struct wl_resource *output_resource)
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001511{
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001512 struct shell_surface *shsurf = resource->data;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001513 struct weston_surface *es = shsurf->surface;
Alex Wu4539b082012-03-01 12:57:46 +08001514
1515 if (output_resource)
1516 shsurf->output = output_resource->data;
1517 else
1518 shsurf->output = get_default_output(es->compositor);
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001519
Alex Wu4539b082012-03-01 12:57:46 +08001520 shsurf->fullscreen_output = shsurf->output;
1521 shsurf->fullscreen.type = method;
1522 shsurf->fullscreen.framerate = framerate;
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001523 shsurf->next_type = SHELL_SURFACE_FULLSCREEN;
Alex Wu4539b082012-03-01 12:57:46 +08001524
Kristian Høgsberga61ca062012-05-22 16:05:52 -04001525 shsurf->client->send_configure(shsurf->surface, 0,
1526 shsurf->output->current->width,
1527 shsurf->output->current->height);
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001528}
1529
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001530static void
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001531popup_grab_focus(struct wl_pointer_grab *grab,
Daniel Stone103db7f2012-05-08 17:17:55 +01001532 struct wl_surface *surface,
1533 wl_fixed_t x,
1534 wl_fixed_t y)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001535{
Daniel Stone37816df2012-05-16 18:45:18 +01001536 struct wl_pointer *pointer = grab->pointer;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001537 struct shell_surface *priv =
1538 container_of(grab, struct shell_surface, popup.grab);
1539 struct wl_client *client = priv->surface->surface.resource.client;
1540
Pekka Paalanencb108432012-01-19 16:25:40 +02001541 if (surface && surface->resource.client == client) {
Daniel Stone37816df2012-05-16 18:45:18 +01001542 wl_pointer_set_focus(pointer, surface, x, y);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001543 grab->focus = surface;
1544 } else {
Daniel Stone37816df2012-05-16 18:45:18 +01001545 wl_pointer_set_focus(pointer, NULL,
1546 wl_fixed_from_int(0),
1547 wl_fixed_from_int(0));
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001548 grab->focus = NULL;
1549 }
1550}
1551
1552static void
Scott Moreau447013d2012-02-18 05:05:29 -07001553popup_grab_motion(struct wl_pointer_grab *grab,
Daniel Stone103db7f2012-05-08 17:17:55 +01001554 uint32_t time, wl_fixed_t sx, wl_fixed_t sy)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001555{
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001556 struct wl_resource *resource;
1557
Daniel Stone37816df2012-05-16 18:45:18 +01001558 resource = grab->pointer->focus_resource;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001559 if (resource)
Daniel Stone37816df2012-05-16 18:45:18 +01001560 wl_pointer_send_motion(resource, time, sx, sy);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001561}
1562
1563static void
Scott Moreau447013d2012-02-18 05:05:29 -07001564popup_grab_button(struct wl_pointer_grab *grab,
Daniel Stone4dbadb12012-05-30 16:31:51 +01001565 uint32_t time, uint32_t button, uint32_t state_w)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001566{
1567 struct wl_resource *resource;
1568 struct shell_surface *shsurf =
1569 container_of(grab, struct shell_surface, popup.grab);
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001570 struct wl_display *display;
Daniel Stone4dbadb12012-05-30 16:31:51 +01001571 enum wl_pointer_button_state state = state_w;
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001572 uint32_t serial;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001573
Daniel Stone37816df2012-05-16 18:45:18 +01001574 resource = grab->pointer->focus_resource;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001575 if (resource) {
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001576 display = wl_client_get_display(resource->client);
1577 serial = wl_display_get_serial(display);
Daniel Stone37816df2012-05-16 18:45:18 +01001578 wl_pointer_send_button(resource, serial, time, button, state);
Daniel Stone4dbadb12012-05-30 16:31:51 +01001579 } else if (state == WL_POINTER_BUTTON_STATE_RELEASED &&
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001580 (shsurf->popup.initial_up ||
Daniel Stone37816df2012-05-16 18:45:18 +01001581 time - shsurf->popup.seat->pointer->grab_time > 500)) {
Kristian Høgsberg0b5cd0c2012-03-04 21:57:37 -05001582 wl_shell_surface_send_popup_done(&shsurf->resource);
Daniel Stone37816df2012-05-16 18:45:18 +01001583 wl_pointer_end_grab(grab->pointer);
1584 shsurf->popup.grab.pointer = NULL;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001585 }
1586
Daniel Stone4dbadb12012-05-30 16:31:51 +01001587 if (state == WL_POINTER_BUTTON_STATE_RELEASED)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001588 shsurf->popup.initial_up = 1;
1589}
1590
Scott Moreau447013d2012-02-18 05:05:29 -07001591static const struct wl_pointer_grab_interface popup_grab_interface = {
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001592 popup_grab_focus,
1593 popup_grab_motion,
1594 popup_grab_button,
1595};
1596
1597static void
Kristian Høgsberg3730f362012-04-13 12:40:07 -04001598shell_map_popup(struct shell_surface *shsurf)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001599{
Daniel Stone37816df2012-05-16 18:45:18 +01001600 struct wl_seat *seat = shsurf->popup.seat;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001601 struct weston_surface *es = shsurf->surface;
1602 struct weston_surface *parent = shsurf->parent->surface;
1603
1604 es->output = parent->output;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001605 shsurf->popup.grab.interface = &popup_grab_interface;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001606
Pekka Paalanen938269a2012-02-07 14:19:01 +02001607 weston_surface_update_transform(parent);
1608 if (parent->transform.enabled) {
1609 shsurf->popup.parent_transform.matrix =
1610 parent->transform.matrix;
1611 } else {
1612 /* construct x, y translation matrix */
1613 weston_matrix_init(&shsurf->popup.parent_transform.matrix);
1614 shsurf->popup.parent_transform.matrix.d[12] =
1615 parent->geometry.x;
1616 shsurf->popup.parent_transform.matrix.d[13] =
1617 parent->geometry.y;
1618 }
1619 wl_list_insert(es->geometry.transformation_list.prev,
1620 &shsurf->popup.parent_transform.link);
Pekka Paalanen8fb8d3b2012-02-13 13:03:59 +02001621 weston_surface_set_position(es, shsurf->popup.x, shsurf->popup.y);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001622
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001623 shsurf->popup.initial_up = 0;
1624
Kristian Høgsberg3730f362012-04-13 12:40:07 -04001625 /* We don't require the grab to still be active, but if another
1626 * grab has started in the meantime, we end the popup now. */
Daniel Stone37816df2012-05-16 18:45:18 +01001627 if (seat->pointer->grab_serial == shsurf->popup.serial) {
1628 wl_pointer_start_grab(seat->pointer, &shsurf->popup.grab);
Kristian Høgsberg3730f362012-04-13 12:40:07 -04001629 } else {
1630 wl_shell_surface_send_popup_done(&shsurf->resource);
1631 }
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001632}
1633
1634static void
1635shell_surface_set_popup(struct wl_client *client,
1636 struct wl_resource *resource,
Daniel Stone37816df2012-05-16 18:45:18 +01001637 struct wl_resource *seat_resource,
Kristian Høgsberg3730f362012-04-13 12:40:07 -04001638 uint32_t serial,
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001639 struct wl_resource *parent_resource,
1640 int32_t x, int32_t y, uint32_t flags)
1641{
1642 struct shell_surface *shsurf = resource->data;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001643
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001644 shsurf->type = SHELL_SURFACE_POPUP;
1645 shsurf->parent = parent_resource->data;
Daniel Stone37816df2012-05-16 18:45:18 +01001646 shsurf->popup.seat = seat_resource->data;
Kristian Høgsberg3730f362012-04-13 12:40:07 -04001647 shsurf->popup.serial = serial;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001648 shsurf->popup.x = x;
1649 shsurf->popup.y = y;
1650}
1651
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001652static const struct wl_shell_surface_interface shell_surface_implementation = {
Scott Moreauff1db4a2012-04-17 19:06:18 -06001653 shell_surface_pong,
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001654 shell_surface_move,
1655 shell_surface_resize,
1656 shell_surface_set_toplevel,
1657 shell_surface_set_transient,
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001658 shell_surface_set_fullscreen,
Juan Zhao96879df2012-02-07 08:45:41 +08001659 shell_surface_set_popup,
Kristian Høgsberge7afd912012-05-02 09:47:44 -04001660 shell_surface_set_maximized,
1661 shell_surface_set_title,
1662 shell_surface_set_class
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001663};
1664
1665static void
Tiago Vignattibc052c92012-04-19 16:18:18 +03001666destroy_shell_surface(struct shell_surface *shsurf)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001667{
Daniel Stone37816df2012-05-16 18:45:18 +01001668 if (shsurf->popup.grab.pointer)
1669 wl_pointer_end_grab(shsurf->popup.grab.pointer);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001670
Alex Wubd3354b2012-04-17 17:20:49 +08001671 if (shsurf->fullscreen.type == WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER &&
1672 shell_surface_is_top_fullscreen(shsurf)) {
1673 weston_output_switch_mode(shsurf->fullscreen_output,
1674 shsurf->fullscreen_output->origin);
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03001675 }
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001676
Alex Wuaa08e2d2012-03-05 11:01:40 +08001677 if (shsurf->fullscreen.black_surface)
1678 weston_surface_destroy(shsurf->fullscreen.black_surface);
1679
Alex Wubd3354b2012-04-17 17:20:49 +08001680 /* As destroy_resource() use wl_list_for_each_safe(),
1681 * we can always remove the listener.
1682 */
1683 wl_list_remove(&shsurf->surface_destroy_listener.link);
1684 shsurf->surface->configure = NULL;
Scott Moreau9521d5e2012-04-19 13:06:17 -06001685 ping_timer_destroy(shsurf);
Alex Wubd3354b2012-04-17 17:20:49 +08001686
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001687 wl_list_remove(&shsurf->link);
1688 free(shsurf);
1689}
1690
1691static void
Tiago Vignattibc052c92012-04-19 16:18:18 +03001692shell_destroy_shell_surface(struct wl_resource *resource)
1693{
1694 struct shell_surface *shsurf = resource->data;
1695
1696 destroy_shell_surface(shsurf);
1697}
1698
1699static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001700shell_handle_surface_destroy(struct wl_listener *listener, void *data)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001701{
1702 struct shell_surface *shsurf = container_of(listener,
1703 struct shell_surface,
1704 surface_destroy_listener);
1705
Kristian Høgsberg633b1452012-06-07 18:08:47 -04001706 if (shsurf->resource.client) {
Tiago Vignattibc052c92012-04-19 16:18:18 +03001707 wl_resource_destroy(&shsurf->resource);
Kristian Høgsberg633b1452012-06-07 18:08:47 -04001708 } else {
1709 wl_signal_emit(&shsurf->resource.destroy_signal,
1710 &shsurf->resource);
Tiago Vignattibc052c92012-04-19 16:18:18 +03001711 destroy_shell_surface(shsurf);
Kristian Høgsberg633b1452012-06-07 18:08:47 -04001712 }
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001713}
1714
Kristian Høgsbergd8134452012-06-21 12:49:02 -04001715static void
1716shell_surface_configure(struct weston_surface *, int32_t, int32_t);
1717
Pekka Paalanenec2b32f2011-11-28 15:12:34 +02001718static struct shell_surface *
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001719get_shell_surface(struct weston_surface *surface)
Pekka Paalanenec2b32f2011-11-28 15:12:34 +02001720{
Kristian Høgsbergd8134452012-06-21 12:49:02 -04001721 if (surface->configure == shell_surface_configure)
1722 return surface->private;
1723 else
1724 return NULL;
Pekka Paalanenec2b32f2011-11-28 15:12:34 +02001725}
1726
Kristian Høgsberg45ba8692012-05-21 14:27:33 -04001727static struct shell_surface *
Kristian Høgsberga61ca062012-05-22 16:05:52 -04001728create_shell_surface(void *shell, struct weston_surface *surface,
1729 const struct weston_shell_client *client)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001730{
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001731 struct shell_surface *shsurf;
1732
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03001733 if (surface->configure) {
Martin Minarik6d118362012-06-07 18:01:59 +02001734 weston_log("surface->configure already set\n");
Kristian Høgsberg45ba8692012-05-21 14:27:33 -04001735 return NULL;
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03001736 }
1737
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001738 shsurf = calloc(1, sizeof *shsurf);
1739 if (!shsurf) {
Martin Minarik6d118362012-06-07 18:01:59 +02001740 weston_log("no memory to allocate shell surface\n");
Kristian Høgsberg45ba8692012-05-21 14:27:33 -04001741 return NULL;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001742 }
1743
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03001744 surface->configure = shell_surface_configure;
Kristian Høgsbergd8134452012-06-21 12:49:02 -04001745 surface->private = shsurf;
Tiago Vignattibc052c92012-04-19 16:18:18 +03001746 surface->compositor->shell_interface.shell = shell;
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03001747
Tiago Vignattibc052c92012-04-19 16:18:18 +03001748 shsurf->shell = (struct desktop_shell *) shell;
Scott Moreauff1db4a2012-04-17 19:06:18 -06001749 shsurf->unresponsive = 0;
Alex Wu4539b082012-03-01 12:57:46 +08001750 shsurf->saved_position_valid = false;
Alex Wu7bcb8bd2012-04-27 09:07:24 +08001751 shsurf->saved_rotation_valid = false;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001752 shsurf->surface = surface;
Alex Wu4539b082012-03-01 12:57:46 +08001753 shsurf->fullscreen.type = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT;
1754 shsurf->fullscreen.framerate = 0;
1755 shsurf->fullscreen.black_surface = NULL;
Scott Moreauff1db4a2012-04-17 19:06:18 -06001756 shsurf->ping_timer = NULL;
Alex Wu4539b082012-03-01 12:57:46 +08001757 wl_list_init(&shsurf->fullscreen.transform.link);
1758
Tiago Vignattibc052c92012-04-19 16:18:18 +03001759 wl_signal_init(&shsurf->resource.destroy_signal);
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001760 shsurf->surface_destroy_listener.notify = shell_handle_surface_destroy;
1761 wl_signal_add(&surface->surface.resource.destroy_signal,
1762 &shsurf->surface_destroy_listener);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001763
1764 /* init link so its safe to always remove it in destroy_shell_surface */
1765 wl_list_init(&shsurf->link);
1766
Pekka Paalanen460099f2012-01-20 16:48:25 +02001767 /* empty when not in use */
1768 wl_list_init(&shsurf->rotation.transform.link);
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05001769 weston_matrix_init(&shsurf->rotation.rotation);
Pekka Paalanen460099f2012-01-20 16:48:25 +02001770
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001771 wl_list_init(&shsurf->workspace_transform.link);
1772
Pekka Paalanen98262232011-12-01 10:42:22 +02001773 shsurf->type = SHELL_SURFACE_NONE;
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001774 shsurf->next_type = SHELL_SURFACE_NONE;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001775
Kristian Høgsberga61ca062012-05-22 16:05:52 -04001776 shsurf->client = client;
1777
Kristian Høgsberg45ba8692012-05-21 14:27:33 -04001778 return shsurf;
Tiago Vignattibc052c92012-04-19 16:18:18 +03001779}
1780
1781static void
1782shell_get_shell_surface(struct wl_client *client,
1783 struct wl_resource *resource,
1784 uint32_t id,
1785 struct wl_resource *surface_resource)
1786{
1787 struct weston_surface *surface = surface_resource->data;
1788 struct desktop_shell *shell = resource->data;
1789 struct shell_surface *shsurf;
1790
1791 if (get_shell_surface(surface)) {
1792 wl_resource_post_error(surface_resource,
Kristian Høgsberg9540ea62012-05-21 14:28:57 -04001793 WL_DISPLAY_ERROR_INVALID_OBJECT,
1794 "desktop_shell::get_shell_surface already requested");
Tiago Vignattibc052c92012-04-19 16:18:18 +03001795 return;
1796 }
1797
Kristian Høgsberga61ca062012-05-22 16:05:52 -04001798 shsurf = create_shell_surface(shell, surface, &shell_client);
Kristian Høgsberg9540ea62012-05-21 14:28:57 -04001799 if (!shsurf) {
1800 wl_resource_post_error(surface_resource,
1801 WL_DISPLAY_ERROR_INVALID_OBJECT,
1802 "surface->configure already set");
1803 return;
1804 }
Tiago Vignattibc052c92012-04-19 16:18:18 +03001805
Kristian Høgsberg9540ea62012-05-21 14:28:57 -04001806 shsurf->resource.destroy = shell_destroy_shell_surface;
1807 shsurf->resource.object.id = id;
1808 shsurf->resource.object.interface = &wl_shell_surface_interface;
1809 shsurf->resource.object.implementation =
1810 (void (**)(void)) &shell_surface_implementation;
1811 shsurf->resource.data = shsurf;
Tiago Vignattibc052c92012-04-19 16:18:18 +03001812
Kristian Høgsberg9540ea62012-05-21 14:28:57 -04001813 wl_client_add_resource(client, &shsurf->resource);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001814}
1815
1816static const struct wl_shell_interface shell_implementation = {
Pekka Paalanen46229672011-11-29 15:49:31 +02001817 shell_get_shell_surface
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001818};
1819
Kristian Høgsberg07937562011-04-12 17:25:42 -04001820static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001821handle_screensaver_sigchld(struct weston_process *proc, int status)
Pekka Paalanen18027e52011-12-02 16:31:49 +02001822{
1823 proc->pid = 0;
1824}
1825
1826static void
Tiago Vignattibe143262012-04-16 17:31:41 +03001827launch_screensaver(struct desktop_shell *shell)
Pekka Paalanen77346a62011-11-30 16:26:35 +02001828{
1829 if (shell->screensaver.binding)
1830 return;
1831
Pekka Paalanene955f1e2011-12-07 11:49:52 +02001832 if (!shell->screensaver.path)
1833 return;
1834
Kristian Høgsberg32bed572012-03-01 17:11:36 -05001835 if (shell->screensaver.process.pid != 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001836 weston_log("old screensaver still running\n");
Kristian Høgsberg32bed572012-03-01 17:11:36 -05001837 return;
1838 }
1839
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001840 weston_client_launch(shell->compositor,
Pekka Paalanen18027e52011-12-02 16:31:49 +02001841 &shell->screensaver.process,
Pekka Paalanene955f1e2011-12-07 11:49:52 +02001842 shell->screensaver.path,
Pekka Paalanen18027e52011-12-02 16:31:49 +02001843 handle_screensaver_sigchld);
Pekka Paalanen77346a62011-11-30 16:26:35 +02001844}
1845
1846static void
Tiago Vignattibe143262012-04-16 17:31:41 +03001847terminate_screensaver(struct desktop_shell *shell)
Pekka Paalanen77346a62011-11-30 16:26:35 +02001848{
Pekka Paalanen18027e52011-12-02 16:31:49 +02001849 if (shell->screensaver.process.pid == 0)
1850 return;
1851
1852 kill(shell->screensaver.process.pid, SIGTERM);
Pekka Paalanen77346a62011-11-30 16:26:35 +02001853}
1854
1855static void
Tiago Vignattibe143262012-04-16 17:31:41 +03001856show_screensaver(struct desktop_shell *shell, struct shell_surface *surface)
Pekka Paalanen77346a62011-11-30 16:26:35 +02001857{
1858 struct wl_list *list;
1859
1860 if (shell->lock_surface)
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05001861 list = &shell->lock_surface->surface->layer_link;
Pekka Paalanen77346a62011-11-30 16:26:35 +02001862 else
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05001863 list = &shell->lock_layer.surface_list;
Pekka Paalanen77346a62011-11-30 16:26:35 +02001864
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05001865 wl_list_remove(&surface->surface->layer_link);
1866 wl_list_insert(list, &surface->surface->layer_link);
Pekka Paalanen77346a62011-11-30 16:26:35 +02001867 surface->surface->output = surface->output;
Pekka Paalanenfc6d91a2012-02-10 15:33:10 +02001868 weston_surface_damage(surface->surface);
Pekka Paalanen77346a62011-11-30 16:26:35 +02001869}
1870
1871static void
Tiago Vignattibe143262012-04-16 17:31:41 +03001872hide_screensaver(struct desktop_shell *shell, struct shell_surface *surface)
Pekka Paalanen77346a62011-11-30 16:26:35 +02001873{
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05001874 wl_list_remove(&surface->surface->layer_link);
1875 wl_list_init(&surface->surface->layer_link);
Pekka Paalanen77346a62011-11-30 16:26:35 +02001876 surface->surface->output = NULL;
1877}
1878
1879static void
Jan Arne Petersen42feced2012-06-21 21:52:17 +02001880show_input_panel(struct desktop_shell *shell, struct shell_surface *surface)
1881{
Kristian Høgsberg1ce6a2a2012-06-21 22:34:39 -04001882 if (weston_surface_is_mapped(surface->surface))
1883 return;
1884
Jan Arne Petersen42feced2012-06-21 21:52:17 +02001885 wl_list_remove(&surface->surface->layer_link);
1886 wl_list_insert(&shell->panel_layer.surface_list, &surface->surface->layer_link);
1887 surface->surface->output = surface->output;
1888 weston_surface_damage(surface->surface);
Kristian Høgsberg414bd422012-06-21 22:07:30 -04001889
Kristian Høgsberg1ce6a2a2012-06-21 22:34:39 -04001890 weston_slide_run(surface->surface,
1891 surface->surface->geometry.height, 0,
1892 NULL, NULL);
Jan Arne Petersen42feced2012-06-21 21:52:17 +02001893}
1894
1895static void
1896hide_input_panel(struct desktop_shell *shell, struct shell_surface *surface)
1897{
1898 weston_surface_damage_below(surface->surface);
1899 wl_list_remove(&surface->surface->layer_link);
1900 wl_list_init(&surface->surface->layer_link);
1901 surface->surface->output = NULL;
1902
1903 weston_compositor_schedule_repaint(surface->surface->compositor);
1904}
1905
1906static void
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001907configure_static_surface(struct weston_surface *es, struct weston_layer *layer)
Kristian Høgsberg962342c2012-06-26 16:29:50 -04001908{
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001909 struct weston_surface *s, *next;
Kristian Høgsberg962342c2012-06-26 16:29:50 -04001910
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001911 wl_list_for_each_safe(s, next, &layer->surface_list, layer_link) {
1912 if (s->output == es->output && s != es) {
1913 weston_surface_unmap(s);
Kristian Høgsberg962342c2012-06-26 16:29:50 -04001914 s->configure = NULL;
Kristian Høgsberg962342c2012-06-26 16:29:50 -04001915 }
1916 }
1917
1918 weston_surface_configure(es, es->output->x, es->output->y,
1919 es->buffer->width, es->buffer->height);
1920
1921 if (wl_list_empty(&es->layer_link)) {
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001922 wl_list_insert(&layer->surface_list, &es->layer_link);
Kristian Høgsberg962342c2012-06-26 16:29:50 -04001923 weston_surface_assign_output(es);
1924 }
1925}
1926
1927static void
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001928background_configure(struct weston_surface *es, int32_t sx, int32_t sy)
1929{
1930 struct desktop_shell *shell = es->private;
1931
1932 configure_static_surface(es, &shell->background_layer);
1933}
1934
1935static void
Kristian Høgsberg75840622011-09-06 13:48:16 -04001936desktop_shell_set_background(struct wl_client *client,
1937 struct wl_resource *resource,
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01001938 struct wl_resource *output_resource,
Kristian Høgsberg75840622011-09-06 13:48:16 -04001939 struct wl_resource *surface_resource)
1940{
Kristian Høgsberg962342c2012-06-26 16:29:50 -04001941 struct desktop_shell *shell = resource->data;
1942 struct weston_surface *surface = surface_resource->data;
Kristian Høgsberg75840622011-09-06 13:48:16 -04001943
Kristian Høgsberg962342c2012-06-26 16:29:50 -04001944 if (surface->configure) {
1945 wl_resource_post_error(surface_resource,
1946 WL_DISPLAY_ERROR_INVALID_OBJECT,
1947 "surface role already assigned");
1948 return;
1949 }
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01001950
Kristian Høgsberg962342c2012-06-26 16:29:50 -04001951 surface->configure = background_configure;
1952 surface->private = shell;
1953 surface->output = output_resource->data;
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001954 desktop_shell_send_configure(resource, 0,
Kristian Høgsberg0b5cd0c2012-03-04 21:57:37 -05001955 surface_resource,
Kristian Høgsberg962342c2012-06-26 16:29:50 -04001956 surface->output->current->width,
1957 surface->output->current->height);
Kristian Høgsberg75840622011-09-06 13:48:16 -04001958}
1959
1960static void
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001961panel_configure(struct weston_surface *es, int32_t sx, int32_t sy)
1962{
1963 struct desktop_shell *shell = es->private;
1964
1965 configure_static_surface(es, &shell->panel_layer);
1966}
1967
1968static void
Kristian Høgsberg75840622011-09-06 13:48:16 -04001969desktop_shell_set_panel(struct wl_client *client,
1970 struct wl_resource *resource,
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01001971 struct wl_resource *output_resource,
Kristian Høgsberg75840622011-09-06 13:48:16 -04001972 struct wl_resource *surface_resource)
1973{
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001974 struct desktop_shell *shell = resource->data;
1975 struct weston_surface *surface = surface_resource->data;
Kristian Høgsberg75840622011-09-06 13:48:16 -04001976
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001977 if (surface->configure) {
1978 wl_resource_post_error(surface_resource,
1979 WL_DISPLAY_ERROR_INVALID_OBJECT,
1980 "surface role already assigned");
1981 return;
1982 }
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01001983
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001984 surface->configure = panel_configure;
1985 surface->private = shell;
1986 surface->output = output_resource->data;
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001987 desktop_shell_send_configure(resource, 0,
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001988 surface_resource,
1989 surface->output->current->width,
1990 surface->output->current->height);
Kristian Høgsberg75840622011-09-06 13:48:16 -04001991}
1992
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001993static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001994handle_lock_surface_destroy(struct wl_listener *listener, void *data)
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001995{
Tiago Vignattibe143262012-04-16 17:31:41 +03001996 struct desktop_shell *shell =
1997 container_of(listener, struct desktop_shell, lock_surface_listener);
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001998
Martin Minarik6d118362012-06-07 18:01:59 +02001999 weston_log("lock surface gone\n");
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05002000 shell->lock_surface = NULL;
2001}
2002
2003static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002004desktop_shell_set_lock_surface(struct wl_client *client,
2005 struct wl_resource *resource,
2006 struct wl_resource *surface_resource)
2007{
Tiago Vignattibe143262012-04-16 17:31:41 +03002008 struct desktop_shell *shell = resource->data;
Pekka Paalanen98262232011-12-01 10:42:22 +02002009 struct shell_surface *surface = surface_resource->data;
2010
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002011 shell->prepare_event_sent = false;
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +02002012
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002013 if (!shell->locked)
2014 return;
2015
Pekka Paalanen98262232011-12-01 10:42:22 +02002016 shell->lock_surface = surface;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002017
Kristian Høgsberg27e30522012-04-11 23:18:23 -04002018 shell->lock_surface_listener.notify = handle_lock_surface_destroy;
2019 wl_signal_add(&surface_resource->destroy_signal,
2020 &shell->lock_surface_listener);
Pekka Paalanen57da4a82011-11-23 16:42:16 +02002021
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04002022 shell->lock_surface->next_type = SHELL_SURFACE_LOCK;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002023}
2024
2025static void
Tiago Vignattibe143262012-04-16 17:31:41 +03002026resume_desktop(struct desktop_shell *shell)
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002027{
Pekka Paalanen77346a62011-11-30 16:26:35 +02002028 struct shell_surface *tmp;
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04002029 struct workspace *ws = get_current_workspace(shell);
Pekka Paalanen77346a62011-11-30 16:26:35 +02002030
2031 wl_list_for_each(tmp, &shell->screensaver.surfaces, link)
2032 hide_screensaver(shell, tmp);
2033
2034 terminate_screensaver(shell);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002035
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002036 wl_list_remove(&shell->lock_layer.link);
2037 wl_list_insert(&shell->compositor->cursor_layer.link,
2038 &shell->fullscreen_layer.link);
2039 wl_list_insert(&shell->fullscreen_layer.link,
2040 &shell->panel_layer.link);
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04002041 wl_list_insert(&shell->panel_layer.link, &ws->layer.link);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002042
Jonas Ådahl04769742012-06-13 00:01:24 +02002043 pop_focus_state(shell, get_current_workspace(shell));
2044
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002045 shell->locked = false;
Pekka Paalanen7296e792011-12-07 16:22:00 +02002046 shell->compositor->idle_time = shell->compositor->option_idle_time;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002047 weston_compositor_wake(shell->compositor);
Pekka Paalanenfc6d91a2012-02-10 15:33:10 +02002048 weston_compositor_damage_all(shell->compositor);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002049}
2050
2051static void
2052desktop_shell_unlock(struct wl_client *client,
2053 struct wl_resource *resource)
2054{
Tiago Vignattibe143262012-04-16 17:31:41 +03002055 struct desktop_shell *shell = resource->data;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002056
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002057 shell->prepare_event_sent = false;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002058
2059 if (shell->locked)
2060 resume_desktop(shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002061}
2062
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04002063static void
2064desktop_shell_set_busy_surface(struct wl_client *client,
2065 struct wl_resource *resource,
2066 struct wl_resource *surface_resource)
2067{
2068 struct desktop_shell *shell = resource->data;
2069
2070 shell->busy_surface = surface_resource->data;
2071}
2072
Kristian Høgsberg75840622011-09-06 13:48:16 -04002073static const struct desktop_shell_interface desktop_shell_implementation = {
2074 desktop_shell_set_background,
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002075 desktop_shell_set_panel,
2076 desktop_shell_set_lock_surface,
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04002077 desktop_shell_unlock,
2078 desktop_shell_set_busy_surface
Kristian Høgsberg75840622011-09-06 13:48:16 -04002079};
2080
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02002081static enum shell_surface_type
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002082get_shell_surface_type(struct weston_surface *surface)
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02002083{
2084 struct shell_surface *shsurf;
2085
2086 shsurf = get_shell_surface(surface);
2087 if (!shsurf)
Pekka Paalanen98262232011-12-01 10:42:22 +02002088 return SHELL_SURFACE_NONE;
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02002089 return shsurf->type;
2090}
2091
Kristian Høgsberg75840622011-09-06 13:48:16 -04002092static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002093move_binding(struct wl_seat *seat, uint32_t time, uint32_t button, void *data)
Kristian Høgsberg07937562011-04-12 17:25:42 -04002094{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002095 struct weston_surface *surface =
Daniel Stone37816df2012-05-16 18:45:18 +01002096 (struct weston_surface *) seat->pointer->focus;
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04002097 struct shell_surface *shsurf;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -05002098
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01002099 if (surface == NULL)
2100 return;
Kristian Høgsberg07937562011-04-12 17:25:42 -04002101
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04002102 shsurf = get_shell_surface(surface);
2103 if (shsurf == NULL)
2104 return;
2105
2106 switch (shsurf->type) {
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01002107 case SHELL_SURFACE_FULLSCREEN:
Pekka Paalanen77346a62011-11-30 16:26:35 +02002108 case SHELL_SURFACE_SCREENSAVER:
Kristian Høgsberga4a4de42012-06-21 16:46:14 -04002109 case SHELL_SURFACE_INPUT_PANEL:
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01002110 return;
2111 default:
2112 break;
2113 }
Kristian Høgsberg10f097e2011-04-13 11:52:54 -04002114
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04002115 surface_move(shsurf, (struct weston_seat *) seat);
Kristian Høgsberg07937562011-04-12 17:25:42 -04002116}
2117
2118static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002119resize_binding(struct wl_seat *seat, uint32_t time, uint32_t button, void *data)
Kristian Høgsberg07937562011-04-12 17:25:42 -04002120{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002121 struct weston_surface *surface =
Daniel Stone37816df2012-05-16 18:45:18 +01002122 (struct weston_surface *) seat->pointer->focus;
Kristian Høgsberg07937562011-04-12 17:25:42 -04002123 uint32_t edges = 0;
2124 int32_t x, y;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002125 struct shell_surface *shsurf;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -05002126
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01002127 if (surface == NULL)
2128 return;
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02002129
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002130 shsurf = get_shell_surface(surface);
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02002131 if (!shsurf)
2132 return;
2133
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002134 switch (shsurf->type) {
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01002135 case SHELL_SURFACE_FULLSCREEN:
Pekka Paalanen77346a62011-11-30 16:26:35 +02002136 case SHELL_SURFACE_SCREENSAVER:
Kristian Høgsberga4a4de42012-06-21 16:46:14 -04002137 case SHELL_SURFACE_INPUT_PANEL:
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01002138 return;
2139 default:
2140 break;
2141 }
Kristian Høgsberg10f097e2011-04-13 11:52:54 -04002142
Pekka Paalanen5c97ae72012-01-30 16:19:47 +02002143 weston_surface_from_global(surface,
Daniel Stone37816df2012-05-16 18:45:18 +01002144 wl_fixed_to_int(seat->pointer->grab_x),
2145 wl_fixed_to_int(seat->pointer->grab_y),
Daniel Stone103db7f2012-05-08 17:17:55 +01002146 &x, &y);
Kristian Høgsberg07937562011-04-12 17:25:42 -04002147
Pekka Paalanen60921e52012-01-25 15:55:43 +02002148 if (x < surface->geometry.width / 3)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002149 edges |= WL_SHELL_SURFACE_RESIZE_LEFT;
Pekka Paalanen60921e52012-01-25 15:55:43 +02002150 else if (x < 2 * surface->geometry.width / 3)
Kristian Høgsberg07937562011-04-12 17:25:42 -04002151 edges |= 0;
2152 else
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002153 edges |= WL_SHELL_SURFACE_RESIZE_RIGHT;
Kristian Høgsberg07937562011-04-12 17:25:42 -04002154
Pekka Paalanen60921e52012-01-25 15:55:43 +02002155 if (y < surface->geometry.height / 3)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002156 edges |= WL_SHELL_SURFACE_RESIZE_TOP;
Pekka Paalanen60921e52012-01-25 15:55:43 +02002157 else if (y < 2 * surface->geometry.height / 3)
Kristian Høgsberg07937562011-04-12 17:25:42 -04002158 edges |= 0;
2159 else
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002160 edges |= WL_SHELL_SURFACE_RESIZE_BOTTOM;
Kristian Høgsberg07937562011-04-12 17:25:42 -04002161
Kristian Høgsbergc1693f22012-05-22 16:56:23 -04002162 surface_resize(shsurf, (struct weston_seat *) seat, edges);
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04002163}
2164
2165static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002166surface_opacity_binding(struct wl_seat *seat, uint32_t time, uint32_t axis,
Daniel Stone0c1e46e2012-05-30 16:31:59 +01002167 wl_fixed_t value, void *data)
Scott Moreaua3aa9c92012-03-22 11:01:03 -06002168{
Scott Moreau02709af2012-05-22 01:54:10 -06002169 float step = 0.05;
Scott Moreaua3aa9c92012-03-22 11:01:03 -06002170 struct shell_surface *shsurf;
2171 struct weston_surface *surface =
Daniel Stone37816df2012-05-16 18:45:18 +01002172 (struct weston_surface *) seat->pointer->focus;
Scott Moreaua3aa9c92012-03-22 11:01:03 -06002173
2174 if (surface == NULL)
2175 return;
2176
2177 shsurf = get_shell_surface(surface);
2178 if (!shsurf)
2179 return;
2180
2181 switch (shsurf->type) {
Scott Moreaua3aa9c92012-03-22 11:01:03 -06002182 case SHELL_SURFACE_SCREENSAVER:
2183 return;
2184 default:
2185 break;
2186 }
2187
Daniel Stone0c1e46e2012-05-30 16:31:59 +01002188 surface->alpha += wl_fixed_to_double(value) * step;
Scott Moreaua3aa9c92012-03-22 11:01:03 -06002189
Scott Moreau02709af2012-05-22 01:54:10 -06002190 if (surface->alpha > 1.0)
2191 surface->alpha = 1.0;
Scott Moreaua3aa9c92012-03-22 11:01:03 -06002192 if (surface->alpha < step)
2193 surface->alpha = step;
2194
2195 surface->geometry.dirty = 1;
2196 weston_surface_damage(surface);
2197}
2198
2199static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002200do_zoom(struct wl_seat *seat, uint32_t time, uint32_t key, uint32_t axis,
Daniel Stone0c1e46e2012-05-30 16:31:59 +01002201 wl_fixed_t value)
Scott Moreauccbf29d2012-02-22 14:21:41 -07002202{
Daniel Stone37816df2012-05-16 18:45:18 +01002203 struct weston_seat *ws = (struct weston_seat *) seat;
2204 struct weston_compositor *compositor = ws->compositor;
Scott Moreauccbf29d2012-02-22 14:21:41 -07002205 struct weston_output *output;
Scott Moreaue6603982012-06-11 13:07:51 -06002206 float increment;
Scott Moreauccbf29d2012-02-22 14:21:41 -07002207
2208 wl_list_for_each(output, &compositor->output_list, link) {
2209 if (pixman_region32_contains_point(&output->region,
Daniel Stone37816df2012-05-16 18:45:18 +01002210 wl_fixed_to_double(seat->pointer->x),
2211 wl_fixed_to_double(seat->pointer->y),
Daniel Stone103db7f2012-05-08 17:17:55 +01002212 NULL)) {
Daniel Stone325fc2d2012-05-30 16:31:58 +01002213 if (key == KEY_PAGEUP)
Kristian Høgsberg9b68af02012-05-22 12:55:18 -04002214 increment = output->zoom.increment;
Daniel Stone325fc2d2012-05-30 16:31:58 +01002215 else if (key == KEY_PAGEDOWN)
Kristian Høgsberg9b68af02012-05-22 12:55:18 -04002216 increment = -output->zoom.increment;
2217 else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
Daniel Stone0c1e46e2012-05-30 16:31:59 +01002218 increment = output->zoom.increment *
2219 wl_fixed_to_double(value);
Kristian Høgsberg9b68af02012-05-22 12:55:18 -04002220 else
2221 increment = 0;
2222
Kristian Høgsberg9b68af02012-05-22 12:55:18 -04002223 output->zoom.level += increment;
Scott Moreauc6d7f602012-02-23 22:28:37 -07002224
Scott Moreaue6603982012-06-11 13:07:51 -06002225 if (output->zoom.level < 0.0)
Scott Moreau850ca422012-05-21 15:21:25 -06002226 output->zoom.level = 0.0;
Scott Moreaue6603982012-06-11 13:07:51 -06002227 else if (output->zoom.level > output->zoom.max_level)
2228 output->zoom.level = output->zoom.max_level;
2229 else
2230 output->zoom.active = 1;
Scott Moreauccbf29d2012-02-22 14:21:41 -07002231
Scott Moreaue6603982012-06-11 13:07:51 -06002232 output->zoom.spring_z.target = output->zoom.level;
Scott Moreauccbf29d2012-02-22 14:21:41 -07002233
Scott Moreau8dacaab2012-06-17 18:10:58 -06002234 weston_output_update_zoom(output, output->zoom.type);
Scott Moreauccbf29d2012-02-22 14:21:41 -07002235 }
2236 }
2237}
2238
Scott Moreauccbf29d2012-02-22 14:21:41 -07002239static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002240zoom_axis_binding(struct wl_seat *seat, uint32_t time, uint32_t axis,
Daniel Stone0c1e46e2012-05-30 16:31:59 +01002241 wl_fixed_t value, void *data)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002242{
2243 do_zoom(seat, time, 0, axis, value);
2244}
2245
2246static void
2247zoom_key_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
2248 void *data)
2249{
2250 do_zoom(seat, time, key, 0, 0);
2251}
2252
2253static void
2254terminate_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
2255 void *data)
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05002256{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002257 struct weston_compositor *compositor = data;
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05002258
Daniel Stone325fc2d2012-05-30 16:31:58 +01002259 wl_display_terminate(compositor->wl_display);
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05002260}
2261
2262static void
Scott Moreau447013d2012-02-18 05:05:29 -07002263rotate_grab_motion(struct wl_pointer_grab *grab,
Daniel Stone103db7f2012-05-08 17:17:55 +01002264 uint32_t time, wl_fixed_t x, wl_fixed_t y)
Pekka Paalanen460099f2012-01-20 16:48:25 +02002265{
2266 struct rotate_grab *rotate =
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002267 container_of(grab, struct rotate_grab, base.grab);
Daniel Stone37816df2012-05-16 18:45:18 +01002268 struct wl_pointer *pointer = grab->pointer;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002269 struct shell_surface *shsurf = rotate->base.shsurf;
2270 struct weston_surface *surface;
2271 GLfloat cx, cy, dx, dy, cposx, cposy, dposx, dposy, r;
2272
2273 if (!shsurf)
2274 return;
2275
2276 surface = shsurf->surface;
2277
2278 cx = 0.5f * surface->geometry.width;
2279 cy = 0.5f * surface->geometry.height;
Pekka Paalanen460099f2012-01-20 16:48:25 +02002280
Daniel Stone37816df2012-05-16 18:45:18 +01002281 dx = wl_fixed_to_double(pointer->x) - rotate->center.x;
2282 dy = wl_fixed_to_double(pointer->y) - rotate->center.y;
Pekka Paalanen460099f2012-01-20 16:48:25 +02002283 r = sqrtf(dx * dx + dy * dy);
2284
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002285 wl_list_remove(&shsurf->rotation.transform.link);
2286 shsurf->surface->geometry.dirty = 1;
Pekka Paalanen460099f2012-01-20 16:48:25 +02002287
2288 if (r > 20.0f) {
Pekka Paalanen460099f2012-01-20 16:48:25 +02002289 struct weston_matrix *matrix =
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002290 &shsurf->rotation.transform.matrix;
Pekka Paalanen460099f2012-01-20 16:48:25 +02002291
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05002292 weston_matrix_init(&rotate->rotation);
2293 rotate->rotation.d[0] = dx / r;
2294 rotate->rotation.d[4] = -dy / r;
2295 rotate->rotation.d[1] = -rotate->rotation.d[4];
2296 rotate->rotation.d[5] = rotate->rotation.d[0];
Pekka Paalanen460099f2012-01-20 16:48:25 +02002297
2298 weston_matrix_init(matrix);
Pekka Paalanen7b3bd3d2012-01-30 14:16:34 +02002299 weston_matrix_translate(matrix, -cx, -cy, 0.0f);
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002300 weston_matrix_multiply(matrix, &shsurf->rotation.rotation);
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05002301 weston_matrix_multiply(matrix, &rotate->rotation);
Pekka Paalanen7b3bd3d2012-01-30 14:16:34 +02002302 weston_matrix_translate(matrix, cx, cy, 0.0f);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002303
Pekka Paalanenbc0b7e72012-01-24 09:53:37 +02002304 wl_list_insert(
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002305 &shsurf->surface->geometry.transformation_list,
2306 &shsurf->rotation.transform.link);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002307 } else {
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002308 wl_list_init(&shsurf->rotation.transform.link);
2309 weston_matrix_init(&shsurf->rotation.rotation);
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05002310 weston_matrix_init(&rotate->rotation);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002311 }
Pekka Paalanenb45ac5e2012-02-09 15:58:44 +02002312
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01002313 /* We need to adjust the position of the surface
2314 * in case it was resized in a rotated state before */
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002315 cposx = surface->geometry.x + cx;
2316 cposy = surface->geometry.y + cy;
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01002317 dposx = rotate->center.x - cposx;
2318 dposy = rotate->center.y - cposy;
2319 if (dposx != 0.0f || dposy != 0.0f) {
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002320 weston_surface_set_position(surface,
2321 surface->geometry.x + dposx,
2322 surface->geometry.y + dposy);
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01002323 }
2324
Pekka Paalanenb45ac5e2012-02-09 15:58:44 +02002325 /* Repaint implies weston_surface_update_transform(), which
2326 * lazily applies the damage due to rotation update.
2327 */
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002328 weston_compositor_schedule_repaint(shsurf->surface->compositor);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002329}
2330
2331static void
Scott Moreau447013d2012-02-18 05:05:29 -07002332rotate_grab_button(struct wl_pointer_grab *grab,
Daniel Stone4dbadb12012-05-30 16:31:51 +01002333 uint32_t time, uint32_t button, uint32_t state_w)
Pekka Paalanen460099f2012-01-20 16:48:25 +02002334{
2335 struct rotate_grab *rotate =
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002336 container_of(grab, struct rotate_grab, base.grab);
Daniel Stone37816df2012-05-16 18:45:18 +01002337 struct wl_pointer *pointer = grab->pointer;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002338 struct shell_surface *shsurf = rotate->base.shsurf;
Daniel Stone4dbadb12012-05-30 16:31:51 +01002339 enum wl_pointer_button_state state = state_w;
Pekka Paalanen460099f2012-01-20 16:48:25 +02002340
Daniel Stone4dbadb12012-05-30 16:31:51 +01002341 if (pointer->button_count == 0 &&
2342 state == WL_POINTER_BUTTON_STATE_RELEASED) {
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002343 if (shsurf)
2344 weston_matrix_multiply(&shsurf->rotation.rotation,
2345 &rotate->rotation);
2346 shell_grab_finish(&rotate->base);
Daniel Stone37816df2012-05-16 18:45:18 +01002347 wl_pointer_end_grab(pointer);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002348 free(rotate);
2349 }
2350}
2351
Scott Moreau447013d2012-02-18 05:05:29 -07002352static const struct wl_pointer_grab_interface rotate_grab_interface = {
Pekka Paalanen460099f2012-01-20 16:48:25 +02002353 noop_grab_focus,
2354 rotate_grab_motion,
2355 rotate_grab_button,
2356};
2357
2358static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002359rotate_binding(struct wl_seat *seat, uint32_t time, uint32_t button,
Daniel Stonee5a01202012-05-04 11:21:57 +01002360 void *data)
Pekka Paalanen460099f2012-01-20 16:48:25 +02002361{
2362 struct weston_surface *base_surface =
Daniel Stone37816df2012-05-16 18:45:18 +01002363 (struct weston_surface *) seat->pointer->focus;
Pekka Paalanen460099f2012-01-20 16:48:25 +02002364 struct shell_surface *surface;
2365 struct rotate_grab *rotate;
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01002366 GLfloat dx, dy;
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05002367 GLfloat r;
Pekka Paalanen460099f2012-01-20 16:48:25 +02002368
2369 if (base_surface == NULL)
2370 return;
2371
2372 surface = get_shell_surface(base_surface);
2373 if (!surface)
2374 return;
2375
2376 switch (surface->type) {
Pekka Paalanen460099f2012-01-20 16:48:25 +02002377 case SHELL_SURFACE_FULLSCREEN:
2378 case SHELL_SURFACE_SCREENSAVER:
Kristian Høgsberga4a4de42012-06-21 16:46:14 -04002379 case SHELL_SURFACE_INPUT_PANEL:
Pekka Paalanen460099f2012-01-20 16:48:25 +02002380 return;
2381 default:
2382 break;
2383 }
2384
Pekka Paalanen460099f2012-01-20 16:48:25 +02002385 rotate = malloc(sizeof *rotate);
2386 if (!rotate)
2387 return;
2388
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002389 shell_grab_init(&rotate->base, &rotate_grab_interface, surface);
Pekka Paalanene0f3cb22012-01-24 09:59:29 +02002390
Kristian Høgsbergb2af93e2012-06-07 20:10:23 -04002391 weston_surface_to_global_float(surface->surface,
2392 surface->surface->geometry.width / 2,
2393 surface->surface->geometry.height / 2,
2394 &rotate->center.x, &rotate->center.y);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002395
Daniel Stone37816df2012-05-16 18:45:18 +01002396 wl_pointer_start_grab(seat->pointer, &rotate->base.grab);
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05002397
Daniel Stone37816df2012-05-16 18:45:18 +01002398 dx = wl_fixed_to_double(seat->pointer->x) - rotate->center.x;
2399 dy = wl_fixed_to_double(seat->pointer->y) - rotate->center.y;
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05002400 r = sqrtf(dx * dx + dy * dy);
2401 if (r > 20.0f) {
2402 struct weston_matrix inverse;
2403
2404 weston_matrix_init(&inverse);
2405 inverse.d[0] = dx / r;
2406 inverse.d[4] = dy / r;
2407 inverse.d[1] = -inverse.d[4];
2408 inverse.d[5] = inverse.d[0];
2409 weston_matrix_multiply(&surface->rotation.rotation, &inverse);
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01002410
2411 weston_matrix_init(&rotate->rotation);
2412 rotate->rotation.d[0] = dx / r;
2413 rotate->rotation.d[4] = -dy / r;
2414 rotate->rotation.d[1] = -rotate->rotation.d[4];
2415 rotate->rotation.d[5] = rotate->rotation.d[0];
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05002416 } else {
2417 weston_matrix_init(&surface->rotation.rotation);
2418 weston_matrix_init(&rotate->rotation);
2419 }
2420
Daniel Stone37816df2012-05-16 18:45:18 +01002421 wl_pointer_set_focus(seat->pointer, NULL,
2422 wl_fixed_from_int(0),
2423 wl_fixed_from_int(0));
Pekka Paalanen460099f2012-01-20 16:48:25 +02002424}
2425
2426static void
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04002427lower_fullscreen_layer(struct desktop_shell *shell)
2428{
2429 struct workspace *ws;
2430 struct weston_surface *surface, *prev;
2431
2432 ws = get_current_workspace(shell);
2433 wl_list_for_each_reverse_safe(surface, prev,
2434 &shell->fullscreen_layer.surface_list,
2435 layer_link)
2436 weston_surface_restack(surface, &ws->layer.surface_list);
2437}
2438
2439static void
Tiago Vignattibe143262012-04-16 17:31:41 +03002440activate(struct desktop_shell *shell, struct weston_surface *es,
Daniel Stone37816df2012-05-16 18:45:18 +01002441 struct weston_seat *seat)
Kristian Høgsberg75840622011-09-06 13:48:16 -04002442{
Jonas Ådahle3cddce2012-06-13 00:01:22 +02002443 struct workspace *ws;
Kristian Høgsberg75840622011-09-06 13:48:16 -04002444
Daniel Stone37816df2012-05-16 18:45:18 +01002445 weston_surface_activate(es, seat);
Kristian Høgsberg75840622011-09-06 13:48:16 -04002446
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02002447 switch (get_shell_surface_type(es)) {
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002448 case SHELL_SURFACE_LOCK:
Jan Arne Petersen42feced2012-06-21 21:52:17 +02002449 case SHELL_SURFACE_INPUT_PANEL:
Pekka Paalanen57da4a82011-11-23 16:42:16 +02002450 break;
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002451
Pekka Paalanen77346a62011-11-30 16:26:35 +02002452 case SHELL_SURFACE_SCREENSAVER:
2453 /* always below lock surface */
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002454 if (shell->lock_surface)
2455 weston_surface_restack(es,
2456 &shell->lock_surface->surface->layer_link);
Pekka Paalanen77346a62011-11-30 16:26:35 +02002457 break;
Alex Wu4539b082012-03-01 12:57:46 +08002458 case SHELL_SURFACE_FULLSCREEN:
2459 /* should on top of panels */
Alex Wu21858432012-04-01 20:13:08 +08002460 shell_stack_fullscreen(get_shell_surface(es));
Alex Wubd3354b2012-04-17 17:20:49 +08002461 shell_configure_fullscreen(get_shell_surface(es));
Alex Wu4539b082012-03-01 12:57:46 +08002462 break;
Pekka Paalanen57da4a82011-11-23 16:42:16 +02002463 default:
Jonas Ådahle3cddce2012-06-13 00:01:22 +02002464 ws = get_current_workspace(shell);
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04002465 lower_fullscreen_layer(shell);
2466 weston_surface_restack(es, &ws->layer.surface_list);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002467 break;
Kristian Høgsberg75840622011-09-06 13:48:16 -04002468 }
2469}
2470
Alex Wu21858432012-04-01 20:13:08 +08002471/* no-op func for checking black surface */
2472static void
2473black_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
2474{
2475}
2476
2477static bool
2478is_black_surface (struct weston_surface *es, struct weston_surface **fs_surface)
2479{
2480 if (es->configure == black_surface_configure) {
2481 if (fs_surface)
2482 *fs_surface = (struct weston_surface *)es->private;
2483 return true;
2484 }
2485 return false;
2486}
2487
Kristian Høgsberg75840622011-09-06 13:48:16 -04002488static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002489click_to_activate_binding(struct wl_seat *seat, uint32_t time, uint32_t button,
Daniel Stone4dbadb12012-05-30 16:31:51 +01002490 void *data)
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05002491{
Daniel Stone37816df2012-05-16 18:45:18 +01002492 struct weston_seat *ws = (struct weston_seat *) seat;
Tiago Vignattibe143262012-04-16 17:31:41 +03002493 struct desktop_shell *shell = data;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002494 struct weston_surface *focus;
Alex Wu4539b082012-03-01 12:57:46 +08002495 struct weston_surface *upper;
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05002496
Daniel Stone37816df2012-05-16 18:45:18 +01002497 focus = (struct weston_surface *) seat->pointer->focus;
Alex Wu9c35e6b2012-03-05 14:13:13 +08002498 if (!focus)
2499 return;
2500
Alex Wu21858432012-04-01 20:13:08 +08002501 if (is_black_surface(focus, &upper))
Alex Wu4539b082012-03-01 12:57:46 +08002502 focus = upper;
Alex Wu4539b082012-03-01 12:57:46 +08002503
Kristian Høgsberg85b2e4b2012-06-21 16:49:42 -04002504 switch (get_shell_surface_type(focus)) {
Kristian Høgsberg85b2e4b2012-06-21 16:49:42 -04002505 case SHELL_SURFACE_SCREENSAVER:
2506 case SHELL_SURFACE_INPUT_PANEL:
2507 return;
2508 default:
2509 break;
2510 }
2511
Daniel Stone325fc2d2012-05-30 16:31:58 +01002512 if (seat->pointer->grab == &seat->pointer->default_grab)
Daniel Stone37816df2012-05-16 18:45:18 +01002513 activate(shell, focus, ws);
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05002514}
2515
2516static void
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04002517lock(struct wl_listener *listener, void *data)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04002518{
Tiago Vignattibe143262012-04-16 17:31:41 +03002519 struct desktop_shell *shell =
2520 container_of(listener, struct desktop_shell, lock_listener);
Pekka Paalanen77346a62011-11-30 16:26:35 +02002521 struct shell_surface *shsurf;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002522 struct weston_output *output;
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04002523 struct workspace *ws = get_current_workspace(shell);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002524
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002525 if (shell->locked) {
2526 wl_list_for_each(output, &shell->compositor->output_list, link)
2527 /* TODO: find a way to jump to other DPMS levels */
2528 if (output->set_dpms)
2529 output->set_dpms(output, WESTON_DPMS_STANDBY);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002530 return;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002531 }
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002532
2533 shell->locked = true;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002534
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002535 /* Hide all surfaces by removing the fullscreen, panel and
2536 * toplevel layers. This way nothing else can show or receive
2537 * input events while we are locked. */
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002538
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002539 wl_list_remove(&shell->panel_layer.link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002540 wl_list_remove(&shell->fullscreen_layer.link);
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04002541 wl_list_remove(&ws->layer.link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002542 wl_list_insert(&shell->compositor->cursor_layer.link,
2543 &shell->lock_layer.link);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002544
Pekka Paalanen77346a62011-11-30 16:26:35 +02002545 launch_screensaver(shell);
2546
2547 wl_list_for_each(shsurf, &shell->screensaver.surfaces, link)
2548 show_screensaver(shell, shsurf);
2549
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002550 if (!wl_list_empty(&shell->screensaver.surfaces)) {
Pekka Paalanen7296e792011-12-07 16:22:00 +02002551 shell->compositor->idle_time = shell->screensaver.duration;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002552 weston_compositor_wake(shell->compositor);
2553 shell->compositor->state = WESTON_COMPOSITOR_IDLE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002554 }
Pekka Paalanenbaeb6a12011-12-01 16:23:57 +02002555
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002556 /* reset pointer foci */
Kristian Høgsbergaa6019e2012-03-11 16:35:16 -04002557 weston_compositor_schedule_repaint(shell->compositor);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002558
Jonas Ådahl04769742012-06-13 00:01:24 +02002559 /* stash keyboard foci in current workspace */
2560 push_focus_state(shell, get_current_workspace(shell));
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002561
2562 /* TODO: disable bindings that should not work while locked. */
2563
2564 /* All this must be undone in resume_desktop(). */
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002565}
2566
2567static void
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04002568unlock(struct wl_listener *listener, void *data)
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002569{
Tiago Vignattibe143262012-04-16 17:31:41 +03002570 struct desktop_shell *shell =
2571 container_of(listener, struct desktop_shell, unlock_listener);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002572
Pekka Paalanend81c2162011-11-16 13:47:34 +02002573 if (!shell->locked || shell->lock_surface) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002574 weston_compositor_wake(shell->compositor);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002575 return;
2576 }
2577
2578 /* If desktop-shell client has gone away, unlock immediately. */
2579 if (!shell->child.desktop_shell) {
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002580 resume_desktop(shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002581 return;
2582 }
2583
2584 if (shell->prepare_event_sent)
2585 return;
2586
Kristian Høgsberg0b5cd0c2012-03-04 21:57:37 -05002587 desktop_shell_send_prepare_lock_surface(shell->child.desktop_shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002588 shell->prepare_event_sent = true;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04002589}
2590
2591static void
Jan Arne Petersen42feced2012-06-21 21:52:17 +02002592show_input_panels(struct wl_listener *listener, void *data)
2593{
2594 struct desktop_shell *shell =
2595 container_of(listener, struct desktop_shell, show_input_panel_listener);
2596 struct shell_surface *priv;
2597
2598 wl_list_for_each(priv, &shell->input_panel.surfaces, link) {
2599 show_input_panel(shell, priv);
2600 }
2601}
2602
2603static void
2604hide_input_panels(struct wl_listener *listener, void *data)
2605{
2606 struct desktop_shell *shell =
2607 container_of(listener, struct desktop_shell, hide_input_panel_listener);
2608 struct shell_surface *priv;
2609
2610 wl_list_for_each(priv, &shell->input_panel.surfaces, link) {
2611 hide_input_panel(shell, priv);
2612 }
2613}
2614
2615static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002616center_on_output(struct weston_surface *surface, struct weston_output *output)
Pekka Paalanen77346a62011-11-30 16:26:35 +02002617{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002618 struct weston_mode *mode = output->current;
Pekka Paalanen8fb8d3b2012-02-13 13:03:59 +02002619 GLfloat x = (mode->width - surface->geometry.width) / 2;
2620 GLfloat y = (mode->height - surface->geometry.height) / 2;
Pekka Paalanen77346a62011-11-30 16:26:35 +02002621
Pekka Paalanen8fb8d3b2012-02-13 13:03:59 +02002622 weston_surface_set_position(surface, output->x + x, output->y + y);
Pekka Paalanen77346a62011-11-30 16:26:35 +02002623}
2624
Jan Arne Petersen42feced2012-06-21 21:52:17 +02002625
2626static void
2627bottom_center_on_output(struct weston_surface *surface, struct weston_output *output)
2628{
2629 struct weston_mode *mode = output->current;
2630 GLfloat x = (mode->width - surface->geometry.width) / 2;
2631 GLfloat y = mode->height - surface->geometry.height;
2632
2633 weston_surface_set_position(surface, output->x + x, output->y + y);
2634}
2635
Pekka Paalanen77346a62011-11-30 16:26:35 +02002636static void
Tiago Vignattibe143262012-04-16 17:31:41 +03002637map(struct desktop_shell *shell, struct weston_surface *surface,
Ander Conselvan de Oliveirae9e05152012-02-15 17:02:56 +02002638 int32_t width, int32_t height, int32_t sx, int32_t sy)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04002639{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002640 struct weston_compositor *compositor = shell->compositor;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02002641 struct shell_surface *shsurf = get_shell_surface(surface);
2642 enum shell_surface_type surface_type = shsurf->type;
Kristian Høgsberg60c49542012-03-05 20:51:34 -05002643 struct weston_surface *parent;
Daniel Stoneb2104682012-05-30 16:31:56 +01002644 struct weston_seat *seat;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02002645 struct workspace *ws;
Juan Zhao96879df2012-02-07 08:45:41 +08002646 int panel_height = 0;
Pekka Paalanen57da4a82011-11-23 16:42:16 +02002647
Pekka Paalanen60921e52012-01-25 15:55:43 +02002648 surface->geometry.width = width;
2649 surface->geometry.height = height;
2650 surface->geometry.dirty = 1;
Pekka Paalanen77346a62011-11-30 16:26:35 +02002651
2652 /* initial positioning, see also configure() */
2653 switch (surface_type) {
2654 case SHELL_SURFACE_TOPLEVEL:
Pekka Paalanen8fb8d3b2012-02-13 13:03:59 +02002655 weston_surface_set_position(surface, 10 + random() % 400,
2656 10 + random() % 400);
Pekka Paalanen77346a62011-11-30 16:26:35 +02002657 break;
2658 case SHELL_SURFACE_SCREENSAVER:
Kristian Høgsberg1cbf3262012-02-17 23:49:07 -05002659 center_on_output(surface, shsurf->fullscreen_output);
Pekka Paalanen77346a62011-11-30 16:26:35 +02002660 break;
Alex Wu4539b082012-03-01 12:57:46 +08002661 case SHELL_SURFACE_FULLSCREEN:
2662 shell_map_fullscreen(shsurf);
2663 break;
Juan Zhao96879df2012-02-07 08:45:41 +08002664 case SHELL_SURFACE_MAXIMIZED:
Alex Wu4539b082012-03-01 12:57:46 +08002665 /* use surface configure to set the geometry */
Juan Zhao96879df2012-02-07 08:45:41 +08002666 panel_height = get_output_panel_height(shell,surface->output);
2667 weston_surface_set_position(surface, surface->output->x,
2668 surface->output->y + panel_height);
2669 break;
Pekka Paalanenaf0e34c2011-12-02 10:59:17 +02002670 case SHELL_SURFACE_LOCK:
2671 center_on_output(surface, get_default_output(compositor));
2672 break;
Jan Arne Petersen42feced2012-06-21 21:52:17 +02002673 case SHELL_SURFACE_INPUT_PANEL:
2674 bottom_center_on_output(surface, get_default_output(compositor));
Kristian Høgsberg1ce6a2a2012-06-21 22:34:39 -04002675 /* Don't map the input panel here, wait for
2676 * show_input_panels signal. */
2677 return;
Tiago Vignatti0f997012012-02-10 16:17:23 +02002678 case SHELL_SURFACE_POPUP:
Kristian Høgsberg3730f362012-04-13 12:40:07 -04002679 shell_map_popup(shsurf);
Ander Conselvan de Oliveirae9e05152012-02-15 17:02:56 +02002680 case SHELL_SURFACE_NONE:
2681 weston_surface_set_position(surface,
2682 surface->geometry.x + sx,
2683 surface->geometry.y + sy);
Tiago Vignatti0f997012012-02-10 16:17:23 +02002684 break;
Pekka Paalanen77346a62011-11-30 16:26:35 +02002685 default:
2686 ;
2687 }
Kristian Høgsberg75840622011-09-06 13:48:16 -04002688
Pekka Paalanend3dd6e12011-11-16 13:47:33 +02002689 /* surface stacking order, see also activate() */
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02002690 switch (surface_type) {
Pekka Paalanen57da4a82011-11-23 16:42:16 +02002691 case SHELL_SURFACE_LOCK:
Pekka Paalanend3dd6e12011-11-16 13:47:33 +02002692 /* lock surface always visible, on top */
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002693 wl_list_insert(&shell->lock_layer.surface_list,
2694 &surface->layer_link);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002695 weston_compositor_wake(compositor);
Pekka Paalanen77346a62011-11-30 16:26:35 +02002696 break;
2697 case SHELL_SURFACE_SCREENSAVER:
2698 /* If locked, show it. */
Pekka Paalanenbaeb6a12011-12-01 16:23:57 +02002699 if (shell->locked) {
Pekka Paalanen77346a62011-11-30 16:26:35 +02002700 show_screensaver(shell, shsurf);
Pekka Paalanen7296e792011-12-07 16:22:00 +02002701 compositor->idle_time = shell->screensaver.duration;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002702 weston_compositor_wake(compositor);
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002703 if (!shell->lock_surface)
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002704 compositor->state = WESTON_COMPOSITOR_IDLE;
Pekka Paalanenbaeb6a12011-12-01 16:23:57 +02002705 }
Pekka Paalanen57da4a82011-11-23 16:42:16 +02002706 break;
Kristian Høgsberg60c49542012-03-05 20:51:34 -05002707 case SHELL_SURFACE_POPUP:
2708 case SHELL_SURFACE_TRANSIENT:
2709 parent = shsurf->parent->surface;
2710 wl_list_insert(parent->layer_link.prev, &surface->layer_link);
2711 break;
Alex Wu4539b082012-03-01 12:57:46 +08002712 case SHELL_SURFACE_FULLSCREEN:
Ander Conselvan de Oliveiraa1ff53b2012-02-15 17:02:54 +02002713 case SHELL_SURFACE_NONE:
Jan Arne Petersen42feced2012-06-21 21:52:17 +02002714 case SHELL_SURFACE_INPUT_PANEL:
Ander Conselvan de Oliveiraa1ff53b2012-02-15 17:02:54 +02002715 break;
Pekka Paalanen57da4a82011-11-23 16:42:16 +02002716 default:
Jonas Ådahle3cddce2012-06-13 00:01:22 +02002717 ws = get_current_workspace(shell);
2718 wl_list_insert(&ws->layer.surface_list, &surface->layer_link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002719 break;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002720 }
2721
Ander Conselvan de Oliveirade56c312012-03-05 15:39:23 +02002722 if (surface_type != SHELL_SURFACE_NONE) {
2723 weston_surface_assign_output(surface);
Ander Conselvan de Oliveirade56c312012-03-05 15:39:23 +02002724 if (surface_type == SHELL_SURFACE_MAXIMIZED)
2725 surface->output = shsurf->output;
2726 }
Kristian Høgsberg2f88a402011-12-04 15:32:59 -05002727
Juan Zhao7bb92f02011-12-15 11:31:51 -05002728 switch (surface_type) {
Juan Zhao7bb92f02011-12-15 11:31:51 -05002729 case SHELL_SURFACE_TRANSIENT:
Tiago Vignatti99aeb1e2012-05-23 22:06:26 +03002730 if (shsurf->transient.flags ==
2731 WL_SHELL_SURFACE_TRANSIENT_INACTIVE)
2732 break;
2733 case SHELL_SURFACE_TOPLEVEL:
Juan Zhao7bb92f02011-12-15 11:31:51 -05002734 case SHELL_SURFACE_FULLSCREEN:
Juan Zhao96879df2012-02-07 08:45:41 +08002735 case SHELL_SURFACE_MAXIMIZED:
Daniel Stoneb2104682012-05-30 16:31:56 +01002736 if (!shell->locked) {
2737 wl_list_for_each(seat, &compositor->seat_list, link)
2738 activate(shell, surface, seat);
2739 }
Juan Zhao7bb92f02011-12-15 11:31:51 -05002740 break;
2741 default:
2742 break;
2743 }
2744
Kristian Høgsberg2f88a402011-12-04 15:32:59 -05002745 if (surface_type == SHELL_SURFACE_TOPLEVEL)
Juan Zhaoe10d2792012-04-25 19:09:52 +08002746 {
2747 switch (shell->win_animation_type) {
2748 case ANIMATION_FADE:
2749 weston_fade_run(surface, NULL, NULL);
2750 break;
2751 case ANIMATION_ZOOM:
2752 weston_zoom_run(surface, 0.8, 1.0, NULL, NULL);
2753 break;
2754 default:
2755 break;
2756 }
2757 }
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05002758}
2759
2760static void
Tiago Vignattibe143262012-04-16 17:31:41 +03002761configure(struct desktop_shell *shell, struct weston_surface *surface,
Pekka Paalanenddae03c2012-02-06 14:54:20 +02002762 GLfloat x, GLfloat y, int32_t width, int32_t height)
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05002763{
Pekka Paalanen77346a62011-11-30 16:26:35 +02002764 enum shell_surface_type surface_type = SHELL_SURFACE_NONE;
2765 struct shell_surface *shsurf;
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05002766
Pekka Paalanen77346a62011-11-30 16:26:35 +02002767 shsurf = get_shell_surface(surface);
2768 if (shsurf)
2769 surface_type = shsurf->type;
2770
Kristian Høgsberg6a8b5532012-02-16 23:43:59 -05002771 surface->geometry.x = x;
2772 surface->geometry.y = y;
Pekka Paalanen60921e52012-01-25 15:55:43 +02002773 surface->geometry.width = width;
2774 surface->geometry.height = height;
2775 surface->geometry.dirty = 1;
Pekka Paalanen77346a62011-11-30 16:26:35 +02002776
2777 switch (surface_type) {
2778 case SHELL_SURFACE_SCREENSAVER:
Kristian Høgsberg1cbf3262012-02-17 23:49:07 -05002779 center_on_output(surface, shsurf->fullscreen_output);
Kristian Høgsbergd2abb832011-11-23 10:52:40 -05002780 break;
Alex Wu4539b082012-03-01 12:57:46 +08002781 case SHELL_SURFACE_FULLSCREEN:
Alex Wubd3354b2012-04-17 17:20:49 +08002782 shell_stack_fullscreen(shsurf);
Alex Wu4539b082012-03-01 12:57:46 +08002783 shell_configure_fullscreen(shsurf);
Alex Wu4539b082012-03-01 12:57:46 +08002784 break;
Juan Zhao96879df2012-02-07 08:45:41 +08002785 case SHELL_SURFACE_MAXIMIZED:
Alex Wu4539b082012-03-01 12:57:46 +08002786 /* setting x, y and using configure to change that geometry */
Kristian Høgsberg6a8b5532012-02-16 23:43:59 -05002787 surface->geometry.x = surface->output->x;
2788 surface->geometry.y = surface->output->y +
2789 get_output_panel_height(shell,surface->output);
Juan Zhao96879df2012-02-07 08:45:41 +08002790 break;
Alex Wu4539b082012-03-01 12:57:46 +08002791 case SHELL_SURFACE_TOPLEVEL:
2792 break;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -05002793 default:
2794 break;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04002795 }
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05002796
Alex Wu4539b082012-03-01 12:57:46 +08002797 /* XXX: would a fullscreen surface need the same handling? */
Kristian Høgsberg6a8b5532012-02-16 23:43:59 -05002798 if (surface->output) {
Pekka Paalanenf07cb5d2012-02-10 13:34:36 +02002799 weston_surface_assign_output(surface);
Pekka Paalanen77346a62011-11-30 16:26:35 +02002800
2801 if (surface_type == SHELL_SURFACE_SCREENSAVER)
2802 surface->output = shsurf->output;
Juan Zhao96879df2012-02-07 08:45:41 +08002803 else if (surface_type == SHELL_SURFACE_MAXIMIZED)
2804 surface->output = shsurf->output;
Pekka Paalanen77346a62011-11-30 16:26:35 +02002805 }
Kristian Høgsberg07937562011-04-12 17:25:42 -04002806}
2807
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03002808static void
2809shell_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
2810{
Ander Conselvan de Oliveira7fb9f952012-03-27 17:36:42 +03002811 struct shell_surface *shsurf = get_shell_surface(es);
Tiago Vignattibe143262012-04-16 17:31:41 +03002812 struct desktop_shell *shell = shsurf->shell;
Tiago Vignatti70e5c9c2012-05-07 15:23:07 +03002813 int type_changed = 0;
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03002814
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04002815 if (shsurf->next_type != SHELL_SURFACE_NONE &&
Kristian Høgsbergf7e23d52012-04-27 17:51:59 -04002816 shsurf->type != shsurf->next_type) {
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04002817 set_surface_type(shsurf);
Kristian Høgsbergf7e23d52012-04-27 17:51:59 -04002818 type_changed = 1;
2819 }
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04002820
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03002821 if (!weston_surface_is_mapped(es)) {
2822 map(shell, es, es->buffer->width, es->buffer->height, sx, sy);
Kristian Høgsbergf7e23d52012-04-27 17:51:59 -04002823 } else if (type_changed || sx != 0 || sy != 0 ||
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03002824 es->geometry.width != es->buffer->width ||
2825 es->geometry.height != es->buffer->height) {
2826 GLfloat from_x, from_y;
2827 GLfloat to_x, to_y;
2828
2829 weston_surface_to_global_float(es, 0, 0, &from_x, &from_y);
2830 weston_surface_to_global_float(es, sx, sy, &to_x, &to_y);
2831 configure(shell, es,
2832 es->geometry.x + to_x - from_x,
2833 es->geometry.y + to_y - from_y,
2834 es->buffer->width, es->buffer->height);
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03002835 }
2836}
2837
Tiago Vignattibe143262012-04-16 17:31:41 +03002838static int launch_desktop_shell_process(struct desktop_shell *shell);
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02002839
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04002840static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002841desktop_shell_sigchld(struct weston_process *process, int status)
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02002842{
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02002843 uint32_t time;
Tiago Vignattibe143262012-04-16 17:31:41 +03002844 struct desktop_shell *shell =
2845 container_of(process, struct desktop_shell, child.process);
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02002846
2847 shell->child.process.pid = 0;
2848 shell->child.client = NULL; /* already destroyed by wayland */
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02002849
2850 /* if desktop-shell dies more than 5 times in 30 seconds, give up */
2851 time = weston_compositor_get_time();
Kristian Høgsbergf03a6162012-01-17 11:07:42 -05002852 if (time - shell->child.deathstamp > 30000) {
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02002853 shell->child.deathstamp = time;
2854 shell->child.deathcount = 0;
2855 }
2856
2857 shell->child.deathcount++;
2858 if (shell->child.deathcount > 5) {
Martin Minarik6d118362012-06-07 18:01:59 +02002859 weston_log("weston-desktop-shell died, giving up.\n");
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02002860 return;
2861 }
2862
Martin Minarik6d118362012-06-07 18:01:59 +02002863 weston_log("weston-desktop-shell died, respawning...\n");
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02002864 launch_desktop_shell_process(shell);
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02002865}
2866
2867static int
Tiago Vignattibe143262012-04-16 17:31:41 +03002868launch_desktop_shell_process(struct desktop_shell *shell)
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02002869{
Kristian Høgsberg9724b512012-01-03 14:35:49 -05002870 const char *shell_exe = LIBEXECDIR "/weston-desktop-shell";
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02002871
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002872 shell->child.client = weston_client_launch(shell->compositor,
Pekka Paalanen409ef0a2011-12-02 15:30:21 +02002873 &shell->child.process,
2874 shell_exe,
2875 desktop_shell_sigchld);
2876
2877 if (!shell->child.client)
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02002878 return -1;
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02002879 return 0;
2880}
2881
2882static void
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04002883bind_shell(struct wl_client *client, void *data, uint32_t version, uint32_t id)
2884{
Tiago Vignattibe143262012-04-16 17:31:41 +03002885 struct desktop_shell *shell = data;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04002886
2887 wl_client_add_object(client, &wl_shell_interface,
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002888 &shell_implementation, id, shell);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04002889}
2890
Kristian Høgsberg75840622011-09-06 13:48:16 -04002891static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002892unbind_desktop_shell(struct wl_resource *resource)
2893{
Tiago Vignattibe143262012-04-16 17:31:41 +03002894 struct desktop_shell *shell = resource->data;
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05002895
2896 if (shell->locked)
2897 resume_desktop(shell);
2898
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002899 shell->child.desktop_shell = NULL;
2900 shell->prepare_event_sent = false;
2901 free(resource);
2902}
2903
2904static void
Kristian Høgsberg75840622011-09-06 13:48:16 -04002905bind_desktop_shell(struct wl_client *client,
2906 void *data, uint32_t version, uint32_t id)
2907{
Tiago Vignattibe143262012-04-16 17:31:41 +03002908 struct desktop_shell *shell = data;
Pekka Paalanenbbe60522011-11-03 14:11:33 +02002909 struct wl_resource *resource;
Kristian Høgsberg75840622011-09-06 13:48:16 -04002910
Pekka Paalanenbbe60522011-11-03 14:11:33 +02002911 resource = wl_client_add_object(client, &desktop_shell_interface,
2912 &desktop_shell_implementation,
2913 id, shell);
2914
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002915 if (client == shell->child.client) {
2916 resource->destroy = unbind_desktop_shell;
2917 shell->child.desktop_shell = resource;
Pekka Paalanenbbe60522011-11-03 14:11:33 +02002918 return;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002919 }
Pekka Paalanenbbe60522011-11-03 14:11:33 +02002920
2921 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
2922 "permission to bind desktop_shell denied");
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04002923 wl_resource_destroy(resource);
Kristian Høgsberg75840622011-09-06 13:48:16 -04002924}
2925
Pekka Paalanen6e168112011-11-24 11:34:05 +02002926static void
2927screensaver_set_surface(struct wl_client *client,
2928 struct wl_resource *resource,
2929 struct wl_resource *shell_surface_resource,
2930 struct wl_resource *output_resource)
2931{
Tiago Vignattibe143262012-04-16 17:31:41 +03002932 struct desktop_shell *shell = resource->data;
Pekka Paalanen6e168112011-11-24 11:34:05 +02002933 struct shell_surface *surface = shell_surface_resource->data;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002934 struct weston_output *output = output_resource->data;
Pekka Paalanen6e168112011-11-24 11:34:05 +02002935
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04002936 surface->next_type = SHELL_SURFACE_SCREENSAVER;
Pekka Paalanen77346a62011-11-30 16:26:35 +02002937
Kristian Høgsberg1cbf3262012-02-17 23:49:07 -05002938 surface->fullscreen_output = output;
Pekka Paalanen77346a62011-11-30 16:26:35 +02002939 surface->output = output;
2940 wl_list_insert(shell->screensaver.surfaces.prev, &surface->link);
Pekka Paalanen6e168112011-11-24 11:34:05 +02002941}
2942
2943static const struct screensaver_interface screensaver_implementation = {
2944 screensaver_set_surface
2945};
2946
2947static void
2948unbind_screensaver(struct wl_resource *resource)
2949{
Tiago Vignattibe143262012-04-16 17:31:41 +03002950 struct desktop_shell *shell = resource->data;
Pekka Paalanen6e168112011-11-24 11:34:05 +02002951
Pekka Paalanen77346a62011-11-30 16:26:35 +02002952 shell->screensaver.binding = NULL;
Pekka Paalanen6e168112011-11-24 11:34:05 +02002953 free(resource);
2954}
2955
2956static void
2957bind_screensaver(struct wl_client *client,
2958 void *data, uint32_t version, uint32_t id)
2959{
Tiago Vignattibe143262012-04-16 17:31:41 +03002960 struct desktop_shell *shell = data;
Pekka Paalanen6e168112011-11-24 11:34:05 +02002961 struct wl_resource *resource;
2962
2963 resource = wl_client_add_object(client, &screensaver_interface,
2964 &screensaver_implementation,
2965 id, shell);
2966
Pekka Paalanen77346a62011-11-30 16:26:35 +02002967 if (shell->screensaver.binding == NULL) {
Pekka Paalanen6e168112011-11-24 11:34:05 +02002968 resource->destroy = unbind_screensaver;
Pekka Paalanen77346a62011-11-30 16:26:35 +02002969 shell->screensaver.binding = resource;
Pekka Paalanen6e168112011-11-24 11:34:05 +02002970 return;
2971 }
2972
2973 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
2974 "interface object already bound");
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04002975 wl_resource_destroy(resource);
Pekka Paalanen6e168112011-11-24 11:34:05 +02002976}
2977
Jan Arne Petersen42feced2012-06-21 21:52:17 +02002978static void
2979input_panel_set_surface(struct wl_client *client,
2980 struct wl_resource *resource,
2981 struct wl_resource *shell_surface_resource,
2982 struct wl_resource *output_resource)
2983{
2984 struct desktop_shell *shell = resource->data;
2985 struct shell_surface *surface = shell_surface_resource->data;
2986 struct weston_output *output = output_resource->data;
2987
2988 surface->next_type = SHELL_SURFACE_INPUT_PANEL;
2989
2990 surface->fullscreen_output = output;
2991 surface->output = output;
2992 wl_list_insert(shell->input_panel.surfaces.prev, &surface->link);
2993}
2994
2995static const struct input_panel_interface input_panel_implementation = {
2996 input_panel_set_surface
2997};
2998
2999static void
3000unbind_input_panel(struct wl_resource *resource)
3001{
3002 struct desktop_shell *shell = resource->data;
3003
3004 shell->input_panel.binding = NULL;
3005 free(resource);
3006}
3007
3008static void
3009bind_input_panel(struct wl_client *client,
3010 void *data, uint32_t version, uint32_t id)
3011{
3012 struct desktop_shell *shell = data;
3013 struct wl_resource *resource;
3014
3015 resource = wl_client_add_object(client, &input_panel_interface,
3016 &input_panel_implementation,
3017 id, shell);
3018
3019 if (shell->input_panel.binding == NULL) {
3020 resource->destroy = unbind_input_panel;
3021 shell->input_panel.binding = resource;
3022 return;
3023 }
3024
3025 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
3026 "interface object already bound");
3027 wl_resource_destroy(resource);
3028}
3029
Kristian Høgsberg07045392012-02-19 18:52:44 -05003030struct switcher {
Tiago Vignattibe143262012-04-16 17:31:41 +03003031 struct desktop_shell *shell;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003032 struct weston_surface *current;
3033 struct wl_listener listener;
3034 struct wl_keyboard_grab grab;
3035};
3036
3037static void
3038switcher_next(struct switcher *switcher)
3039{
Kristian Høgsberg07045392012-02-19 18:52:44 -05003040 struct weston_surface *surface;
3041 struct weston_surface *first = NULL, *prev = NULL, *next = NULL;
Kristian Høgsberg32e56862012-04-02 22:18:58 -04003042 struct shell_surface *shsurf;
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04003043 struct workspace *ws = get_current_workspace(switcher->shell);
Kristian Høgsberg07045392012-02-19 18:52:44 -05003044
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04003045 wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
Kristian Høgsberg07045392012-02-19 18:52:44 -05003046 switch (get_shell_surface_type(surface)) {
3047 case SHELL_SURFACE_TOPLEVEL:
3048 case SHELL_SURFACE_FULLSCREEN:
3049 case SHELL_SURFACE_MAXIMIZED:
3050 if (first == NULL)
3051 first = surface;
3052 if (prev == switcher->current)
3053 next = surface;
3054 prev = surface;
Scott Moreau02709af2012-05-22 01:54:10 -06003055 surface->alpha = 0.25;
Kristian Høgsbergcacb7cd2012-02-28 09:20:21 -05003056 surface->geometry.dirty = 1;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003057 weston_surface_damage(surface);
3058 break;
3059 default:
3060 break;
3061 }
Alex Wu1659daa2012-04-01 20:13:09 +08003062
3063 if (is_black_surface(surface, NULL)) {
Scott Moreau02709af2012-05-22 01:54:10 -06003064 surface->alpha = 0.25;
Alex Wu1659daa2012-04-01 20:13:09 +08003065 surface->geometry.dirty = 1;
3066 weston_surface_damage(surface);
3067 }
Kristian Høgsberg07045392012-02-19 18:52:44 -05003068 }
3069
3070 if (next == NULL)
3071 next = first;
3072
Alex Wu07b26062012-03-12 16:06:01 +08003073 if (next == NULL)
3074 return;
3075
Kristian Høgsberg07045392012-02-19 18:52:44 -05003076 wl_list_remove(&switcher->listener.link);
Kristian Høgsberg27e30522012-04-11 23:18:23 -04003077 wl_signal_add(&next->surface.resource.destroy_signal,
3078 &switcher->listener);
Kristian Høgsberg07045392012-02-19 18:52:44 -05003079
3080 switcher->current = next;
Kristian Høgsberga416fa12012-05-21 14:06:52 -04003081 next->alpha = 1.0;
Alex Wu1659daa2012-04-01 20:13:09 +08003082
Kristian Høgsberg32e56862012-04-02 22:18:58 -04003083 shsurf = get_shell_surface(switcher->current);
3084 if (shsurf && shsurf->type ==SHELL_SURFACE_FULLSCREEN)
Kristian Høgsberga416fa12012-05-21 14:06:52 -04003085 shsurf->fullscreen.black_surface->alpha = 1.0;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003086}
3087
3088static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04003089switcher_handle_surface_destroy(struct wl_listener *listener, void *data)
Kristian Høgsberg07045392012-02-19 18:52:44 -05003090{
3091 struct switcher *switcher =
3092 container_of(listener, struct switcher, listener);
3093
3094 switcher_next(switcher);
3095}
3096
3097static void
Daniel Stone351eb612012-05-31 15:27:47 -04003098switcher_destroy(struct switcher *switcher)
Kristian Høgsberg07045392012-02-19 18:52:44 -05003099{
Kristian Høgsberg07045392012-02-19 18:52:44 -05003100 struct weston_surface *surface;
Daniel Stone37816df2012-05-16 18:45:18 +01003101 struct wl_keyboard *keyboard = switcher->grab.keyboard;
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04003102 struct workspace *ws = get_current_workspace(switcher->shell);
Kristian Høgsberg07045392012-02-19 18:52:44 -05003103
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04003104 wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
Kristian Høgsberga416fa12012-05-21 14:06:52 -04003105 surface->alpha = 1.0;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003106 weston_surface_damage(surface);
3107 }
3108
Alex Wu07b26062012-03-12 16:06:01 +08003109 if (switcher->current)
Daniel Stone37816df2012-05-16 18:45:18 +01003110 activate(switcher->shell, switcher->current,
3111 (struct weston_seat *) keyboard->seat);
Kristian Høgsberg07045392012-02-19 18:52:44 -05003112 wl_list_remove(&switcher->listener.link);
Daniel Stone37816df2012-05-16 18:45:18 +01003113 wl_keyboard_end_grab(keyboard);
Kristian Høgsberg07045392012-02-19 18:52:44 -05003114 free(switcher);
3115}
3116
3117static void
3118switcher_key(struct wl_keyboard_grab *grab,
Daniel Stonec9785ea2012-05-30 16:31:52 +01003119 uint32_t time, uint32_t key, uint32_t state_w)
Kristian Høgsberg07045392012-02-19 18:52:44 -05003120{
3121 struct switcher *switcher = container_of(grab, struct switcher, grab);
Daniel Stonec9785ea2012-05-30 16:31:52 +01003122 enum wl_keyboard_key_state state = state_w;
Daniel Stone351eb612012-05-31 15:27:47 -04003123
Daniel Stonec9785ea2012-05-30 16:31:52 +01003124 if (key == KEY_TAB && state == WL_KEYBOARD_KEY_STATE_PRESSED)
Daniel Stone351eb612012-05-31 15:27:47 -04003125 switcher_next(switcher);
3126}
3127
3128static void
3129switcher_modifier(struct wl_keyboard_grab *grab, uint32_t serial,
3130 uint32_t mods_depressed, uint32_t mods_latched,
3131 uint32_t mods_locked, uint32_t group)
3132{
3133 struct switcher *switcher = container_of(grab, struct switcher, grab);
Daniel Stone37816df2012-05-16 18:45:18 +01003134 struct weston_seat *seat = (struct weston_seat *) grab->keyboard->seat;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003135
Daniel Stone351eb612012-05-31 15:27:47 -04003136 if ((seat->modifier_state & switcher->shell->binding_modifier) == 0)
3137 switcher_destroy(switcher);
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04003138}
Kristian Høgsberg07045392012-02-19 18:52:44 -05003139
3140static const struct wl_keyboard_grab_interface switcher_grab = {
Daniel Stone351eb612012-05-31 15:27:47 -04003141 switcher_key,
3142 switcher_modifier,
Kristian Høgsberg07045392012-02-19 18:52:44 -05003143};
3144
3145static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01003146switcher_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
3147 void *data)
Kristian Høgsberg07045392012-02-19 18:52:44 -05003148{
Tiago Vignattibe143262012-04-16 17:31:41 +03003149 struct desktop_shell *shell = data;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003150 struct switcher *switcher;
3151
3152 switcher = malloc(sizeof *switcher);
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04003153 switcher->shell = shell;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003154 switcher->current = NULL;
Kristian Høgsberg27e30522012-04-11 23:18:23 -04003155 switcher->listener.notify = switcher_handle_surface_destroy;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003156 wl_list_init(&switcher->listener.link);
3157
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04003158 lower_fullscreen_layer(switcher->shell);
Kristian Høgsberg07045392012-02-19 18:52:44 -05003159 switcher->grab.interface = &switcher_grab;
Daniel Stone37816df2012-05-16 18:45:18 +01003160 wl_keyboard_start_grab(seat->keyboard, &switcher->grab);
3161 wl_keyboard_set_focus(seat->keyboard, NULL);
Kristian Høgsberg07045392012-02-19 18:52:44 -05003162 switcher_next(switcher);
3163}
3164
Pekka Paalanen3c647232011-12-22 13:43:43 +02003165static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01003166backlight_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
3167 void *data)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003168{
3169 struct weston_compositor *compositor = data;
3170 struct weston_output *output;
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03003171 long backlight_new = 0;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003172
3173 /* TODO: we're limiting to simple use cases, where we assume just
3174 * control on the primary display. We'd have to extend later if we
3175 * ever get support for setting backlights on random desktop LCD
3176 * panels though */
3177 output = get_default_output(compositor);
3178 if (!output)
3179 return;
3180
3181 if (!output->set_backlight)
3182 return;
3183
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03003184 if (key == KEY_F9 || key == KEY_BRIGHTNESSDOWN)
3185 backlight_new = output->backlight_current - 25;
3186 else if (key == KEY_F10 || key == KEY_BRIGHTNESSUP)
3187 backlight_new = output->backlight_current + 25;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003188
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03003189 if (backlight_new < 5)
3190 backlight_new = 5;
3191 if (backlight_new > 255)
3192 backlight_new = 255;
3193
3194 output->backlight_current = backlight_new;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003195 output->set_backlight(output, output->backlight_current);
3196}
3197
3198static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01003199debug_repaint_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
3200 void *data)
Kristian Høgsbergb41c0812012-03-04 14:53:40 -05003201{
Tiago Vignattibe143262012-04-16 17:31:41 +03003202 struct desktop_shell *shell = data;
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04003203 struct weston_compositor *compositor = shell->compositor;
Kristian Høgsbergb41c0812012-03-04 14:53:40 -05003204 struct weston_surface *surface;
3205
3206 if (shell->debug_repaint_surface) {
3207 weston_surface_destroy(shell->debug_repaint_surface);
3208 shell->debug_repaint_surface = NULL;
3209 } else {
3210 surface = weston_surface_create(compositor);
3211 weston_surface_set_color(surface, 1.0, 0.0, 0.0, 0.2);
3212 weston_surface_configure(surface, 0, 0, 8192, 8192);
3213 wl_list_insert(&compositor->fade_layer.surface_list,
3214 &surface->layer_link);
3215 weston_surface_assign_output(surface);
3216 pixman_region32_init(&surface->input);
3217
3218 /* Here's the dirty little trick that makes the
3219 * repaint debugging work: we force an
3220 * update_transform first to update dependent state
3221 * and clear the geometry.dirty bit. Then we clear
3222 * the surface damage so it only gets repainted
3223 * piecewise as we repaint other things. */
3224
3225 weston_surface_update_transform(surface);
3226 pixman_region32_fini(&surface->damage);
3227 pixman_region32_init(&surface->damage);
3228 shell->debug_repaint_surface = surface;
3229 }
3230}
3231
3232static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01003233force_kill_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
3234 void *data)
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04003235{
3236 struct wl_client *client;
3237 pid_t pid;
3238 uid_t uid;
3239 gid_t gid;
3240
Daniel Stone325fc2d2012-05-30 16:31:58 +01003241 client = seat->keyboard->focus->resource.client;
3242 wl_client_get_credentials(client, &pid, &uid, &gid);
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04003243
Daniel Stone325fc2d2012-05-30 16:31:58 +01003244 kill(pid, SIGKILL);
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04003245}
3246
3247static void
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003248workspace_up_binding(struct wl_seat *seat, uint32_t time,
3249 uint32_t key, void *data)
3250{
3251 struct desktop_shell *shell = data;
3252 unsigned int new_index = shell->workspaces.current;
3253
Kristian Høgsbergce345b02012-06-25 21:35:29 -04003254 if (shell->locked)
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04003255 return;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003256 if (new_index != 0)
3257 new_index--;
3258
3259 change_workspace(shell, new_index);
3260}
3261
3262static void
3263workspace_down_binding(struct wl_seat *seat, uint32_t time,
3264 uint32_t key, void *data)
3265{
3266 struct desktop_shell *shell = data;
3267 unsigned int new_index = shell->workspaces.current;
3268
Kristian Høgsbergce345b02012-06-25 21:35:29 -04003269 if (shell->locked)
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04003270 return;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003271 if (new_index < shell->workspaces.num - 1)
3272 new_index++;
3273
3274 change_workspace(shell, new_index);
3275}
3276
3277static void
3278workspace_f_binding(struct wl_seat *seat, uint32_t time,
3279 uint32_t key, void *data)
3280{
3281 struct desktop_shell *shell = data;
3282 unsigned int new_index;
3283
Kristian Høgsbergce345b02012-06-25 21:35:29 -04003284 if (shell->locked)
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04003285 return;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003286 new_index = key - KEY_F1;
3287 if (new_index >= shell->workspaces.num)
3288 new_index = shell->workspaces.num - 1;
3289
3290 change_workspace(shell, new_index);
3291}
3292
3293
3294static void
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04003295shell_destroy(struct wl_listener *listener, void *data)
Pekka Paalanen3c647232011-12-22 13:43:43 +02003296{
Tiago Vignattibe143262012-04-16 17:31:41 +03003297 struct desktop_shell *shell =
3298 container_of(listener, struct desktop_shell, destroy_listener);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003299 struct workspace **ws;
Pekka Paalanen3c647232011-12-22 13:43:43 +02003300
Pekka Paalanen9cf5cc82012-01-02 16:00:24 +02003301 if (shell->child.client)
3302 wl_client_destroy(shell->child.client);
3303
Kristian Høgsberg88c16072012-05-16 08:04:19 -04003304 wl_list_remove(&shell->lock_listener.link);
3305 wl_list_remove(&shell->unlock_listener.link);
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003306 wl_list_remove(&shell->show_input_panel_listener.link);
3307 wl_list_remove(&shell->hide_input_panel_listener.link);
Kristian Høgsberg88c16072012-05-16 08:04:19 -04003308
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003309 wl_array_for_each(ws, &shell->workspaces.array)
3310 workspace_destroy(*ws);
3311 wl_array_release(&shell->workspaces.array);
3312
Pekka Paalanen3c647232011-12-22 13:43:43 +02003313 free(shell->screensaver.path);
3314 free(shell);
3315}
3316
Tiago Vignatti0b52d482012-04-20 18:54:25 +03003317static void
3318shell_add_bindings(struct weston_compositor *ec, struct desktop_shell *shell)
3319{
3320 uint32_t mod;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003321 int i, num_workspace_bindings;
Tiago Vignatti0b52d482012-04-20 18:54:25 +03003322
3323 /* fixed bindings */
Daniel Stone325fc2d2012-05-30 16:31:58 +01003324 weston_compositor_add_key_binding(ec, KEY_BACKSPACE,
3325 MODIFIER_CTRL | MODIFIER_ALT,
3326 terminate_binding, ec);
3327 weston_compositor_add_button_binding(ec, BTN_LEFT, 0,
3328 click_to_activate_binding,
3329 shell);
3330 weston_compositor_add_axis_binding(ec, WL_POINTER_AXIS_VERTICAL_SCROLL,
3331 MODIFIER_SUPER | MODIFIER_ALT,
3332 surface_opacity_binding, NULL);
3333 weston_compositor_add_axis_binding(ec, WL_POINTER_AXIS_VERTICAL_SCROLL,
3334 MODIFIER_SUPER, zoom_axis_binding,
3335 NULL);
Tiago Vignatti0b52d482012-04-20 18:54:25 +03003336
3337 /* configurable bindings */
3338 mod = shell->binding_modifier;
Daniel Stone325fc2d2012-05-30 16:31:58 +01003339 weston_compositor_add_key_binding(ec, KEY_PAGEUP, mod,
3340 zoom_key_binding, NULL);
3341 weston_compositor_add_key_binding(ec, KEY_PAGEDOWN, mod,
3342 zoom_key_binding, NULL);
3343 weston_compositor_add_button_binding(ec, BTN_LEFT, mod, move_binding,
3344 shell);
3345 weston_compositor_add_button_binding(ec, BTN_MIDDLE, mod,
3346 resize_binding, shell);
3347 weston_compositor_add_button_binding(ec, BTN_RIGHT, mod,
3348 rotate_binding, NULL);
3349 weston_compositor_add_key_binding(ec, KEY_TAB, mod, switcher_binding,
3350 shell);
3351 weston_compositor_add_key_binding(ec, KEY_F9, mod, backlight_binding,
3352 ec);
3353 weston_compositor_add_key_binding(ec, KEY_BRIGHTNESSDOWN, 0,
3354 backlight_binding, ec);
3355 weston_compositor_add_key_binding(ec, KEY_F10, mod, backlight_binding,
3356 ec);
3357 weston_compositor_add_key_binding(ec, KEY_BRIGHTNESSUP, 0,
3358 backlight_binding, ec);
3359 weston_compositor_add_key_binding(ec, KEY_SPACE, mod,
3360 debug_repaint_binding, shell);
3361 weston_compositor_add_key_binding(ec, KEY_K, mod,
3362 force_kill_binding, shell);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003363 weston_compositor_add_key_binding(ec, KEY_UP, mod,
3364 workspace_up_binding, shell);
3365 weston_compositor_add_key_binding(ec, KEY_DOWN, mod,
3366 workspace_down_binding, shell);
3367
3368 /* Add bindings for mod+F[1-6] for workspace 1 to 6. */
3369 if (shell->workspaces.num > 1) {
3370 num_workspace_bindings = shell->workspaces.num;
3371 if (num_workspace_bindings > 6)
3372 num_workspace_bindings = 6;
3373 for (i = 0; i < num_workspace_bindings; i++)
3374 weston_compositor_add_key_binding(ec, KEY_F1 + i, mod,
3375 workspace_f_binding,
3376 shell);
3377 }
Tiago Vignatti0b52d482012-04-20 18:54:25 +03003378}
3379
Kristian Høgsberg6c709a32011-05-06 14:52:41 -04003380int
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05003381shell_init(struct weston_compositor *ec);
Kristian Høgsberg6c709a32011-05-06 14:52:41 -04003382
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003383WL_EXPORT int
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05003384shell_init(struct weston_compositor *ec)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05003385{
Tiago Vignattibe143262012-04-16 17:31:41 +03003386 struct desktop_shell *shell;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003387 struct workspace **pws;
3388 unsigned int i;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04003389
3390 shell = malloc(sizeof *shell);
3391 if (shell == NULL)
3392 return -1;
3393
Kristian Høgsbergf0d91162011-10-11 22:44:23 -04003394 memset(shell, 0, sizeof *shell);
Kristian Høgsberg75840622011-09-06 13:48:16 -04003395 shell->compositor = ec;
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04003396
3397 shell->destroy_listener.notify = shell_destroy;
3398 wl_signal_add(&ec->destroy_signal, &shell->destroy_listener);
3399 shell->lock_listener.notify = lock;
3400 wl_signal_add(&ec->lock_signal, &shell->lock_listener);
3401 shell->unlock_listener.notify = unlock;
3402 wl_signal_add(&ec->unlock_signal, &shell->unlock_listener);
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003403 shell->show_input_panel_listener.notify = show_input_panels;
3404 wl_signal_add(&ec->show_input_panel_signal, &shell->show_input_panel_listener);
3405 shell->hide_input_panel_listener.notify = hide_input_panels;
3406 wl_signal_add(&ec->hide_input_panel_signal, &shell->hide_input_panel_listener);
Scott Moreauff1db4a2012-04-17 19:06:18 -06003407 ec->ping_handler = ping_handler;
Tiago Vignattibc052c92012-04-19 16:18:18 +03003408 ec->shell_interface.create_shell_surface = create_shell_surface;
3409 ec->shell_interface.set_toplevel = set_toplevel;
Tiago Vignatti491bac12012-05-18 16:37:43 -04003410 ec->shell_interface.set_transient = set_transient;
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04003411 ec->shell_interface.move = surface_move;
Kristian Høgsbergc1693f22012-05-22 16:56:23 -04003412 ec->shell_interface.resize = surface_resize;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05003413
Pekka Paalanen77346a62011-11-30 16:26:35 +02003414 wl_list_init(&shell->screensaver.surfaces);
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003415 wl_list_init(&shell->input_panel.surfaces);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02003416
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05003417 weston_layer_init(&shell->fullscreen_layer, &ec->cursor_layer.link);
3418 weston_layer_init(&shell->panel_layer, &shell->fullscreen_layer.link);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003419 weston_layer_init(&shell->background_layer, &shell->panel_layer.link);
3420 weston_layer_init(&shell->lock_layer, NULL);
3421
3422 wl_array_init(&shell->workspaces.array);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05003423
Kristian Høgsberg6af8eb92012-01-25 16:57:11 -05003424 shell_configuration(shell);
Pekka Paalanene955f1e2011-12-07 11:49:52 +02003425
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003426 for (i = 0; i < shell->workspaces.num; i++) {
3427 pws = wl_array_add(&shell->workspaces.array, sizeof *pws);
3428 if (pws == NULL)
3429 return -1;
3430
3431 *pws = workspace_create();
3432 if (*pws == NULL)
3433 return -1;
3434 }
3435 activate_workspace(shell, 0);
3436
Jonas Ådahl62fcd042012-06-13 00:01:23 +02003437 wl_list_init(&shell->workspaces.animation.link);
3438 shell->workspaces.animation.frame = animate_workspace_change_frame;
3439
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04003440 if (wl_display_add_global(ec->wl_display, &wl_shell_interface,
3441 shell, bind_shell) == NULL)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05003442 return -1;
3443
Kristian Høgsberg75840622011-09-06 13:48:16 -04003444 if (wl_display_add_global(ec->wl_display,
3445 &desktop_shell_interface,
3446 shell, bind_desktop_shell) == NULL)
3447 return -1;
3448
Pekka Paalanen6e168112011-11-24 11:34:05 +02003449 if (wl_display_add_global(ec->wl_display, &screensaver_interface,
3450 shell, bind_screensaver) == NULL)
3451 return -1;
3452
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003453 if (wl_display_add_global(ec->wl_display, &input_panel_interface,
3454 shell, bind_input_panel) == NULL)
3455 return -1;
3456
Kristian Høgsbergf03a6162012-01-17 11:07:42 -05003457 shell->child.deathstamp = weston_compositor_get_time();
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02003458 if (launch_desktop_shell_process(shell) != 0)
3459 return -1;
3460
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04003461 shell->pointer_focus_listener.notify = handle_pointer_focus;
Pekka Paalanen43e1ba82012-06-07 15:07:06 +03003462 if (ec->seat->seat.pointer)
3463 wl_signal_add(&ec->seat->seat.pointer->focus_signal,
3464 &shell->pointer_focus_listener);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04003465
Tiago Vignatti0b52d482012-04-20 18:54:25 +03003466 shell_add_bindings(ec, shell);
Kristian Høgsberg07937562011-04-12 17:25:42 -04003467
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05003468 return 0;
3469}