blob: 4633049aa628a5c6126f92771f8833108bc2ccdd [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"
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050039
Jonas Ådahle3cddce2012-06-13 00:01:22 +020040#define DEFAULT_NUM_WORKSPACES 1
Jonas Ådahl62fcd042012-06-13 00:01:23 +020041#define DEFAULT_WORKSPACE_CHANGE_ANIMATION_LENGTH 200
Jonas Ådahle3cddce2012-06-13 00:01:22 +020042
Juan Zhaoe10d2792012-04-25 19:09:52 +080043enum animation_type {
44 ANIMATION_NONE,
45
46 ANIMATION_ZOOM,
47 ANIMATION_FADE
48};
49
Jonas Ådahl04769742012-06-13 00:01:24 +020050struct focus_state {
51 struct weston_seat *seat;
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -040052 struct workspace *ws;
Jonas Ådahl04769742012-06-13 00:01:24 +020053 struct weston_surface *keyboard_focus;
54 struct wl_list link;
55 struct wl_listener seat_destroy_listener;
56 struct wl_listener surface_destroy_listener;
57};
58
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
Philipp Brüschweiler88013572012-08-06 13:44:42 +020066struct input_panel_surface {
67 struct wl_list link;
68 struct weston_surface *surface;
69 struct wl_listener listener;
70};
71
Tiago Vignattibe143262012-04-16 17:31:41 +030072struct desktop_shell {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050073 struct weston_compositor *compositor;
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -040074
75 struct wl_listener lock_listener;
76 struct wl_listener unlock_listener;
77 struct wl_listener destroy_listener;
Jan Arne Petersen42feced2012-06-21 21:52:17 +020078 struct wl_listener show_input_panel_listener;
79 struct wl_listener hide_input_panel_listener;
Pekka Paalanen6cd281a2011-11-03 14:11:32 +020080
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -050081 struct weston_layer fullscreen_layer;
82 struct weston_layer panel_layer;
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -050083 struct weston_layer background_layer;
84 struct weston_layer lock_layer;
Philipp Brüschweiler711fda82012-08-09 18:50:43 +020085 struct weston_layer input_panel_layer;
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -050086
Kristian Høgsbergd56bd902012-06-05 09:58:51 -040087 struct wl_listener pointer_focus_listener;
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +030088 struct weston_surface *grab_surface;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -040089
Pekka Paalanen6cd281a2011-11-03 14:11:32 +020090 struct {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050091 struct weston_process process;
Pekka Paalanen6cd281a2011-11-03 14:11:32 +020092 struct wl_client *client;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +020093 struct wl_resource *desktop_shell;
Pekka Paalanen4d733ee2012-01-17 14:36:27 +020094
95 unsigned deathcount;
96 uint32_t deathstamp;
Pekka Paalanen6cd281a2011-11-03 14:11:32 +020097 } child;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +020098
99 bool locked;
Philipp Brüschweiler711fda82012-08-09 18:50:43 +0200100 bool showing_input_panels;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200101 bool prepare_event_sent;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200102
Kristian Høgsberg730c94d2012-06-26 21:44:35 -0400103 struct weston_surface *lock_surface;
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500104 struct wl_listener lock_surface_listener;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100105
Pekka Paalanen77346a62011-11-30 16:26:35 +0200106 struct {
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200107 struct wl_array array;
108 unsigned int current;
109 unsigned int num;
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200110
111 struct weston_animation animation;
112 int anim_dir;
113 uint32_t anim_timestamp;
114 double anim_current;
115 struct workspace *anim_from;
116 struct workspace *anim_to;
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200117 } workspaces;
118
119 struct {
Pekka Paalanen3c647232011-12-22 13:43:43 +0200120 char *path;
Pekka Paalanen7296e792011-12-07 16:22:00 +0200121 int duration;
Pekka Paalanen77346a62011-11-30 16:26:35 +0200122 struct wl_resource *binding;
123 struct wl_list surfaces;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500124 struct weston_process process;
Pekka Paalanen77346a62011-11-30 16:26:35 +0200125 } screensaver;
Kristian Høgsbergb41c0812012-03-04 14:53:40 -0500126
Jan Arne Petersen42feced2012-06-21 21:52:17 +0200127 struct {
128 struct wl_resource *binding;
129 struct wl_list surfaces;
130 } input_panel;
131
Tiago Vignatti0b52d482012-04-20 18:54:25 +0300132 uint32_t binding_modifier;
Juan Zhaoe10d2792012-04-25 19:09:52 +0800133 enum animation_type win_animation_type;
Kristian Høgsbergb41c0812012-03-04 14:53:40 -0500134 struct weston_surface *debug_repaint_surface;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400135};
136
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500137enum shell_surface_type {
Pekka Paalanen98262232011-12-01 10:42:22 +0200138 SHELL_SURFACE_NONE,
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500139 SHELL_SURFACE_TOPLEVEL,
140 SHELL_SURFACE_TRANSIENT,
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500141 SHELL_SURFACE_FULLSCREEN,
Juan Zhao96879df2012-02-07 08:45:41 +0800142 SHELL_SURFACE_MAXIMIZED,
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500143 SHELL_SURFACE_POPUP
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200144};
145
Scott Moreauff1db4a2012-04-17 19:06:18 -0600146struct ping_timer {
147 struct wl_event_source *source;
Scott Moreauff1db4a2012-04-17 19:06:18 -0600148 uint32_t serial;
149};
150
Pekka Paalanen56cdea92011-11-23 16:14:12 +0200151struct shell_surface {
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200152 struct wl_resource resource;
153
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500154 struct weston_surface *surface;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200155 struct wl_listener surface_destroy_listener;
Kristian Høgsberg8150b192012-06-27 10:22:58 -0400156 struct weston_surface *parent;
Tiago Vignattibe143262012-04-16 17:31:41 +0300157 struct desktop_shell *shell;
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200158
Kristian Høgsberg7f366e72012-04-27 17:20:01 -0400159 enum shell_surface_type type, next_type;
Kristian Høgsberge7afd912012-05-02 09:47:44 -0400160 char *title, *class;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500161 int32_t saved_x, saved_y;
Alex Wu4539b082012-03-01 12:57:46 +0800162 bool saved_position_valid;
Alex Wu7bcb8bd2012-04-27 09:07:24 +0800163 bool saved_rotation_valid;
Scott Moreauff1db4a2012-04-17 19:06:18 -0600164 int unresponsive;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100165
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500166 struct {
Pekka Paalanen460099f2012-01-20 16:48:25 +0200167 struct weston_transform transform;
Kristian Høgsberg765e27b2012-01-27 13:36:13 -0500168 struct weston_matrix rotation;
Pekka Paalanen460099f2012-01-20 16:48:25 +0200169 } rotation;
170
171 struct {
Scott Moreau447013d2012-02-18 05:05:29 -0700172 struct wl_pointer_grab grab;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500173 int32_t x, y;
Pekka Paalanen938269a2012-02-07 14:19:01 +0200174 struct weston_transform parent_transform;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500175 int32_t initial_up;
Daniel Stone37816df2012-05-16 18:45:18 +0100176 struct wl_seat *seat;
Kristian Høgsberg3730f362012-04-13 12:40:07 -0400177 uint32_t serial;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500178 } popup;
179
Alex Wu4539b082012-03-01 12:57:46 +0800180 struct {
Tiago Vignatti52e598c2012-05-07 15:23:08 +0300181 int32_t x, y;
Tiago Vignatti491bac12012-05-18 16:37:43 -0400182 uint32_t flags;
Tiago Vignatti52e598c2012-05-07 15:23:08 +0300183 } transient;
184
185 struct {
Alex Wu4539b082012-03-01 12:57:46 +0800186 enum wl_shell_surface_fullscreen_method type;
187 struct weston_transform transform; /* matrix from x, y */
188 uint32_t framerate;
189 struct weston_surface *black_surface;
190 } fullscreen;
191
Scott Moreauff1db4a2012-04-17 19:06:18 -0600192 struct ping_timer *ping_timer;
193
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200194 struct weston_transform workspace_transform;
195
Kristian Høgsberg1cbf3262012-02-17 23:49:07 -0500196 struct weston_output *fullscreen_output;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500197 struct weston_output *output;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100198 struct wl_list link;
Kristian Høgsberga61ca062012-05-22 16:05:52 -0400199
200 const struct weston_shell_client *client;
Pekka Paalanen56cdea92011-11-23 16:14:12 +0200201};
202
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300203struct shell_grab {
Scott Moreau447013d2012-02-18 05:05:29 -0700204 struct wl_pointer_grab grab;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300205 struct shell_surface *shsurf;
206 struct wl_listener shsurf_destroy_listener;
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300207 struct wl_pointer *pointer;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300208};
209
210struct weston_move_grab {
211 struct shell_grab base;
Daniel Stone103db7f2012-05-08 17:17:55 +0100212 wl_fixed_t dx, dy;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500213};
214
Pekka Paalanen460099f2012-01-20 16:48:25 +0200215struct rotate_grab {
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300216 struct shell_grab base;
Kristian Høgsberg765e27b2012-01-27 13:36:13 -0500217 struct weston_matrix rotation;
Pekka Paalanen460099f2012-01-20 16:48:25 +0200218 struct {
Kristian Høgsbergb2af93e2012-06-07 20:10:23 -0400219 GLfloat x;
220 GLfloat y;
Pekka Paalanen460099f2012-01-20 16:48:25 +0200221 } center;
222};
223
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400224static void
225activate(struct desktop_shell *shell, struct weston_surface *es,
226 struct weston_seat *seat);
227
228static struct workspace *
229get_current_workspace(struct desktop_shell *shell);
230
Alex Wubd3354b2012-04-17 17:20:49 +0800231static struct shell_surface *
232get_shell_surface(struct weston_surface *surface);
233
234static struct desktop_shell *
235shell_surface_get_shell(struct shell_surface *shsurf);
236
237static bool
238shell_surface_is_top_fullscreen(struct shell_surface *shsurf)
239{
240 struct desktop_shell *shell;
241 struct weston_surface *top_fs_es;
242
243 shell = shell_surface_get_shell(shsurf);
244
245 if (wl_list_empty(&shell->fullscreen_layer.surface_list))
246 return false;
247
248 top_fs_es = container_of(shell->fullscreen_layer.surface_list.next,
249 struct weston_surface,
250 layer_link);
251 return (shsurf == get_shell_surface(top_fs_es));
252}
253
Kristian Høgsberg6af8eb92012-01-25 16:57:11 -0500254static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400255destroy_shell_grab_shsurf(struct wl_listener *listener, void *data)
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300256{
257 struct shell_grab *grab;
258
259 grab = container_of(listener, struct shell_grab,
260 shsurf_destroy_listener);
261
262 grab->shsurf = NULL;
263}
264
265static void
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300266shell_grab_start(struct shell_grab *grab,
267 const struct wl_pointer_grab_interface *interface,
268 struct shell_surface *shsurf,
269 struct wl_pointer *pointer,
270 enum desktop_shell_cursor cursor)
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300271{
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300272 struct desktop_shell *shell = shsurf->shell;
273
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300274 grab->grab.interface = interface;
275 grab->shsurf = shsurf;
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400276 grab->shsurf_destroy_listener.notify = destroy_shell_grab_shsurf;
277 wl_signal_add(&shsurf->resource.destroy_signal,
278 &grab->shsurf_destroy_listener);
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300279
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300280 grab->pointer = pointer;
281 grab->grab.focus = &shsurf->surface->surface;
282
283 wl_pointer_start_grab(pointer, &grab->grab);
284 desktop_shell_send_grab_cursor(shell->child.desktop_shell, cursor);
285 wl_pointer_set_focus(pointer, &shell->grab_surface->surface,
286 wl_fixed_from_int(0), wl_fixed_from_int(0));
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300287}
288
289static void
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300290shell_grab_end(struct shell_grab *grab)
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300291{
Kristian Høgsberg47b5dca2012-06-07 18:08:04 -0400292 if (grab->shsurf)
293 wl_list_remove(&grab->shsurf_destroy_listener.link);
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300294
295 wl_pointer_end_grab(grab->pointer);
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300296}
297
298static void
Alex Wu4539b082012-03-01 12:57:46 +0800299center_on_output(struct weston_surface *surface,
300 struct weston_output *output);
301
Daniel Stone496ca172012-05-30 16:31:42 +0100302static enum weston_keyboard_modifier
Tiago Vignatti0b52d482012-04-20 18:54:25 +0300303get_modifier(char *modifier)
304{
305 if (!modifier)
306 return MODIFIER_SUPER;
307
308 if (!strcmp("ctrl", modifier))
309 return MODIFIER_CTRL;
310 else if (!strcmp("alt", modifier))
311 return MODIFIER_ALT;
312 else if (!strcmp("super", modifier))
313 return MODIFIER_SUPER;
314 else
315 return MODIFIER_SUPER;
316}
317
Juan Zhaoe10d2792012-04-25 19:09:52 +0800318static enum animation_type
319get_animation_type(char *animation)
320{
321 if (!animation)
322 return ANIMATION_NONE;
323
324 if (!strcmp("zoom", animation))
325 return ANIMATION_ZOOM;
326 else if (!strcmp("fade", animation))
327 return ANIMATION_FADE;
328 else
329 return ANIMATION_NONE;
330}
331
Alex Wu4539b082012-03-01 12:57:46 +0800332static void
Tiago Vignattibe143262012-04-16 17:31:41 +0300333shell_configuration(struct desktop_shell *shell)
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200334{
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200335 char *config_file;
Pekka Paalanen7296e792011-12-07 16:22:00 +0200336 char *path = NULL;
337 int duration = 60;
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200338 unsigned int num_workspaces = DEFAULT_NUM_WORKSPACES;
Tiago Vignatti0b52d482012-04-20 18:54:25 +0300339 char *modifier = NULL;
Juan Zhaoe10d2792012-04-25 19:09:52 +0800340 char *win_animation = NULL;
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200341
Kristian Høgsberga4e8b332012-04-20 16:48:21 -0400342 struct config_key shell_keys[] = {
Tiago Vignatti0b52d482012-04-20 18:54:25 +0300343 { "binding-modifier", CONFIG_KEY_STRING, &modifier },
Juan Zhaoe10d2792012-04-25 19:09:52 +0800344 { "animation", CONFIG_KEY_STRING, &win_animation},
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200345 { "num-workspaces",
346 CONFIG_KEY_UNSIGNED_INTEGER, &num_workspaces },
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200347 };
348
Kristian Høgsberga4e8b332012-04-20 16:48:21 -0400349 struct config_key saver_keys[] = {
350 { "path", CONFIG_KEY_STRING, &path },
351 { "duration", CONFIG_KEY_INTEGER, &duration },
352 };
353
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200354 struct config_section cs[] = {
Kristian Høgsberga4e8b332012-04-20 16:48:21 -0400355 { "shell", shell_keys, ARRAY_LENGTH(shell_keys), NULL },
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200356 { "screensaver", saver_keys, ARRAY_LENGTH(saver_keys), NULL },
357 };
358
Tiago Vignatti9a206c42012-03-21 19:49:18 +0200359 config_file = config_file_path("weston.ini");
Kristian Høgsberg6af8eb92012-01-25 16:57:11 -0500360 parse_config_file(config_file, cs, ARRAY_LENGTH(cs), shell);
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200361 free(config_file);
362
Pekka Paalanen7296e792011-12-07 16:22:00 +0200363 shell->screensaver.path = path;
364 shell->screensaver.duration = duration;
Tiago Vignatti0b52d482012-04-20 18:54:25 +0300365 shell->binding_modifier = get_modifier(modifier);
Juan Zhaoe10d2792012-04-25 19:09:52 +0800366 shell->win_animation_type = get_animation_type(win_animation);
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200367 shell->workspaces.num = num_workspaces > 0 ? num_workspaces : 1;
368}
369
370static void
Jonas Ådahl04769742012-06-13 00:01:24 +0200371focus_state_destroy(struct focus_state *state)
372{
373 wl_list_remove(&state->seat_destroy_listener.link);
374 wl_list_remove(&state->surface_destroy_listener.link);
375 free(state);
376}
377
378static void
379focus_state_seat_destroy(struct wl_listener *listener, void *data)
380{
381 struct focus_state *state = container_of(listener,
382 struct focus_state,
383 seat_destroy_listener);
384
385 wl_list_remove(&state->link);
386 focus_state_destroy(state);
387}
388
389static void
390focus_state_surface_destroy(struct wl_listener *listener, void *data)
391{
392 struct focus_state *state = container_of(listener,
393 struct focus_state,
Kristian Høgsbergb8e0d0f2012-07-31 10:30:26 -0400394 surface_destroy_listener);
Kristian Høgsberge3778222012-07-31 17:29:30 -0400395 struct desktop_shell *shell;
396 struct weston_surface *surface, *next;
Jonas Ådahl04769742012-06-13 00:01:24 +0200397
Kristian Høgsberge3778222012-07-31 17:29:30 -0400398 next = NULL;
399 wl_list_for_each(surface, &state->ws->layer.surface_list, layer_link) {
400 if (surface == state->keyboard_focus)
401 continue;
402
403 next = surface;
404 break;
405 }
406
407 if (next) {
408 shell = state->seat->compositor->shell_interface.shell;
409 activate(shell, next, state->seat);
410 } else {
411 wl_list_remove(&state->link);
412 focus_state_destroy(state);
413 }
Jonas Ådahl04769742012-06-13 00:01:24 +0200414}
415
416static struct focus_state *
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400417focus_state_create(struct weston_seat *seat, struct workspace *ws)
Jonas Ådahl04769742012-06-13 00:01:24 +0200418{
Jonas Ådahl04769742012-06-13 00:01:24 +0200419 struct focus_state *state;
Jonas Ådahl04769742012-06-13 00:01:24 +0200420
421 state = malloc(sizeof *state);
422 if (state == NULL)
423 return NULL;
424
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400425 state->ws = ws;
Jonas Ådahl04769742012-06-13 00:01:24 +0200426 state->seat = seat;
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400427 wl_list_insert(&ws->focus_list, &state->link);
Jonas Ådahl04769742012-06-13 00:01:24 +0200428
429 state->seat_destroy_listener.notify = focus_state_seat_destroy;
430 state->surface_destroy_listener.notify = focus_state_surface_destroy;
431 wl_signal_add(&seat->seat.destroy_signal,
432 &state->seat_destroy_listener);
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400433 wl_list_init(&state->surface_destroy_listener.link);
Jonas Ådahl04769742012-06-13 00:01:24 +0200434
435 return state;
436}
437
438static void
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400439restore_focus_state(struct desktop_shell *shell, struct workspace *ws)
Jonas Ådahl04769742012-06-13 00:01:24 +0200440{
441 struct focus_state *state, *next;
442
443 wl_list_for_each_safe(state, next, &ws->focus_list, link) {
444 if (state->keyboard_focus)
445 wl_keyboard_set_focus(state->seat->seat.keyboard,
446 &state->keyboard_focus->surface);
Jonas Ådahl04769742012-06-13 00:01:24 +0200447 }
448}
449
450static void
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200451workspace_destroy(struct workspace *ws)
452{
Jonas Ådahl04769742012-06-13 00:01:24 +0200453 struct focus_state *state, *next;
454
455 wl_list_for_each_safe(state, next, &ws->focus_list, link)
456 focus_state_destroy(state);
457
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200458 free(ws);
459}
460
Jonas Ådahl04769742012-06-13 00:01:24 +0200461static void
462seat_destroyed(struct wl_listener *listener, void *data)
463{
464 struct weston_seat *seat = data;
465 struct focus_state *state, *next;
466 struct workspace *ws = container_of(listener,
467 struct workspace,
468 seat_destroyed_listener);
469
470 wl_list_for_each_safe(state, next, &ws->focus_list, link)
471 if (state->seat == seat)
472 wl_list_remove(&state->link);
473}
474
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200475static struct workspace *
476workspace_create(void)
477{
478 struct workspace *ws = malloc(sizeof *ws);
479 if (ws == NULL)
480 return NULL;
481
482 weston_layer_init(&ws->layer, NULL);
483
Jonas Ådahl04769742012-06-13 00:01:24 +0200484 wl_list_init(&ws->focus_list);
485 wl_list_init(&ws->seat_destroyed_listener.link);
486 ws->seat_destroyed_listener.notify = seat_destroyed;
487
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200488 return ws;
489}
490
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200491static int
492workspace_is_empty(struct workspace *ws)
493{
494 return wl_list_empty(&ws->layer.surface_list);
495}
496
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200497static struct workspace *
498get_workspace(struct desktop_shell *shell, unsigned int index)
499{
500 struct workspace **pws = shell->workspaces.array.data;
501 pws += index;
502 return *pws;
503}
504
505static struct workspace *
506get_current_workspace(struct desktop_shell *shell)
507{
508 return get_workspace(shell, shell->workspaces.current);
509}
510
511static void
512activate_workspace(struct desktop_shell *shell, unsigned int index)
513{
514 struct workspace *ws;
515
516 ws = get_workspace(shell, index);
517 wl_list_insert(&shell->panel_layer.link, &ws->layer.link);
518
519 shell->workspaces.current = index;
520}
521
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200522static unsigned int
523get_output_height(struct weston_output *output)
524{
525 return abs(output->region.extents.y1 - output->region.extents.y2);
526}
527
528static void
529surface_translate(struct weston_surface *surface, double d)
530{
531 struct shell_surface *shsurf = get_shell_surface(surface);
532 struct weston_transform *transform;
533
534 transform = &shsurf->workspace_transform;
535 if (wl_list_empty(&transform->link))
536 wl_list_insert(surface->geometry.transformation_list.prev,
537 &shsurf->workspace_transform.link);
538
539 weston_matrix_init(&shsurf->workspace_transform.matrix);
540 weston_matrix_translate(&shsurf->workspace_transform.matrix,
541 0.0, d, 0.0);
542 surface->geometry.dirty = 1;
543}
544
545static void
546workspace_translate_out(struct workspace *ws, double fraction)
547{
548 struct weston_surface *surface;
549 unsigned int height;
550 double d;
551
552 wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
553 height = get_output_height(surface->output);
554 d = height * fraction;
555
556 surface_translate(surface, d);
557 }
558}
559
560static void
561workspace_translate_in(struct workspace *ws, double fraction)
562{
563 struct weston_surface *surface;
564 unsigned int height;
565 double d;
566
567 wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
568 height = get_output_height(surface->output);
569
570 if (fraction > 0)
571 d = -(height - height * fraction);
572 else
573 d = height + height * fraction;
574
575 surface_translate(surface, d);
576 }
577}
578
579static void
580workspace_damage_all_surfaces(struct workspace *ws)
581{
582 struct weston_surface *surface;
583
584 wl_list_for_each(surface, &ws->layer.surface_list, layer_link)
585 weston_surface_damage(surface);
586}
587
588static void
589reverse_workspace_change_animation(struct desktop_shell *shell,
590 unsigned int index,
591 struct workspace *from,
592 struct workspace *to)
593{
594 shell->workspaces.current = index;
595
596 shell->workspaces.anim_to = to;
597 shell->workspaces.anim_from = from;
598 shell->workspaces.anim_dir = -1 * shell->workspaces.anim_dir;
599 shell->workspaces.anim_timestamp = 0;
600
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400601 restore_focus_state(shell, to);
Jonas Ådahl04769742012-06-13 00:01:24 +0200602
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200603 workspace_damage_all_surfaces(from);
604 workspace_damage_all_surfaces(to);
605}
606
607static void
608workspace_deactivate_transforms(struct workspace *ws)
609{
610 struct weston_surface *surface;
611 struct shell_surface *shsurf;
612
613 wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
614 shsurf = get_shell_surface(surface);
615 wl_list_remove(&shsurf->workspace_transform.link);
616 wl_list_init(&shsurf->workspace_transform.link);
617 shsurf->surface->geometry.dirty = 1;
618 }
619}
620
621static void
622finish_workspace_change_animation(struct desktop_shell *shell,
623 struct workspace *from,
624 struct workspace *to)
625{
626 workspace_damage_all_surfaces(from);
627 workspace_damage_all_surfaces(to);
628
629 wl_list_remove(&shell->workspaces.animation.link);
630 workspace_deactivate_transforms(from);
631 workspace_deactivate_transforms(to);
632 shell->workspaces.anim_to = NULL;
633
634 wl_list_remove(&shell->workspaces.anim_from->layer.link);
635}
636
637static void
638animate_workspace_change_frame(struct weston_animation *animation,
639 struct weston_output *output, uint32_t msecs)
640{
641 struct desktop_shell *shell =
642 container_of(animation, struct desktop_shell,
643 workspaces.animation);
644 struct workspace *from = shell->workspaces.anim_from;
645 struct workspace *to = shell->workspaces.anim_to;
646 uint32_t t;
647 double x, y;
648
649 if (workspace_is_empty(from) && workspace_is_empty(to)) {
650 finish_workspace_change_animation(shell, from, to);
651 return;
652 }
653
654 if (shell->workspaces.anim_timestamp == 0) {
655 if (shell->workspaces.anim_current == 0.0)
656 shell->workspaces.anim_timestamp = msecs;
657 else
658 shell->workspaces.anim_timestamp =
659 msecs -
660 /* Invers of movement function 'y' below. */
661 (asin(1.0 - shell->workspaces.anim_current) *
662 DEFAULT_WORKSPACE_CHANGE_ANIMATION_LENGTH *
663 M_2_PI);
664 }
665
666 t = msecs - shell->workspaces.anim_timestamp;
667
668 /*
669 * x = [0, π/2]
670 * y(x) = sin(x)
671 */
672 x = t * (1.0/DEFAULT_WORKSPACE_CHANGE_ANIMATION_LENGTH) * M_PI_2;
673 y = sin(x);
674
675 if (t < DEFAULT_WORKSPACE_CHANGE_ANIMATION_LENGTH) {
676 workspace_damage_all_surfaces(from);
677 workspace_damage_all_surfaces(to);
678
679 workspace_translate_out(from, shell->workspaces.anim_dir * y);
680 workspace_translate_in(to, shell->workspaces.anim_dir * y);
681 shell->workspaces.anim_current = y;
682
683 workspace_damage_all_surfaces(from);
684 workspace_damage_all_surfaces(to);
685 }
Jonas Ådahl04769742012-06-13 00:01:24 +0200686 else
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200687 finish_workspace_change_animation(shell, from, to);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200688}
689
690static void
691animate_workspace_change(struct desktop_shell *shell,
692 unsigned int index,
693 struct workspace *from,
694 struct workspace *to)
695{
696 struct weston_output *output;
697
698 int dir;
699
700 if (index > shell->workspaces.current)
701 dir = -1;
702 else
703 dir = 1;
704
705 shell->workspaces.current = index;
706
707 shell->workspaces.anim_dir = dir;
708 shell->workspaces.anim_from = from;
709 shell->workspaces.anim_to = to;
710 shell->workspaces.anim_current = 0.0;
711 shell->workspaces.anim_timestamp = 0;
712
713 output = container_of(shell->compositor->output_list.next,
714 struct weston_output, link);
715 wl_list_insert(&output->animation_list,
716 &shell->workspaces.animation.link);
717
718 wl_list_insert(&from->layer.link, &to->layer.link);
719
720 workspace_translate_in(to, 0);
721
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400722 restore_focus_state(shell, to);
Jonas Ådahl04769742012-06-13 00:01:24 +0200723
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200724 workspace_damage_all_surfaces(from);
725 workspace_damage_all_surfaces(to);
726}
727
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200728static void
729change_workspace(struct desktop_shell *shell, unsigned int index)
730{
731 struct workspace *from;
732 struct workspace *to;
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200733
734 if (index == shell->workspaces.current)
735 return;
736
737 /* Don't change workspace when there is any fullscreen surfaces. */
738 if (!wl_list_empty(&shell->fullscreen_layer.surface_list))
739 return;
740
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200741 from = get_current_workspace(shell);
742 to = get_workspace(shell, index);
743
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200744 if (shell->workspaces.anim_from == to &&
745 shell->workspaces.anim_to == from) {
746 reverse_workspace_change_animation(shell, index, from, to);
747 return;
748 }
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200749
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200750 if (shell->workspaces.anim_to != NULL)
751 finish_workspace_change_animation(shell,
752 shell->workspaces.anim_from,
753 shell->workspaces.anim_to);
754
755 if (workspace_is_empty(to) && workspace_is_empty(from)) {
756 shell->workspaces.current = index;
757 wl_list_insert(&from->layer.link, &to->layer.link);
758 wl_list_remove(&from->layer.link);
Jonas Ådahl04769742012-06-13 00:01:24 +0200759
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400760 restore_focus_state(shell, to);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200761 }
762 else
763 animate_workspace_change(shell, index, from, to);
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200764}
765
Pekka Paalanen56cdea92011-11-23 16:14:12 +0200766static void
Kristian Høgsbergeae5de72012-04-11 22:42:15 -0400767noop_grab_focus(struct wl_pointer_grab *grab,
Daniel Stone103db7f2012-05-08 17:17:55 +0100768 struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y)
Kristian Høgsberg9ddb8262012-01-04 21:30:29 -0500769{
770 grab->focus = NULL;
771}
772
773static void
Scott Moreau447013d2012-02-18 05:05:29 -0700774move_grab_motion(struct wl_pointer_grab *grab,
Daniel Stone103db7f2012-05-08 17:17:55 +0100775 uint32_t time, wl_fixed_t x, wl_fixed_t y)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500776{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500777 struct weston_move_grab *move = (struct weston_move_grab *) grab;
Daniel Stone37816df2012-05-16 18:45:18 +0100778 struct wl_pointer *pointer = grab->pointer;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300779 struct shell_surface *shsurf = move->base.shsurf;
780 struct weston_surface *es;
Daniel Stone37816df2012-05-16 18:45:18 +0100781 int dx = wl_fixed_to_int(pointer->x + move->dx);
782 int dy = wl_fixed_to_int(pointer->y + move->dy);
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300783
784 if (!shsurf)
785 return;
786
787 es = shsurf->surface;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500788
Daniel Stone103db7f2012-05-08 17:17:55 +0100789 weston_surface_configure(es, dx, dy,
Pekka Paalanen60921e52012-01-25 15:55:43 +0200790 es->geometry.width, es->geometry.height);
Kristian Høgsberg6c6fb992012-06-21 12:06:22 -0400791
792 weston_compositor_schedule_repaint(es->compositor);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500793}
794
795static void
Scott Moreau447013d2012-02-18 05:05:29 -0700796move_grab_button(struct wl_pointer_grab *grab,
Daniel Stone4dbadb12012-05-30 16:31:51 +0100797 uint32_t time, uint32_t button, uint32_t state_w)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500798{
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300799 struct shell_grab *shell_grab = container_of(grab, struct shell_grab,
800 grab);
Daniel Stone37816df2012-05-16 18:45:18 +0100801 struct wl_pointer *pointer = grab->pointer;
Daniel Stone4dbadb12012-05-30 16:31:51 +0100802 enum wl_pointer_button_state state = state_w;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500803
Daniel Stone4dbadb12012-05-30 16:31:51 +0100804 if (pointer->button_count == 0 &&
805 state == WL_POINTER_BUTTON_STATE_RELEASED) {
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300806 shell_grab_end(shell_grab);
Kristian Høgsberg9ddb8262012-01-04 21:30:29 -0500807 free(grab);
808 }
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500809}
810
Scott Moreau447013d2012-02-18 05:05:29 -0700811static const struct wl_pointer_grab_interface move_grab_interface = {
Kristian Høgsberg9ddb8262012-01-04 21:30:29 -0500812 noop_grab_focus,
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500813 move_grab_motion,
814 move_grab_button,
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500815};
816
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -0400817static int
818surface_move(struct shell_surface *shsurf, struct weston_seat *ws)
819{
820 struct weston_move_grab *move;
821
822 if (!shsurf)
823 return -1;
824
825 if (shsurf->type == SHELL_SURFACE_FULLSCREEN)
826 return 0;
827
828 move = malloc(sizeof *move);
829 if (!move)
830 return -1;
831
832 move->dx = wl_fixed_from_double(shsurf->surface->geometry.x) -
833 ws->seat.pointer->grab_x;
834 move->dy = wl_fixed_from_double(shsurf->surface->geometry.y) -
835 ws->seat.pointer->grab_y;
836
837 shell_grab_start(&move->base, &move_grab_interface, shsurf,
838 ws->seat.pointer, DESKTOP_SHELL_CURSOR_MOVE);
839
840 return 0;
841}
842
843static void
844shell_surface_move(struct wl_client *client, struct wl_resource *resource,
845 struct wl_resource *seat_resource, uint32_t serial)
846{
847 struct weston_seat *ws = seat_resource->data;
848 struct shell_surface *shsurf = resource->data;
849
850 if (ws->seat.pointer->button_count == 0 ||
851 ws->seat.pointer->grab_serial != serial ||
852 ws->seat.pointer->focus != &shsurf->surface->surface)
853 return;
854
855 if (surface_move(shsurf, ws) < 0)
856 wl_resource_post_no_memory(resource);
857}
858
859struct weston_resize_grab {
860 struct shell_grab base;
861 uint32_t edges;
862 int32_t width, height;
863};
864
865static void
866resize_grab_motion(struct wl_pointer_grab *grab,
867 uint32_t time, wl_fixed_t x, wl_fixed_t y)
868{
869 struct weston_resize_grab *resize = (struct weston_resize_grab *) grab;
870 struct wl_pointer *pointer = grab->pointer;
871 struct shell_surface *shsurf = resize->base.shsurf;
872 int32_t width, height;
873 wl_fixed_t from_x, from_y;
874 wl_fixed_t to_x, to_y;
875
876 if (!shsurf)
877 return;
878
879 weston_surface_from_global_fixed(shsurf->surface,
880 pointer->grab_x, pointer->grab_y,
881 &from_x, &from_y);
882 weston_surface_from_global_fixed(shsurf->surface,
883 pointer->x, pointer->y, &to_x, &to_y);
884
885 width = resize->width;
886 if (resize->edges & WL_SHELL_SURFACE_RESIZE_LEFT) {
887 width += wl_fixed_to_int(from_x - to_x);
888 } else if (resize->edges & WL_SHELL_SURFACE_RESIZE_RIGHT) {
889 width += wl_fixed_to_int(to_x - from_x);
890 }
891
892 height = resize->height;
893 if (resize->edges & WL_SHELL_SURFACE_RESIZE_TOP) {
894 height += wl_fixed_to_int(from_y - to_y);
895 } else if (resize->edges & WL_SHELL_SURFACE_RESIZE_BOTTOM) {
896 height += wl_fixed_to_int(to_y - from_y);
897 }
898
899 shsurf->client->send_configure(shsurf->surface,
900 resize->edges, width, height);
901}
902
903static void
904send_configure(struct weston_surface *surface,
905 uint32_t edges, int32_t width, int32_t height)
906{
907 struct shell_surface *shsurf = get_shell_surface(surface);
908
909 wl_shell_surface_send_configure(&shsurf->resource,
910 edges, width, height);
911}
912
913static const struct weston_shell_client shell_client = {
914 send_configure
915};
916
917static void
918resize_grab_button(struct wl_pointer_grab *grab,
919 uint32_t time, uint32_t button, uint32_t state_w)
920{
921 struct weston_resize_grab *resize = (struct weston_resize_grab *) grab;
922 struct wl_pointer *pointer = grab->pointer;
923 enum wl_pointer_button_state state = state_w;
924
925 if (pointer->button_count == 0 &&
926 state == WL_POINTER_BUTTON_STATE_RELEASED) {
927 shell_grab_end(&resize->base);
928 free(grab);
929 }
930}
931
932static const struct wl_pointer_grab_interface resize_grab_interface = {
933 noop_grab_focus,
934 resize_grab_motion,
935 resize_grab_button,
936};
937
938static int
939surface_resize(struct shell_surface *shsurf,
940 struct weston_seat *ws, uint32_t edges)
941{
942 struct weston_resize_grab *resize;
943
944 if (shsurf->type == SHELL_SURFACE_FULLSCREEN)
945 return 0;
946
947 if (edges == 0 || edges > 15 ||
948 (edges & 3) == 3 || (edges & 12) == 12)
949 return 0;
950
951 resize = malloc(sizeof *resize);
952 if (!resize)
953 return -1;
954
955 resize->edges = edges;
956 resize->width = shsurf->surface->geometry.width;
957 resize->height = shsurf->surface->geometry.height;
958
959 shell_grab_start(&resize->base, &resize_grab_interface, shsurf,
960 ws->seat.pointer, edges);
961
962 return 0;
963}
964
965static void
966shell_surface_resize(struct wl_client *client, struct wl_resource *resource,
967 struct wl_resource *seat_resource, uint32_t serial,
968 uint32_t edges)
969{
970 struct weston_seat *ws = seat_resource->data;
971 struct shell_surface *shsurf = resource->data;
972
973 if (shsurf->type == SHELL_SURFACE_FULLSCREEN)
974 return;
975
976 if (ws->seat.pointer->button_count == 0 ||
977 ws->seat.pointer->grab_serial != serial ||
978 ws->seat.pointer->focus != &shsurf->surface->surface)
979 return;
980
981 if (surface_resize(shsurf, ws, edges) < 0)
982 wl_resource_post_no_memory(resource);
983}
984
Scott Moreauc3e54eb2012-04-17 19:06:20 -0600985static void
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400986busy_cursor_grab_focus(struct wl_pointer_grab *base,
987 struct wl_surface *surface, int32_t x, int32_t y)
Scott Moreauc3e54eb2012-04-17 19:06:20 -0600988{
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400989 struct shell_grab *grab = (struct shell_grab *) base;
Scott Moreauc3e54eb2012-04-17 19:06:20 -0600990
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400991 if (grab->grab.focus != surface) {
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300992 shell_grab_end(grab);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400993 free(grab);
Scott Moreauc3e54eb2012-04-17 19:06:20 -0600994 }
995}
996
997static void
Kristian Høgsbergd56bd902012-06-05 09:58:51 -0400998busy_cursor_grab_motion(struct wl_pointer_grab *grab,
999 uint32_t time, int32_t x, int32_t y)
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001000{
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001001}
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001002
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001003static void
Kristian Høgsbergbbe98392012-08-01 00:20:21 -04001004busy_cursor_grab_button(struct wl_pointer_grab *base,
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001005 uint32_t time, uint32_t button, uint32_t state)
1006{
Kristian Høgsbergbbe98392012-08-01 00:20:21 -04001007 struct shell_grab *grab = (struct shell_grab *) base;
1008 struct shell_surface *shsurf;
1009 struct weston_surface *surface =
1010 (struct weston_surface *) grab->grab.pointer->current;
1011 struct weston_seat *seat =
1012 (struct weston_seat *) grab->grab.pointer->seat;
1013
1014 shsurf = get_shell_surface(surface);
1015 if (shsurf && button == BTN_LEFT && state) {
1016 activate(shsurf->shell, shsurf->surface, seat);
1017 surface_move(shsurf, seat);
1018 }
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001019}
1020
1021static const struct wl_pointer_grab_interface busy_cursor_grab_interface = {
1022 busy_cursor_grab_focus,
1023 busy_cursor_grab_motion,
1024 busy_cursor_grab_button,
1025};
1026
1027static void
1028set_busy_cursor(struct shell_surface *shsurf, struct wl_pointer *pointer)
1029{
1030 struct shell_grab *grab;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001031
1032 grab = malloc(sizeof *grab);
1033 if (!grab)
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001034 return;
1035
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001036 shell_grab_start(grab, &busy_cursor_grab_interface, shsurf, pointer,
1037 DESKTOP_SHELL_CURSOR_BUSY);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001038}
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001039
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001040static void
1041end_busy_cursor(struct shell_surface *shsurf, struct wl_pointer *pointer)
1042{
1043 struct shell_grab *grab = (struct shell_grab *) pointer->grab;
1044
1045 if (grab->grab.interface == &busy_cursor_grab_interface) {
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001046 shell_grab_end(grab);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001047 free(grab);
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001048 }
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001049}
1050
Scott Moreau9521d5e2012-04-19 13:06:17 -06001051static void
1052ping_timer_destroy(struct shell_surface *shsurf)
1053{
1054 if (!shsurf || !shsurf->ping_timer)
1055 return;
1056
1057 if (shsurf->ping_timer->source)
1058 wl_event_source_remove(shsurf->ping_timer->source);
1059
1060 free(shsurf->ping_timer);
1061 shsurf->ping_timer = NULL;
1062}
1063
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001064static int
Scott Moreauff1db4a2012-04-17 19:06:18 -06001065ping_timeout_handler(void *data)
1066{
1067 struct shell_surface *shsurf = data;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001068 struct weston_seat *seat;
Scott Moreauff1db4a2012-04-17 19:06:18 -06001069
Scott Moreau9521d5e2012-04-19 13:06:17 -06001070 /* Client is not responding */
1071 shsurf->unresponsive = 1;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001072
1073 wl_list_for_each(seat, &shsurf->surface->compositor->seat_list, link)
1074 if (seat->seat.pointer->focus == &shsurf->surface->surface)
1075 set_busy_cursor(shsurf, seat->seat.pointer);
Scott Moreauff1db4a2012-04-17 19:06:18 -06001076
1077 return 1;
1078}
1079
1080static void
1081ping_handler(struct weston_surface *surface, uint32_t serial)
1082{
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001083 struct shell_surface *shsurf = get_shell_surface(surface);
Scott Moreauff1db4a2012-04-17 19:06:18 -06001084 struct wl_event_loop *loop;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001085 int ping_timeout = 200;
Scott Moreauff1db4a2012-04-17 19:06:18 -06001086
1087 if (!shsurf)
1088 return;
Kristian Høgsbergca535c12012-04-21 23:20:07 -04001089 if (!shsurf->resource.client)
1090 return;
Scott Moreauff1db4a2012-04-17 19:06:18 -06001091
Ander Conselvan de Oliveiraeac9a462012-07-16 14:15:48 +03001092 if (shsurf->surface == shsurf->shell->grab_surface)
1093 return;
1094
Scott Moreauff1db4a2012-04-17 19:06:18 -06001095 if (!shsurf->ping_timer) {
Ander Conselvan de Oliveirafb980892012-04-27 13:55:55 +03001096 shsurf->ping_timer = malloc(sizeof *shsurf->ping_timer);
Scott Moreauff1db4a2012-04-17 19:06:18 -06001097 if (!shsurf->ping_timer)
1098 return;
1099
1100 shsurf->ping_timer->serial = serial;
Scott Moreauff1db4a2012-04-17 19:06:18 -06001101 loop = wl_display_get_event_loop(surface->compositor->wl_display);
1102 shsurf->ping_timer->source =
1103 wl_event_loop_add_timer(loop, ping_timeout_handler, shsurf);
1104 wl_event_source_timer_update(shsurf->ping_timer->source, ping_timeout);
1105
1106 wl_shell_surface_send_ping(&shsurf->resource, serial);
1107 }
1108}
1109
1110static void
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001111handle_pointer_focus(struct wl_listener *listener, void *data)
1112{
1113 struct wl_pointer *pointer = data;
1114 struct weston_surface *surface =
1115 (struct weston_surface *) pointer->focus;
1116 struct weston_compositor *compositor;
1117 struct shell_surface *shsurf;
1118 uint32_t serial;
1119
1120 if (!surface)
1121 return;
1122
1123 compositor = surface->compositor;
1124 shsurf = get_shell_surface(surface);
1125
Pekka Paalanen4e1f2ff2012-06-06 16:59:45 +03001126 if (shsurf && shsurf->unresponsive) {
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001127 set_busy_cursor(shsurf, pointer);
1128 } else {
1129 serial = wl_display_next_serial(compositor->wl_display);
1130 ping_handler(surface, serial);
1131 }
1132}
1133
1134static void
Kristian Høgsbergf4d2f232012-08-10 10:05:39 -04001135create_pointer_focus_listener(struct weston_seat *seat)
1136{
1137 struct wl_listener *listener;
1138
1139 if (!seat->seat.pointer)
1140 return;
1141
1142 listener = malloc(sizeof *listener);
1143 listener->notify = handle_pointer_focus;
1144 wl_signal_add(&seat->seat.pointer->focus_signal, listener);
1145}
1146
1147static void
Scott Moreauff1db4a2012-04-17 19:06:18 -06001148shell_surface_pong(struct wl_client *client, struct wl_resource *resource,
1149 uint32_t serial)
1150{
1151 struct shell_surface *shsurf = resource->data;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001152 struct desktop_shell *shell = shsurf->shell;
1153 struct weston_seat *seat;
1154 struct weston_compositor *ec = shsurf->surface->compositor;
1155 struct wl_pointer *pointer;
1156 int was_unresponsive;
Scott Moreauff1db4a2012-04-17 19:06:18 -06001157
Kristian Høgsberg92374e12012-08-11 22:39:12 -04001158 if (shsurf->ping_timer == NULL)
1159 /* Just ignore unsolicited pong. */
1160 return;
1161
Scott Moreauff1db4a2012-04-17 19:06:18 -06001162 if (shsurf->ping_timer->serial == serial) {
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001163 was_unresponsive = shsurf->unresponsive;
Scott Moreauff1db4a2012-04-17 19:06:18 -06001164 shsurf->unresponsive = 0;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001165 if (was_unresponsive) {
1166 /* Received pong from previously unresponsive client */
1167 wl_list_for_each(seat, &ec->seat_list, link) {
1168 pointer = seat->seat.pointer;
1169 if (pointer->focus ==
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001170 &shell->grab_surface->surface &&
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001171 pointer->current ==
1172 &shsurf->surface->surface)
1173 end_busy_cursor(shsurf, pointer);
1174 }
1175 }
Scott Moreau9521d5e2012-04-19 13:06:17 -06001176 ping_timer_destroy(shsurf);
Scott Moreauff1db4a2012-04-17 19:06:18 -06001177 }
1178}
1179
Kristian Høgsberge7afd912012-05-02 09:47:44 -04001180static void
1181shell_surface_set_title(struct wl_client *client,
1182 struct wl_resource *resource, const char *title)
1183{
1184 struct shell_surface *shsurf = resource->data;
1185
1186 free(shsurf->title);
1187 shsurf->title = strdup(title);
1188}
1189
1190static void
1191shell_surface_set_class(struct wl_client *client,
1192 struct wl_resource *resource, const char *class)
1193{
1194 struct shell_surface *shsurf = resource->data;
1195
1196 free(shsurf->class);
1197 shsurf->class = strdup(class);
1198}
1199
Juan Zhao96879df2012-02-07 08:45:41 +08001200static struct weston_output *
1201get_default_output(struct weston_compositor *compositor)
1202{
1203 return container_of(compositor->output_list.next,
1204 struct weston_output, link);
1205}
1206
Alex Wu4539b082012-03-01 12:57:46 +08001207static void
1208shell_unset_fullscreen(struct shell_surface *shsurf)
1209{
1210 /* undo all fullscreen things here */
Alex Wubd3354b2012-04-17 17:20:49 +08001211 if (shsurf->fullscreen.type == WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER &&
1212 shell_surface_is_top_fullscreen(shsurf)) {
1213 weston_output_switch_mode(shsurf->fullscreen_output,
1214 shsurf->fullscreen_output->origin);
1215 }
Alex Wu4539b082012-03-01 12:57:46 +08001216 shsurf->fullscreen.type = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT;
1217 shsurf->fullscreen.framerate = 0;
1218 wl_list_remove(&shsurf->fullscreen.transform.link);
1219 wl_list_init(&shsurf->fullscreen.transform.link);
Alex Wubd3354b2012-04-17 17:20:49 +08001220 if (shsurf->fullscreen.black_surface)
1221 weston_surface_destroy(shsurf->fullscreen.black_surface);
Alex Wu4539b082012-03-01 12:57:46 +08001222 shsurf->fullscreen.black_surface = NULL;
1223 shsurf->fullscreen_output = NULL;
Alex Wu4539b082012-03-01 12:57:46 +08001224 weston_surface_set_position(shsurf->surface,
1225 shsurf->saved_x, shsurf->saved_y);
Alex Wu7bcb8bd2012-04-27 09:07:24 +08001226 if (shsurf->saved_rotation_valid) {
1227 wl_list_insert(&shsurf->surface->geometry.transformation_list,
1228 &shsurf->rotation.transform.link);
1229 shsurf->saved_rotation_valid = false;
1230 }
Alex Wu4539b082012-03-01 12:57:46 +08001231}
1232
Pekka Paalanen98262232011-12-01 10:42:22 +02001233static int
1234reset_shell_surface_type(struct shell_surface *surface)
1235{
1236 switch (surface->type) {
1237 case SHELL_SURFACE_FULLSCREEN:
Alex Wu4539b082012-03-01 12:57:46 +08001238 shell_unset_fullscreen(surface);
Pekka Paalanen98262232011-12-01 10:42:22 +02001239 break;
Juan Zhao96879df2012-02-07 08:45:41 +08001240 case SHELL_SURFACE_MAXIMIZED:
1241 surface->output = get_default_output(surface->surface->compositor);
1242 weston_surface_set_position(surface->surface,
1243 surface->saved_x,
1244 surface->saved_y);
1245 break;
Pekka Paalanen98262232011-12-01 10:42:22 +02001246 case SHELL_SURFACE_NONE:
1247 case SHELL_SURFACE_TOPLEVEL:
1248 case SHELL_SURFACE_TRANSIENT:
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001249 case SHELL_SURFACE_POPUP:
Pekka Paalanen98262232011-12-01 10:42:22 +02001250 break;
1251 }
1252
1253 surface->type = SHELL_SURFACE_NONE;
1254 return 0;
1255}
1256
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001257static void
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001258set_surface_type(struct shell_surface *shsurf)
1259{
1260 struct weston_surface *surface = shsurf->surface;
Kristian Høgsberg8150b192012-06-27 10:22:58 -04001261 struct weston_surface *pes = shsurf->parent;
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001262
1263 reset_shell_surface_type(shsurf);
1264
1265 shsurf->type = shsurf->next_type;
1266 shsurf->next_type = SHELL_SURFACE_NONE;
1267
1268 switch (shsurf->type) {
1269 case SHELL_SURFACE_TOPLEVEL:
1270 break;
1271 case SHELL_SURFACE_TRANSIENT:
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001272 weston_surface_set_position(surface,
Tiago Vignatti52e598c2012-05-07 15:23:08 +03001273 pes->geometry.x + shsurf->transient.x,
1274 pes->geometry.y + shsurf->transient.y);
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001275 break;
1276
1277 case SHELL_SURFACE_MAXIMIZED:
1278 shsurf->saved_x = surface->geometry.x;
1279 shsurf->saved_y = surface->geometry.y;
1280 shsurf->saved_position_valid = true;
1281 break;
1282
1283 case SHELL_SURFACE_FULLSCREEN:
1284 shsurf->saved_x = surface->geometry.x;
1285 shsurf->saved_y = surface->geometry.y;
1286 shsurf->saved_position_valid = true;
1287
1288 if (!wl_list_empty(&shsurf->rotation.transform.link)) {
1289 wl_list_remove(&shsurf->rotation.transform.link);
1290 wl_list_init(&shsurf->rotation.transform.link);
1291 shsurf->surface->geometry.dirty = 1;
1292 shsurf->saved_rotation_valid = true;
1293 }
1294 break;
1295
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001296 default:
1297 break;
1298 }
1299}
1300
1301static void
Tiago Vignattibc052c92012-04-19 16:18:18 +03001302set_toplevel(struct shell_surface *shsurf)
1303{
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001304 shsurf->next_type = SHELL_SURFACE_TOPLEVEL;
Tiago Vignattibc052c92012-04-19 16:18:18 +03001305}
1306
1307static void
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001308shell_surface_set_toplevel(struct wl_client *client,
1309 struct wl_resource *resource)
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001310{
Pekka Paalanen98262232011-12-01 10:42:22 +02001311 struct shell_surface *surface = resource->data;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001312
Tiago Vignattibc052c92012-04-19 16:18:18 +03001313 set_toplevel(surface);
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001314}
1315
1316static void
Tiago Vignatti491bac12012-05-18 16:37:43 -04001317set_transient(struct shell_surface *shsurf,
Kristian Høgsberg8150b192012-06-27 10:22:58 -04001318 struct weston_surface *parent, int x, int y, uint32_t flags)
Tiago Vignatti491bac12012-05-18 16:37:43 -04001319{
1320 /* assign to parents output */
Kristian Høgsberg8150b192012-06-27 10:22:58 -04001321 shsurf->parent = parent;
Tiago Vignatti491bac12012-05-18 16:37:43 -04001322 shsurf->transient.x = x;
1323 shsurf->transient.y = y;
1324 shsurf->transient.flags = flags;
1325 shsurf->next_type = SHELL_SURFACE_TRANSIENT;
1326}
1327
1328static void
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001329shell_surface_set_transient(struct wl_client *client,
1330 struct wl_resource *resource,
1331 struct wl_resource *parent_resource,
1332 int x, int y, uint32_t flags)
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001333{
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001334 struct shell_surface *shsurf = resource->data;
Kristian Høgsberg8150b192012-06-27 10:22:58 -04001335 struct weston_surface *parent = parent_resource->data;
Pekka Paalanen98262232011-12-01 10:42:22 +02001336
Kristian Høgsberg8150b192012-06-27 10:22:58 -04001337 set_transient(shsurf, parent, x, y, flags);
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001338}
1339
Tiago Vignattibe143262012-04-16 17:31:41 +03001340static struct desktop_shell *
Juan Zhao96879df2012-02-07 08:45:41 +08001341shell_surface_get_shell(struct shell_surface *shsurf)
Pekka Paalanenaf0e34c2011-12-02 10:59:17 +02001342{
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04001343 return shsurf->shell;
Juan Zhao96879df2012-02-07 08:45:41 +08001344}
1345
1346static int
Tiago Vignattibe143262012-04-16 17:31:41 +03001347get_output_panel_height(struct desktop_shell *shell,
1348 struct weston_output *output)
Juan Zhao96879df2012-02-07 08:45:41 +08001349{
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001350 struct weston_surface *surface;
Juan Zhao96879df2012-02-07 08:45:41 +08001351 int panel_height = 0;
1352
1353 if (!output)
1354 return 0;
1355
Juan Zhao4ab94682012-07-09 22:24:09 -07001356 wl_list_for_each(surface, &shell->panel_layer.surface_list, layer_link) {
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001357 if (surface->output == output) {
1358 panel_height = surface->geometry.height;
Juan Zhao96879df2012-02-07 08:45:41 +08001359 break;
1360 }
1361 }
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001362
Juan Zhao96879df2012-02-07 08:45:41 +08001363 return panel_height;
1364}
1365
1366static void
1367shell_surface_set_maximized(struct wl_client *client,
1368 struct wl_resource *resource,
1369 struct wl_resource *output_resource )
1370{
1371 struct shell_surface *shsurf = resource->data;
1372 struct weston_surface *es = shsurf->surface;
Tiago Vignattibe143262012-04-16 17:31:41 +03001373 struct desktop_shell *shell = NULL;
Juan Zhao96879df2012-02-07 08:45:41 +08001374 uint32_t edges = 0, panel_height = 0;
1375
1376 /* get the default output, if the client set it as NULL
1377 check whether the ouput is available */
1378 if (output_resource)
1379 shsurf->output = output_resource->data;
Kristian Høgsberg94de6802012-07-18 09:54:04 -04001380 else if (es->output)
1381 shsurf->output = es->output;
Juan Zhao96879df2012-02-07 08:45:41 +08001382 else
1383 shsurf->output = get_default_output(es->compositor);
1384
Tiago Vignattibe143262012-04-16 17:31:41 +03001385 shell = shell_surface_get_shell(shsurf);
Rob Bradford31b68622012-07-02 19:00:19 +01001386 panel_height = get_output_panel_height(shell, shsurf->output);
Juan Zhao96879df2012-02-07 08:45:41 +08001387 edges = WL_SHELL_SURFACE_RESIZE_TOP|WL_SHELL_SURFACE_RESIZE_LEFT;
Kristian Høgsberg0b5cd0c2012-03-04 21:57:37 -05001388
Kristian Høgsberga61ca062012-05-22 16:05:52 -04001389 shsurf->client->send_configure(shsurf->surface, edges,
Rob Bradford31b68622012-07-02 19:00:19 +01001390 shsurf->output->current->width,
1391 shsurf->output->current->height - panel_height);
Juan Zhao96879df2012-02-07 08:45:41 +08001392
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001393 shsurf->next_type = SHELL_SURFACE_MAXIMIZED;
Pekka Paalanenaf0e34c2011-12-02 10:59:17 +02001394}
1395
Alex Wu21858432012-04-01 20:13:08 +08001396static void
1397black_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy);
1398
Alex Wu4539b082012-03-01 12:57:46 +08001399static struct weston_surface *
1400create_black_surface(struct weston_compositor *ec,
Alex Wu21858432012-04-01 20:13:08 +08001401 struct weston_surface *fs_surface,
Alex Wu4539b082012-03-01 12:57:46 +08001402 GLfloat x, GLfloat y, int w, int h)
1403{
1404 struct weston_surface *surface = NULL;
1405
1406 surface = weston_surface_create(ec);
1407 if (surface == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001408 weston_log("no memory\n");
Alex Wu4539b082012-03-01 12:57:46 +08001409 return NULL;
1410 }
1411
Alex Wu21858432012-04-01 20:13:08 +08001412 surface->configure = black_surface_configure;
1413 surface->private = fs_surface;
Alex Wu4539b082012-03-01 12:57:46 +08001414 weston_surface_configure(surface, x, y, w, h);
1415 weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1);
Kristian Høgsberg61f00f52012-08-03 16:31:36 -04001416 pixman_region32_init_rect(&surface->opaque, 0, 0, w, h);
1417
Alex Wu4539b082012-03-01 12:57:46 +08001418 return surface;
1419}
1420
1421/* Create black surface and append it to the associated fullscreen surface.
1422 * Handle size dismatch and positioning according to the method. */
1423static void
1424shell_configure_fullscreen(struct shell_surface *shsurf)
1425{
1426 struct weston_output *output = shsurf->fullscreen_output;
1427 struct weston_surface *surface = shsurf->surface;
1428 struct weston_matrix *matrix;
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04001429 float scale, output_aspect, surface_aspect, x, y;
Alex Wu4539b082012-03-01 12:57:46 +08001430
Alex Wu4539b082012-03-01 12:57:46 +08001431 if (!shsurf->fullscreen.black_surface)
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05001432 shsurf->fullscreen.black_surface =
1433 create_black_surface(surface->compositor,
Alex Wu21858432012-04-01 20:13:08 +08001434 surface,
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05001435 output->x, output->y,
1436 output->current->width,
1437 output->current->height);
1438
1439 wl_list_remove(&shsurf->fullscreen.black_surface->layer_link);
1440 wl_list_insert(&surface->layer_link,
1441 &shsurf->fullscreen.black_surface->layer_link);
Alex Wu4539b082012-03-01 12:57:46 +08001442 shsurf->fullscreen.black_surface->output = output;
1443
1444 switch (shsurf->fullscreen.type) {
1445 case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT:
Kristian Høgsberga08b5282012-07-20 15:30:36 -04001446 if (surface->buffer)
1447 center_on_output(surface, shsurf->fullscreen_output);
Alex Wu4539b082012-03-01 12:57:46 +08001448 break;
1449 case WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE:
1450 matrix = &shsurf->fullscreen.transform.matrix;
1451 weston_matrix_init(matrix);
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04001452
1453 output_aspect = (float) output->current->width /
1454 (float) output->current->height;
1455 surface_aspect = (float) surface->geometry.width /
1456 (float) surface->geometry.height;
1457 if (output_aspect < surface_aspect)
1458 scale = (float) output->current->width /
1459 (float) surface->geometry.width;
1460 else
1461 scale = (float) output->current->height /
1462 (float) surface->geometry.height;
1463
Alex Wu4539b082012-03-01 12:57:46 +08001464 weston_matrix_scale(matrix, scale, scale, 1);
1465 wl_list_remove(&shsurf->fullscreen.transform.link);
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04001466 wl_list_insert(&surface->geometry.transformation_list,
Alex Wu4539b082012-03-01 12:57:46 +08001467 &shsurf->fullscreen.transform.link);
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04001468 x = output->x + (output->current->width - surface->geometry.width * scale) / 2;
1469 y = output->y + (output->current->height - surface->geometry.height * scale) / 2;
1470 weston_surface_set_position(surface, x, y);
1471
Alex Wu4539b082012-03-01 12:57:46 +08001472 break;
1473 case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER:
Alex Wubd3354b2012-04-17 17:20:49 +08001474 if (shell_surface_is_top_fullscreen(shsurf)) {
1475 struct weston_mode mode = {0,
1476 surface->geometry.width,
1477 surface->geometry.height,
1478 shsurf->fullscreen.framerate};
1479
1480 if (weston_output_switch_mode(output, &mode) == 0) {
1481 weston_surface_configure(shsurf->fullscreen.black_surface,
1482 output->x, output->y,
1483 output->current->width,
1484 output->current->height);
1485 weston_surface_set_position(surface, output->x, output->y);
1486 break;
1487 }
1488 }
Alex Wu4539b082012-03-01 12:57:46 +08001489 break;
1490 case WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL:
1491 break;
1492 default:
1493 break;
1494 }
1495}
1496
1497/* make the fullscreen and black surface at the top */
1498static void
1499shell_stack_fullscreen(struct shell_surface *shsurf)
1500{
Alex Wubd3354b2012-04-17 17:20:49 +08001501 struct weston_output *output = shsurf->fullscreen_output;
Alex Wu4539b082012-03-01 12:57:46 +08001502 struct weston_surface *surface = shsurf->surface;
Tiago Vignattibe143262012-04-16 17:31:41 +03001503 struct desktop_shell *shell = shell_surface_get_shell(shsurf);
Alex Wu4539b082012-03-01 12:57:46 +08001504
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05001505 wl_list_remove(&surface->layer_link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05001506 wl_list_insert(&shell->fullscreen_layer.surface_list,
1507 &surface->layer_link);
Alex Wubd3354b2012-04-17 17:20:49 +08001508 weston_surface_damage(surface);
1509
1510 if (!shsurf->fullscreen.black_surface)
1511 shsurf->fullscreen.black_surface =
1512 create_black_surface(surface->compositor,
1513 surface,
1514 output->x, output->y,
1515 output->current->width,
1516 output->current->height);
1517
1518 wl_list_remove(&shsurf->fullscreen.black_surface->layer_link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05001519 wl_list_insert(&surface->layer_link,
1520 &shsurf->fullscreen.black_surface->layer_link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05001521 weston_surface_damage(shsurf->fullscreen.black_surface);
Alex Wu4539b082012-03-01 12:57:46 +08001522}
1523
1524static void
1525shell_map_fullscreen(struct shell_surface *shsurf)
1526{
Alex Wu4539b082012-03-01 12:57:46 +08001527 shell_stack_fullscreen(shsurf);
Alex Wubd3354b2012-04-17 17:20:49 +08001528 shell_configure_fullscreen(shsurf);
Alex Wu4539b082012-03-01 12:57:46 +08001529}
1530
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001531static void
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001532shell_surface_set_fullscreen(struct wl_client *client,
Kristian Høgsbergf856fd22012-02-16 15:58:14 -05001533 struct wl_resource *resource,
1534 uint32_t method,
1535 uint32_t framerate,
1536 struct wl_resource *output_resource)
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001537{
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001538 struct shell_surface *shsurf = resource->data;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001539 struct weston_surface *es = shsurf->surface;
Alex Wu4539b082012-03-01 12:57:46 +08001540
1541 if (output_resource)
1542 shsurf->output = output_resource->data;
Kristian Høgsberg94de6802012-07-18 09:54:04 -04001543 else if (es->output)
1544 shsurf->output = es->output;
Alex Wu4539b082012-03-01 12:57:46 +08001545 else
1546 shsurf->output = get_default_output(es->compositor);
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001547
Alex Wu4539b082012-03-01 12:57:46 +08001548 shsurf->fullscreen_output = shsurf->output;
1549 shsurf->fullscreen.type = method;
1550 shsurf->fullscreen.framerate = framerate;
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001551 shsurf->next_type = SHELL_SURFACE_FULLSCREEN;
Alex Wu4539b082012-03-01 12:57:46 +08001552
Kristian Høgsberga61ca062012-05-22 16:05:52 -04001553 shsurf->client->send_configure(shsurf->surface, 0,
1554 shsurf->output->current->width,
1555 shsurf->output->current->height);
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001556}
1557
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001558static void
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001559popup_grab_focus(struct wl_pointer_grab *grab,
Daniel Stone103db7f2012-05-08 17:17:55 +01001560 struct wl_surface *surface,
1561 wl_fixed_t x,
1562 wl_fixed_t y)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001563{
Daniel Stone37816df2012-05-16 18:45:18 +01001564 struct wl_pointer *pointer = grab->pointer;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001565 struct shell_surface *priv =
1566 container_of(grab, struct shell_surface, popup.grab);
1567 struct wl_client *client = priv->surface->surface.resource.client;
1568
Pekka Paalanencb108432012-01-19 16:25:40 +02001569 if (surface && surface->resource.client == client) {
Daniel Stone37816df2012-05-16 18:45:18 +01001570 wl_pointer_set_focus(pointer, surface, x, y);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001571 grab->focus = surface;
1572 } else {
Daniel Stone37816df2012-05-16 18:45:18 +01001573 wl_pointer_set_focus(pointer, NULL,
1574 wl_fixed_from_int(0),
1575 wl_fixed_from_int(0));
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001576 grab->focus = NULL;
1577 }
1578}
1579
1580static void
Scott Moreau447013d2012-02-18 05:05:29 -07001581popup_grab_motion(struct wl_pointer_grab *grab,
Daniel Stone103db7f2012-05-08 17:17:55 +01001582 uint32_t time, wl_fixed_t sx, wl_fixed_t sy)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001583{
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001584 struct wl_resource *resource;
1585
Daniel Stone37816df2012-05-16 18:45:18 +01001586 resource = grab->pointer->focus_resource;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001587 if (resource)
Daniel Stone37816df2012-05-16 18:45:18 +01001588 wl_pointer_send_motion(resource, time, sx, sy);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001589}
1590
1591static void
Scott Moreau447013d2012-02-18 05:05:29 -07001592popup_grab_button(struct wl_pointer_grab *grab,
Daniel Stone4dbadb12012-05-30 16:31:51 +01001593 uint32_t time, uint32_t button, uint32_t state_w)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001594{
1595 struct wl_resource *resource;
1596 struct shell_surface *shsurf =
1597 container_of(grab, struct shell_surface, popup.grab);
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001598 struct wl_display *display;
Daniel Stone4dbadb12012-05-30 16:31:51 +01001599 enum wl_pointer_button_state state = state_w;
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001600 uint32_t serial;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001601
Daniel Stone37816df2012-05-16 18:45:18 +01001602 resource = grab->pointer->focus_resource;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001603 if (resource) {
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001604 display = wl_client_get_display(resource->client);
1605 serial = wl_display_get_serial(display);
Daniel Stone37816df2012-05-16 18:45:18 +01001606 wl_pointer_send_button(resource, serial, time, button, state);
Daniel Stone4dbadb12012-05-30 16:31:51 +01001607 } else if (state == WL_POINTER_BUTTON_STATE_RELEASED &&
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001608 (shsurf->popup.initial_up ||
Daniel Stone37816df2012-05-16 18:45:18 +01001609 time - shsurf->popup.seat->pointer->grab_time > 500)) {
Kristian Høgsberg0b5cd0c2012-03-04 21:57:37 -05001610 wl_shell_surface_send_popup_done(&shsurf->resource);
Daniel Stone37816df2012-05-16 18:45:18 +01001611 wl_pointer_end_grab(grab->pointer);
1612 shsurf->popup.grab.pointer = NULL;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001613 }
1614
Daniel Stone4dbadb12012-05-30 16:31:51 +01001615 if (state == WL_POINTER_BUTTON_STATE_RELEASED)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001616 shsurf->popup.initial_up = 1;
1617}
1618
Scott Moreau447013d2012-02-18 05:05:29 -07001619static const struct wl_pointer_grab_interface popup_grab_interface = {
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001620 popup_grab_focus,
1621 popup_grab_motion,
1622 popup_grab_button,
1623};
1624
1625static void
Kristian Høgsberg3730f362012-04-13 12:40:07 -04001626shell_map_popup(struct shell_surface *shsurf)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001627{
Daniel Stone37816df2012-05-16 18:45:18 +01001628 struct wl_seat *seat = shsurf->popup.seat;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001629 struct weston_surface *es = shsurf->surface;
Kristian Høgsberg8150b192012-06-27 10:22:58 -04001630 struct weston_surface *parent = shsurf->parent;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001631
1632 es->output = parent->output;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001633 shsurf->popup.grab.interface = &popup_grab_interface;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001634
Pekka Paalanen938269a2012-02-07 14:19:01 +02001635 weston_surface_update_transform(parent);
1636 if (parent->transform.enabled) {
1637 shsurf->popup.parent_transform.matrix =
1638 parent->transform.matrix;
1639 } else {
1640 /* construct x, y translation matrix */
1641 weston_matrix_init(&shsurf->popup.parent_transform.matrix);
1642 shsurf->popup.parent_transform.matrix.d[12] =
1643 parent->geometry.x;
1644 shsurf->popup.parent_transform.matrix.d[13] =
1645 parent->geometry.y;
1646 }
1647 wl_list_insert(es->geometry.transformation_list.prev,
1648 &shsurf->popup.parent_transform.link);
Pekka Paalanen8fb8d3b2012-02-13 13:03:59 +02001649 weston_surface_set_position(es, shsurf->popup.x, shsurf->popup.y);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001650
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001651 shsurf->popup.initial_up = 0;
1652
Kristian Høgsberg3730f362012-04-13 12:40:07 -04001653 /* We don't require the grab to still be active, but if another
1654 * grab has started in the meantime, we end the popup now. */
Daniel Stone37816df2012-05-16 18:45:18 +01001655 if (seat->pointer->grab_serial == shsurf->popup.serial) {
1656 wl_pointer_start_grab(seat->pointer, &shsurf->popup.grab);
Kristian Høgsberg3730f362012-04-13 12:40:07 -04001657 } else {
1658 wl_shell_surface_send_popup_done(&shsurf->resource);
1659 }
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001660}
1661
1662static void
1663shell_surface_set_popup(struct wl_client *client,
1664 struct wl_resource *resource,
Daniel Stone37816df2012-05-16 18:45:18 +01001665 struct wl_resource *seat_resource,
Kristian Høgsberg3730f362012-04-13 12:40:07 -04001666 uint32_t serial,
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001667 struct wl_resource *parent_resource,
1668 int32_t x, int32_t y, uint32_t flags)
1669{
1670 struct shell_surface *shsurf = resource->data;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001671
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001672 shsurf->type = SHELL_SURFACE_POPUP;
1673 shsurf->parent = parent_resource->data;
Daniel Stone37816df2012-05-16 18:45:18 +01001674 shsurf->popup.seat = seat_resource->data;
Kristian Høgsberg3730f362012-04-13 12:40:07 -04001675 shsurf->popup.serial = serial;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001676 shsurf->popup.x = x;
1677 shsurf->popup.y = y;
1678}
1679
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001680static const struct wl_shell_surface_interface shell_surface_implementation = {
Scott Moreauff1db4a2012-04-17 19:06:18 -06001681 shell_surface_pong,
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001682 shell_surface_move,
1683 shell_surface_resize,
1684 shell_surface_set_toplevel,
1685 shell_surface_set_transient,
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001686 shell_surface_set_fullscreen,
Juan Zhao96879df2012-02-07 08:45:41 +08001687 shell_surface_set_popup,
Kristian Høgsberge7afd912012-05-02 09:47:44 -04001688 shell_surface_set_maximized,
1689 shell_surface_set_title,
1690 shell_surface_set_class
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001691};
1692
1693static void
Tiago Vignattibc052c92012-04-19 16:18:18 +03001694destroy_shell_surface(struct shell_surface *shsurf)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001695{
Daniel Stone37816df2012-05-16 18:45:18 +01001696 if (shsurf->popup.grab.pointer)
1697 wl_pointer_end_grab(shsurf->popup.grab.pointer);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001698
Alex Wubd3354b2012-04-17 17:20:49 +08001699 if (shsurf->fullscreen.type == WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER &&
1700 shell_surface_is_top_fullscreen(shsurf)) {
1701 weston_output_switch_mode(shsurf->fullscreen_output,
1702 shsurf->fullscreen_output->origin);
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03001703 }
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001704
Alex Wuaa08e2d2012-03-05 11:01:40 +08001705 if (shsurf->fullscreen.black_surface)
1706 weston_surface_destroy(shsurf->fullscreen.black_surface);
1707
Alex Wubd3354b2012-04-17 17:20:49 +08001708 /* As destroy_resource() use wl_list_for_each_safe(),
1709 * we can always remove the listener.
1710 */
1711 wl_list_remove(&shsurf->surface_destroy_listener.link);
1712 shsurf->surface->configure = NULL;
Scott Moreau9521d5e2012-04-19 13:06:17 -06001713 ping_timer_destroy(shsurf);
Alex Wubd3354b2012-04-17 17:20:49 +08001714
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001715 wl_list_remove(&shsurf->link);
1716 free(shsurf);
1717}
1718
1719static void
Tiago Vignattibc052c92012-04-19 16:18:18 +03001720shell_destroy_shell_surface(struct wl_resource *resource)
1721{
1722 struct shell_surface *shsurf = resource->data;
1723
1724 destroy_shell_surface(shsurf);
1725}
1726
1727static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001728shell_handle_surface_destroy(struct wl_listener *listener, void *data)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001729{
1730 struct shell_surface *shsurf = container_of(listener,
1731 struct shell_surface,
1732 surface_destroy_listener);
1733
Kristian Høgsberg633b1452012-06-07 18:08:47 -04001734 if (shsurf->resource.client) {
Tiago Vignattibc052c92012-04-19 16:18:18 +03001735 wl_resource_destroy(&shsurf->resource);
Kristian Høgsberg633b1452012-06-07 18:08:47 -04001736 } else {
1737 wl_signal_emit(&shsurf->resource.destroy_signal,
1738 &shsurf->resource);
Tiago Vignattibc052c92012-04-19 16:18:18 +03001739 destroy_shell_surface(shsurf);
Kristian Høgsberg633b1452012-06-07 18:08:47 -04001740 }
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001741}
1742
Kristian Høgsbergd8134452012-06-21 12:49:02 -04001743static void
1744shell_surface_configure(struct weston_surface *, int32_t, int32_t);
1745
Pekka Paalanenec2b32f2011-11-28 15:12:34 +02001746static struct shell_surface *
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001747get_shell_surface(struct weston_surface *surface)
Pekka Paalanenec2b32f2011-11-28 15:12:34 +02001748{
Kristian Høgsbergd8134452012-06-21 12:49:02 -04001749 if (surface->configure == shell_surface_configure)
1750 return surface->private;
1751 else
1752 return NULL;
Pekka Paalanenec2b32f2011-11-28 15:12:34 +02001753}
1754
Kristian Høgsberg45ba8692012-05-21 14:27:33 -04001755static struct shell_surface *
Kristian Høgsberga61ca062012-05-22 16:05:52 -04001756create_shell_surface(void *shell, struct weston_surface *surface,
1757 const struct weston_shell_client *client)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001758{
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001759 struct shell_surface *shsurf;
1760
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03001761 if (surface->configure) {
Martin Minarik6d118362012-06-07 18:01:59 +02001762 weston_log("surface->configure already set\n");
Kristian Høgsberg45ba8692012-05-21 14:27:33 -04001763 return NULL;
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03001764 }
1765
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001766 shsurf = calloc(1, sizeof *shsurf);
1767 if (!shsurf) {
Martin Minarik6d118362012-06-07 18:01:59 +02001768 weston_log("no memory to allocate shell surface\n");
Kristian Høgsberg45ba8692012-05-21 14:27:33 -04001769 return NULL;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001770 }
1771
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03001772 surface->configure = shell_surface_configure;
Kristian Høgsbergd8134452012-06-21 12:49:02 -04001773 surface->private = shsurf;
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03001774
Tiago Vignattibc052c92012-04-19 16:18:18 +03001775 shsurf->shell = (struct desktop_shell *) shell;
Scott Moreauff1db4a2012-04-17 19:06:18 -06001776 shsurf->unresponsive = 0;
Alex Wu4539b082012-03-01 12:57:46 +08001777 shsurf->saved_position_valid = false;
Alex Wu7bcb8bd2012-04-27 09:07:24 +08001778 shsurf->saved_rotation_valid = false;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001779 shsurf->surface = surface;
Alex Wu4539b082012-03-01 12:57:46 +08001780 shsurf->fullscreen.type = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT;
1781 shsurf->fullscreen.framerate = 0;
1782 shsurf->fullscreen.black_surface = NULL;
Scott Moreauff1db4a2012-04-17 19:06:18 -06001783 shsurf->ping_timer = NULL;
Alex Wu4539b082012-03-01 12:57:46 +08001784 wl_list_init(&shsurf->fullscreen.transform.link);
1785
Tiago Vignattibc052c92012-04-19 16:18:18 +03001786 wl_signal_init(&shsurf->resource.destroy_signal);
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001787 shsurf->surface_destroy_listener.notify = shell_handle_surface_destroy;
1788 wl_signal_add(&surface->surface.resource.destroy_signal,
1789 &shsurf->surface_destroy_listener);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001790
1791 /* init link so its safe to always remove it in destroy_shell_surface */
1792 wl_list_init(&shsurf->link);
1793
Pekka Paalanen460099f2012-01-20 16:48:25 +02001794 /* empty when not in use */
1795 wl_list_init(&shsurf->rotation.transform.link);
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05001796 weston_matrix_init(&shsurf->rotation.rotation);
Pekka Paalanen460099f2012-01-20 16:48:25 +02001797
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001798 wl_list_init(&shsurf->workspace_transform.link);
1799
Pekka Paalanen98262232011-12-01 10:42:22 +02001800 shsurf->type = SHELL_SURFACE_NONE;
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001801 shsurf->next_type = SHELL_SURFACE_NONE;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001802
Kristian Høgsberga61ca062012-05-22 16:05:52 -04001803 shsurf->client = client;
1804
Kristian Høgsberg45ba8692012-05-21 14:27:33 -04001805 return shsurf;
Tiago Vignattibc052c92012-04-19 16:18:18 +03001806}
1807
1808static void
1809shell_get_shell_surface(struct wl_client *client,
1810 struct wl_resource *resource,
1811 uint32_t id,
1812 struct wl_resource *surface_resource)
1813{
1814 struct weston_surface *surface = surface_resource->data;
1815 struct desktop_shell *shell = resource->data;
1816 struct shell_surface *shsurf;
1817
1818 if (get_shell_surface(surface)) {
1819 wl_resource_post_error(surface_resource,
Kristian Høgsberg9540ea62012-05-21 14:28:57 -04001820 WL_DISPLAY_ERROR_INVALID_OBJECT,
1821 "desktop_shell::get_shell_surface already requested");
Tiago Vignattibc052c92012-04-19 16:18:18 +03001822 return;
1823 }
1824
Kristian Høgsberga61ca062012-05-22 16:05:52 -04001825 shsurf = create_shell_surface(shell, surface, &shell_client);
Kristian Høgsberg9540ea62012-05-21 14:28:57 -04001826 if (!shsurf) {
1827 wl_resource_post_error(surface_resource,
1828 WL_DISPLAY_ERROR_INVALID_OBJECT,
1829 "surface->configure already set");
1830 return;
1831 }
Tiago Vignattibc052c92012-04-19 16:18:18 +03001832
Kristian Høgsberg9540ea62012-05-21 14:28:57 -04001833 shsurf->resource.destroy = shell_destroy_shell_surface;
1834 shsurf->resource.object.id = id;
1835 shsurf->resource.object.interface = &wl_shell_surface_interface;
1836 shsurf->resource.object.implementation =
1837 (void (**)(void)) &shell_surface_implementation;
1838 shsurf->resource.data = shsurf;
Tiago Vignattibc052c92012-04-19 16:18:18 +03001839
Kristian Høgsberg9540ea62012-05-21 14:28:57 -04001840 wl_client_add_resource(client, &shsurf->resource);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001841}
1842
1843static const struct wl_shell_interface shell_implementation = {
Pekka Paalanen46229672011-11-29 15:49:31 +02001844 shell_get_shell_surface
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001845};
1846
Kristian Høgsberg07937562011-04-12 17:25:42 -04001847static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001848handle_screensaver_sigchld(struct weston_process *proc, int status)
Pekka Paalanen18027e52011-12-02 16:31:49 +02001849{
1850 proc->pid = 0;
1851}
1852
1853static void
Tiago Vignattibe143262012-04-16 17:31:41 +03001854launch_screensaver(struct desktop_shell *shell)
Pekka Paalanen77346a62011-11-30 16:26:35 +02001855{
1856 if (shell->screensaver.binding)
1857 return;
1858
Pekka Paalanene955f1e2011-12-07 11:49:52 +02001859 if (!shell->screensaver.path)
1860 return;
1861
Kristian Høgsberg32bed572012-03-01 17:11:36 -05001862 if (shell->screensaver.process.pid != 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001863 weston_log("old screensaver still running\n");
Kristian Høgsberg32bed572012-03-01 17:11:36 -05001864 return;
1865 }
1866
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001867 weston_client_launch(shell->compositor,
Pekka Paalanen18027e52011-12-02 16:31:49 +02001868 &shell->screensaver.process,
Pekka Paalanene955f1e2011-12-07 11:49:52 +02001869 shell->screensaver.path,
Pekka Paalanen18027e52011-12-02 16:31:49 +02001870 handle_screensaver_sigchld);
Pekka Paalanen77346a62011-11-30 16:26:35 +02001871}
1872
1873static void
Tiago Vignattibe143262012-04-16 17:31:41 +03001874terminate_screensaver(struct desktop_shell *shell)
Pekka Paalanen77346a62011-11-30 16:26:35 +02001875{
Pekka Paalanen18027e52011-12-02 16:31:49 +02001876 if (shell->screensaver.process.pid == 0)
1877 return;
1878
1879 kill(shell->screensaver.process.pid, SIGTERM);
Pekka Paalanen77346a62011-11-30 16:26:35 +02001880}
1881
1882static void
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001883configure_static_surface(struct weston_surface *es, struct weston_layer *layer)
Kristian Høgsberg962342c2012-06-26 16:29:50 -04001884{
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001885 struct weston_surface *s, *next;
Kristian Høgsberg962342c2012-06-26 16:29:50 -04001886
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001887 wl_list_for_each_safe(s, next, &layer->surface_list, layer_link) {
1888 if (s->output == es->output && s != es) {
1889 weston_surface_unmap(s);
Kristian Høgsberg962342c2012-06-26 16:29:50 -04001890 s->configure = NULL;
Kristian Høgsberg962342c2012-06-26 16:29:50 -04001891 }
1892 }
1893
1894 weston_surface_configure(es, es->output->x, es->output->y,
1895 es->buffer->width, es->buffer->height);
1896
1897 if (wl_list_empty(&es->layer_link)) {
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001898 wl_list_insert(&layer->surface_list, &es->layer_link);
Kristian Høgsbergc7cd6262012-06-28 13:46:09 -04001899 weston_compositor_schedule_repaint(es->compositor);
Kristian Høgsberg962342c2012-06-26 16:29:50 -04001900 }
1901}
1902
1903static void
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001904background_configure(struct weston_surface *es, int32_t sx, int32_t sy)
1905{
1906 struct desktop_shell *shell = es->private;
1907
1908 configure_static_surface(es, &shell->background_layer);
1909}
1910
1911static void
Kristian Høgsberg75840622011-09-06 13:48:16 -04001912desktop_shell_set_background(struct wl_client *client,
1913 struct wl_resource *resource,
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01001914 struct wl_resource *output_resource,
Kristian Høgsberg75840622011-09-06 13:48:16 -04001915 struct wl_resource *surface_resource)
1916{
Kristian Høgsberg962342c2012-06-26 16:29:50 -04001917 struct desktop_shell *shell = resource->data;
1918 struct weston_surface *surface = surface_resource->data;
Kristian Høgsberg75840622011-09-06 13:48:16 -04001919
Kristian Høgsberg962342c2012-06-26 16:29:50 -04001920 if (surface->configure) {
1921 wl_resource_post_error(surface_resource,
1922 WL_DISPLAY_ERROR_INVALID_OBJECT,
1923 "surface role already assigned");
1924 return;
1925 }
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01001926
Kristian Høgsberg962342c2012-06-26 16:29:50 -04001927 surface->configure = background_configure;
1928 surface->private = shell;
1929 surface->output = output_resource->data;
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001930 desktop_shell_send_configure(resource, 0,
Kristian Høgsberg0b5cd0c2012-03-04 21:57:37 -05001931 surface_resource,
Kristian Høgsberg962342c2012-06-26 16:29:50 -04001932 surface->output->current->width,
1933 surface->output->current->height);
Kristian Høgsberg75840622011-09-06 13:48:16 -04001934}
1935
1936static void
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001937panel_configure(struct weston_surface *es, int32_t sx, int32_t sy)
1938{
1939 struct desktop_shell *shell = es->private;
1940
1941 configure_static_surface(es, &shell->panel_layer);
1942}
1943
1944static void
Kristian Høgsberg75840622011-09-06 13:48:16 -04001945desktop_shell_set_panel(struct wl_client *client,
1946 struct wl_resource *resource,
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01001947 struct wl_resource *output_resource,
Kristian Høgsberg75840622011-09-06 13:48:16 -04001948 struct wl_resource *surface_resource)
1949{
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001950 struct desktop_shell *shell = resource->data;
1951 struct weston_surface *surface = surface_resource->data;
Kristian Høgsberg75840622011-09-06 13:48:16 -04001952
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001953 if (surface->configure) {
1954 wl_resource_post_error(surface_resource,
1955 WL_DISPLAY_ERROR_INVALID_OBJECT,
1956 "surface role already assigned");
1957 return;
1958 }
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01001959
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001960 surface->configure = panel_configure;
1961 surface->private = shell;
1962 surface->output = output_resource->data;
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001963 desktop_shell_send_configure(resource, 0,
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001964 surface_resource,
1965 surface->output->current->width,
1966 surface->output->current->height);
Kristian Høgsberg75840622011-09-06 13:48:16 -04001967}
1968
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001969static void
Kristian Høgsberg730c94d2012-06-26 21:44:35 -04001970lock_surface_configure(struct weston_surface *surface, int32_t sx, int32_t sy)
1971{
1972 struct desktop_shell *shell = surface->private;
1973
1974 center_on_output(surface, get_default_output(shell->compositor));
1975
1976 if (!weston_surface_is_mapped(surface)) {
1977 wl_list_insert(&shell->lock_layer.surface_list,
1978 &surface->layer_link);
1979 weston_surface_assign_output(surface);
1980 weston_compositor_wake(shell->compositor);
1981 }
1982}
1983
1984static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001985handle_lock_surface_destroy(struct wl_listener *listener, void *data)
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001986{
Tiago Vignattibe143262012-04-16 17:31:41 +03001987 struct desktop_shell *shell =
1988 container_of(listener, struct desktop_shell, lock_surface_listener);
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001989
Martin Minarik6d118362012-06-07 18:01:59 +02001990 weston_log("lock surface gone\n");
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001991 shell->lock_surface = NULL;
1992}
1993
1994static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001995desktop_shell_set_lock_surface(struct wl_client *client,
1996 struct wl_resource *resource,
1997 struct wl_resource *surface_resource)
1998{
Tiago Vignattibe143262012-04-16 17:31:41 +03001999 struct desktop_shell *shell = resource->data;
Kristian Høgsberg730c94d2012-06-26 21:44:35 -04002000 struct weston_surface *surface = surface_resource->data;
Pekka Paalanen98262232011-12-01 10:42:22 +02002001
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002002 shell->prepare_event_sent = false;
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +02002003
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002004 if (!shell->locked)
2005 return;
2006
Pekka Paalanen98262232011-12-01 10:42:22 +02002007 shell->lock_surface = surface;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002008
Kristian Høgsberg27e30522012-04-11 23:18:23 -04002009 shell->lock_surface_listener.notify = handle_lock_surface_destroy;
2010 wl_signal_add(&surface_resource->destroy_signal,
2011 &shell->lock_surface_listener);
Pekka Paalanen57da4a82011-11-23 16:42:16 +02002012
Kristian Høgsberg730c94d2012-06-26 21:44:35 -04002013 surface->configure = lock_surface_configure;
2014 surface->private = shell;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002015}
2016
2017static void
Tiago Vignattibe143262012-04-16 17:31:41 +03002018resume_desktop(struct desktop_shell *shell)
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002019{
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04002020 struct weston_surface *surface;
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04002021 struct workspace *ws = get_current_workspace(shell);
Pekka Paalanen77346a62011-11-30 16:26:35 +02002022
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04002023 wl_list_for_each(surface, &shell->screensaver.surfaces, link)
2024 weston_surface_unmap(surface);
Pekka Paalanen77346a62011-11-30 16:26:35 +02002025
2026 terminate_screensaver(shell);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002027
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002028 wl_list_remove(&shell->lock_layer.link);
2029 wl_list_insert(&shell->compositor->cursor_layer.link,
2030 &shell->fullscreen_layer.link);
2031 wl_list_insert(&shell->fullscreen_layer.link,
2032 &shell->panel_layer.link);
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02002033 if (shell->showing_input_panels) {
2034 wl_list_insert(&shell->panel_layer.link,
2035 &shell->input_panel_layer.link);
2036 wl_list_insert(&shell->input_panel_layer.link,
2037 &ws->layer.link);
2038 } else {
2039 wl_list_insert(&shell->panel_layer.link, &ws->layer.link);
2040 }
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002041
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -04002042 restore_focus_state(shell, get_current_workspace(shell));
Jonas Ådahl04769742012-06-13 00:01:24 +02002043
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002044 shell->locked = false;
Pekka Paalanen7296e792011-12-07 16:22:00 +02002045 shell->compositor->idle_time = shell->compositor->option_idle_time;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002046 weston_compositor_wake(shell->compositor);
Pekka Paalanenfc6d91a2012-02-10 15:33:10 +02002047 weston_compositor_damage_all(shell->compositor);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002048}
2049
2050static void
2051desktop_shell_unlock(struct wl_client *client,
2052 struct wl_resource *resource)
2053{
Tiago Vignattibe143262012-04-16 17:31:41 +03002054 struct desktop_shell *shell = resource->data;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002055
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002056 shell->prepare_event_sent = false;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002057
2058 if (shell->locked)
2059 resume_desktop(shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002060}
2061
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04002062static void
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03002063desktop_shell_set_grab_surface(struct wl_client *client,
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04002064 struct wl_resource *resource,
2065 struct wl_resource *surface_resource)
2066{
2067 struct desktop_shell *shell = resource->data;
2068
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03002069 shell->grab_surface = surface_resource->data;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04002070}
2071
Kristian Høgsberg75840622011-09-06 13:48:16 -04002072static const struct desktop_shell_interface desktop_shell_implementation = {
2073 desktop_shell_set_background,
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002074 desktop_shell_set_panel,
2075 desktop_shell_set_lock_surface,
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04002076 desktop_shell_unlock,
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03002077 desktop_shell_set_grab_surface
Kristian Høgsberg75840622011-09-06 13:48:16 -04002078};
2079
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02002080static enum shell_surface_type
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002081get_shell_surface_type(struct weston_surface *surface)
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02002082{
2083 struct shell_surface *shsurf;
2084
2085 shsurf = get_shell_surface(surface);
2086 if (!shsurf)
Pekka Paalanen98262232011-12-01 10:42:22 +02002087 return SHELL_SURFACE_NONE;
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02002088 return shsurf->type;
2089}
2090
Kristian Høgsberg75840622011-09-06 13:48:16 -04002091static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002092move_binding(struct wl_seat *seat, uint32_t time, uint32_t button, void *data)
Kristian Høgsberg07937562011-04-12 17:25:42 -04002093{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002094 struct weston_surface *surface =
Daniel Stone37816df2012-05-16 18:45:18 +01002095 (struct weston_surface *) seat->pointer->focus;
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04002096 struct shell_surface *shsurf;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -05002097
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01002098 if (surface == NULL)
2099 return;
Kristian Høgsberg07937562011-04-12 17:25:42 -04002100
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04002101 shsurf = get_shell_surface(surface);
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04002102 if (shsurf == NULL || shsurf->type == SHELL_SURFACE_FULLSCREEN)
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04002103 return;
2104
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04002105 surface_move(shsurf, (struct weston_seat *) seat);
Kristian Høgsberg07937562011-04-12 17:25:42 -04002106}
2107
2108static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002109resize_binding(struct wl_seat *seat, uint32_t time, uint32_t button, void *data)
Kristian Høgsberg07937562011-04-12 17:25:42 -04002110{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002111 struct weston_surface *surface =
Daniel Stone37816df2012-05-16 18:45:18 +01002112 (struct weston_surface *) seat->pointer->focus;
Kristian Høgsberg07937562011-04-12 17:25:42 -04002113 uint32_t edges = 0;
2114 int32_t x, y;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002115 struct shell_surface *shsurf;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -05002116
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01002117 if (surface == NULL)
2118 return;
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02002119
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002120 shsurf = get_shell_surface(surface);
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04002121 if (!shsurf || shsurf->type == SHELL_SURFACE_FULLSCREEN)
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02002122 return;
2123
Pekka Paalanen5c97ae72012-01-30 16:19:47 +02002124 weston_surface_from_global(surface,
Daniel Stone37816df2012-05-16 18:45:18 +01002125 wl_fixed_to_int(seat->pointer->grab_x),
2126 wl_fixed_to_int(seat->pointer->grab_y),
Daniel Stone103db7f2012-05-08 17:17:55 +01002127 &x, &y);
Kristian Høgsberg07937562011-04-12 17:25:42 -04002128
Pekka Paalanen60921e52012-01-25 15:55:43 +02002129 if (x < surface->geometry.width / 3)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002130 edges |= WL_SHELL_SURFACE_RESIZE_LEFT;
Pekka Paalanen60921e52012-01-25 15:55:43 +02002131 else if (x < 2 * surface->geometry.width / 3)
Kristian Høgsberg07937562011-04-12 17:25:42 -04002132 edges |= 0;
2133 else
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002134 edges |= WL_SHELL_SURFACE_RESIZE_RIGHT;
Kristian Høgsberg07937562011-04-12 17:25:42 -04002135
Pekka Paalanen60921e52012-01-25 15:55:43 +02002136 if (y < surface->geometry.height / 3)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002137 edges |= WL_SHELL_SURFACE_RESIZE_TOP;
Pekka Paalanen60921e52012-01-25 15:55:43 +02002138 else if (y < 2 * surface->geometry.height / 3)
Kristian Høgsberg07937562011-04-12 17:25:42 -04002139 edges |= 0;
2140 else
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002141 edges |= WL_SHELL_SURFACE_RESIZE_BOTTOM;
Kristian Høgsberg07937562011-04-12 17:25:42 -04002142
Kristian Høgsbergc1693f22012-05-22 16:56:23 -04002143 surface_resize(shsurf, (struct weston_seat *) seat, edges);
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04002144}
2145
2146static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002147surface_opacity_binding(struct wl_seat *seat, uint32_t time, uint32_t axis,
Daniel Stone0c1e46e2012-05-30 16:31:59 +01002148 wl_fixed_t value, void *data)
Scott Moreaua3aa9c92012-03-22 11:01:03 -06002149{
Scott Moreau02709af2012-05-22 01:54:10 -06002150 float step = 0.05;
Scott Moreaua3aa9c92012-03-22 11:01:03 -06002151 struct shell_surface *shsurf;
2152 struct weston_surface *surface =
Daniel Stone37816df2012-05-16 18:45:18 +01002153 (struct weston_surface *) seat->pointer->focus;
Scott Moreaua3aa9c92012-03-22 11:01:03 -06002154
2155 if (surface == NULL)
2156 return;
2157
2158 shsurf = get_shell_surface(surface);
2159 if (!shsurf)
2160 return;
2161
Daniel Stone0c1e46e2012-05-30 16:31:59 +01002162 surface->alpha += wl_fixed_to_double(value) * step;
Scott Moreaua3aa9c92012-03-22 11:01:03 -06002163
Scott Moreau02709af2012-05-22 01:54:10 -06002164 if (surface->alpha > 1.0)
2165 surface->alpha = 1.0;
Scott Moreaua3aa9c92012-03-22 11:01:03 -06002166 if (surface->alpha < step)
2167 surface->alpha = step;
2168
2169 surface->geometry.dirty = 1;
2170 weston_surface_damage(surface);
2171}
2172
2173static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002174do_zoom(struct wl_seat *seat, uint32_t time, uint32_t key, uint32_t axis,
Daniel Stone0c1e46e2012-05-30 16:31:59 +01002175 wl_fixed_t value)
Scott Moreauccbf29d2012-02-22 14:21:41 -07002176{
Daniel Stone37816df2012-05-16 18:45:18 +01002177 struct weston_seat *ws = (struct weston_seat *) seat;
2178 struct weston_compositor *compositor = ws->compositor;
Scott Moreauccbf29d2012-02-22 14:21:41 -07002179 struct weston_output *output;
Scott Moreaue6603982012-06-11 13:07:51 -06002180 float increment;
Scott Moreauccbf29d2012-02-22 14:21:41 -07002181
2182 wl_list_for_each(output, &compositor->output_list, link) {
2183 if (pixman_region32_contains_point(&output->region,
Daniel Stone37816df2012-05-16 18:45:18 +01002184 wl_fixed_to_double(seat->pointer->x),
2185 wl_fixed_to_double(seat->pointer->y),
Daniel Stone103db7f2012-05-08 17:17:55 +01002186 NULL)) {
Daniel Stone325fc2d2012-05-30 16:31:58 +01002187 if (key == KEY_PAGEUP)
Kristian Høgsberg9b68af02012-05-22 12:55:18 -04002188 increment = output->zoom.increment;
Daniel Stone325fc2d2012-05-30 16:31:58 +01002189 else if (key == KEY_PAGEDOWN)
Kristian Høgsberg9b68af02012-05-22 12:55:18 -04002190 increment = -output->zoom.increment;
2191 else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
Daniel Stone0c1e46e2012-05-30 16:31:59 +01002192 increment = output->zoom.increment *
2193 wl_fixed_to_double(value);
Kristian Høgsberg9b68af02012-05-22 12:55:18 -04002194 else
2195 increment = 0;
2196
Kristian Høgsberg9b68af02012-05-22 12:55:18 -04002197 output->zoom.level += increment;
Scott Moreauc6d7f602012-02-23 22:28:37 -07002198
Scott Moreaue6603982012-06-11 13:07:51 -06002199 if (output->zoom.level < 0.0)
Scott Moreau850ca422012-05-21 15:21:25 -06002200 output->zoom.level = 0.0;
Scott Moreaue6603982012-06-11 13:07:51 -06002201 else if (output->zoom.level > output->zoom.max_level)
2202 output->zoom.level = output->zoom.max_level;
Kristian Høgsberg79af73e2012-08-03 15:45:23 -04002203 else {
Scott Moreaue6603982012-06-11 13:07:51 -06002204 output->zoom.active = 1;
Kristian Høgsberg79af73e2012-08-03 15:45:23 -04002205 output->disable_planes++;
2206 }
Scott Moreauccbf29d2012-02-22 14:21:41 -07002207
Scott Moreaue6603982012-06-11 13:07:51 -06002208 output->zoom.spring_z.target = output->zoom.level;
Scott Moreauccbf29d2012-02-22 14:21:41 -07002209
Scott Moreau8dacaab2012-06-17 18:10:58 -06002210 weston_output_update_zoom(output, output->zoom.type);
Scott Moreauccbf29d2012-02-22 14:21:41 -07002211 }
2212 }
2213}
2214
Scott Moreauccbf29d2012-02-22 14:21:41 -07002215static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002216zoom_axis_binding(struct wl_seat *seat, uint32_t time, uint32_t axis,
Daniel Stone0c1e46e2012-05-30 16:31:59 +01002217 wl_fixed_t value, void *data)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002218{
2219 do_zoom(seat, time, 0, axis, value);
2220}
2221
2222static void
2223zoom_key_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
2224 void *data)
2225{
2226 do_zoom(seat, time, key, 0, 0);
2227}
2228
2229static void
2230terminate_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
2231 void *data)
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05002232{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002233 struct weston_compositor *compositor = data;
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05002234
Daniel Stone325fc2d2012-05-30 16:31:58 +01002235 wl_display_terminate(compositor->wl_display);
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05002236}
2237
2238static void
Scott Moreau447013d2012-02-18 05:05:29 -07002239rotate_grab_motion(struct wl_pointer_grab *grab,
Daniel Stone103db7f2012-05-08 17:17:55 +01002240 uint32_t time, wl_fixed_t x, wl_fixed_t y)
Pekka Paalanen460099f2012-01-20 16:48:25 +02002241{
2242 struct rotate_grab *rotate =
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002243 container_of(grab, struct rotate_grab, base.grab);
Daniel Stone37816df2012-05-16 18:45:18 +01002244 struct wl_pointer *pointer = grab->pointer;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002245 struct shell_surface *shsurf = rotate->base.shsurf;
2246 struct weston_surface *surface;
2247 GLfloat cx, cy, dx, dy, cposx, cposy, dposx, dposy, r;
2248
2249 if (!shsurf)
2250 return;
2251
2252 surface = shsurf->surface;
2253
2254 cx = 0.5f * surface->geometry.width;
2255 cy = 0.5f * surface->geometry.height;
Pekka Paalanen460099f2012-01-20 16:48:25 +02002256
Daniel Stone37816df2012-05-16 18:45:18 +01002257 dx = wl_fixed_to_double(pointer->x) - rotate->center.x;
2258 dy = wl_fixed_to_double(pointer->y) - rotate->center.y;
Pekka Paalanen460099f2012-01-20 16:48:25 +02002259 r = sqrtf(dx * dx + dy * dy);
2260
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002261 wl_list_remove(&shsurf->rotation.transform.link);
2262 shsurf->surface->geometry.dirty = 1;
Pekka Paalanen460099f2012-01-20 16:48:25 +02002263
2264 if (r > 20.0f) {
Pekka Paalanen460099f2012-01-20 16:48:25 +02002265 struct weston_matrix *matrix =
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002266 &shsurf->rotation.transform.matrix;
Pekka Paalanen460099f2012-01-20 16:48:25 +02002267
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05002268 weston_matrix_init(&rotate->rotation);
2269 rotate->rotation.d[0] = dx / r;
2270 rotate->rotation.d[4] = -dy / r;
2271 rotate->rotation.d[1] = -rotate->rotation.d[4];
2272 rotate->rotation.d[5] = rotate->rotation.d[0];
Pekka Paalanen460099f2012-01-20 16:48:25 +02002273
2274 weston_matrix_init(matrix);
Pekka Paalanen7b3bd3d2012-01-30 14:16:34 +02002275 weston_matrix_translate(matrix, -cx, -cy, 0.0f);
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002276 weston_matrix_multiply(matrix, &shsurf->rotation.rotation);
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05002277 weston_matrix_multiply(matrix, &rotate->rotation);
Pekka Paalanen7b3bd3d2012-01-30 14:16:34 +02002278 weston_matrix_translate(matrix, cx, cy, 0.0f);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002279
Pekka Paalanenbc0b7e72012-01-24 09:53:37 +02002280 wl_list_insert(
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002281 &shsurf->surface->geometry.transformation_list,
2282 &shsurf->rotation.transform.link);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002283 } else {
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002284 wl_list_init(&shsurf->rotation.transform.link);
2285 weston_matrix_init(&shsurf->rotation.rotation);
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05002286 weston_matrix_init(&rotate->rotation);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002287 }
Pekka Paalanenb45ac5e2012-02-09 15:58:44 +02002288
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01002289 /* We need to adjust the position of the surface
2290 * in case it was resized in a rotated state before */
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002291 cposx = surface->geometry.x + cx;
2292 cposy = surface->geometry.y + cy;
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01002293 dposx = rotate->center.x - cposx;
2294 dposy = rotate->center.y - cposy;
2295 if (dposx != 0.0f || dposy != 0.0f) {
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002296 weston_surface_set_position(surface,
2297 surface->geometry.x + dposx,
2298 surface->geometry.y + dposy);
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01002299 }
2300
Pekka Paalanenb45ac5e2012-02-09 15:58:44 +02002301 /* Repaint implies weston_surface_update_transform(), which
2302 * lazily applies the damage due to rotation update.
2303 */
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002304 weston_compositor_schedule_repaint(shsurf->surface->compositor);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002305}
2306
2307static void
Scott Moreau447013d2012-02-18 05:05:29 -07002308rotate_grab_button(struct wl_pointer_grab *grab,
Daniel Stone4dbadb12012-05-30 16:31:51 +01002309 uint32_t time, uint32_t button, uint32_t state_w)
Pekka Paalanen460099f2012-01-20 16:48:25 +02002310{
2311 struct rotate_grab *rotate =
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002312 container_of(grab, struct rotate_grab, base.grab);
Daniel Stone37816df2012-05-16 18:45:18 +01002313 struct wl_pointer *pointer = grab->pointer;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002314 struct shell_surface *shsurf = rotate->base.shsurf;
Daniel Stone4dbadb12012-05-30 16:31:51 +01002315 enum wl_pointer_button_state state = state_w;
Pekka Paalanen460099f2012-01-20 16:48:25 +02002316
Daniel Stone4dbadb12012-05-30 16:31:51 +01002317 if (pointer->button_count == 0 &&
2318 state == WL_POINTER_BUTTON_STATE_RELEASED) {
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002319 if (shsurf)
2320 weston_matrix_multiply(&shsurf->rotation.rotation,
2321 &rotate->rotation);
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03002322 shell_grab_end(&rotate->base);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002323 free(rotate);
2324 }
2325}
2326
Scott Moreau447013d2012-02-18 05:05:29 -07002327static const struct wl_pointer_grab_interface rotate_grab_interface = {
Pekka Paalanen460099f2012-01-20 16:48:25 +02002328 noop_grab_focus,
2329 rotate_grab_motion,
2330 rotate_grab_button,
2331};
2332
2333static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002334rotate_binding(struct wl_seat *seat, uint32_t time, uint32_t button,
Daniel Stonee5a01202012-05-04 11:21:57 +01002335 void *data)
Pekka Paalanen460099f2012-01-20 16:48:25 +02002336{
2337 struct weston_surface *base_surface =
Daniel Stone37816df2012-05-16 18:45:18 +01002338 (struct weston_surface *) seat->pointer->focus;
Pekka Paalanen460099f2012-01-20 16:48:25 +02002339 struct shell_surface *surface;
2340 struct rotate_grab *rotate;
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01002341 GLfloat dx, dy;
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05002342 GLfloat r;
Pekka Paalanen460099f2012-01-20 16:48:25 +02002343
2344 if (base_surface == NULL)
2345 return;
2346
2347 surface = get_shell_surface(base_surface);
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04002348 if (!surface || surface->type == SHELL_SURFACE_FULLSCREEN)
Pekka Paalanen460099f2012-01-20 16:48:25 +02002349 return;
2350
Pekka Paalanen460099f2012-01-20 16:48:25 +02002351 rotate = malloc(sizeof *rotate);
2352 if (!rotate)
2353 return;
2354
Kristian Høgsbergb2af93e2012-06-07 20:10:23 -04002355 weston_surface_to_global_float(surface->surface,
2356 surface->surface->geometry.width / 2,
2357 surface->surface->geometry.height / 2,
2358 &rotate->center.x, &rotate->center.y);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002359
Daniel Stone37816df2012-05-16 18:45:18 +01002360 dx = wl_fixed_to_double(seat->pointer->x) - rotate->center.x;
2361 dy = wl_fixed_to_double(seat->pointer->y) - rotate->center.y;
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05002362 r = sqrtf(dx * dx + dy * dy);
2363 if (r > 20.0f) {
2364 struct weston_matrix inverse;
2365
2366 weston_matrix_init(&inverse);
2367 inverse.d[0] = dx / r;
2368 inverse.d[4] = dy / r;
2369 inverse.d[1] = -inverse.d[4];
2370 inverse.d[5] = inverse.d[0];
2371 weston_matrix_multiply(&surface->rotation.rotation, &inverse);
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01002372
2373 weston_matrix_init(&rotate->rotation);
2374 rotate->rotation.d[0] = dx / r;
2375 rotate->rotation.d[4] = -dy / r;
2376 rotate->rotation.d[1] = -rotate->rotation.d[4];
2377 rotate->rotation.d[5] = rotate->rotation.d[0];
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05002378 } else {
2379 weston_matrix_init(&surface->rotation.rotation);
2380 weston_matrix_init(&rotate->rotation);
2381 }
2382
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03002383 shell_grab_start(&rotate->base, &rotate_grab_interface, surface,
2384 seat->pointer, DESKTOP_SHELL_CURSOR_ARROW);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002385}
2386
2387static void
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04002388lower_fullscreen_layer(struct desktop_shell *shell)
2389{
2390 struct workspace *ws;
2391 struct weston_surface *surface, *prev;
2392
2393 ws = get_current_workspace(shell);
2394 wl_list_for_each_reverse_safe(surface, prev,
2395 &shell->fullscreen_layer.surface_list,
2396 layer_link)
2397 weston_surface_restack(surface, &ws->layer.surface_list);
2398}
2399
2400static void
Tiago Vignattibe143262012-04-16 17:31:41 +03002401activate(struct desktop_shell *shell, struct weston_surface *es,
Daniel Stone37816df2012-05-16 18:45:18 +01002402 struct weston_seat *seat)
Kristian Høgsberg75840622011-09-06 13:48:16 -04002403{
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -04002404 struct workspace *ws = get_current_workspace(shell);
2405 struct focus_state *state;
Kristian Høgsberg75840622011-09-06 13:48:16 -04002406
Daniel Stone37816df2012-05-16 18:45:18 +01002407 weston_surface_activate(es, seat);
Kristian Høgsberg75840622011-09-06 13:48:16 -04002408
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -04002409 wl_list_for_each(state, &ws->focus_list, link)
2410 if (state->seat == seat)
2411 break;
2412
2413 if (&state->link == &ws->focus_list) {
2414 state = focus_state_create(seat, ws);
2415 if (state == NULL)
2416 return;
2417 }
2418
2419 state->keyboard_focus = es;
2420 wl_list_remove(&state->surface_destroy_listener.link);
2421 wl_signal_add(&es->surface.resource.destroy_signal,
2422 &state->surface_destroy_listener);
2423
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02002424 switch (get_shell_surface_type(es)) {
Alex Wu4539b082012-03-01 12:57:46 +08002425 case SHELL_SURFACE_FULLSCREEN:
2426 /* should on top of panels */
Alex Wu21858432012-04-01 20:13:08 +08002427 shell_stack_fullscreen(get_shell_surface(es));
Alex Wubd3354b2012-04-17 17:20:49 +08002428 shell_configure_fullscreen(get_shell_surface(es));
Alex Wu4539b082012-03-01 12:57:46 +08002429 break;
Pekka Paalanen57da4a82011-11-23 16:42:16 +02002430 default:
Jonas Ådahle3cddce2012-06-13 00:01:22 +02002431 ws = get_current_workspace(shell);
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04002432 lower_fullscreen_layer(shell);
2433 weston_surface_restack(es, &ws->layer.surface_list);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002434 break;
Kristian Høgsberg75840622011-09-06 13:48:16 -04002435 }
2436}
2437
Alex Wu21858432012-04-01 20:13:08 +08002438/* no-op func for checking black surface */
2439static void
2440black_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
2441{
2442}
2443
2444static bool
2445is_black_surface (struct weston_surface *es, struct weston_surface **fs_surface)
2446{
2447 if (es->configure == black_surface_configure) {
2448 if (fs_surface)
2449 *fs_surface = (struct weston_surface *)es->private;
2450 return true;
2451 }
2452 return false;
2453}
2454
Kristian Høgsberg75840622011-09-06 13:48:16 -04002455static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002456click_to_activate_binding(struct wl_seat *seat, uint32_t time, uint32_t button,
Daniel Stone4dbadb12012-05-30 16:31:51 +01002457 void *data)
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05002458{
Daniel Stone37816df2012-05-16 18:45:18 +01002459 struct weston_seat *ws = (struct weston_seat *) seat;
Tiago Vignattibe143262012-04-16 17:31:41 +03002460 struct desktop_shell *shell = data;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002461 struct weston_surface *focus;
Alex Wu4539b082012-03-01 12:57:46 +08002462 struct weston_surface *upper;
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05002463
Daniel Stone37816df2012-05-16 18:45:18 +01002464 focus = (struct weston_surface *) seat->pointer->focus;
Alex Wu9c35e6b2012-03-05 14:13:13 +08002465 if (!focus)
2466 return;
2467
Alex Wu21858432012-04-01 20:13:08 +08002468 if (is_black_surface(focus, &upper))
Alex Wu4539b082012-03-01 12:57:46 +08002469 focus = upper;
Alex Wu4539b082012-03-01 12:57:46 +08002470
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04002471 if (get_shell_surface_type(focus) == SHELL_SURFACE_NONE)
2472 return;
Kristian Høgsberg85b2e4b2012-06-21 16:49:42 -04002473
Daniel Stone325fc2d2012-05-30 16:31:58 +01002474 if (seat->pointer->grab == &seat->pointer->default_grab)
Daniel Stone37816df2012-05-16 18:45:18 +01002475 activate(shell, focus, ws);
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05002476}
2477
2478static void
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04002479lock(struct wl_listener *listener, void *data)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04002480{
Tiago Vignattibe143262012-04-16 17:31:41 +03002481 struct desktop_shell *shell =
2482 container_of(listener, struct desktop_shell, lock_listener);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002483 struct weston_output *output;
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04002484 struct workspace *ws = get_current_workspace(shell);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002485
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002486 if (shell->locked) {
2487 wl_list_for_each(output, &shell->compositor->output_list, link)
2488 /* TODO: find a way to jump to other DPMS levels */
2489 if (output->set_dpms)
2490 output->set_dpms(output, WESTON_DPMS_STANDBY);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002491 return;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002492 }
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002493
2494 shell->locked = true;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002495
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002496 /* Hide all surfaces by removing the fullscreen, panel and
2497 * toplevel layers. This way nothing else can show or receive
2498 * input events while we are locked. */
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002499
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002500 wl_list_remove(&shell->panel_layer.link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002501 wl_list_remove(&shell->fullscreen_layer.link);
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02002502 if (shell->showing_input_panels)
2503 wl_list_remove(&shell->input_panel_layer.link);
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04002504 wl_list_remove(&ws->layer.link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002505 wl_list_insert(&shell->compositor->cursor_layer.link,
2506 &shell->lock_layer.link);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002507
Pekka Paalanen77346a62011-11-30 16:26:35 +02002508 launch_screensaver(shell);
2509
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002510 /* TODO: disable bindings that should not work while locked. */
2511
2512 /* All this must be undone in resume_desktop(). */
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002513}
2514
2515static void
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04002516unlock(struct wl_listener *listener, void *data)
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002517{
Tiago Vignattibe143262012-04-16 17:31:41 +03002518 struct desktop_shell *shell =
2519 container_of(listener, struct desktop_shell, unlock_listener);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002520
Pekka Paalanend81c2162011-11-16 13:47:34 +02002521 if (!shell->locked || shell->lock_surface) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002522 weston_compositor_wake(shell->compositor);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002523 return;
2524 }
2525
2526 /* If desktop-shell client has gone away, unlock immediately. */
2527 if (!shell->child.desktop_shell) {
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002528 resume_desktop(shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002529 return;
2530 }
2531
2532 if (shell->prepare_event_sent)
2533 return;
2534
Kristian Høgsberg0b5cd0c2012-03-04 21:57:37 -05002535 desktop_shell_send_prepare_lock_surface(shell->child.desktop_shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002536 shell->prepare_event_sent = true;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04002537}
2538
2539static void
Jan Arne Petersen42feced2012-06-21 21:52:17 +02002540show_input_panels(struct wl_listener *listener, void *data)
2541{
2542 struct desktop_shell *shell =
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02002543 container_of(listener, struct desktop_shell,
2544 show_input_panel_listener);
Philipp Brüschweiler88013572012-08-06 13:44:42 +02002545 struct input_panel_surface *surface, *next;
2546 struct weston_surface *ws;
Jan Arne Petersen42feced2012-06-21 21:52:17 +02002547
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02002548 shell->showing_input_panels = true;
2549
2550 wl_list_insert(&shell->panel_layer.link,
2551 &shell->input_panel_layer.link);
2552
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04002553 wl_list_for_each_safe(surface, next,
Philipp Brüschweiler88013572012-08-06 13:44:42 +02002554 &shell->input_panel.surfaces, link) {
2555 ws = surface->surface;
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02002556 wl_list_insert(&shell->input_panel_layer.surface_list,
Philipp Brüschweiler88013572012-08-06 13:44:42 +02002557 &ws->layer_link);
2558 weston_surface_assign_output(ws);
2559 weston_surface_damage(ws);
2560 weston_slide_run(ws, ws->geometry.height, 0, NULL, NULL);
Jan Arne Petersen42feced2012-06-21 21:52:17 +02002561 }
2562}
2563
2564static void
2565hide_input_panels(struct wl_listener *listener, void *data)
2566{
2567 struct desktop_shell *shell =
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02002568 container_of(listener, struct desktop_shell,
2569 hide_input_panel_listener);
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04002570 struct weston_surface *surface, *next;
Jan Arne Petersen42feced2012-06-21 21:52:17 +02002571
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02002572 shell->showing_input_panels = false;
2573
2574 wl_list_remove(&shell->input_panel_layer.link);
2575
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04002576 wl_list_for_each_safe(surface, next,
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02002577 &shell->input_panel_layer.surface_list, layer_link)
2578 weston_surface_unmap(surface);
Jan Arne Petersen42feced2012-06-21 21:52:17 +02002579}
2580
2581static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002582center_on_output(struct weston_surface *surface, struct weston_output *output)
Pekka Paalanen77346a62011-11-30 16:26:35 +02002583{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002584 struct weston_mode *mode = output->current;
Kristian Høgsberg730c94d2012-06-26 21:44:35 -04002585 GLfloat x = (mode->width - surface->buffer->width) / 2;
2586 GLfloat y = (mode->height - surface->buffer->height) / 2;
Pekka Paalanen77346a62011-11-30 16:26:35 +02002587
Kristian Høgsberg730c94d2012-06-26 21:44:35 -04002588 weston_surface_configure(surface, output->x + x, output->y + y,
2589 surface->buffer->width,
2590 surface->buffer->height);
Pekka Paalanen77346a62011-11-30 16:26:35 +02002591}
2592
2593static void
Rob Bradfordac63e5b2012-08-13 14:07:52 +01002594weston_surface_set_initial_position (struct weston_surface *surface,
2595 struct desktop_shell *shell)
2596{
2597 struct weston_compositor *compositor = shell->compositor;
2598 int ix = 0, iy = 0;
2599 int range_x, range_y;
2600 int dx, dy, x, y, panel_height;
2601 struct weston_output *output, *target_output = NULL;
2602 struct weston_seat *seat;
2603
2604 /* As a heuristic place the new window on the same output as the
2605 * pointer. Falling back to the output containing 0, 0.
2606 *
2607 * TODO: Do something clever for touch too?
2608 */
2609 wl_list_for_each(seat, &compositor->seat_list, link) {
2610 if (seat->has_pointer) {
2611 ix = wl_fixed_to_int(seat->pointer.x);
2612 iy = wl_fixed_to_int(seat->pointer.y);
2613 break;
2614 }
2615 }
2616
2617 wl_list_for_each(output, &compositor->output_list, link) {
2618 if (pixman_region32_contains_point(&output->region, ix, iy, NULL)) {
2619 target_output = output;
2620 break;
2621 }
2622 }
2623
2624 if (!target_output) {
2625 weston_surface_set_position(surface, 10 + random() % 400,
2626 10 + random() % 400);
2627 return;
2628 }
2629
2630 /* Valid range within output where the surface will still be onscreen.
2631 * If this is negative it means that the surface is bigger than
2632 * output.
2633 */
2634 panel_height = get_output_panel_height(shell, target_output);
2635 range_x = target_output->current->width - surface->geometry.width;
2636 range_y = (target_output->current->height - panel_height) -
2637 surface->geometry.height;
2638
Rob Bradford4cb88c72012-08-13 15:18:44 +01002639 if (range_x > 0)
Rob Bradfordac63e5b2012-08-13 14:07:52 +01002640 dx = random() % range_x;
Rob Bradfordac63e5b2012-08-13 14:07:52 +01002641 else
Rob Bradford4cb88c72012-08-13 15:18:44 +01002642 dx = 0;
2643
2644 if (range_y > 0)
Rob Bradfordac63e5b2012-08-13 14:07:52 +01002645 dy = panel_height + random() % range_y;
Rob Bradford4cb88c72012-08-13 15:18:44 +01002646 else
2647 dy = panel_height;
Rob Bradfordac63e5b2012-08-13 14:07:52 +01002648
2649 x = target_output->x + dx;
2650 y = target_output->y + dy;
2651
2652 weston_surface_set_position (surface, x, y);
2653}
2654
2655static void
Tiago Vignattibe143262012-04-16 17:31:41 +03002656map(struct desktop_shell *shell, struct weston_surface *surface,
Ander Conselvan de Oliveirae9e05152012-02-15 17:02:56 +02002657 int32_t width, int32_t height, int32_t sx, int32_t sy)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04002658{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002659 struct weston_compositor *compositor = shell->compositor;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02002660 struct shell_surface *shsurf = get_shell_surface(surface);
2661 enum shell_surface_type surface_type = shsurf->type;
Kristian Høgsberg60c49542012-03-05 20:51:34 -05002662 struct weston_surface *parent;
Daniel Stoneb2104682012-05-30 16:31:56 +01002663 struct weston_seat *seat;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02002664 struct workspace *ws;
Juan Zhao96879df2012-02-07 08:45:41 +08002665 int panel_height = 0;
Pekka Paalanen57da4a82011-11-23 16:42:16 +02002666
Pekka Paalanen60921e52012-01-25 15:55:43 +02002667 surface->geometry.width = width;
2668 surface->geometry.height = height;
2669 surface->geometry.dirty = 1;
Pekka Paalanen77346a62011-11-30 16:26:35 +02002670
2671 /* initial positioning, see also configure() */
2672 switch (surface_type) {
2673 case SHELL_SURFACE_TOPLEVEL:
Rob Bradfordac63e5b2012-08-13 14:07:52 +01002674 weston_surface_set_initial_position(surface, shell);
Pekka Paalanen77346a62011-11-30 16:26:35 +02002675 break;
Alex Wu4539b082012-03-01 12:57:46 +08002676 case SHELL_SURFACE_FULLSCREEN:
Kristian Høgsberge4d3a2b2012-07-09 21:43:22 -04002677 center_on_output(surface, shsurf->fullscreen_output);
Alex Wu4539b082012-03-01 12:57:46 +08002678 shell_map_fullscreen(shsurf);
2679 break;
Juan Zhao96879df2012-02-07 08:45:41 +08002680 case SHELL_SURFACE_MAXIMIZED:
Alex Wu4539b082012-03-01 12:57:46 +08002681 /* use surface configure to set the geometry */
Juan Zhao96879df2012-02-07 08:45:41 +08002682 panel_height = get_output_panel_height(shell,surface->output);
Rob Bradford31b68622012-07-02 19:00:19 +01002683 weston_surface_set_position(surface, shsurf->output->x,
2684 shsurf->output->y + panel_height);
Juan Zhao96879df2012-02-07 08:45:41 +08002685 break;
Tiago Vignatti0f997012012-02-10 16:17:23 +02002686 case SHELL_SURFACE_POPUP:
Kristian Høgsberg3730f362012-04-13 12:40:07 -04002687 shell_map_popup(shsurf);
Ander Conselvan de Oliveirae9e05152012-02-15 17:02:56 +02002688 case SHELL_SURFACE_NONE:
2689 weston_surface_set_position(surface,
2690 surface->geometry.x + sx,
2691 surface->geometry.y + sy);
Tiago Vignatti0f997012012-02-10 16:17:23 +02002692 break;
Pekka Paalanen77346a62011-11-30 16:26:35 +02002693 default:
2694 ;
2695 }
Kristian Høgsberg75840622011-09-06 13:48:16 -04002696
Pekka Paalanend3dd6e12011-11-16 13:47:33 +02002697 /* surface stacking order, see also activate() */
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02002698 switch (surface_type) {
Kristian Høgsberg60c49542012-03-05 20:51:34 -05002699 case SHELL_SURFACE_POPUP:
2700 case SHELL_SURFACE_TRANSIENT:
Kristian Høgsberg8150b192012-06-27 10:22:58 -04002701 parent = shsurf->parent;
Kristian Høgsberg60c49542012-03-05 20:51:34 -05002702 wl_list_insert(parent->layer_link.prev, &surface->layer_link);
2703 break;
Alex Wu4539b082012-03-01 12:57:46 +08002704 case SHELL_SURFACE_FULLSCREEN:
Ander Conselvan de Oliveiraa1ff53b2012-02-15 17:02:54 +02002705 case SHELL_SURFACE_NONE:
2706 break;
Pekka Paalanen57da4a82011-11-23 16:42:16 +02002707 default:
Jonas Ådahle3cddce2012-06-13 00:01:22 +02002708 ws = get_current_workspace(shell);
2709 wl_list_insert(&ws->layer.surface_list, &surface->layer_link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002710 break;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002711 }
2712
Ander Conselvan de Oliveirade56c312012-03-05 15:39:23 +02002713 if (surface_type != SHELL_SURFACE_NONE) {
2714 weston_surface_assign_output(surface);
Ander Conselvan de Oliveirade56c312012-03-05 15:39:23 +02002715 if (surface_type == SHELL_SURFACE_MAXIMIZED)
2716 surface->output = shsurf->output;
2717 }
Kristian Høgsberg2f88a402011-12-04 15:32:59 -05002718
Juan Zhao7bb92f02011-12-15 11:31:51 -05002719 switch (surface_type) {
Juan Zhao7bb92f02011-12-15 11:31:51 -05002720 case SHELL_SURFACE_TRANSIENT:
Tiago Vignatti99aeb1e2012-05-23 22:06:26 +03002721 if (shsurf->transient.flags ==
2722 WL_SHELL_SURFACE_TRANSIENT_INACTIVE)
2723 break;
2724 case SHELL_SURFACE_TOPLEVEL:
Juan Zhao7bb92f02011-12-15 11:31:51 -05002725 case SHELL_SURFACE_FULLSCREEN:
Juan Zhao96879df2012-02-07 08:45:41 +08002726 case SHELL_SURFACE_MAXIMIZED:
Daniel Stoneb2104682012-05-30 16:31:56 +01002727 if (!shell->locked) {
2728 wl_list_for_each(seat, &compositor->seat_list, link)
2729 activate(shell, surface, seat);
2730 }
Juan Zhao7bb92f02011-12-15 11:31:51 -05002731 break;
2732 default:
2733 break;
2734 }
2735
Kristian Høgsberg2f88a402011-12-04 15:32:59 -05002736 if (surface_type == SHELL_SURFACE_TOPLEVEL)
Juan Zhaoe10d2792012-04-25 19:09:52 +08002737 {
2738 switch (shell->win_animation_type) {
2739 case ANIMATION_FADE:
2740 weston_fade_run(surface, NULL, NULL);
2741 break;
2742 case ANIMATION_ZOOM:
2743 weston_zoom_run(surface, 0.8, 1.0, NULL, NULL);
2744 break;
2745 default:
2746 break;
2747 }
2748 }
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05002749}
2750
2751static void
Tiago Vignattibe143262012-04-16 17:31:41 +03002752configure(struct desktop_shell *shell, struct weston_surface *surface,
Pekka Paalanenddae03c2012-02-06 14:54:20 +02002753 GLfloat x, GLfloat y, int32_t width, int32_t height)
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05002754{
Pekka Paalanen77346a62011-11-30 16:26:35 +02002755 enum shell_surface_type surface_type = SHELL_SURFACE_NONE;
2756 struct shell_surface *shsurf;
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05002757
Pekka Paalanen77346a62011-11-30 16:26:35 +02002758 shsurf = get_shell_surface(surface);
2759 if (shsurf)
2760 surface_type = shsurf->type;
2761
Kristian Høgsberg6a8b5532012-02-16 23:43:59 -05002762 surface->geometry.x = x;
2763 surface->geometry.y = y;
Pekka Paalanen60921e52012-01-25 15:55:43 +02002764 surface->geometry.width = width;
2765 surface->geometry.height = height;
2766 surface->geometry.dirty = 1;
Pekka Paalanen77346a62011-11-30 16:26:35 +02002767
2768 switch (surface_type) {
Alex Wu4539b082012-03-01 12:57:46 +08002769 case SHELL_SURFACE_FULLSCREEN:
Alex Wubd3354b2012-04-17 17:20:49 +08002770 shell_stack_fullscreen(shsurf);
Alex Wu4539b082012-03-01 12:57:46 +08002771 shell_configure_fullscreen(shsurf);
Alex Wu4539b082012-03-01 12:57:46 +08002772 break;
Juan Zhao96879df2012-02-07 08:45:41 +08002773 case SHELL_SURFACE_MAXIMIZED:
Alex Wu4539b082012-03-01 12:57:46 +08002774 /* setting x, y and using configure to change that geometry */
Kristian Høgsberg6a8b5532012-02-16 23:43:59 -05002775 surface->geometry.x = surface->output->x;
2776 surface->geometry.y = surface->output->y +
2777 get_output_panel_height(shell,surface->output);
Juan Zhao96879df2012-02-07 08:45:41 +08002778 break;
Alex Wu4539b082012-03-01 12:57:46 +08002779 case SHELL_SURFACE_TOPLEVEL:
2780 break;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -05002781 default:
2782 break;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04002783 }
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05002784
Alex Wu4539b082012-03-01 12:57:46 +08002785 /* XXX: would a fullscreen surface need the same handling? */
Kristian Høgsberg6a8b5532012-02-16 23:43:59 -05002786 if (surface->output) {
Pekka Paalanenf07cb5d2012-02-10 13:34:36 +02002787 weston_surface_assign_output(surface);
Pekka Paalanen77346a62011-11-30 16:26:35 +02002788
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04002789 if (surface_type == SHELL_SURFACE_MAXIMIZED)
Juan Zhao96879df2012-02-07 08:45:41 +08002790 surface->output = shsurf->output;
Pekka Paalanen77346a62011-11-30 16:26:35 +02002791 }
Kristian Høgsberg07937562011-04-12 17:25:42 -04002792}
2793
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03002794static void
2795shell_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
2796{
Ander Conselvan de Oliveira7fb9f952012-03-27 17:36:42 +03002797 struct shell_surface *shsurf = get_shell_surface(es);
Tiago Vignattibe143262012-04-16 17:31:41 +03002798 struct desktop_shell *shell = shsurf->shell;
Tiago Vignatti70e5c9c2012-05-07 15:23:07 +03002799 int type_changed = 0;
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03002800
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04002801 if (shsurf->next_type != SHELL_SURFACE_NONE &&
Kristian Høgsbergf7e23d52012-04-27 17:51:59 -04002802 shsurf->type != shsurf->next_type) {
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04002803 set_surface_type(shsurf);
Kristian Høgsbergf7e23d52012-04-27 17:51:59 -04002804 type_changed = 1;
2805 }
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04002806
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03002807 if (!weston_surface_is_mapped(es)) {
2808 map(shell, es, es->buffer->width, es->buffer->height, sx, sy);
Kristian Høgsbergf7e23d52012-04-27 17:51:59 -04002809 } else if (type_changed || sx != 0 || sy != 0 ||
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03002810 es->geometry.width != es->buffer->width ||
2811 es->geometry.height != es->buffer->height) {
2812 GLfloat from_x, from_y;
2813 GLfloat to_x, to_y;
2814
2815 weston_surface_to_global_float(es, 0, 0, &from_x, &from_y);
2816 weston_surface_to_global_float(es, sx, sy, &to_x, &to_y);
2817 configure(shell, es,
2818 es->geometry.x + to_x - from_x,
2819 es->geometry.y + to_y - from_y,
2820 es->buffer->width, es->buffer->height);
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03002821 }
2822}
2823
Tiago Vignattibe143262012-04-16 17:31:41 +03002824static int launch_desktop_shell_process(struct desktop_shell *shell);
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02002825
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04002826static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002827desktop_shell_sigchld(struct weston_process *process, int status)
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02002828{
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02002829 uint32_t time;
Tiago Vignattibe143262012-04-16 17:31:41 +03002830 struct desktop_shell *shell =
2831 container_of(process, struct desktop_shell, child.process);
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02002832
2833 shell->child.process.pid = 0;
2834 shell->child.client = NULL; /* already destroyed by wayland */
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02002835
2836 /* if desktop-shell dies more than 5 times in 30 seconds, give up */
2837 time = weston_compositor_get_time();
Kristian Høgsbergf03a6162012-01-17 11:07:42 -05002838 if (time - shell->child.deathstamp > 30000) {
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02002839 shell->child.deathstamp = time;
2840 shell->child.deathcount = 0;
2841 }
2842
2843 shell->child.deathcount++;
2844 if (shell->child.deathcount > 5) {
Martin Minarik6d118362012-06-07 18:01:59 +02002845 weston_log("weston-desktop-shell died, giving up.\n");
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02002846 return;
2847 }
2848
Martin Minarik6d118362012-06-07 18:01:59 +02002849 weston_log("weston-desktop-shell died, respawning...\n");
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02002850 launch_desktop_shell_process(shell);
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02002851}
2852
2853static int
Tiago Vignattibe143262012-04-16 17:31:41 +03002854launch_desktop_shell_process(struct desktop_shell *shell)
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02002855{
Kristian Høgsberg9724b512012-01-03 14:35:49 -05002856 const char *shell_exe = LIBEXECDIR "/weston-desktop-shell";
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02002857
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002858 shell->child.client = weston_client_launch(shell->compositor,
Pekka Paalanen409ef0a2011-12-02 15:30:21 +02002859 &shell->child.process,
2860 shell_exe,
2861 desktop_shell_sigchld);
2862
2863 if (!shell->child.client)
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02002864 return -1;
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02002865 return 0;
2866}
2867
2868static void
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04002869bind_shell(struct wl_client *client, void *data, uint32_t version, uint32_t id)
2870{
Tiago Vignattibe143262012-04-16 17:31:41 +03002871 struct desktop_shell *shell = data;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04002872
2873 wl_client_add_object(client, &wl_shell_interface,
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002874 &shell_implementation, id, shell);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04002875}
2876
Kristian Høgsberg75840622011-09-06 13:48:16 -04002877static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002878unbind_desktop_shell(struct wl_resource *resource)
2879{
Tiago Vignattibe143262012-04-16 17:31:41 +03002880 struct desktop_shell *shell = resource->data;
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05002881
2882 if (shell->locked)
2883 resume_desktop(shell);
2884
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002885 shell->child.desktop_shell = NULL;
2886 shell->prepare_event_sent = false;
2887 free(resource);
2888}
2889
2890static void
Kristian Høgsberg75840622011-09-06 13:48:16 -04002891bind_desktop_shell(struct wl_client *client,
2892 void *data, uint32_t version, uint32_t id)
2893{
Tiago Vignattibe143262012-04-16 17:31:41 +03002894 struct desktop_shell *shell = data;
Pekka Paalanenbbe60522011-11-03 14:11:33 +02002895 struct wl_resource *resource;
Kristian Høgsberg75840622011-09-06 13:48:16 -04002896
Pekka Paalanenbbe60522011-11-03 14:11:33 +02002897 resource = wl_client_add_object(client, &desktop_shell_interface,
2898 &desktop_shell_implementation,
2899 id, shell);
2900
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002901 if (client == shell->child.client) {
2902 resource->destroy = unbind_desktop_shell;
2903 shell->child.desktop_shell = resource;
Pekka Paalanenbbe60522011-11-03 14:11:33 +02002904 return;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002905 }
Pekka Paalanenbbe60522011-11-03 14:11:33 +02002906
2907 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
2908 "permission to bind desktop_shell denied");
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04002909 wl_resource_destroy(resource);
Kristian Høgsberg75840622011-09-06 13:48:16 -04002910}
2911
Pekka Paalanen6e168112011-11-24 11:34:05 +02002912static void
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04002913screensaver_configure(struct weston_surface *surface, int32_t sx, int32_t sy)
2914{
2915 struct desktop_shell *shell = surface->private;
2916
2917 if (!shell->locked)
2918 return;
2919
2920 center_on_output(surface, surface->output);
2921
2922 if (wl_list_empty(&surface->layer_link)) {
2923 wl_list_insert(shell->lock_layer.surface_list.prev,
2924 &surface->layer_link);
2925 weston_surface_assign_output(surface);
2926 shell->compositor->idle_time = shell->screensaver.duration;
2927 weston_compositor_wake(shell->compositor);
2928 shell->compositor->state = WESTON_COMPOSITOR_IDLE;
2929 }
2930}
2931
2932static void
Pekka Paalanen6e168112011-11-24 11:34:05 +02002933screensaver_set_surface(struct wl_client *client,
2934 struct wl_resource *resource,
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04002935 struct wl_resource *surface_resource,
Pekka Paalanen6e168112011-11-24 11:34:05 +02002936 struct wl_resource *output_resource)
2937{
Tiago Vignattibe143262012-04-16 17:31:41 +03002938 struct desktop_shell *shell = resource->data;
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04002939 struct weston_surface *surface = surface_resource->data;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002940 struct weston_output *output = output_resource->data;
Pekka Paalanen6e168112011-11-24 11:34:05 +02002941
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04002942 surface->configure = screensaver_configure;
2943 surface->private = shell;
Pekka Paalanen77346a62011-11-30 16:26:35 +02002944 surface->output = output;
Pekka Paalanen6e168112011-11-24 11:34:05 +02002945}
2946
2947static const struct screensaver_interface screensaver_implementation = {
2948 screensaver_set_surface
2949};
2950
2951static void
2952unbind_screensaver(struct wl_resource *resource)
2953{
Tiago Vignattibe143262012-04-16 17:31:41 +03002954 struct desktop_shell *shell = resource->data;
Pekka Paalanen6e168112011-11-24 11:34:05 +02002955
Pekka Paalanen77346a62011-11-30 16:26:35 +02002956 shell->screensaver.binding = NULL;
Pekka Paalanen6e168112011-11-24 11:34:05 +02002957 free(resource);
2958}
2959
2960static void
2961bind_screensaver(struct wl_client *client,
2962 void *data, uint32_t version, uint32_t id)
2963{
Tiago Vignattibe143262012-04-16 17:31:41 +03002964 struct desktop_shell *shell = data;
Pekka Paalanen6e168112011-11-24 11:34:05 +02002965 struct wl_resource *resource;
2966
2967 resource = wl_client_add_object(client, &screensaver_interface,
2968 &screensaver_implementation,
2969 id, shell);
2970
Pekka Paalanen77346a62011-11-30 16:26:35 +02002971 if (shell->screensaver.binding == NULL) {
Pekka Paalanen6e168112011-11-24 11:34:05 +02002972 resource->destroy = unbind_screensaver;
Pekka Paalanen77346a62011-11-30 16:26:35 +02002973 shell->screensaver.binding = resource;
Pekka Paalanen6e168112011-11-24 11:34:05 +02002974 return;
2975 }
2976
2977 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
2978 "interface object already bound");
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04002979 wl_resource_destroy(resource);
Pekka Paalanen6e168112011-11-24 11:34:05 +02002980}
2981
Jan Arne Petersen42feced2012-06-21 21:52:17 +02002982static void
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04002983input_panel_configure(struct weston_surface *surface, int32_t sx, int32_t sy)
2984{
2985 struct weston_mode *mode = surface->output->current;
2986 GLfloat x = (mode->width - surface->buffer->width) / 2;
2987 GLfloat y = mode->height - surface->buffer->height;
2988
2989 /* Don't map the input panel here, wait for
2990 * show_input_panels signal. */
2991
2992 weston_surface_configure(surface,
2993 surface->output->x + x,
2994 surface->output->y + y,
2995 surface->buffer->width,
2996 surface->buffer->height);
2997}
2998
2999static void
Philipp Brüschweiler88013572012-08-06 13:44:42 +02003000destroy_input_panel_surface(struct wl_listener *listener,
3001 void *data)
3002{
3003 struct input_panel_surface *input_panel_surface =
3004 container_of(listener, struct input_panel_surface, listener);
3005
3006 wl_list_remove(&listener->link);
3007 wl_list_remove(&input_panel_surface->link);
3008
3009 free(input_panel_surface);
3010}
3011
3012static void
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003013input_panel_set_surface(struct wl_client *client,
3014 struct wl_resource *resource,
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04003015 struct wl_resource *surface_resource,
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003016 struct wl_resource *output_resource)
3017{
3018 struct desktop_shell *shell = resource->data;
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04003019 struct weston_surface *surface = surface_resource->data;
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003020 struct weston_output *output = output_resource->data;
Philipp Brüschweiler88013572012-08-06 13:44:42 +02003021 struct input_panel_surface *input_panel_surface;
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003022
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04003023 surface->configure = input_panel_configure;
3024 surface->private = shell;
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003025 surface->output = output;
Philipp Brüschweiler88013572012-08-06 13:44:42 +02003026
3027 input_panel_surface = malloc(sizeof *input_panel_surface);
3028 if (!input_panel_surface) {
3029 wl_resource_post_no_memory(resource);
3030 return;
3031 }
3032
3033 input_panel_surface->surface = surface;
3034 input_panel_surface->listener.notify = destroy_input_panel_surface;
3035
3036 wl_signal_add(&surface_resource->destroy_signal,
3037 &input_panel_surface->listener);
3038
3039 wl_list_insert(&shell->input_panel.surfaces,
3040 &input_panel_surface->link);
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003041}
3042
3043static const struct input_panel_interface input_panel_implementation = {
3044 input_panel_set_surface
3045};
3046
3047static void
3048unbind_input_panel(struct wl_resource *resource)
3049{
3050 struct desktop_shell *shell = resource->data;
3051
3052 shell->input_panel.binding = NULL;
3053 free(resource);
3054}
3055
3056static void
3057bind_input_panel(struct wl_client *client,
3058 void *data, uint32_t version, uint32_t id)
3059{
3060 struct desktop_shell *shell = data;
3061 struct wl_resource *resource;
3062
3063 resource = wl_client_add_object(client, &input_panel_interface,
3064 &input_panel_implementation,
3065 id, shell);
3066
3067 if (shell->input_panel.binding == NULL) {
3068 resource->destroy = unbind_input_panel;
3069 shell->input_panel.binding = resource;
3070 return;
3071 }
3072
3073 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
3074 "interface object already bound");
3075 wl_resource_destroy(resource);
3076}
3077
Kristian Høgsberg07045392012-02-19 18:52:44 -05003078struct switcher {
Tiago Vignattibe143262012-04-16 17:31:41 +03003079 struct desktop_shell *shell;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003080 struct weston_surface *current;
3081 struct wl_listener listener;
3082 struct wl_keyboard_grab grab;
3083};
3084
3085static void
3086switcher_next(struct switcher *switcher)
3087{
Kristian Høgsberg07045392012-02-19 18:52:44 -05003088 struct weston_surface *surface;
3089 struct weston_surface *first = NULL, *prev = NULL, *next = NULL;
Kristian Høgsberg32e56862012-04-02 22:18:58 -04003090 struct shell_surface *shsurf;
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04003091 struct workspace *ws = get_current_workspace(switcher->shell);
Kristian Høgsberg07045392012-02-19 18:52:44 -05003092
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04003093 wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
Kristian Høgsberg07045392012-02-19 18:52:44 -05003094 switch (get_shell_surface_type(surface)) {
3095 case SHELL_SURFACE_TOPLEVEL:
3096 case SHELL_SURFACE_FULLSCREEN:
3097 case SHELL_SURFACE_MAXIMIZED:
3098 if (first == NULL)
3099 first = surface;
3100 if (prev == switcher->current)
3101 next = surface;
3102 prev = surface;
Scott Moreau02709af2012-05-22 01:54:10 -06003103 surface->alpha = 0.25;
Kristian Høgsbergcacb7cd2012-02-28 09:20:21 -05003104 surface->geometry.dirty = 1;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003105 weston_surface_damage(surface);
3106 break;
3107 default:
3108 break;
3109 }
Alex Wu1659daa2012-04-01 20:13:09 +08003110
3111 if (is_black_surface(surface, NULL)) {
Scott Moreau02709af2012-05-22 01:54:10 -06003112 surface->alpha = 0.25;
Alex Wu1659daa2012-04-01 20:13:09 +08003113 surface->geometry.dirty = 1;
3114 weston_surface_damage(surface);
3115 }
Kristian Høgsberg07045392012-02-19 18:52:44 -05003116 }
3117
3118 if (next == NULL)
3119 next = first;
3120
Alex Wu07b26062012-03-12 16:06:01 +08003121 if (next == NULL)
3122 return;
3123
Kristian Høgsberg07045392012-02-19 18:52:44 -05003124 wl_list_remove(&switcher->listener.link);
Kristian Høgsberg27e30522012-04-11 23:18:23 -04003125 wl_signal_add(&next->surface.resource.destroy_signal,
3126 &switcher->listener);
Kristian Høgsberg07045392012-02-19 18:52:44 -05003127
3128 switcher->current = next;
Kristian Høgsberga416fa12012-05-21 14:06:52 -04003129 next->alpha = 1.0;
Alex Wu1659daa2012-04-01 20:13:09 +08003130
Kristian Høgsberg32e56862012-04-02 22:18:58 -04003131 shsurf = get_shell_surface(switcher->current);
3132 if (shsurf && shsurf->type ==SHELL_SURFACE_FULLSCREEN)
Kristian Høgsberga416fa12012-05-21 14:06:52 -04003133 shsurf->fullscreen.black_surface->alpha = 1.0;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003134}
3135
3136static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04003137switcher_handle_surface_destroy(struct wl_listener *listener, void *data)
Kristian Høgsberg07045392012-02-19 18:52:44 -05003138{
3139 struct switcher *switcher =
3140 container_of(listener, struct switcher, listener);
3141
3142 switcher_next(switcher);
3143}
3144
3145static void
Daniel Stone351eb612012-05-31 15:27:47 -04003146switcher_destroy(struct switcher *switcher)
Kristian Høgsberg07045392012-02-19 18:52:44 -05003147{
Kristian Høgsberg07045392012-02-19 18:52:44 -05003148 struct weston_surface *surface;
Daniel Stone37816df2012-05-16 18:45:18 +01003149 struct wl_keyboard *keyboard = switcher->grab.keyboard;
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04003150 struct workspace *ws = get_current_workspace(switcher->shell);
Kristian Høgsberg07045392012-02-19 18:52:44 -05003151
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04003152 wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
Kristian Høgsberga416fa12012-05-21 14:06:52 -04003153 surface->alpha = 1.0;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003154 weston_surface_damage(surface);
3155 }
3156
Alex Wu07b26062012-03-12 16:06:01 +08003157 if (switcher->current)
Daniel Stone37816df2012-05-16 18:45:18 +01003158 activate(switcher->shell, switcher->current,
3159 (struct weston_seat *) keyboard->seat);
Kristian Høgsberg07045392012-02-19 18:52:44 -05003160 wl_list_remove(&switcher->listener.link);
Daniel Stone37816df2012-05-16 18:45:18 +01003161 wl_keyboard_end_grab(keyboard);
Kristian Høgsberg07045392012-02-19 18:52:44 -05003162 free(switcher);
3163}
3164
3165static void
3166switcher_key(struct wl_keyboard_grab *grab,
Daniel Stonec9785ea2012-05-30 16:31:52 +01003167 uint32_t time, uint32_t key, uint32_t state_w)
Kristian Høgsberg07045392012-02-19 18:52:44 -05003168{
3169 struct switcher *switcher = container_of(grab, struct switcher, grab);
Daniel Stonec9785ea2012-05-30 16:31:52 +01003170 enum wl_keyboard_key_state state = state_w;
Daniel Stone351eb612012-05-31 15:27:47 -04003171
Daniel Stonec9785ea2012-05-30 16:31:52 +01003172 if (key == KEY_TAB && state == WL_KEYBOARD_KEY_STATE_PRESSED)
Daniel Stone351eb612012-05-31 15:27:47 -04003173 switcher_next(switcher);
3174}
3175
3176static void
3177switcher_modifier(struct wl_keyboard_grab *grab, uint32_t serial,
3178 uint32_t mods_depressed, uint32_t mods_latched,
3179 uint32_t mods_locked, uint32_t group)
3180{
3181 struct switcher *switcher = container_of(grab, struct switcher, grab);
Daniel Stone37816df2012-05-16 18:45:18 +01003182 struct weston_seat *seat = (struct weston_seat *) grab->keyboard->seat;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003183
Daniel Stone351eb612012-05-31 15:27:47 -04003184 if ((seat->modifier_state & switcher->shell->binding_modifier) == 0)
3185 switcher_destroy(switcher);
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04003186}
Kristian Høgsberg07045392012-02-19 18:52:44 -05003187
3188static const struct wl_keyboard_grab_interface switcher_grab = {
Daniel Stone351eb612012-05-31 15:27:47 -04003189 switcher_key,
3190 switcher_modifier,
Kristian Høgsberg07045392012-02-19 18:52:44 -05003191};
3192
3193static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01003194switcher_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
3195 void *data)
Kristian Høgsberg07045392012-02-19 18:52:44 -05003196{
Tiago Vignattibe143262012-04-16 17:31:41 +03003197 struct desktop_shell *shell = data;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003198 struct switcher *switcher;
3199
3200 switcher = malloc(sizeof *switcher);
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04003201 switcher->shell = shell;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003202 switcher->current = NULL;
Kristian Høgsberg27e30522012-04-11 23:18:23 -04003203 switcher->listener.notify = switcher_handle_surface_destroy;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003204 wl_list_init(&switcher->listener.link);
3205
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04003206 lower_fullscreen_layer(switcher->shell);
Kristian Høgsberg07045392012-02-19 18:52:44 -05003207 switcher->grab.interface = &switcher_grab;
Daniel Stone37816df2012-05-16 18:45:18 +01003208 wl_keyboard_start_grab(seat->keyboard, &switcher->grab);
3209 wl_keyboard_set_focus(seat->keyboard, NULL);
Kristian Høgsberg07045392012-02-19 18:52:44 -05003210 switcher_next(switcher);
3211}
3212
Pekka Paalanen3c647232011-12-22 13:43:43 +02003213static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01003214backlight_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
3215 void *data)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003216{
3217 struct weston_compositor *compositor = data;
3218 struct weston_output *output;
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03003219 long backlight_new = 0;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003220
3221 /* TODO: we're limiting to simple use cases, where we assume just
3222 * control on the primary display. We'd have to extend later if we
3223 * ever get support for setting backlights on random desktop LCD
3224 * panels though */
3225 output = get_default_output(compositor);
3226 if (!output)
3227 return;
3228
3229 if (!output->set_backlight)
3230 return;
3231
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03003232 if (key == KEY_F9 || key == KEY_BRIGHTNESSDOWN)
3233 backlight_new = output->backlight_current - 25;
3234 else if (key == KEY_F10 || key == KEY_BRIGHTNESSUP)
3235 backlight_new = output->backlight_current + 25;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003236
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03003237 if (backlight_new < 5)
3238 backlight_new = 5;
3239 if (backlight_new > 255)
3240 backlight_new = 255;
3241
3242 output->backlight_current = backlight_new;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003243 output->set_backlight(output, output->backlight_current);
3244}
3245
3246static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01003247debug_repaint_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
3248 void *data)
Kristian Høgsbergb41c0812012-03-04 14:53:40 -05003249{
Tiago Vignattibe143262012-04-16 17:31:41 +03003250 struct desktop_shell *shell = data;
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04003251 struct weston_compositor *compositor = shell->compositor;
Kristian Høgsbergb41c0812012-03-04 14:53:40 -05003252 struct weston_surface *surface;
Ander Conselvan de Oliveira383b6712012-08-09 16:44:59 +03003253 struct weston_plane plane;
Kristian Høgsbergb41c0812012-03-04 14:53:40 -05003254
3255 if (shell->debug_repaint_surface) {
3256 weston_surface_destroy(shell->debug_repaint_surface);
3257 shell->debug_repaint_surface = NULL;
3258 } else {
3259 surface = weston_surface_create(compositor);
3260 weston_surface_set_color(surface, 1.0, 0.0, 0.0, 0.2);
3261 weston_surface_configure(surface, 0, 0, 8192, 8192);
3262 wl_list_insert(&compositor->fade_layer.surface_list,
3263 &surface->layer_link);
3264 weston_surface_assign_output(surface);
3265 pixman_region32_init(&surface->input);
3266
3267 /* Here's the dirty little trick that makes the
Ander Conselvan de Oliveira383b6712012-08-09 16:44:59 +03003268 * repaint debugging work: we move the surface to a
3269 * different plane and force an update_transform to
3270 * update dependent state and clear the
3271 * geometry.dirty bit. This way the call to
3272 * damage_below() in update_transform() does not
3273 * add damage to the primary plane. */
Kristian Høgsbergb41c0812012-03-04 14:53:40 -05003274
Ander Conselvan de Oliveira383b6712012-08-09 16:44:59 +03003275 weston_plane_init(&plane, 0, 0);
3276 surface->plane = &plane;
Kristian Høgsbergb41c0812012-03-04 14:53:40 -05003277 weston_surface_update_transform(surface);
Kristian Høgsbergb41c0812012-03-04 14:53:40 -05003278 shell->debug_repaint_surface = surface;
Ander Conselvan de Oliveira383b6712012-08-09 16:44:59 +03003279 surface->plane = &compositor->primary_plane;
3280 weston_plane_release(&plane);
Kristian Høgsbergb41c0812012-03-04 14:53:40 -05003281 }
3282}
3283
3284static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01003285force_kill_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
3286 void *data)
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04003287{
3288 struct wl_client *client;
3289 pid_t pid;
3290 uid_t uid;
3291 gid_t gid;
3292
Daniel Stone325fc2d2012-05-30 16:31:58 +01003293 client = seat->keyboard->focus->resource.client;
3294 wl_client_get_credentials(client, &pid, &uid, &gid);
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04003295
Daniel Stone325fc2d2012-05-30 16:31:58 +01003296 kill(pid, SIGKILL);
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04003297}
3298
3299static void
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003300workspace_up_binding(struct wl_seat *seat, uint32_t time,
3301 uint32_t key, void *data)
3302{
3303 struct desktop_shell *shell = data;
3304 unsigned int new_index = shell->workspaces.current;
3305
Kristian Høgsbergce345b02012-06-25 21:35:29 -04003306 if (shell->locked)
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04003307 return;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003308 if (new_index != 0)
3309 new_index--;
3310
3311 change_workspace(shell, new_index);
3312}
3313
3314static void
3315workspace_down_binding(struct wl_seat *seat, uint32_t time,
3316 uint32_t key, void *data)
3317{
3318 struct desktop_shell *shell = data;
3319 unsigned int new_index = shell->workspaces.current;
3320
Kristian Høgsbergce345b02012-06-25 21:35:29 -04003321 if (shell->locked)
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04003322 return;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003323 if (new_index < shell->workspaces.num - 1)
3324 new_index++;
3325
3326 change_workspace(shell, new_index);
3327}
3328
3329static void
3330workspace_f_binding(struct wl_seat *seat, uint32_t time,
3331 uint32_t key, void *data)
3332{
3333 struct desktop_shell *shell = data;
3334 unsigned int new_index;
3335
Kristian Høgsbergce345b02012-06-25 21:35:29 -04003336 if (shell->locked)
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04003337 return;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003338 new_index = key - KEY_F1;
3339 if (new_index >= shell->workspaces.num)
3340 new_index = shell->workspaces.num - 1;
3341
3342 change_workspace(shell, new_index);
3343}
3344
3345
3346static void
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04003347shell_destroy(struct wl_listener *listener, void *data)
Pekka Paalanen3c647232011-12-22 13:43:43 +02003348{
Tiago Vignattibe143262012-04-16 17:31:41 +03003349 struct desktop_shell *shell =
3350 container_of(listener, struct desktop_shell, destroy_listener);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003351 struct workspace **ws;
Pekka Paalanen3c647232011-12-22 13:43:43 +02003352
Pekka Paalanen9cf5cc82012-01-02 16:00:24 +02003353 if (shell->child.client)
3354 wl_client_destroy(shell->child.client);
3355
Kristian Høgsberg88c16072012-05-16 08:04:19 -04003356 wl_list_remove(&shell->lock_listener.link);
3357 wl_list_remove(&shell->unlock_listener.link);
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003358 wl_list_remove(&shell->show_input_panel_listener.link);
3359 wl_list_remove(&shell->hide_input_panel_listener.link);
Kristian Høgsberg88c16072012-05-16 08:04:19 -04003360
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003361 wl_array_for_each(ws, &shell->workspaces.array)
3362 workspace_destroy(*ws);
3363 wl_array_release(&shell->workspaces.array);
3364
Pekka Paalanen3c647232011-12-22 13:43:43 +02003365 free(shell->screensaver.path);
3366 free(shell);
3367}
3368
Tiago Vignatti0b52d482012-04-20 18:54:25 +03003369static void
3370shell_add_bindings(struct weston_compositor *ec, struct desktop_shell *shell)
3371{
3372 uint32_t mod;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003373 int i, num_workspace_bindings;
Tiago Vignatti0b52d482012-04-20 18:54:25 +03003374
3375 /* fixed bindings */
Daniel Stone325fc2d2012-05-30 16:31:58 +01003376 weston_compositor_add_key_binding(ec, KEY_BACKSPACE,
3377 MODIFIER_CTRL | MODIFIER_ALT,
3378 terminate_binding, ec);
3379 weston_compositor_add_button_binding(ec, BTN_LEFT, 0,
3380 click_to_activate_binding,
3381 shell);
3382 weston_compositor_add_axis_binding(ec, WL_POINTER_AXIS_VERTICAL_SCROLL,
3383 MODIFIER_SUPER | MODIFIER_ALT,
3384 surface_opacity_binding, NULL);
3385 weston_compositor_add_axis_binding(ec, WL_POINTER_AXIS_VERTICAL_SCROLL,
3386 MODIFIER_SUPER, zoom_axis_binding,
3387 NULL);
Tiago Vignatti0b52d482012-04-20 18:54:25 +03003388
3389 /* configurable bindings */
3390 mod = shell->binding_modifier;
Daniel Stone325fc2d2012-05-30 16:31:58 +01003391 weston_compositor_add_key_binding(ec, KEY_PAGEUP, mod,
3392 zoom_key_binding, NULL);
3393 weston_compositor_add_key_binding(ec, KEY_PAGEDOWN, mod,
3394 zoom_key_binding, NULL);
3395 weston_compositor_add_button_binding(ec, BTN_LEFT, mod, move_binding,
3396 shell);
3397 weston_compositor_add_button_binding(ec, BTN_MIDDLE, mod,
3398 resize_binding, shell);
3399 weston_compositor_add_button_binding(ec, BTN_RIGHT, mod,
3400 rotate_binding, NULL);
3401 weston_compositor_add_key_binding(ec, KEY_TAB, mod, switcher_binding,
3402 shell);
3403 weston_compositor_add_key_binding(ec, KEY_F9, mod, backlight_binding,
3404 ec);
3405 weston_compositor_add_key_binding(ec, KEY_BRIGHTNESSDOWN, 0,
3406 backlight_binding, ec);
3407 weston_compositor_add_key_binding(ec, KEY_F10, mod, backlight_binding,
3408 ec);
3409 weston_compositor_add_key_binding(ec, KEY_BRIGHTNESSUP, 0,
3410 backlight_binding, ec);
Kristian Høgsberg73694c82012-06-28 14:13:10 -04003411 weston_compositor_add_key_binding(ec, KEY_SPACE, mod | MODIFIER_SHIFT,
Daniel Stone325fc2d2012-05-30 16:31:58 +01003412 debug_repaint_binding, shell);
3413 weston_compositor_add_key_binding(ec, KEY_K, mod,
3414 force_kill_binding, shell);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003415 weston_compositor_add_key_binding(ec, KEY_UP, mod,
3416 workspace_up_binding, shell);
3417 weston_compositor_add_key_binding(ec, KEY_DOWN, mod,
3418 workspace_down_binding, shell);
3419
3420 /* Add bindings for mod+F[1-6] for workspace 1 to 6. */
3421 if (shell->workspaces.num > 1) {
3422 num_workspace_bindings = shell->workspaces.num;
3423 if (num_workspace_bindings > 6)
3424 num_workspace_bindings = 6;
3425 for (i = 0; i < num_workspace_bindings; i++)
3426 weston_compositor_add_key_binding(ec, KEY_F1 + i, mod,
3427 workspace_f_binding,
3428 shell);
3429 }
Tiago Vignatti0b52d482012-04-20 18:54:25 +03003430}
3431
Kristian Høgsberg6c709a32011-05-06 14:52:41 -04003432int
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05003433shell_init(struct weston_compositor *ec);
Kristian Høgsberg6c709a32011-05-06 14:52:41 -04003434
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003435WL_EXPORT int
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05003436shell_init(struct weston_compositor *ec)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05003437{
Kristian Høgsbergf4d2f232012-08-10 10:05:39 -04003438 struct weston_seat *seat;
Tiago Vignattibe143262012-04-16 17:31:41 +03003439 struct desktop_shell *shell;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003440 struct workspace **pws;
3441 unsigned int i;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04003442
3443 shell = malloc(sizeof *shell);
3444 if (shell == NULL)
3445 return -1;
3446
Kristian Høgsbergf0d91162011-10-11 22:44:23 -04003447 memset(shell, 0, sizeof *shell);
Kristian Høgsberg75840622011-09-06 13:48:16 -04003448 shell->compositor = ec;
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04003449
3450 shell->destroy_listener.notify = shell_destroy;
3451 wl_signal_add(&ec->destroy_signal, &shell->destroy_listener);
3452 shell->lock_listener.notify = lock;
3453 wl_signal_add(&ec->lock_signal, &shell->lock_listener);
3454 shell->unlock_listener.notify = unlock;
3455 wl_signal_add(&ec->unlock_signal, &shell->unlock_listener);
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003456 shell->show_input_panel_listener.notify = show_input_panels;
3457 wl_signal_add(&ec->show_input_panel_signal, &shell->show_input_panel_listener);
3458 shell->hide_input_panel_listener.notify = hide_input_panels;
3459 wl_signal_add(&ec->hide_input_panel_signal, &shell->hide_input_panel_listener);
Scott Moreauff1db4a2012-04-17 19:06:18 -06003460 ec->ping_handler = ping_handler;
Kristian Høgsberg82a1d112012-07-19 14:02:00 -04003461 ec->shell_interface.shell = shell;
Tiago Vignattibc052c92012-04-19 16:18:18 +03003462 ec->shell_interface.create_shell_surface = create_shell_surface;
3463 ec->shell_interface.set_toplevel = set_toplevel;
Tiago Vignatti491bac12012-05-18 16:37:43 -04003464 ec->shell_interface.set_transient = set_transient;
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04003465 ec->shell_interface.move = surface_move;
Kristian Høgsbergc1693f22012-05-22 16:56:23 -04003466 ec->shell_interface.resize = surface_resize;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05003467
Pekka Paalanen77346a62011-11-30 16:26:35 +02003468 wl_list_init(&shell->screensaver.surfaces);
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003469 wl_list_init(&shell->input_panel.surfaces);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02003470
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05003471 weston_layer_init(&shell->fullscreen_layer, &ec->cursor_layer.link);
3472 weston_layer_init(&shell->panel_layer, &shell->fullscreen_layer.link);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003473 weston_layer_init(&shell->background_layer, &shell->panel_layer.link);
3474 weston_layer_init(&shell->lock_layer, NULL);
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02003475 weston_layer_init(&shell->input_panel_layer, NULL);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003476
3477 wl_array_init(&shell->workspaces.array);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05003478
Kristian Høgsberg6af8eb92012-01-25 16:57:11 -05003479 shell_configuration(shell);
Pekka Paalanene955f1e2011-12-07 11:49:52 +02003480
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003481 for (i = 0; i < shell->workspaces.num; i++) {
3482 pws = wl_array_add(&shell->workspaces.array, sizeof *pws);
3483 if (pws == NULL)
3484 return -1;
3485
3486 *pws = workspace_create();
3487 if (*pws == NULL)
3488 return -1;
3489 }
3490 activate_workspace(shell, 0);
3491
Jonas Ådahl62fcd042012-06-13 00:01:23 +02003492 wl_list_init(&shell->workspaces.animation.link);
3493 shell->workspaces.animation.frame = animate_workspace_change_frame;
3494
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04003495 if (wl_display_add_global(ec->wl_display, &wl_shell_interface,
3496 shell, bind_shell) == NULL)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05003497 return -1;
3498
Kristian Høgsberg75840622011-09-06 13:48:16 -04003499 if (wl_display_add_global(ec->wl_display,
3500 &desktop_shell_interface,
3501 shell, bind_desktop_shell) == NULL)
3502 return -1;
3503
Pekka Paalanen6e168112011-11-24 11:34:05 +02003504 if (wl_display_add_global(ec->wl_display, &screensaver_interface,
3505 shell, bind_screensaver) == NULL)
3506 return -1;
3507
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003508 if (wl_display_add_global(ec->wl_display, &input_panel_interface,
3509 shell, bind_input_panel) == NULL)
3510 return -1;
3511
Kristian Høgsbergf03a6162012-01-17 11:07:42 -05003512 shell->child.deathstamp = weston_compositor_get_time();
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02003513 if (launch_desktop_shell_process(shell) != 0)
3514 return -1;
3515
Kristian Høgsbergf4d2f232012-08-10 10:05:39 -04003516 wl_list_for_each(seat, &ec->seat_list, link)
3517 create_pointer_focus_listener(seat);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04003518
Tiago Vignatti0b52d482012-04-20 18:54:25 +03003519 shell_add_bindings(ec, shell);
Kristian Høgsberg07937562011-04-12 17:25:42 -04003520
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05003521 return 0;
3522}