blob: 121301499338b1517fb4b378507601857046593f [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;
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200112 struct wl_list anim_sticky_list;
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200113 int anim_dir;
114 uint32_t anim_timestamp;
115 double anim_current;
116 struct workspace *anim_from;
117 struct workspace *anim_to;
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200118 } workspaces;
119
120 struct {
Pekka Paalanen3c647232011-12-22 13:43:43 +0200121 char *path;
Pekka Paalanen7296e792011-12-07 16:22:00 +0200122 int duration;
Pekka Paalanen77346a62011-11-30 16:26:35 +0200123 struct wl_resource *binding;
124 struct wl_list surfaces;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500125 struct weston_process process;
Pekka Paalanen77346a62011-11-30 16:26:35 +0200126 } screensaver;
Kristian Høgsbergb41c0812012-03-04 14:53:40 -0500127
Jan Arne Petersen42feced2012-06-21 21:52:17 +0200128 struct {
129 struct wl_resource *binding;
130 struct wl_list surfaces;
131 } input_panel;
132
Tiago Vignatti0b52d482012-04-20 18:54:25 +0300133 uint32_t binding_modifier;
Juan Zhaoe10d2792012-04-25 19:09:52 +0800134 enum animation_type win_animation_type;
Kristian Høgsbergb41c0812012-03-04 14:53:40 -0500135 struct weston_surface *debug_repaint_surface;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400136};
137
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500138enum shell_surface_type {
Pekka Paalanen98262232011-12-01 10:42:22 +0200139 SHELL_SURFACE_NONE,
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500140 SHELL_SURFACE_TOPLEVEL,
141 SHELL_SURFACE_TRANSIENT,
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500142 SHELL_SURFACE_FULLSCREEN,
Juan Zhao96879df2012-02-07 08:45:41 +0800143 SHELL_SURFACE_MAXIMIZED,
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500144 SHELL_SURFACE_POPUP
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200145};
146
Scott Moreauff1db4a2012-04-17 19:06:18 -0600147struct ping_timer {
148 struct wl_event_source *source;
Scott Moreauff1db4a2012-04-17 19:06:18 -0600149 uint32_t serial;
150};
151
Pekka Paalanen56cdea92011-11-23 16:14:12 +0200152struct shell_surface {
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200153 struct wl_resource resource;
154
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500155 struct weston_surface *surface;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200156 struct wl_listener surface_destroy_listener;
Kristian Høgsberg8150b192012-06-27 10:22:58 -0400157 struct weston_surface *parent;
Tiago Vignattibe143262012-04-16 17:31:41 +0300158 struct desktop_shell *shell;
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200159
Kristian Høgsberg7f366e72012-04-27 17:20:01 -0400160 enum shell_surface_type type, next_type;
Kristian Høgsberge7afd912012-05-02 09:47:44 -0400161 char *title, *class;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500162 int32_t saved_x, saved_y;
Alex Wu4539b082012-03-01 12:57:46 +0800163 bool saved_position_valid;
Alex Wu7bcb8bd2012-04-27 09:07:24 +0800164 bool saved_rotation_valid;
Scott Moreauff1db4a2012-04-17 19:06:18 -0600165 int unresponsive;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100166
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500167 struct {
Pekka Paalanen460099f2012-01-20 16:48:25 +0200168 struct weston_transform transform;
Kristian Høgsberg765e27b2012-01-27 13:36:13 -0500169 struct weston_matrix rotation;
Pekka Paalanen460099f2012-01-20 16:48:25 +0200170 } rotation;
171
172 struct {
Scott Moreau447013d2012-02-18 05:05:29 -0700173 struct wl_pointer_grab grab;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500174 int32_t x, y;
Pekka Paalanen938269a2012-02-07 14:19:01 +0200175 struct weston_transform parent_transform;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500176 int32_t initial_up;
Daniel Stone37816df2012-05-16 18:45:18 +0100177 struct wl_seat *seat;
Kristian Høgsberg3730f362012-04-13 12:40:07 -0400178 uint32_t serial;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -0500179 } popup;
180
Alex Wu4539b082012-03-01 12:57:46 +0800181 struct {
Tiago Vignatti52e598c2012-05-07 15:23:08 +0300182 int32_t x, y;
Tiago Vignatti491bac12012-05-18 16:37:43 -0400183 uint32_t flags;
Tiago Vignatti52e598c2012-05-07 15:23:08 +0300184 } transient;
185
186 struct {
Alex Wu4539b082012-03-01 12:57:46 +0800187 enum wl_shell_surface_fullscreen_method type;
188 struct weston_transform transform; /* matrix from x, y */
189 uint32_t framerate;
190 struct weston_surface *black_surface;
191 } fullscreen;
192
Scott Moreauff1db4a2012-04-17 19:06:18 -0600193 struct ping_timer *ping_timer;
194
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200195 struct weston_transform workspace_transform;
196
Kristian Høgsberg1cbf3262012-02-17 23:49:07 -0500197 struct weston_output *fullscreen_output;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500198 struct weston_output *output;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100199 struct wl_list link;
Kristian Høgsberga61ca062012-05-22 16:05:52 -0400200
201 const struct weston_shell_client *client;
Pekka Paalanen56cdea92011-11-23 16:14:12 +0200202};
203
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300204struct shell_grab {
Scott Moreau447013d2012-02-18 05:05:29 -0700205 struct wl_pointer_grab grab;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300206 struct shell_surface *shsurf;
207 struct wl_listener shsurf_destroy_listener;
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300208 struct wl_pointer *pointer;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300209};
210
211struct weston_move_grab {
212 struct shell_grab base;
Daniel Stone103db7f2012-05-08 17:17:55 +0100213 wl_fixed_t dx, dy;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500214};
215
Pekka Paalanen460099f2012-01-20 16:48:25 +0200216struct rotate_grab {
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300217 struct shell_grab base;
Kristian Høgsberg765e27b2012-01-27 13:36:13 -0500218 struct weston_matrix rotation;
Pekka Paalanen460099f2012-01-20 16:48:25 +0200219 struct {
Kristian Høgsbergb2af93e2012-06-07 20:10:23 -0400220 GLfloat x;
221 GLfloat y;
Pekka Paalanen460099f2012-01-20 16:48:25 +0200222 } center;
223};
224
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400225static void
226activate(struct desktop_shell *shell, struct weston_surface *es,
227 struct weston_seat *seat);
228
229static struct workspace *
230get_current_workspace(struct desktop_shell *shell);
231
Alex Wubd3354b2012-04-17 17:20:49 +0800232static struct shell_surface *
233get_shell_surface(struct weston_surface *surface);
234
235static struct desktop_shell *
236shell_surface_get_shell(struct shell_surface *shsurf);
237
238static bool
239shell_surface_is_top_fullscreen(struct shell_surface *shsurf)
240{
241 struct desktop_shell *shell;
242 struct weston_surface *top_fs_es;
243
244 shell = shell_surface_get_shell(shsurf);
245
246 if (wl_list_empty(&shell->fullscreen_layer.surface_list))
247 return false;
248
249 top_fs_es = container_of(shell->fullscreen_layer.surface_list.next,
250 struct weston_surface,
251 layer_link);
252 return (shsurf == get_shell_surface(top_fs_es));
253}
254
Kristian Høgsberg6af8eb92012-01-25 16:57:11 -0500255static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400256destroy_shell_grab_shsurf(struct wl_listener *listener, void *data)
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300257{
258 struct shell_grab *grab;
259
260 grab = container_of(listener, struct shell_grab,
261 shsurf_destroy_listener);
262
263 grab->shsurf = NULL;
264}
265
266static void
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300267shell_grab_start(struct shell_grab *grab,
268 const struct wl_pointer_grab_interface *interface,
269 struct shell_surface *shsurf,
270 struct wl_pointer *pointer,
271 enum desktop_shell_cursor cursor)
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300272{
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300273 struct desktop_shell *shell = shsurf->shell;
274
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300275 grab->grab.interface = interface;
276 grab->shsurf = shsurf;
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400277 grab->shsurf_destroy_listener.notify = destroy_shell_grab_shsurf;
278 wl_signal_add(&shsurf->resource.destroy_signal,
279 &grab->shsurf_destroy_listener);
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300280
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300281 grab->pointer = pointer;
282 grab->grab.focus = &shsurf->surface->surface;
283
284 wl_pointer_start_grab(pointer, &grab->grab);
285 desktop_shell_send_grab_cursor(shell->child.desktop_shell, cursor);
286 wl_pointer_set_focus(pointer, &shell->grab_surface->surface,
287 wl_fixed_from_int(0), wl_fixed_from_int(0));
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300288}
289
290static void
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300291shell_grab_end(struct shell_grab *grab)
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300292{
Kristian Høgsberg47b5dca2012-06-07 18:08:04 -0400293 if (grab->shsurf)
294 wl_list_remove(&grab->shsurf_destroy_listener.link);
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300295
296 wl_pointer_end_grab(grab->pointer);
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300297}
298
299static void
Alex Wu4539b082012-03-01 12:57:46 +0800300center_on_output(struct weston_surface *surface,
301 struct weston_output *output);
302
Daniel Stone496ca172012-05-30 16:31:42 +0100303static enum weston_keyboard_modifier
Tiago Vignatti0b52d482012-04-20 18:54:25 +0300304get_modifier(char *modifier)
305{
306 if (!modifier)
307 return MODIFIER_SUPER;
308
309 if (!strcmp("ctrl", modifier))
310 return MODIFIER_CTRL;
311 else if (!strcmp("alt", modifier))
312 return MODIFIER_ALT;
313 else if (!strcmp("super", modifier))
314 return MODIFIER_SUPER;
315 else
316 return MODIFIER_SUPER;
317}
318
Juan Zhaoe10d2792012-04-25 19:09:52 +0800319static enum animation_type
320get_animation_type(char *animation)
321{
322 if (!animation)
323 return ANIMATION_NONE;
324
325 if (!strcmp("zoom", animation))
326 return ANIMATION_ZOOM;
327 else if (!strcmp("fade", animation))
328 return ANIMATION_FADE;
329 else
330 return ANIMATION_NONE;
331}
332
Alex Wu4539b082012-03-01 12:57:46 +0800333static void
Tiago Vignattibe143262012-04-16 17:31:41 +0300334shell_configuration(struct desktop_shell *shell)
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200335{
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200336 char *config_file;
Pekka Paalanen7296e792011-12-07 16:22:00 +0200337 char *path = NULL;
338 int duration = 60;
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200339 unsigned int num_workspaces = DEFAULT_NUM_WORKSPACES;
Tiago Vignatti0b52d482012-04-20 18:54:25 +0300340 char *modifier = NULL;
Juan Zhaoe10d2792012-04-25 19:09:52 +0800341 char *win_animation = NULL;
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200342
Kristian Høgsberga4e8b332012-04-20 16:48:21 -0400343 struct config_key shell_keys[] = {
Tiago Vignatti0b52d482012-04-20 18:54:25 +0300344 { "binding-modifier", CONFIG_KEY_STRING, &modifier },
Juan Zhaoe10d2792012-04-25 19:09:52 +0800345 { "animation", CONFIG_KEY_STRING, &win_animation},
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200346 { "num-workspaces",
347 CONFIG_KEY_UNSIGNED_INTEGER, &num_workspaces },
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200348 };
349
Kristian Høgsberga4e8b332012-04-20 16:48:21 -0400350 struct config_key saver_keys[] = {
351 { "path", CONFIG_KEY_STRING, &path },
352 { "duration", CONFIG_KEY_INTEGER, &duration },
353 };
354
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200355 struct config_section cs[] = {
Kristian Høgsberga4e8b332012-04-20 16:48:21 -0400356 { "shell", shell_keys, ARRAY_LENGTH(shell_keys), NULL },
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200357 { "screensaver", saver_keys, ARRAY_LENGTH(saver_keys), NULL },
358 };
359
Tiago Vignatti9a206c42012-03-21 19:49:18 +0200360 config_file = config_file_path("weston.ini");
Kristian Høgsberg6af8eb92012-01-25 16:57:11 -0500361 parse_config_file(config_file, cs, ARRAY_LENGTH(cs), shell);
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200362 free(config_file);
363
Pekka Paalanen7296e792011-12-07 16:22:00 +0200364 shell->screensaver.path = path;
365 shell->screensaver.duration = duration;
Tiago Vignatti0b52d482012-04-20 18:54:25 +0300366 shell->binding_modifier = get_modifier(modifier);
Juan Zhaoe10d2792012-04-25 19:09:52 +0800367 shell->win_animation_type = get_animation_type(win_animation);
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200368 shell->workspaces.num = num_workspaces > 0 ? num_workspaces : 1;
369}
370
371static void
Jonas Ådahl04769742012-06-13 00:01:24 +0200372focus_state_destroy(struct focus_state *state)
373{
374 wl_list_remove(&state->seat_destroy_listener.link);
375 wl_list_remove(&state->surface_destroy_listener.link);
376 free(state);
377}
378
379static void
380focus_state_seat_destroy(struct wl_listener *listener, void *data)
381{
382 struct focus_state *state = container_of(listener,
383 struct focus_state,
384 seat_destroy_listener);
385
386 wl_list_remove(&state->link);
387 focus_state_destroy(state);
388}
389
390static void
391focus_state_surface_destroy(struct wl_listener *listener, void *data)
392{
393 struct focus_state *state = container_of(listener,
394 struct focus_state,
Kristian Høgsbergb8e0d0f2012-07-31 10:30:26 -0400395 surface_destroy_listener);
Kristian Høgsberge3778222012-07-31 17:29:30 -0400396 struct desktop_shell *shell;
397 struct weston_surface *surface, *next;
Jonas Ådahl04769742012-06-13 00:01:24 +0200398
Kristian Høgsberge3778222012-07-31 17:29:30 -0400399 next = NULL;
400 wl_list_for_each(surface, &state->ws->layer.surface_list, layer_link) {
401 if (surface == state->keyboard_focus)
402 continue;
403
404 next = surface;
405 break;
406 }
407
408 if (next) {
409 shell = state->seat->compositor->shell_interface.shell;
410 activate(shell, next, state->seat);
411 } else {
412 wl_list_remove(&state->link);
413 focus_state_destroy(state);
414 }
Jonas Ådahl04769742012-06-13 00:01:24 +0200415}
416
417static struct focus_state *
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400418focus_state_create(struct weston_seat *seat, struct workspace *ws)
Jonas Ådahl04769742012-06-13 00:01:24 +0200419{
Jonas Ådahl04769742012-06-13 00:01:24 +0200420 struct focus_state *state;
Jonas Ådahl04769742012-06-13 00:01:24 +0200421
422 state = malloc(sizeof *state);
423 if (state == NULL)
424 return NULL;
425
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400426 state->ws = ws;
Jonas Ådahl04769742012-06-13 00:01:24 +0200427 state->seat = seat;
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400428 wl_list_insert(&ws->focus_list, &state->link);
Jonas Ådahl04769742012-06-13 00:01:24 +0200429
430 state->seat_destroy_listener.notify = focus_state_seat_destroy;
431 state->surface_destroy_listener.notify = focus_state_surface_destroy;
432 wl_signal_add(&seat->seat.destroy_signal,
433 &state->seat_destroy_listener);
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400434 wl_list_init(&state->surface_destroy_listener.link);
Jonas Ådahl04769742012-06-13 00:01:24 +0200435
436 return state;
437}
438
439static void
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400440restore_focus_state(struct desktop_shell *shell, struct workspace *ws)
Jonas Ådahl04769742012-06-13 00:01:24 +0200441{
442 struct focus_state *state, *next;
Jonas Ådahl56899442012-08-29 22:12:59 +0200443 struct wl_surface *surface;
Jonas Ådahl04769742012-06-13 00:01:24 +0200444
445 wl_list_for_each_safe(state, next, &ws->focus_list, link) {
Jonas Ådahl56899442012-08-29 22:12:59 +0200446 surface = state->keyboard_focus ?
447 &state->keyboard_focus->surface : NULL;
448
449 wl_keyboard_set_focus(state->seat->seat.keyboard, surface);
Jonas Ådahl04769742012-06-13 00:01:24 +0200450 }
451}
452
453static void
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200454replace_focus_state(struct desktop_shell *shell, struct workspace *ws,
455 struct weston_seat *seat)
456{
457 struct focus_state *state;
458 struct wl_surface *surface;
459
460 wl_list_for_each(state, &ws->focus_list, link) {
461 if (state->seat == seat) {
462 surface = seat->seat.keyboard->focus;
463 state->keyboard_focus =
464 (struct weston_surface *) surface;
465 return;
466 }
467 }
468}
469
470static void
471drop_focus_state(struct desktop_shell *shell, struct workspace *ws,
472 struct weston_surface *surface)
473{
474 struct focus_state *state;
475
476 wl_list_for_each(state, &ws->focus_list, link)
477 if (state->keyboard_focus == surface)
478 state->keyboard_focus = NULL;
479}
480
481static void
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200482workspace_destroy(struct workspace *ws)
483{
Jonas Ådahl04769742012-06-13 00:01:24 +0200484 struct focus_state *state, *next;
485
486 wl_list_for_each_safe(state, next, &ws->focus_list, link)
487 focus_state_destroy(state);
488
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200489 free(ws);
490}
491
Jonas Ådahl04769742012-06-13 00:01:24 +0200492static void
493seat_destroyed(struct wl_listener *listener, void *data)
494{
495 struct weston_seat *seat = data;
496 struct focus_state *state, *next;
497 struct workspace *ws = container_of(listener,
498 struct workspace,
499 seat_destroyed_listener);
500
501 wl_list_for_each_safe(state, next, &ws->focus_list, link)
502 if (state->seat == seat)
503 wl_list_remove(&state->link);
504}
505
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200506static struct workspace *
507workspace_create(void)
508{
509 struct workspace *ws = malloc(sizeof *ws);
510 if (ws == NULL)
511 return NULL;
512
513 weston_layer_init(&ws->layer, NULL);
514
Jonas Ådahl04769742012-06-13 00:01:24 +0200515 wl_list_init(&ws->focus_list);
516 wl_list_init(&ws->seat_destroyed_listener.link);
517 ws->seat_destroyed_listener.notify = seat_destroyed;
518
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200519 return ws;
520}
521
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200522static int
523workspace_is_empty(struct workspace *ws)
524{
525 return wl_list_empty(&ws->layer.surface_list);
526}
527
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200528static struct workspace *
529get_workspace(struct desktop_shell *shell, unsigned int index)
530{
531 struct workspace **pws = shell->workspaces.array.data;
532 pws += index;
533 return *pws;
534}
535
536static struct workspace *
537get_current_workspace(struct desktop_shell *shell)
538{
539 return get_workspace(shell, shell->workspaces.current);
540}
541
542static void
543activate_workspace(struct desktop_shell *shell, unsigned int index)
544{
545 struct workspace *ws;
546
547 ws = get_workspace(shell, index);
548 wl_list_insert(&shell->panel_layer.link, &ws->layer.link);
549
550 shell->workspaces.current = index;
551}
552
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200553static unsigned int
554get_output_height(struct weston_output *output)
555{
556 return abs(output->region.extents.y1 - output->region.extents.y2);
557}
558
559static void
560surface_translate(struct weston_surface *surface, double d)
561{
562 struct shell_surface *shsurf = get_shell_surface(surface);
563 struct weston_transform *transform;
564
565 transform = &shsurf->workspace_transform;
566 if (wl_list_empty(&transform->link))
567 wl_list_insert(surface->geometry.transformation_list.prev,
568 &shsurf->workspace_transform.link);
569
570 weston_matrix_init(&shsurf->workspace_transform.matrix);
571 weston_matrix_translate(&shsurf->workspace_transform.matrix,
572 0.0, d, 0.0);
573 surface->geometry.dirty = 1;
574}
575
576static void
577workspace_translate_out(struct workspace *ws, double fraction)
578{
579 struct weston_surface *surface;
580 unsigned int height;
581 double d;
582
583 wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
584 height = get_output_height(surface->output);
585 d = height * fraction;
586
587 surface_translate(surface, d);
588 }
589}
590
591static void
592workspace_translate_in(struct workspace *ws, double fraction)
593{
594 struct weston_surface *surface;
595 unsigned int height;
596 double d;
597
598 wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
599 height = get_output_height(surface->output);
600
601 if (fraction > 0)
602 d = -(height - height * fraction);
603 else
604 d = height + height * fraction;
605
606 surface_translate(surface, d);
607 }
608}
609
610static void
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200611reverse_workspace_change_animation(struct desktop_shell *shell,
612 unsigned int index,
613 struct workspace *from,
614 struct workspace *to)
615{
616 shell->workspaces.current = index;
617
618 shell->workspaces.anim_to = to;
619 shell->workspaces.anim_from = from;
620 shell->workspaces.anim_dir = -1 * shell->workspaces.anim_dir;
621 shell->workspaces.anim_timestamp = 0;
622
Scott Moreau4272e632012-08-13 09:58:41 -0600623 weston_compositor_schedule_repaint(shell->compositor);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200624}
625
626static void
627workspace_deactivate_transforms(struct workspace *ws)
628{
629 struct weston_surface *surface;
630 struct shell_surface *shsurf;
631
632 wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
633 shsurf = get_shell_surface(surface);
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200634 if (!wl_list_empty(&shsurf->workspace_transform.link)) {
635 wl_list_remove(&shsurf->workspace_transform.link);
636 wl_list_init(&shsurf->workspace_transform.link);
637 }
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200638 shsurf->surface->geometry.dirty = 1;
639 }
640}
641
642static void
643finish_workspace_change_animation(struct desktop_shell *shell,
644 struct workspace *from,
645 struct workspace *to)
646{
Scott Moreau4272e632012-08-13 09:58:41 -0600647 weston_compositor_schedule_repaint(shell->compositor);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200648
649 wl_list_remove(&shell->workspaces.animation.link);
650 workspace_deactivate_transforms(from);
651 workspace_deactivate_transforms(to);
652 shell->workspaces.anim_to = NULL;
653
654 wl_list_remove(&shell->workspaces.anim_from->layer.link);
655}
656
657static void
658animate_workspace_change_frame(struct weston_animation *animation,
659 struct weston_output *output, uint32_t msecs)
660{
661 struct desktop_shell *shell =
662 container_of(animation, struct desktop_shell,
663 workspaces.animation);
664 struct workspace *from = shell->workspaces.anim_from;
665 struct workspace *to = shell->workspaces.anim_to;
666 uint32_t t;
667 double x, y;
668
669 if (workspace_is_empty(from) && workspace_is_empty(to)) {
670 finish_workspace_change_animation(shell, from, to);
671 return;
672 }
673
674 if (shell->workspaces.anim_timestamp == 0) {
675 if (shell->workspaces.anim_current == 0.0)
676 shell->workspaces.anim_timestamp = msecs;
677 else
678 shell->workspaces.anim_timestamp =
679 msecs -
680 /* Invers of movement function 'y' below. */
681 (asin(1.0 - shell->workspaces.anim_current) *
682 DEFAULT_WORKSPACE_CHANGE_ANIMATION_LENGTH *
683 M_2_PI);
684 }
685
686 t = msecs - shell->workspaces.anim_timestamp;
687
688 /*
689 * x = [0, π/2]
690 * y(x) = sin(x)
691 */
692 x = t * (1.0/DEFAULT_WORKSPACE_CHANGE_ANIMATION_LENGTH) * M_PI_2;
693 y = sin(x);
694
695 if (t < DEFAULT_WORKSPACE_CHANGE_ANIMATION_LENGTH) {
Scott Moreau4272e632012-08-13 09:58:41 -0600696 weston_compositor_schedule_repaint(shell->compositor);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200697
698 workspace_translate_out(from, shell->workspaces.anim_dir * y);
699 workspace_translate_in(to, shell->workspaces.anim_dir * y);
700 shell->workspaces.anim_current = y;
701
Scott Moreau4272e632012-08-13 09:58:41 -0600702 weston_compositor_schedule_repaint(shell->compositor);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200703 }
Jonas Ådahl04769742012-06-13 00:01:24 +0200704 else
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200705 finish_workspace_change_animation(shell, from, to);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200706}
707
708static void
709animate_workspace_change(struct desktop_shell *shell,
710 unsigned int index,
711 struct workspace *from,
712 struct workspace *to)
713{
714 struct weston_output *output;
715
716 int dir;
717
718 if (index > shell->workspaces.current)
719 dir = -1;
720 else
721 dir = 1;
722
723 shell->workspaces.current = index;
724
725 shell->workspaces.anim_dir = dir;
726 shell->workspaces.anim_from = from;
727 shell->workspaces.anim_to = to;
728 shell->workspaces.anim_current = 0.0;
729 shell->workspaces.anim_timestamp = 0;
730
731 output = container_of(shell->compositor->output_list.next,
732 struct weston_output, link);
733 wl_list_insert(&output->animation_list,
734 &shell->workspaces.animation.link);
735
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200736 wl_list_insert(from->layer.link.prev, &to->layer.link);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200737
738 workspace_translate_in(to, 0);
739
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -0400740 restore_focus_state(shell, to);
Jonas Ådahl04769742012-06-13 00:01:24 +0200741
Scott Moreau4272e632012-08-13 09:58:41 -0600742 weston_compositor_schedule_repaint(shell->compositor);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200743}
744
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200745static void
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200746update_workspace(struct desktop_shell *shell, unsigned int index,
747 struct workspace *from, struct workspace *to)
748{
749 shell->workspaces.current = index;
750 wl_list_insert(&from->layer.link, &to->layer.link);
751 wl_list_remove(&from->layer.link);
752}
753
754static void
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200755change_workspace(struct desktop_shell *shell, unsigned int index)
756{
757 struct workspace *from;
758 struct workspace *to;
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200759
760 if (index == shell->workspaces.current)
761 return;
762
763 /* Don't change workspace when there is any fullscreen surfaces. */
764 if (!wl_list_empty(&shell->fullscreen_layer.surface_list))
765 return;
766
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200767 from = get_current_workspace(shell);
768 to = get_workspace(shell, index);
769
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200770 if (shell->workspaces.anim_from == to &&
771 shell->workspaces.anim_to == from) {
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200772 restore_focus_state(shell, to);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200773 reverse_workspace_change_animation(shell, index, from, to);
774 return;
775 }
Jonas Ådahle3cddce2012-06-13 00:01:22 +0200776
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200777 if (shell->workspaces.anim_to != NULL)
778 finish_workspace_change_animation(shell,
779 shell->workspaces.anim_from,
780 shell->workspaces.anim_to);
781
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200782 restore_focus_state(shell, to);
Jonas Ådahl04769742012-06-13 00:01:24 +0200783
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200784 if (workspace_is_empty(to) && workspace_is_empty(from))
785 update_workspace(shell, index, from, to);
Jonas Ådahl62fcd042012-06-13 00:01:23 +0200786 else
787 animate_workspace_change(shell, index, from, to);
Pekka Paalanene955f1e2011-12-07 11:49:52 +0200788}
789
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +0200790static bool
791workspace_has_only(struct workspace *ws, struct weston_surface *surface)
792{
793 struct wl_list *list = &ws->layer.surface_list;
794 struct wl_list *e;
795
796 if (wl_list_empty(list))
797 return false;
798
799 e = list->next;
800
801 if (e->next != list)
802 return false;
803
804 return container_of(e, struct weston_surface, layer_link) == surface;
805}
806
807static void
808take_surface_to_workspace_by_seat(struct desktop_shell *shell,
809 struct wl_seat *seat,
810 unsigned int index)
811{
812 struct weston_surface *surface =
813 (struct weston_surface *) seat->keyboard->focus;
814 struct shell_surface *shsurf;
815 struct workspace *from;
816 struct workspace *to;
817
818 if (surface == NULL ||
819 index == shell->workspaces.current)
820 return;
821
822 from = get_current_workspace(shell);
823 to = get_workspace(shell, index);
824
825 wl_list_remove(&surface->layer_link);
826 wl_list_insert(&to->layer.surface_list, &surface->layer_link);
827
828 replace_focus_state(shell, to, (struct weston_seat *) seat);
829 drop_focus_state(shell, from, surface);
830
831 if (shell->workspaces.anim_from == to &&
832 shell->workspaces.anim_to == from) {
833 reverse_workspace_change_animation(shell, index, from, to);
834 return;
835 }
836
837 if (shell->workspaces.anim_to != NULL)
838 finish_workspace_change_animation(shell,
839 shell->workspaces.anim_from,
840 shell->workspaces.anim_to);
841
842 if (workspace_is_empty(from) &&
843 workspace_has_only(to, surface))
844 update_workspace(shell, index, from, to);
845 else {
846 shsurf = get_shell_surface(surface);
847 if (wl_list_empty(&shsurf->workspace_transform.link))
848 wl_list_insert(&shell->workspaces.anim_sticky_list,
849 &shsurf->workspace_transform.link);
850
851 animate_workspace_change(shell, index, from, to);
852 }
853}
854
Pekka Paalanen56cdea92011-11-23 16:14:12 +0200855static void
Kristian Høgsbergeae5de72012-04-11 22:42:15 -0400856noop_grab_focus(struct wl_pointer_grab *grab,
Daniel Stone103db7f2012-05-08 17:17:55 +0100857 struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y)
Kristian Høgsberg9ddb8262012-01-04 21:30:29 -0500858{
859 grab->focus = NULL;
860}
861
862static void
Scott Moreau447013d2012-02-18 05:05:29 -0700863move_grab_motion(struct wl_pointer_grab *grab,
Daniel Stone103db7f2012-05-08 17:17:55 +0100864 uint32_t time, wl_fixed_t x, wl_fixed_t y)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500865{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500866 struct weston_move_grab *move = (struct weston_move_grab *) grab;
Daniel Stone37816df2012-05-16 18:45:18 +0100867 struct wl_pointer *pointer = grab->pointer;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300868 struct shell_surface *shsurf = move->base.shsurf;
869 struct weston_surface *es;
Daniel Stone37816df2012-05-16 18:45:18 +0100870 int dx = wl_fixed_to_int(pointer->x + move->dx);
871 int dy = wl_fixed_to_int(pointer->y + move->dy);
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300872
873 if (!shsurf)
874 return;
875
876 es = shsurf->surface;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500877
Daniel Stone103db7f2012-05-08 17:17:55 +0100878 weston_surface_configure(es, dx, dy,
Pekka Paalanen60921e52012-01-25 15:55:43 +0200879 es->geometry.width, es->geometry.height);
Kristian Høgsberg6c6fb992012-06-21 12:06:22 -0400880
881 weston_compositor_schedule_repaint(es->compositor);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500882}
883
884static void
Scott Moreau447013d2012-02-18 05:05:29 -0700885move_grab_button(struct wl_pointer_grab *grab,
Daniel Stone4dbadb12012-05-30 16:31:51 +0100886 uint32_t time, uint32_t button, uint32_t state_w)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500887{
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +0300888 struct shell_grab *shell_grab = container_of(grab, struct shell_grab,
889 grab);
Daniel Stone37816df2012-05-16 18:45:18 +0100890 struct wl_pointer *pointer = grab->pointer;
Daniel Stone4dbadb12012-05-30 16:31:51 +0100891 enum wl_pointer_button_state state = state_w;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500892
Daniel Stone4dbadb12012-05-30 16:31:51 +0100893 if (pointer->button_count == 0 &&
894 state == WL_POINTER_BUTTON_STATE_RELEASED) {
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +0300895 shell_grab_end(shell_grab);
Kristian Høgsberg9ddb8262012-01-04 21:30:29 -0500896 free(grab);
897 }
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500898}
899
Scott Moreau447013d2012-02-18 05:05:29 -0700900static const struct wl_pointer_grab_interface move_grab_interface = {
Kristian Høgsberg9ddb8262012-01-04 21:30:29 -0500901 noop_grab_focus,
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500902 move_grab_motion,
903 move_grab_button,
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500904};
905
Kristian Høgsberg9e31bff2012-08-01 00:08:07 -0400906static int
907surface_move(struct shell_surface *shsurf, struct weston_seat *ws)
908{
909 struct weston_move_grab *move;
910
911 if (!shsurf)
912 return -1;
913
914 if (shsurf->type == SHELL_SURFACE_FULLSCREEN)
915 return 0;
916
917 move = malloc(sizeof *move);
918 if (!move)
919 return -1;
920
921 move->dx = wl_fixed_from_double(shsurf->surface->geometry.x) -
922 ws->seat.pointer->grab_x;
923 move->dy = wl_fixed_from_double(shsurf->surface->geometry.y) -
924 ws->seat.pointer->grab_y;
925
926 shell_grab_start(&move->base, &move_grab_interface, shsurf,
927 ws->seat.pointer, DESKTOP_SHELL_CURSOR_MOVE);
928
929 return 0;
930}
931
932static void
933shell_surface_move(struct wl_client *client, struct wl_resource *resource,
934 struct wl_resource *seat_resource, uint32_t serial)
935{
936 struct weston_seat *ws = seat_resource->data;
937 struct shell_surface *shsurf = resource->data;
938
939 if (ws->seat.pointer->button_count == 0 ||
940 ws->seat.pointer->grab_serial != serial ||
941 ws->seat.pointer->focus != &shsurf->surface->surface)
942 return;
943
944 if (surface_move(shsurf, ws) < 0)
945 wl_resource_post_no_memory(resource);
946}
947
948struct weston_resize_grab {
949 struct shell_grab base;
950 uint32_t edges;
951 int32_t width, height;
952};
953
954static void
955resize_grab_motion(struct wl_pointer_grab *grab,
956 uint32_t time, wl_fixed_t x, wl_fixed_t y)
957{
958 struct weston_resize_grab *resize = (struct weston_resize_grab *) grab;
959 struct wl_pointer *pointer = grab->pointer;
960 struct shell_surface *shsurf = resize->base.shsurf;
961 int32_t width, height;
962 wl_fixed_t from_x, from_y;
963 wl_fixed_t to_x, to_y;
964
965 if (!shsurf)
966 return;
967
968 weston_surface_from_global_fixed(shsurf->surface,
969 pointer->grab_x, pointer->grab_y,
970 &from_x, &from_y);
971 weston_surface_from_global_fixed(shsurf->surface,
972 pointer->x, pointer->y, &to_x, &to_y);
973
974 width = resize->width;
975 if (resize->edges & WL_SHELL_SURFACE_RESIZE_LEFT) {
976 width += wl_fixed_to_int(from_x - to_x);
977 } else if (resize->edges & WL_SHELL_SURFACE_RESIZE_RIGHT) {
978 width += wl_fixed_to_int(to_x - from_x);
979 }
980
981 height = resize->height;
982 if (resize->edges & WL_SHELL_SURFACE_RESIZE_TOP) {
983 height += wl_fixed_to_int(from_y - to_y);
984 } else if (resize->edges & WL_SHELL_SURFACE_RESIZE_BOTTOM) {
985 height += wl_fixed_to_int(to_y - from_y);
986 }
987
988 shsurf->client->send_configure(shsurf->surface,
989 resize->edges, width, height);
990}
991
992static void
993send_configure(struct weston_surface *surface,
994 uint32_t edges, int32_t width, int32_t height)
995{
996 struct shell_surface *shsurf = get_shell_surface(surface);
997
998 wl_shell_surface_send_configure(&shsurf->resource,
999 edges, width, height);
1000}
1001
1002static const struct weston_shell_client shell_client = {
1003 send_configure
1004};
1005
1006static void
1007resize_grab_button(struct wl_pointer_grab *grab,
1008 uint32_t time, uint32_t button, uint32_t state_w)
1009{
1010 struct weston_resize_grab *resize = (struct weston_resize_grab *) grab;
1011 struct wl_pointer *pointer = grab->pointer;
1012 enum wl_pointer_button_state state = state_w;
1013
1014 if (pointer->button_count == 0 &&
1015 state == WL_POINTER_BUTTON_STATE_RELEASED) {
1016 shell_grab_end(&resize->base);
1017 free(grab);
1018 }
1019}
1020
1021static const struct wl_pointer_grab_interface resize_grab_interface = {
1022 noop_grab_focus,
1023 resize_grab_motion,
1024 resize_grab_button,
1025};
1026
1027static int
1028surface_resize(struct shell_surface *shsurf,
1029 struct weston_seat *ws, uint32_t edges)
1030{
1031 struct weston_resize_grab *resize;
1032
1033 if (shsurf->type == SHELL_SURFACE_FULLSCREEN)
1034 return 0;
1035
1036 if (edges == 0 || edges > 15 ||
1037 (edges & 3) == 3 || (edges & 12) == 12)
1038 return 0;
1039
1040 resize = malloc(sizeof *resize);
1041 if (!resize)
1042 return -1;
1043
1044 resize->edges = edges;
1045 resize->width = shsurf->surface->geometry.width;
1046 resize->height = shsurf->surface->geometry.height;
1047
1048 shell_grab_start(&resize->base, &resize_grab_interface, shsurf,
1049 ws->seat.pointer, edges);
1050
1051 return 0;
1052}
1053
1054static void
1055shell_surface_resize(struct wl_client *client, struct wl_resource *resource,
1056 struct wl_resource *seat_resource, uint32_t serial,
1057 uint32_t edges)
1058{
1059 struct weston_seat *ws = seat_resource->data;
1060 struct shell_surface *shsurf = resource->data;
1061
1062 if (shsurf->type == SHELL_SURFACE_FULLSCREEN)
1063 return;
1064
1065 if (ws->seat.pointer->button_count == 0 ||
1066 ws->seat.pointer->grab_serial != serial ||
1067 ws->seat.pointer->focus != &shsurf->surface->surface)
1068 return;
1069
1070 if (surface_resize(shsurf, ws, edges) < 0)
1071 wl_resource_post_no_memory(resource);
1072}
1073
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001074static void
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001075busy_cursor_grab_focus(struct wl_pointer_grab *base,
1076 struct wl_surface *surface, int32_t x, int32_t y)
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001077{
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001078 struct shell_grab *grab = (struct shell_grab *) base;
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001079
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001080 if (grab->grab.focus != surface) {
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001081 shell_grab_end(grab);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001082 free(grab);
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001083 }
1084}
1085
1086static void
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001087busy_cursor_grab_motion(struct wl_pointer_grab *grab,
1088 uint32_t time, int32_t x, int32_t y)
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001089{
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001090}
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001091
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001092static void
Kristian Høgsbergbbe98392012-08-01 00:20:21 -04001093busy_cursor_grab_button(struct wl_pointer_grab *base,
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001094 uint32_t time, uint32_t button, uint32_t state)
1095{
Kristian Høgsbergbbe98392012-08-01 00:20:21 -04001096 struct shell_grab *grab = (struct shell_grab *) base;
1097 struct shell_surface *shsurf;
1098 struct weston_surface *surface =
1099 (struct weston_surface *) grab->grab.pointer->current;
1100 struct weston_seat *seat =
1101 (struct weston_seat *) grab->grab.pointer->seat;
1102
1103 shsurf = get_shell_surface(surface);
1104 if (shsurf && button == BTN_LEFT && state) {
1105 activate(shsurf->shell, shsurf->surface, seat);
1106 surface_move(shsurf, seat);
1107 }
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001108}
1109
1110static const struct wl_pointer_grab_interface busy_cursor_grab_interface = {
1111 busy_cursor_grab_focus,
1112 busy_cursor_grab_motion,
1113 busy_cursor_grab_button,
1114};
1115
1116static void
1117set_busy_cursor(struct shell_surface *shsurf, struct wl_pointer *pointer)
1118{
1119 struct shell_grab *grab;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001120
1121 grab = malloc(sizeof *grab);
1122 if (!grab)
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001123 return;
1124
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001125 shell_grab_start(grab, &busy_cursor_grab_interface, shsurf, pointer,
1126 DESKTOP_SHELL_CURSOR_BUSY);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001127}
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001128
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001129static void
1130end_busy_cursor(struct shell_surface *shsurf, struct wl_pointer *pointer)
1131{
1132 struct shell_grab *grab = (struct shell_grab *) pointer->grab;
1133
1134 if (grab->grab.interface == &busy_cursor_grab_interface) {
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001135 shell_grab_end(grab);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001136 free(grab);
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001137 }
Scott Moreauc3e54eb2012-04-17 19:06:20 -06001138}
1139
Scott Moreau9521d5e2012-04-19 13:06:17 -06001140static void
1141ping_timer_destroy(struct shell_surface *shsurf)
1142{
1143 if (!shsurf || !shsurf->ping_timer)
1144 return;
1145
1146 if (shsurf->ping_timer->source)
1147 wl_event_source_remove(shsurf->ping_timer->source);
1148
1149 free(shsurf->ping_timer);
1150 shsurf->ping_timer = NULL;
1151}
1152
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04001153static int
Scott Moreauff1db4a2012-04-17 19:06:18 -06001154ping_timeout_handler(void *data)
1155{
1156 struct shell_surface *shsurf = data;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001157 struct weston_seat *seat;
Scott Moreauff1db4a2012-04-17 19:06:18 -06001158
Scott Moreau9521d5e2012-04-19 13:06:17 -06001159 /* Client is not responding */
1160 shsurf->unresponsive = 1;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001161
1162 wl_list_for_each(seat, &shsurf->surface->compositor->seat_list, link)
1163 if (seat->seat.pointer->focus == &shsurf->surface->surface)
1164 set_busy_cursor(shsurf, seat->seat.pointer);
Scott Moreauff1db4a2012-04-17 19:06:18 -06001165
1166 return 1;
1167}
1168
1169static void
1170ping_handler(struct weston_surface *surface, uint32_t serial)
1171{
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001172 struct shell_surface *shsurf = get_shell_surface(surface);
Scott Moreauff1db4a2012-04-17 19:06:18 -06001173 struct wl_event_loop *loop;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001174 int ping_timeout = 200;
Scott Moreauff1db4a2012-04-17 19:06:18 -06001175
1176 if (!shsurf)
1177 return;
Kristian Høgsbergca535c12012-04-21 23:20:07 -04001178 if (!shsurf->resource.client)
1179 return;
Scott Moreauff1db4a2012-04-17 19:06:18 -06001180
Ander Conselvan de Oliveiraeac9a462012-07-16 14:15:48 +03001181 if (shsurf->surface == shsurf->shell->grab_surface)
1182 return;
1183
Scott Moreauff1db4a2012-04-17 19:06:18 -06001184 if (!shsurf->ping_timer) {
Ander Conselvan de Oliveirafb980892012-04-27 13:55:55 +03001185 shsurf->ping_timer = malloc(sizeof *shsurf->ping_timer);
Scott Moreauff1db4a2012-04-17 19:06:18 -06001186 if (!shsurf->ping_timer)
1187 return;
1188
1189 shsurf->ping_timer->serial = serial;
Scott Moreauff1db4a2012-04-17 19:06:18 -06001190 loop = wl_display_get_event_loop(surface->compositor->wl_display);
1191 shsurf->ping_timer->source =
1192 wl_event_loop_add_timer(loop, ping_timeout_handler, shsurf);
1193 wl_event_source_timer_update(shsurf->ping_timer->source, ping_timeout);
1194
1195 wl_shell_surface_send_ping(&shsurf->resource, serial);
1196 }
1197}
1198
1199static void
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001200handle_pointer_focus(struct wl_listener *listener, void *data)
1201{
1202 struct wl_pointer *pointer = data;
1203 struct weston_surface *surface =
1204 (struct weston_surface *) pointer->focus;
1205 struct weston_compositor *compositor;
1206 struct shell_surface *shsurf;
1207 uint32_t serial;
1208
1209 if (!surface)
1210 return;
1211
1212 compositor = surface->compositor;
1213 shsurf = get_shell_surface(surface);
1214
Pekka Paalanen4e1f2ff2012-06-06 16:59:45 +03001215 if (shsurf && shsurf->unresponsive) {
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001216 set_busy_cursor(shsurf, pointer);
1217 } else {
1218 serial = wl_display_next_serial(compositor->wl_display);
1219 ping_handler(surface, serial);
1220 }
1221}
1222
1223static void
Kristian Høgsbergf4d2f232012-08-10 10:05:39 -04001224create_pointer_focus_listener(struct weston_seat *seat)
1225{
1226 struct wl_listener *listener;
1227
1228 if (!seat->seat.pointer)
1229 return;
1230
1231 listener = malloc(sizeof *listener);
1232 listener->notify = handle_pointer_focus;
1233 wl_signal_add(&seat->seat.pointer->focus_signal, listener);
1234}
1235
1236static void
Scott Moreauff1db4a2012-04-17 19:06:18 -06001237shell_surface_pong(struct wl_client *client, struct wl_resource *resource,
1238 uint32_t serial)
1239{
1240 struct shell_surface *shsurf = resource->data;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001241 struct desktop_shell *shell = shsurf->shell;
1242 struct weston_seat *seat;
1243 struct weston_compositor *ec = shsurf->surface->compositor;
1244 struct wl_pointer *pointer;
1245 int was_unresponsive;
Scott Moreauff1db4a2012-04-17 19:06:18 -06001246
Kristian Høgsberg92374e12012-08-11 22:39:12 -04001247 if (shsurf->ping_timer == NULL)
1248 /* Just ignore unsolicited pong. */
1249 return;
1250
Scott Moreauff1db4a2012-04-17 19:06:18 -06001251 if (shsurf->ping_timer->serial == serial) {
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001252 was_unresponsive = shsurf->unresponsive;
Scott Moreauff1db4a2012-04-17 19:06:18 -06001253 shsurf->unresponsive = 0;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001254 if (was_unresponsive) {
1255 /* Received pong from previously unresponsive client */
1256 wl_list_for_each(seat, &ec->seat_list, link) {
1257 pointer = seat->seat.pointer;
1258 if (pointer->focus ==
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001259 &shell->grab_surface->surface &&
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001260 pointer->current ==
1261 &shsurf->surface->surface)
1262 end_busy_cursor(shsurf, pointer);
1263 }
1264 }
Scott Moreau9521d5e2012-04-19 13:06:17 -06001265 ping_timer_destroy(shsurf);
Scott Moreauff1db4a2012-04-17 19:06:18 -06001266 }
1267}
1268
Kristian Høgsberge7afd912012-05-02 09:47:44 -04001269static void
1270shell_surface_set_title(struct wl_client *client,
1271 struct wl_resource *resource, const char *title)
1272{
1273 struct shell_surface *shsurf = resource->data;
1274
1275 free(shsurf->title);
1276 shsurf->title = strdup(title);
1277}
1278
1279static void
1280shell_surface_set_class(struct wl_client *client,
1281 struct wl_resource *resource, const char *class)
1282{
1283 struct shell_surface *shsurf = resource->data;
1284
1285 free(shsurf->class);
1286 shsurf->class = strdup(class);
1287}
1288
Juan Zhao96879df2012-02-07 08:45:41 +08001289static struct weston_output *
1290get_default_output(struct weston_compositor *compositor)
1291{
1292 return container_of(compositor->output_list.next,
1293 struct weston_output, link);
1294}
1295
Alex Wu4539b082012-03-01 12:57:46 +08001296static void
1297shell_unset_fullscreen(struct shell_surface *shsurf)
1298{
1299 /* undo all fullscreen things here */
Alex Wubd3354b2012-04-17 17:20:49 +08001300 if (shsurf->fullscreen.type == WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER &&
1301 shell_surface_is_top_fullscreen(shsurf)) {
1302 weston_output_switch_mode(shsurf->fullscreen_output,
1303 shsurf->fullscreen_output->origin);
1304 }
Alex Wu4539b082012-03-01 12:57:46 +08001305 shsurf->fullscreen.type = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT;
1306 shsurf->fullscreen.framerate = 0;
1307 wl_list_remove(&shsurf->fullscreen.transform.link);
1308 wl_list_init(&shsurf->fullscreen.transform.link);
Alex Wubd3354b2012-04-17 17:20:49 +08001309 if (shsurf->fullscreen.black_surface)
1310 weston_surface_destroy(shsurf->fullscreen.black_surface);
Alex Wu4539b082012-03-01 12:57:46 +08001311 shsurf->fullscreen.black_surface = NULL;
1312 shsurf->fullscreen_output = NULL;
Alex Wu4539b082012-03-01 12:57:46 +08001313 weston_surface_set_position(shsurf->surface,
1314 shsurf->saved_x, shsurf->saved_y);
Alex Wu7bcb8bd2012-04-27 09:07:24 +08001315 if (shsurf->saved_rotation_valid) {
1316 wl_list_insert(&shsurf->surface->geometry.transformation_list,
1317 &shsurf->rotation.transform.link);
1318 shsurf->saved_rotation_valid = false;
1319 }
Alex Wu4539b082012-03-01 12:57:46 +08001320}
1321
Pekka Paalanen98262232011-12-01 10:42:22 +02001322static int
1323reset_shell_surface_type(struct shell_surface *surface)
1324{
1325 switch (surface->type) {
1326 case SHELL_SURFACE_FULLSCREEN:
Alex Wu4539b082012-03-01 12:57:46 +08001327 shell_unset_fullscreen(surface);
Pekka Paalanen98262232011-12-01 10:42:22 +02001328 break;
Juan Zhao96879df2012-02-07 08:45:41 +08001329 case SHELL_SURFACE_MAXIMIZED:
1330 surface->output = get_default_output(surface->surface->compositor);
1331 weston_surface_set_position(surface->surface,
1332 surface->saved_x,
1333 surface->saved_y);
1334 break;
Pekka Paalanen98262232011-12-01 10:42:22 +02001335 case SHELL_SURFACE_NONE:
1336 case SHELL_SURFACE_TOPLEVEL:
1337 case SHELL_SURFACE_TRANSIENT:
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001338 case SHELL_SURFACE_POPUP:
Pekka Paalanen98262232011-12-01 10:42:22 +02001339 break;
1340 }
1341
1342 surface->type = SHELL_SURFACE_NONE;
1343 return 0;
1344}
1345
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001346static void
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001347set_surface_type(struct shell_surface *shsurf)
1348{
1349 struct weston_surface *surface = shsurf->surface;
Kristian Høgsberg8150b192012-06-27 10:22:58 -04001350 struct weston_surface *pes = shsurf->parent;
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001351
1352 reset_shell_surface_type(shsurf);
1353
1354 shsurf->type = shsurf->next_type;
1355 shsurf->next_type = SHELL_SURFACE_NONE;
1356
1357 switch (shsurf->type) {
1358 case SHELL_SURFACE_TOPLEVEL:
1359 break;
1360 case SHELL_SURFACE_TRANSIENT:
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001361 weston_surface_set_position(surface,
Tiago Vignatti52e598c2012-05-07 15:23:08 +03001362 pes->geometry.x + shsurf->transient.x,
1363 pes->geometry.y + shsurf->transient.y);
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001364 break;
1365
1366 case SHELL_SURFACE_MAXIMIZED:
1367 shsurf->saved_x = surface->geometry.x;
1368 shsurf->saved_y = surface->geometry.y;
1369 shsurf->saved_position_valid = true;
1370 break;
1371
1372 case SHELL_SURFACE_FULLSCREEN:
1373 shsurf->saved_x = surface->geometry.x;
1374 shsurf->saved_y = surface->geometry.y;
1375 shsurf->saved_position_valid = true;
1376
1377 if (!wl_list_empty(&shsurf->rotation.transform.link)) {
1378 wl_list_remove(&shsurf->rotation.transform.link);
1379 wl_list_init(&shsurf->rotation.transform.link);
1380 shsurf->surface->geometry.dirty = 1;
1381 shsurf->saved_rotation_valid = true;
1382 }
1383 break;
1384
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001385 default:
1386 break;
1387 }
1388}
1389
1390static void
Tiago Vignattibc052c92012-04-19 16:18:18 +03001391set_toplevel(struct shell_surface *shsurf)
1392{
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001393 shsurf->next_type = SHELL_SURFACE_TOPLEVEL;
Tiago Vignattibc052c92012-04-19 16:18:18 +03001394}
1395
1396static void
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001397shell_surface_set_toplevel(struct wl_client *client,
1398 struct wl_resource *resource)
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001399{
Pekka Paalanen98262232011-12-01 10:42:22 +02001400 struct shell_surface *surface = resource->data;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001401
Tiago Vignattibc052c92012-04-19 16:18:18 +03001402 set_toplevel(surface);
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001403}
1404
1405static void
Tiago Vignatti491bac12012-05-18 16:37:43 -04001406set_transient(struct shell_surface *shsurf,
Kristian Høgsberg8150b192012-06-27 10:22:58 -04001407 struct weston_surface *parent, int x, int y, uint32_t flags)
Tiago Vignatti491bac12012-05-18 16:37:43 -04001408{
1409 /* assign to parents output */
Kristian Høgsberg8150b192012-06-27 10:22:58 -04001410 shsurf->parent = parent;
Tiago Vignatti491bac12012-05-18 16:37:43 -04001411 shsurf->transient.x = x;
1412 shsurf->transient.y = y;
1413 shsurf->transient.flags = flags;
1414 shsurf->next_type = SHELL_SURFACE_TRANSIENT;
1415}
1416
1417static void
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001418shell_surface_set_transient(struct wl_client *client,
1419 struct wl_resource *resource,
1420 struct wl_resource *parent_resource,
1421 int x, int y, uint32_t flags)
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001422{
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001423 struct shell_surface *shsurf = resource->data;
Kristian Høgsberg8150b192012-06-27 10:22:58 -04001424 struct weston_surface *parent = parent_resource->data;
Pekka Paalanen98262232011-12-01 10:42:22 +02001425
Kristian Høgsberg8150b192012-06-27 10:22:58 -04001426 set_transient(shsurf, parent, x, y, flags);
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001427}
1428
Tiago Vignattibe143262012-04-16 17:31:41 +03001429static struct desktop_shell *
Juan Zhao96879df2012-02-07 08:45:41 +08001430shell_surface_get_shell(struct shell_surface *shsurf)
Pekka Paalanenaf0e34c2011-12-02 10:59:17 +02001431{
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04001432 return shsurf->shell;
Juan Zhao96879df2012-02-07 08:45:41 +08001433}
1434
1435static int
Tiago Vignattibe143262012-04-16 17:31:41 +03001436get_output_panel_height(struct desktop_shell *shell,
1437 struct weston_output *output)
Juan Zhao96879df2012-02-07 08:45:41 +08001438{
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001439 struct weston_surface *surface;
Juan Zhao96879df2012-02-07 08:45:41 +08001440 int panel_height = 0;
1441
1442 if (!output)
1443 return 0;
1444
Juan Zhao4ab94682012-07-09 22:24:09 -07001445 wl_list_for_each(surface, &shell->panel_layer.surface_list, layer_link) {
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001446 if (surface->output == output) {
1447 panel_height = surface->geometry.height;
Juan Zhao96879df2012-02-07 08:45:41 +08001448 break;
1449 }
1450 }
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001451
Juan Zhao96879df2012-02-07 08:45:41 +08001452 return panel_height;
1453}
1454
1455static void
1456shell_surface_set_maximized(struct wl_client *client,
1457 struct wl_resource *resource,
1458 struct wl_resource *output_resource )
1459{
1460 struct shell_surface *shsurf = resource->data;
1461 struct weston_surface *es = shsurf->surface;
Tiago Vignattibe143262012-04-16 17:31:41 +03001462 struct desktop_shell *shell = NULL;
Juan Zhao96879df2012-02-07 08:45:41 +08001463 uint32_t edges = 0, panel_height = 0;
1464
1465 /* get the default output, if the client set it as NULL
1466 check whether the ouput is available */
1467 if (output_resource)
1468 shsurf->output = output_resource->data;
Kristian Høgsberg94de6802012-07-18 09:54:04 -04001469 else if (es->output)
1470 shsurf->output = es->output;
Juan Zhao96879df2012-02-07 08:45:41 +08001471 else
1472 shsurf->output = get_default_output(es->compositor);
1473
Tiago Vignattibe143262012-04-16 17:31:41 +03001474 shell = shell_surface_get_shell(shsurf);
Rob Bradford31b68622012-07-02 19:00:19 +01001475 panel_height = get_output_panel_height(shell, shsurf->output);
Juan Zhao96879df2012-02-07 08:45:41 +08001476 edges = WL_SHELL_SURFACE_RESIZE_TOP|WL_SHELL_SURFACE_RESIZE_LEFT;
Kristian Høgsberg0b5cd0c2012-03-04 21:57:37 -05001477
Kristian Høgsberga61ca062012-05-22 16:05:52 -04001478 shsurf->client->send_configure(shsurf->surface, edges,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001479 shsurf->output->width,
1480 shsurf->output->height - panel_height);
Juan Zhao96879df2012-02-07 08:45:41 +08001481
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001482 shsurf->next_type = SHELL_SURFACE_MAXIMIZED;
Pekka Paalanenaf0e34c2011-12-02 10:59:17 +02001483}
1484
Alex Wu21858432012-04-01 20:13:08 +08001485static void
1486black_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy);
1487
Alex Wu4539b082012-03-01 12:57:46 +08001488static struct weston_surface *
1489create_black_surface(struct weston_compositor *ec,
Alex Wu21858432012-04-01 20:13:08 +08001490 struct weston_surface *fs_surface,
Alex Wu4539b082012-03-01 12:57:46 +08001491 GLfloat x, GLfloat y, int w, int h)
1492{
1493 struct weston_surface *surface = NULL;
1494
1495 surface = weston_surface_create(ec);
1496 if (surface == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001497 weston_log("no memory\n");
Alex Wu4539b082012-03-01 12:57:46 +08001498 return NULL;
1499 }
1500
Alex Wu21858432012-04-01 20:13:08 +08001501 surface->configure = black_surface_configure;
1502 surface->private = fs_surface;
Alex Wu4539b082012-03-01 12:57:46 +08001503 weston_surface_configure(surface, x, y, w, h);
1504 weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1);
Kristian Høgsberg61f00f52012-08-03 16:31:36 -04001505 pixman_region32_init_rect(&surface->opaque, 0, 0, w, h);
1506
Alex Wu4539b082012-03-01 12:57:46 +08001507 return surface;
1508}
1509
1510/* Create black surface and append it to the associated fullscreen surface.
1511 * Handle size dismatch and positioning according to the method. */
1512static void
1513shell_configure_fullscreen(struct shell_surface *shsurf)
1514{
1515 struct weston_output *output = shsurf->fullscreen_output;
1516 struct weston_surface *surface = shsurf->surface;
1517 struct weston_matrix *matrix;
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04001518 float scale, output_aspect, surface_aspect, x, y;
Alex Wu4539b082012-03-01 12:57:46 +08001519
Alex Wu4539b082012-03-01 12:57:46 +08001520 if (!shsurf->fullscreen.black_surface)
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05001521 shsurf->fullscreen.black_surface =
1522 create_black_surface(surface->compositor,
Alex Wu21858432012-04-01 20:13:08 +08001523 surface,
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05001524 output->x, output->y,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001525 output->width,
1526 output->height);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05001527
1528 wl_list_remove(&shsurf->fullscreen.black_surface->layer_link);
1529 wl_list_insert(&surface->layer_link,
1530 &shsurf->fullscreen.black_surface->layer_link);
Alex Wu4539b082012-03-01 12:57:46 +08001531 shsurf->fullscreen.black_surface->output = output;
1532
1533 switch (shsurf->fullscreen.type) {
1534 case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT:
Kristian Høgsberga08b5282012-07-20 15:30:36 -04001535 if (surface->buffer)
1536 center_on_output(surface, shsurf->fullscreen_output);
Alex Wu4539b082012-03-01 12:57:46 +08001537 break;
1538 case WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE:
1539 matrix = &shsurf->fullscreen.transform.matrix;
1540 weston_matrix_init(matrix);
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04001541
Scott Moreau1bad5db2012-08-18 01:04:05 -06001542 output_aspect = (float) output->width /
1543 (float) output->height;
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04001544 surface_aspect = (float) surface->geometry.width /
1545 (float) surface->geometry.height;
1546 if (output_aspect < surface_aspect)
Scott Moreau1bad5db2012-08-18 01:04:05 -06001547 scale = (float) output->width /
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04001548 (float) surface->geometry.width;
1549 else
Scott Moreau1bad5db2012-08-18 01:04:05 -06001550 scale = (float) output->height /
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04001551 (float) surface->geometry.height;
1552
Alex Wu4539b082012-03-01 12:57:46 +08001553 weston_matrix_scale(matrix, scale, scale, 1);
1554 wl_list_remove(&shsurf->fullscreen.transform.link);
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04001555 wl_list_insert(&surface->geometry.transformation_list,
Alex Wu4539b082012-03-01 12:57:46 +08001556 &shsurf->fullscreen.transform.link);
Scott Moreau1bad5db2012-08-18 01:04:05 -06001557 x = output->x + (output->width - surface->geometry.width * scale) / 2;
1558 y = output->y + (output->height - surface->geometry.height * scale) / 2;
Kristian Høgsberg240dfeb2012-07-12 12:32:31 -04001559 weston_surface_set_position(surface, x, y);
1560
Alex Wu4539b082012-03-01 12:57:46 +08001561 break;
1562 case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER:
Alex Wubd3354b2012-04-17 17:20:49 +08001563 if (shell_surface_is_top_fullscreen(shsurf)) {
1564 struct weston_mode mode = {0,
1565 surface->geometry.width,
1566 surface->geometry.height,
1567 shsurf->fullscreen.framerate};
1568
1569 if (weston_output_switch_mode(output, &mode) == 0) {
1570 weston_surface_configure(shsurf->fullscreen.black_surface,
1571 output->x, output->y,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001572 output->width,
1573 output->height);
Alex Wubd3354b2012-04-17 17:20:49 +08001574 weston_surface_set_position(surface, output->x, output->y);
1575 break;
1576 }
1577 }
Alex Wu4539b082012-03-01 12:57:46 +08001578 break;
1579 case WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL:
1580 break;
1581 default:
1582 break;
1583 }
1584}
1585
1586/* make the fullscreen and black surface at the top */
1587static void
1588shell_stack_fullscreen(struct shell_surface *shsurf)
1589{
Alex Wubd3354b2012-04-17 17:20:49 +08001590 struct weston_output *output = shsurf->fullscreen_output;
Alex Wu4539b082012-03-01 12:57:46 +08001591 struct weston_surface *surface = shsurf->surface;
Tiago Vignattibe143262012-04-16 17:31:41 +03001592 struct desktop_shell *shell = shell_surface_get_shell(shsurf);
Alex Wu4539b082012-03-01 12:57:46 +08001593
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05001594 wl_list_remove(&surface->layer_link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05001595 wl_list_insert(&shell->fullscreen_layer.surface_list,
1596 &surface->layer_link);
Alex Wubd3354b2012-04-17 17:20:49 +08001597 weston_surface_damage(surface);
1598
1599 if (!shsurf->fullscreen.black_surface)
1600 shsurf->fullscreen.black_surface =
1601 create_black_surface(surface->compositor,
1602 surface,
1603 output->x, output->y,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001604 output->width,
1605 output->height);
Alex Wubd3354b2012-04-17 17:20:49 +08001606
1607 wl_list_remove(&shsurf->fullscreen.black_surface->layer_link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05001608 wl_list_insert(&surface->layer_link,
1609 &shsurf->fullscreen.black_surface->layer_link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05001610 weston_surface_damage(shsurf->fullscreen.black_surface);
Alex Wu4539b082012-03-01 12:57:46 +08001611}
1612
1613static void
1614shell_map_fullscreen(struct shell_surface *shsurf)
1615{
Alex Wu4539b082012-03-01 12:57:46 +08001616 shell_stack_fullscreen(shsurf);
Alex Wubd3354b2012-04-17 17:20:49 +08001617 shell_configure_fullscreen(shsurf);
Alex Wu4539b082012-03-01 12:57:46 +08001618}
1619
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001620static void
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001621shell_surface_set_fullscreen(struct wl_client *client,
Kristian Høgsbergf856fd22012-02-16 15:58:14 -05001622 struct wl_resource *resource,
1623 uint32_t method,
1624 uint32_t framerate,
1625 struct wl_resource *output_resource)
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001626{
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001627 struct shell_surface *shsurf = resource->data;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001628 struct weston_surface *es = shsurf->surface;
Alex Wu4539b082012-03-01 12:57:46 +08001629
1630 if (output_resource)
1631 shsurf->output = output_resource->data;
Kristian Høgsberg94de6802012-07-18 09:54:04 -04001632 else if (es->output)
1633 shsurf->output = es->output;
Alex Wu4539b082012-03-01 12:57:46 +08001634 else
1635 shsurf->output = get_default_output(es->compositor);
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001636
Alex Wu4539b082012-03-01 12:57:46 +08001637 shsurf->fullscreen_output = shsurf->output;
1638 shsurf->fullscreen.type = method;
1639 shsurf->fullscreen.framerate = framerate;
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001640 shsurf->next_type = SHELL_SURFACE_FULLSCREEN;
Alex Wu4539b082012-03-01 12:57:46 +08001641
Kristian Høgsberga61ca062012-05-22 16:05:52 -04001642 shsurf->client->send_configure(shsurf->surface, 0,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001643 shsurf->output->width,
1644 shsurf->output->height);
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04001645}
1646
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001647static void
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001648popup_grab_focus(struct wl_pointer_grab *grab,
Daniel Stone103db7f2012-05-08 17:17:55 +01001649 struct wl_surface *surface,
1650 wl_fixed_t x,
1651 wl_fixed_t y)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001652{
Daniel Stone37816df2012-05-16 18:45:18 +01001653 struct wl_pointer *pointer = grab->pointer;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001654 struct shell_surface *priv =
1655 container_of(grab, struct shell_surface, popup.grab);
1656 struct wl_client *client = priv->surface->surface.resource.client;
1657
Pekka Paalanencb108432012-01-19 16:25:40 +02001658 if (surface && surface->resource.client == client) {
Daniel Stone37816df2012-05-16 18:45:18 +01001659 wl_pointer_set_focus(pointer, surface, x, y);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001660 grab->focus = surface;
1661 } else {
Daniel Stone37816df2012-05-16 18:45:18 +01001662 wl_pointer_set_focus(pointer, NULL,
1663 wl_fixed_from_int(0),
1664 wl_fixed_from_int(0));
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001665 grab->focus = NULL;
1666 }
1667}
1668
1669static void
Scott Moreau447013d2012-02-18 05:05:29 -07001670popup_grab_motion(struct wl_pointer_grab *grab,
Daniel Stone103db7f2012-05-08 17:17:55 +01001671 uint32_t time, wl_fixed_t sx, wl_fixed_t sy)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001672{
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001673 struct wl_resource *resource;
1674
Daniel Stone37816df2012-05-16 18:45:18 +01001675 resource = grab->pointer->focus_resource;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001676 if (resource)
Daniel Stone37816df2012-05-16 18:45:18 +01001677 wl_pointer_send_motion(resource, time, sx, sy);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001678}
1679
1680static void
Scott Moreau447013d2012-02-18 05:05:29 -07001681popup_grab_button(struct wl_pointer_grab *grab,
Daniel Stone4dbadb12012-05-30 16:31:51 +01001682 uint32_t time, uint32_t button, uint32_t state_w)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001683{
1684 struct wl_resource *resource;
1685 struct shell_surface *shsurf =
1686 container_of(grab, struct shell_surface, popup.grab);
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001687 struct wl_display *display;
Daniel Stone4dbadb12012-05-30 16:31:51 +01001688 enum wl_pointer_button_state state = state_w;
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001689 uint32_t serial;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001690
Daniel Stone37816df2012-05-16 18:45:18 +01001691 resource = grab->pointer->focus_resource;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001692 if (resource) {
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001693 display = wl_client_get_display(resource->client);
1694 serial = wl_display_get_serial(display);
Daniel Stone37816df2012-05-16 18:45:18 +01001695 wl_pointer_send_button(resource, serial, time, button, state);
Daniel Stone4dbadb12012-05-30 16:31:51 +01001696 } else if (state == WL_POINTER_BUTTON_STATE_RELEASED &&
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001697 (shsurf->popup.initial_up ||
Daniel Stone37816df2012-05-16 18:45:18 +01001698 time - shsurf->popup.seat->pointer->grab_time > 500)) {
Kristian Høgsberg0b5cd0c2012-03-04 21:57:37 -05001699 wl_shell_surface_send_popup_done(&shsurf->resource);
Daniel Stone37816df2012-05-16 18:45:18 +01001700 wl_pointer_end_grab(grab->pointer);
1701 shsurf->popup.grab.pointer = NULL;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001702 }
1703
Daniel Stone4dbadb12012-05-30 16:31:51 +01001704 if (state == WL_POINTER_BUTTON_STATE_RELEASED)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001705 shsurf->popup.initial_up = 1;
1706}
1707
Scott Moreau447013d2012-02-18 05:05:29 -07001708static const struct wl_pointer_grab_interface popup_grab_interface = {
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001709 popup_grab_focus,
1710 popup_grab_motion,
1711 popup_grab_button,
1712};
1713
1714static void
Kristian Høgsberg3730f362012-04-13 12:40:07 -04001715shell_map_popup(struct shell_surface *shsurf)
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001716{
Daniel Stone37816df2012-05-16 18:45:18 +01001717 struct wl_seat *seat = shsurf->popup.seat;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001718 struct weston_surface *es = shsurf->surface;
Kristian Høgsberg8150b192012-06-27 10:22:58 -04001719 struct weston_surface *parent = shsurf->parent;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001720
1721 es->output = parent->output;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001722 shsurf->popup.grab.interface = &popup_grab_interface;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001723
Pekka Paalanen938269a2012-02-07 14:19:01 +02001724 weston_surface_update_transform(parent);
1725 if (parent->transform.enabled) {
1726 shsurf->popup.parent_transform.matrix =
1727 parent->transform.matrix;
1728 } else {
1729 /* construct x, y translation matrix */
1730 weston_matrix_init(&shsurf->popup.parent_transform.matrix);
1731 shsurf->popup.parent_transform.matrix.d[12] =
1732 parent->geometry.x;
1733 shsurf->popup.parent_transform.matrix.d[13] =
1734 parent->geometry.y;
1735 }
1736 wl_list_insert(es->geometry.transformation_list.prev,
1737 &shsurf->popup.parent_transform.link);
Pekka Paalanen8fb8d3b2012-02-13 13:03:59 +02001738 weston_surface_set_position(es, shsurf->popup.x, shsurf->popup.y);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001739
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001740 shsurf->popup.initial_up = 0;
1741
Kristian Høgsberg3730f362012-04-13 12:40:07 -04001742 /* We don't require the grab to still be active, but if another
1743 * grab has started in the meantime, we end the popup now. */
Daniel Stone37816df2012-05-16 18:45:18 +01001744 if (seat->pointer->grab_serial == shsurf->popup.serial) {
1745 wl_pointer_start_grab(seat->pointer, &shsurf->popup.grab);
Kristian Høgsberg3730f362012-04-13 12:40:07 -04001746 } else {
1747 wl_shell_surface_send_popup_done(&shsurf->resource);
1748 }
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001749}
1750
1751static void
1752shell_surface_set_popup(struct wl_client *client,
1753 struct wl_resource *resource,
Daniel Stone37816df2012-05-16 18:45:18 +01001754 struct wl_resource *seat_resource,
Kristian Høgsberg3730f362012-04-13 12:40:07 -04001755 uint32_t serial,
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001756 struct wl_resource *parent_resource,
1757 int32_t x, int32_t y, uint32_t flags)
1758{
1759 struct shell_surface *shsurf = resource->data;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001760
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001761 shsurf->type = SHELL_SURFACE_POPUP;
1762 shsurf->parent = parent_resource->data;
Daniel Stone37816df2012-05-16 18:45:18 +01001763 shsurf->popup.seat = seat_resource->data;
Kristian Høgsberg3730f362012-04-13 12:40:07 -04001764 shsurf->popup.serial = serial;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001765 shsurf->popup.x = x;
1766 shsurf->popup.y = y;
1767}
1768
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001769static const struct wl_shell_surface_interface shell_surface_implementation = {
Scott Moreauff1db4a2012-04-17 19:06:18 -06001770 shell_surface_pong,
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001771 shell_surface_move,
1772 shell_surface_resize,
1773 shell_surface_set_toplevel,
1774 shell_surface_set_transient,
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001775 shell_surface_set_fullscreen,
Juan Zhao96879df2012-02-07 08:45:41 +08001776 shell_surface_set_popup,
Kristian Høgsberge7afd912012-05-02 09:47:44 -04001777 shell_surface_set_maximized,
1778 shell_surface_set_title,
1779 shell_surface_set_class
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001780};
1781
1782static void
Tiago Vignattibc052c92012-04-19 16:18:18 +03001783destroy_shell_surface(struct shell_surface *shsurf)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001784{
Daniel Stone37816df2012-05-16 18:45:18 +01001785 if (shsurf->popup.grab.pointer)
1786 wl_pointer_end_grab(shsurf->popup.grab.pointer);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05001787
Alex Wubd3354b2012-04-17 17:20:49 +08001788 if (shsurf->fullscreen.type == WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER &&
1789 shell_surface_is_top_fullscreen(shsurf)) {
1790 weston_output_switch_mode(shsurf->fullscreen_output,
1791 shsurf->fullscreen_output->origin);
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03001792 }
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001793
Alex Wuaa08e2d2012-03-05 11:01:40 +08001794 if (shsurf->fullscreen.black_surface)
1795 weston_surface_destroy(shsurf->fullscreen.black_surface);
1796
Alex Wubd3354b2012-04-17 17:20:49 +08001797 /* As destroy_resource() use wl_list_for_each_safe(),
1798 * we can always remove the listener.
1799 */
1800 wl_list_remove(&shsurf->surface_destroy_listener.link);
1801 shsurf->surface->configure = NULL;
Scott Moreau9521d5e2012-04-19 13:06:17 -06001802 ping_timer_destroy(shsurf);
Alex Wubd3354b2012-04-17 17:20:49 +08001803
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001804 wl_list_remove(&shsurf->link);
1805 free(shsurf);
1806}
1807
1808static void
Tiago Vignattibc052c92012-04-19 16:18:18 +03001809shell_destroy_shell_surface(struct wl_resource *resource)
1810{
1811 struct shell_surface *shsurf = resource->data;
1812
1813 destroy_shell_surface(shsurf);
1814}
1815
1816static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001817shell_handle_surface_destroy(struct wl_listener *listener, void *data)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001818{
1819 struct shell_surface *shsurf = container_of(listener,
1820 struct shell_surface,
1821 surface_destroy_listener);
1822
Kristian Høgsberg633b1452012-06-07 18:08:47 -04001823 if (shsurf->resource.client) {
Tiago Vignattibc052c92012-04-19 16:18:18 +03001824 wl_resource_destroy(&shsurf->resource);
Kristian Høgsberg633b1452012-06-07 18:08:47 -04001825 } else {
1826 wl_signal_emit(&shsurf->resource.destroy_signal,
1827 &shsurf->resource);
Tiago Vignattibc052c92012-04-19 16:18:18 +03001828 destroy_shell_surface(shsurf);
Kristian Høgsberg633b1452012-06-07 18:08:47 -04001829 }
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001830}
1831
Kristian Høgsbergd8134452012-06-21 12:49:02 -04001832static void
1833shell_surface_configure(struct weston_surface *, int32_t, int32_t);
1834
Pekka Paalanenec2b32f2011-11-28 15:12:34 +02001835static struct shell_surface *
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001836get_shell_surface(struct weston_surface *surface)
Pekka Paalanenec2b32f2011-11-28 15:12:34 +02001837{
Kristian Høgsbergd8134452012-06-21 12:49:02 -04001838 if (surface->configure == shell_surface_configure)
1839 return surface->private;
1840 else
1841 return NULL;
Pekka Paalanenec2b32f2011-11-28 15:12:34 +02001842}
1843
Kristian Høgsberg45ba8692012-05-21 14:27:33 -04001844static struct shell_surface *
Kristian Høgsberga61ca062012-05-22 16:05:52 -04001845create_shell_surface(void *shell, struct weston_surface *surface,
1846 const struct weston_shell_client *client)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001847{
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001848 struct shell_surface *shsurf;
1849
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03001850 if (surface->configure) {
Martin Minarik6d118362012-06-07 18:01:59 +02001851 weston_log("surface->configure already set\n");
Kristian Høgsberg45ba8692012-05-21 14:27:33 -04001852 return NULL;
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03001853 }
1854
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001855 shsurf = calloc(1, sizeof *shsurf);
1856 if (!shsurf) {
Martin Minarik6d118362012-06-07 18:01:59 +02001857 weston_log("no memory to allocate shell surface\n");
Kristian Høgsberg45ba8692012-05-21 14:27:33 -04001858 return NULL;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001859 }
1860
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03001861 surface->configure = shell_surface_configure;
Kristian Høgsbergd8134452012-06-21 12:49:02 -04001862 surface->private = shsurf;
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03001863
Tiago Vignattibc052c92012-04-19 16:18:18 +03001864 shsurf->shell = (struct desktop_shell *) shell;
Scott Moreauff1db4a2012-04-17 19:06:18 -06001865 shsurf->unresponsive = 0;
Alex Wu4539b082012-03-01 12:57:46 +08001866 shsurf->saved_position_valid = false;
Alex Wu7bcb8bd2012-04-27 09:07:24 +08001867 shsurf->saved_rotation_valid = false;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001868 shsurf->surface = surface;
Alex Wu4539b082012-03-01 12:57:46 +08001869 shsurf->fullscreen.type = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT;
1870 shsurf->fullscreen.framerate = 0;
1871 shsurf->fullscreen.black_surface = NULL;
Scott Moreauff1db4a2012-04-17 19:06:18 -06001872 shsurf->ping_timer = NULL;
Alex Wu4539b082012-03-01 12:57:46 +08001873 wl_list_init(&shsurf->fullscreen.transform.link);
1874
Tiago Vignattibc052c92012-04-19 16:18:18 +03001875 wl_signal_init(&shsurf->resource.destroy_signal);
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001876 shsurf->surface_destroy_listener.notify = shell_handle_surface_destroy;
1877 wl_signal_add(&surface->surface.resource.destroy_signal,
1878 &shsurf->surface_destroy_listener);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001879
1880 /* init link so its safe to always remove it in destroy_shell_surface */
1881 wl_list_init(&shsurf->link);
1882
Pekka Paalanen460099f2012-01-20 16:48:25 +02001883 /* empty when not in use */
1884 wl_list_init(&shsurf->rotation.transform.link);
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05001885 weston_matrix_init(&shsurf->rotation.rotation);
Pekka Paalanen460099f2012-01-20 16:48:25 +02001886
Jonas Ådahl62fcd042012-06-13 00:01:23 +02001887 wl_list_init(&shsurf->workspace_transform.link);
1888
Pekka Paalanen98262232011-12-01 10:42:22 +02001889 shsurf->type = SHELL_SURFACE_NONE;
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04001890 shsurf->next_type = SHELL_SURFACE_NONE;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001891
Kristian Høgsberga61ca062012-05-22 16:05:52 -04001892 shsurf->client = client;
1893
Kristian Høgsberg45ba8692012-05-21 14:27:33 -04001894 return shsurf;
Tiago Vignattibc052c92012-04-19 16:18:18 +03001895}
1896
1897static void
1898shell_get_shell_surface(struct wl_client *client,
1899 struct wl_resource *resource,
1900 uint32_t id,
1901 struct wl_resource *surface_resource)
1902{
1903 struct weston_surface *surface = surface_resource->data;
1904 struct desktop_shell *shell = resource->data;
1905 struct shell_surface *shsurf;
1906
1907 if (get_shell_surface(surface)) {
1908 wl_resource_post_error(surface_resource,
Kristian Høgsberg9540ea62012-05-21 14:28:57 -04001909 WL_DISPLAY_ERROR_INVALID_OBJECT,
1910 "desktop_shell::get_shell_surface already requested");
Tiago Vignattibc052c92012-04-19 16:18:18 +03001911 return;
1912 }
1913
Kristian Høgsberga61ca062012-05-22 16:05:52 -04001914 shsurf = create_shell_surface(shell, surface, &shell_client);
Kristian Høgsberg9540ea62012-05-21 14:28:57 -04001915 if (!shsurf) {
1916 wl_resource_post_error(surface_resource,
1917 WL_DISPLAY_ERROR_INVALID_OBJECT,
1918 "surface->configure already set");
1919 return;
1920 }
Tiago Vignattibc052c92012-04-19 16:18:18 +03001921
Kristian Høgsberg9540ea62012-05-21 14:28:57 -04001922 shsurf->resource.destroy = shell_destroy_shell_surface;
1923 shsurf->resource.object.id = id;
1924 shsurf->resource.object.interface = &wl_shell_surface_interface;
1925 shsurf->resource.object.implementation =
1926 (void (**)(void)) &shell_surface_implementation;
1927 shsurf->resource.data = shsurf;
Tiago Vignattibc052c92012-04-19 16:18:18 +03001928
Kristian Høgsberg9540ea62012-05-21 14:28:57 -04001929 wl_client_add_resource(client, &shsurf->resource);
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001930}
1931
1932static const struct wl_shell_interface shell_implementation = {
Pekka Paalanen46229672011-11-29 15:49:31 +02001933 shell_get_shell_surface
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001934};
1935
Kristian Høgsberg07937562011-04-12 17:25:42 -04001936static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001937handle_screensaver_sigchld(struct weston_process *proc, int status)
Pekka Paalanen18027e52011-12-02 16:31:49 +02001938{
1939 proc->pid = 0;
1940}
1941
1942static void
Tiago Vignattibe143262012-04-16 17:31:41 +03001943launch_screensaver(struct desktop_shell *shell)
Pekka Paalanen77346a62011-11-30 16:26:35 +02001944{
1945 if (shell->screensaver.binding)
1946 return;
1947
Pekka Paalanene955f1e2011-12-07 11:49:52 +02001948 if (!shell->screensaver.path)
1949 return;
1950
Kristian Høgsberg32bed572012-03-01 17:11:36 -05001951 if (shell->screensaver.process.pid != 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001952 weston_log("old screensaver still running\n");
Kristian Høgsberg32bed572012-03-01 17:11:36 -05001953 return;
1954 }
1955
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001956 weston_client_launch(shell->compositor,
Pekka Paalanen18027e52011-12-02 16:31:49 +02001957 &shell->screensaver.process,
Pekka Paalanene955f1e2011-12-07 11:49:52 +02001958 shell->screensaver.path,
Pekka Paalanen18027e52011-12-02 16:31:49 +02001959 handle_screensaver_sigchld);
Pekka Paalanen77346a62011-11-30 16:26:35 +02001960}
1961
1962static void
Tiago Vignattibe143262012-04-16 17:31:41 +03001963terminate_screensaver(struct desktop_shell *shell)
Pekka Paalanen77346a62011-11-30 16:26:35 +02001964{
Pekka Paalanen18027e52011-12-02 16:31:49 +02001965 if (shell->screensaver.process.pid == 0)
1966 return;
1967
1968 kill(shell->screensaver.process.pid, SIGTERM);
Pekka Paalanen77346a62011-11-30 16:26:35 +02001969}
1970
1971static void
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001972configure_static_surface(struct weston_surface *es, struct weston_layer *layer)
Kristian Høgsberg962342c2012-06-26 16:29:50 -04001973{
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001974 struct weston_surface *s, *next;
Kristian Høgsberg962342c2012-06-26 16:29:50 -04001975
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001976 wl_list_for_each_safe(s, next, &layer->surface_list, layer_link) {
1977 if (s->output == es->output && s != es) {
1978 weston_surface_unmap(s);
Kristian Høgsberg962342c2012-06-26 16:29:50 -04001979 s->configure = NULL;
Kristian Høgsberg962342c2012-06-26 16:29:50 -04001980 }
1981 }
1982
1983 weston_surface_configure(es, es->output->x, es->output->y,
1984 es->buffer->width, es->buffer->height);
1985
1986 if (wl_list_empty(&es->layer_link)) {
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001987 wl_list_insert(&layer->surface_list, &es->layer_link);
Kristian Høgsbergc7cd6262012-06-28 13:46:09 -04001988 weston_compositor_schedule_repaint(es->compositor);
Kristian Høgsberg962342c2012-06-26 16:29:50 -04001989 }
1990}
1991
1992static void
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04001993background_configure(struct weston_surface *es, int32_t sx, int32_t sy)
1994{
1995 struct desktop_shell *shell = es->private;
1996
1997 configure_static_surface(es, &shell->background_layer);
1998}
1999
2000static void
Kristian Høgsberg75840622011-09-06 13:48:16 -04002001desktop_shell_set_background(struct wl_client *client,
2002 struct wl_resource *resource,
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01002003 struct wl_resource *output_resource,
Kristian Høgsberg75840622011-09-06 13:48:16 -04002004 struct wl_resource *surface_resource)
2005{
Kristian Høgsberg962342c2012-06-26 16:29:50 -04002006 struct desktop_shell *shell = resource->data;
2007 struct weston_surface *surface = surface_resource->data;
Kristian Høgsberg75840622011-09-06 13:48:16 -04002008
Kristian Høgsberg962342c2012-06-26 16:29:50 -04002009 if (surface->configure) {
2010 wl_resource_post_error(surface_resource,
2011 WL_DISPLAY_ERROR_INVALID_OBJECT,
2012 "surface role already assigned");
2013 return;
2014 }
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01002015
Kristian Høgsberg962342c2012-06-26 16:29:50 -04002016 surface->configure = background_configure;
2017 surface->private = shell;
2018 surface->output = output_resource->data;
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04002019 desktop_shell_send_configure(resource, 0,
Kristian Høgsberg0b5cd0c2012-03-04 21:57:37 -05002020 surface_resource,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002021 surface->output->width,
2022 surface->output->height);
Kristian Høgsberg75840622011-09-06 13:48:16 -04002023}
2024
2025static void
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04002026panel_configure(struct weston_surface *es, int32_t sx, int32_t sy)
2027{
2028 struct desktop_shell *shell = es->private;
2029
2030 configure_static_surface(es, &shell->panel_layer);
2031}
2032
2033static void
Kristian Høgsberg75840622011-09-06 13:48:16 -04002034desktop_shell_set_panel(struct wl_client *client,
2035 struct wl_resource *resource,
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01002036 struct wl_resource *output_resource,
Kristian Høgsberg75840622011-09-06 13:48:16 -04002037 struct wl_resource *surface_resource)
2038{
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04002039 struct desktop_shell *shell = resource->data;
2040 struct weston_surface *surface = surface_resource->data;
Kristian Høgsberg75840622011-09-06 13:48:16 -04002041
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04002042 if (surface->configure) {
2043 wl_resource_post_error(surface_resource,
2044 WL_DISPLAY_ERROR_INVALID_OBJECT,
2045 "surface role already assigned");
2046 return;
2047 }
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01002048
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04002049 surface->configure = panel_configure;
2050 surface->private = shell;
2051 surface->output = output_resource->data;
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04002052 desktop_shell_send_configure(resource, 0,
Kristian Høgsbergaf7b1ff2012-06-26 21:19:23 -04002053 surface_resource,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002054 surface->output->width,
2055 surface->output->height);
Kristian Høgsberg75840622011-09-06 13:48:16 -04002056}
2057
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002058static void
Kristian Høgsberg730c94d2012-06-26 21:44:35 -04002059lock_surface_configure(struct weston_surface *surface, int32_t sx, int32_t sy)
2060{
2061 struct desktop_shell *shell = surface->private;
2062
2063 center_on_output(surface, get_default_output(shell->compositor));
2064
2065 if (!weston_surface_is_mapped(surface)) {
2066 wl_list_insert(&shell->lock_layer.surface_list,
2067 &surface->layer_link);
2068 weston_surface_assign_output(surface);
2069 weston_compositor_wake(shell->compositor);
2070 }
2071}
2072
2073static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04002074handle_lock_surface_destroy(struct wl_listener *listener, void *data)
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05002075{
Tiago Vignattibe143262012-04-16 17:31:41 +03002076 struct desktop_shell *shell =
2077 container_of(listener, struct desktop_shell, lock_surface_listener);
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05002078
Martin Minarik6d118362012-06-07 18:01:59 +02002079 weston_log("lock surface gone\n");
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05002080 shell->lock_surface = NULL;
2081}
2082
2083static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002084desktop_shell_set_lock_surface(struct wl_client *client,
2085 struct wl_resource *resource,
2086 struct wl_resource *surface_resource)
2087{
Tiago Vignattibe143262012-04-16 17:31:41 +03002088 struct desktop_shell *shell = resource->data;
Kristian Høgsberg730c94d2012-06-26 21:44:35 -04002089 struct weston_surface *surface = surface_resource->data;
Pekka Paalanen98262232011-12-01 10:42:22 +02002090
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002091 shell->prepare_event_sent = false;
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +02002092
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002093 if (!shell->locked)
2094 return;
2095
Pekka Paalanen98262232011-12-01 10:42:22 +02002096 shell->lock_surface = surface;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002097
Kristian Høgsberg27e30522012-04-11 23:18:23 -04002098 shell->lock_surface_listener.notify = handle_lock_surface_destroy;
2099 wl_signal_add(&surface_resource->destroy_signal,
2100 &shell->lock_surface_listener);
Pekka Paalanen57da4a82011-11-23 16:42:16 +02002101
Kristian Høgsberg730c94d2012-06-26 21:44:35 -04002102 surface->configure = lock_surface_configure;
2103 surface->private = shell;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002104}
2105
2106static void
Tiago Vignattibe143262012-04-16 17:31:41 +03002107resume_desktop(struct desktop_shell *shell)
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002108{
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04002109 struct weston_surface *surface;
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04002110 struct workspace *ws = get_current_workspace(shell);
Pekka Paalanen77346a62011-11-30 16:26:35 +02002111
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04002112 wl_list_for_each(surface, &shell->screensaver.surfaces, link)
2113 weston_surface_unmap(surface);
Pekka Paalanen77346a62011-11-30 16:26:35 +02002114
2115 terminate_screensaver(shell);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002116
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002117 wl_list_remove(&shell->lock_layer.link);
2118 wl_list_insert(&shell->compositor->cursor_layer.link,
2119 &shell->fullscreen_layer.link);
2120 wl_list_insert(&shell->fullscreen_layer.link,
2121 &shell->panel_layer.link);
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02002122 if (shell->showing_input_panels) {
2123 wl_list_insert(&shell->panel_layer.link,
2124 &shell->input_panel_layer.link);
2125 wl_list_insert(&shell->input_panel_layer.link,
2126 &ws->layer.link);
2127 } else {
2128 wl_list_insert(&shell->panel_layer.link, &ws->layer.link);
2129 }
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002130
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -04002131 restore_focus_state(shell, get_current_workspace(shell));
Jonas Ådahl04769742012-06-13 00:01:24 +02002132
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002133 shell->locked = false;
Pekka Paalanen7296e792011-12-07 16:22:00 +02002134 shell->compositor->idle_time = shell->compositor->option_idle_time;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002135 weston_compositor_wake(shell->compositor);
Pekka Paalanenfc6d91a2012-02-10 15:33:10 +02002136 weston_compositor_damage_all(shell->compositor);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002137}
2138
2139static void
2140desktop_shell_unlock(struct wl_client *client,
2141 struct wl_resource *resource)
2142{
Tiago Vignattibe143262012-04-16 17:31:41 +03002143 struct desktop_shell *shell = resource->data;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002144
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002145 shell->prepare_event_sent = false;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002146
2147 if (shell->locked)
2148 resume_desktop(shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002149}
2150
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04002151static void
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03002152desktop_shell_set_grab_surface(struct wl_client *client,
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04002153 struct wl_resource *resource,
2154 struct wl_resource *surface_resource)
2155{
2156 struct desktop_shell *shell = resource->data;
2157
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03002158 shell->grab_surface = surface_resource->data;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04002159}
2160
Kristian Høgsberg75840622011-09-06 13:48:16 -04002161static const struct desktop_shell_interface desktop_shell_implementation = {
2162 desktop_shell_set_background,
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002163 desktop_shell_set_panel,
2164 desktop_shell_set_lock_surface,
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04002165 desktop_shell_unlock,
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03002166 desktop_shell_set_grab_surface
Kristian Høgsberg75840622011-09-06 13:48:16 -04002167};
2168
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02002169static enum shell_surface_type
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002170get_shell_surface_type(struct weston_surface *surface)
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02002171{
2172 struct shell_surface *shsurf;
2173
2174 shsurf = get_shell_surface(surface);
2175 if (!shsurf)
Pekka Paalanen98262232011-12-01 10:42:22 +02002176 return SHELL_SURFACE_NONE;
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02002177 return shsurf->type;
2178}
2179
Kristian Høgsberg75840622011-09-06 13:48:16 -04002180static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002181move_binding(struct wl_seat *seat, uint32_t time, uint32_t button, void *data)
Kristian Høgsberg07937562011-04-12 17:25:42 -04002182{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002183 struct weston_surface *surface =
Daniel Stone37816df2012-05-16 18:45:18 +01002184 (struct weston_surface *) seat->pointer->focus;
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04002185 struct shell_surface *shsurf;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -05002186
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01002187 if (surface == NULL)
2188 return;
Kristian Høgsberg07937562011-04-12 17:25:42 -04002189
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04002190 shsurf = get_shell_surface(surface);
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04002191 if (shsurf == NULL || shsurf->type == SHELL_SURFACE_FULLSCREEN)
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04002192 return;
2193
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04002194 surface_move(shsurf, (struct weston_seat *) seat);
Kristian Høgsberg07937562011-04-12 17:25:42 -04002195}
2196
2197static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002198resize_binding(struct wl_seat *seat, uint32_t time, uint32_t button, void *data)
Kristian Høgsberg07937562011-04-12 17:25:42 -04002199{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002200 struct weston_surface *surface =
Daniel Stone37816df2012-05-16 18:45:18 +01002201 (struct weston_surface *) seat->pointer->focus;
Kristian Høgsberg07937562011-04-12 17:25:42 -04002202 uint32_t edges = 0;
2203 int32_t x, y;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002204 struct shell_surface *shsurf;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -05002205
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01002206 if (surface == NULL)
2207 return;
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02002208
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002209 shsurf = get_shell_surface(surface);
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04002210 if (!shsurf || shsurf->type == SHELL_SURFACE_FULLSCREEN)
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02002211 return;
2212
Pekka Paalanen5c97ae72012-01-30 16:19:47 +02002213 weston_surface_from_global(surface,
Daniel Stone37816df2012-05-16 18:45:18 +01002214 wl_fixed_to_int(seat->pointer->grab_x),
2215 wl_fixed_to_int(seat->pointer->grab_y),
Daniel Stone103db7f2012-05-08 17:17:55 +01002216 &x, &y);
Kristian Høgsberg07937562011-04-12 17:25:42 -04002217
Pekka Paalanen60921e52012-01-25 15:55:43 +02002218 if (x < surface->geometry.width / 3)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002219 edges |= WL_SHELL_SURFACE_RESIZE_LEFT;
Pekka Paalanen60921e52012-01-25 15:55:43 +02002220 else if (x < 2 * surface->geometry.width / 3)
Kristian Høgsberg07937562011-04-12 17:25:42 -04002221 edges |= 0;
2222 else
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002223 edges |= WL_SHELL_SURFACE_RESIZE_RIGHT;
Kristian Høgsberg07937562011-04-12 17:25:42 -04002224
Pekka Paalanen60921e52012-01-25 15:55:43 +02002225 if (y < surface->geometry.height / 3)
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002226 edges |= WL_SHELL_SURFACE_RESIZE_TOP;
Pekka Paalanen60921e52012-01-25 15:55:43 +02002227 else if (y < 2 * surface->geometry.height / 3)
Kristian Høgsberg07937562011-04-12 17:25:42 -04002228 edges |= 0;
2229 else
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002230 edges |= WL_SHELL_SURFACE_RESIZE_BOTTOM;
Kristian Høgsberg07937562011-04-12 17:25:42 -04002231
Kristian Høgsbergc1693f22012-05-22 16:56:23 -04002232 surface_resize(shsurf, (struct weston_seat *) seat, edges);
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04002233}
2234
2235static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002236surface_opacity_binding(struct wl_seat *seat, uint32_t time, uint32_t axis,
Daniel Stone0c1e46e2012-05-30 16:31:59 +01002237 wl_fixed_t value, void *data)
Scott Moreaua3aa9c92012-03-22 11:01:03 -06002238{
Scott Moreau02709af2012-05-22 01:54:10 -06002239 float step = 0.05;
Scott Moreaua3aa9c92012-03-22 11:01:03 -06002240 struct shell_surface *shsurf;
2241 struct weston_surface *surface =
Daniel Stone37816df2012-05-16 18:45:18 +01002242 (struct weston_surface *) seat->pointer->focus;
Scott Moreaua3aa9c92012-03-22 11:01:03 -06002243
2244 if (surface == NULL)
2245 return;
2246
2247 shsurf = get_shell_surface(surface);
2248 if (!shsurf)
2249 return;
2250
Daniel Stone0c1e46e2012-05-30 16:31:59 +01002251 surface->alpha += wl_fixed_to_double(value) * step;
Scott Moreaua3aa9c92012-03-22 11:01:03 -06002252
Scott Moreau02709af2012-05-22 01:54:10 -06002253 if (surface->alpha > 1.0)
2254 surface->alpha = 1.0;
Scott Moreaua3aa9c92012-03-22 11:01:03 -06002255 if (surface->alpha < step)
2256 surface->alpha = step;
2257
2258 surface->geometry.dirty = 1;
2259 weston_surface_damage(surface);
2260}
2261
2262static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002263do_zoom(struct wl_seat *seat, uint32_t time, uint32_t key, uint32_t axis,
Daniel Stone0c1e46e2012-05-30 16:31:59 +01002264 wl_fixed_t value)
Scott Moreauccbf29d2012-02-22 14:21:41 -07002265{
Daniel Stone37816df2012-05-16 18:45:18 +01002266 struct weston_seat *ws = (struct weston_seat *) seat;
2267 struct weston_compositor *compositor = ws->compositor;
Scott Moreauccbf29d2012-02-22 14:21:41 -07002268 struct weston_output *output;
Scott Moreaue6603982012-06-11 13:07:51 -06002269 float increment;
Scott Moreauccbf29d2012-02-22 14:21:41 -07002270
2271 wl_list_for_each(output, &compositor->output_list, link) {
2272 if (pixman_region32_contains_point(&output->region,
Daniel Stone37816df2012-05-16 18:45:18 +01002273 wl_fixed_to_double(seat->pointer->x),
2274 wl_fixed_to_double(seat->pointer->y),
Daniel Stone103db7f2012-05-08 17:17:55 +01002275 NULL)) {
Daniel Stone325fc2d2012-05-30 16:31:58 +01002276 if (key == KEY_PAGEUP)
Kristian Høgsberg9b68af02012-05-22 12:55:18 -04002277 increment = output->zoom.increment;
Daniel Stone325fc2d2012-05-30 16:31:58 +01002278 else if (key == KEY_PAGEDOWN)
Kristian Høgsberg9b68af02012-05-22 12:55:18 -04002279 increment = -output->zoom.increment;
2280 else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
Daniel Stone0c1e46e2012-05-30 16:31:59 +01002281 increment = output->zoom.increment *
2282 wl_fixed_to_double(value);
Kristian Høgsberg9b68af02012-05-22 12:55:18 -04002283 else
2284 increment = 0;
2285
Kristian Høgsberg9b68af02012-05-22 12:55:18 -04002286 output->zoom.level += increment;
Scott Moreauc6d7f602012-02-23 22:28:37 -07002287
Scott Moreaue6603982012-06-11 13:07:51 -06002288 if (output->zoom.level < 0.0)
Scott Moreau850ca422012-05-21 15:21:25 -06002289 output->zoom.level = 0.0;
Scott Moreaue6603982012-06-11 13:07:51 -06002290 else if (output->zoom.level > output->zoom.max_level)
2291 output->zoom.level = output->zoom.max_level;
Kristian Høgsberg79af73e2012-08-03 15:45:23 -04002292 else {
Scott Moreaue6603982012-06-11 13:07:51 -06002293 output->zoom.active = 1;
Kristian Høgsberg79af73e2012-08-03 15:45:23 -04002294 output->disable_planes++;
2295 }
Scott Moreauccbf29d2012-02-22 14:21:41 -07002296
Scott Moreaue6603982012-06-11 13:07:51 -06002297 output->zoom.spring_z.target = output->zoom.level;
Scott Moreauccbf29d2012-02-22 14:21:41 -07002298
Scott Moreau8dacaab2012-06-17 18:10:58 -06002299 weston_output_update_zoom(output, output->zoom.type);
Scott Moreauccbf29d2012-02-22 14:21:41 -07002300 }
2301 }
2302}
2303
Scott Moreauccbf29d2012-02-22 14:21:41 -07002304static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002305zoom_axis_binding(struct wl_seat *seat, uint32_t time, uint32_t axis,
Daniel Stone0c1e46e2012-05-30 16:31:59 +01002306 wl_fixed_t value, void *data)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002307{
2308 do_zoom(seat, time, 0, axis, value);
2309}
2310
2311static void
2312zoom_key_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
2313 void *data)
2314{
2315 do_zoom(seat, time, key, 0, 0);
2316}
2317
2318static void
2319terminate_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
2320 void *data)
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05002321{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002322 struct weston_compositor *compositor = data;
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05002323
Daniel Stone325fc2d2012-05-30 16:31:58 +01002324 wl_display_terminate(compositor->wl_display);
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05002325}
2326
2327static void
Scott Moreau447013d2012-02-18 05:05:29 -07002328rotate_grab_motion(struct wl_pointer_grab *grab,
Daniel Stone103db7f2012-05-08 17:17:55 +01002329 uint32_t time, wl_fixed_t x, wl_fixed_t y)
Pekka Paalanen460099f2012-01-20 16:48:25 +02002330{
2331 struct rotate_grab *rotate =
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002332 container_of(grab, struct rotate_grab, base.grab);
Daniel Stone37816df2012-05-16 18:45:18 +01002333 struct wl_pointer *pointer = grab->pointer;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002334 struct shell_surface *shsurf = rotate->base.shsurf;
2335 struct weston_surface *surface;
2336 GLfloat cx, cy, dx, dy, cposx, cposy, dposx, dposy, r;
2337
2338 if (!shsurf)
2339 return;
2340
2341 surface = shsurf->surface;
2342
2343 cx = 0.5f * surface->geometry.width;
2344 cy = 0.5f * surface->geometry.height;
Pekka Paalanen460099f2012-01-20 16:48:25 +02002345
Daniel Stone37816df2012-05-16 18:45:18 +01002346 dx = wl_fixed_to_double(pointer->x) - rotate->center.x;
2347 dy = wl_fixed_to_double(pointer->y) - rotate->center.y;
Pekka Paalanen460099f2012-01-20 16:48:25 +02002348 r = sqrtf(dx * dx + dy * dy);
2349
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002350 wl_list_remove(&shsurf->rotation.transform.link);
2351 shsurf->surface->geometry.dirty = 1;
Pekka Paalanen460099f2012-01-20 16:48:25 +02002352
2353 if (r > 20.0f) {
Pekka Paalanen460099f2012-01-20 16:48:25 +02002354 struct weston_matrix *matrix =
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002355 &shsurf->rotation.transform.matrix;
Pekka Paalanen460099f2012-01-20 16:48:25 +02002356
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05002357 weston_matrix_init(&rotate->rotation);
2358 rotate->rotation.d[0] = dx / r;
2359 rotate->rotation.d[4] = -dy / r;
2360 rotate->rotation.d[1] = -rotate->rotation.d[4];
2361 rotate->rotation.d[5] = rotate->rotation.d[0];
Pekka Paalanen460099f2012-01-20 16:48:25 +02002362
2363 weston_matrix_init(matrix);
Pekka Paalanen7b3bd3d2012-01-30 14:16:34 +02002364 weston_matrix_translate(matrix, -cx, -cy, 0.0f);
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002365 weston_matrix_multiply(matrix, &shsurf->rotation.rotation);
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05002366 weston_matrix_multiply(matrix, &rotate->rotation);
Pekka Paalanen7b3bd3d2012-01-30 14:16:34 +02002367 weston_matrix_translate(matrix, cx, cy, 0.0f);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002368
Pekka Paalanenbc0b7e72012-01-24 09:53:37 +02002369 wl_list_insert(
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002370 &shsurf->surface->geometry.transformation_list,
2371 &shsurf->rotation.transform.link);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002372 } else {
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002373 wl_list_init(&shsurf->rotation.transform.link);
2374 weston_matrix_init(&shsurf->rotation.rotation);
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05002375 weston_matrix_init(&rotate->rotation);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002376 }
Pekka Paalanenb45ac5e2012-02-09 15:58:44 +02002377
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01002378 /* We need to adjust the position of the surface
2379 * in case it was resized in a rotated state before */
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002380 cposx = surface->geometry.x + cx;
2381 cposy = surface->geometry.y + cy;
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01002382 dposx = rotate->center.x - cposx;
2383 dposy = rotate->center.y - cposy;
2384 if (dposx != 0.0f || dposy != 0.0f) {
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002385 weston_surface_set_position(surface,
2386 surface->geometry.x + dposx,
2387 surface->geometry.y + dposy);
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01002388 }
2389
Pekka Paalanenb45ac5e2012-02-09 15:58:44 +02002390 /* Repaint implies weston_surface_update_transform(), which
2391 * lazily applies the damage due to rotation update.
2392 */
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002393 weston_compositor_schedule_repaint(shsurf->surface->compositor);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002394}
2395
2396static void
Scott Moreau447013d2012-02-18 05:05:29 -07002397rotate_grab_button(struct wl_pointer_grab *grab,
Daniel Stone4dbadb12012-05-30 16:31:51 +01002398 uint32_t time, uint32_t button, uint32_t state_w)
Pekka Paalanen460099f2012-01-20 16:48:25 +02002399{
2400 struct rotate_grab *rotate =
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002401 container_of(grab, struct rotate_grab, base.grab);
Daniel Stone37816df2012-05-16 18:45:18 +01002402 struct wl_pointer *pointer = grab->pointer;
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002403 struct shell_surface *shsurf = rotate->base.shsurf;
Daniel Stone4dbadb12012-05-30 16:31:51 +01002404 enum wl_pointer_button_state state = state_w;
Pekka Paalanen460099f2012-01-20 16:48:25 +02002405
Daniel Stone4dbadb12012-05-30 16:31:51 +01002406 if (pointer->button_count == 0 &&
2407 state == WL_POINTER_BUTTON_STATE_RELEASED) {
Ander Conselvan de Oliveirafe0444a2012-04-04 17:48:05 +03002408 if (shsurf)
2409 weston_matrix_multiply(&shsurf->rotation.rotation,
2410 &rotate->rotation);
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03002411 shell_grab_end(&rotate->base);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002412 free(rotate);
2413 }
2414}
2415
Scott Moreau447013d2012-02-18 05:05:29 -07002416static const struct wl_pointer_grab_interface rotate_grab_interface = {
Pekka Paalanen460099f2012-01-20 16:48:25 +02002417 noop_grab_focus,
2418 rotate_grab_motion,
2419 rotate_grab_button,
2420};
2421
2422static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002423rotate_binding(struct wl_seat *seat, uint32_t time, uint32_t button,
Daniel Stonee5a01202012-05-04 11:21:57 +01002424 void *data)
Pekka Paalanen460099f2012-01-20 16:48:25 +02002425{
2426 struct weston_surface *base_surface =
Daniel Stone37816df2012-05-16 18:45:18 +01002427 (struct weston_surface *) seat->pointer->focus;
Pekka Paalanen460099f2012-01-20 16:48:25 +02002428 struct shell_surface *surface;
2429 struct rotate_grab *rotate;
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01002430 GLfloat dx, dy;
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05002431 GLfloat r;
Pekka Paalanen460099f2012-01-20 16:48:25 +02002432
2433 if (base_surface == NULL)
2434 return;
2435
2436 surface = get_shell_surface(base_surface);
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04002437 if (!surface || surface->type == SHELL_SURFACE_FULLSCREEN)
Pekka Paalanen460099f2012-01-20 16:48:25 +02002438 return;
2439
Pekka Paalanen460099f2012-01-20 16:48:25 +02002440 rotate = malloc(sizeof *rotate);
2441 if (!rotate)
2442 return;
2443
Kristian Høgsbergb2af93e2012-06-07 20:10:23 -04002444 weston_surface_to_global_float(surface->surface,
2445 surface->surface->geometry.width / 2,
2446 surface->surface->geometry.height / 2,
2447 &rotate->center.x, &rotate->center.y);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002448
Daniel Stone37816df2012-05-16 18:45:18 +01002449 dx = wl_fixed_to_double(seat->pointer->x) - rotate->center.x;
2450 dy = wl_fixed_to_double(seat->pointer->y) - rotate->center.y;
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05002451 r = sqrtf(dx * dx + dy * dy);
2452 if (r > 20.0f) {
2453 struct weston_matrix inverse;
2454
2455 weston_matrix_init(&inverse);
2456 inverse.d[0] = dx / r;
2457 inverse.d[4] = dy / r;
2458 inverse.d[1] = -inverse.d[4];
2459 inverse.d[5] = inverse.d[0];
2460 weston_matrix_multiply(&surface->rotation.rotation, &inverse);
Rafal Mielniczuk2d7ab822012-03-22 22:22:04 +01002461
2462 weston_matrix_init(&rotate->rotation);
2463 rotate->rotation.d[0] = dx / r;
2464 rotate->rotation.d[4] = -dy / r;
2465 rotate->rotation.d[1] = -rotate->rotation.d[4];
2466 rotate->rotation.d[5] = rotate->rotation.d[0];
Kristian Høgsberg765e27b2012-01-27 13:36:13 -05002467 } else {
2468 weston_matrix_init(&surface->rotation.rotation);
2469 weston_matrix_init(&rotate->rotation);
2470 }
2471
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03002472 shell_grab_start(&rotate->base, &rotate_grab_interface, surface,
2473 seat->pointer, DESKTOP_SHELL_CURSOR_ARROW);
Pekka Paalanen460099f2012-01-20 16:48:25 +02002474}
2475
2476static void
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04002477lower_fullscreen_layer(struct desktop_shell *shell)
2478{
2479 struct workspace *ws;
2480 struct weston_surface *surface, *prev;
2481
2482 ws = get_current_workspace(shell);
2483 wl_list_for_each_reverse_safe(surface, prev,
2484 &shell->fullscreen_layer.surface_list,
2485 layer_link)
2486 weston_surface_restack(surface, &ws->layer.surface_list);
2487}
2488
2489static void
Tiago Vignattibe143262012-04-16 17:31:41 +03002490activate(struct desktop_shell *shell, struct weston_surface *es,
Daniel Stone37816df2012-05-16 18:45:18 +01002491 struct weston_seat *seat)
Kristian Høgsberg75840622011-09-06 13:48:16 -04002492{
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -04002493 struct workspace *ws = get_current_workspace(shell);
2494 struct focus_state *state;
Kristian Høgsberg75840622011-09-06 13:48:16 -04002495
Daniel Stone37816df2012-05-16 18:45:18 +01002496 weston_surface_activate(es, seat);
Kristian Høgsberg75840622011-09-06 13:48:16 -04002497
Kristian Høgsberg2f5faff2012-07-31 16:36:34 -04002498 wl_list_for_each(state, &ws->focus_list, link)
2499 if (state->seat == seat)
2500 break;
2501
2502 if (&state->link == &ws->focus_list) {
2503 state = focus_state_create(seat, ws);
2504 if (state == NULL)
2505 return;
2506 }
2507
2508 state->keyboard_focus = es;
2509 wl_list_remove(&state->surface_destroy_listener.link);
2510 wl_signal_add(&es->surface.resource.destroy_signal,
2511 &state->surface_destroy_listener);
2512
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02002513 switch (get_shell_surface_type(es)) {
Alex Wu4539b082012-03-01 12:57:46 +08002514 case SHELL_SURFACE_FULLSCREEN:
2515 /* should on top of panels */
Alex Wu21858432012-04-01 20:13:08 +08002516 shell_stack_fullscreen(get_shell_surface(es));
Alex Wubd3354b2012-04-17 17:20:49 +08002517 shell_configure_fullscreen(get_shell_surface(es));
Alex Wu4539b082012-03-01 12:57:46 +08002518 break;
Pekka Paalanen57da4a82011-11-23 16:42:16 +02002519 default:
Jonas Ådahle3cddce2012-06-13 00:01:22 +02002520 ws = get_current_workspace(shell);
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04002521 lower_fullscreen_layer(shell);
2522 weston_surface_restack(es, &ws->layer.surface_list);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002523 break;
Kristian Høgsberg75840622011-09-06 13:48:16 -04002524 }
2525}
2526
Alex Wu21858432012-04-01 20:13:08 +08002527/* no-op func for checking black surface */
2528static void
2529black_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
2530{
2531}
2532
2533static bool
2534is_black_surface (struct weston_surface *es, struct weston_surface **fs_surface)
2535{
2536 if (es->configure == black_surface_configure) {
2537 if (fs_surface)
2538 *fs_surface = (struct weston_surface *)es->private;
2539 return true;
2540 }
2541 return false;
2542}
2543
Kristian Høgsberg75840622011-09-06 13:48:16 -04002544static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002545click_to_activate_binding(struct wl_seat *seat, uint32_t time, uint32_t button,
Daniel Stone4dbadb12012-05-30 16:31:51 +01002546 void *data)
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05002547{
Daniel Stone37816df2012-05-16 18:45:18 +01002548 struct weston_seat *ws = (struct weston_seat *) seat;
Tiago Vignattibe143262012-04-16 17:31:41 +03002549 struct desktop_shell *shell = data;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002550 struct weston_surface *focus;
Alex Wu4539b082012-03-01 12:57:46 +08002551 struct weston_surface *upper;
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05002552
Daniel Stone37816df2012-05-16 18:45:18 +01002553 focus = (struct weston_surface *) seat->pointer->focus;
Alex Wu9c35e6b2012-03-05 14:13:13 +08002554 if (!focus)
2555 return;
2556
Alex Wu21858432012-04-01 20:13:08 +08002557 if (is_black_surface(focus, &upper))
Alex Wu4539b082012-03-01 12:57:46 +08002558 focus = upper;
Alex Wu4539b082012-03-01 12:57:46 +08002559
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04002560 if (get_shell_surface_type(focus) == SHELL_SURFACE_NONE)
2561 return;
Kristian Høgsberg85b2e4b2012-06-21 16:49:42 -04002562
Daniel Stone325fc2d2012-05-30 16:31:58 +01002563 if (seat->pointer->grab == &seat->pointer->default_grab)
Daniel Stone37816df2012-05-16 18:45:18 +01002564 activate(shell, focus, ws);
Kristian Høgsberge1a850e2011-12-19 15:18:05 -05002565}
2566
2567static void
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04002568lock(struct wl_listener *listener, void *data)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04002569{
Tiago Vignattibe143262012-04-16 17:31:41 +03002570 struct desktop_shell *shell =
2571 container_of(listener, struct desktop_shell, lock_listener);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002572 struct weston_output *output;
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04002573 struct workspace *ws = get_current_workspace(shell);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002574
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002575 if (shell->locked) {
2576 wl_list_for_each(output, &shell->compositor->output_list, link)
2577 /* TODO: find a way to jump to other DPMS levels */
2578 if (output->set_dpms)
2579 output->set_dpms(output, WESTON_DPMS_STANDBY);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002580 return;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002581 }
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002582
2583 shell->locked = true;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002584
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002585 /* Hide all surfaces by removing the fullscreen, panel and
2586 * toplevel layers. This way nothing else can show or receive
2587 * input events while we are locked. */
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002588
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002589 wl_list_remove(&shell->panel_layer.link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002590 wl_list_remove(&shell->fullscreen_layer.link);
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02002591 if (shell->showing_input_panels)
2592 wl_list_remove(&shell->input_panel_layer.link);
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04002593 wl_list_remove(&ws->layer.link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002594 wl_list_insert(&shell->compositor->cursor_layer.link,
2595 &shell->lock_layer.link);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002596
Pekka Paalanen77346a62011-11-30 16:26:35 +02002597 launch_screensaver(shell);
2598
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002599 /* TODO: disable bindings that should not work while locked. */
2600
2601 /* All this must be undone in resume_desktop(). */
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002602}
2603
2604static void
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04002605unlock(struct wl_listener *listener, void *data)
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002606{
Tiago Vignattibe143262012-04-16 17:31:41 +03002607 struct desktop_shell *shell =
2608 container_of(listener, struct desktop_shell, unlock_listener);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002609
Pekka Paalanend81c2162011-11-16 13:47:34 +02002610 if (!shell->locked || shell->lock_surface) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002611 weston_compositor_wake(shell->compositor);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002612 return;
2613 }
2614
2615 /* If desktop-shell client has gone away, unlock immediately. */
2616 if (!shell->child.desktop_shell) {
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002617 resume_desktop(shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002618 return;
2619 }
2620
2621 if (shell->prepare_event_sent)
2622 return;
2623
Kristian Høgsberg0b5cd0c2012-03-04 21:57:37 -05002624 desktop_shell_send_prepare_lock_surface(shell->child.desktop_shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002625 shell->prepare_event_sent = true;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04002626}
2627
2628static void
Jan Arne Petersen42feced2012-06-21 21:52:17 +02002629show_input_panels(struct wl_listener *listener, void *data)
2630{
2631 struct desktop_shell *shell =
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02002632 container_of(listener, struct desktop_shell,
2633 show_input_panel_listener);
Philipp Brüschweiler88013572012-08-06 13:44:42 +02002634 struct input_panel_surface *surface, *next;
2635 struct weston_surface *ws;
Jan Arne Petersen42feced2012-06-21 21:52:17 +02002636
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02002637 shell->showing_input_panels = true;
2638
2639 wl_list_insert(&shell->panel_layer.link,
2640 &shell->input_panel_layer.link);
2641
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04002642 wl_list_for_each_safe(surface, next,
Philipp Brüschweiler88013572012-08-06 13:44:42 +02002643 &shell->input_panel.surfaces, link) {
2644 ws = surface->surface;
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02002645 wl_list_insert(&shell->input_panel_layer.surface_list,
Philipp Brüschweiler88013572012-08-06 13:44:42 +02002646 &ws->layer_link);
2647 weston_surface_assign_output(ws);
2648 weston_surface_damage(ws);
2649 weston_slide_run(ws, ws->geometry.height, 0, NULL, NULL);
Jan Arne Petersen42feced2012-06-21 21:52:17 +02002650 }
2651}
2652
2653static void
2654hide_input_panels(struct wl_listener *listener, void *data)
2655{
2656 struct desktop_shell *shell =
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02002657 container_of(listener, struct desktop_shell,
2658 hide_input_panel_listener);
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04002659 struct weston_surface *surface, *next;
Jan Arne Petersen42feced2012-06-21 21:52:17 +02002660
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02002661 shell->showing_input_panels = false;
2662
2663 wl_list_remove(&shell->input_panel_layer.link);
2664
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04002665 wl_list_for_each_safe(surface, next,
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02002666 &shell->input_panel_layer.surface_list, layer_link)
2667 weston_surface_unmap(surface);
Jan Arne Petersen42feced2012-06-21 21:52:17 +02002668}
2669
2670static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002671center_on_output(struct weston_surface *surface, struct weston_output *output)
Pekka Paalanen77346a62011-11-30 16:26:35 +02002672{
Scott Moreau1bad5db2012-08-18 01:04:05 -06002673 GLfloat x = (output->width - surface->buffer->width) / 2;
2674 GLfloat y = (output->height - surface->buffer->height) / 2;
Pekka Paalanen77346a62011-11-30 16:26:35 +02002675
Kristian Høgsberg730c94d2012-06-26 21:44:35 -04002676 weston_surface_configure(surface, output->x + x, output->y + y,
2677 surface->buffer->width,
2678 surface->buffer->height);
Pekka Paalanen77346a62011-11-30 16:26:35 +02002679}
2680
2681static void
Rob Bradfordac63e5b2012-08-13 14:07:52 +01002682weston_surface_set_initial_position (struct weston_surface *surface,
2683 struct desktop_shell *shell)
2684{
2685 struct weston_compositor *compositor = shell->compositor;
2686 int ix = 0, iy = 0;
2687 int range_x, range_y;
2688 int dx, dy, x, y, panel_height;
2689 struct weston_output *output, *target_output = NULL;
2690 struct weston_seat *seat;
2691
2692 /* As a heuristic place the new window on the same output as the
2693 * pointer. Falling back to the output containing 0, 0.
2694 *
2695 * TODO: Do something clever for touch too?
2696 */
2697 wl_list_for_each(seat, &compositor->seat_list, link) {
2698 if (seat->has_pointer) {
2699 ix = wl_fixed_to_int(seat->pointer.x);
2700 iy = wl_fixed_to_int(seat->pointer.y);
2701 break;
2702 }
2703 }
2704
2705 wl_list_for_each(output, &compositor->output_list, link) {
2706 if (pixman_region32_contains_point(&output->region, ix, iy, NULL)) {
2707 target_output = output;
2708 break;
2709 }
2710 }
2711
2712 if (!target_output) {
2713 weston_surface_set_position(surface, 10 + random() % 400,
2714 10 + random() % 400);
2715 return;
2716 }
2717
2718 /* Valid range within output where the surface will still be onscreen.
2719 * If this is negative it means that the surface is bigger than
2720 * output.
2721 */
2722 panel_height = get_output_panel_height(shell, target_output);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002723 range_x = target_output->width - surface->geometry.width;
2724 range_y = (target_output->height - panel_height) -
Rob Bradfordac63e5b2012-08-13 14:07:52 +01002725 surface->geometry.height;
2726
Rob Bradford4cb88c72012-08-13 15:18:44 +01002727 if (range_x > 0)
Rob Bradfordac63e5b2012-08-13 14:07:52 +01002728 dx = random() % range_x;
Rob Bradfordac63e5b2012-08-13 14:07:52 +01002729 else
Rob Bradford4cb88c72012-08-13 15:18:44 +01002730 dx = 0;
2731
2732 if (range_y > 0)
Rob Bradfordac63e5b2012-08-13 14:07:52 +01002733 dy = panel_height + random() % range_y;
Rob Bradford4cb88c72012-08-13 15:18:44 +01002734 else
2735 dy = panel_height;
Rob Bradfordac63e5b2012-08-13 14:07:52 +01002736
2737 x = target_output->x + dx;
2738 y = target_output->y + dy;
2739
2740 weston_surface_set_position (surface, x, y);
2741}
2742
2743static void
Tiago Vignattibe143262012-04-16 17:31:41 +03002744map(struct desktop_shell *shell, struct weston_surface *surface,
Ander Conselvan de Oliveirae9e05152012-02-15 17:02:56 +02002745 int32_t width, int32_t height, int32_t sx, int32_t sy)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04002746{
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002747 struct weston_compositor *compositor = shell->compositor;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02002748 struct shell_surface *shsurf = get_shell_surface(surface);
2749 enum shell_surface_type surface_type = shsurf->type;
Kristian Høgsberg60c49542012-03-05 20:51:34 -05002750 struct weston_surface *parent;
Daniel Stoneb2104682012-05-30 16:31:56 +01002751 struct weston_seat *seat;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02002752 struct workspace *ws;
Juan Zhao96879df2012-02-07 08:45:41 +08002753 int panel_height = 0;
Pekka Paalanen57da4a82011-11-23 16:42:16 +02002754
Pekka Paalanen60921e52012-01-25 15:55:43 +02002755 surface->geometry.width = width;
2756 surface->geometry.height = height;
2757 surface->geometry.dirty = 1;
Pekka Paalanen77346a62011-11-30 16:26:35 +02002758
2759 /* initial positioning, see also configure() */
2760 switch (surface_type) {
2761 case SHELL_SURFACE_TOPLEVEL:
Rob Bradfordac63e5b2012-08-13 14:07:52 +01002762 weston_surface_set_initial_position(surface, shell);
Pekka Paalanen77346a62011-11-30 16:26:35 +02002763 break;
Alex Wu4539b082012-03-01 12:57:46 +08002764 case SHELL_SURFACE_FULLSCREEN:
Kristian Høgsberge4d3a2b2012-07-09 21:43:22 -04002765 center_on_output(surface, shsurf->fullscreen_output);
Alex Wu4539b082012-03-01 12:57:46 +08002766 shell_map_fullscreen(shsurf);
2767 break;
Juan Zhao96879df2012-02-07 08:45:41 +08002768 case SHELL_SURFACE_MAXIMIZED:
Alex Wu4539b082012-03-01 12:57:46 +08002769 /* use surface configure to set the geometry */
Juan Zhao96879df2012-02-07 08:45:41 +08002770 panel_height = get_output_panel_height(shell,surface->output);
Rob Bradford31b68622012-07-02 19:00:19 +01002771 weston_surface_set_position(surface, shsurf->output->x,
2772 shsurf->output->y + panel_height);
Juan Zhao96879df2012-02-07 08:45:41 +08002773 break;
Tiago Vignatti0f997012012-02-10 16:17:23 +02002774 case SHELL_SURFACE_POPUP:
Kristian Høgsberg3730f362012-04-13 12:40:07 -04002775 shell_map_popup(shsurf);
Ander Conselvan de Oliveirae9e05152012-02-15 17:02:56 +02002776 case SHELL_SURFACE_NONE:
2777 weston_surface_set_position(surface,
2778 surface->geometry.x + sx,
2779 surface->geometry.y + sy);
Tiago Vignatti0f997012012-02-10 16:17:23 +02002780 break;
Pekka Paalanen77346a62011-11-30 16:26:35 +02002781 default:
2782 ;
2783 }
Kristian Høgsberg75840622011-09-06 13:48:16 -04002784
Pekka Paalanend3dd6e12011-11-16 13:47:33 +02002785 /* surface stacking order, see also activate() */
Pekka Paalanen92a0dc42011-11-28 15:34:13 +02002786 switch (surface_type) {
Kristian Høgsberg60c49542012-03-05 20:51:34 -05002787 case SHELL_SURFACE_POPUP:
2788 case SHELL_SURFACE_TRANSIENT:
Kristian Høgsberg8150b192012-06-27 10:22:58 -04002789 parent = shsurf->parent;
Kristian Høgsberg60c49542012-03-05 20:51:34 -05002790 wl_list_insert(parent->layer_link.prev, &surface->layer_link);
2791 break;
Alex Wu4539b082012-03-01 12:57:46 +08002792 case SHELL_SURFACE_FULLSCREEN:
Ander Conselvan de Oliveiraa1ff53b2012-02-15 17:02:54 +02002793 case SHELL_SURFACE_NONE:
2794 break;
Pekka Paalanen57da4a82011-11-23 16:42:16 +02002795 default:
Jonas Ådahle3cddce2012-06-13 00:01:22 +02002796 ws = get_current_workspace(shell);
2797 wl_list_insert(&ws->layer.surface_list, &surface->layer_link);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05002798 break;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02002799 }
2800
Ander Conselvan de Oliveirade56c312012-03-05 15:39:23 +02002801 if (surface_type != SHELL_SURFACE_NONE) {
2802 weston_surface_assign_output(surface);
Ander Conselvan de Oliveirade56c312012-03-05 15:39:23 +02002803 if (surface_type == SHELL_SURFACE_MAXIMIZED)
2804 surface->output = shsurf->output;
2805 }
Kristian Høgsberg2f88a402011-12-04 15:32:59 -05002806
Juan Zhao7bb92f02011-12-15 11:31:51 -05002807 switch (surface_type) {
Juan Zhao7bb92f02011-12-15 11:31:51 -05002808 case SHELL_SURFACE_TRANSIENT:
Tiago Vignatti99aeb1e2012-05-23 22:06:26 +03002809 if (shsurf->transient.flags ==
2810 WL_SHELL_SURFACE_TRANSIENT_INACTIVE)
2811 break;
2812 case SHELL_SURFACE_TOPLEVEL:
Juan Zhao7bb92f02011-12-15 11:31:51 -05002813 case SHELL_SURFACE_FULLSCREEN:
Juan Zhao96879df2012-02-07 08:45:41 +08002814 case SHELL_SURFACE_MAXIMIZED:
Daniel Stoneb2104682012-05-30 16:31:56 +01002815 if (!shell->locked) {
2816 wl_list_for_each(seat, &compositor->seat_list, link)
2817 activate(shell, surface, seat);
2818 }
Juan Zhao7bb92f02011-12-15 11:31:51 -05002819 break;
2820 default:
2821 break;
2822 }
2823
Kristian Høgsberg2f88a402011-12-04 15:32:59 -05002824 if (surface_type == SHELL_SURFACE_TOPLEVEL)
Juan Zhaoe10d2792012-04-25 19:09:52 +08002825 {
2826 switch (shell->win_animation_type) {
2827 case ANIMATION_FADE:
2828 weston_fade_run(surface, NULL, NULL);
2829 break;
2830 case ANIMATION_ZOOM:
2831 weston_zoom_run(surface, 0.8, 1.0, NULL, NULL);
2832 break;
2833 default:
2834 break;
2835 }
2836 }
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05002837}
2838
2839static void
Tiago Vignattibe143262012-04-16 17:31:41 +03002840configure(struct desktop_shell *shell, struct weston_surface *surface,
Pekka Paalanenddae03c2012-02-06 14:54:20 +02002841 GLfloat x, GLfloat y, int32_t width, int32_t height)
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05002842{
Pekka Paalanen77346a62011-11-30 16:26:35 +02002843 enum shell_surface_type surface_type = SHELL_SURFACE_NONE;
2844 struct shell_surface *shsurf;
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05002845
Pekka Paalanen77346a62011-11-30 16:26:35 +02002846 shsurf = get_shell_surface(surface);
2847 if (shsurf)
2848 surface_type = shsurf->type;
2849
Kristian Høgsberg6a8b5532012-02-16 23:43:59 -05002850 surface->geometry.x = x;
2851 surface->geometry.y = y;
Pekka Paalanen60921e52012-01-25 15:55:43 +02002852 surface->geometry.width = width;
2853 surface->geometry.height = height;
2854 surface->geometry.dirty = 1;
Pekka Paalanen77346a62011-11-30 16:26:35 +02002855
2856 switch (surface_type) {
Alex Wu4539b082012-03-01 12:57:46 +08002857 case SHELL_SURFACE_FULLSCREEN:
Alex Wubd3354b2012-04-17 17:20:49 +08002858 shell_stack_fullscreen(shsurf);
Alex Wu4539b082012-03-01 12:57:46 +08002859 shell_configure_fullscreen(shsurf);
Alex Wu4539b082012-03-01 12:57:46 +08002860 break;
Juan Zhao96879df2012-02-07 08:45:41 +08002861 case SHELL_SURFACE_MAXIMIZED:
Alex Wu4539b082012-03-01 12:57:46 +08002862 /* setting x, y and using configure to change that geometry */
Kristian Høgsberg6a8b5532012-02-16 23:43:59 -05002863 surface->geometry.x = surface->output->x;
2864 surface->geometry.y = surface->output->y +
2865 get_output_panel_height(shell,surface->output);
Juan Zhao96879df2012-02-07 08:45:41 +08002866 break;
Alex Wu4539b082012-03-01 12:57:46 +08002867 case SHELL_SURFACE_TOPLEVEL:
2868 break;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -05002869 default:
2870 break;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -04002871 }
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -05002872
Alex Wu4539b082012-03-01 12:57:46 +08002873 /* XXX: would a fullscreen surface need the same handling? */
Kristian Høgsberg6a8b5532012-02-16 23:43:59 -05002874 if (surface->output) {
Pekka Paalanenf07cb5d2012-02-10 13:34:36 +02002875 weston_surface_assign_output(surface);
Pekka Paalanen77346a62011-11-30 16:26:35 +02002876
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04002877 if (surface_type == SHELL_SURFACE_MAXIMIZED)
Juan Zhao96879df2012-02-07 08:45:41 +08002878 surface->output = shsurf->output;
Pekka Paalanen77346a62011-11-30 16:26:35 +02002879 }
Kristian Høgsberg07937562011-04-12 17:25:42 -04002880}
2881
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03002882static void
2883shell_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
2884{
Ander Conselvan de Oliveira7fb9f952012-03-27 17:36:42 +03002885 struct shell_surface *shsurf = get_shell_surface(es);
Tiago Vignattibe143262012-04-16 17:31:41 +03002886 struct desktop_shell *shell = shsurf->shell;
Tiago Vignatti70e5c9c2012-05-07 15:23:07 +03002887 int type_changed = 0;
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03002888
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04002889 if (shsurf->next_type != SHELL_SURFACE_NONE &&
Kristian Høgsbergf7e23d52012-04-27 17:51:59 -04002890 shsurf->type != shsurf->next_type) {
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04002891 set_surface_type(shsurf);
Kristian Høgsbergf7e23d52012-04-27 17:51:59 -04002892 type_changed = 1;
2893 }
Kristian Høgsberg7f366e72012-04-27 17:20:01 -04002894
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03002895 if (!weston_surface_is_mapped(es)) {
2896 map(shell, es, es->buffer->width, es->buffer->height, sx, sy);
Kristian Høgsbergf7e23d52012-04-27 17:51:59 -04002897 } else if (type_changed || sx != 0 || sy != 0 ||
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03002898 es->geometry.width != es->buffer->width ||
2899 es->geometry.height != es->buffer->height) {
2900 GLfloat from_x, from_y;
2901 GLfloat to_x, to_y;
2902
2903 weston_surface_to_global_float(es, 0, 0, &from_x, &from_y);
2904 weston_surface_to_global_float(es, sx, sy, &to_x, &to_y);
2905 configure(shell, es,
2906 es->geometry.x + to_x - from_x,
2907 es->geometry.y + to_y - from_y,
2908 es->buffer->width, es->buffer->height);
Ander Conselvan de Oliveira093bfa32012-03-27 17:36:41 +03002909 }
2910}
2911
Tiago Vignattibe143262012-04-16 17:31:41 +03002912static int launch_desktop_shell_process(struct desktop_shell *shell);
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02002913
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04002914static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002915desktop_shell_sigchld(struct weston_process *process, int status)
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02002916{
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02002917 uint32_t time;
Tiago Vignattibe143262012-04-16 17:31:41 +03002918 struct desktop_shell *shell =
2919 container_of(process, struct desktop_shell, child.process);
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02002920
2921 shell->child.process.pid = 0;
2922 shell->child.client = NULL; /* already destroyed by wayland */
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02002923
2924 /* if desktop-shell dies more than 5 times in 30 seconds, give up */
2925 time = weston_compositor_get_time();
Kristian Høgsbergf03a6162012-01-17 11:07:42 -05002926 if (time - shell->child.deathstamp > 30000) {
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02002927 shell->child.deathstamp = time;
2928 shell->child.deathcount = 0;
2929 }
2930
2931 shell->child.deathcount++;
2932 if (shell->child.deathcount > 5) {
Martin Minarik6d118362012-06-07 18:01:59 +02002933 weston_log("weston-desktop-shell died, giving up.\n");
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02002934 return;
2935 }
2936
Martin Minarik6d118362012-06-07 18:01:59 +02002937 weston_log("weston-desktop-shell died, respawning...\n");
Pekka Paalanen4d733ee2012-01-17 14:36:27 +02002938 launch_desktop_shell_process(shell);
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02002939}
2940
2941static int
Tiago Vignattibe143262012-04-16 17:31:41 +03002942launch_desktop_shell_process(struct desktop_shell *shell)
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02002943{
Kristian Høgsberg9724b512012-01-03 14:35:49 -05002944 const char *shell_exe = LIBEXECDIR "/weston-desktop-shell";
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02002945
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002946 shell->child.client = weston_client_launch(shell->compositor,
Pekka Paalanen409ef0a2011-12-02 15:30:21 +02002947 &shell->child.process,
2948 shell_exe,
2949 desktop_shell_sigchld);
2950
2951 if (!shell->child.client)
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02002952 return -1;
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02002953 return 0;
2954}
2955
2956static void
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04002957bind_shell(struct wl_client *client, void *data, uint32_t version, uint32_t id)
2958{
Tiago Vignattibe143262012-04-16 17:31:41 +03002959 struct desktop_shell *shell = data;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04002960
2961 wl_client_add_object(client, &wl_shell_interface,
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002962 &shell_implementation, id, shell);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04002963}
2964
Kristian Høgsberg75840622011-09-06 13:48:16 -04002965static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002966unbind_desktop_shell(struct wl_resource *resource)
2967{
Tiago Vignattibe143262012-04-16 17:31:41 +03002968 struct desktop_shell *shell = resource->data;
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05002969
2970 if (shell->locked)
2971 resume_desktop(shell);
2972
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002973 shell->child.desktop_shell = NULL;
2974 shell->prepare_event_sent = false;
2975 free(resource);
2976}
2977
2978static void
Kristian Høgsberg75840622011-09-06 13:48:16 -04002979bind_desktop_shell(struct wl_client *client,
2980 void *data, uint32_t version, uint32_t id)
2981{
Tiago Vignattibe143262012-04-16 17:31:41 +03002982 struct desktop_shell *shell = data;
Pekka Paalanenbbe60522011-11-03 14:11:33 +02002983 struct wl_resource *resource;
Kristian Høgsberg75840622011-09-06 13:48:16 -04002984
Pekka Paalanenbbe60522011-11-03 14:11:33 +02002985 resource = wl_client_add_object(client, &desktop_shell_interface,
2986 &desktop_shell_implementation,
2987 id, shell);
2988
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002989 if (client == shell->child.client) {
2990 resource->destroy = unbind_desktop_shell;
2991 shell->child.desktop_shell = resource;
Pekka Paalanenbbe60522011-11-03 14:11:33 +02002992 return;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02002993 }
Pekka Paalanenbbe60522011-11-03 14:11:33 +02002994
2995 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
2996 "permission to bind desktop_shell denied");
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04002997 wl_resource_destroy(resource);
Kristian Høgsberg75840622011-09-06 13:48:16 -04002998}
2999
Pekka Paalanen6e168112011-11-24 11:34:05 +02003000static void
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04003001screensaver_configure(struct weston_surface *surface, int32_t sx, int32_t sy)
3002{
3003 struct desktop_shell *shell = surface->private;
3004
3005 if (!shell->locked)
3006 return;
3007
3008 center_on_output(surface, surface->output);
3009
3010 if (wl_list_empty(&surface->layer_link)) {
3011 wl_list_insert(shell->lock_layer.surface_list.prev,
3012 &surface->layer_link);
3013 weston_surface_assign_output(surface);
3014 shell->compositor->idle_time = shell->screensaver.duration;
3015 weston_compositor_wake(shell->compositor);
3016 shell->compositor->state = WESTON_COMPOSITOR_IDLE;
3017 }
3018}
3019
3020static void
Pekka Paalanen6e168112011-11-24 11:34:05 +02003021screensaver_set_surface(struct wl_client *client,
3022 struct wl_resource *resource,
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04003023 struct wl_resource *surface_resource,
Pekka Paalanen6e168112011-11-24 11:34:05 +02003024 struct wl_resource *output_resource)
3025{
Tiago Vignattibe143262012-04-16 17:31:41 +03003026 struct desktop_shell *shell = resource->data;
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04003027 struct weston_surface *surface = surface_resource->data;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05003028 struct weston_output *output = output_resource->data;
Pekka Paalanen6e168112011-11-24 11:34:05 +02003029
Kristian Høgsberg1a73a632012-06-26 22:15:53 -04003030 surface->configure = screensaver_configure;
3031 surface->private = shell;
Pekka Paalanen77346a62011-11-30 16:26:35 +02003032 surface->output = output;
Pekka Paalanen6e168112011-11-24 11:34:05 +02003033}
3034
3035static const struct screensaver_interface screensaver_implementation = {
3036 screensaver_set_surface
3037};
3038
3039static void
3040unbind_screensaver(struct wl_resource *resource)
3041{
Tiago Vignattibe143262012-04-16 17:31:41 +03003042 struct desktop_shell *shell = resource->data;
Pekka Paalanen6e168112011-11-24 11:34:05 +02003043
Pekka Paalanen77346a62011-11-30 16:26:35 +02003044 shell->screensaver.binding = NULL;
Pekka Paalanen6e168112011-11-24 11:34:05 +02003045 free(resource);
3046}
3047
3048static void
3049bind_screensaver(struct wl_client *client,
3050 void *data, uint32_t version, uint32_t id)
3051{
Tiago Vignattibe143262012-04-16 17:31:41 +03003052 struct desktop_shell *shell = data;
Pekka Paalanen6e168112011-11-24 11:34:05 +02003053 struct wl_resource *resource;
3054
3055 resource = wl_client_add_object(client, &screensaver_interface,
3056 &screensaver_implementation,
3057 id, shell);
3058
Pekka Paalanen77346a62011-11-30 16:26:35 +02003059 if (shell->screensaver.binding == NULL) {
Pekka Paalanen6e168112011-11-24 11:34:05 +02003060 resource->destroy = unbind_screensaver;
Pekka Paalanen77346a62011-11-30 16:26:35 +02003061 shell->screensaver.binding = resource;
Pekka Paalanen6e168112011-11-24 11:34:05 +02003062 return;
3063 }
3064
3065 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
3066 "interface object already bound");
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04003067 wl_resource_destroy(resource);
Pekka Paalanen6e168112011-11-24 11:34:05 +02003068}
3069
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003070static void
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04003071input_panel_configure(struct weston_surface *surface, int32_t sx, int32_t sy)
3072{
3073 struct weston_mode *mode = surface->output->current;
3074 GLfloat x = (mode->width - surface->buffer->width) / 2;
3075 GLfloat y = mode->height - surface->buffer->height;
3076
3077 /* Don't map the input panel here, wait for
3078 * show_input_panels signal. */
3079
3080 weston_surface_configure(surface,
3081 surface->output->x + x,
3082 surface->output->y + y,
3083 surface->buffer->width,
3084 surface->buffer->height);
3085}
3086
3087static void
Philipp Brüschweiler88013572012-08-06 13:44:42 +02003088destroy_input_panel_surface(struct wl_listener *listener,
3089 void *data)
3090{
3091 struct input_panel_surface *input_panel_surface =
3092 container_of(listener, struct input_panel_surface, listener);
3093
3094 wl_list_remove(&listener->link);
3095 wl_list_remove(&input_panel_surface->link);
3096
3097 free(input_panel_surface);
3098}
3099
3100static void
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003101input_panel_set_surface(struct wl_client *client,
3102 struct wl_resource *resource,
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04003103 struct wl_resource *surface_resource,
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003104 struct wl_resource *output_resource)
3105{
3106 struct desktop_shell *shell = resource->data;
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04003107 struct weston_surface *surface = surface_resource->data;
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003108 struct weston_output *output = output_resource->data;
Philipp Brüschweiler88013572012-08-06 13:44:42 +02003109 struct input_panel_surface *input_panel_surface;
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003110
Kristian Høgsberg0636ac32012-06-27 10:22:15 -04003111 surface->configure = input_panel_configure;
3112 surface->private = shell;
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003113 surface->output = output;
Philipp Brüschweiler88013572012-08-06 13:44:42 +02003114
3115 input_panel_surface = malloc(sizeof *input_panel_surface);
3116 if (!input_panel_surface) {
3117 wl_resource_post_no_memory(resource);
3118 return;
3119 }
3120
3121 input_panel_surface->surface = surface;
3122 input_panel_surface->listener.notify = destroy_input_panel_surface;
3123
3124 wl_signal_add(&surface_resource->destroy_signal,
3125 &input_panel_surface->listener);
3126
3127 wl_list_insert(&shell->input_panel.surfaces,
3128 &input_panel_surface->link);
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003129}
3130
3131static const struct input_panel_interface input_panel_implementation = {
3132 input_panel_set_surface
3133};
3134
3135static void
3136unbind_input_panel(struct wl_resource *resource)
3137{
3138 struct desktop_shell *shell = resource->data;
3139
3140 shell->input_panel.binding = NULL;
3141 free(resource);
3142}
3143
3144static void
3145bind_input_panel(struct wl_client *client,
3146 void *data, uint32_t version, uint32_t id)
3147{
3148 struct desktop_shell *shell = data;
3149 struct wl_resource *resource;
3150
3151 resource = wl_client_add_object(client, &input_panel_interface,
3152 &input_panel_implementation,
3153 id, shell);
3154
3155 if (shell->input_panel.binding == NULL) {
3156 resource->destroy = unbind_input_panel;
3157 shell->input_panel.binding = resource;
3158 return;
3159 }
3160
3161 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
3162 "interface object already bound");
3163 wl_resource_destroy(resource);
3164}
3165
Kristian Høgsberg07045392012-02-19 18:52:44 -05003166struct switcher {
Tiago Vignattibe143262012-04-16 17:31:41 +03003167 struct desktop_shell *shell;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003168 struct weston_surface *current;
3169 struct wl_listener listener;
3170 struct wl_keyboard_grab grab;
3171};
3172
3173static void
3174switcher_next(struct switcher *switcher)
3175{
Kristian Høgsberg07045392012-02-19 18:52:44 -05003176 struct weston_surface *surface;
3177 struct weston_surface *first = NULL, *prev = NULL, *next = NULL;
Kristian Høgsberg32e56862012-04-02 22:18:58 -04003178 struct shell_surface *shsurf;
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04003179 struct workspace *ws = get_current_workspace(switcher->shell);
Kristian Høgsberg07045392012-02-19 18:52:44 -05003180
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04003181 wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
Kristian Høgsberg07045392012-02-19 18:52:44 -05003182 switch (get_shell_surface_type(surface)) {
3183 case SHELL_SURFACE_TOPLEVEL:
3184 case SHELL_SURFACE_FULLSCREEN:
3185 case SHELL_SURFACE_MAXIMIZED:
3186 if (first == NULL)
3187 first = surface;
3188 if (prev == switcher->current)
3189 next = surface;
3190 prev = surface;
Scott Moreau02709af2012-05-22 01:54:10 -06003191 surface->alpha = 0.25;
Kristian Høgsbergcacb7cd2012-02-28 09:20:21 -05003192 surface->geometry.dirty = 1;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003193 weston_surface_damage(surface);
3194 break;
3195 default:
3196 break;
3197 }
Alex Wu1659daa2012-04-01 20:13:09 +08003198
3199 if (is_black_surface(surface, NULL)) {
Scott Moreau02709af2012-05-22 01:54:10 -06003200 surface->alpha = 0.25;
Alex Wu1659daa2012-04-01 20:13:09 +08003201 surface->geometry.dirty = 1;
3202 weston_surface_damage(surface);
3203 }
Kristian Høgsberg07045392012-02-19 18:52:44 -05003204 }
3205
3206 if (next == NULL)
3207 next = first;
3208
Alex Wu07b26062012-03-12 16:06:01 +08003209 if (next == NULL)
3210 return;
3211
Kristian Høgsberg07045392012-02-19 18:52:44 -05003212 wl_list_remove(&switcher->listener.link);
Kristian Høgsberg27e30522012-04-11 23:18:23 -04003213 wl_signal_add(&next->surface.resource.destroy_signal,
3214 &switcher->listener);
Kristian Høgsberg07045392012-02-19 18:52:44 -05003215
3216 switcher->current = next;
Kristian Høgsberga416fa12012-05-21 14:06:52 -04003217 next->alpha = 1.0;
Alex Wu1659daa2012-04-01 20:13:09 +08003218
Kristian Høgsberg32e56862012-04-02 22:18:58 -04003219 shsurf = get_shell_surface(switcher->current);
3220 if (shsurf && shsurf->type ==SHELL_SURFACE_FULLSCREEN)
Kristian Høgsberga416fa12012-05-21 14:06:52 -04003221 shsurf->fullscreen.black_surface->alpha = 1.0;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003222}
3223
3224static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04003225switcher_handle_surface_destroy(struct wl_listener *listener, void *data)
Kristian Høgsberg07045392012-02-19 18:52:44 -05003226{
3227 struct switcher *switcher =
3228 container_of(listener, struct switcher, listener);
3229
3230 switcher_next(switcher);
3231}
3232
3233static void
Daniel Stone351eb612012-05-31 15:27:47 -04003234switcher_destroy(struct switcher *switcher)
Kristian Høgsberg07045392012-02-19 18:52:44 -05003235{
Kristian Høgsberg07045392012-02-19 18:52:44 -05003236 struct weston_surface *surface;
Daniel Stone37816df2012-05-16 18:45:18 +01003237 struct wl_keyboard *keyboard = switcher->grab.keyboard;
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04003238 struct workspace *ws = get_current_workspace(switcher->shell);
Kristian Høgsberg07045392012-02-19 18:52:44 -05003239
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04003240 wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
Kristian Høgsberga416fa12012-05-21 14:06:52 -04003241 surface->alpha = 1.0;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003242 weston_surface_damage(surface);
3243 }
3244
Alex Wu07b26062012-03-12 16:06:01 +08003245 if (switcher->current)
Daniel Stone37816df2012-05-16 18:45:18 +01003246 activate(switcher->shell, switcher->current,
3247 (struct weston_seat *) keyboard->seat);
Kristian Høgsberg07045392012-02-19 18:52:44 -05003248 wl_list_remove(&switcher->listener.link);
Daniel Stone37816df2012-05-16 18:45:18 +01003249 wl_keyboard_end_grab(keyboard);
Kristian Høgsberg07045392012-02-19 18:52:44 -05003250 free(switcher);
3251}
3252
3253static void
3254switcher_key(struct wl_keyboard_grab *grab,
Daniel Stonec9785ea2012-05-30 16:31:52 +01003255 uint32_t time, uint32_t key, uint32_t state_w)
Kristian Høgsberg07045392012-02-19 18:52:44 -05003256{
3257 struct switcher *switcher = container_of(grab, struct switcher, grab);
Daniel Stonec9785ea2012-05-30 16:31:52 +01003258 enum wl_keyboard_key_state state = state_w;
Daniel Stone351eb612012-05-31 15:27:47 -04003259
Daniel Stonec9785ea2012-05-30 16:31:52 +01003260 if (key == KEY_TAB && state == WL_KEYBOARD_KEY_STATE_PRESSED)
Daniel Stone351eb612012-05-31 15:27:47 -04003261 switcher_next(switcher);
3262}
3263
3264static void
3265switcher_modifier(struct wl_keyboard_grab *grab, uint32_t serial,
3266 uint32_t mods_depressed, uint32_t mods_latched,
3267 uint32_t mods_locked, uint32_t group)
3268{
3269 struct switcher *switcher = container_of(grab, struct switcher, grab);
Daniel Stone37816df2012-05-16 18:45:18 +01003270 struct weston_seat *seat = (struct weston_seat *) grab->keyboard->seat;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003271
Daniel Stone351eb612012-05-31 15:27:47 -04003272 if ((seat->modifier_state & switcher->shell->binding_modifier) == 0)
3273 switcher_destroy(switcher);
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04003274}
Kristian Høgsberg07045392012-02-19 18:52:44 -05003275
3276static const struct wl_keyboard_grab_interface switcher_grab = {
Daniel Stone351eb612012-05-31 15:27:47 -04003277 switcher_key,
3278 switcher_modifier,
Kristian Høgsberg07045392012-02-19 18:52:44 -05003279};
3280
3281static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01003282switcher_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
3283 void *data)
Kristian Høgsberg07045392012-02-19 18:52:44 -05003284{
Tiago Vignattibe143262012-04-16 17:31:41 +03003285 struct desktop_shell *shell = data;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003286 struct switcher *switcher;
3287
3288 switcher = malloc(sizeof *switcher);
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04003289 switcher->shell = shell;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003290 switcher->current = NULL;
Kristian Høgsberg27e30522012-04-11 23:18:23 -04003291 switcher->listener.notify = switcher_handle_surface_destroy;
Kristian Høgsberg07045392012-02-19 18:52:44 -05003292 wl_list_init(&switcher->listener.link);
3293
Kristian Høgsbergb0d8e772012-06-18 16:34:58 -04003294 lower_fullscreen_layer(switcher->shell);
Kristian Høgsberg07045392012-02-19 18:52:44 -05003295 switcher->grab.interface = &switcher_grab;
Daniel Stone37816df2012-05-16 18:45:18 +01003296 wl_keyboard_start_grab(seat->keyboard, &switcher->grab);
3297 wl_keyboard_set_focus(seat->keyboard, NULL);
Kristian Høgsberg07045392012-02-19 18:52:44 -05003298 switcher_next(switcher);
3299}
3300
Pekka Paalanen3c647232011-12-22 13:43:43 +02003301static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01003302backlight_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
3303 void *data)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003304{
3305 struct weston_compositor *compositor = data;
3306 struct weston_output *output;
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03003307 long backlight_new = 0;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003308
3309 /* TODO: we're limiting to simple use cases, where we assume just
3310 * control on the primary display. We'd have to extend later if we
3311 * ever get support for setting backlights on random desktop LCD
3312 * panels though */
3313 output = get_default_output(compositor);
3314 if (!output)
3315 return;
3316
3317 if (!output->set_backlight)
3318 return;
3319
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03003320 if (key == KEY_F9 || key == KEY_BRIGHTNESSDOWN)
3321 backlight_new = output->backlight_current - 25;
3322 else if (key == KEY_F10 || key == KEY_BRIGHTNESSUP)
3323 backlight_new = output->backlight_current + 25;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003324
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03003325 if (backlight_new < 5)
3326 backlight_new = 5;
3327 if (backlight_new > 255)
3328 backlight_new = 255;
3329
3330 output->backlight_current = backlight_new;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003331 output->set_backlight(output, output->backlight_current);
3332}
3333
3334static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01003335debug_repaint_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
3336 void *data)
Kristian Høgsbergb41c0812012-03-04 14:53:40 -05003337{
Tiago Vignattibe143262012-04-16 17:31:41 +03003338 struct desktop_shell *shell = data;
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04003339 struct weston_compositor *compositor = shell->compositor;
Kristian Høgsbergb41c0812012-03-04 14:53:40 -05003340 struct weston_surface *surface;
Ander Conselvan de Oliveira383b6712012-08-09 16:44:59 +03003341 struct weston_plane plane;
Kristian Høgsbergb41c0812012-03-04 14:53:40 -05003342
3343 if (shell->debug_repaint_surface) {
3344 weston_surface_destroy(shell->debug_repaint_surface);
3345 shell->debug_repaint_surface = NULL;
3346 } else {
3347 surface = weston_surface_create(compositor);
3348 weston_surface_set_color(surface, 1.0, 0.0, 0.0, 0.2);
3349 weston_surface_configure(surface, 0, 0, 8192, 8192);
3350 wl_list_insert(&compositor->fade_layer.surface_list,
3351 &surface->layer_link);
3352 weston_surface_assign_output(surface);
3353 pixman_region32_init(&surface->input);
3354
3355 /* Here's the dirty little trick that makes the
Ander Conselvan de Oliveira383b6712012-08-09 16:44:59 +03003356 * repaint debugging work: we move the surface to a
3357 * different plane and force an update_transform to
3358 * update dependent state and clear the
3359 * geometry.dirty bit. This way the call to
3360 * damage_below() in update_transform() does not
3361 * add damage to the primary plane. */
Kristian Høgsbergb41c0812012-03-04 14:53:40 -05003362
Ander Conselvan de Oliveira383b6712012-08-09 16:44:59 +03003363 weston_plane_init(&plane, 0, 0);
3364 surface->plane = &plane;
Kristian Høgsbergb41c0812012-03-04 14:53:40 -05003365 weston_surface_update_transform(surface);
Kristian Høgsbergb41c0812012-03-04 14:53:40 -05003366 shell->debug_repaint_surface = surface;
Ander Conselvan de Oliveira383b6712012-08-09 16:44:59 +03003367 surface->plane = &compositor->primary_plane;
3368 weston_plane_release(&plane);
Kristian Høgsbergb41c0812012-03-04 14:53:40 -05003369 }
3370}
3371
Pekka Paalanen07c91f82012-08-30 16:47:21 -05003372
3373static void
3374fan_debug_repaint_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
3375 void *data)
3376{
3377 struct desktop_shell *shell = data;
3378 struct weston_compositor *compositor = shell->compositor;
3379 compositor->fan_debug = !compositor->fan_debug;
3380 weston_compositor_damage_all(compositor);
3381}
3382
Kristian Høgsbergb41c0812012-03-04 14:53:40 -05003383static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01003384force_kill_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
3385 void *data)
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04003386{
Philipp Brüschweiler6cef0092012-08-13 21:27:27 +02003387 struct wl_surface *focus_surface;
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04003388 struct wl_client *client;
3389 pid_t pid;
3390 uid_t uid;
3391 gid_t gid;
3392
Philipp Brüschweiler6cef0092012-08-13 21:27:27 +02003393 focus_surface = seat->keyboard->focus;
3394 if (!focus_surface)
3395 return;
3396
3397 client = focus_surface->resource.client;
Daniel Stone325fc2d2012-05-30 16:31:58 +01003398 wl_client_get_credentials(client, &pid, &uid, &gid);
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04003399
Daniel Stone325fc2d2012-05-30 16:31:58 +01003400 kill(pid, SIGKILL);
Kristian Høgsberg92a57db2012-05-26 13:41:06 -04003401}
3402
3403static void
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003404workspace_up_binding(struct wl_seat *seat, uint32_t time,
3405 uint32_t key, void *data)
3406{
3407 struct desktop_shell *shell = data;
3408 unsigned int new_index = shell->workspaces.current;
3409
Kristian Høgsbergce345b02012-06-25 21:35:29 -04003410 if (shell->locked)
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04003411 return;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003412 if (new_index != 0)
3413 new_index--;
3414
3415 change_workspace(shell, new_index);
3416}
3417
3418static void
3419workspace_down_binding(struct wl_seat *seat, uint32_t time,
3420 uint32_t key, void *data)
3421{
3422 struct desktop_shell *shell = data;
3423 unsigned int new_index = shell->workspaces.current;
3424
Kristian Høgsbergce345b02012-06-25 21:35:29 -04003425 if (shell->locked)
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04003426 return;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003427 if (new_index < shell->workspaces.num - 1)
3428 new_index++;
3429
3430 change_workspace(shell, new_index);
3431}
3432
3433static void
3434workspace_f_binding(struct wl_seat *seat, uint32_t time,
3435 uint32_t key, void *data)
3436{
3437 struct desktop_shell *shell = data;
3438 unsigned int new_index;
3439
Kristian Høgsbergce345b02012-06-25 21:35:29 -04003440 if (shell->locked)
Kristian Høgsberg4476aaf2012-06-25 14:03:13 -04003441 return;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003442 new_index = key - KEY_F1;
3443 if (new_index >= shell->workspaces.num)
3444 new_index = shell->workspaces.num - 1;
3445
3446 change_workspace(shell, new_index);
3447}
3448
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02003449static void
3450workspace_move_surface_up_binding(struct wl_seat *seat, uint32_t time,
3451 uint32_t key, void *data)
3452{
3453 struct desktop_shell *shell = data;
3454 unsigned int new_index = shell->workspaces.current;
3455
3456 if (shell->locked)
3457 return;
3458
3459 if (new_index != 0)
3460 new_index--;
3461
3462 take_surface_to_workspace_by_seat(shell, seat, new_index);
3463}
3464
3465static void
3466workspace_move_surface_down_binding(struct wl_seat *seat, uint32_t time,
3467 uint32_t key, void *data)
3468{
3469 struct desktop_shell *shell = data;
3470 unsigned int new_index = shell->workspaces.current;
3471
3472 if (shell->locked)
3473 return;
3474
3475 if (new_index < shell->workspaces.num - 1)
3476 new_index++;
3477
3478 take_surface_to_workspace_by_seat(shell, seat, new_index);
3479}
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003480
3481static void
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04003482shell_destroy(struct wl_listener *listener, void *data)
Pekka Paalanen3c647232011-12-22 13:43:43 +02003483{
Tiago Vignattibe143262012-04-16 17:31:41 +03003484 struct desktop_shell *shell =
3485 container_of(listener, struct desktop_shell, destroy_listener);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003486 struct workspace **ws;
Pekka Paalanen3c647232011-12-22 13:43:43 +02003487
Pekka Paalanen9cf5cc82012-01-02 16:00:24 +02003488 if (shell->child.client)
3489 wl_client_destroy(shell->child.client);
3490
Kristian Høgsberg88c16072012-05-16 08:04:19 -04003491 wl_list_remove(&shell->lock_listener.link);
3492 wl_list_remove(&shell->unlock_listener.link);
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003493 wl_list_remove(&shell->show_input_panel_listener.link);
3494 wl_list_remove(&shell->hide_input_panel_listener.link);
Kristian Høgsberg88c16072012-05-16 08:04:19 -04003495
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003496 wl_array_for_each(ws, &shell->workspaces.array)
3497 workspace_destroy(*ws);
3498 wl_array_release(&shell->workspaces.array);
3499
Pekka Paalanen3c647232011-12-22 13:43:43 +02003500 free(shell->screensaver.path);
3501 free(shell);
3502}
3503
Tiago Vignatti0b52d482012-04-20 18:54:25 +03003504static void
3505shell_add_bindings(struct weston_compositor *ec, struct desktop_shell *shell)
3506{
3507 uint32_t mod;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003508 int i, num_workspace_bindings;
Tiago Vignatti0b52d482012-04-20 18:54:25 +03003509
3510 /* fixed bindings */
Daniel Stone325fc2d2012-05-30 16:31:58 +01003511 weston_compositor_add_key_binding(ec, KEY_BACKSPACE,
3512 MODIFIER_CTRL | MODIFIER_ALT,
3513 terminate_binding, ec);
3514 weston_compositor_add_button_binding(ec, BTN_LEFT, 0,
3515 click_to_activate_binding,
3516 shell);
3517 weston_compositor_add_axis_binding(ec, WL_POINTER_AXIS_VERTICAL_SCROLL,
3518 MODIFIER_SUPER | MODIFIER_ALT,
3519 surface_opacity_binding, NULL);
3520 weston_compositor_add_axis_binding(ec, WL_POINTER_AXIS_VERTICAL_SCROLL,
3521 MODIFIER_SUPER, zoom_axis_binding,
3522 NULL);
Tiago Vignatti0b52d482012-04-20 18:54:25 +03003523
3524 /* configurable bindings */
3525 mod = shell->binding_modifier;
Daniel Stone325fc2d2012-05-30 16:31:58 +01003526 weston_compositor_add_key_binding(ec, KEY_PAGEUP, mod,
3527 zoom_key_binding, NULL);
3528 weston_compositor_add_key_binding(ec, KEY_PAGEDOWN, mod,
3529 zoom_key_binding, NULL);
3530 weston_compositor_add_button_binding(ec, BTN_LEFT, mod, move_binding,
3531 shell);
3532 weston_compositor_add_button_binding(ec, BTN_MIDDLE, mod,
3533 resize_binding, shell);
3534 weston_compositor_add_button_binding(ec, BTN_RIGHT, mod,
3535 rotate_binding, NULL);
3536 weston_compositor_add_key_binding(ec, KEY_TAB, mod, switcher_binding,
3537 shell);
3538 weston_compositor_add_key_binding(ec, KEY_F9, mod, backlight_binding,
3539 ec);
3540 weston_compositor_add_key_binding(ec, KEY_BRIGHTNESSDOWN, 0,
3541 backlight_binding, ec);
3542 weston_compositor_add_key_binding(ec, KEY_F10, mod, backlight_binding,
3543 ec);
3544 weston_compositor_add_key_binding(ec, KEY_BRIGHTNESSUP, 0,
3545 backlight_binding, ec);
Kristian Høgsberg73694c82012-06-28 14:13:10 -04003546 weston_compositor_add_key_binding(ec, KEY_SPACE, mod | MODIFIER_SHIFT,
Daniel Stone325fc2d2012-05-30 16:31:58 +01003547 debug_repaint_binding, shell);
Pekka Paalanen07c91f82012-08-30 16:47:21 -05003548 weston_compositor_add_key_binding(ec, KEY_SPACE, mod | MODIFIER_ALT,
3549 fan_debug_repaint_binding, shell);
Daniel Stone325fc2d2012-05-30 16:31:58 +01003550 weston_compositor_add_key_binding(ec, KEY_K, mod,
3551 force_kill_binding, shell);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003552 weston_compositor_add_key_binding(ec, KEY_UP, mod,
3553 workspace_up_binding, shell);
3554 weston_compositor_add_key_binding(ec, KEY_DOWN, mod,
3555 workspace_down_binding, shell);
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02003556 weston_compositor_add_key_binding(ec, KEY_UP, mod | MODIFIER_SHIFT,
3557 workspace_move_surface_up_binding,
3558 shell);
3559 weston_compositor_add_key_binding(ec, KEY_DOWN, mod | MODIFIER_SHIFT,
3560 workspace_move_surface_down_binding,
3561 shell);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003562
3563 /* Add bindings for mod+F[1-6] for workspace 1 to 6. */
3564 if (shell->workspaces.num > 1) {
3565 num_workspace_bindings = shell->workspaces.num;
3566 if (num_workspace_bindings > 6)
3567 num_workspace_bindings = 6;
3568 for (i = 0; i < num_workspace_bindings; i++)
3569 weston_compositor_add_key_binding(ec, KEY_F1 + i, mod,
3570 workspace_f_binding,
3571 shell);
3572 }
Tiago Vignatti0b52d482012-04-20 18:54:25 +03003573}
3574
Kristian Høgsberg6c709a32011-05-06 14:52:41 -04003575int
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05003576shell_init(struct weston_compositor *ec);
Kristian Høgsberg6c709a32011-05-06 14:52:41 -04003577
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003578WL_EXPORT int
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05003579shell_init(struct weston_compositor *ec)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05003580{
Kristian Høgsbergf4d2f232012-08-10 10:05:39 -04003581 struct weston_seat *seat;
Tiago Vignattibe143262012-04-16 17:31:41 +03003582 struct desktop_shell *shell;
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003583 struct workspace **pws;
3584 unsigned int i;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -04003585
3586 shell = malloc(sizeof *shell);
3587 if (shell == NULL)
3588 return -1;
3589
Kristian Høgsbergf0d91162011-10-11 22:44:23 -04003590 memset(shell, 0, sizeof *shell);
Kristian Høgsberg75840622011-09-06 13:48:16 -04003591 shell->compositor = ec;
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -04003592
3593 shell->destroy_listener.notify = shell_destroy;
3594 wl_signal_add(&ec->destroy_signal, &shell->destroy_listener);
3595 shell->lock_listener.notify = lock;
3596 wl_signal_add(&ec->lock_signal, &shell->lock_listener);
3597 shell->unlock_listener.notify = unlock;
3598 wl_signal_add(&ec->unlock_signal, &shell->unlock_listener);
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003599 shell->show_input_panel_listener.notify = show_input_panels;
3600 wl_signal_add(&ec->show_input_panel_signal, &shell->show_input_panel_listener);
3601 shell->hide_input_panel_listener.notify = hide_input_panels;
3602 wl_signal_add(&ec->hide_input_panel_signal, &shell->hide_input_panel_listener);
Scott Moreauff1db4a2012-04-17 19:06:18 -06003603 ec->ping_handler = ping_handler;
Kristian Høgsberg82a1d112012-07-19 14:02:00 -04003604 ec->shell_interface.shell = shell;
Tiago Vignattibc052c92012-04-19 16:18:18 +03003605 ec->shell_interface.create_shell_surface = create_shell_surface;
3606 ec->shell_interface.set_toplevel = set_toplevel;
Tiago Vignatti491bac12012-05-18 16:37:43 -04003607 ec->shell_interface.set_transient = set_transient;
Kristian Høgsberg938b8fa2012-05-18 13:46:27 -04003608 ec->shell_interface.move = surface_move;
Kristian Høgsbergc1693f22012-05-22 16:56:23 -04003609 ec->shell_interface.resize = surface_resize;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05003610
Pekka Paalanen77346a62011-11-30 16:26:35 +02003611 wl_list_init(&shell->screensaver.surfaces);
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003612 wl_list_init(&shell->input_panel.surfaces);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +02003613
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05003614 weston_layer_init(&shell->fullscreen_layer, &ec->cursor_layer.link);
3615 weston_layer_init(&shell->panel_layer, &shell->fullscreen_layer.link);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003616 weston_layer_init(&shell->background_layer, &shell->panel_layer.link);
3617 weston_layer_init(&shell->lock_layer, NULL);
Philipp Brüschweiler711fda82012-08-09 18:50:43 +02003618 weston_layer_init(&shell->input_panel_layer, NULL);
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003619
3620 wl_array_init(&shell->workspaces.array);
Kristian Høgsberg3be2ce92012-02-29 12:42:35 -05003621
Kristian Høgsberg6af8eb92012-01-25 16:57:11 -05003622 shell_configuration(shell);
Pekka Paalanene955f1e2011-12-07 11:49:52 +02003623
Jonas Ådahle3cddce2012-06-13 00:01:22 +02003624 for (i = 0; i < shell->workspaces.num; i++) {
3625 pws = wl_array_add(&shell->workspaces.array, sizeof *pws);
3626 if (pws == NULL)
3627 return -1;
3628
3629 *pws = workspace_create();
3630 if (*pws == NULL)
3631 return -1;
3632 }
3633 activate_workspace(shell, 0);
3634
Jonas Ådahl8de6a1d2012-08-29 22:13:00 +02003635 wl_list_init(&shell->workspaces.anim_sticky_list);
Jonas Ådahl62fcd042012-06-13 00:01:23 +02003636 wl_list_init(&shell->workspaces.animation.link);
3637 shell->workspaces.animation.frame = animate_workspace_change_frame;
3638
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -04003639 if (wl_display_add_global(ec->wl_display, &wl_shell_interface,
3640 shell, bind_shell) == NULL)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05003641 return -1;
3642
Kristian Høgsberg75840622011-09-06 13:48:16 -04003643 if (wl_display_add_global(ec->wl_display,
3644 &desktop_shell_interface,
3645 shell, bind_desktop_shell) == NULL)
3646 return -1;
3647
Pekka Paalanen6e168112011-11-24 11:34:05 +02003648 if (wl_display_add_global(ec->wl_display, &screensaver_interface,
3649 shell, bind_screensaver) == NULL)
3650 return -1;
3651
Jan Arne Petersen42feced2012-06-21 21:52:17 +02003652 if (wl_display_add_global(ec->wl_display, &input_panel_interface,
3653 shell, bind_input_panel) == NULL)
3654 return -1;
3655
Kristian Høgsbergf03a6162012-01-17 11:07:42 -05003656 shell->child.deathstamp = weston_compositor_get_time();
Pekka Paalanen6cd281a2011-11-03 14:11:32 +02003657 if (launch_desktop_shell_process(shell) != 0)
3658 return -1;
3659
Kristian Høgsbergf4d2f232012-08-10 10:05:39 -04003660 wl_list_for_each(seat, &ec->seat_list, link)
3661 create_pointer_focus_listener(seat);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04003662
Tiago Vignatti0b52d482012-04-20 18:54:25 +03003663 shell_add_bindings(ec, shell);
Kristian Høgsberg07937562011-04-12 17:25:42 -04003664
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05003665 return 0;
3666}