blob: 3502a95fc9653b38d0eebb343e4f392ca80712de [file] [log] [blame]
Kristian Høgsbergffd710e2008-12-02 15:15:01 -05001/*
2 * Copyright © 2008 Kristian Høgsberg
Pekka Paalanen4e373742013-02-13 16:17:13 +02003 * Copyright © 2012-2013 Collabora, Ltd.
Kristian Høgsbergffd710e2008-12-02 15:15:01 -05004 *
5 * Permission to use, copy, modify, distribute, and sell this software and its
6 * documentation for any purpose is hereby granted without fee, provided that
7 * the above copyright notice appear in all copies and that both that copyright
8 * notice and this permission notice appear in supporting documentation, and
9 * that the name of the copyright holders not be used in advertising or
10 * publicity pertaining to distribution of the software without specific,
11 * written prior permission. The copyright holders make no representations
12 * about the suitability of this software for any purpose. It is provided "as
13 * is" without express or implied warranty.
14 *
15 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
21 * OF THIS SOFTWARE.
22 */
23
Daniel Stonec228e232013-05-22 18:03:19 +030024#include "config.h"
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -040025
Kristian Høgsberg61017b12008-11-02 18:51:48 -050026#include <stdint.h>
27#include <stdio.h>
28#include <stdlib.h>
Pekka Paalanen71233882013-04-25 13:57:53 +030029#include <stdarg.h>
Kristian Høgsberg61017b12008-11-02 18:51:48 -050030#include <string.h>
Kristian Høgsberg61017b12008-11-02 18:51:48 -050031#include <fcntl.h>
32#include <unistd.h>
Kristian Høgsbergfa80e112012-10-10 21:34:26 -040033#include <errno.h>
Kristian Høgsberg61017b12008-11-02 18:51:48 -050034#include <math.h>
Benjamin Franzke0c991632011-09-27 21:57:31 +020035#include <assert.h>
Kristian Høgsberg61017b12008-11-02 18:51:48 -050036#include <time.h>
37#include <cairo.h>
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -040038#include <sys/mman.h>
Kristian Høgsberg3a696272011-09-14 17:33:48 -040039#include <sys/epoll.h>
Tiago Vignatti82db9d82012-05-23 22:06:27 +030040#include <sys/timerfd.h>
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -040041
Pekka Paalanenfb39d8d2012-10-16 17:27:19 +030042#ifdef HAVE_CAIRO_EGL
Kristian Høgsberg297d6dd2011-02-09 10:51:15 -050043#include <wayland-egl.h>
44
Rob Clark6396ed32012-03-11 19:48:41 -050045#ifdef USE_CAIRO_GLESV2
46#include <GLES2/gl2.h>
47#include <GLES2/gl2ext.h>
48#else
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -040049#include <GL/gl.h>
Rob Clark6396ed32012-03-11 19:48:41 -050050#endif
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -040051#include <EGL/egl.h>
52#include <EGL/eglext.h>
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -040053
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -040054#include <cairo-gl.h>
Pekka Paalanenfb39d8d2012-10-16 17:27:19 +030055#else /* HAVE_CAIRO_EGL */
56typedef void *EGLDisplay;
57typedef void *EGLConfig;
58typedef void *EGLContext;
59#define EGL_NO_DISPLAY ((EGLDisplay)0)
60#endif /* no HAVE_CAIRO_EGL */
Kristian Høgsberg61017b12008-11-02 18:51:48 -050061
Daniel Stone9d4f0302012-02-15 16:33:21 +000062#include <xkbcommon/xkbcommon.h>
Ander Conselvan de Oliveira1042dc12012-05-22 15:39:42 +030063#include <wayland-cursor.h>
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -040064
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -050065#include <linux/input.h>
Pekka Paalanen50719bc2011-11-22 14:18:50 +020066#include <wayland-client.h>
Kristian Høgsberg5a315bc2012-05-15 22:33:43 -040067#include "../shared/cairo-util.h"
Scott Moreau7a1b32a2012-05-27 14:25:02 -060068#include "text-cursor-position-client-protocol.h"
Jonas Ådahl14c92ff2012-08-29 22:13:02 +020069#include "workspaces-client-protocol.h"
Pekka Paalanen647f2bf2012-05-30 15:53:43 +030070#include "../shared/os-compatibility.h"
Kristian Høgsberg2f2cfae2008-11-08 22:46:30 -050071
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -050072#include "window.h"
Kristian Høgsberg8a9cda82008-11-03 15:31:30 -050073
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -070074struct shm_pool;
Ander Conselvan de Oliveira1493d2a2012-05-03 12:29:46 +030075
Kristian Høgsbergfa80e112012-10-10 21:34:26 -040076struct global {
77 uint32_t name;
78 char *interface;
79 uint32_t version;
80 struct wl_list link;
81};
82
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -050083struct display {
Kristian Høgsberg40979232008-11-25 22:40:39 -050084 struct wl_display *display;
Kristian Høgsbergfa80e112012-10-10 21:34:26 -040085 struct wl_registry *registry;
Kristian Høgsbergd2412e22008-12-15 20:35:24 -050086 struct wl_compositor *compositor;
Pekka Paalanen35e82632013-04-25 13:57:48 +030087 struct wl_subcompositor *subcompositor;
Kristian Høgsberg83fc0612010-08-04 22:44:55 -040088 struct wl_shell *shell;
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -040089 struct wl_shm *shm;
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -040090 struct wl_data_device_manager *data_device_manager;
Scott Moreau7a1b32a2012-05-27 14:25:02 -060091 struct text_cursor_position *text_cursor_position;
Jonas Ådahl14c92ff2012-08-29 22:13:02 +020092 struct workspace_manager *workspace_manager;
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -040093 EGLDisplay dpy;
Kristian Høgsberg8e81df42012-01-11 14:24:46 -050094 EGLConfig argb_config;
Benjamin Franzke0c991632011-09-27 21:57:31 +020095 EGLContext argb_ctx;
Benjamin Franzke0c991632011-09-27 21:57:31 +020096 cairo_device_t *argb_device;
Kristian Høgsbergeae5de72012-04-11 22:42:15 -040097 uint32_t serial;
Kristian Høgsberg3a696272011-09-14 17:33:48 -040098
99 int display_fd;
U. Artie Eoff44874d92012-10-02 21:12:35 -0700100 uint32_t display_fd_events;
Kristian Høgsberg3a696272011-09-14 17:33:48 -0400101 struct task display_task;
102
103 int epoll_fd;
104 struct wl_list deferred_list;
105
Pekka Paalanen826d7952011-12-15 10:14:07 +0200106 int running;
107
Kristian Høgsbergfa80e112012-10-10 21:34:26 -0400108 struct wl_list global_list;
Kristian Høgsberg478d9262010-06-08 20:34:11 -0400109 struct wl_list window_list;
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400110 struct wl_list input_list;
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -0500111 struct wl_list output_list;
Kristian Høgsberg291c69c2012-05-15 22:12:54 -0400112
Kristian Høgsberg5adb4802012-05-15 22:25:28 -0400113 struct theme *theme;
Kristian Høgsberg70163132012-05-08 15:55:39 -0400114
Ander Conselvan de Oliveira1042dc12012-05-22 15:39:42 +0300115 struct wl_cursor_theme *cursor_theme;
Ander Conselvan de Oliveirad8f527c2012-05-25 09:30:02 +0300116 struct wl_cursor **cursors;
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -0400117
Pekka Paalanen999c5b52011-11-30 10:52:38 +0200118 display_output_handler_t output_configure_handler;
Kristian Høgsbergfa80e112012-10-10 21:34:26 -0400119 display_global_handler_t global_handler;
Pekka Paalanen999c5b52011-11-30 10:52:38 +0200120
121 void *user_data;
Daniel Stone97f68542012-05-30 16:32:01 +0100122
123 struct xkb_context *xkb_context;
Jonas Ådahl14c92ff2012-08-29 22:13:02 +0200124
125 uint32_t workspace;
126 uint32_t workspace_count;
Pekka Paalanen3cbb0892012-11-19 17:16:01 +0200127
128 /* A hack to get text extents for tooltips */
129 cairo_surface_t *dummy_surface;
130 void *dummy_surface_data;
Tomeu Vizosobee45a12013-08-06 20:05:54 +0200131
132 int has_rgb565;
Rob Bradford08031182013-08-13 20:11:03 +0100133 int seat_version;
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -0500134};
135
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400136enum {
Kristian Høgsberg407ef642012-04-27 17:17:12 -0400137 TYPE_NONE,
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400138 TYPE_TOPLEVEL,
Kristian Høgsbergf8ab46e2011-09-08 16:56:38 -0400139 TYPE_FULLSCREEN,
Kristian Høgsbergd6bcd7d2012-02-16 15:53:46 -0500140 TYPE_MAXIMIZED,
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400141 TYPE_TRANSIENT,
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -0500142 TYPE_MENU,
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400143 TYPE_CUSTOM
144};
Rob Bradford7507b572012-05-15 17:55:34 +0100145
146struct window_output {
147 struct output *output;
148 struct wl_list link;
149};
150
Pekka Paalanen03fc3162012-11-19 17:15:58 +0200151struct toysurface {
152 /*
153 * Prepare the surface for drawing. Makes sure there is a surface
154 * of the right size available for rendering, and returns it.
155 * dx,dy are the x,y of wl_surface.attach.
Alexander Larsson5e9b6522013-05-22 14:41:28 +0200156 * width,height are the new buffer size.
Pekka Paalanenec076692012-11-30 13:37:27 +0200157 * If flags has SURFACE_HINT_RESIZE set, the user is
158 * doing continuous resizing.
Pekka Paalanen03fc3162012-11-19 17:15:58 +0200159 * Returns the Cairo surface to draw to.
160 */
161 cairo_surface_t *(*prepare)(struct toysurface *base, int dx, int dy,
Alexander Larsson1818e312013-05-22 14:41:31 +0200162 int32_t width, int32_t height, uint32_t flags,
Alexander Larssonedddbd12013-05-24 13:09:43 +0200163 enum wl_output_transform buffer_transform, int32_t buffer_scale);
Pekka Paalanen03fc3162012-11-19 17:15:58 +0200164
165 /*
166 * Post the surface to the server, returning the server allocation
167 * rectangle. The Cairo surface from prepare() must be destroyed
168 * after calling this.
169 */
170 void (*swap)(struct toysurface *base,
Alexander Larssonedddbd12013-05-24 13:09:43 +0200171 enum wl_output_transform buffer_transform, int32_t buffer_scale,
Pekka Paalanen03fc3162012-11-19 17:15:58 +0200172 struct rectangle *server_allocation);
173
174 /*
175 * Make the toysurface current with the given EGL context.
176 * Returns 0 on success, and negative of failure.
177 */
178 int (*acquire)(struct toysurface *base, EGLContext ctx);
179
180 /*
181 * Release the toysurface from the EGL context, returning control
182 * to Cairo.
183 */
184 void (*release)(struct toysurface *base);
185
186 /*
187 * Destroy the toysurface, including the Cairo surface, any
188 * backing storage, and the Wayland protocol objects.
189 */
190 void (*destroy)(struct toysurface *base);
191};
192
Pekka Paalanen4e373742013-02-13 16:17:13 +0200193struct surface {
194 struct window *window;
195
196 struct wl_surface *surface;
Pekka Paalanen35e82632013-04-25 13:57:48 +0300197 struct wl_subsurface *subsurface;
198 int synchronized;
199 int synchronized_default;
Pekka Paalanen811ec4f2013-02-13 16:17:14 +0200200 struct toysurface *toysurface;
Pekka Paalanenac95f3e2013-02-13 16:17:17 +0200201 struct widget *widget;
Pekka Paalanen40cb67b2013-04-25 13:57:49 +0300202 int redraw_needed;
203 struct wl_callback *frame_cb;
Pekka Paalanen7ff7a802013-04-25 13:57:50 +0300204 uint32_t last_time;
Pekka Paalanen811ec4f2013-02-13 16:17:14 +0200205
206 struct rectangle allocation;
207 struct rectangle server_allocation;
Pekka Paalanen02bba7c2013-02-13 16:17:15 +0200208
Pekka Paalanenb1cd9b12013-02-13 16:17:18 +0200209 struct wl_region *input_region;
210 struct wl_region *opaque_region;
211
Pekka Paalanen02bba7c2013-02-13 16:17:15 +0200212 enum window_buffer_type buffer_type;
213 enum wl_output_transform buffer_transform;
Alexander Larssonedddbd12013-05-24 13:09:43 +0200214 int32_t buffer_scale;
Pekka Paalanen89dee002013-02-13 16:17:20 +0200215
216 cairo_surface_t *cairo_surface;
Pekka Paalanen35e82632013-04-25 13:57:48 +0300217
218 struct wl_list link;
Pekka Paalanen4e373742013-02-13 16:17:13 +0200219};
220
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -0500221struct window {
222 struct display *display;
Kristian Høgsberg248c1b62011-01-21 18:03:15 -0500223 struct window *parent;
Rob Bradford7507b572012-05-15 17:55:34 +0100224 struct wl_list window_output_list;
Kristian Høgsbergd5fb9cc2011-01-25 12:45:37 -0500225 char *title;
Pekka Paalanen811ec4f2013-02-13 16:17:14 +0200226 struct rectangle saved_allocation;
Kristian Høgsbergd3a19652012-07-20 11:32:51 -0400227 struct rectangle min_allocation;
Kristian Høgsberg0d1c0622012-01-31 15:30:47 -0500228 struct rectangle pending_allocation;
Kristian Høgsberg248c1b62011-01-21 18:03:15 -0500229 int x, y;
Kristian Høgsberg83fc0612010-08-04 22:44:55 -0400230 int resize_edges;
Kristian Høgsberg6bd4d972012-03-24 14:42:09 -0400231 int redraw_needed;
Pekka Paalanen40cb67b2013-04-25 13:57:49 +0300232 int redraw_task_scheduled;
Kristian Høgsberg3a696272011-09-14 17:33:48 -0400233 struct task redraw_task;
Kristian Høgsberg42b4f802012-03-26 13:49:29 -0400234 int resize_needed;
Rafal Mielniczukc1a3cd12013-03-11 19:26:56 +0100235 int saved_type;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400236 int type;
Kristian Høgsberg86adef92012-08-13 22:25:53 -0400237 int focus_count;
238
Pekka Paalanen99436862012-11-19 17:15:59 +0200239 int resizing;
Ander Conselvan de Oliveira5403f522012-12-14 13:37:23 -0200240 int fullscreen_method;
MoD063a8822013-03-02 23:43:57 +0000241 int configure_requests;
Kristian Høgsberg1103a1a2012-04-03 12:00:48 -0400242
Tomeu Vizosobee45a12013-08-06 20:05:54 +0200243 enum preferred_format preferred_format;
244
Kristian Høgsberg6e83d582008-12-08 00:01:36 -0500245 window_key_handler_t key_handler;
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -0500246 window_keyboard_focus_handler_t keyboard_focus_handler;
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400247 window_data_handler_t data_handler;
248 window_drop_handler_t drop_handler;
Kristian Høgsberg4f7dcd62012-01-06 21:59:05 -0500249 window_close_handler_t close_handler;
Kristian Høgsberg67ace202012-07-23 21:56:31 -0400250 window_fullscreen_handler_t fullscreen_handler;
Ander Conselvan de Oliveira15256f62012-11-30 17:34:25 +0200251 window_output_handler_t output_handler;
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400252
Pekka Paalanen4e373742013-02-13 16:17:13 +0200253 struct surface *main_surface;
254 struct wl_shell_surface *shell_surface;
Pekka Vuorela6e1e3852012-09-17 22:15:57 +0300255
Jason Ekstrand3f66cf92013-10-13 19:08:40 -0500256 struct window_frame *frame;
Kristian Høgsberg4f7dcd62012-01-06 21:59:05 -0500257
Pekka Paalanen35e82632013-04-25 13:57:48 +0300258 /* struct surface::link, contains also main_surface */
259 struct wl_list subsurface_list;
260
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500261 void *user_data;
Kristian Høgsberg478d9262010-06-08 20:34:11 -0400262 struct wl_list link;
Kristian Høgsberg61017b12008-11-02 18:51:48 -0500263};
264
Kristian Høgsbergc51f7992012-01-08 15:09:53 -0500265struct widget {
Kristian Høgsberg9a13dab2012-01-08 15:18:19 -0500266 struct window *window;
Pekka Paalanen2d8a32a2013-02-13 16:17:19 +0200267 struct surface *surface;
Tiago Vignatti82db9d82012-05-23 22:06:27 +0300268 struct tooltip *tooltip;
Kristian Høgsberg441338c2012-01-10 13:52:34 -0500269 struct wl_list child_list;
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400270 struct wl_list link;
271 struct rectangle allocation;
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -0500272 widget_resize_handler_t resize_handler;
273 widget_redraw_handler_t redraw_handler;
Kristian Høgsbergee143232012-01-09 08:42:24 -0500274 widget_enter_handler_t enter_handler;
275 widget_leave_handler_t leave_handler;
Kristian Høgsberg04e98342012-01-09 09:36:16 -0500276 widget_motion_handler_t motion_handler;
Kristian Høgsberga8a0db32012-01-09 11:12:05 -0500277 widget_button_handler_t button_handler;
Rusty Lynch041815a2013-08-08 21:20:38 -0700278 widget_touch_down_handler_t touch_down_handler;
279 widget_touch_up_handler_t touch_up_handler;
280 widget_touch_motion_handler_t touch_motion_handler;
281 widget_touch_frame_handler_t touch_frame_handler;
282 widget_touch_cancel_handler_t touch_cancel_handler;
Philipp Brüschweiler7e0cc542012-08-14 11:02:41 +0200283 widget_axis_handler_t axis_handler;
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400284 void *user_data;
Kristian Høgsberg010f98b2012-02-23 17:30:45 -0500285 int opaque;
Tiago Vignatti82db9d82012-05-23 22:06:27 +0300286 int tooltip_count;
Kristian Høgsbergbf74d522012-11-30 14:54:35 -0500287 int default_cursor;
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400288};
289
Rusty Lynch041815a2013-08-08 21:20:38 -0700290struct touch_point {
291 int32_t id;
292 struct widget *widget;
293 struct wl_list link;
294};
295
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400296struct input {
297 struct display *display;
Daniel Stone37816df2012-05-16 18:45:18 +0100298 struct wl_seat *seat;
299 struct wl_pointer *pointer;
300 struct wl_keyboard *keyboard;
Rusty Lynch041815a2013-08-08 21:20:38 -0700301 struct wl_touch *touch;
302 struct wl_list touch_point_list;
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400303 struct window *pointer_focus;
304 struct window *keyboard_focus;
Rusty Lynch041815a2013-08-08 21:20:38 -0700305 struct window *touch_focus;
Ander Conselvan de Oliveira1493d2a2012-05-03 12:29:46 +0300306 int current_cursor;
Ander Conselvan de Oliveira80620072012-06-15 17:27:36 +0300307 uint32_t cursor_anim_start;
308 struct wl_callback *cursor_frame_cb;
Ander Conselvan de Oliveira37ffc3c2012-06-15 17:27:35 +0300309 struct wl_surface *pointer_surface;
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400310 uint32_t modifiers;
Kristian Høgsbergeae5de72012-04-11 22:42:15 -0400311 uint32_t pointer_enter_serial;
Kristian Høgsberg11f600d2012-06-22 10:52:58 -0400312 uint32_t cursor_serial;
Kristian Høgsberg80680c72012-05-10 12:21:37 -0400313 float sx, sy;
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400314 struct wl_list link;
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400315
Kristian Høgsbergb6323512012-01-11 00:04:42 -0500316 struct widget *focus_widget;
Kristian Høgsberg831dd522012-01-10 23:46:33 -0500317 struct widget *grab;
318 uint32_t grab_button;
319
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400320 struct wl_data_device *data_device;
321 struct data_offer *drag_offer;
322 struct data_offer *selection_offer;
Daniel Stone97f68542012-05-30 16:32:01 +0100323
324 struct {
Daniel Stone97f68542012-05-30 16:32:01 +0100325 struct xkb_keymap *keymap;
326 struct xkb_state *state;
327 xkb_mod_mask_t control_mask;
328 xkb_mod_mask_t alt_mask;
329 xkb_mod_mask_t shift_mask;
330 } xkb;
Kristian Høgsbergcf4d2442012-06-20 14:52:12 -0400331
332 struct task repeat_task;
333 int repeat_timer_fd;
334 uint32_t repeat_sym;
335 uint32_t repeat_key;
336 uint32_t repeat_time;
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400337};
338
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -0500339struct output {
340 struct display *display;
341 struct wl_output *output;
342 struct rectangle allocation;
343 struct wl_list link;
Scott Moreau4e072362012-09-29 02:03:11 -0600344 int transform;
Alexander Larssonafd319a2013-05-22 14:41:27 +0200345 int scale;
Pekka Paalanen999c5b52011-11-30 10:52:38 +0200346
347 display_output_handler_t destroy_handler;
348 void *user_data;
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -0500349};
350
Jason Ekstrand3f66cf92013-10-13 19:08:40 -0500351struct window_frame {
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -0500352 struct widget *widget;
353 struct widget *child;
Jason Ekstrand3f66cf92013-10-13 19:08:40 -0500354 struct frame *frame;
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -0500355};
356
Kristian Høgsberg4f7dcd62012-01-06 21:59:05 -0500357struct menu {
358 struct window *window;
Kristian Høgsberg75bc6672012-01-10 09:43:58 -0500359 struct widget *widget;
Kristian Høgsberg831dd522012-01-10 23:46:33 -0500360 struct input *input;
Kristian Høgsbergc680e902013-10-23 21:49:30 -0700361 struct frame *frame;
Kristian Høgsberg4f7dcd62012-01-06 21:59:05 -0500362 const char **entries;
363 uint32_t time;
364 int current;
365 int count;
Kristian Høgsbergd2fbb382012-10-30 13:45:22 -0400366 int release_count;
Kristian Høgsberg4f7dcd62012-01-06 21:59:05 -0500367 menu_func_t func;
368};
369
Tiago Vignatti82db9d82012-05-23 22:06:27 +0300370struct tooltip {
371 struct widget *parent;
372 struct window *window;
373 struct widget *widget;
374 char *entry;
375 struct task tooltip_task;
376 int tooltip_fd;
377 float x, y;
378};
379
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700380struct shm_pool {
381 struct wl_shm_pool *pool;
382 size_t size;
383 size_t used;
384 void *data;
385};
386
Kristian Høgsberg7d804062010-09-07 21:50:06 -0400387enum {
Ander Conselvan de Oliveiradc8c8fc2012-05-25 16:01:41 +0300388 CURSOR_DEFAULT = 100,
389 CURSOR_UNSET
Kristian Høgsberg7d804062010-09-07 21:50:06 -0400390};
391
Kristian Høgsberg82da52b2010-12-17 09:53:12 -0500392enum window_location {
393 WINDOW_INTERIOR = 0,
394 WINDOW_RESIZING_TOP = 1,
395 WINDOW_RESIZING_BOTTOM = 2,
396 WINDOW_RESIZING_LEFT = 4,
397 WINDOW_RESIZING_TOP_LEFT = 5,
398 WINDOW_RESIZING_BOTTOM_LEFT = 6,
399 WINDOW_RESIZING_RIGHT = 8,
400 WINDOW_RESIZING_TOP_RIGHT = 9,
401 WINDOW_RESIZING_BOTTOM_RIGHT = 10,
402 WINDOW_RESIZING_MASK = 15,
403 WINDOW_EXTERIOR = 16,
404 WINDOW_TITLEBAR = 17,
405 WINDOW_CLIENT_AREA = 18,
406};
407
Pekka Paalanen32127ca2012-11-19 15:32:51 +0200408static const cairo_user_data_key_t shm_surface_data_key;
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400409
Pekka Paalanen97777442013-05-22 10:20:05 +0300410/* #define DEBUG */
411
412#ifdef DEBUG
Pekka Paalanen71233882013-04-25 13:57:53 +0300413
414static void
415debug_print(void *proxy, int line, const char *func, const char *fmt, ...)
416__attribute__ ((format (printf, 4, 5)));
417
418static void
419debug_print(void *proxy, int line, const char *func, const char *fmt, ...)
420{
421 va_list ap;
422 struct timeval tv;
423
424 gettimeofday(&tv, NULL);
425 fprintf(stderr, "%8ld.%03ld ",
426 (long)tv.tv_sec & 0xffff, (long)tv.tv_usec / 1000);
427
428 if (proxy)
429 fprintf(stderr, "%s@%d ",
430 wl_proxy_get_class(proxy), wl_proxy_get_id(proxy));
431
432 /*fprintf(stderr, __FILE__ ":%d:%s ", line, func);*/
433 fprintf(stderr, "%s ", func);
434
435 va_start(ap, fmt);
436 vfprintf(stderr, fmt, ap);
437 va_end(ap);
438}
439
440#define DBG(fmt, ...) \
441 debug_print(NULL, __LINE__, __func__, fmt, ##__VA_ARGS__)
442
443#define DBG_OBJ(obj, fmt, ...) \
444 debug_print(obj, __LINE__, __func__, fmt, ##__VA_ARGS__)
445
446#else
447
448#define DBG(...) do {} while (0)
449#define DBG_OBJ(...) do {} while (0)
450
451#endif
452
Alexander Larsson1818e312013-05-22 14:41:31 +0200453static void
Alexander Larssonedddbd12013-05-24 13:09:43 +0200454surface_to_buffer_size (enum wl_output_transform buffer_transform, int32_t buffer_scale, int32_t *width, int32_t *height)
Alexander Larsson1818e312013-05-22 14:41:31 +0200455{
456 int32_t tmp;
457
458 switch (buffer_transform) {
459 case WL_OUTPUT_TRANSFORM_90:
460 case WL_OUTPUT_TRANSFORM_270:
461 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
462 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
463 tmp = *width;
464 *width = *height;
465 *height = tmp;
466 break;
467 default:
468 break;
469 }
470
471 *width *= buffer_scale;
472 *height *= buffer_scale;
473}
474
475static void
Alexander Larssonedddbd12013-05-24 13:09:43 +0200476buffer_to_surface_size (enum wl_output_transform buffer_transform, int32_t buffer_scale, int32_t *width, int32_t *height)
Alexander Larsson1818e312013-05-22 14:41:31 +0200477{
478 int32_t tmp;
479
480 switch (buffer_transform) {
481 case WL_OUTPUT_TRANSFORM_90:
482 case WL_OUTPUT_TRANSFORM_270:
483 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
484 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
485 tmp = *width;
486 *width = *height;
487 *height = tmp;
488 break;
489 default:
490 break;
491 }
492
493 *width /= buffer_scale;
494 *height /= buffer_scale;
495}
496
Kristian Høgsberg8def2642011-01-14 17:41:33 -0500497#ifdef HAVE_CAIRO_EGL
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400498
Pekka Paalanen03fc3162012-11-19 17:15:58 +0200499struct egl_window_surface {
500 struct toysurface base;
501 cairo_surface_t *cairo_surface;
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100502 struct display *display;
503 struct wl_surface *surface;
Pekka Paalanen03fc3162012-11-19 17:15:58 +0200504 struct wl_egl_window *egl_window;
505 EGLSurface egl_surface;
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100506};
507
Pekka Paalanen03fc3162012-11-19 17:15:58 +0200508static struct egl_window_surface *
509to_egl_window_surface(struct toysurface *base)
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100510{
Pekka Paalanen03fc3162012-11-19 17:15:58 +0200511 return container_of(base, struct egl_window_surface, base);
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100512}
513
514static cairo_surface_t *
Pekka Paalanen03fc3162012-11-19 17:15:58 +0200515egl_window_surface_prepare(struct toysurface *base, int dx, int dy,
Alexander Larsson1818e312013-05-22 14:41:31 +0200516 int32_t width, int32_t height, uint32_t flags,
Alexander Larssonedddbd12013-05-24 13:09:43 +0200517 enum wl_output_transform buffer_transform, int32_t buffer_scale)
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100518{
Pekka Paalanen03fc3162012-11-19 17:15:58 +0200519 struct egl_window_surface *surface = to_egl_window_surface(base);
520
Alexander Larsson1818e312013-05-22 14:41:31 +0200521 surface_to_buffer_size (buffer_transform, buffer_scale, &width, &height);
522
Pekka Paalanen03fc3162012-11-19 17:15:58 +0200523 wl_egl_window_resize(surface->egl_window, width, height, dx, dy);
524 cairo_gl_surface_set_size(surface->cairo_surface, width, height);
525
526 return cairo_surface_reference(surface->cairo_surface);
527}
528
529static void
530egl_window_surface_swap(struct toysurface *base,
Alexander Larssonedddbd12013-05-24 13:09:43 +0200531 enum wl_output_transform buffer_transform, int32_t buffer_scale,
Pekka Paalanen03fc3162012-11-19 17:15:58 +0200532 struct rectangle *server_allocation)
533{
534 struct egl_window_surface *surface = to_egl_window_surface(base);
535
536 cairo_gl_surface_swapbuffers(surface->cairo_surface);
537 wl_egl_window_get_attached_size(surface->egl_window,
538 &server_allocation->width,
539 &server_allocation->height);
Alexander Larsson1818e312013-05-22 14:41:31 +0200540
541 buffer_to_surface_size (buffer_transform, buffer_scale,
542 &server_allocation->width,
543 &server_allocation->height);
Pekka Paalanen03fc3162012-11-19 17:15:58 +0200544}
545
546static int
547egl_window_surface_acquire(struct toysurface *base, EGLContext ctx)
548{
549 struct egl_window_surface *surface = to_egl_window_surface(base);
Benjamin Franzke0c991632011-09-27 21:57:31 +0200550 cairo_device_t *device;
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100551
Pekka Paalanen03fc3162012-11-19 17:15:58 +0200552 device = cairo_surface_get_device(surface->cairo_surface);
553 if (!device)
554 return -1;
555
556 if (!ctx) {
557 if (device == surface->display->argb_device)
558 ctx = surface->display->argb_ctx;
559 else
560 assert(0);
561 }
562
563 cairo_device_flush(device);
564 cairo_device_acquire(device);
565 if (!eglMakeCurrent(surface->display->dpy, surface->egl_surface,
566 surface->egl_surface, ctx))
567 fprintf(stderr, "failed to make surface current\n");
568
569 return 0;
570}
571
572static void
573egl_window_surface_release(struct toysurface *base)
574{
575 struct egl_window_surface *surface = to_egl_window_surface(base);
576 cairo_device_t *device;
577
578 device = cairo_surface_get_device(surface->cairo_surface);
579 if (!device)
580 return;
581
582 if (!eglMakeCurrent(surface->display->dpy, NULL, NULL,
583 surface->display->argb_ctx))
584 fprintf(stderr, "failed to make context current\n");
585
586 cairo_device_release(device);
587}
588
589static void
590egl_window_surface_destroy(struct toysurface *base)
591{
592 struct egl_window_surface *surface = to_egl_window_surface(base);
593 struct display *d = surface->display;
594
595 cairo_surface_destroy(surface->cairo_surface);
596 eglDestroySurface(d->dpy, surface->egl_surface);
597 wl_egl_window_destroy(surface->egl_window);
598 surface->surface = NULL;
599
600 free(surface);
601}
602
603static struct toysurface *
604egl_window_surface_create(struct display *display,
605 struct wl_surface *wl_surface,
606 uint32_t flags,
607 struct rectangle *rectangle)
608{
609 struct egl_window_surface *surface;
610
Pekka Paalanenb3627362012-11-19 17:16:00 +0200611 if (display->dpy == EGL_NO_DISPLAY)
612 return NULL;
613
Pekka Paalanen03fc3162012-11-19 17:15:58 +0200614 surface = calloc(1, sizeof *surface);
615 if (!surface)
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100616 return NULL;
617
Pekka Paalanen03fc3162012-11-19 17:15:58 +0200618 surface->base.prepare = egl_window_surface_prepare;
619 surface->base.swap = egl_window_surface_swap;
620 surface->base.acquire = egl_window_surface_acquire;
621 surface->base.release = egl_window_surface_release;
622 surface->base.destroy = egl_window_surface_destroy;
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100623
Pekka Paalanen03fc3162012-11-19 17:15:58 +0200624 surface->display = display;
625 surface->surface = wl_surface;
Kristian Høgsbergf389cac2011-08-31 16:21:38 -0400626
Pekka Paalanen03fc3162012-11-19 17:15:58 +0200627 surface->egl_window = wl_egl_window_create(surface->surface,
628 rectangle->width,
629 rectangle->height);
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100630
Pekka Paalanen03fc3162012-11-19 17:15:58 +0200631 surface->egl_surface = eglCreateWindowSurface(display->dpy,
632 display->argb_config,
633 surface->egl_window,
634 NULL);
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100635
Pekka Paalanen03fc3162012-11-19 17:15:58 +0200636 surface->cairo_surface =
637 cairo_gl_surface_create_for_egl(display->argb_device,
638 surface->egl_surface,
639 rectangle->width,
640 rectangle->height);
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100641
Pekka Paalanen03fc3162012-11-19 17:15:58 +0200642 return &surface->base;
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100643}
644
Pekka Paalanenb3627362012-11-19 17:16:00 +0200645#else
646
647static struct toysurface *
648egl_window_surface_create(struct display *display,
649 struct wl_surface *wl_surface,
650 uint32_t flags,
651 struct rectangle *rectangle)
652{
653 return NULL;
654}
655
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400656#endif
657
Pekka Paalanen0c6a3432012-11-19 15:32:50 +0200658struct shm_surface_data {
659 struct wl_buffer *buffer;
660 struct shm_pool *pool;
661};
662
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400663struct wl_buffer *
664display_get_buffer_for_surface(struct display *display,
665 cairo_surface_t *surface)
666{
Pekka Paalanen0c6a3432012-11-19 15:32:50 +0200667 struct shm_surface_data *data;
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400668
Pekka Paalanen32127ca2012-11-19 15:32:51 +0200669 data = cairo_surface_get_user_data(surface, &shm_surface_data_key);
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400670
671 return data->buffer;
672}
673
Kristian Høgsberg06bc2642010-12-01 09:50:16 -0500674static void
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700675shm_pool_destroy(struct shm_pool *pool);
676
677static void
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400678shm_surface_data_destroy(void *p)
679{
680 struct shm_surface_data *data = p;
681
Pekka Paalanen0c6a3432012-11-19 15:32:50 +0200682 wl_buffer_destroy(data->buffer);
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700683 if (data->pool)
684 shm_pool_destroy(data->pool);
Ander Conselvan de Oliveira2a3cd282012-06-19 13:45:55 +0300685
686 free(data);
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400687}
688
Kristian Høgsberg16626282012-04-03 11:21:27 -0400689static struct wl_shm_pool *
690make_shm_pool(struct display *display, int size, void **data)
691{
Kristian Høgsberg16626282012-04-03 11:21:27 -0400692 struct wl_shm_pool *pool;
693 int fd;
694
Pekka Paalanen1da1b8f2012-06-06 16:59:43 +0300695 fd = os_create_anonymous_file(size);
Kristian Høgsberg16626282012-04-03 11:21:27 -0400696 if (fd < 0) {
Pekka Paalanen1da1b8f2012-06-06 16:59:43 +0300697 fprintf(stderr, "creating a buffer file for %d B failed: %m\n",
698 size);
Kristian Høgsberg16626282012-04-03 11:21:27 -0400699 return NULL;
700 }
701
702 *data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
Kristian Høgsberg16626282012-04-03 11:21:27 -0400703 if (*data == MAP_FAILED) {
704 fprintf(stderr, "mmap failed: %m\n");
705 close(fd);
706 return NULL;
707 }
708
709 pool = wl_shm_create_pool(display->shm, fd, size);
710
711 close(fd);
712
713 return pool;
714}
715
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700716static struct shm_pool *
717shm_pool_create(struct display *display, size_t size)
718{
719 struct shm_pool *pool = malloc(sizeof *pool);
720
721 if (!pool)
722 return NULL;
723
724 pool->pool = make_shm_pool(display, size, &pool->data);
725 if (!pool->pool) {
726 free(pool);
727 return NULL;
728 }
729
730 pool->size = size;
731 pool->used = 0;
732
733 return pool;
734}
735
736static void *
737shm_pool_allocate(struct shm_pool *pool, size_t size, int *offset)
738{
739 if (pool->used + size > pool->size)
740 return NULL;
741
742 *offset = pool->used;
743 pool->used += size;
744
745 return (char *) pool->data + *offset;
746}
747
748/* destroy the pool. this does not unmap the memory though */
749static void
750shm_pool_destroy(struct shm_pool *pool)
751{
752 munmap(pool->data, pool->size);
753 wl_shm_pool_destroy(pool->pool);
754 free(pool);
755}
756
757/* Start allocating from the beginning of the pool again */
758static void
759shm_pool_reset(struct shm_pool *pool)
760{
761 pool->used = 0;
762}
763
764static int
765data_length_for_shm_surface(struct rectangle *rect)
766{
767 int stride;
768
769 stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32,
770 rect->width);
771 return stride * rect->height;
772}
773
Kristian Høgsberg06bc2642010-12-01 09:50:16 -0500774static cairo_surface_t *
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700775display_create_shm_surface_from_pool(struct display *display,
776 struct rectangle *rectangle,
777 uint32_t flags, struct shm_pool *pool)
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400778{
779 struct shm_surface_data *data;
Kristian Høgsbergf389cac2011-08-31 16:21:38 -0400780 uint32_t format;
Kristian Høgsberg3be87d12011-05-13 13:45:17 -0400781 cairo_surface_t *surface;
Tomeu Vizosobee45a12013-08-06 20:05:54 +0200782 cairo_format_t cairo_format;
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700783 int stride, length, offset;
Kristian Høgsberg1103a1a2012-04-03 12:00:48 -0400784 void *map;
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400785
786 data = malloc(sizeof *data);
787 if (data == NULL)
788 return NULL;
789
Tomeu Vizosobee45a12013-08-06 20:05:54 +0200790 if (flags & SURFACE_HINT_RGB565 && display->has_rgb565)
791 cairo_format = CAIRO_FORMAT_RGB16_565;
792 else
793 cairo_format = CAIRO_FORMAT_ARGB32;
794
795 stride = cairo_format_stride_for_width (cairo_format, rectangle->width);
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700796 length = stride * rectangle->height;
797 data->pool = NULL;
798 map = shm_pool_allocate(pool, length, &offset);
799
800 if (!map) {
801 free(data);
802 return NULL;
Kristian Høgsberg1103a1a2012-04-03 12:00:48 -0400803 }
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400804
Kristian Høgsberg1103a1a2012-04-03 12:00:48 -0400805 surface = cairo_image_surface_create_for_data (map,
Tomeu Vizosobee45a12013-08-06 20:05:54 +0200806 cairo_format,
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400807 rectangle->width,
808 rectangle->height,
809 stride);
810
Pekka Paalanen32127ca2012-11-19 15:32:51 +0200811 cairo_surface_set_user_data(surface, &shm_surface_data_key,
812 data, shm_surface_data_destroy);
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400813
Tomeu Vizosobee45a12013-08-06 20:05:54 +0200814 if (flags & SURFACE_HINT_RGB565 && display->has_rgb565)
815 format = WL_SHM_FORMAT_RGB565;
816 else {
817 if (flags & SURFACE_OPAQUE)
818 format = WL_SHM_FORMAT_XRGB8888;
819 else
820 format = WL_SHM_FORMAT_ARGB8888;
821 }
Kristian Høgsberg3be87d12011-05-13 13:45:17 -0400822
Pekka Paalanen0c6a3432012-11-19 15:32:50 +0200823 data->buffer = wl_shm_pool_create_buffer(pool->pool, offset,
824 rectangle->width,
825 rectangle->height,
826 stride, format);
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400827
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700828 return surface;
829}
830
831static cairo_surface_t *
832display_create_shm_surface(struct display *display,
833 struct rectangle *rectangle, uint32_t flags,
Pekka Paalanen99436862012-11-19 17:15:59 +0200834 struct shm_pool *alternate_pool,
835 struct shm_surface_data **data_ret)
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700836{
837 struct shm_surface_data *data;
838 struct shm_pool *pool;
839 cairo_surface_t *surface;
840
Pekka Paalanen99436862012-11-19 17:15:59 +0200841 if (alternate_pool) {
842 shm_pool_reset(alternate_pool);
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700843 surface = display_create_shm_surface_from_pool(display,
844 rectangle,
845 flags,
Pekka Paalanen99436862012-11-19 17:15:59 +0200846 alternate_pool);
847 if (surface) {
848 data = cairo_surface_get_user_data(surface,
849 &shm_surface_data_key);
850 goto out;
851 }
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700852 }
853
854 pool = shm_pool_create(display,
855 data_length_for_shm_surface(rectangle));
856 if (!pool)
857 return NULL;
858
859 surface =
860 display_create_shm_surface_from_pool(display, rectangle,
861 flags, pool);
862
863 if (!surface) {
864 shm_pool_destroy(pool);
865 return NULL;
866 }
867
868 /* make sure we destroy the pool when the surface is destroyed */
Pekka Paalanen32127ca2012-11-19 15:32:51 +0200869 data = cairo_surface_get_user_data(surface, &shm_surface_data_key);
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700870 data->pool = pool;
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400871
Pekka Paalanen99436862012-11-19 17:15:59 +0200872out:
873 if (data_ret)
874 *data_ret = data;
875
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400876 return surface;
877}
878
nobled7b87cb02011-02-01 18:51:47 +0000879static int
880check_size(struct rectangle *rect)
881{
882 if (rect->width && rect->height)
883 return 0;
884
885 fprintf(stderr, "tried to create surface of "
886 "width: %d, height: %d\n", rect->width, rect->height);
887 return -1;
888}
889
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400890cairo_surface_t *
891display_create_surface(struct display *display,
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100892 struct wl_surface *surface,
Kristian Høgsberg3be87d12011-05-13 13:45:17 -0400893 struct rectangle *rectangle,
894 uint32_t flags)
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400895{
nobled7b87cb02011-02-01 18:51:47 +0000896 if (check_size(rectangle) < 0)
897 return NULL;
Pekka Paalanen768117f2012-11-19 17:15:57 +0200898
899 assert(flags & SURFACE_SHM);
Pekka Paalanen99436862012-11-19 17:15:59 +0200900 return display_create_shm_surface(display, rectangle, flags,
901 NULL, NULL);
902}
903
Pekka Paalanena4eda732012-11-19 17:16:02 +0200904struct shm_surface_leaf {
905 cairo_surface_t *cairo_surface;
906 /* 'data' is automatically destroyed, when 'cairo_surface' is */
907 struct shm_surface_data *data;
908
909 struct shm_pool *resize_pool;
910 int busy;
911};
912
913static void
914shm_surface_leaf_release(struct shm_surface_leaf *leaf)
915{
916 if (leaf->cairo_surface)
917 cairo_surface_destroy(leaf->cairo_surface);
918 /* leaf->data already destroyed via cairo private */
919
920 if (leaf->resize_pool)
921 shm_pool_destroy(leaf->resize_pool);
Pekka Paalanen550d66b2013-02-13 16:17:12 +0200922
923 memset(leaf, 0, sizeof *leaf);
Pekka Paalanena4eda732012-11-19 17:16:02 +0200924}
925
Pekka Paalanenaef02542013-04-25 13:57:47 +0300926#define MAX_LEAVES 3
927
Pekka Paalanen99436862012-11-19 17:15:59 +0200928struct shm_surface {
929 struct toysurface base;
930 struct display *display;
931 struct wl_surface *surface;
932 uint32_t flags;
933 int dx, dy;
934
Pekka Paalanenaef02542013-04-25 13:57:47 +0300935 struct shm_surface_leaf leaf[MAX_LEAVES];
Pekka Paalanena4eda732012-11-19 17:16:02 +0200936 struct shm_surface_leaf *current;
Pekka Paalanen99436862012-11-19 17:15:59 +0200937};
938
939static struct shm_surface *
940to_shm_surface(struct toysurface *base)
941{
942 return container_of(base, struct shm_surface, base);
943}
944
Pekka Paalanena4eda732012-11-19 17:16:02 +0200945static void
Pekka Paalanen97777442013-05-22 10:20:05 +0300946shm_surface_buffer_state_debug(struct shm_surface *surface, const char *msg)
947{
948#ifdef DEBUG
949 struct shm_surface_leaf *leaf;
950 char bufs[MAX_LEAVES + 1];
951 int i;
952
953 for (i = 0; i < MAX_LEAVES; i++) {
954 leaf = &surface->leaf[i];
955
956 if (leaf->busy)
957 bufs[i] = 'b';
958 else if (leaf->cairo_surface)
959 bufs[i] = 'a';
960 else
961 bufs[i] = ' ';
962 }
963
964 bufs[MAX_LEAVES] = '\0';
965 DBG_OBJ(surface->surface, "%s, leaves [%s]\n", msg, bufs);
966#endif
967}
968
969static void
Pekka Paalanena4eda732012-11-19 17:16:02 +0200970shm_surface_buffer_release(void *data, struct wl_buffer *buffer)
971{
Pekka Paalanen550d66b2013-02-13 16:17:12 +0200972 struct shm_surface *surface = data;
Pekka Paalanenaef02542013-04-25 13:57:47 +0300973 struct shm_surface_leaf *leaf;
974 int i;
975 int free_found;
Pekka Paalanen97777442013-05-22 10:20:05 +0300976
977 shm_surface_buffer_state_debug(surface, "buffer_release before");
Pekka Paalanena4eda732012-11-19 17:16:02 +0200978
Pekka Paalanenaef02542013-04-25 13:57:47 +0300979 for (i = 0; i < MAX_LEAVES; i++) {
980 leaf = &surface->leaf[i];
981 if (leaf->data && leaf->data->buffer == buffer) {
982 leaf->busy = 0;
983 break;
984 }
985 }
986 assert(i < MAX_LEAVES && "unknown buffer released");
Pekka Paalanen4dd0c412012-12-04 16:01:16 +0200987
Pekka Paalanenaef02542013-04-25 13:57:47 +0300988 /* Leave one free leaf with storage, release others */
989 free_found = 0;
990 for (i = 0; i < MAX_LEAVES; i++) {
991 leaf = &surface->leaf[i];
992
993 if (!leaf->cairo_surface || leaf->busy)
994 continue;
995
996 if (!free_found)
997 free_found = 1;
Pekka Paalanen97777442013-05-22 10:20:05 +0300998 else
Pekka Paalanenaef02542013-04-25 13:57:47 +0300999 shm_surface_leaf_release(leaf);
1000 }
Pekka Paalanen71233882013-04-25 13:57:53 +03001001
Pekka Paalanen97777442013-05-22 10:20:05 +03001002 shm_surface_buffer_state_debug(surface, "buffer_release after");
Pekka Paalanena4eda732012-11-19 17:16:02 +02001003}
1004
1005static const struct wl_buffer_listener shm_surface_buffer_listener = {
1006 shm_surface_buffer_release
1007};
1008
Pekka Paalanen99436862012-11-19 17:15:59 +02001009static cairo_surface_t *
1010shm_surface_prepare(struct toysurface *base, int dx, int dy,
Alexander Larsson1818e312013-05-22 14:41:31 +02001011 int32_t width, int32_t height, uint32_t flags,
Alexander Larssonedddbd12013-05-24 13:09:43 +02001012 enum wl_output_transform buffer_transform, int32_t buffer_scale)
Pekka Paalanen99436862012-11-19 17:15:59 +02001013{
Pekka Paalanenec076692012-11-30 13:37:27 +02001014 int resize_hint = !!(flags & SURFACE_HINT_RESIZE);
Pekka Paalanen99436862012-11-19 17:15:59 +02001015 struct shm_surface *surface = to_shm_surface(base);
Alexander Larsson1818e312013-05-22 14:41:31 +02001016 struct rectangle rect = { 0};
Pekka Paalanenaef02542013-04-25 13:57:47 +03001017 struct shm_surface_leaf *leaf = NULL;
1018 int i;
Pekka Paalanen99436862012-11-19 17:15:59 +02001019
1020 surface->dx = dx;
1021 surface->dy = dy;
1022
Pekka Paalanenaef02542013-04-25 13:57:47 +03001023 /* pick a free buffer, preferrably one that already has storage */
1024 for (i = 0; i < MAX_LEAVES; i++) {
1025 if (surface->leaf[i].busy)
1026 continue;
Pekka Paalanen4dd0c412012-12-04 16:01:16 +02001027
Pekka Paalanenaef02542013-04-25 13:57:47 +03001028 if (!leaf || surface->leaf[i].cairo_surface)
1029 leaf = &surface->leaf[i];
1030 }
Pekka Paalanen71233882013-04-25 13:57:53 +03001031 DBG_OBJ(surface->surface, "pick leaf %d\n",
1032 (int)(leaf - &surface->leaf[0]));
1033
Pekka Paalanenaef02542013-04-25 13:57:47 +03001034 if (!leaf) {
1035 fprintf(stderr, "%s: all buffers are held by the server.\n",
Pekka Paalanena4eda732012-11-19 17:16:02 +02001036 __func__);
Pekka Paalanen71233882013-04-25 13:57:53 +03001037 exit(1);
Pekka Paalanena4eda732012-11-19 17:16:02 +02001038 return NULL;
Pekka Paalanen99436862012-11-19 17:15:59 +02001039 }
1040
Pekka Paalanena4eda732012-11-19 17:16:02 +02001041 if (!resize_hint && leaf->resize_pool) {
1042 cairo_surface_destroy(leaf->cairo_surface);
1043 leaf->cairo_surface = NULL;
1044 shm_pool_destroy(leaf->resize_pool);
1045 leaf->resize_pool = NULL;
1046 }
1047
Alexander Larsson1818e312013-05-22 14:41:31 +02001048 surface_to_buffer_size (buffer_transform, buffer_scale, &width, &height);
1049
Pekka Paalanena4eda732012-11-19 17:16:02 +02001050 if (leaf->cairo_surface &&
1051 cairo_image_surface_get_width(leaf->cairo_surface) == width &&
1052 cairo_image_surface_get_height(leaf->cairo_surface) == height)
Pekka Paalanen99436862012-11-19 17:15:59 +02001053 goto out;
1054
Pekka Paalanena4eda732012-11-19 17:16:02 +02001055 if (leaf->cairo_surface)
1056 cairo_surface_destroy(leaf->cairo_surface);
Pekka Paalanen99436862012-11-19 17:15:59 +02001057
Louis-Francis Ratté-Boulianne6cd1de32013-05-22 18:03:11 +03001058#ifdef USE_RESIZE_POOL
Pekka Paalanena4eda732012-11-19 17:16:02 +02001059 if (resize_hint && !leaf->resize_pool) {
Pekka Paalanen99436862012-11-19 17:15:59 +02001060 /* Create a big pool to allocate from, while continuously
1061 * resizing. Mmapping a new pool in the server
1062 * is relatively expensive, so reusing a pool performs
1063 * better, but may temporarily reserve unneeded memory.
1064 */
1065 /* We should probably base this number on the output size. */
Pekka Paalanena4eda732012-11-19 17:16:02 +02001066 leaf->resize_pool = shm_pool_create(surface->display,
1067 6 * 1024 * 1024);
Pekka Paalanen99436862012-11-19 17:15:59 +02001068 }
Louis-Francis Ratté-Boulianne6cd1de32013-05-22 18:03:11 +03001069#endif
Pekka Paalanen99436862012-11-19 17:15:59 +02001070
Alexander Larsson1818e312013-05-22 14:41:31 +02001071 rect.width = width;
1072 rect.height = height;
1073
Pekka Paalanena4eda732012-11-19 17:16:02 +02001074 leaf->cairo_surface =
Pekka Paalanen99436862012-11-19 17:15:59 +02001075 display_create_shm_surface(surface->display, &rect,
1076 surface->flags,
Pekka Paalanena4eda732012-11-19 17:16:02 +02001077 leaf->resize_pool,
1078 &leaf->data);
1079 wl_buffer_add_listener(leaf->data->buffer,
Pekka Paalanen550d66b2013-02-13 16:17:12 +02001080 &shm_surface_buffer_listener, surface);
Pekka Paalanen99436862012-11-19 17:15:59 +02001081
1082out:
Pekka Paalanena4eda732012-11-19 17:16:02 +02001083 surface->current = leaf;
1084
1085 return cairo_surface_reference(leaf->cairo_surface);
Pekka Paalanen99436862012-11-19 17:15:59 +02001086}
1087
1088static void
1089shm_surface_swap(struct toysurface *base,
Alexander Larssonedddbd12013-05-24 13:09:43 +02001090 enum wl_output_transform buffer_transform, int32_t buffer_scale,
Pekka Paalanen99436862012-11-19 17:15:59 +02001091 struct rectangle *server_allocation)
1092{
1093 struct shm_surface *surface = to_shm_surface(base);
Pekka Paalanena4eda732012-11-19 17:16:02 +02001094 struct shm_surface_leaf *leaf = surface->current;
Pekka Paalanen99436862012-11-19 17:15:59 +02001095
1096 server_allocation->width =
Pekka Paalanena4eda732012-11-19 17:16:02 +02001097 cairo_image_surface_get_width(leaf->cairo_surface);
Pekka Paalanen99436862012-11-19 17:15:59 +02001098 server_allocation->height =
Pekka Paalanena4eda732012-11-19 17:16:02 +02001099 cairo_image_surface_get_height(leaf->cairo_surface);
Pekka Paalanen99436862012-11-19 17:15:59 +02001100
Alexander Larsson1818e312013-05-22 14:41:31 +02001101 buffer_to_surface_size (buffer_transform, buffer_scale,
1102 &server_allocation->width,
1103 &server_allocation->height);
1104
Pekka Paalanena4eda732012-11-19 17:16:02 +02001105 wl_surface_attach(surface->surface, leaf->data->buffer,
Pekka Paalanen99436862012-11-19 17:15:59 +02001106 surface->dx, surface->dy);
1107 wl_surface_damage(surface->surface, 0, 0,
1108 server_allocation->width, server_allocation->height);
1109 wl_surface_commit(surface->surface);
Pekka Paalanena4eda732012-11-19 17:16:02 +02001110
Pekka Paalanen71233882013-04-25 13:57:53 +03001111 DBG_OBJ(surface->surface, "leaf %d busy\n",
1112 (int)(leaf - &surface->leaf[0]));
1113
Pekka Paalanena4eda732012-11-19 17:16:02 +02001114 leaf->busy = 1;
1115 surface->current = NULL;
Pekka Paalanen99436862012-11-19 17:15:59 +02001116}
1117
1118static int
1119shm_surface_acquire(struct toysurface *base, EGLContext ctx)
1120{
1121 return -1;
1122}
1123
1124static void
1125shm_surface_release(struct toysurface *base)
1126{
1127}
1128
1129static void
1130shm_surface_destroy(struct toysurface *base)
1131{
1132 struct shm_surface *surface = to_shm_surface(base);
Pekka Paalanenaef02542013-04-25 13:57:47 +03001133 int i;
Pekka Paalanen99436862012-11-19 17:15:59 +02001134
Pekka Paalanenaef02542013-04-25 13:57:47 +03001135 for (i = 0; i < MAX_LEAVES; i++)
1136 shm_surface_leaf_release(&surface->leaf[i]);
Pekka Paalanen99436862012-11-19 17:15:59 +02001137
1138 free(surface);
1139}
1140
1141static struct toysurface *
1142shm_surface_create(struct display *display, struct wl_surface *wl_surface,
1143 uint32_t flags, struct rectangle *rectangle)
1144{
1145 struct shm_surface *surface;
Pekka Paalanen71233882013-04-25 13:57:53 +03001146 DBG_OBJ(wl_surface, "\n");
Pekka Paalanen99436862012-11-19 17:15:59 +02001147
Brian Lovinbc919262013-08-07 15:34:59 -07001148 surface = xmalloc(sizeof *surface);
1149 memset(surface, 0, sizeof *surface);
1150
Pekka Paalanen99436862012-11-19 17:15:59 +02001151 if (!surface)
1152 return NULL;
1153
1154 surface->base.prepare = shm_surface_prepare;
1155 surface->base.swap = shm_surface_swap;
1156 surface->base.acquire = shm_surface_acquire;
1157 surface->base.release = shm_surface_release;
1158 surface->base.destroy = shm_surface_destroy;
1159
1160 surface->display = display;
1161 surface->surface = wl_surface;
1162 surface->flags = flags;
Pekka Paalanen99436862012-11-19 17:15:59 +02001163
1164 return &surface->base;
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -04001165}
1166
Philipp Brüschweilerbd3f2192012-08-21 20:36:16 +02001167/*
1168 * The following correspondences between file names and cursors was copied
1169 * from: https://bugs.kde.org/attachment.cgi?id=67313
1170 */
1171
1172static const char *bottom_left_corners[] = {
Ander Conselvan de Oliveirad8f527c2012-05-25 09:30:02 +03001173 "bottom_left_corner",
Dima Ryazanovf6128fc2013-05-13 23:51:11 -07001174 "sw-resize",
1175 "size_bdiag"
Philipp Brüschweilerbd3f2192012-08-21 20:36:16 +02001176};
1177
1178static const char *bottom_right_corners[] = {
Ander Conselvan de Oliveirad8f527c2012-05-25 09:30:02 +03001179 "bottom_right_corner",
Dima Ryazanovf6128fc2013-05-13 23:51:11 -07001180 "se-resize",
1181 "size_fdiag"
Philipp Brüschweilerbd3f2192012-08-21 20:36:16 +02001182};
1183
1184static const char *bottom_sides[] = {
Ander Conselvan de Oliveirad8f527c2012-05-25 09:30:02 +03001185 "bottom_side",
Dima Ryazanovf6128fc2013-05-13 23:51:11 -07001186 "s-resize",
1187 "size_ver"
Philipp Brüschweilerbd3f2192012-08-21 20:36:16 +02001188};
1189
1190static const char *grabbings[] = {
Ander Conselvan de Oliveirad8f527c2012-05-25 09:30:02 +03001191 "grabbing",
Philipp Brüschweilerbd3f2192012-08-21 20:36:16 +02001192 "closedhand",
1193 "208530c400c041818281048008011002"
1194};
1195
1196static const char *left_ptrs[] = {
Ander Conselvan de Oliveirad8f527c2012-05-25 09:30:02 +03001197 "left_ptr",
Philipp Brüschweilerbd3f2192012-08-21 20:36:16 +02001198 "default",
1199 "top_left_arrow",
1200 "left-arrow"
1201};
1202
1203static const char *left_sides[] = {
Ander Conselvan de Oliveirad8f527c2012-05-25 09:30:02 +03001204 "left_side",
Dima Ryazanovf6128fc2013-05-13 23:51:11 -07001205 "w-resize",
1206 "size_hor"
Philipp Brüschweilerbd3f2192012-08-21 20:36:16 +02001207};
1208
1209static const char *right_sides[] = {
Ander Conselvan de Oliveirad8f527c2012-05-25 09:30:02 +03001210 "right_side",
Dima Ryazanovf6128fc2013-05-13 23:51:11 -07001211 "e-resize",
1212 "size_hor"
Philipp Brüschweilerbd3f2192012-08-21 20:36:16 +02001213};
1214
1215static const char *top_left_corners[] = {
Ander Conselvan de Oliveirad8f527c2012-05-25 09:30:02 +03001216 "top_left_corner",
Dima Ryazanovf6128fc2013-05-13 23:51:11 -07001217 "nw-resize",
1218 "size_fdiag"
Philipp Brüschweilerbd3f2192012-08-21 20:36:16 +02001219};
1220
1221static const char *top_right_corners[] = {
Ander Conselvan de Oliveirad8f527c2012-05-25 09:30:02 +03001222 "top_right_corner",
Dima Ryazanovf6128fc2013-05-13 23:51:11 -07001223 "ne-resize",
1224 "size_bdiag"
Philipp Brüschweilerbd3f2192012-08-21 20:36:16 +02001225};
1226
1227static const char *top_sides[] = {
Ander Conselvan de Oliveirad8f527c2012-05-25 09:30:02 +03001228 "top_side",
Dima Ryazanovf6128fc2013-05-13 23:51:11 -07001229 "n-resize",
1230 "size_ver"
Philipp Brüschweilerbd3f2192012-08-21 20:36:16 +02001231};
1232
1233static const char *xterms[] = {
Ander Conselvan de Oliveirad8f527c2012-05-25 09:30:02 +03001234 "xterm",
Philipp Brüschweilerbd3f2192012-08-21 20:36:16 +02001235 "ibeam",
1236 "text"
1237};
1238
1239static const char *hand1s[] = {
Ander Conselvan de Oliveirad8f527c2012-05-25 09:30:02 +03001240 "hand1",
Philipp Brüschweilerbd3f2192012-08-21 20:36:16 +02001241 "pointer",
1242 "pointing_hand",
1243 "e29285e634086352946a0e7090d73106"
1244};
1245
1246static const char *watches[] = {
Kristian Høgsberg8591dbf2012-06-04 16:10:40 -04001247 "watch",
Philipp Brüschweilerbd3f2192012-08-21 20:36:16 +02001248 "wait",
1249 "0426c94ea35c87780ff01dc239897213"
1250};
1251
1252struct cursor_alternatives {
1253 const char **names;
1254 size_t count;
1255};
1256
1257static const struct cursor_alternatives cursors[] = {
1258 {bottom_left_corners, ARRAY_LENGTH(bottom_left_corners)},
1259 {bottom_right_corners, ARRAY_LENGTH(bottom_right_corners)},
1260 {bottom_sides, ARRAY_LENGTH(bottom_sides)},
1261 {grabbings, ARRAY_LENGTH(grabbings)},
1262 {left_ptrs, ARRAY_LENGTH(left_ptrs)},
1263 {left_sides, ARRAY_LENGTH(left_sides)},
1264 {right_sides, ARRAY_LENGTH(right_sides)},
1265 {top_left_corners, ARRAY_LENGTH(top_left_corners)},
1266 {top_right_corners, ARRAY_LENGTH(top_right_corners)},
1267 {top_sides, ARRAY_LENGTH(top_sides)},
1268 {xterms, ARRAY_LENGTH(xterms)},
1269 {hand1s, ARRAY_LENGTH(hand1s)},
1270 {watches, ARRAY_LENGTH(watches)},
Ander Conselvan de Oliveirad8f527c2012-05-25 09:30:02 +03001271};
1272
1273static void
1274create_cursors(struct display *display)
1275{
Kristian Høgsberg8c079ae2013-09-21 22:26:10 -07001276 struct weston_config *config;
1277 struct weston_config_section *s;
Kristian Høgsberg1abe0482013-09-21 23:02:31 -07001278 int size;
Christopher Michaelac3e5f22012-08-11 15:12:09 +01001279 char *theme = NULL;
Philipp Brüschweilerbd3f2192012-08-21 20:36:16 +02001280 unsigned int i, j;
1281 struct wl_cursor *cursor;
Ander Conselvan de Oliveirad8f527c2012-05-25 09:30:02 +03001282
Kristian Høgsberg1abe0482013-09-21 23:02:31 -07001283 config = weston_config_parse("weston.ini");
Kristian Høgsberg8c079ae2013-09-21 22:26:10 -07001284 s = weston_config_get_section(config, "shell", NULL, NULL);
1285 weston_config_section_get_string(s, "cursor-theme", &theme, NULL);
1286 weston_config_section_get_int(s, "cursor-size", &size, 32);
1287 weston_config_destroy(config);
1288
Emilio Pozuelo Monfortab44b0c2013-03-14 17:23:37 +01001289 display->cursor_theme = wl_cursor_theme_load(theme, size, display->shm);
Kristian Høgsbergb5c973c2013-10-09 13:02:04 -07001290 free(theme);
Ander Conselvan de Oliveirad8f527c2012-05-25 09:30:02 +03001291 display->cursors =
Brian Lovinbc919262013-08-07 15:34:59 -07001292 xmalloc(ARRAY_LENGTH(cursors) * sizeof display->cursors[0]);
Ander Conselvan de Oliveirad8f527c2012-05-25 09:30:02 +03001293
Pekka Paalanene288a0f2012-07-31 13:21:09 +03001294 for (i = 0; i < ARRAY_LENGTH(cursors); i++) {
Philipp Brüschweilerbd3f2192012-08-21 20:36:16 +02001295 cursor = NULL;
1296 for (j = 0; !cursor && j < cursors[i].count; ++j)
1297 cursor = wl_cursor_theme_get_cursor(
1298 display->cursor_theme, cursors[i].names[j]);
1299
1300 if (!cursor)
Pekka Paalanene288a0f2012-07-31 13:21:09 +03001301 fprintf(stderr, "could not load cursor '%s'\n",
Philipp Brüschweilerbd3f2192012-08-21 20:36:16 +02001302 cursors[i].names[0]);
1303
1304 display->cursors[i] = cursor;
Pekka Paalanene288a0f2012-07-31 13:21:09 +03001305 }
Ander Conselvan de Oliveirad8f527c2012-05-25 09:30:02 +03001306}
1307
1308static void
1309destroy_cursors(struct display *display)
1310{
1311 wl_cursor_theme_destroy(display->cursor_theme);
Yan Wanga261f7e2012-05-28 14:07:25 +08001312 free(display->cursors);
Ander Conselvan de Oliveirad8f527c2012-05-25 09:30:02 +03001313}
1314
Ander Conselvan de Oliveira1042dc12012-05-22 15:39:42 +03001315struct wl_cursor_image *
1316display_get_pointer_image(struct display *display, int pointer)
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04001317{
Philipp Brüschweilerbd3f2192012-08-21 20:36:16 +02001318 struct wl_cursor *cursor = display->cursors[pointer];
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04001319
Ander Conselvan de Oliveira1042dc12012-05-22 15:39:42 +03001320 return cursor ? cursor->images[0] : NULL;
Kristian Høgsberg9a686242010-08-18 15:28:04 -04001321}
1322
Kristian Høgsberg9d69f8e2010-09-03 14:46:38 -04001323static void
Pekka Paalanen89dee002013-02-13 16:17:20 +02001324surface_flush(struct surface *surface)
Pekka Paalanen811ec4f2013-02-13 16:17:14 +02001325{
Pekka Paalanen89dee002013-02-13 16:17:20 +02001326 if (!surface->cairo_surface)
1327 return;
1328
Pekka Paalanenb1cd9b12013-02-13 16:17:18 +02001329 if (surface->opaque_region) {
1330 wl_surface_set_opaque_region(surface->surface,
1331 surface->opaque_region);
1332 wl_region_destroy(surface->opaque_region);
1333 surface->opaque_region = NULL;
1334 }
1335
1336 if (surface->input_region) {
1337 wl_surface_set_input_region(surface->surface,
1338 surface->input_region);
1339 wl_region_destroy(surface->input_region);
1340 surface->input_region = NULL;
1341 }
1342
Pekka Paalanen811ec4f2013-02-13 16:17:14 +02001343 surface->toysurface->swap(surface->toysurface,
Alexander Larsson1818e312013-05-22 14:41:31 +02001344 surface->buffer_transform, surface->buffer_scale,
Pekka Paalanen811ec4f2013-02-13 16:17:14 +02001345 &surface->server_allocation);
Pekka Paalanen811ec4f2013-02-13 16:17:14 +02001346
Pekka Paalanen89dee002013-02-13 16:17:20 +02001347 cairo_surface_destroy(surface->cairo_surface);
1348 surface->cairo_surface = NULL;
Kristian Høgsberg6a1b2012009-12-16 14:43:37 -05001349}
1350
Kristian Høgsberg86adef92012-08-13 22:25:53 -04001351int
1352window_has_focus(struct window *window)
1353{
1354 return window->focus_count > 0;
1355}
1356
Pekka Paalanena8d4c842012-11-19 15:32:48 +02001357static void
Kristian Høgsberg9d69f8e2010-09-03 14:46:38 -04001358window_flush(struct window *window)
Kristian Høgsberga341fa02010-01-24 18:10:15 -05001359{
Pekka Paalanen35e82632013-04-25 13:57:48 +03001360 struct surface *surface;
1361
Pekka Paalanen89dee002013-02-13 16:17:20 +02001362 if (window->type == TYPE_NONE) {
1363 window->type = TYPE_TOPLEVEL;
1364 if (window->shell_surface)
1365 wl_shell_surface_set_toplevel(window->shell_surface);
1366 }
Pekka Paalanen03fc3162012-11-19 17:15:58 +02001367
Pekka Paalanen35e82632013-04-25 13:57:48 +03001368 wl_list_for_each(surface, &window->subsurface_list, link) {
1369 if (surface == window->main_surface)
1370 continue;
1371
1372 surface_flush(surface);
1373 }
1374
Pekka Paalanen89dee002013-02-13 16:17:20 +02001375 surface_flush(window->main_surface);
Kristian Høgsberga341fa02010-01-24 18:10:15 -05001376}
1377
Kristian Høgsbergbcee9a42011-10-12 00:36:16 -04001378struct display *
1379window_get_display(struct window *window)
1380{
1381 return window->display;
1382}
1383
Pekka Paalanen89dee002013-02-13 16:17:20 +02001384static void
Pekka Paalanen02bba7c2013-02-13 16:17:15 +02001385surface_create_surface(struct surface *surface, int dx, int dy, uint32_t flags)
Kristian Høgsberg012a0072010-10-26 00:02:20 -04001386{
Pekka Paalanen02bba7c2013-02-13 16:17:15 +02001387 struct display *display = surface->window->display;
Pekka Paalanen811ec4f2013-02-13 16:17:14 +02001388 struct rectangle allocation = surface->allocation;
Pekka Paalanen03fc3162012-11-19 17:15:58 +02001389
Pekka Paalanen02bba7c2013-02-13 16:17:15 +02001390 if (!surface->toysurface && display->dpy &&
1391 surface->buffer_type == WINDOW_BUFFER_TYPE_EGL_WINDOW) {
Pekka Paalanen811ec4f2013-02-13 16:17:14 +02001392 surface->toysurface =
Pekka Paalanen02bba7c2013-02-13 16:17:15 +02001393 egl_window_surface_create(display,
Pekka Paalanen811ec4f2013-02-13 16:17:14 +02001394 surface->surface,
Pekka Paalanen4e373742013-02-13 16:17:13 +02001395 flags,
Ander Conselvan de Oliveira6d4cb4e2012-11-30 17:34:24 +02001396 &allocation);
Pekka Paalanenb3627362012-11-19 17:16:00 +02001397 }
Pekka Paalanen03fc3162012-11-19 17:15:58 +02001398
Pekka Paalanen811ec4f2013-02-13 16:17:14 +02001399 if (!surface->toysurface)
Pekka Paalanen02bba7c2013-02-13 16:17:15 +02001400 surface->toysurface = shm_surface_create(display,
Pekka Paalanen811ec4f2013-02-13 16:17:14 +02001401 surface->surface,
1402 flags, &allocation);
Kristian Høgsberg012a0072010-10-26 00:02:20 -04001403
Pekka Paalanen89dee002013-02-13 16:17:20 +02001404 surface->cairo_surface = surface->toysurface->prepare(
1405 surface->toysurface, dx, dy,
Alexander Larsson1818e312013-05-22 14:41:31 +02001406 allocation.width, allocation.height, flags,
1407 surface->buffer_transform, surface->buffer_scale);
Pekka Paalanen02bba7c2013-02-13 16:17:15 +02001408}
1409
1410static void
Pekka Paalanen0c4445b2013-02-13 16:17:23 +02001411window_create_main_surface(struct window *window)
Pekka Paalanen02bba7c2013-02-13 16:17:15 +02001412{
Pekka Paalanen7bcfead2013-02-13 16:17:16 +02001413 struct surface *surface = window->main_surface;
Pekka Paalanen02bba7c2013-02-13 16:17:15 +02001414 uint32_t flags = 0;
Pekka Paalanen7bcfead2013-02-13 16:17:16 +02001415 int dx = 0;
1416 int dy = 0;
Pekka Paalanen02bba7c2013-02-13 16:17:15 +02001417
Pekka Paalanenec076692012-11-30 13:37:27 +02001418 if (window->resizing)
Pekka Paalanen02bba7c2013-02-13 16:17:15 +02001419 flags |= SURFACE_HINT_RESIZE;
Pekka Paalanenec076692012-11-30 13:37:27 +02001420
Tomeu Vizosobee45a12013-08-06 20:05:54 +02001421 if (window->preferred_format == WINDOW_PREFERRED_FORMAT_RGB565)
1422 flags |= SURFACE_HINT_RGB565;
1423
Pekka Paalanen7bcfead2013-02-13 16:17:16 +02001424 if (window->resize_edges & WINDOW_RESIZING_LEFT)
1425 dx = surface->server_allocation.width -
1426 surface->allocation.width;
1427
1428 if (window->resize_edges & WINDOW_RESIZING_TOP)
1429 dy = surface->server_allocation.height -
1430 surface->allocation.height;
1431
1432 window->resize_edges = 0;
1433
Pekka Paalanen89dee002013-02-13 16:17:20 +02001434 surface_create_surface(surface, dx, dy, flags);
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -04001435}
1436
Ander Conselvan de Oliveira6d4cb4e2012-11-30 17:34:24 +02001437int
1438window_get_buffer_transform(struct window *window)
1439{
Pekka Paalanen02bba7c2013-02-13 16:17:15 +02001440 return window->main_surface->buffer_transform;
Ander Conselvan de Oliveira6d4cb4e2012-11-30 17:34:24 +02001441}
1442
1443void
1444window_set_buffer_transform(struct window *window,
1445 enum wl_output_transform transform)
1446{
Pekka Paalanen02bba7c2013-02-13 16:17:15 +02001447 window->main_surface->buffer_transform = transform;
Pekka Paalanen4e373742013-02-13 16:17:13 +02001448 wl_surface_set_buffer_transform(window->main_surface->surface,
1449 transform);
Ander Conselvan de Oliveira6d4cb4e2012-11-30 17:34:24 +02001450}
1451
Alexander Larsson5e9b6522013-05-22 14:41:28 +02001452void
1453window_set_buffer_scale(struct window *window,
Alexander Larssonedddbd12013-05-24 13:09:43 +02001454 int32_t scale)
Alexander Larsson5e9b6522013-05-22 14:41:28 +02001455{
1456 window->main_surface->buffer_scale = scale;
1457 wl_surface_set_buffer_scale(window->main_surface->surface,
1458 scale);
1459}
1460
1461uint32_t
1462window_get_buffer_scale(struct window *window)
1463{
1464 return window->main_surface->buffer_scale;
1465}
1466
Alexander Larssond68f5232013-05-22 14:41:33 +02001467uint32_t
1468window_get_output_scale(struct window *window)
1469{
1470 struct window_output *window_output;
1471 struct window_output *window_output_tmp;
1472 int scale = 1;
1473
1474 wl_list_for_each_safe(window_output, window_output_tmp,
1475 &window->window_output_list, link) {
1476 if (window_output->output->scale > scale)
1477 scale = window_output->output->scale;
1478 }
1479
1480 return scale;
1481}
1482
Jason Ekstrand3f66cf92013-10-13 19:08:40 -05001483static void window_frame_destroy(struct window_frame *frame);
Pekka Paalanen4dde2fc2012-01-19 13:33:50 +02001484
Pekka Paalanen4e373742013-02-13 16:17:13 +02001485static void
1486surface_destroy(struct surface *surface)
1487{
Pekka Paalanen40cb67b2013-04-25 13:57:49 +03001488 if (surface->frame_cb)
1489 wl_callback_destroy(surface->frame_cb);
1490
Pekka Paalanenb1cd9b12013-02-13 16:17:18 +02001491 if (surface->input_region)
1492 wl_region_destroy(surface->input_region);
1493
1494 if (surface->opaque_region)
1495 wl_region_destroy(surface->opaque_region);
1496
Pekka Paalanen35e82632013-04-25 13:57:48 +03001497 if (surface->subsurface)
1498 wl_subsurface_destroy(surface->subsurface);
1499
Pekka Paalanen4e373742013-02-13 16:17:13 +02001500 wl_surface_destroy(surface->surface);
Pekka Paalanen811ec4f2013-02-13 16:17:14 +02001501
1502 if (surface->toysurface)
1503 surface->toysurface->destroy(surface->toysurface);
1504
Pekka Paalanen35e82632013-04-25 13:57:48 +03001505 wl_list_remove(&surface->link);
Pekka Paalanen4e373742013-02-13 16:17:13 +02001506 free(surface);
1507}
1508
Kristian Høgsberge968f9c2010-08-27 22:18:00 -04001509void
Kristian Høgsberg248c1b62011-01-21 18:03:15 -05001510window_destroy(struct window *window)
1511{
Pekka Paalanen77cbc952011-11-15 13:34:55 +02001512 struct display *display = window->display;
1513 struct input *input;
Rob Bradford7507b572012-05-15 17:55:34 +01001514 struct window_output *window_output;
1515 struct window_output *window_output_tmp;
Pekka Paalanen77cbc952011-11-15 13:34:55 +02001516
Pekka Paalanen40cb67b2013-04-25 13:57:49 +03001517 wl_list_remove(&window->redraw_task.link);
Pekka Paalanen77cbc952011-11-15 13:34:55 +02001518
Rusty Lynch1084da52013-08-15 09:10:08 -07001519 wl_list_for_each(input, &display->input_list, link) {
1520 if (input->touch_focus == window)
1521 input->touch_focus = NULL;
Pekka Paalanen77cbc952011-11-15 13:34:55 +02001522 if (input->pointer_focus == window)
1523 input->pointer_focus = NULL;
1524 if (input->keyboard_focus == window)
1525 input->keyboard_focus = NULL;
Kristian Høgsbergae6e2712012-01-26 11:09:20 -05001526 if (input->focus_widget &&
1527 input->focus_widget->window == window)
1528 input->focus_widget = NULL;
Pekka Paalanen77cbc952011-11-15 13:34:55 +02001529 }
1530
Rob Bradford7507b572012-05-15 17:55:34 +01001531 wl_list_for_each_safe(window_output, window_output_tmp,
1532 &window->window_output_list, link) {
1533 free (window_output);
1534 }
1535
Pekka Paalanen4dde2fc2012-01-19 13:33:50 +02001536 if (window->frame)
Jason Ekstrandee7fefc2013-10-13 19:08:38 -05001537 window_frame_destroy(window->frame);
Pekka Paalanen4dde2fc2012-01-19 13:33:50 +02001538
Pekka Paalanen6b2dc912011-11-29 10:25:08 +02001539 if (window->shell_surface)
1540 wl_shell_surface_destroy(window->shell_surface);
Pekka Paalanen4e373742013-02-13 16:17:13 +02001541
1542 surface_destroy(window->main_surface);
1543
Kristian Høgsberg248c1b62011-01-21 18:03:15 -05001544 wl_list_remove(&window->link);
Pekka Paalanen5ec65852011-12-16 10:09:29 +02001545
Pekka Paalanen5ec65852011-12-16 10:09:29 +02001546 free(window->title);
Kristian Høgsberg248c1b62011-01-21 18:03:15 -05001547 free(window);
1548}
1549
Kristian Høgsbergc51f7992012-01-08 15:09:53 -05001550static struct widget *
Kristian Høgsberg441338c2012-01-10 13:52:34 -05001551widget_find_widget(struct widget *widget, int32_t x, int32_t y)
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001552{
Kristian Høgsberg441338c2012-01-10 13:52:34 -05001553 struct widget *child, *target;
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001554
Kristian Høgsberg441338c2012-01-10 13:52:34 -05001555 wl_list_for_each(child, &widget->child_list, link) {
1556 target = widget_find_widget(child, x, y);
1557 if (target)
1558 return target;
1559 }
1560
1561 if (widget->allocation.x <= x &&
1562 x < widget->allocation.x + widget->allocation.width &&
1563 widget->allocation.y <= y &&
1564 y < widget->allocation.y + widget->allocation.height) {
1565 return widget;
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001566 }
1567
1568 return NULL;
1569}
1570
Kristian Høgsberg441338c2012-01-10 13:52:34 -05001571static struct widget *
Pekka Paalanenac95f3e2013-02-13 16:17:17 +02001572window_find_widget(struct window *window, int32_t x, int32_t y)
1573{
Pekka Paalanen35e82632013-04-25 13:57:48 +03001574 struct surface *surface;
1575 struct widget *widget;
1576
1577 wl_list_for_each(surface, &window->subsurface_list, link) {
1578 widget = widget_find_widget(surface->widget, x, y);
1579 if (widget)
1580 return widget;
1581 }
1582
1583 return NULL;
Pekka Paalanenac95f3e2013-02-13 16:17:17 +02001584}
1585
1586static struct widget *
Pekka Paalanen2d8a32a2013-02-13 16:17:19 +02001587widget_create(struct window *window, struct surface *surface, void *data)
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001588{
Kristian Høgsbergc51f7992012-01-08 15:09:53 -05001589 struct widget *widget;
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001590
Peter Huttererf3d62272013-08-08 11:57:05 +10001591 widget = xzalloc(sizeof *widget);
Kristian Høgsberg9a13dab2012-01-08 15:18:19 -05001592 widget->window = window;
Pekka Paalanen2d8a32a2013-02-13 16:17:19 +02001593 widget->surface = surface;
Kristian Høgsbergc51f7992012-01-08 15:09:53 -05001594 widget->user_data = data;
Pekka Paalanen2d8a32a2013-02-13 16:17:19 +02001595 widget->allocation = surface->allocation;
Kristian Høgsberg441338c2012-01-10 13:52:34 -05001596 wl_list_init(&widget->child_list);
Kristian Høgsberg010f98b2012-02-23 17:30:45 -05001597 widget->opaque = 0;
Tiago Vignatti82db9d82012-05-23 22:06:27 +03001598 widget->tooltip = NULL;
1599 widget->tooltip_count = 0;
Kristian Høgsbergbf74d522012-11-30 14:54:35 -05001600 widget->default_cursor = CURSOR_LEFT_PTR;
Kristian Høgsberg441338c2012-01-10 13:52:34 -05001601
1602 return widget;
1603}
1604
1605struct widget *
1606window_add_widget(struct window *window, void *data)
1607{
Pekka Paalanenac95f3e2013-02-13 16:17:17 +02001608 struct widget *widget;
Kristian Høgsberg441338c2012-01-10 13:52:34 -05001609
Pekka Paalanen2d8a32a2013-02-13 16:17:19 +02001610 widget = widget_create(window, window->main_surface, data);
Pekka Paalanenac95f3e2013-02-13 16:17:17 +02001611 wl_list_init(&widget->link);
1612 window->main_surface->widget = widget;
1613
1614 return widget;
Kristian Høgsberg441338c2012-01-10 13:52:34 -05001615}
1616
1617struct widget *
1618widget_add_widget(struct widget *parent, void *data)
1619{
1620 struct widget *widget;
1621
Pekka Paalanen2d8a32a2013-02-13 16:17:19 +02001622 widget = widget_create(parent->window, parent->surface, data);
Kristian Høgsberg441338c2012-01-10 13:52:34 -05001623 wl_list_insert(parent->child_list.prev, &widget->link);
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001624
Kristian Høgsbergc51f7992012-01-08 15:09:53 -05001625 return widget;
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001626}
1627
1628void
Kristian Høgsberg441338c2012-01-10 13:52:34 -05001629widget_destroy(struct widget *widget)
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001630{
Pekka Paalanene156fb62012-01-19 13:51:38 +02001631 struct display *display = widget->window->display;
Pekka Paalanen35e82632013-04-25 13:57:48 +03001632 struct surface *surface = widget->surface;
Pekka Paalanene156fb62012-01-19 13:51:38 +02001633 struct input *input;
1634
Pekka Paalanen35e82632013-04-25 13:57:48 +03001635 /* Destroy the sub-surface along with the root widget */
1636 if (surface->widget == widget && surface->subsurface)
1637 surface_destroy(widget->surface);
1638
Tiago Vignatti82db9d82012-05-23 22:06:27 +03001639 if (widget->tooltip) {
1640 free(widget->tooltip);
1641 widget->tooltip = NULL;
1642 }
1643
Pekka Paalanene156fb62012-01-19 13:51:38 +02001644 wl_list_for_each(input, &display->input_list, link) {
1645 if (input->focus_widget == widget)
1646 input->focus_widget = NULL;
1647 }
1648
Kristian Høgsberg441338c2012-01-10 13:52:34 -05001649 wl_list_remove(&widget->link);
1650 free(widget);
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001651}
1652
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001653void
Kristian Høgsbergbf74d522012-11-30 14:54:35 -05001654widget_set_default_cursor(struct widget *widget, int cursor)
1655{
1656 widget->default_cursor = cursor;
1657}
1658
1659void
Kristian Høgsbergc51f7992012-01-08 15:09:53 -05001660widget_get_allocation(struct widget *widget, struct rectangle *allocation)
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001661{
Kristian Høgsbergc51f7992012-01-08 15:09:53 -05001662 *allocation = widget->allocation;
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001663}
1664
1665void
Kristian Høgsbergbb977002012-01-10 19:11:42 -05001666widget_set_size(struct widget *widget, int32_t width, int32_t height)
1667{
Kristian Høgsbergbb977002012-01-10 19:11:42 -05001668 widget->allocation.width = width;
1669 widget->allocation.height = height;
Kristian Høgsbergbb977002012-01-10 19:11:42 -05001670}
1671
1672void
Kristian Høgsbergc51f7992012-01-08 15:09:53 -05001673widget_set_allocation(struct widget *widget,
1674 int32_t x, int32_t y, int32_t width, int32_t height)
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001675{
Kristian Høgsbergc51f7992012-01-08 15:09:53 -05001676 widget->allocation.x = x;
1677 widget->allocation.y = y;
Tiago Vignattic5528d82012-02-09 19:06:55 +02001678 widget_set_size(widget, width, height);
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001679}
1680
Kristian Høgsberg010f98b2012-02-23 17:30:45 -05001681void
1682widget_set_transparent(struct widget *widget, int transparent)
1683{
1684 widget->opaque = !transparent;
1685}
1686
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001687void *
Kristian Høgsbergc51f7992012-01-08 15:09:53 -05001688widget_get_user_data(struct widget *widget)
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001689{
Kristian Høgsbergc51f7992012-01-08 15:09:53 -05001690 return widget->user_data;
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001691}
1692
Pekka Paalanen0c4445b2013-02-13 16:17:23 +02001693static cairo_surface_t *
1694widget_get_cairo_surface(struct widget *widget)
1695{
1696 struct surface *surface = widget->surface;
1697 struct window *window = widget->window;
1698
1699 if (!surface->cairo_surface) {
1700 if (surface == window->main_surface)
1701 window_create_main_surface(window);
1702 else
1703 surface_create_surface(surface, 0, 0, 0);
1704 }
1705
1706 return surface->cairo_surface;
1707}
1708
Alexander Larsson15901f02013-05-22 14:41:25 +02001709static void
1710widget_cairo_update_transform(struct widget *widget, cairo_t *cr)
1711{
1712 struct surface *surface = widget->surface;
1713 double angle;
1714 cairo_matrix_t m;
1715 enum wl_output_transform transform;
1716 int surface_width, surface_height;
1717 int translate_x, translate_y;
Alexander Larssonedddbd12013-05-24 13:09:43 +02001718 int32_t scale;
Alexander Larsson15901f02013-05-22 14:41:25 +02001719
1720 surface_width = surface->allocation.width;
1721 surface_height = surface->allocation.height;
1722
Alexander Larsson5e9b6522013-05-22 14:41:28 +02001723 transform = surface->buffer_transform;
Alexander Larsson2aaa8b72013-05-22 14:41:29 +02001724 scale = surface->buffer_scale;
Alexander Larsson5e9b6522013-05-22 14:41:28 +02001725
Alexander Larsson15901f02013-05-22 14:41:25 +02001726 switch (transform) {
1727 case WL_OUTPUT_TRANSFORM_FLIPPED:
1728 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
1729 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
1730 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
1731 cairo_matrix_init(&m, -1, 0, 0, 1, 0, 0);
1732 break;
1733 default:
1734 cairo_matrix_init_identity(&m);
1735 break;
1736 }
1737
1738 switch (transform) {
1739 case WL_OUTPUT_TRANSFORM_NORMAL:
1740 default:
1741 angle = 0;
1742 translate_x = 0;
1743 translate_y = 0;
1744 break;
1745 case WL_OUTPUT_TRANSFORM_FLIPPED:
1746 angle = 0;
1747 translate_x = surface_width;
1748 translate_y = 0;
1749 break;
1750 case WL_OUTPUT_TRANSFORM_90:
1751 angle = M_PI_2;
1752 translate_x = surface_height;
1753 translate_y = 0;
1754 break;
1755 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
1756 angle = M_PI_2;
1757 translate_x = surface_height;
1758 translate_y = surface_width;
1759 break;
1760 case WL_OUTPUT_TRANSFORM_180:
1761 angle = M_PI;
1762 translate_x = surface_width;
1763 translate_y = surface_height;
1764 break;
1765 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
1766 angle = M_PI;
1767 translate_x = 0;
1768 translate_y = surface_height;
1769 break;
1770 case WL_OUTPUT_TRANSFORM_270:
1771 angle = M_PI + M_PI_2;
1772 translate_x = 0;
1773 translate_y = surface_width;
1774 break;
1775 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
1776 angle = M_PI + M_PI_2;
1777 translate_x = 0;
1778 translate_y = 0;
1779 break;
1780 }
1781
Alexander Larsson2aaa8b72013-05-22 14:41:29 +02001782 cairo_scale(cr, scale, scale);
Alexander Larsson15901f02013-05-22 14:41:25 +02001783 cairo_translate(cr, translate_x, translate_y);
1784 cairo_rotate(cr, angle);
1785 cairo_transform(cr, &m);
1786}
1787
Pekka Paalanen0c4445b2013-02-13 16:17:23 +02001788cairo_t *
1789widget_cairo_create(struct widget *widget)
1790{
Pekka Paalanen35e82632013-04-25 13:57:48 +03001791 struct surface *surface = widget->surface;
Pekka Paalanen0c4445b2013-02-13 16:17:23 +02001792 cairo_surface_t *cairo_surface;
1793 cairo_t *cr;
1794
1795 cairo_surface = widget_get_cairo_surface(widget);
1796 cr = cairo_create(cairo_surface);
1797
Alexander Larsson15901f02013-05-22 14:41:25 +02001798 widget_cairo_update_transform(widget, cr);
1799
Pekka Paalanen35e82632013-04-25 13:57:48 +03001800 cairo_translate(cr, -surface->allocation.x, -surface->allocation.y);
1801
Pekka Paalanen0c4445b2013-02-13 16:17:23 +02001802 return cr;
1803}
1804
Pekka Paalanen7ff7a802013-04-25 13:57:50 +03001805struct wl_surface *
1806widget_get_wl_surface(struct widget *widget)
1807{
1808 return widget->surface->surface;
1809}
1810
1811uint32_t
1812widget_get_last_time(struct widget *widget)
1813{
1814 return widget->surface->last_time;
1815}
1816
1817void
1818widget_input_region_add(struct widget *widget, const struct rectangle *rect)
1819{
1820 struct wl_compositor *comp = widget->window->display->compositor;
1821 struct surface *surface = widget->surface;
1822
1823 if (!surface->input_region)
1824 surface->input_region = wl_compositor_create_region(comp);
1825
1826 if (rect) {
1827 wl_region_add(surface->input_region,
1828 rect->x, rect->y, rect->width, rect->height);
1829 }
1830}
1831
Kristian Høgsberg248c1b62011-01-21 18:03:15 -05001832void
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -05001833widget_set_resize_handler(struct widget *widget,
1834 widget_resize_handler_t handler)
1835{
1836 widget->resize_handler = handler;
1837}
1838
1839void
1840widget_set_redraw_handler(struct widget *widget,
1841 widget_redraw_handler_t handler)
1842{
1843 widget->redraw_handler = handler;
1844}
1845
1846void
Kristian Høgsbergee143232012-01-09 08:42:24 -05001847widget_set_enter_handler(struct widget *widget, widget_enter_handler_t handler)
Kristian Høgsberg9a13dab2012-01-08 15:18:19 -05001848{
Kristian Høgsbergee143232012-01-09 08:42:24 -05001849 widget->enter_handler = handler;
1850}
1851
1852void
1853widget_set_leave_handler(struct widget *widget, widget_leave_handler_t handler)
1854{
1855 widget->leave_handler = handler;
Kristian Høgsberg9a13dab2012-01-08 15:18:19 -05001856}
1857
1858void
Kristian Høgsberg04e98342012-01-09 09:36:16 -05001859widget_set_motion_handler(struct widget *widget,
1860 widget_motion_handler_t handler)
1861{
1862 widget->motion_handler = handler;
1863}
1864
1865void
Kristian Høgsberga8a0db32012-01-09 11:12:05 -05001866widget_set_button_handler(struct widget *widget,
1867 widget_button_handler_t handler)
1868{
1869 widget->button_handler = handler;
1870}
1871
1872void
Rusty Lynch041815a2013-08-08 21:20:38 -07001873widget_set_touch_up_handler(struct widget *widget,
1874 widget_touch_up_handler_t handler)
1875{
1876 widget->touch_up_handler = handler;
1877}
1878
1879void
1880widget_set_touch_down_handler(struct widget *widget,
1881 widget_touch_down_handler_t handler)
1882{
1883 widget->touch_down_handler = handler;
1884}
1885
1886void
1887widget_set_touch_motion_handler(struct widget *widget,
1888 widget_touch_motion_handler_t handler)
1889{
1890 widget->touch_motion_handler = handler;
1891}
1892
1893void
1894widget_set_touch_frame_handler(struct widget *widget,
1895 widget_touch_frame_handler_t handler)
1896{
1897 widget->touch_frame_handler = handler;
1898}
1899
1900void
1901widget_set_touch_cancel_handler(struct widget *widget,
1902 widget_touch_cancel_handler_t handler)
1903{
1904 widget->touch_cancel_handler = handler;
1905}
1906
1907void
Philipp Brüschweiler7e0cc542012-08-14 11:02:41 +02001908widget_set_axis_handler(struct widget *widget,
1909 widget_axis_handler_t handler)
1910{
1911 widget->axis_handler = handler;
1912}
1913
Pekka Paalanen40cb67b2013-04-25 13:57:49 +03001914static void
1915window_schedule_redraw_task(struct window *window);
1916
Philipp Brüschweiler7e0cc542012-08-14 11:02:41 +02001917void
Kristian Høgsberg9a13dab2012-01-08 15:18:19 -05001918widget_schedule_redraw(struct widget *widget)
1919{
Pekka Paalanen71233882013-04-25 13:57:53 +03001920 DBG_OBJ(widget->surface->surface, "widget %p\n", widget);
Pekka Paalanen40cb67b2013-04-25 13:57:49 +03001921 widget->surface->redraw_needed = 1;
1922 window_schedule_redraw_task(widget->window);
Kristian Høgsberg9a13dab2012-01-08 15:18:19 -05001923}
1924
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -04001925cairo_surface_t *
1926window_get_surface(struct window *window)
1927{
Pekka Paalanen0c4445b2013-02-13 16:17:23 +02001928 cairo_surface_t *cairo_surface;
1929
1930 cairo_surface = widget_get_cairo_surface(window->main_surface->widget);
1931
1932 return cairo_surface_reference(cairo_surface);
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -04001933}
1934
Benjamin Franzkeec4d3422011-03-14 12:07:26 +01001935struct wl_surface *
1936window_get_wl_surface(struct window *window)
1937{
Pekka Paalanen4e373742013-02-13 16:17:13 +02001938 return window->main_surface->surface;
Benjamin Franzkeec4d3422011-03-14 12:07:26 +01001939}
1940
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001941struct wl_shell_surface *
1942window_get_wl_shell_surface(struct window *window)
1943{
1944 return window->shell_surface;
1945}
1946
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001947static void
Tiago Vignatti82db9d82012-05-23 22:06:27 +03001948tooltip_redraw_handler(struct widget *widget, void *data)
1949{
1950 cairo_t *cr;
1951 const int32_t r = 3;
1952 struct tooltip *tooltip = data;
1953 int32_t width, height;
Tiago Vignatti82db9d82012-05-23 22:06:27 +03001954
Pekka Paalanen0c4445b2013-02-13 16:17:23 +02001955 cr = widget_cairo_create(widget);
Tiago Vignatti82db9d82012-05-23 22:06:27 +03001956 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
1957 cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.0);
1958 cairo_paint(cr);
1959
Pekka Paalanen0a9686f2013-02-13 16:17:22 +02001960 width = widget->allocation.width;
1961 height = widget->allocation.height;
Tiago Vignatti82db9d82012-05-23 22:06:27 +03001962 rounded_rect(cr, 0, 0, width, height, r);
1963
1964 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
1965 cairo_set_source_rgba(cr, 0.0, 0.0, 0.4, 0.8);
1966 cairo_fill(cr);
1967
1968 cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
1969 cairo_move_to(cr, 10, 16);
1970 cairo_show_text(cr, tooltip->entry);
1971 cairo_destroy(cr);
1972}
1973
1974static cairo_text_extents_t
1975get_text_extents(struct tooltip *tooltip)
1976{
Tiago Vignatti82db9d82012-05-23 22:06:27 +03001977 cairo_t *cr;
1978 cairo_text_extents_t extents;
1979
Pekka Paalanen3cbb0892012-11-19 17:16:01 +02001980 /* Use the dummy_surface because tooltip's surface was not
1981 * created yet, and parent does not have a valid surface
1982 * outside repaint, either.
1983 */
1984 cr = cairo_create(tooltip->window->display->dummy_surface);
Tiago Vignatti82db9d82012-05-23 22:06:27 +03001985 cairo_text_extents(cr, tooltip->entry, &extents);
1986 cairo_destroy(cr);
1987
1988 return extents;
1989}
1990
1991static int
1992window_create_tooltip(struct tooltip *tooltip)
1993{
1994 struct widget *parent = tooltip->parent;
1995 struct display *display = parent->window->display;
1996 struct window *window;
1997 const int offset_y = 27;
1998 const int margin = 3;
1999 cairo_text_extents_t extents;
2000
2001 if (tooltip->widget)
2002 return 0;
2003
2004 window = window_create_transient(display, parent->window, tooltip->x,
2005 tooltip->y + offset_y,
2006 WL_SHELL_SURFACE_TRANSIENT_INACTIVE);
2007 if (!window)
2008 return -1;
2009
2010 tooltip->window = window;
2011 tooltip->widget = window_add_widget(tooltip->window, tooltip);
2012
2013 extents = get_text_extents(tooltip);
2014 widget_set_redraw_handler(tooltip->widget, tooltip_redraw_handler);
2015 window_schedule_resize(window, extents.width + 20, 20 + margin * 2);
2016
2017 return 0;
2018}
2019
2020void
2021widget_destroy_tooltip(struct widget *parent)
2022{
2023 struct tooltip *tooltip = parent->tooltip;
2024
2025 parent->tooltip_count = 0;
2026 if (!tooltip)
2027 return;
2028
2029 if (tooltip->widget) {
2030 widget_destroy(tooltip->widget);
2031 window_destroy(tooltip->window);
2032 tooltip->widget = NULL;
2033 tooltip->window = NULL;
2034 }
2035
2036 close(tooltip->tooltip_fd);
2037 free(tooltip->entry);
2038 free(tooltip);
2039 parent->tooltip = NULL;
2040}
2041
2042static void
2043tooltip_func(struct task *task, uint32_t events)
2044{
2045 struct tooltip *tooltip =
2046 container_of(task, struct tooltip, tooltip_task);
2047 uint64_t exp;
2048
Martin Olsson8df662a2012-07-08 03:03:47 +02002049 if (read(tooltip->tooltip_fd, &exp, sizeof (uint64_t)) != sizeof (uint64_t))
2050 abort();
Tiago Vignatti82db9d82012-05-23 22:06:27 +03002051 window_create_tooltip(tooltip);
2052}
2053
2054#define TOOLTIP_TIMEOUT 500
2055static int
2056tooltip_timer_reset(struct tooltip *tooltip)
2057{
2058 struct itimerspec its;
2059
2060 its.it_interval.tv_sec = 0;
2061 its.it_interval.tv_nsec = 0;
2062 its.it_value.tv_sec = TOOLTIP_TIMEOUT / 1000;
2063 its.it_value.tv_nsec = (TOOLTIP_TIMEOUT % 1000) * 1000 * 1000;
2064 if (timerfd_settime(tooltip->tooltip_fd, 0, &its, NULL) < 0) {
2065 fprintf(stderr, "could not set timerfd\n: %m");
2066 return -1;
2067 }
2068
2069 return 0;
2070}
2071
2072int
2073widget_set_tooltip(struct widget *parent, char *entry, float x, float y)
2074{
2075 struct tooltip *tooltip = parent->tooltip;
2076
2077 parent->tooltip_count++;
2078 if (tooltip) {
2079 tooltip->x = x;
2080 tooltip->y = y;
2081 tooltip_timer_reset(tooltip);
2082 return 0;
2083 }
2084
2085 /* the handler might be triggered too fast via input device motion, so
2086 * we need this check here to make sure tooltip is fully initialized */
2087 if (parent->tooltip_count > 1)
2088 return 0;
2089
2090 tooltip = malloc(sizeof *tooltip);
2091 if (!tooltip)
2092 return -1;
2093
2094 parent->tooltip = tooltip;
2095 tooltip->parent = parent;
2096 tooltip->widget = NULL;
2097 tooltip->window = NULL;
2098 tooltip->x = x;
2099 tooltip->y = y;
2100 tooltip->entry = strdup(entry);
2101 tooltip->tooltip_fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
2102 if (tooltip->tooltip_fd < 0) {
2103 fprintf(stderr, "could not create timerfd\n: %m");
2104 return -1;
2105 }
2106
2107 tooltip->tooltip_task.run = tooltip_func;
2108 display_watch_fd(parent->window->display, tooltip->tooltip_fd,
2109 EPOLLIN, &tooltip->tooltip_task);
2110 tooltip_timer_reset(tooltip);
2111
2112 return 0;
2113}
2114
2115static void
Jonas Ådahl14c92ff2012-08-29 22:13:02 +02002116workspace_manager_state(void *data,
2117 struct workspace_manager *workspace_manager,
2118 uint32_t current,
2119 uint32_t count)
2120{
2121 struct display *display = data;
2122
2123 display->workspace = current;
2124 display->workspace_count = count;
2125}
2126
2127static const struct workspace_manager_listener workspace_manager_listener = {
2128 workspace_manager_state
2129};
2130
2131static void
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002132frame_resize_handler(struct widget *widget,
2133 int32_t width, int32_t height, void *data)
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04002134{
Jason Ekstrand3f66cf92013-10-13 19:08:40 -05002135 struct window_frame *frame = data;
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002136 struct widget *child = frame->child;
Jason Ekstrand3f66cf92013-10-13 19:08:40 -05002137 struct rectangle interior;
2138 struct rectangle input;
2139 struct rectangle opaque;
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002140
Jason Ekstrand3f66cf92013-10-13 19:08:40 -05002141 if (widget->window->type == TYPE_FULLSCREEN) {
2142 interior.x = 0;
2143 interior.y = 0;
2144 interior.width = width;
2145 interior.height = height;
2146 } else {
2147 if (widget->window->type == TYPE_MAXIMIZED) {
2148 frame_set_flag(frame->frame, FRAME_FLAG_MAXIMIZED);
2149 } else {
2150 frame_unset_flag(frame->frame, FRAME_FLAG_MAXIMIZED);
2151 }
Scott Moreauc6a7e4b2012-09-28 02:45:06 -06002152
Jason Ekstrand3f66cf92013-10-13 19:08:40 -05002153 frame_resize(frame->frame, width, height);
2154 frame_interior(frame->frame, &interior.x, &interior.y,
2155 &interior.width, &interior.height);
Kristian Høgsberg010f98b2012-02-23 17:30:45 -05002156 }
2157
Jason Ekstrand3f66cf92013-10-13 19:08:40 -05002158 widget_set_allocation(child, interior.x, interior.y,
2159 interior.width, interior.height);
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002160
Jason Ekstrand3f66cf92013-10-13 19:08:40 -05002161 if (child->resize_handler) {
2162 child->resize_handler(child, interior.width, interior.height,
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002163 child->user_data);
2164
Jason Ekstrand3f66cf92013-10-13 19:08:40 -05002165 if (widget->window->type == TYPE_FULLSCREEN) {
2166 width = child->allocation.width;
2167 height = child->allocation.height;
2168 } else {
2169 frame_resize_inside(frame->frame,
2170 child->allocation.width,
2171 child->allocation.height);
2172 width = frame_width(frame->frame);
2173 height = frame_height(frame->frame);
2174 }
Kristian Høgsberg023be102012-07-31 11:59:12 -04002175 }
2176
Scott Moreauf7e498c2012-05-14 11:39:29 -06002177 widget_set_allocation(widget, 0, 0, width, height);
Kristian Høgsbergf10df852012-02-28 21:52:12 -05002178
Jason Ekstrand3f66cf92013-10-13 19:08:40 -05002179 widget->surface->input_region =
2180 wl_compositor_create_region(widget->window->display->compositor);
2181 if (widget->window->type != TYPE_FULLSCREEN) {
2182 frame_input_rect(frame->frame, &input.x, &input.y,
2183 &input.width, &input.height);
2184 wl_region_add(widget->surface->input_region,
2185 input.x, input.y, input.width, input.height);
Pekka Vuorela4e363d22012-09-26 15:05:45 +03002186 } else {
Jason Ekstrand3f66cf92013-10-13 19:08:40 -05002187 wl_region_add(widget->surface->input_region, 0, 0, width, height);
Pekka Vuorela4e363d22012-09-26 15:05:45 +03002188 }
2189
Jason Ekstrand3f66cf92013-10-13 19:08:40 -05002190 widget_set_allocation(widget, 0, 0, width, height);
Pekka Vuorela4e363d22012-09-26 15:05:45 +03002191
Jason Ekstrand3f66cf92013-10-13 19:08:40 -05002192 if (child->opaque) {
Kristian Høgsberg598477d2013-10-16 16:06:18 -07002193 if (widget->window->type != TYPE_FULLSCREEN) {
2194 frame_opaque_rect(frame->frame, &opaque.x, &opaque.y,
2195 &opaque.width, &opaque.height);
2196
2197 wl_region_add(widget->surface->opaque_region,
2198 opaque.x, opaque.y,
2199 opaque.width, opaque.height);
2200 } else {
2201 wl_region_add(widget->surface->opaque_region,
2202 0, 0, width, height);
2203 }
Martin Minarik1998b152012-05-10 02:04:35 +02002204 }
2205
Martin Minarik1998b152012-05-10 02:04:35 +02002206
Jason Ekstrand3f66cf92013-10-13 19:08:40 -05002207 widget_schedule_redraw(widget);
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002208}
2209
2210static void
2211frame_redraw_handler(struct widget *widget, void *data)
2212{
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002213 cairo_t *cr;
Jason Ekstrand3f66cf92013-10-13 19:08:40 -05002214 struct window_frame *frame = data;
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002215 struct window *window = widget->window;
2216
Kristian Høgsberg2675dc12012-02-16 22:57:21 -05002217 if (window->type == TYPE_FULLSCREEN)
2218 return;
2219
Jason Ekstrand3f66cf92013-10-13 19:08:40 -05002220 if (window->focus_count) {
2221 frame_set_flag(frame->frame, FRAME_FLAG_ACTIVE);
2222 } else {
2223 frame_unset_flag(frame->frame, FRAME_FLAG_ACTIVE);
2224 }
2225
Pekka Paalanen0c4445b2013-02-13 16:17:23 +02002226 cr = widget_cairo_create(widget);
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002227
Jason Ekstrand3f66cf92013-10-13 19:08:40 -05002228 frame_repaint(frame->frame, cr);
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002229
2230 cairo_destroy(cr);
2231}
2232
2233static int
Jason Ekstrand3f66cf92013-10-13 19:08:40 -05002234frame_get_pointer_image_for_location(struct window_frame *frame,
2235 enum theme_location location)
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04002236{
Scott Moreauc6a7e4b2012-09-28 02:45:06 -06002237 struct window *window = frame->widget->window;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04002238
Kristian Høgsberge994edd2013-02-14 16:31:42 -05002239 if (window->type != TYPE_TOPLEVEL)
2240 return CURSOR_LEFT_PTR;
2241
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04002242 switch (location) {
Kristian Høgsbergf96e6c02012-05-22 16:38:53 -04002243 case THEME_LOCATION_RESIZING_TOP:
Ander Conselvan de Oliveiradc8c8fc2012-05-25 16:01:41 +03002244 return CURSOR_TOP;
Kristian Høgsbergf96e6c02012-05-22 16:38:53 -04002245 case THEME_LOCATION_RESIZING_BOTTOM:
Ander Conselvan de Oliveiradc8c8fc2012-05-25 16:01:41 +03002246 return CURSOR_BOTTOM;
Kristian Høgsbergf96e6c02012-05-22 16:38:53 -04002247 case THEME_LOCATION_RESIZING_LEFT:
Ander Conselvan de Oliveiradc8c8fc2012-05-25 16:01:41 +03002248 return CURSOR_LEFT;
Kristian Høgsbergf96e6c02012-05-22 16:38:53 -04002249 case THEME_LOCATION_RESIZING_RIGHT:
Ander Conselvan de Oliveiradc8c8fc2012-05-25 16:01:41 +03002250 return CURSOR_RIGHT;
Kristian Høgsbergf96e6c02012-05-22 16:38:53 -04002251 case THEME_LOCATION_RESIZING_TOP_LEFT:
Ander Conselvan de Oliveiradc8c8fc2012-05-25 16:01:41 +03002252 return CURSOR_TOP_LEFT;
Kristian Høgsbergf96e6c02012-05-22 16:38:53 -04002253 case THEME_LOCATION_RESIZING_TOP_RIGHT:
Ander Conselvan de Oliveiradc8c8fc2012-05-25 16:01:41 +03002254 return CURSOR_TOP_RIGHT;
Kristian Høgsbergf96e6c02012-05-22 16:38:53 -04002255 case THEME_LOCATION_RESIZING_BOTTOM_LEFT:
Ander Conselvan de Oliveiradc8c8fc2012-05-25 16:01:41 +03002256 return CURSOR_BOTTOM_LEFT;
Kristian Høgsbergf96e6c02012-05-22 16:38:53 -04002257 case THEME_LOCATION_RESIZING_BOTTOM_RIGHT:
Ander Conselvan de Oliveiradc8c8fc2012-05-25 16:01:41 +03002258 return CURSOR_BOTTOM_RIGHT;
Kristian Høgsbergf96e6c02012-05-22 16:38:53 -04002259 case THEME_LOCATION_EXTERIOR:
2260 case THEME_LOCATION_TITLEBAR:
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04002261 default:
Ander Conselvan de Oliveiradc8c8fc2012-05-25 16:01:41 +03002262 return CURSOR_LEFT_PTR;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04002263 }
Kristian Høgsbergcd9ac1d2011-12-15 09:14:34 -05002264}
2265
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002266static void
Kristian Høgsberg67b82152013-10-23 16:52:05 -07002267frame_menu_func(struct window *window,
2268 struct input *input, int index, void *data)
Kristian Høgsbergcd9ac1d2011-12-15 09:14:34 -05002269{
Jonas Ådahl14c92ff2012-08-29 22:13:02 +02002270 struct display *display;
2271
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002272 switch (index) {
2273 case 0: /* close */
2274 if (window->close_handler)
2275 window->close_handler(window->parent,
2276 window->user_data);
2277 else
2278 display_exit(window->display);
2279 break;
Kristian Høgsbergefb94882012-10-30 18:07:02 -04002280 case 1: /* move to workspace above */
Jonas Ådahl14c92ff2012-08-29 22:13:02 +02002281 display = window->display;
2282 if (display->workspace > 0)
Pekka Paalanen4e373742013-02-13 16:17:13 +02002283 workspace_manager_move_surface(
2284 display->workspace_manager,
2285 window->main_surface->surface,
2286 display->workspace - 1);
Jonas Ådahl14c92ff2012-08-29 22:13:02 +02002287 break;
Kristian Høgsbergefb94882012-10-30 18:07:02 -04002288 case 2: /* move to workspace below */
Jonas Ådahl14c92ff2012-08-29 22:13:02 +02002289 display = window->display;
Philipp Brüschweiler067abf62012-09-01 16:03:05 +02002290 if (display->workspace < display->workspace_count - 1)
Pekka Paalanen4e373742013-02-13 16:17:13 +02002291 workspace_manager_move_surface(
2292 display->workspace_manager,
2293 window->main_surface->surface,
2294 display->workspace + 1);
Kristian Høgsberg0f7a2852012-11-05 20:20:53 -05002295 break;
Kristian Høgsbergefb94882012-10-30 18:07:02 -04002296 case 3: /* fullscreen */
2297 /* we don't have a way to get out of fullscreen for now */
2298 if (window->fullscreen_handler)
2299 window->fullscreen_handler(window, window->user_data);
2300 break;
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002301 }
2302}
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04002303
Kristian Høgsbergd31fcab2012-01-31 09:53:44 -05002304void
2305window_show_frame_menu(struct window *window,
2306 struct input *input, uint32_t time)
2307{
2308 int32_t x, y;
Kristian Høgsbergefb94882012-10-30 18:07:02 -04002309 int count;
Kristian Høgsbergd31fcab2012-01-31 09:53:44 -05002310
2311 static const char *entries[] = {
Kristian Høgsbergefb94882012-10-30 18:07:02 -04002312 "Close",
2313 "Move to workspace above", "Move to workspace below",
2314 "Fullscreen"
Kristian Høgsbergd31fcab2012-01-31 09:53:44 -05002315 };
2316
Kristian Høgsbergefb94882012-10-30 18:07:02 -04002317 if (window->fullscreen_handler)
2318 count = ARRAY_LENGTH(entries);
2319 else
2320 count = ARRAY_LENGTH(entries) - 1;
2321
Kristian Høgsbergd31fcab2012-01-31 09:53:44 -05002322 input_get_position(input, &x, &y);
2323 window_show_menu(window->display, input, time, window,
Kristian Høgsbergefb94882012-10-30 18:07:02 -04002324 x - 10, y - 10, frame_menu_func, entries, count);
Kristian Høgsbergd31fcab2012-01-31 09:53:44 -05002325}
2326
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002327static int
2328frame_enter_handler(struct widget *widget,
Kristian Høgsberg80680c72012-05-10 12:21:37 -04002329 struct input *input, float x, float y, void *data)
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002330{
Jason Ekstrand3f66cf92013-10-13 19:08:40 -05002331 struct window_frame *frame = data;
2332 enum theme_location location;
2333
2334 location = frame_pointer_enter(frame->frame, input, x, y);
2335 if (frame_status(frame->frame) & FRAME_STATUS_REPAINT)
2336 widget_schedule_redraw(frame->widget);
2337
2338 return frame_get_pointer_image_for_location(data, location);
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002339}
Kristian Høgsberg7d804062010-09-07 21:50:06 -04002340
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002341static int
2342frame_motion_handler(struct widget *widget,
2343 struct input *input, uint32_t time,
Kristian Høgsberg80680c72012-05-10 12:21:37 -04002344 float x, float y, void *data)
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002345{
Jason Ekstrand3f66cf92013-10-13 19:08:40 -05002346 struct window_frame *frame = data;
2347 enum theme_location location;
2348
2349 location = frame_pointer_motion(frame->frame, input, x, y);
2350 if (frame_status(frame->frame) & FRAME_STATUS_REPAINT)
2351 widget_schedule_redraw(frame->widget);
2352
2353 return frame_get_pointer_image_for_location(data, location);
2354}
2355
2356static void
2357frame_leave_handler(struct widget *widget,
2358 struct input *input, void *data)
2359{
2360 struct window_frame *frame = data;
2361
2362 frame_pointer_leave(frame->frame, input);
2363 if (frame_status(frame->frame) & FRAME_STATUS_REPAINT)
2364 widget_schedule_redraw(frame->widget);
2365}
2366
2367static void
2368frame_handle_status(struct window_frame *frame, struct input *input,
2369 uint32_t time, enum theme_location location)
2370{
2371 struct window *window = frame->widget->window;
2372 uint32_t status;
2373
2374 status = frame_status(frame->frame);
2375 if (status & FRAME_STATUS_REPAINT)
2376 widget_schedule_redraw(frame->widget);
2377
2378 if (status & FRAME_STATUS_MINIMIZE)
2379 fprintf(stderr,"Minimize stub\n");
2380
2381 if (status & FRAME_STATUS_MENU) {
2382 window_show_frame_menu(window, input, time);
2383 frame_status_clear(frame->frame, FRAME_STATUS_MENU);
2384 }
2385
2386 if (status & FRAME_STATUS_MAXIMIZE) {
2387 window_set_maximized(window, window->type != TYPE_MAXIMIZED);
2388 frame_status_clear(frame->frame, FRAME_STATUS_MAXIMIZE);
2389 }
2390
2391 if (status & FRAME_STATUS_CLOSE) {
2392 if (window->close_handler)
2393 window->close_handler(window->parent,
2394 window->user_data);
2395 else
2396 display_exit(window->display);
2397 frame_status_clear(frame->frame, FRAME_STATUS_CLOSE);
2398 }
2399
2400 if ((status & FRAME_STATUS_MOVE) && window->shell_surface) {
2401 input_ungrab(input);
2402 wl_shell_surface_move(window->shell_surface,
2403 input_get_seat(input),
2404 window->display->serial);
2405
2406 frame_status_clear(frame->frame, FRAME_STATUS_MOVE);
2407 }
2408
2409 if ((status & FRAME_STATUS_RESIZE) && window->shell_surface) {
2410 input_ungrab(input);
2411
2412 window->resizing = 1;
2413 wl_shell_surface_resize(window->shell_surface,
2414 input_get_seat(input),
2415 window->display->serial,
2416 location);
2417
2418 frame_status_clear(frame->frame, FRAME_STATUS_RESIZE);
2419 }
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002420}
Rob Bradford8bd35c72011-10-25 12:20:51 +01002421
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002422static void
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002423frame_button_handler(struct widget *widget,
2424 struct input *input, uint32_t time,
Daniel Stone4dbadb12012-05-30 16:31:51 +01002425 uint32_t button, enum wl_pointer_button_state state,
2426 void *data)
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002427
2428{
Jason Ekstrand3f66cf92013-10-13 19:08:40 -05002429 struct window_frame *frame = data;
2430 enum theme_location location;
Kristian Høgsberg1103a1a2012-04-03 12:00:48 -04002431
Jason Ekstrand3f66cf92013-10-13 19:08:40 -05002432 location = frame_pointer_button(frame->frame, input, button, state);
2433 frame_handle_status(frame, input, time, location);
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002434}
2435
Jason Ekstrand3f66cf92013-10-13 19:08:40 -05002436static void
Rusty Lynch1084da52013-08-15 09:10:08 -07002437frame_touch_down_handler(struct widget *widget, struct input *input,
2438 uint32_t serial, uint32_t time, int32_t id,
2439 float x, float y, void *data)
2440{
Jason Ekstrand3f66cf92013-10-13 19:08:40 -05002441 struct window_frame *frame = data;
2442
2443 frame_touch_down(frame->frame, input, id, x, y);
2444 frame_handle_status(frame, input, time, THEME_LOCATION_CLIENT_AREA);
2445}
2446
2447static void
2448frame_touch_up_handler(struct widget *widget,
2449 struct input *input, uint32_t serial, uint32_t time,
2450 int32_t id, void *data)
2451{
2452 struct window_frame *frame = data;
2453
2454 frame_touch_up(frame->frame, input, id);
2455 frame_handle_status(frame, input, time, THEME_LOCATION_CLIENT_AREA);
Rusty Lynch1084da52013-08-15 09:10:08 -07002456}
2457
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002458struct widget *
Jason Ekstrandee7fefc2013-10-13 19:08:38 -05002459window_frame_create(struct window *window, void *data)
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002460{
Jason Ekstrand3f66cf92013-10-13 19:08:40 -05002461 struct window_frame *frame;
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002462
Peter Huttererf3d62272013-08-08 11:57:05 +10002463 frame = xzalloc(sizeof *frame);
Jason Ekstrand3f66cf92013-10-13 19:08:40 -05002464 frame->frame = frame_create(window->display->theme, 0, 0,
2465 FRAME_BUTTON_ALL, window->title);
2466
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002467 frame->widget = window_add_widget(window, frame);
2468 frame->child = widget_add_widget(frame->widget, data);
Martin Minarik1998b152012-05-10 02:04:35 +02002469
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002470 widget_set_redraw_handler(frame->widget, frame_redraw_handler);
2471 widget_set_resize_handler(frame->widget, frame_resize_handler);
2472 widget_set_enter_handler(frame->widget, frame_enter_handler);
Jason Ekstrand3f66cf92013-10-13 19:08:40 -05002473 widget_set_leave_handler(frame->widget, frame_leave_handler);
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002474 widget_set_motion_handler(frame->widget, frame_motion_handler);
2475 widget_set_button_handler(frame->widget, frame_button_handler);
Rusty Lynch1084da52013-08-15 09:10:08 -07002476 widget_set_touch_down_handler(frame->widget, frame_touch_down_handler);
Jason Ekstrand3f66cf92013-10-13 19:08:40 -05002477 widget_set_touch_up_handler(frame->widget, frame_touch_up_handler);
Martin Minarik1998b152012-05-10 02:04:35 +02002478
Pekka Paalanen4dde2fc2012-01-19 13:33:50 +02002479 window->frame = frame;
2480
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002481 return frame->child;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04002482}
2483
Kristian Høgsberga1627922012-06-20 17:30:03 -04002484void
Jason Ekstrandee7fefc2013-10-13 19:08:38 -05002485window_frame_set_child_size(struct widget *widget, int child_width,
2486 int child_height)
Kristian Høgsberga1627922012-06-20 17:30:03 -04002487{
2488 struct display *display = widget->window->display;
2489 struct theme *t = display->theme;
2490 int decoration_width, decoration_height;
2491 int width, height;
Scott Moreauc6a7e4b2012-09-28 02:45:06 -06002492 int margin = widget->window->type == TYPE_MAXIMIZED ? 0 : t->margin;
Kristian Høgsberga1627922012-06-20 17:30:03 -04002493
2494 if (widget->window->type != TYPE_FULLSCREEN) {
Scott Moreauc6a7e4b2012-09-28 02:45:06 -06002495 decoration_width = (t->width + margin) * 2;
Kristian Høgsberga1627922012-06-20 17:30:03 -04002496 decoration_height = t->width +
Scott Moreauc6a7e4b2012-09-28 02:45:06 -06002497 t->titlebar_height + margin * 2;
Kristian Høgsberga1627922012-06-20 17:30:03 -04002498
2499 width = child_width + decoration_width;
2500 height = child_height + decoration_height;
2501 } else {
2502 width = child_width;
2503 height = child_height;
2504 }
2505
2506 window_schedule_resize(widget->window, width, height);
2507}
2508
Kristian Høgsberge4feb562008-11-08 18:53:37 -05002509static void
Jason Ekstrand3f66cf92013-10-13 19:08:40 -05002510window_frame_destroy(struct window_frame *frame)
Pekka Paalanen4dde2fc2012-01-19 13:33:50 +02002511{
Jason Ekstrand3f66cf92013-10-13 19:08:40 -05002512 frame_destroy(frame->frame);
Martin Minarik1998b152012-05-10 02:04:35 +02002513
Pekka Paalanen4dde2fc2012-01-19 13:33:50 +02002514 /* frame->child must be destroyed by the application */
2515 widget_destroy(frame->widget);
2516 free(frame);
2517}
2518
2519static void
Kristian Høgsbergb6323512012-01-11 00:04:42 -05002520input_set_focus_widget(struct input *input, struct widget *focus,
Kristian Høgsberg80680c72012-05-10 12:21:37 -04002521 float x, float y)
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04002522{
Kristian Høgsberg831dd522012-01-10 23:46:33 -05002523 struct widget *old, *widget;
Kristian Høgsbergbf74d522012-11-30 14:54:35 -05002524 int cursor;
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04002525
Kristian Høgsbergb6323512012-01-11 00:04:42 -05002526 if (focus == input->focus_widget)
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04002527 return;
2528
Kristian Høgsbergb6323512012-01-11 00:04:42 -05002529 old = input->focus_widget;
Kristian Høgsbergee143232012-01-09 08:42:24 -05002530 if (old) {
Kristian Høgsberg831dd522012-01-10 23:46:33 -05002531 widget = old;
2532 if (input->grab)
2533 widget = input->grab;
2534 if (widget->leave_handler)
2535 widget->leave_handler(old, input, widget->user_data);
Kristian Høgsbergb6323512012-01-11 00:04:42 -05002536 input->focus_widget = NULL;
Kristian Høgsbergee143232012-01-09 08:42:24 -05002537 }
2538
2539 if (focus) {
Kristian Høgsberg831dd522012-01-10 23:46:33 -05002540 widget = focus;
2541 if (input->grab)
2542 widget = input->grab;
Kristian Høgsbergf33984e2012-06-04 23:36:32 -04002543 input->focus_widget = focus;
Kristian Høgsberg831dd522012-01-10 23:46:33 -05002544 if (widget->enter_handler)
Kristian Høgsbergbf74d522012-11-30 14:54:35 -05002545 cursor = widget->enter_handler(focus, input, x, y,
2546 widget->user_data);
2547 else
2548 cursor = widget->default_cursor;
Kristian Høgsbergbb901fa2012-01-09 11:22:32 -05002549
Kristian Høgsbergbf74d522012-11-30 14:54:35 -05002550 input_set_pointer_image(input, cursor);
Kristian Høgsbergee143232012-01-09 08:42:24 -05002551 }
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04002552}
2553
Kristian Høgsbergb29798b2012-08-11 14:56:08 -04002554void
2555input_grab(struct input *input, struct widget *widget, uint32_t button)
2556{
2557 input->grab = widget;
2558 input->grab_button = button;
2559}
2560
2561void
2562input_ungrab(struct input *input)
2563{
2564 struct widget *widget;
2565
2566 input->grab = NULL;
2567 if (input->pointer_focus) {
Pekka Paalanenac95f3e2013-02-13 16:17:17 +02002568 widget = window_find_widget(input->pointer_focus,
Kristian Høgsbergb29798b2012-08-11 14:56:08 -04002569 input->sx, input->sy);
2570 input_set_focus_widget(input, widget, input->sx, input->sy);
2571 }
2572}
2573
2574static void
2575input_remove_pointer_focus(struct input *input)
2576{
2577 struct window *window = input->pointer_focus;
2578
2579 if (!window)
2580 return;
2581
2582 input_set_focus_widget(input, NULL, 0, 0);
2583
2584 input->pointer_focus = NULL;
2585 input->current_cursor = CURSOR_UNSET;
2586}
2587
2588static void
2589pointer_handle_enter(void *data, struct wl_pointer *pointer,
2590 uint32_t serial, struct wl_surface *surface,
2591 wl_fixed_t sx_w, wl_fixed_t sy_w)
2592{
2593 struct input *input = data;
2594 struct window *window;
2595 struct widget *widget;
2596 float sx = wl_fixed_to_double(sx_w);
2597 float sy = wl_fixed_to_double(sy_w);
2598
2599 if (!surface) {
2600 /* enter event for a window we've just destroyed */
2601 return;
2602 }
2603
2604 input->display->serial = serial;
2605 input->pointer_enter_serial = serial;
2606 input->pointer_focus = wl_surface_get_user_data(surface);
2607 window = input->pointer_focus;
2608
Pekka Paalanen99436862012-11-19 17:15:59 +02002609 if (window->resizing) {
2610 window->resizing = 0;
Kristian Høgsbergb29798b2012-08-11 14:56:08 -04002611 /* Schedule a redraw to free the pool */
2612 window_schedule_redraw(window);
2613 }
2614
2615 input->sx = sx;
2616 input->sy = sy;
2617
Pekka Paalanenac95f3e2013-02-13 16:17:17 +02002618 widget = window_find_widget(window, sx, sy);
Kristian Høgsbergb29798b2012-08-11 14:56:08 -04002619 input_set_focus_widget(input, widget, sx, sy);
2620}
2621
2622static void
2623pointer_handle_leave(void *data, struct wl_pointer *pointer,
2624 uint32_t serial, struct wl_surface *surface)
2625{
2626 struct input *input = data;
2627
2628 input->display->serial = serial;
2629 input_remove_pointer_focus(input);
2630}
2631
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04002632static void
Daniel Stone37816df2012-05-16 18:45:18 +01002633pointer_handle_motion(void *data, struct wl_pointer *pointer,
2634 uint32_t time, wl_fixed_t sx_w, wl_fixed_t sy_w)
Kristian Høgsberg61017b12008-11-02 18:51:48 -05002635{
Kristian Høgsberg808fd412010-07-20 17:06:19 -04002636 struct input *input = data;
Kristian Høgsberg9a686242010-08-18 15:28:04 -04002637 struct window *window = input->pointer_focus;
Kristian Høgsbergc51f7992012-01-08 15:09:53 -05002638 struct widget *widget;
Kristian Høgsbergbf74d522012-11-30 14:54:35 -05002639 int cursor;
Kristian Høgsberg80680c72012-05-10 12:21:37 -04002640 float sx = wl_fixed_to_double(sx_w);
2641 float sy = wl_fixed_to_double(sy_w);
Kristian Høgsberg808fd412010-07-20 17:06:19 -04002642
Paul Winwoodb22bf572013-08-29 10:52:54 +01002643 input->sx = sx;
2644 input->sy = sy;
2645
2646 if (!window)
2647 return;
2648
Rob Bradford5f087742013-07-11 19:41:27 +01002649 /* when making the window smaller - e.g. after a unmaximise we might
2650 * still have a pending motion event that the compositor has picked
2651 * based on the old surface dimensions
2652 */
2653 if (sx > window->main_surface->allocation.width ||
2654 sy > window->main_surface->allocation.height)
2655 return;
2656
Kristian Høgsberg831dd522012-01-10 23:46:33 -05002657 if (!(input->grab && input->grab_button)) {
Pekka Paalanenac95f3e2013-02-13 16:17:17 +02002658 widget = window_find_widget(window, sx, sy);
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04002659 input_set_focus_widget(input, widget, sx, sy);
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04002660 }
2661
Kristian Høgsberg831dd522012-01-10 23:46:33 -05002662 if (input->grab)
2663 widget = input->grab;
2664 else
Kristian Høgsbergb6323512012-01-11 00:04:42 -05002665 widget = input->focus_widget;
Kristian Høgsberg1a5f0c32013-08-15 14:15:18 -07002666 if (widget) {
2667 if (widget->motion_handler)
2668 cursor = widget->motion_handler(input->focus_widget,
2669 input, time, sx, sy,
2670 widget->user_data);
2671 else
2672 cursor = widget->default_cursor;
2673 } else
2674 cursor = CURSOR_LEFT_PTR;
Kristian Høgsberg9a686242010-08-18 15:28:04 -04002675
Kristian Høgsberg5a4e9ff2012-06-04 16:04:07 -04002676 input_set_pointer_image(input, cursor);
Kristian Høgsberg61017b12008-11-02 18:51:48 -05002677}
2678
Kristian Høgsberg1d7ffd32010-08-25 16:34:05 -04002679static void
Daniel Stone37816df2012-05-16 18:45:18 +01002680pointer_handle_button(void *data, struct wl_pointer *pointer, uint32_t serial,
Daniel Stone4dbadb12012-05-30 16:31:51 +01002681 uint32_t time, uint32_t button, uint32_t state_w)
Kristian Høgsberg94448c02008-12-30 11:03:33 -05002682{
Kristian Høgsberg808fd412010-07-20 17:06:19 -04002683 struct input *input = data;
Kristian Høgsbergc51f7992012-01-08 15:09:53 -05002684 struct widget *widget;
Daniel Stone4dbadb12012-05-30 16:31:51 +01002685 enum wl_pointer_button_state state = state_w;
Kristian Høgsbergbf6ceda2010-06-14 20:25:06 -04002686
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04002687 input->display->serial = serial;
Daniel Stone4dbadb12012-05-30 16:31:51 +01002688 if (input->focus_widget && input->grab == NULL &&
2689 state == WL_POINTER_BUTTON_STATE_PRESSED)
Kristian Høgsbergb6323512012-01-11 00:04:42 -05002690 input_grab(input, input->focus_widget, button);
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04002691
Neil Roberts6b28aad2012-01-23 19:11:18 +00002692 widget = input->grab;
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002693 if (widget && widget->button_handler)
Neil Roberts6b28aad2012-01-23 19:11:18 +00002694 (*widget->button_handler)(widget,
2695 input, time,
2696 button, state,
2697 input->grab->user_data);
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04002698
Daniel Stone4dbadb12012-05-30 16:31:51 +01002699 if (input->grab && input->grab_button == button &&
2700 state == WL_POINTER_BUTTON_STATE_RELEASED)
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04002701 input_ungrab(input);
Kristian Høgsberg94448c02008-12-30 11:03:33 -05002702}
2703
Kristian Høgsberg99f090d2009-02-23 22:37:14 -05002704static void
Daniel Stone37816df2012-05-16 18:45:18 +01002705pointer_handle_axis(void *data, struct wl_pointer *pointer,
Daniel Stone2fce4022012-05-30 16:32:00 +01002706 uint32_t time, uint32_t axis, wl_fixed_t value)
Scott Moreau210d0792012-03-22 10:47:01 -06002707{
Philipp Brüschweiler7e0cc542012-08-14 11:02:41 +02002708 struct input *input = data;
2709 struct widget *widget;
2710
2711 widget = input->focus_widget;
2712 if (input->grab)
2713 widget = input->grab;
2714 if (widget && widget->axis_handler)
2715 (*widget->axis_handler)(widget,
2716 input, time,
2717 axis, value,
2718 widget->user_data);
Scott Moreau210d0792012-03-22 10:47:01 -06002719}
2720
Kristian Høgsbergb29798b2012-08-11 14:56:08 -04002721static const struct wl_pointer_listener pointer_listener = {
2722 pointer_handle_enter,
2723 pointer_handle_leave,
2724 pointer_handle_motion,
2725 pointer_handle_button,
2726 pointer_handle_axis,
2727};
2728
2729static void
2730input_remove_keyboard_focus(struct input *input)
2731{
2732 struct window *window = input->keyboard_focus;
2733 struct itimerspec its;
2734
2735 its.it_interval.tv_sec = 0;
2736 its.it_interval.tv_nsec = 0;
2737 its.it_value.tv_sec = 0;
2738 its.it_value.tv_nsec = 0;
2739 timerfd_settime(input->repeat_timer_fd, 0, &its, NULL);
2740
2741 if (!window)
2742 return;
2743
Kristian Høgsberg86adef92012-08-13 22:25:53 -04002744 window->focus_count--;
Kristian Høgsbergb29798b2012-08-11 14:56:08 -04002745 if (window->keyboard_focus_handler)
2746 (*window->keyboard_focus_handler)(window, NULL,
2747 window->user_data);
2748
2749 input->keyboard_focus = NULL;
2750}
2751
2752static void
2753keyboard_repeat_func(struct task *task, uint32_t events)
2754{
2755 struct input *input =
2756 container_of(task, struct input, repeat_task);
2757 struct window *window = input->keyboard_focus;
2758 uint64_t exp;
2759
2760 if (read(input->repeat_timer_fd, &exp, sizeof exp) != sizeof exp)
2761 /* If we change the timer between the fd becoming
2762 * readable and getting here, there'll be nothing to
2763 * read and we get EAGAIN. */
2764 return;
2765
2766 if (window && window->key_handler) {
2767 (*window->key_handler)(window, input, input->repeat_time,
2768 input->repeat_key, input->repeat_sym,
2769 WL_KEYBOARD_KEY_STATE_PRESSED,
2770 window->user_data);
2771 }
2772}
2773
2774static void
2775keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
2776 uint32_t format, int fd, uint32_t size)
2777{
2778 struct input *input = data;
Rui Matos3eccb862013-10-10 19:44:22 +02002779 struct xkb_keymap *keymap;
2780 struct xkb_state *state;
Kristian Høgsbergb29798b2012-08-11 14:56:08 -04002781 char *map_str;
2782
2783 if (!data) {
2784 close(fd);
2785 return;
2786 }
2787
2788 if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
2789 close(fd);
2790 return;
2791 }
2792
2793 map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
2794 if (map_str == MAP_FAILED) {
2795 close(fd);
2796 return;
2797 }
2798
Rui Matos3eccb862013-10-10 19:44:22 +02002799 keymap = xkb_map_new_from_string(input->display->xkb_context,
2800 map_str,
2801 XKB_KEYMAP_FORMAT_TEXT_V1,
2802 0);
Kristian Høgsbergb29798b2012-08-11 14:56:08 -04002803 munmap(map_str, size);
2804 close(fd);
2805
Rui Matos3eccb862013-10-10 19:44:22 +02002806 if (!keymap) {
Kristian Høgsbergb29798b2012-08-11 14:56:08 -04002807 fprintf(stderr, "failed to compile keymap\n");
2808 return;
2809 }
2810
Rui Matos3eccb862013-10-10 19:44:22 +02002811 state = xkb_state_new(keymap);
2812 if (!state) {
Kristian Høgsbergb29798b2012-08-11 14:56:08 -04002813 fprintf(stderr, "failed to create XKB state\n");
Rui Matos3eccb862013-10-10 19:44:22 +02002814 xkb_map_unref(keymap);
Kristian Høgsbergb29798b2012-08-11 14:56:08 -04002815 return;
2816 }
2817
Rui Matos3eccb862013-10-10 19:44:22 +02002818 xkb_keymap_unref(input->xkb.keymap);
2819 xkb_state_unref(input->xkb.state);
2820 input->xkb.keymap = keymap;
2821 input->xkb.state = state;
2822
Kristian Høgsbergb29798b2012-08-11 14:56:08 -04002823 input->xkb.control_mask =
2824 1 << xkb_map_mod_get_index(input->xkb.keymap, "Control");
2825 input->xkb.alt_mask =
2826 1 << xkb_map_mod_get_index(input->xkb.keymap, "Mod1");
2827 input->xkb.shift_mask =
2828 1 << xkb_map_mod_get_index(input->xkb.keymap, "Shift");
2829}
2830
2831static void
2832keyboard_handle_enter(void *data, struct wl_keyboard *keyboard,
2833 uint32_t serial, struct wl_surface *surface,
2834 struct wl_array *keys)
2835{
2836 struct input *input = data;
2837 struct window *window;
2838
2839 input->display->serial = serial;
2840 input->keyboard_focus = wl_surface_get_user_data(surface);
2841
2842 window = input->keyboard_focus;
Kristian Høgsberg86adef92012-08-13 22:25:53 -04002843 window->focus_count++;
Kristian Høgsbergb29798b2012-08-11 14:56:08 -04002844 if (window->keyboard_focus_handler)
2845 (*window->keyboard_focus_handler)(window,
Kristian Høgsberg86adef92012-08-13 22:25:53 -04002846 input, window->user_data);
Kristian Høgsbergb29798b2012-08-11 14:56:08 -04002847}
2848
2849static void
2850keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
2851 uint32_t serial, struct wl_surface *surface)
2852{
2853 struct input *input = data;
2854
2855 input->display->serial = serial;
2856 input_remove_keyboard_focus(input);
2857}
2858
Scott Moreau210d0792012-03-22 10:47:01 -06002859static void
Daniel Stone37816df2012-05-16 18:45:18 +01002860keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
Daniel Stonec9785ea2012-05-30 16:31:52 +01002861 uint32_t serial, uint32_t time, uint32_t key,
2862 uint32_t state_w)
Kristian Høgsberg99f090d2009-02-23 22:37:14 -05002863{
Kristian Høgsberg808fd412010-07-20 17:06:19 -04002864 struct input *input = data;
2865 struct window *window = input->keyboard_focus;
Kristian Høgsberg70163132012-05-08 15:55:39 -04002866 uint32_t code, num_syms;
Daniel Stonec9785ea2012-05-30 16:31:52 +01002867 enum wl_keyboard_key_state state = state_w;
Kristian Høgsberg70163132012-05-08 15:55:39 -04002868 const xkb_keysym_t *syms;
2869 xkb_keysym_t sym;
Kristian Høgsbergcf4d2442012-06-20 14:52:12 -04002870 struct itimerspec its;
Kristian Høgsberg99f090d2009-02-23 22:37:14 -05002871
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04002872 input->display->serial = serial;
Daniel Stone0d5a5092012-02-16 12:48:00 +00002873 code = key + 8;
Kristian Høgsberg86adef92012-08-13 22:25:53 -04002874 if (!window || !input->xkb.state)
Kristian Høgsberg99f090d2009-02-23 22:37:14 -05002875 return;
2876
Daniel Stone97f68542012-05-30 16:32:01 +01002877 num_syms = xkb_key_get_syms(input->xkb.state, code, &syms);
Kristian Høgsberg99f090d2009-02-23 22:37:14 -05002878
Kristian Høgsbergcf4d2442012-06-20 14:52:12 -04002879 sym = XKB_KEY_NoSymbol;
2880 if (num_syms == 1)
2881 sym = syms[0];
2882
2883 if (sym == XKB_KEY_F5 && input->modifiers == MOD_ALT_MASK) {
Daniel Stonec9785ea2012-05-30 16:31:52 +01002884 if (state == WL_KEYBOARD_KEY_STATE_PRESSED)
Kristian Høgsbergd6bcd7d2012-02-16 15:53:46 -05002885 window_set_maximized(window,
2886 window->type != TYPE_MAXIMIZED);
Kristian Høgsberg67ace202012-07-23 21:56:31 -04002887 } else if (sym == XKB_KEY_F11 &&
2888 window->fullscreen_handler &&
2889 state == WL_KEYBOARD_KEY_STATE_PRESSED) {
2890 window->fullscreen_handler(window, window->user_data);
Kristian Høgsberg4fc15352012-07-25 16:35:28 -04002891 } else if (sym == XKB_KEY_F4 &&
2892 input->modifiers == MOD_ALT_MASK &&
2893 state == WL_KEYBOARD_KEY_STATE_PRESSED) {
2894 if (window->close_handler)
2895 window->close_handler(window->parent,
2896 window->user_data);
2897 else
2898 display_exit(window->display);
Kristian Høgsbergd6bcd7d2012-02-16 15:53:46 -05002899 } else if (window->key_handler) {
2900 (*window->key_handler)(window, input, time, key,
2901 sym, state, window->user_data);
2902 }
Kristian Høgsbergcf4d2442012-06-20 14:52:12 -04002903
2904 if (state == WL_KEYBOARD_KEY_STATE_RELEASED &&
2905 key == input->repeat_key) {
2906 its.it_interval.tv_sec = 0;
2907 its.it_interval.tv_nsec = 0;
2908 its.it_value.tv_sec = 0;
2909 its.it_value.tv_nsec = 0;
2910 timerfd_settime(input->repeat_timer_fd, 0, &its, NULL);
2911 } else if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
2912 input->repeat_sym = sym;
2913 input->repeat_key = key;
2914 input->repeat_time = time;
2915 its.it_interval.tv_sec = 0;
2916 its.it_interval.tv_nsec = 25 * 1000 * 1000;
2917 its.it_value.tv_sec = 0;
2918 its.it_value.tv_nsec = 400 * 1000 * 1000;
2919 timerfd_settime(input->repeat_timer_fd, 0, &its, NULL);
2920 }
2921}
2922
2923static void
Daniel Stone351eb612012-05-31 15:27:47 -04002924keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard,
2925 uint32_t serial, uint32_t mods_depressed,
2926 uint32_t mods_latched, uint32_t mods_locked,
2927 uint32_t group)
2928{
2929 struct input *input = data;
Jonas Ådahld9f6b072012-09-27 18:40:45 +02002930 xkb_mod_mask_t mask;
Daniel Stone351eb612012-05-31 15:27:47 -04002931
Matt Ropere61561f2013-06-24 16:52:43 +01002932 /* If we're not using a keymap, then we don't handle PC-style modifiers */
2933 if (!input->xkb.keymap)
2934 return;
2935
Daniel Stoneb7452fe2012-06-01 12:14:06 +01002936 xkb_state_update_mask(input->xkb.state, mods_depressed, mods_latched,
2937 mods_locked, 0, 0, group);
Jonas Ådahld9f6b072012-09-27 18:40:45 +02002938 mask = xkb_state_serialize_mods(input->xkb.state,
2939 XKB_STATE_DEPRESSED |
2940 XKB_STATE_LATCHED);
2941 input->modifiers = 0;
2942 if (mask & input->xkb.control_mask)
2943 input->modifiers |= MOD_CONTROL_MASK;
2944 if (mask & input->xkb.alt_mask)
2945 input->modifiers |= MOD_ALT_MASK;
2946 if (mask & input->xkb.shift_mask)
2947 input->modifiers |= MOD_SHIFT_MASK;
Daniel Stone351eb612012-05-31 15:27:47 -04002948}
2949
Daniel Stone37816df2012-05-16 18:45:18 +01002950static const struct wl_keyboard_listener keyboard_listener = {
Daniel Stoneb7452fe2012-06-01 12:14:06 +01002951 keyboard_handle_keymap,
Daniel Stone37816df2012-05-16 18:45:18 +01002952 keyboard_handle_enter,
2953 keyboard_handle_leave,
2954 keyboard_handle_key,
Daniel Stone351eb612012-05-31 15:27:47 -04002955 keyboard_handle_modifiers,
Daniel Stone37816df2012-05-16 18:45:18 +01002956};
Kristian Høgsberge04ad572011-12-21 17:14:54 -05002957
2958static void
Rusty Lynch041815a2013-08-08 21:20:38 -07002959touch_handle_down(void *data, struct wl_touch *wl_touch,
2960 uint32_t serial, uint32_t time, struct wl_surface *surface,
2961 int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
2962{
2963 struct input *input = data;
2964 struct widget *widget;
2965 float sx = wl_fixed_to_double(x_w);
2966 float sy = wl_fixed_to_double(y_w);
2967
Rusty Lynch1084da52013-08-15 09:10:08 -07002968 input->display->serial = serial;
Rusty Lynch041815a2013-08-08 21:20:38 -07002969 input->touch_focus = wl_surface_get_user_data(surface);
2970 if (!input->touch_focus) {
2971 DBG("Failed to find to touch focus for surface %p\n", surface);
2972 return;
2973 }
2974
2975 widget = window_find_widget(input->touch_focus,
2976 wl_fixed_to_double(x_w),
2977 wl_fixed_to_double(y_w));
2978 if (widget) {
2979 struct touch_point *tp = xmalloc(sizeof *tp);
2980 if (tp) {
2981 tp->id = id;
2982 tp->widget = widget;
2983 wl_list_insert(&input->touch_point_list, &tp->link);
2984
2985 if (widget->touch_down_handler)
Rusty Lynch1084da52013-08-15 09:10:08 -07002986 (*widget->touch_down_handler)(widget, input,
2987 serial, time, id,
Rusty Lynch041815a2013-08-08 21:20:38 -07002988 sx, sy,
2989 widget->user_data);
2990 }
2991 }
2992}
2993
2994static void
2995touch_handle_up(void *data, struct wl_touch *wl_touch,
2996 uint32_t serial, uint32_t time, int32_t id)
2997{
2998 struct input *input = data;
2999 struct touch_point *tp, *tmp;
3000
Rusty Lynch041815a2013-08-08 21:20:38 -07003001 if (!input->touch_focus) {
3002 DBG("No touch focus found for touch up event!\n");
3003 return;
3004 }
3005
3006 wl_list_for_each_safe(tp, tmp, &input->touch_point_list, link) {
3007 if (tp->id != id)
3008 continue;
3009
3010 if (tp->widget->touch_up_handler)
Rusty Lynch1084da52013-08-15 09:10:08 -07003011 (*tp->widget->touch_up_handler)(tp->widget, input, serial,
Rusty Lynch041815a2013-08-08 21:20:38 -07003012 time, id,
3013 tp->widget->user_data);
3014
3015 wl_list_remove(&tp->link);
3016 free(tp);
3017
3018 return;
3019 }
3020}
3021
3022static void
3023touch_handle_motion(void *data, struct wl_touch *wl_touch,
3024 uint32_t time, int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
3025{
3026 struct input *input = data;
3027 struct touch_point *tp;
3028 float sx = wl_fixed_to_double(x_w);
3029 float sy = wl_fixed_to_double(y_w);
3030
3031 DBG("touch_handle_motion: %i %i\n", id, wl_list_length(&input->touch_point_list));
3032
3033 if (!input->touch_focus) {
3034 DBG("No touch focus found for touch motion event!\n");
3035 return;
3036 }
3037
3038 wl_list_for_each(tp, &input->touch_point_list, link) {
3039 if (tp->id != id)
3040 continue;
3041
3042 if (tp->widget->touch_motion_handler)
Rusty Lynch1084da52013-08-15 09:10:08 -07003043 (*tp->widget->touch_motion_handler)(tp->widget, input, time,
Rusty Lynch041815a2013-08-08 21:20:38 -07003044 id, sx, sy,
3045 tp->widget->user_data);
3046 return;
3047 }
3048}
3049
3050static void
3051touch_handle_frame(void *data, struct wl_touch *wl_touch)
3052{
3053 struct input *input = data;
3054 struct touch_point *tp, *tmp;
3055
3056 DBG("touch_handle_frame\n");
3057
3058 if (!input->touch_focus) {
3059 DBG("No touch focus found for touch frame event!\n");
3060 return;
3061 }
3062
3063 wl_list_for_each_safe(tp, tmp, &input->touch_point_list, link) {
3064 if (tp->widget->touch_frame_handler)
Rusty Lynch1084da52013-08-15 09:10:08 -07003065 (*tp->widget->touch_frame_handler)(tp->widget, input,
3066 tp->widget->user_data);
Rusty Lynch041815a2013-08-08 21:20:38 -07003067
3068 wl_list_remove(&tp->link);
3069 free(tp);
3070 }
3071}
3072
3073static void
3074touch_handle_cancel(void *data, struct wl_touch *wl_touch)
3075{
3076 struct input *input = data;
3077 struct touch_point *tp, *tmp;
3078
3079 DBG("touch_handle_cancel\n");
3080
3081 if (!input->touch_focus) {
3082 DBG("No touch focus found for touch cancel event!\n");
3083 return;
3084 }
3085
3086 wl_list_for_each_safe(tp, tmp, &input->touch_point_list, link) {
3087 if (tp->widget->touch_cancel_handler)
Rusty Lynch1084da52013-08-15 09:10:08 -07003088 (*tp->widget->touch_cancel_handler)(tp->widget, input,
3089 tp->widget->user_data);
Rusty Lynch041815a2013-08-08 21:20:38 -07003090
3091 wl_list_remove(&tp->link);
3092 free(tp);
3093 }
3094}
3095
3096static const struct wl_touch_listener touch_listener = {
3097 touch_handle_down,
3098 touch_handle_up,
3099 touch_handle_motion,
3100 touch_handle_frame,
3101 touch_handle_cancel,
3102};
3103
3104static void
Daniel Stone37816df2012-05-16 18:45:18 +01003105seat_handle_capabilities(void *data, struct wl_seat *seat,
3106 enum wl_seat_capability caps)
Kristian Høgsberge04ad572011-12-21 17:14:54 -05003107{
Daniel Stone37816df2012-05-16 18:45:18 +01003108 struct input *input = data;
3109
3110 if ((caps & WL_SEAT_CAPABILITY_POINTER) && !input->pointer) {
3111 input->pointer = wl_seat_get_pointer(seat);
3112 wl_pointer_set_user_data(input->pointer, input);
3113 wl_pointer_add_listener(input->pointer, &pointer_listener,
3114 input);
3115 } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && input->pointer) {
3116 wl_pointer_destroy(input->pointer);
3117 input->pointer = NULL;
3118 }
3119
3120 if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !input->keyboard) {
3121 input->keyboard = wl_seat_get_keyboard(seat);
3122 wl_keyboard_set_user_data(input->keyboard, input);
3123 wl_keyboard_add_listener(input->keyboard, &keyboard_listener,
3124 input);
3125 } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && input->keyboard) {
3126 wl_keyboard_destroy(input->keyboard);
3127 input->keyboard = NULL;
3128 }
Rusty Lynch041815a2013-08-08 21:20:38 -07003129
3130 if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !input->touch) {
3131 input->touch = wl_seat_get_touch(seat);
3132 wl_touch_set_user_data(input->touch, input);
3133 wl_touch_add_listener(input->touch, &touch_listener, input);
3134 } else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && input->touch) {
3135 wl_touch_destroy(input->touch);
3136 input->touch = NULL;
3137 }
Kristian Høgsberge04ad572011-12-21 17:14:54 -05003138}
3139
Rob Bradford08031182013-08-13 20:11:03 +01003140static void
3141seat_handle_name(void *data, struct wl_seat *seat,
3142 const char *name)
3143{
3144
3145}
3146
Daniel Stone37816df2012-05-16 18:45:18 +01003147static const struct wl_seat_listener seat_listener = {
3148 seat_handle_capabilities,
Rob Bradford08031182013-08-13 20:11:03 +01003149 seat_handle_name
Kristian Høgsberg94448c02008-12-30 11:03:33 -05003150};
3151
Kristian Høgsberg9a686242010-08-18 15:28:04 -04003152void
3153input_get_position(struct input *input, int32_t *x, int32_t *y)
3154{
3155 *x = input->sx;
3156 *y = input->sy;
3157}
3158
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04003159struct display *
3160input_get_display(struct input *input)
3161{
3162 return input->display;
3163}
3164
Daniel Stone37816df2012-05-16 18:45:18 +01003165struct wl_seat *
3166input_get_seat(struct input *input)
Kristian Høgsberg1d7ffd32010-08-25 16:34:05 -04003167{
Daniel Stone37816df2012-05-16 18:45:18 +01003168 return input->seat;
Kristian Høgsberg1d7ffd32010-08-25 16:34:05 -04003169}
3170
Kristian Høgsberg67cac8a2011-01-19 14:20:33 -05003171uint32_t
3172input_get_modifiers(struct input *input)
3173{
3174 return input->modifiers;
3175}
3176
Kristian Høgsbergb6323512012-01-11 00:04:42 -05003177struct widget *
3178input_get_focus_widget(struct input *input)
3179{
3180 return input->focus_widget;
3181}
3182
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04003183struct data_offer {
3184 struct wl_data_offer *offer;
3185 struct input *input;
3186 struct wl_array types;
3187 int refcount;
Kristian Høgsberg9a686242010-08-18 15:28:04 -04003188
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04003189 struct task io_task;
3190 int fd;
3191 data_func_t func;
3192 int32_t x, y;
3193 void *user_data;
3194};
3195
3196static void
3197data_offer_offer(void *data, struct wl_data_offer *wl_data_offer, const char *type)
3198{
3199 struct data_offer *offer = data;
3200 char **p;
3201
3202 p = wl_array_add(&offer->types, sizeof *p);
3203 *p = strdup(type);
3204}
3205
3206static const struct wl_data_offer_listener data_offer_listener = {
3207 data_offer_offer,
3208};
3209
3210static void
3211data_offer_destroy(struct data_offer *offer)
3212{
3213 char **p;
3214
3215 offer->refcount--;
3216 if (offer->refcount == 0) {
3217 wl_data_offer_destroy(offer->offer);
3218 for (p = offer->types.data; *p; p++)
3219 free(*p);
3220 wl_array_release(&offer->types);
3221 free(offer);
3222 }
3223}
3224
3225static void
3226data_device_data_offer(void *data,
Kristian Høgsberg8733b332012-06-28 22:04:06 -04003227 struct wl_data_device *data_device,
3228 struct wl_data_offer *_offer)
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04003229{
3230 struct data_offer *offer;
3231
Brian Lovinbc919262013-08-07 15:34:59 -07003232 offer = xmalloc(sizeof *offer);
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04003233
3234 wl_array_init(&offer->types);
3235 offer->refcount = 1;
3236 offer->input = data;
Kristian Høgsberg8733b332012-06-28 22:04:06 -04003237 offer->offer = _offer;
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04003238 wl_data_offer_add_listener(offer->offer,
3239 &data_offer_listener, offer);
3240}
3241
3242static void
3243data_device_enter(void *data, struct wl_data_device *data_device,
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04003244 uint32_t serial, struct wl_surface *surface,
Daniel Stone103db7f2012-05-08 17:17:55 +01003245 wl_fixed_t x_w, wl_fixed_t y_w,
3246 struct wl_data_offer *offer)
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04003247{
3248 struct input *input = data;
3249 struct window *window;
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +03003250 void *types_data;
Kristian Høgsberg80680c72012-05-10 12:21:37 -04003251 float x = wl_fixed_to_double(x_w);
3252 float y = wl_fixed_to_double(y_w);
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04003253 char **p;
3254
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04003255 input->pointer_enter_serial = serial;
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04003256 window = wl_surface_get_user_data(surface);
3257 input->pointer_focus = window;
3258
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +03003259 if (offer) {
3260 input->drag_offer = wl_data_offer_get_user_data(offer);
3261
3262 p = wl_array_add(&input->drag_offer->types, sizeof *p);
3263 *p = NULL;
3264
3265 types_data = input->drag_offer->types.data;
3266 } else {
3267 input->drag_offer = NULL;
3268 types_data = NULL;
3269 }
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04003270
3271 window = input->pointer_focus;
3272 if (window->data_handler)
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +03003273 window->data_handler(window, input, x, y, types_data,
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04003274 window->user_data);
3275}
3276
3277static void
3278data_device_leave(void *data, struct wl_data_device *data_device)
3279{
3280 struct input *input = data;
3281
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +03003282 if (input->drag_offer) {
3283 data_offer_destroy(input->drag_offer);
3284 input->drag_offer = NULL;
3285 }
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04003286}
3287
3288static void
3289data_device_motion(void *data, struct wl_data_device *data_device,
Daniel Stone103db7f2012-05-08 17:17:55 +01003290 uint32_t time, wl_fixed_t x_w, wl_fixed_t y_w)
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04003291{
3292 struct input *input = data;
3293 struct window *window = input->pointer_focus;
Kristian Høgsberg80680c72012-05-10 12:21:37 -04003294 float x = wl_fixed_to_double(x_w);
3295 float y = wl_fixed_to_double(y_w);
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +03003296 void *types_data;
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04003297
3298 input->sx = x;
3299 input->sy = y;
3300
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +03003301 if (input->drag_offer)
3302 types_data = input->drag_offer->types.data;
3303 else
3304 types_data = NULL;
3305
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04003306 if (window->data_handler)
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +03003307 window->data_handler(window, input, x, y, types_data,
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04003308 window->user_data);
3309}
3310
3311static void
3312data_device_drop(void *data, struct wl_data_device *data_device)
3313{
3314 struct input *input = data;
3315 struct window *window = input->pointer_focus;
3316
3317 if (window->drop_handler)
3318 window->drop_handler(window, input,
3319 input->sx, input->sy, window->user_data);
3320}
3321
3322static void
3323data_device_selection(void *data,
3324 struct wl_data_device *wl_data_device,
3325 struct wl_data_offer *offer)
3326{
3327 struct input *input = data;
3328 char **p;
3329
3330 if (input->selection_offer)
3331 data_offer_destroy(input->selection_offer);
3332
Kristian Høgsberg42c8f602012-01-27 11:04:18 -05003333 if (offer) {
3334 input->selection_offer = wl_data_offer_get_user_data(offer);
3335 p = wl_array_add(&input->selection_offer->types, sizeof *p);
3336 *p = NULL;
Kristian Høgsberga4b3d0e2012-05-31 23:30:32 -04003337 } else {
3338 input->selection_offer = NULL;
Kristian Høgsberg42c8f602012-01-27 11:04:18 -05003339 }
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04003340}
3341
3342static const struct wl_data_device_listener data_device_listener = {
3343 data_device_data_offer,
3344 data_device_enter,
3345 data_device_leave,
3346 data_device_motion,
3347 data_device_drop,
3348 data_device_selection
3349};
3350
Ander Conselvan de Oliveira80620072012-06-15 17:27:36 +03003351static void
3352input_set_pointer_image_index(struct input *input, int index)
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05003353{
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05003354 struct wl_buffer *buffer;
Ander Conselvan de Oliveira1042dc12012-05-22 15:39:42 +03003355 struct wl_cursor *cursor;
3356 struct wl_cursor_image *image;
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05003357
Daniel Stone80972742012-11-07 17:51:39 +11003358 if (!input->pointer)
3359 return;
3360
Ander Conselvan de Oliveira80620072012-06-15 17:27:36 +03003361 cursor = input->display->cursors[input->current_cursor];
Ander Conselvan de Oliveira1042dc12012-05-22 15:39:42 +03003362 if (!cursor)
Dima Ryazanovff1c2d72012-05-08 21:02:33 -07003363 return;
3364
Kristian Høgsberg7cee1972012-06-04 23:37:42 -04003365 if (index >= (int) cursor->image_count) {
3366 fprintf(stderr, "cursor index out of range\n");
3367 return;
3368 }
3369
3370 image = cursor->images[index];
Ander Conselvan de Oliveira1042dc12012-05-22 15:39:42 +03003371 buffer = wl_cursor_image_get_buffer(image);
3372 if (!buffer)
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05003373 return;
3374
Kristian Høgsbergae277372012-08-01 09:41:08 -04003375 wl_pointer_set_cursor(input->pointer, input->pointer_enter_serial,
Ander Conselvan de Oliveira37ffc3c2012-06-15 17:27:35 +03003376 input->pointer_surface,
3377 image->hotspot_x, image->hotspot_y);
3378 wl_surface_attach(input->pointer_surface, buffer, 0, 0);
3379 wl_surface_damage(input->pointer_surface, 0, 0,
3380 image->width, image->height);
Pekka Paalanenc9e00c02012-10-10 12:49:24 +03003381 wl_surface_commit(input->pointer_surface);
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05003382}
3383
Ander Conselvan de Oliveira80620072012-06-15 17:27:36 +03003384static const struct wl_callback_listener pointer_surface_listener;
3385
3386static void
3387pointer_surface_frame_callback(void *data, struct wl_callback *callback,
3388 uint32_t time)
3389{
3390 struct input *input = data;
Daniel Stonea494f1d2012-06-18 19:31:12 +01003391 struct wl_cursor *cursor;
Ander Conselvan de Oliveira80620072012-06-15 17:27:36 +03003392 int i;
3393
3394 if (callback) {
3395 assert(callback == input->cursor_frame_cb);
3396 wl_callback_destroy(callback);
3397 input->cursor_frame_cb = NULL;
3398 }
3399
Daniel Stone80972742012-11-07 17:51:39 +11003400 if (!input->pointer)
3401 return;
3402
Kristian Høgsbergf3370522012-06-20 23:04:41 -04003403 if (input->current_cursor == CURSOR_BLANK) {
Kristian Høgsbergae277372012-08-01 09:41:08 -04003404 wl_pointer_set_cursor(input->pointer,
3405 input->pointer_enter_serial,
Kristian Høgsbergf3370522012-06-20 23:04:41 -04003406 NULL, 0, 0);
3407 return;
3408 }
3409
Ander Conselvan de Oliveira80620072012-06-15 17:27:36 +03003410 if (input->current_cursor == CURSOR_UNSET)
3411 return;
Daniel Stonea494f1d2012-06-18 19:31:12 +01003412 cursor = input->display->cursors[input->current_cursor];
3413 if (!cursor)
3414 return;
Ander Conselvan de Oliveira80620072012-06-15 17:27:36 +03003415
3416 /* FIXME We don't have the current time on the first call so we set
3417 * the animation start to the time of the first frame callback. */
3418 if (time == 0)
3419 input->cursor_anim_start = 0;
3420 else if (input->cursor_anim_start == 0)
3421 input->cursor_anim_start = time;
3422
3423 if (time == 0 || input->cursor_anim_start == 0)
3424 i = 0;
3425 else
3426 i = wl_cursor_frame(cursor, time - input->cursor_anim_start);
3427
Pekka Paalanenbc106382012-10-10 12:49:31 +03003428 if (cursor->image_count > 1) {
3429 input->cursor_frame_cb =
3430 wl_surface_frame(input->pointer_surface);
3431 wl_callback_add_listener(input->cursor_frame_cb,
3432 &pointer_surface_listener, input);
3433 }
3434
Ander Conselvan de Oliveira80620072012-06-15 17:27:36 +03003435 input_set_pointer_image_index(input, i);
Ander Conselvan de Oliveira80620072012-06-15 17:27:36 +03003436}
3437
3438static const struct wl_callback_listener pointer_surface_listener = {
3439 pointer_surface_frame_callback
3440};
3441
Kristian Høgsberg7cee1972012-06-04 23:37:42 -04003442void
3443input_set_pointer_image(struct input *input, int pointer)
3444{
Ander Conselvan de Oliveiraddca4962012-07-16 14:15:49 +03003445 int force = 0;
3446
Kristian Høgsberge530a0a2012-10-29 16:42:26 -04003447 if (!input->pointer)
3448 return;
3449
Ander Conselvan de Oliveiraddca4962012-07-16 14:15:49 +03003450 if (input->pointer_enter_serial > input->cursor_serial)
3451 force = 1;
3452
3453 if (!force && pointer == input->current_cursor)
Kristian Høgsberg7cee1972012-06-04 23:37:42 -04003454 return;
3455
Ander Conselvan de Oliveira80620072012-06-15 17:27:36 +03003456 input->current_cursor = pointer;
Kristian Høgsberg11f600d2012-06-22 10:52:58 -04003457 input->cursor_serial = input->pointer_enter_serial;
Ander Conselvan de Oliveira80620072012-06-15 17:27:36 +03003458 if (!input->cursor_frame_cb)
3459 pointer_surface_frame_callback(input, NULL, 0);
Ander Conselvan de Oliveiraddca4962012-07-16 14:15:49 +03003460 else if (force) {
3461 /* The current frame callback may be stuck if, for instance,
3462 * the set cursor request was processed by the server after
3463 * this client lost the focus. In this case the cursor surface
3464 * might not be mapped and the frame callback wouldn't ever
3465 * complete. Send a set_cursor and attach to try to map the
3466 * cursor surface again so that the callback will finish */
3467 input_set_pointer_image_index(input, 0);
3468 }
Kristian Høgsberg7cee1972012-06-04 23:37:42 -04003469}
3470
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04003471struct wl_data_device *
3472input_get_data_device(struct input *input)
3473{
3474 return input->data_device;
3475}
3476
3477void
3478input_set_selection(struct input *input,
3479 struct wl_data_source *source, uint32_t time)
3480{
3481 wl_data_device_set_selection(input->data_device, source, time);
3482}
3483
3484void
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04003485input_accept(struct input *input, const char *type)
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04003486{
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04003487 wl_data_offer_accept(input->drag_offer->offer,
3488 input->pointer_enter_serial, type);
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04003489}
3490
3491static void
3492offer_io_func(struct task *task, uint32_t events)
3493{
3494 struct data_offer *offer =
3495 container_of(task, struct data_offer, io_task);
3496 unsigned int len;
3497 char buffer[4096];
3498
3499 len = read(offer->fd, buffer, sizeof buffer);
3500 offer->func(buffer, len,
3501 offer->x, offer->y, offer->user_data);
3502
3503 if (len == 0) {
3504 close(offer->fd);
3505 data_offer_destroy(offer);
3506 }
3507}
3508
3509static void
3510data_offer_receive_data(struct data_offer *offer, const char *mime_type,
3511 data_func_t func, void *user_data)
3512{
3513 int p[2];
3514
Jonas Ådahl3685c3a2012-03-30 23:10:27 +02003515 if (pipe2(p, O_CLOEXEC) == -1)
3516 return;
3517
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04003518 wl_data_offer_receive(offer->offer, mime_type, p[1]);
3519 close(p[1]);
3520
3521 offer->io_task.run = offer_io_func;
3522 offer->fd = p[0];
3523 offer->func = func;
3524 offer->refcount++;
3525 offer->user_data = user_data;
3526
3527 display_watch_fd(offer->input->display,
3528 offer->fd, EPOLLIN, &offer->io_task);
3529}
3530
3531void
3532input_receive_drag_data(struct input *input, const char *mime_type,
3533 data_func_t func, void *data)
3534{
3535 data_offer_receive_data(input->drag_offer, mime_type, func, data);
3536 input->drag_offer->x = input->sx;
3537 input->drag_offer->y = input->sy;
3538}
3539
3540int
Kristian Høgsberg0749e3f2013-09-04 20:41:06 -07003541input_receive_drag_data_to_fd(struct input *input,
3542 const char *mime_type, int fd)
3543{
3544 if (input->drag_offer)
3545 wl_data_offer_receive(input->drag_offer->offer, mime_type, fd);
3546
3547 return 0;
3548}
3549
3550int
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04003551input_receive_selection_data(struct input *input, const char *mime_type,
3552 data_func_t func, void *data)
3553{
3554 char **p;
3555
3556 if (input->selection_offer == NULL)
3557 return -1;
3558
3559 for (p = input->selection_offer->types.data; *p; p++)
3560 if (strcmp(mime_type, *p) == 0)
3561 break;
3562
3563 if (*p == NULL)
3564 return -1;
3565
3566 data_offer_receive_data(input->selection_offer,
3567 mime_type, func, data);
3568 return 0;
Kristian Høgsberg41da9082010-11-30 14:01:07 -05003569}
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -04003570
Kristian Høgsberge7aaec32011-12-27 13:50:04 -05003571int
3572input_receive_selection_data_to_fd(struct input *input,
3573 const char *mime_type, int fd)
3574{
Kristian Høgsberga4b3d0e2012-05-31 23:30:32 -04003575 if (input->selection_offer)
3576 wl_data_offer_receive(input->selection_offer->offer,
3577 mime_type, fd);
Kristian Høgsberge7aaec32011-12-27 13:50:04 -05003578
3579 return 0;
3580}
3581
Kristian Høgsberg41da9082010-11-30 14:01:07 -05003582void
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04003583window_move(struct window *window, struct input *input, uint32_t serial)
Kristian Høgsberg82da52b2010-12-17 09:53:12 -05003584{
Pekka Paalanen6b2dc912011-11-29 10:25:08 +02003585 if (!window->shell_surface)
3586 return;
3587
Daniel Stone37816df2012-05-16 18:45:18 +01003588 wl_shell_surface_move(window->shell_surface, input->seat, serial);
Kristian Høgsberg82da52b2010-12-17 09:53:12 -05003589}
3590
Rusty Lynch1084da52013-08-15 09:10:08 -07003591void
3592window_touch_move(struct window *window, struct input *input, uint32_t serial)
3593{
3594 if (!window->shell_surface)
3595 return;
3596
3597 wl_shell_surface_move(window->shell_surface, input->seat,
3598 window->display->serial);
3599}
3600
Kristian Høgsberg83fc0612010-08-04 22:44:55 -04003601static void
Pekka Paalanen35e82632013-04-25 13:57:48 +03003602surface_set_synchronized(struct surface *surface)
3603{
3604 if (!surface->subsurface)
3605 return;
3606
3607 if (surface->synchronized)
3608 return;
3609
3610 wl_subsurface_set_sync(surface->subsurface);
3611 surface->synchronized = 1;
3612}
3613
3614static void
3615surface_set_synchronized_default(struct surface *surface)
3616{
3617 if (!surface->subsurface)
3618 return;
3619
3620 if (surface->synchronized == surface->synchronized_default)
3621 return;
3622
3623 if (surface->synchronized_default)
3624 wl_subsurface_set_sync(surface->subsurface);
3625 else
3626 wl_subsurface_set_desync(surface->subsurface);
3627
3628 surface->synchronized = surface->synchronized_default;
3629}
3630
3631static void
Pekka Paalanenb1cd9b12013-02-13 16:17:18 +02003632surface_resize(struct surface *surface)
Pekka Paalanen811ec4f2013-02-13 16:17:14 +02003633{
Pekka Paalanenb1cd9b12013-02-13 16:17:18 +02003634 struct widget *widget = surface->widget;
3635 struct wl_compositor *compositor = widget->window->display->compositor;
Pekka Paalanen811ec4f2013-02-13 16:17:14 +02003636
Pekka Paalanenb1cd9b12013-02-13 16:17:18 +02003637 if (surface->input_region) {
3638 wl_region_destroy(surface->input_region);
3639 surface->input_region = NULL;
Kristian Høgsberg010f98b2012-02-23 17:30:45 -05003640 }
3641
Pekka Paalanenb1cd9b12013-02-13 16:17:18 +02003642 if (surface->opaque_region)
3643 wl_region_destroy(surface->opaque_region);
Ander Conselvan de Oliveiraddd3e272012-11-30 17:34:23 +02003644
Pekka Paalanenb1cd9b12013-02-13 16:17:18 +02003645 surface->opaque_region = wl_compositor_create_region(compositor);
Kristian Høgsberg010f98b2012-02-23 17:30:45 -05003646
Kristian Høgsbergbb977002012-01-10 19:11:42 -05003647 if (widget->resize_handler)
3648 widget->resize_handler(widget,
Kristian Høgsberg0d1c0622012-01-31 15:30:47 -05003649 widget->allocation.width,
3650 widget->allocation.height,
Kristian Høgsbergbb977002012-01-10 19:11:42 -05003651 widget->user_data);
3652
Pekka Paalanen35e82632013-04-25 13:57:48 +03003653 if (surface->subsurface &&
3654 (surface->allocation.x != widget->allocation.x ||
3655 surface->allocation.y != widget->allocation.y)) {
3656 wl_subsurface_set_position(surface->subsurface,
3657 widget->allocation.x,
3658 widget->allocation.y);
3659 }
Pekka Paalanenb1cd9b12013-02-13 16:17:18 +02003660 if (surface->allocation.width != widget->allocation.width ||
3661 surface->allocation.height != widget->allocation.height) {
Pekka Paalanenb1cd9b12013-02-13 16:17:18 +02003662 window_schedule_redraw(widget->window);
3663 }
Pekka Paalanen35e82632013-04-25 13:57:48 +03003664 surface->allocation = widget->allocation;
Ander Conselvan de Oliveiraddd3e272012-11-30 17:34:23 +02003665
3666 if (widget->opaque)
Pekka Paalanenb1cd9b12013-02-13 16:17:18 +02003667 wl_region_add(surface->opaque_region, 0, 0,
Ander Conselvan de Oliveiraddd3e272012-11-30 17:34:23 +02003668 widget->allocation.width,
3669 widget->allocation.height);
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -05003670}
3671
Pekka Paalanenb1cd9b12013-02-13 16:17:18 +02003672static void
Pekka Paalanene9297f82013-04-25 13:57:51 +03003673hack_prevent_EGL_sub_surface_deadlock(struct window *window)
3674{
3675 /*
3676 * This hack should be removed, when EGL respects
3677 * eglSwapInterval(0).
3678 *
3679 * If this window has sub-surfaces, especially a free-running
3680 * EGL-widget, we need to post the parent surface once with
3681 * all the old state to guarantee, that the EGL-widget will
3682 * receive its frame callback soon. Otherwise, a forced call
3683 * to eglSwapBuffers may end up blocking, waiting for a frame
3684 * event that will never come, because we will commit the parent
3685 * surface with all new state only after eglSwapBuffers returns.
3686 *
3687 * This assumes, that:
3688 * 1. When the EGL widget's resize hook is called, it pauses.
3689 * 2. When the EGL widget's redraw hook is called, it forces a
3690 * repaint and a call to eglSwapBuffers(), and maybe resumes.
3691 * In a single threaded application condition 1 is a no-op.
3692 *
3693 * XXX: This should actually be after the surface_resize() calls,
3694 * but cannot, because then it would commit the incomplete state
3695 * accumulated from the widget resize hooks.
3696 */
3697 if (window->subsurface_list.next != &window->main_surface->link ||
3698 window->subsurface_list.prev != &window->main_surface->link)
3699 wl_surface_commit(window->main_surface->surface);
3700}
3701
3702static void
Pekka Paalanenb1cd9b12013-02-13 16:17:18 +02003703idle_resize(struct window *window)
3704{
Pekka Paalanen35e82632013-04-25 13:57:48 +03003705 struct surface *surface;
3706
Pekka Paalanenb1cd9b12013-02-13 16:17:18 +02003707 window->resize_needed = 0;
Pekka Paalanen40cb67b2013-04-25 13:57:49 +03003708 window->redraw_needed = 1;
Pekka Paalanenb1cd9b12013-02-13 16:17:18 +02003709
Pekka Paalanen71233882013-04-25 13:57:53 +03003710 DBG("from %dx%d to %dx%d\n",
3711 window->main_surface->server_allocation.width,
3712 window->main_surface->server_allocation.height,
3713 window->pending_allocation.width,
3714 window->pending_allocation.height);
3715
Pekka Paalanene9297f82013-04-25 13:57:51 +03003716 hack_prevent_EGL_sub_surface_deadlock(window);
3717
Pekka Paalanenb1cd9b12013-02-13 16:17:18 +02003718 widget_set_allocation(window->main_surface->widget,
3719 window->pending_allocation.x,
3720 window->pending_allocation.y,
3721 window->pending_allocation.width,
3722 window->pending_allocation.height);
3723
3724 surface_resize(window->main_surface);
Pekka Paalanen35e82632013-04-25 13:57:48 +03003725
3726 /* The main surface is in the list, too. Main surface's
3727 * resize_handler is responsible for calling widget_set_allocation()
3728 * on all sub-surface root widgets, so they will be resized
3729 * properly.
3730 */
3731 wl_list_for_each(surface, &window->subsurface_list, link) {
3732 if (surface == window->main_surface)
3733 continue;
3734
3735 surface_set_synchronized(surface);
3736 surface_resize(surface);
3737 }
Pekka Paalanenb1cd9b12013-02-13 16:17:18 +02003738}
3739
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -05003740void
3741window_schedule_resize(struct window *window, int width, int height)
3742{
Kristian Høgsberg53ec5602013-10-21 15:05:49 -07003743 /* We should probably get these numbers from the theme. */
3744 const int min_width = 200, min_height = 200;
3745
Kristian Høgsberg0d1c0622012-01-31 15:30:47 -05003746 window->pending_allocation.x = 0;
3747 window->pending_allocation.y = 0;
3748 window->pending_allocation.width = width;
3749 window->pending_allocation.height = height;
3750
Kristian Høgsberg53ec5602013-10-21 15:05:49 -07003751 if (window->min_allocation.width == 0) {
Kristian Høgsbergafb98282013-10-21 15:23:17 -07003752 if (width < min_width && window->frame)
Kristian Høgsberg53ec5602013-10-21 15:05:49 -07003753 window->min_allocation.width = min_width;
3754 else
3755 window->min_allocation.width = width;
Kristian Høgsbergafb98282013-10-21 15:23:17 -07003756 if (height < min_height && window->frame)
Kristian Høgsberg53ec5602013-10-21 15:05:49 -07003757 window->min_allocation.height = min_height;
3758 else
Kristian Høgsbergafb98282013-10-21 15:23:17 -07003759 window->min_allocation.height = height;
Kristian Høgsberg53ec5602013-10-21 15:05:49 -07003760 }
3761
Kristian Høgsbergd3a19652012-07-20 11:32:51 -04003762 if (window->pending_allocation.width < window->min_allocation.width)
3763 window->pending_allocation.width = window->min_allocation.width;
3764 if (window->pending_allocation.height < window->min_allocation.height)
3765 window->pending_allocation.height = window->min_allocation.height;
3766
Kristian Høgsberg42b4f802012-03-26 13:49:29 -04003767 window->resize_needed = 1;
3768 window_schedule_redraw(window);
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -05003769}
3770
Kristian Høgsbergbb977002012-01-10 19:11:42 -05003771void
3772widget_schedule_resize(struct widget *widget, int32_t width, int32_t height)
3773{
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05003774 window_schedule_resize(widget->window, width, height);
Kristian Høgsbergbb977002012-01-10 19:11:42 -05003775}
3776
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -05003777static void
Scott Moreauff1db4a2012-04-17 19:06:18 -06003778handle_ping(void *data, struct wl_shell_surface *shell_surface,
3779 uint32_t serial)
3780{
3781 wl_shell_surface_pong(shell_surface, serial);
3782}
3783
3784static void
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003785handle_configure(void *data, struct wl_shell_surface *shell_surface,
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04003786 uint32_t edges, int32_t width, int32_t height)
Kristian Høgsberg83fc0612010-08-04 22:44:55 -04003787{
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003788 struct window *window = data;
Kristian Høgsberg83fc0612010-08-04 22:44:55 -04003789
Tim Wiederhakeb6761dc2011-01-17 17:50:07 +01003790 window->resize_edges = edges;
Kristian Høgsberg0d1c0622012-01-31 15:30:47 -05003791 window_schedule_resize(window, width, height);
Kristian Høgsberg83fc0612010-08-04 22:44:55 -04003792}
3793
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05003794static void
Pekka Paalanen6d174cf2012-01-19 15:17:59 +02003795menu_destroy(struct menu *menu)
3796{
3797 widget_destroy(menu->widget);
3798 window_destroy(menu->window);
Kristian Høgsbergc680e902013-10-23 21:49:30 -07003799 frame_destroy(menu->frame);
Pekka Paalanen6d174cf2012-01-19 15:17:59 +02003800 free(menu);
3801}
3802
3803static void
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05003804handle_popup_done(void *data, struct wl_shell_surface *shell_surface)
3805{
3806 struct window *window = data;
Pekka Paalanenac95f3e2013-02-13 16:17:17 +02003807 struct menu *menu = window->main_surface->widget->user_data;
Kristian Høgsberg831dd522012-01-10 23:46:33 -05003808
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05003809 /* FIXME: Need more context in this event, at least the input
Kristian Høgsberg831dd522012-01-10 23:46:33 -05003810 * device. Or just use wl_callback. And this really needs to
3811 * be a window vfunc that the menu can set. And we need the
3812 * time. */
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05003813
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04003814 input_ungrab(menu->input);
Pekka Paalanen6d174cf2012-01-19 15:17:59 +02003815 menu_destroy(menu);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05003816}
3817
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003818static const struct wl_shell_surface_listener shell_surface_listener = {
Scott Moreauff1db4a2012-04-17 19:06:18 -06003819 handle_ping,
Kristian Høgsberg83fc0612010-08-04 22:44:55 -04003820 handle_configure,
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05003821 handle_popup_done
Kristian Høgsberg83fc0612010-08-04 22:44:55 -04003822};
3823
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -05003824void
Benjamin Franzkecff904e2011-02-18 23:00:55 +01003825window_get_allocation(struct window *window,
3826 struct rectangle *allocation)
3827{
Pekka Paalanen811ec4f2013-02-13 16:17:14 +02003828 *allocation = window->main_surface->allocation;
Benjamin Franzkecff904e2011-02-18 23:00:55 +01003829}
3830
Kristian Høgsberg3a696272011-09-14 17:33:48 -04003831static void
Kristian Høgsberg441338c2012-01-10 13:52:34 -05003832widget_redraw(struct widget *widget)
3833{
3834 struct widget *child;
3835
3836 if (widget->redraw_handler)
3837 widget->redraw_handler(widget, widget->user_data);
3838 wl_list_for_each(child, &widget->child_list, link)
3839 widget_redraw(child);
3840}
3841
3842static void
Kristian Høgsberg6bd4d972012-03-24 14:42:09 -04003843frame_callback(void *data, struct wl_callback *callback, uint32_t time)
3844{
Pekka Paalanen40cb67b2013-04-25 13:57:49 +03003845 struct surface *surface = data;
Kristian Høgsberg6bd4d972012-03-24 14:42:09 -04003846
Pekka Paalanen40cb67b2013-04-25 13:57:49 +03003847 assert(callback == surface->frame_cb);
Pekka Paalanen71233882013-04-25 13:57:53 +03003848 DBG_OBJ(callback, "done\n");
Kristian Høgsberg6bd4d972012-03-24 14:42:09 -04003849 wl_callback_destroy(callback);
Pekka Paalanen40cb67b2013-04-25 13:57:49 +03003850 surface->frame_cb = NULL;
3851
Pekka Paalanen7ff7a802013-04-25 13:57:50 +03003852 surface->last_time = time;
3853
Pekka Paalanen71233882013-04-25 13:57:53 +03003854 if (surface->redraw_needed || surface->window->redraw_needed) {
3855 DBG_OBJ(surface->surface, "window_schedule_redraw_task\n");
Pekka Paalanen40cb67b2013-04-25 13:57:49 +03003856 window_schedule_redraw_task(surface->window);
Pekka Paalanen71233882013-04-25 13:57:53 +03003857 }
Kristian Høgsberg6bd4d972012-03-24 14:42:09 -04003858}
3859
3860static const struct wl_callback_listener listener = {
3861 frame_callback
3862};
3863
3864static void
Pekka Paalanen40cb67b2013-04-25 13:57:49 +03003865surface_redraw(struct surface *surface)
3866{
Pekka Paalanen71233882013-04-25 13:57:53 +03003867 DBG_OBJ(surface->surface, "begin\n");
3868
Pekka Paalanen40cb67b2013-04-25 13:57:49 +03003869 if (!surface->window->redraw_needed && !surface->redraw_needed)
3870 return;
3871
3872 /* Whole-window redraw forces a redraw even if the previous has
3873 * not yet hit the screen.
3874 */
3875 if (surface->frame_cb) {
3876 if (!surface->window->redraw_needed)
3877 return;
3878
Pekka Paalanen71233882013-04-25 13:57:53 +03003879 DBG_OBJ(surface->frame_cb, "cancelled\n");
Pekka Paalanen40cb67b2013-04-25 13:57:49 +03003880 wl_callback_destroy(surface->frame_cb);
3881 }
3882
3883 surface->frame_cb = wl_surface_frame(surface->surface);
3884 wl_callback_add_listener(surface->frame_cb, &listener, surface);
Pekka Paalanen71233882013-04-25 13:57:53 +03003885 DBG_OBJ(surface->frame_cb, "new\n");
Pekka Paalanen40cb67b2013-04-25 13:57:49 +03003886
3887 surface->redraw_needed = 0;
Pekka Paalanen71233882013-04-25 13:57:53 +03003888 DBG_OBJ(surface->surface, "-> widget_redraw\n");
Pekka Paalanen40cb67b2013-04-25 13:57:49 +03003889 widget_redraw(surface->widget);
Pekka Paalanen71233882013-04-25 13:57:53 +03003890 DBG_OBJ(surface->surface, "done\n");
Pekka Paalanen40cb67b2013-04-25 13:57:49 +03003891}
3892
3893static void
Kristian Høgsberg3a696272011-09-14 17:33:48 -04003894idle_redraw(struct task *task, uint32_t events)
Kristian Høgsberg80d746f2010-06-14 23:52:50 -04003895{
Kristian Høgsberg42b4f802012-03-26 13:49:29 -04003896 struct window *window = container_of(task, struct window, redraw_task);
Pekka Paalanen35e82632013-04-25 13:57:48 +03003897 struct surface *surface;
Kristian Høgsberg80d746f2010-06-14 23:52:50 -04003898
Pekka Paalanen71233882013-04-25 13:57:53 +03003899 DBG(" --------- \n");
3900
Pekka Paalaneneebff542013-04-25 13:57:52 +03003901 wl_list_init(&window->redraw_task.link);
3902 window->redraw_task_scheduled = 0;
3903
3904 if (window->resize_needed) {
3905 /* throttle resizing to the main surface display */
Pekka Paalanen71233882013-04-25 13:57:53 +03003906 if (window->main_surface->frame_cb) {
3907 DBG_OBJ(window->main_surface->frame_cb, "pending\n");
Pekka Paalaneneebff542013-04-25 13:57:52 +03003908 return;
Pekka Paalanen71233882013-04-25 13:57:53 +03003909 }
Pekka Paalaneneebff542013-04-25 13:57:52 +03003910
Kristian Høgsberg42b4f802012-03-26 13:49:29 -04003911 idle_resize(window);
Pekka Paalaneneebff542013-04-25 13:57:52 +03003912 }
Kristian Høgsberg42b4f802012-03-26 13:49:29 -04003913
Pekka Paalanen35e82632013-04-25 13:57:48 +03003914 wl_list_for_each(surface, &window->subsurface_list, link)
Pekka Paalanen40cb67b2013-04-25 13:57:49 +03003915 surface_redraw(surface);
Pekka Paalanen35e82632013-04-25 13:57:48 +03003916
Kristian Høgsberg6bd4d972012-03-24 14:42:09 -04003917 window->redraw_needed = 0;
Pekka Paalanenbc106382012-10-10 12:49:31 +03003918 window_flush(window);
Pekka Paalanen35e82632013-04-25 13:57:48 +03003919
3920 wl_list_for_each(surface, &window->subsurface_list, link)
3921 surface_set_synchronized_default(surface);
Kristian Høgsberg80d746f2010-06-14 23:52:50 -04003922}
3923
Pekka Paalanen40cb67b2013-04-25 13:57:49 +03003924static void
3925window_schedule_redraw_task(struct window *window)
3926{
3927 if (window->configure_requests)
3928 return;
3929 if (!window->redraw_task_scheduled) {
3930 window->redraw_task.run = idle_redraw;
3931 display_defer(window->display, &window->redraw_task);
3932 window->redraw_task_scheduled = 1;
3933 }
3934}
3935
Kristian Høgsberg80d746f2010-06-14 23:52:50 -04003936void
3937window_schedule_redraw(struct window *window)
3938{
Pekka Paalanen40cb67b2013-04-25 13:57:49 +03003939 struct surface *surface;
3940
Pekka Paalanen71233882013-04-25 13:57:53 +03003941 DBG_OBJ(window->main_surface->surface, "window %p\n", window);
3942
Pekka Paalanen40cb67b2013-04-25 13:57:49 +03003943 wl_list_for_each(surface, &window->subsurface_list, link)
3944 surface->redraw_needed = 1;
3945
3946 window_schedule_redraw_task(window);
Kristian Høgsberg80d746f2010-06-14 23:52:50 -04003947}
3948
Kristian Høgsberg1671e112012-10-10 11:36:24 -04003949int
3950window_is_fullscreen(struct window *window)
3951{
3952 return window->type == TYPE_FULLSCREEN;
3953}
3954
MoD063a8822013-03-02 23:43:57 +00003955static void
3956configure_request_completed(void *data, struct wl_callback *callback, uint32_t time)
3957{
3958 struct window *window = data;
3959
3960 wl_callback_destroy(callback);
3961 window->configure_requests--;
3962
3963 if (!window->configure_requests)
3964 window_schedule_redraw(window);
3965}
3966
3967static struct wl_callback_listener configure_request_listener = {
3968 configure_request_completed,
3969};
3970
3971static void
3972window_defer_redraw_until_configure(struct window* window)
3973{
3974 struct wl_callback *callback;
3975
Pekka Paalanen40cb67b2013-04-25 13:57:49 +03003976 if (window->redraw_task_scheduled) {
MoD063a8822013-03-02 23:43:57 +00003977 wl_list_remove(&window->redraw_task.link);
Pekka Paalanen40cb67b2013-04-25 13:57:49 +03003978 window->redraw_task_scheduled = 0;
MoD063a8822013-03-02 23:43:57 +00003979 }
3980
3981 callback = wl_display_sync(window->display->display);
3982 wl_callback_add_listener(callback, &configure_request_listener, window);
3983 window->configure_requests++;
3984}
3985
Kristian Høgsberg0ac16f02009-01-15 11:37:43 -05003986void
Kristian Høgsberg0395f302008-12-22 12:14:50 -05003987window_set_fullscreen(struct window *window, int fullscreen)
3988{
Kristian Høgsberg1517def2012-02-16 22:56:12 -05003989 if (!window->display->shell)
3990 return;
Kristian Høgsberg0ce24572011-01-28 15:18:33 -05003991
Kristian Høgsberg547da5a2011-09-13 20:58:00 -04003992 if ((window->type == TYPE_FULLSCREEN) == fullscreen)
Kristian Høgsberg0ce24572011-01-28 15:18:33 -05003993 return;
3994
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -04003995 if (fullscreen) {
Rafal Mielniczukc1a3cd12013-03-11 19:26:56 +01003996 window->saved_type = window->type;
Rafal Mielniczukfc22be02013-03-11 19:26:55 +01003997 if (window->type == TYPE_TOPLEVEL) {
3998 window->saved_allocation = window->main_surface->allocation;
3999 }
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -04004000 window->type = TYPE_FULLSCREEN;
Kristian Høgsberg1517def2012-02-16 22:56:12 -05004001 wl_shell_surface_set_fullscreen(window->shell_surface,
Ander Conselvan de Oliveira5403f522012-12-14 13:37:23 -02004002 window->fullscreen_method,
Kristian Høgsberg1517def2012-02-16 22:56:12 -05004003 0, NULL);
MoD063a8822013-03-02 23:43:57 +00004004 window_defer_redraw_until_configure (window);
Kristian Høgsberg0395f302008-12-22 12:14:50 -05004005 } else {
Rafal Mielniczukc1a3cd12013-03-11 19:26:56 +01004006 if (window->saved_type == TYPE_MAXIMIZED) {
4007 window_set_maximized(window, 1);
4008 } else {
4009 window->type = TYPE_TOPLEVEL;
4010 wl_shell_surface_set_toplevel(window->shell_surface);
4011 window_schedule_resize(window,
4012 window->saved_allocation.width,
4013 window->saved_allocation.height);
4014 }
4015
Kristian Høgsberg0395f302008-12-22 12:14:50 -05004016 }
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -04004017}
4018
Ander Conselvan de Oliveira5403f522012-12-14 13:37:23 -02004019void
4020window_set_fullscreen_method(struct window *window,
4021 enum wl_shell_surface_fullscreen_method method)
4022{
4023 window->fullscreen_method = method;
4024}
4025
Kristian Høgsberg1671e112012-10-10 11:36:24 -04004026int
4027window_is_maximized(struct window *window)
4028{
4029 return window->type == TYPE_MAXIMIZED;
4030}
4031
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -04004032void
Kristian Høgsbergd6bcd7d2012-02-16 15:53:46 -05004033window_set_maximized(struct window *window, int maximized)
4034{
4035 if (!window->display->shell)
4036 return;
4037
4038 if ((window->type == TYPE_MAXIMIZED) == maximized)
4039 return;
4040
4041 if (window->type == TYPE_TOPLEVEL) {
Pekka Paalanen811ec4f2013-02-13 16:17:14 +02004042 window->saved_allocation = window->main_surface->allocation;
Kristian Høgsbergd6bcd7d2012-02-16 15:53:46 -05004043 wl_shell_surface_set_maximized(window->shell_surface, NULL);
4044 window->type = TYPE_MAXIMIZED;
MoD063a8822013-03-02 23:43:57 +00004045 window_defer_redraw_until_configure(window);
Rafal Mielniczukc1a3cd12013-03-11 19:26:56 +01004046 } else if (window->type == TYPE_FULLSCREEN) {
4047 wl_shell_surface_set_maximized(window->shell_surface, NULL);
4048 window->type = TYPE_MAXIMIZED;
MoD063a8822013-03-02 23:43:57 +00004049 window_defer_redraw_until_configure(window);
Kristian Høgsbergd6bcd7d2012-02-16 15:53:46 -05004050 } else {
4051 wl_shell_surface_set_toplevel(window->shell_surface);
4052 window->type = TYPE_TOPLEVEL;
4053 window_schedule_resize(window,
4054 window->saved_allocation.width,
4055 window->saved_allocation.height);
4056 }
4057}
4058
4059void
Kristian Høgsbergc8c37342010-06-25 11:19:22 -04004060window_set_user_data(struct window *window, void *data)
4061{
4062 window->user_data = data;
4063}
4064
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -04004065void *
4066window_get_user_data(struct window *window)
4067{
4068 return window->user_data;
4069}
4070
Kristian Høgsbergc8c37342010-06-25 11:19:22 -04004071void
Kristian Høgsberg6e83d582008-12-08 00:01:36 -05004072window_set_key_handler(struct window *window,
Kristian Høgsbergc8c37342010-06-25 11:19:22 -04004073 window_key_handler_t handler)
Kristian Høgsberg6e83d582008-12-08 00:01:36 -05004074{
4075 window->key_handler = handler;
Kristian Høgsberg6e83d582008-12-08 00:01:36 -05004076}
4077
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -05004078void
4079window_set_keyboard_focus_handler(struct window *window,
Kristian Høgsbergc8c37342010-06-25 11:19:22 -04004080 window_keyboard_focus_handler_t handler)
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -05004081{
4082 window->keyboard_focus_handler = handler;
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -05004083}
4084
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -04004085void
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04004086window_set_data_handler(struct window *window, window_data_handler_t handler)
4087{
4088 window->data_handler = handler;
4089}
4090
4091void
4092window_set_drop_handler(struct window *window, window_drop_handler_t handler)
4093{
4094 window->drop_handler = handler;
4095}
4096
4097void
Kristian Høgsberg4f7dcd62012-01-06 21:59:05 -05004098window_set_close_handler(struct window *window,
4099 window_close_handler_t handler)
4100{
4101 window->close_handler = handler;
4102}
4103
4104void
Kristian Høgsberg67ace202012-07-23 21:56:31 -04004105window_set_fullscreen_handler(struct window *window,
4106 window_fullscreen_handler_t handler)
4107{
4108 window->fullscreen_handler = handler;
4109}
4110
4111void
Ander Conselvan de Oliveira15256f62012-11-30 17:34:25 +02004112window_set_output_handler(struct window *window,
4113 window_output_handler_t handler)
4114{
4115 window->output_handler = handler;
4116}
4117
4118void
Callum Lowcayef57a9b2011-01-14 20:46:23 +13004119window_set_title(struct window *window, const char *title)
4120{
Kristian Høgsbergd5fb9cc2011-01-25 12:45:37 -05004121 free(window->title);
Callum Lowcayef57a9b2011-01-14 20:46:23 +13004122 window->title = strdup(title);
Jason Ekstrand3f66cf92013-10-13 19:08:40 -05004123 if (window->frame) {
4124 frame_set_title(window->frame->frame, title);
4125 widget_schedule_redraw(window->frame->widget);
4126 }
Kristian Høgsberg3e0fe5c2012-05-02 09:47:55 -04004127 if (window->shell_surface)
4128 wl_shell_surface_set_title(window->shell_surface, title);
Callum Lowcayef57a9b2011-01-14 20:46:23 +13004129}
4130
4131const char *
4132window_get_title(struct window *window)
4133{
4134 return window->title;
4135}
4136
4137void
Scott Moreau7a1b32a2012-05-27 14:25:02 -06004138window_set_text_cursor_position(struct window *window, int32_t x, int32_t y)
4139{
4140 struct text_cursor_position *text_cursor_position =
4141 window->display->text_cursor_position;
4142
Scott Moreau9295ce02012-06-01 12:46:10 -06004143 if (!text_cursor_position)
Scott Moreau7a1b32a2012-05-27 14:25:02 -06004144 return;
4145
4146 text_cursor_position_notify(text_cursor_position,
Pekka Paalanen4e373742013-02-13 16:17:13 +02004147 window->main_surface->surface,
4148 wl_fixed_from_int(x),
4149 wl_fixed_from_int(y));
Scott Moreau7a1b32a2012-05-27 14:25:02 -06004150}
4151
4152void
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -04004153window_damage(struct window *window, int32_t x, int32_t y,
4154 int32_t width, int32_t height)
4155{
Pekka Paalanen4e373742013-02-13 16:17:13 +02004156 wl_surface_damage(window->main_surface->surface, x, y, width, height);
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -04004157}
4158
Casey Dahlin9074db52012-04-19 22:50:09 -04004159static void
4160surface_enter(void *data,
Rob Bradford7507b572012-05-15 17:55:34 +01004161 struct wl_surface *wl_surface, struct wl_output *wl_output)
Casey Dahlin9074db52012-04-19 22:50:09 -04004162{
Rob Bradford7507b572012-05-15 17:55:34 +01004163 struct window *window = data;
4164 struct output *output;
4165 struct output *output_found = NULL;
4166 struct window_output *window_output;
4167
4168 wl_list_for_each(output, &window->display->output_list, link) {
4169 if (output->output == wl_output) {
4170 output_found = output;
4171 break;
4172 }
4173 }
4174
4175 if (!output_found)
4176 return;
4177
Brian Lovinbc919262013-08-07 15:34:59 -07004178 window_output = xmalloc(sizeof *window_output);
Rob Bradford7507b572012-05-15 17:55:34 +01004179 window_output->output = output_found;
4180
4181 wl_list_insert (&window->window_output_list, &window_output->link);
Ander Conselvan de Oliveira15256f62012-11-30 17:34:25 +02004182
4183 if (window->output_handler)
4184 window->output_handler(window, output_found, 1,
4185 window->user_data);
Casey Dahlin9074db52012-04-19 22:50:09 -04004186}
4187
4188static void
4189surface_leave(void *data,
4190 struct wl_surface *wl_surface, struct wl_output *output)
4191{
Rob Bradford7507b572012-05-15 17:55:34 +01004192 struct window *window = data;
4193 struct window_output *window_output;
4194 struct window_output *window_output_found = NULL;
4195
4196 wl_list_for_each(window_output, &window->window_output_list, link) {
4197 if (window_output->output->output == output) {
4198 window_output_found = window_output;
4199 break;
4200 }
4201 }
4202
4203 if (window_output_found) {
4204 wl_list_remove(&window_output_found->link);
Ander Conselvan de Oliveira15256f62012-11-30 17:34:25 +02004205
4206 if (window->output_handler)
4207 window->output_handler(window, window_output->output,
4208 0, window->user_data);
4209
Rob Bradford7507b572012-05-15 17:55:34 +01004210 free(window_output_found);
4211 }
Casey Dahlin9074db52012-04-19 22:50:09 -04004212}
4213
4214static const struct wl_surface_listener surface_listener = {
4215 surface_enter,
4216 surface_leave
4217};
4218
Pekka Paalanen4e373742013-02-13 16:17:13 +02004219static struct surface *
4220surface_create(struct window *window)
4221{
4222 struct display *display = window->display;
4223 struct surface *surface;
4224
Brian Lovinbc919262013-08-07 15:34:59 -07004225 surface = xmalloc(sizeof *surface);
4226 memset(surface, 0, sizeof *surface);
Pekka Paalanen4e373742013-02-13 16:17:13 +02004227 if (!surface)
4228 return NULL;
4229
4230 surface->window = window;
4231 surface->surface = wl_compositor_create_surface(display->compositor);
Alexander Larsson5e9b6522013-05-22 14:41:28 +02004232 surface->buffer_scale = 1;
Pekka Paalanen4e373742013-02-13 16:17:13 +02004233 wl_surface_add_listener(surface->surface, &surface_listener, window);
4234
Pekka Paalanen35e82632013-04-25 13:57:48 +03004235 wl_list_insert(&window->subsurface_list, &surface->link);
4236
Pekka Paalanen4e373742013-02-13 16:17:13 +02004237 return surface;
4238}
4239
Kristian Høgsberg248c1b62011-01-21 18:03:15 -05004240static struct window *
Kristian Høgsberg962342c2012-06-26 16:29:50 -04004241window_create_internal(struct display *display,
4242 struct window *parent, int type)
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -05004243{
Kristian Høgsberg1cbaa6a2008-11-07 15:54:48 -05004244 struct window *window;
Pekka Paalanen02bba7c2013-02-13 16:17:15 +02004245 struct surface *surface;
Kristian Høgsberg1cbaa6a2008-11-07 15:54:48 -05004246
Peter Huttererf3d62272013-08-08 11:57:05 +10004247 window = xzalloc(sizeof *window);
Pekka Paalanen35e82632013-04-25 13:57:48 +03004248 wl_list_init(&window->subsurface_list);
Kristian Høgsberg40979232008-11-25 22:40:39 -05004249 window->display = display;
Kristian Høgsberg248c1b62011-01-21 18:03:15 -05004250 window->parent = parent;
Pekka Paalanen02bba7c2013-02-13 16:17:15 +02004251
4252 surface = surface_create(window);
4253 window->main_surface = surface;
4254
Kristian Høgsberg962342c2012-06-26 16:29:50 -04004255 if (type != TYPE_CUSTOM && display->shell) {
Pekka Paalanen6b2dc912011-11-29 10:25:08 +02004256 window->shell_surface =
4257 wl_shell_get_shell_surface(display->shell,
Pekka Paalanen02bba7c2013-02-13 16:17:15 +02004258 surface->surface);
Kristian Høgsbergce278412013-07-25 15:20:20 -07004259 fail_on_null(window->shell_surface);
Pekka Paalanen6b2dc912011-11-29 10:25:08 +02004260 }
Pekka Paalanen811ec4f2013-02-13 16:17:14 +02004261
Kristian Høgsberg962342c2012-06-26 16:29:50 -04004262 window->type = type;
Ander Conselvan de Oliveira5403f522012-12-14 13:37:23 -02004263 window->fullscreen_method = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT;
MoD063a8822013-03-02 23:43:57 +00004264 window->configure_requests = 0;
Tomeu Vizosobee45a12013-08-06 20:05:54 +02004265 window->preferred_format = WINDOW_PREFERRED_FORMAT_NONE;
Kristian Høgsberg87a57bb2012-01-09 10:34:35 -05004266
Kristian Høgsberg4e51b442013-01-07 15:47:14 -05004267 if (display->argb_device)
Benjamin Franzke22d54812011-07-16 19:50:32 +00004268#ifdef HAVE_CAIRO_EGL
Pekka Paalanen02bba7c2013-02-13 16:17:15 +02004269 surface->buffer_type = WINDOW_BUFFER_TYPE_EGL_WINDOW;
Benjamin Franzke22d54812011-07-16 19:50:32 +00004270#else
Pekka Paalanen02bba7c2013-02-13 16:17:15 +02004271 surface->buffer_type = WINDOW_BUFFER_TYPE_SHM;
Benjamin Franzke22d54812011-07-16 19:50:32 +00004272#endif
Yuval Fledel45568f62010-12-06 09:18:12 -05004273 else
Pekka Paalanen02bba7c2013-02-13 16:17:15 +02004274 surface->buffer_type = WINDOW_BUFFER_TYPE_SHM;
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -04004275
Pekka Paalanen02bba7c2013-02-13 16:17:15 +02004276 wl_surface_set_user_data(surface->surface, window);
Kristian Høgsberg478d9262010-06-08 20:34:11 -04004277 wl_list_insert(display->window_list.prev, &window->link);
Kristian Høgsberg84b76c72012-04-13 12:01:18 -04004278 wl_list_init(&window->redraw_task.link);
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05004279
Pekka Paalanen6b2dc912011-11-29 10:25:08 +02004280 if (window->shell_surface) {
4281 wl_shell_surface_set_user_data(window->shell_surface, window);
4282 wl_shell_surface_add_listener(window->shell_surface,
4283 &shell_surface_listener, window);
4284 }
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02004285
Rob Bradford7507b572012-05-15 17:55:34 +01004286 wl_list_init (&window->window_output_list);
4287
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05004288 return window;
4289}
4290
Kristian Høgsberg248c1b62011-01-21 18:03:15 -05004291struct window *
Kristian Høgsberg009ac0a2012-01-31 15:24:48 -05004292window_create(struct display *display)
Kristian Høgsberg248c1b62011-01-21 18:03:15 -05004293{
Kristian Høgsberg41624832013-07-25 16:53:10 -07004294 return window_create_internal(display, NULL, TYPE_NONE);
Kristian Høgsberg962342c2012-06-26 16:29:50 -04004295}
4296
4297struct window *
4298window_create_custom(struct display *display)
4299{
Kristian Høgsbergce278412013-07-25 15:20:20 -07004300 return window_create_internal(display, NULL, TYPE_CUSTOM);
Kristian Høgsberg248c1b62011-01-21 18:03:15 -05004301}
4302
4303struct window *
4304window_create_transient(struct display *display, struct window *parent,
Tiago Vignattidec76582012-05-21 16:47:46 +03004305 int32_t x, int32_t y, uint32_t flags)
Kristian Høgsberg248c1b62011-01-21 18:03:15 -05004306{
4307 struct window *window;
4308
Kristian Høgsberg962342c2012-06-26 16:29:50 -04004309 window = window_create_internal(parent->display,
4310 parent, TYPE_TRANSIENT);
Kristian Høgsberg248c1b62011-01-21 18:03:15 -05004311
4312 window->x = x;
4313 window->y = y;
4314
Kristian Høgsberg1517def2012-02-16 22:56:12 -05004315 if (display->shell)
Pekka Paalanen4e373742013-02-13 16:17:13 +02004316 wl_shell_surface_set_transient(
4317 window->shell_surface,
4318 window->parent->main_surface->surface,
4319 window->x, window->y, flags);
Kristian Høgsberg1517def2012-02-16 22:56:12 -05004320
Kristian Høgsberg248c1b62011-01-21 18:03:15 -05004321 return window;
4322}
4323
Kristian Høgsberg831dd522012-01-10 23:46:33 -05004324static void
Kristian Høgsberg19dd1d72012-01-09 10:42:41 -05004325menu_set_item(struct menu *menu, int sy)
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004326{
Kristian Høgsbergc680e902013-10-23 21:49:30 -07004327 int32_t x, y, width, height;
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004328 int next;
4329
Kristian Høgsbergc680e902013-10-23 21:49:30 -07004330 frame_interior(menu->frame, &x, &y, &width, &height);
4331 next = (sy - y) / 20;
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004332 if (menu->current != next) {
4333 menu->current = next;
Kristian Høgsberg75bc6672012-01-10 09:43:58 -05004334 widget_schedule_redraw(menu->widget);
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004335 }
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004336}
4337
4338static int
Kristian Høgsberg5f190ef2012-01-09 09:44:45 -05004339menu_motion_handler(struct widget *widget,
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004340 struct input *input, uint32_t time,
Kristian Høgsberg80680c72012-05-10 12:21:37 -04004341 float x, float y, void *data)
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004342{
Kristian Høgsberg831dd522012-01-10 23:46:33 -05004343 struct menu *menu = data;
4344
4345 if (widget == menu->widget)
4346 menu_set_item(data, y);
4347
Ander Conselvan de Oliveiradc8c8fc2012-05-25 16:01:41 +03004348 return CURSOR_LEFT_PTR;
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004349}
4350
Kristian Høgsbergbb901fa2012-01-09 11:22:32 -05004351static int
Kristian Høgsberg391649b2012-01-09 09:22:30 -05004352menu_enter_handler(struct widget *widget,
Kristian Høgsberg80680c72012-05-10 12:21:37 -04004353 struct input *input, float x, float y, void *data)
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004354{
Kristian Høgsberg831dd522012-01-10 23:46:33 -05004355 struct menu *menu = data;
4356
4357 if (widget == menu->widget)
4358 menu_set_item(data, y);
4359
Ander Conselvan de Oliveiradc8c8fc2012-05-25 16:01:41 +03004360 return CURSOR_LEFT_PTR;
Kristian Høgsberg391649b2012-01-09 09:22:30 -05004361}
4362
4363static void
4364menu_leave_handler(struct widget *widget, struct input *input, void *data)
4365{
Kristian Høgsberg831dd522012-01-10 23:46:33 -05004366 struct menu *menu = data;
4367
4368 if (widget == menu->widget)
4369 menu_set_item(data, -200);
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004370}
4371
4372static void
Kristian Høgsberga8a0db32012-01-09 11:12:05 -05004373menu_button_handler(struct widget *widget,
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004374 struct input *input, uint32_t time,
Daniel Stone4dbadb12012-05-30 16:31:51 +01004375 uint32_t button, enum wl_pointer_button_state state,
4376 void *data)
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004377
4378{
Kristian Høgsberg75bc6672012-01-10 09:43:58 -05004379 struct menu *menu = data;
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004380
Kristian Høgsbergd2fbb382012-10-30 13:45:22 -04004381 if (state == WL_POINTER_BUTTON_STATE_RELEASED &&
4382 (menu->release_count > 0 || time - menu->time > 500)) {
Kristian Høgsberg831dd522012-01-10 23:46:33 -05004383 /* Either relase after press-drag-release or
4384 * click-motion-click. */
Kristian Høgsberg67b82152013-10-23 16:52:05 -07004385 menu->func(menu->window->parent, input,
Kristian Høgsberg75bc6672012-01-10 09:43:58 -05004386 menu->current, menu->window->parent->user_data);
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04004387 input_ungrab(input);
Pekka Paalanen6d174cf2012-01-19 15:17:59 +02004388 menu_destroy(menu);
Kristian Høgsberge77d7572012-10-30 18:10:30 -04004389 } else if (state == WL_POINTER_BUTTON_STATE_RELEASED) {
Kristian Høgsbergd2fbb382012-10-30 13:45:22 -04004390 menu->release_count++;
Kristian Høgsberge77d7572012-10-30 18:10:30 -04004391 }
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004392}
4393
4394static void
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -05004395menu_redraw_handler(struct widget *widget, void *data)
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004396{
4397 cairo_t *cr;
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004398 struct menu *menu = data;
Kristian Høgsbergc680e902013-10-23 21:49:30 -07004399 int32_t x, y, width, height, i;
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004400
Pekka Paalanen0c4445b2013-02-13 16:17:23 +02004401 cr = widget_cairo_create(widget);
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004402
Kristian Høgsbergc680e902013-10-23 21:49:30 -07004403 frame_repaint(menu->frame, cr);
4404 frame_interior(menu->frame, &x, &y, &width, &height);
Kristian Høgsberg824c6d02012-01-19 13:54:09 -05004405
Kristian Høgsbergc680e902013-10-23 21:49:30 -07004406 theme_set_background_source(menu->window->display->theme,
4407 cr, THEME_FRAME_ACTIVE);
4408 cairo_rectangle(cr, x, y, width, height);
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004409 cairo_fill(cr);
4410
Kristian Høgsbergc680e902013-10-23 21:49:30 -07004411 cairo_select_font_face(cr, "sans",
4412 CAIRO_FONT_SLANT_NORMAL,
4413 CAIRO_FONT_WEIGHT_NORMAL);
4414 cairo_set_font_size(cr, 12);
4415
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004416 for (i = 0; i < menu->count; i++) {
4417 if (i == menu->current) {
4418 cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
Kristian Høgsbergc680e902013-10-23 21:49:30 -07004419 cairo_rectangle(cr, x, y + i * 20, width, 20);
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004420 cairo_fill(cr);
4421 cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
Kristian Høgsbergc680e902013-10-23 21:49:30 -07004422 cairo_move_to(cr, x + 10, y + i * 20 + 16);
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004423 cairo_show_text(cr, menu->entries[i]);
4424 } else {
Kristian Høgsbergc680e902013-10-23 21:49:30 -07004425 cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
4426 cairo_move_to(cr, x + 10, y + i * 20 + 16);
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004427 cairo_show_text(cr, menu->entries[i]);
4428 }
4429 }
4430
4431 cairo_destroy(cr);
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004432}
4433
Pekka Paalanen6d174cf2012-01-19 15:17:59 +02004434void
4435window_show_menu(struct display *display,
4436 struct input *input, uint32_t time, struct window *parent,
4437 int32_t x, int32_t y,
4438 menu_func_t func, const char **entries, int count)
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004439{
4440 struct window *window;
4441 struct menu *menu;
Kristian Høgsbergc680e902013-10-23 21:49:30 -07004442 int32_t ix, iy;
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004443
4444 menu = malloc(sizeof *menu);
4445 if (!menu)
Pekka Paalanen6d174cf2012-01-19 15:17:59 +02004446 return;
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004447
Kristian Høgsberg962342c2012-06-26 16:29:50 -04004448 window = window_create_internal(parent->display, parent, TYPE_MENU);
Martin Olsson444799a2012-07-08 03:03:40 +02004449 if (!window) {
4450 free(menu);
Pekka Paalanen6d174cf2012-01-19 15:17:59 +02004451 return;
Martin Olsson444799a2012-07-08 03:03:40 +02004452 }
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004453
4454 menu->window = window;
Kristian Høgsberg75bc6672012-01-10 09:43:58 -05004455 menu->widget = window_add_widget(menu->window, menu);
Alexander Larssond68f5232013-05-22 14:41:33 +02004456 window_set_buffer_scale (menu->window, window_get_buffer_scale (parent));
4457 window_set_buffer_transform (menu->window, window_get_buffer_transform (parent));
Kristian Høgsbergc680e902013-10-23 21:49:30 -07004458 menu->frame = frame_create(window->display->theme, 0, 0,
4459 FRAME_BUTTON_NONE, "Menu");
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004460 menu->entries = entries;
4461 menu->count = count;
Kristian Høgsbergd2fbb382012-10-30 13:45:22 -04004462 menu->release_count = 0;
Kristian Høgsberg831dd522012-01-10 23:46:33 -05004463 menu->current = -1;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05004464 menu->time = time;
Kristian Høgsberg4f7dcd62012-01-06 21:59:05 -05004465 menu->func = func;
Kristian Høgsberg831dd522012-01-10 23:46:33 -05004466 menu->input = input;
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004467 window->type = TYPE_MENU;
4468 window->x = x;
4469 window->y = y;
4470
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -05004471 widget_set_redraw_handler(menu->widget, menu_redraw_handler);
Kristian Høgsberg75bc6672012-01-10 09:43:58 -05004472 widget_set_enter_handler(menu->widget, menu_enter_handler);
4473 widget_set_leave_handler(menu->widget, menu_leave_handler);
4474 widget_set_motion_handler(menu->widget, menu_motion_handler);
4475 widget_set_button_handler(menu->widget, menu_button_handler);
Kristian Høgsberg391649b2012-01-09 09:22:30 -05004476
Kristian Høgsberg831dd522012-01-10 23:46:33 -05004477 input_grab(input, menu->widget, 0);
Kristian Høgsbergc680e902013-10-23 21:49:30 -07004478 frame_resize_inside(menu->frame, 200, count * 20);
4479 frame_set_flag(menu->frame, FRAME_FLAG_ACTIVE);
4480 window_schedule_resize(window, frame_width(menu->frame),
4481 frame_height(menu->frame));
4482
4483 input_ungrab(input);
4484 frame_interior(menu->frame, &ix, &iy, NULL, NULL);
4485 wl_shell_surface_set_popup(window->shell_surface, input->seat,
4486 display_get_serial(window->display),
4487 window->parent->main_surface->surface,
4488 window->x - ix, window->y - iy, 0);
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004489}
4490
Kristian Høgsberg248c1b62011-01-21 18:03:15 -05004491void
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -04004492window_set_buffer_type(struct window *window, enum window_buffer_type type)
4493{
Pekka Paalanen02bba7c2013-02-13 16:17:15 +02004494 window->main_surface->buffer_type = type;
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -04004495}
4496
Tomeu Vizosobee45a12013-08-06 20:05:54 +02004497void
4498window_set_preferred_format(struct window *window,
4499 enum preferred_format format)
4500{
4501 window->preferred_format = format;
4502}
4503
Pekka Paalanen35e82632013-04-25 13:57:48 +03004504struct widget *
4505window_add_subsurface(struct window *window, void *data,
4506 enum subsurface_mode default_mode)
4507{
4508 struct widget *widget;
4509 struct surface *surface;
4510 struct wl_surface *parent;
4511 struct wl_subcompositor *subcompo = window->display->subcompositor;
4512
Pekka Paalanen35e82632013-04-25 13:57:48 +03004513 surface = surface_create(window);
4514 widget = widget_create(window, surface, data);
4515 wl_list_init(&widget->link);
4516 surface->widget = widget;
4517
4518 parent = window->main_surface->surface;
4519 surface->subsurface = wl_subcompositor_get_subsurface(subcompo,
4520 surface->surface,
4521 parent);
4522 surface->synchronized = 1;
4523
4524 switch (default_mode) {
4525 case SUBSURFACE_SYNCHRONIZED:
4526 surface->synchronized_default = 1;
4527 break;
4528 case SUBSURFACE_DESYNCHRONIZED:
4529 surface->synchronized_default = 0;
4530 break;
4531 default:
4532 assert(!"bad enum subsurface_mode");
4533 }
4534
4535 return widget;
4536}
Kristian Høgsberg8357cd62011-05-13 13:24:56 -04004537
4538static void
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05004539display_handle_geometry(void *data,
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04004540 struct wl_output *wl_output,
4541 int x, int y,
4542 int physical_width,
4543 int physical_height,
4544 int subpixel,
4545 const char *make,
Kristian Høgsberg0e696472012-07-22 15:49:57 -04004546 const char *model,
4547 int transform)
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05004548{
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -05004549 struct output *output = data;
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05004550
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -05004551 output->allocation.x = x;
4552 output->allocation.y = y;
Scott Moreau4e072362012-09-29 02:03:11 -06004553 output->transform = transform;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04004554}
4555
4556static void
Alexander Larssonafd319a2013-05-22 14:41:27 +02004557display_handle_done(void *data,
4558 struct wl_output *wl_output)
4559{
4560}
4561
4562static void
4563display_handle_scale(void *data,
4564 struct wl_output *wl_output,
Alexander Larssonedddbd12013-05-24 13:09:43 +02004565 int32_t scale)
Alexander Larssonafd319a2013-05-22 14:41:27 +02004566{
4567 struct output *output = data;
4568
4569 output->scale = scale;
4570}
4571
4572static void
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04004573display_handle_mode(void *data,
4574 struct wl_output *wl_output,
4575 uint32_t flags,
4576 int width,
4577 int height,
4578 int refresh)
4579{
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -05004580 struct output *output = data;
Pekka Paalanen999c5b52011-11-30 10:52:38 +02004581 struct display *display = output->display;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04004582
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -05004583 if (flags & WL_OUTPUT_MODE_CURRENT) {
4584 output->allocation.width = width;
4585 output->allocation.height = height;
Pekka Paalanen999c5b52011-11-30 10:52:38 +02004586 if (display->output_configure_handler)
4587 (*display->output_configure_handler)(
4588 output, display->user_data);
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -05004589 }
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05004590}
4591
4592static const struct wl_output_listener output_listener = {
4593 display_handle_geometry,
Alexander Larssonafd319a2013-05-22 14:41:27 +02004594 display_handle_mode,
4595 display_handle_done,
4596 display_handle_scale
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05004597};
4598
4599static void
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -05004600display_add_output(struct display *d, uint32_t id)
4601{
4602 struct output *output;
4603
Kristian Høgsberg69594cc2013-08-15 14:28:25 -07004604 output = xzalloc(sizeof *output);
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -05004605 output->display = d;
Alexander Larssonafd319a2013-05-22 14:41:27 +02004606 output->scale = 1;
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -05004607 output->output =
Alexander Larssonafd319a2013-05-22 14:41:27 +02004608 wl_registry_bind(d->registry, id, &wl_output_interface, 2);
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -05004609 wl_list_insert(d->output_list.prev, &output->link);
4610
4611 wl_output_add_listener(output->output, &output_listener, output);
4612}
4613
Pekka Paalanen2c1426a2011-12-16 11:35:34 +02004614static void
4615output_destroy(struct output *output)
4616{
4617 if (output->destroy_handler)
4618 (*output->destroy_handler)(output, output->user_data);
4619
4620 wl_output_destroy(output->output);
4621 wl_list_remove(&output->link);
4622 free(output);
4623}
4624
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -05004625void
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04004626display_set_global_handler(struct display *display,
4627 display_global_handler_t handler)
4628{
4629 struct global *global;
4630
4631 display->global_handler = handler;
4632 if (!handler)
4633 return;
4634
4635 wl_list_for_each(global, &display->global_list, link)
4636 display->global_handler(display,
4637 global->name, global->interface,
4638 global->version, display->user_data);
4639}
4640
4641void
Pekka Paalanen999c5b52011-11-30 10:52:38 +02004642display_set_output_configure_handler(struct display *display,
4643 display_output_handler_t handler)
4644{
4645 struct output *output;
4646
4647 display->output_configure_handler = handler;
4648 if (!handler)
4649 return;
4650
Pekka Paalanenb2f957a2012-10-15 12:06:53 +03004651 wl_list_for_each(output, &display->output_list, link) {
4652 if (output->allocation.width == 0 &&
4653 output->allocation.height == 0)
4654 continue;
4655
Pekka Paalanen999c5b52011-11-30 10:52:38 +02004656 (*display->output_configure_handler)(output,
4657 display->user_data);
Pekka Paalanenb2f957a2012-10-15 12:06:53 +03004658 }
Pekka Paalanen999c5b52011-11-30 10:52:38 +02004659}
4660
4661void
4662output_set_user_data(struct output *output, void *data)
4663{
4664 output->user_data = data;
4665}
4666
4667void *
4668output_get_user_data(struct output *output)
4669{
4670 return output->user_data;
4671}
4672
4673void
4674output_set_destroy_handler(struct output *output,
4675 display_output_handler_t handler)
4676{
4677 output->destroy_handler = handler;
4678 /* FIXME: implement this, once we have way to remove outputs */
4679}
4680
4681void
Scott Moreau4e072362012-09-29 02:03:11 -06004682output_get_allocation(struct output *output, struct rectangle *base)
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -05004683{
Scott Moreau4e072362012-09-29 02:03:11 -06004684 struct rectangle allocation = output->allocation;
4685
4686 switch (output->transform) {
4687 case WL_OUTPUT_TRANSFORM_90:
4688 case WL_OUTPUT_TRANSFORM_270:
4689 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
4690 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
4691 /* Swap width and height */
4692 allocation.width = output->allocation.height;
4693 allocation.height = output->allocation.width;
4694 break;
4695 }
4696
4697 *base = allocation;
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -05004698}
4699
Pekka Paalanen999c5b52011-11-30 10:52:38 +02004700struct wl_output *
4701output_get_wl_output(struct output *output)
4702{
4703 return output->output;
4704}
4705
Ander Conselvan de Oliveira15256f62012-11-30 17:34:25 +02004706enum wl_output_transform
4707output_get_transform(struct output *output)
4708{
4709 return output->transform;
4710}
4711
Alexander Larssonafd319a2013-05-22 14:41:27 +02004712uint32_t
4713output_get_scale(struct output *output)
4714{
4715 return output->scale;
4716}
4717
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -05004718static void
Daniel Stone97f68542012-05-30 16:32:01 +01004719fini_xkb(struct input *input)
4720{
4721 xkb_state_unref(input->xkb.state);
4722 xkb_map_unref(input->xkb.keymap);
4723}
4724
Rob Bradford08031182013-08-13 20:11:03 +01004725#define MAX(a,b) ((a) > (b) ? a : b)
4726
Daniel Stone97f68542012-05-30 16:32:01 +01004727static void
Kristian Høgsberg4fe1a3e2010-08-10 14:02:48 -04004728display_add_input(struct display *d, uint32_t id)
Kristian Høgsberg808fd412010-07-20 17:06:19 -04004729{
4730 struct input *input;
4731
Kristian Høgsbergadcd54b2013-08-15 14:17:13 -07004732 input = xzalloc(sizeof *input);
Kristian Høgsberg808fd412010-07-20 17:06:19 -04004733 input->display = d;
Rob Bradford08031182013-08-13 20:11:03 +01004734 input->seat = wl_registry_bind(d->registry, id, &wl_seat_interface,
4735 MAX(d->seat_version, 3));
Rusty Lynch1084da52013-08-15 09:10:08 -07004736 input->touch_focus = NULL;
Kristian Høgsberg808fd412010-07-20 17:06:19 -04004737 input->pointer_focus = NULL;
4738 input->keyboard_focus = NULL;
Rusty Lynch041815a2013-08-08 21:20:38 -07004739 wl_list_init(&input->touch_point_list);
Kristian Høgsberg808fd412010-07-20 17:06:19 -04004740 wl_list_insert(d->input_list.prev, &input->link);
4741
Daniel Stone37816df2012-05-16 18:45:18 +01004742 wl_seat_add_listener(input->seat, &seat_listener, input);
4743 wl_seat_set_user_data(input->seat, input);
Kristian Høgsberg808fd412010-07-20 17:06:19 -04004744
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04004745 input->data_device =
4746 wl_data_device_manager_get_data_device(d->data_device_manager,
Daniel Stone37816df2012-05-16 18:45:18 +01004747 input->seat);
4748 wl_data_device_add_listener(input->data_device, &data_device_listener,
4749 input);
Ander Conselvan de Oliveira37ffc3c2012-06-15 17:27:35 +03004750
4751 input->pointer_surface = wl_compositor_create_surface(d->compositor);
Kristian Høgsbergcf4d2442012-06-20 14:52:12 -04004752
Kristian Høgsberg8b19c642012-06-20 18:00:13 -04004753 input->repeat_timer_fd = timerfd_create(CLOCK_MONOTONIC,
4754 TFD_CLOEXEC | TFD_NONBLOCK);
Kristian Høgsbergcf4d2442012-06-20 14:52:12 -04004755 input->repeat_task.run = keyboard_repeat_func;
4756 display_watch_fd(d, input->repeat_timer_fd,
4757 EPOLLIN, &input->repeat_task);
Kristian Høgsberg58eec362011-01-19 14:27:42 -05004758}
4759
Kristian Høgsberg808fd412010-07-20 17:06:19 -04004760static void
Pekka Paalanene1207c72011-12-16 12:02:09 +02004761input_destroy(struct input *input)
4762{
Kristian Høgsberg8a1d10d2011-12-21 17:11:45 -05004763 input_remove_keyboard_focus(input);
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04004764 input_remove_pointer_focus(input);
Pekka Paalanene1207c72011-12-16 12:02:09 +02004765
4766 if (input->drag_offer)
4767 data_offer_destroy(input->drag_offer);
4768
4769 if (input->selection_offer)
4770 data_offer_destroy(input->selection_offer);
4771
4772 wl_data_device_destroy(input->data_device);
Rob Bradford08031182013-08-13 20:11:03 +01004773
4774 if (input->display->seat_version >= 3) {
4775 if (input->pointer)
4776 wl_pointer_release(input->pointer);
4777 if (input->keyboard)
4778 wl_keyboard_release(input->keyboard);
4779 }
4780
Daniel Stone97f68542012-05-30 16:32:01 +01004781 fini_xkb(input);
4782
Ander Conselvan de Oliveira37ffc3c2012-06-15 17:27:35 +03004783 wl_surface_destroy(input->pointer_surface);
4784
Pekka Paalanene1207c72011-12-16 12:02:09 +02004785 wl_list_remove(&input->link);
Daniel Stone37816df2012-05-16 18:45:18 +01004786 wl_seat_destroy(input->seat);
Kristian Høgsbergcf4d2442012-06-20 14:52:12 -04004787 close(input->repeat_timer_fd);
Pekka Paalanene1207c72011-12-16 12:02:09 +02004788 free(input);
4789}
4790
4791static void
Jonas Ådahl14c92ff2012-08-29 22:13:02 +02004792init_workspace_manager(struct display *d, uint32_t id)
4793{
4794 d->workspace_manager =
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04004795 wl_registry_bind(d->registry, id,
4796 &workspace_manager_interface, 1);
Jonas Ådahl14c92ff2012-08-29 22:13:02 +02004797 if (d->workspace_manager != NULL)
4798 workspace_manager_add_listener(d->workspace_manager,
4799 &workspace_manager_listener,
4800 d);
4801}
4802
4803static void
Tomeu Vizosobee45a12013-08-06 20:05:54 +02004804shm_format(void *data, struct wl_shm *wl_shm, uint32_t format)
4805{
4806 struct display *d = data;
4807
4808 if (format == WL_SHM_FORMAT_RGB565)
4809 d->has_rgb565 = 1;
4810}
4811
4812struct wl_shm_listener shm_listener = {
4813 shm_format
4814};
4815
4816static void
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04004817registry_handle_global(void *data, struct wl_registry *registry, uint32_t id,
4818 const char *interface, uint32_t version)
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05004819{
4820 struct display *d = data;
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04004821 struct global *global;
4822
Brian Lovinbc919262013-08-07 15:34:59 -07004823 global = xmalloc(sizeof *global);
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04004824 global->name = id;
4825 global->interface = strdup(interface);
4826 global->version = version;
4827 wl_list_insert(d->global_list.prev, &global->link);
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05004828
Kristian Høgsberg7cbdb642011-04-20 18:53:07 -04004829 if (strcmp(interface, "wl_compositor") == 0) {
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04004830 d->compositor = wl_registry_bind(registry, id,
Jason Ekstrandd27cb092013-06-26 22:20:31 -05004831 &wl_compositor_interface, 3);
Kristian Høgsberg7cbdb642011-04-20 18:53:07 -04004832 } else if (strcmp(interface, "wl_output") == 0) {
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -05004833 display_add_output(d, id);
Daniel Stone37816df2012-05-16 18:45:18 +01004834 } else if (strcmp(interface, "wl_seat") == 0) {
Rob Bradford08031182013-08-13 20:11:03 +01004835 d->seat_version = version;
Kristian Høgsberg4fe1a3e2010-08-10 14:02:48 -04004836 display_add_input(d, id);
Kristian Høgsberg7cbdb642011-04-20 18:53:07 -04004837 } else if (strcmp(interface, "wl_shell") == 0) {
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04004838 d->shell = wl_registry_bind(registry,
4839 id, &wl_shell_interface, 1);
Kristian Høgsberg7cbdb642011-04-20 18:53:07 -04004840 } else if (strcmp(interface, "wl_shm") == 0) {
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04004841 d->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
Tomeu Vizosobee45a12013-08-06 20:05:54 +02004842 wl_shm_add_listener(d->shm, &shm_listener, d);
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04004843 } else if (strcmp(interface, "wl_data_device_manager") == 0) {
4844 d->data_device_manager =
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04004845 wl_registry_bind(registry, id,
4846 &wl_data_device_manager_interface, 1);
Scott Moreau7a1b32a2012-05-27 14:25:02 -06004847 } else if (strcmp(interface, "text_cursor_position") == 0) {
4848 d->text_cursor_position =
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04004849 wl_registry_bind(registry, id,
4850 &text_cursor_position_interface, 1);
Jonas Ådahl14c92ff2012-08-29 22:13:02 +02004851 } else if (strcmp(interface, "workspace_manager") == 0) {
4852 init_workspace_manager(d, id);
Pekka Paalanen35e82632013-04-25 13:57:48 +03004853 } else if (strcmp(interface, "wl_subcompositor") == 0) {
4854 d->subcompositor =
4855 wl_registry_bind(registry, id,
4856 &wl_subcompositor_interface, 1);
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05004857 }
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04004858
4859 if (d->global_handler)
4860 d->global_handler(d, id, interface, version, d->user_data);
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05004861}
4862
Pekka Paalanen0eab05d2013-01-22 14:53:55 +02004863static void
4864registry_handle_global_remove(void *data, struct wl_registry *registry,
4865 uint32_t name)
4866{
4867 struct display *d = data;
4868 struct global *global;
4869 struct global *tmp;
4870
4871 wl_list_for_each_safe(global, tmp, &d->global_list, link) {
4872 if (global->name != name)
4873 continue;
4874
4875 /* XXX: Should destroy bound globals, and call
4876 * the counterpart of display::global_handler
4877 */
4878 wl_list_remove(&global->link);
4879 free(global->interface);
4880 free(global);
4881 }
4882}
4883
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04004884void *
4885display_bind(struct display *display, uint32_t name,
4886 const struct wl_interface *interface, uint32_t version)
4887{
4888 return wl_registry_bind(display->registry, name, interface, version);
4889}
4890
4891static const struct wl_registry_listener registry_listener = {
Pekka Paalanen0eab05d2013-01-22 14:53:55 +02004892 registry_handle_global,
4893 registry_handle_global_remove
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04004894};
4895
Kristian Høgsberg8f64ed02012-04-03 11:57:44 -04004896#ifdef HAVE_CAIRO_EGL
Yuval Fledel45568f62010-12-06 09:18:12 -05004897static int
Kristian Høgsberg297c6312011-02-04 14:11:33 -05004898init_egl(struct display *d)
Yuval Fledel45568f62010-12-06 09:18:12 -05004899{
4900 EGLint major, minor;
Benjamin Franzke6693ac22011-02-10 12:04:30 +01004901 EGLint n;
Kristian Høgsbergf389cac2011-08-31 16:21:38 -04004902
Rob Clark6396ed32012-03-11 19:48:41 -05004903#ifdef USE_CAIRO_GLESV2
4904# define GL_BIT EGL_OPENGL_ES2_BIT
4905#else
4906# define GL_BIT EGL_OPENGL_BIT
4907#endif
4908
Kristian Høgsberg8e81df42012-01-11 14:24:46 -05004909 static const EGLint argb_cfg_attribs[] = {
Kristian Høgsberg31467562012-10-16 15:31:31 -04004910 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
Benjamin Franzke6693ac22011-02-10 12:04:30 +01004911 EGL_RED_SIZE, 1,
4912 EGL_GREEN_SIZE, 1,
4913 EGL_BLUE_SIZE, 1,
4914 EGL_ALPHA_SIZE, 1,
4915 EGL_DEPTH_SIZE, 1,
Rob Clark6396ed32012-03-11 19:48:41 -05004916 EGL_RENDERABLE_TYPE, GL_BIT,
Benjamin Franzke6693ac22011-02-10 12:04:30 +01004917 EGL_NONE
4918 };
Yuval Fledel45568f62010-12-06 09:18:12 -05004919
Kristian Høgsberg2d574392012-01-18 14:50:58 -05004920#ifdef USE_CAIRO_GLESV2
4921 static const EGLint context_attribs[] = {
4922 EGL_CONTEXT_CLIENT_VERSION, 2,
4923 EGL_NONE
4924 };
4925 EGLint api = EGL_OPENGL_ES_API;
4926#else
4927 EGLint *context_attribs = NULL;
4928 EGLint api = EGL_OPENGL_API;
4929#endif
4930
Kristian Høgsberg91342c62011-04-14 14:44:58 -04004931 d->dpy = eglGetDisplay(d->display);
Yuval Fledel45568f62010-12-06 09:18:12 -05004932 if (!eglInitialize(d->dpy, &major, &minor)) {
Pekka Paalanen4e106542013-02-14 11:49:12 +02004933 fprintf(stderr, "failed to initialize EGL\n");
Yuval Fledel45568f62010-12-06 09:18:12 -05004934 return -1;
4935 }
4936
Kristian Høgsberg2d574392012-01-18 14:50:58 -05004937 if (!eglBindAPI(api)) {
Pekka Paalanen4e106542013-02-14 11:49:12 +02004938 fprintf(stderr, "failed to bind EGL client API\n");
Yuval Fledel45568f62010-12-06 09:18:12 -05004939 return -1;
4940 }
4941
Kristian Høgsberg8e81df42012-01-11 14:24:46 -05004942 if (!eglChooseConfig(d->dpy, argb_cfg_attribs,
4943 &d->argb_config, 1, &n) || n != 1) {
Pekka Paalanen4e106542013-02-14 11:49:12 +02004944 fprintf(stderr, "failed to choose argb EGL config\n");
Benjamin Franzke6693ac22011-02-10 12:04:30 +01004945 return -1;
4946 }
4947
Kristian Høgsberg8e81df42012-01-11 14:24:46 -05004948 d->argb_ctx = eglCreateContext(d->dpy, d->argb_config,
Kristian Høgsberg2d574392012-01-18 14:50:58 -05004949 EGL_NO_CONTEXT, context_attribs);
Benjamin Franzke0c991632011-09-27 21:57:31 +02004950 if (d->argb_ctx == NULL) {
Pekka Paalanen4e106542013-02-14 11:49:12 +02004951 fprintf(stderr, "failed to create EGL context\n");
Yuval Fledel45568f62010-12-06 09:18:12 -05004952 return -1;
4953 }
4954
Benjamin Franzke0c991632011-09-27 21:57:31 +02004955 d->argb_device = cairo_egl_device_create(d->dpy, d->argb_ctx);
4956 if (cairo_device_status(d->argb_device) != CAIRO_STATUS_SUCCESS) {
Pekka Paalanen4e106542013-02-14 11:49:12 +02004957 fprintf(stderr, "failed to get cairo EGL argb device\n");
Benjamin Franzke0c991632011-09-27 21:57:31 +02004958 return -1;
4959 }
Yuval Fledel45568f62010-12-06 09:18:12 -05004960
4961 return 0;
4962}
4963
Pekka Paalanenfe6079a2011-12-15 15:20:04 +02004964static void
4965fini_egl(struct display *display)
4966{
Pekka Paalanenfe6079a2011-12-15 15:20:04 +02004967 cairo_device_destroy(display->argb_device);
Pekka Paalanenfe6079a2011-12-15 15:20:04 +02004968
4969 eglMakeCurrent(display->dpy, EGL_NO_SURFACE, EGL_NO_SURFACE,
4970 EGL_NO_CONTEXT);
4971
4972 eglTerminate(display->dpy);
4973 eglReleaseThread();
4974}
Kristian Høgsberg8f64ed02012-04-03 11:57:44 -04004975#endif
Pekka Paalanenfe6079a2011-12-15 15:20:04 +02004976
Kristian Høgsberg3a696272011-09-14 17:33:48 -04004977static void
Pekka Paalanen3cbb0892012-11-19 17:16:01 +02004978init_dummy_surface(struct display *display)
4979{
4980 int len;
4981 void *data;
4982
4983 len = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, 1);
4984 data = malloc(len);
4985 display->dummy_surface =
4986 cairo_image_surface_create_for_data(data, CAIRO_FORMAT_ARGB32,
4987 1, 1, len);
4988 display->dummy_surface_data = data;
4989}
4990
4991static void
Kristian Høgsberg3a696272011-09-14 17:33:48 -04004992handle_display_data(struct task *task, uint32_t events)
4993{
4994 struct display *display =
4995 container_of(task, struct display, display_task);
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04004996 struct epoll_event ep;
4997 int ret;
U. Artie Eoff44874d92012-10-02 21:12:35 -07004998
4999 display->display_fd_events = events;
5000
5001 if (events & EPOLLERR || events & EPOLLHUP) {
5002 display_exit(display);
5003 return;
5004 }
5005
Kristian Høgsberga17f7a12012-10-16 13:16:10 -04005006 if (events & EPOLLIN) {
5007 ret = wl_display_dispatch(display->display);
5008 if (ret == -1) {
5009 display_exit(display);
5010 return;
5011 }
5012 }
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04005013
5014 if (events & EPOLLOUT) {
5015 ret = wl_display_flush(display->display);
5016 if (ret == 0) {
5017 ep.events = EPOLLIN | EPOLLERR | EPOLLHUP;
5018 ep.data.ptr = &display->display_task;
5019 epoll_ctl(display->epoll_fd, EPOLL_CTL_MOD,
5020 display->display_fd, &ep);
5021 } else if (ret == -1 && errno != EAGAIN) {
5022 display_exit(display);
5023 return;
5024 }
5025 }
Kristian Høgsberg3a696272011-09-14 17:33:48 -04005026}
5027
Kristian Høgsberg2e437202013-04-16 11:21:48 -04005028static void
5029log_handler(const char *format, va_list args)
5030{
5031 vfprintf(stderr, format, args);
5032}
5033
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05005034struct display *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05005035display_create(int *argc, char *argv[])
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05005036{
5037 struct display *d;
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -04005038
Kristian Høgsberg2e437202013-04-16 11:21:48 -04005039 wl_log_set_handler_client(log_handler);
5040
Peter Huttererf3d62272013-08-08 11:57:05 +10005041 d = zalloc(sizeof *d);
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05005042 if (d == NULL)
5043 return NULL;
5044
Kristian Høgsberg2bb3ebe2010-12-01 15:36:20 -05005045 d->display = wl_display_connect(NULL);
Kristian Høgsberg478d9262010-06-08 20:34:11 -04005046 if (d->display == NULL) {
Pekka Paalanen4e106542013-02-14 11:49:12 +02005047 fprintf(stderr, "failed to connect to Wayland display: %m\n");
Rob Bradfordf0a1af92013-01-10 19:48:54 +00005048 free(d);
Kristian Høgsberg7824d812010-06-08 14:59:44 -04005049 return NULL;
5050 }
5051
Rob Bradford5ab9c752013-07-26 16:29:43 +01005052 d->xkb_context = xkb_context_new(0);
5053 if (d->xkb_context == NULL) {
5054 fprintf(stderr, "Failed to create XKB context\n");
5055 free(d);
5056 return NULL;
5057 }
5058
Pekka Paalanen647f2bf2012-05-30 15:53:43 +03005059 d->epoll_fd = os_epoll_create_cloexec();
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04005060 d->display_fd = wl_display_get_fd(d->display);
Kristian Høgsberg3a696272011-09-14 17:33:48 -04005061 d->display_task.run = handle_display_data;
U. Artie Eoff44874d92012-10-02 21:12:35 -07005062 display_watch_fd(d, d->display_fd, EPOLLIN | EPOLLERR | EPOLLHUP,
5063 &d->display_task);
Kristian Høgsberg3a696272011-09-14 17:33:48 -04005064
5065 wl_list_init(&d->deferred_list);
Kristian Høgsberg808fd412010-07-20 17:06:19 -04005066 wl_list_init(&d->input_list);
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -05005067 wl_list_init(&d->output_list);
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04005068 wl_list_init(&d->global_list);
Kristian Høgsberg808fd412010-07-20 17:06:19 -04005069
Jonas Ådahlf77beeb2012-10-08 22:49:04 +02005070 d->workspace = 0;
5071 d->workspace_count = 1;
5072
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04005073 d->registry = wl_display_get_registry(d->display);
5074 wl_registry_add_listener(d->registry, &registry_listener, d);
Pekka Paalanen33a68ea2013-02-14 12:18:00 +02005075
5076 if (wl_display_dispatch(d->display) < 0) {
5077 fprintf(stderr, "Failed to process Wayland connection: %m\n");
5078 return NULL;
5079 }
5080
Kristian Høgsberg8f64ed02012-04-03 11:57:44 -04005081#ifdef HAVE_CAIRO_EGL
Pekka Paalanen4e106542013-02-14 11:49:12 +02005082 if (init_egl(d) < 0)
5083 fprintf(stderr, "EGL does not seem to work, "
5084 "falling back to software rendering and wl_shm.\n");
Kristian Høgsberg8f64ed02012-04-03 11:57:44 -04005085#endif
Kristian Høgsberg8a9cda82008-11-03 15:31:30 -05005086
Ander Conselvan de Oliveirad8f527c2012-05-25 09:30:02 +03005087 create_cursors(d);
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04005088
Kristian Høgsberg5adb4802012-05-15 22:25:28 -04005089 d->theme = theme_create();
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -04005090
Kristian Høgsberg478d9262010-06-08 20:34:11 -04005091 wl_list_init(&d->window_list);
5092
Pekka Paalanen3cbb0892012-11-19 17:16:01 +02005093 init_dummy_surface(d);
5094
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05005095 return d;
5096}
5097
Pekka Paalanen2c1426a2011-12-16 11:35:34 +02005098static void
5099display_destroy_outputs(struct display *display)
5100{
5101 struct output *tmp;
5102 struct output *output;
5103
5104 wl_list_for_each_safe(output, tmp, &display->output_list, link)
5105 output_destroy(output);
5106}
5107
Pekka Paalanene1207c72011-12-16 12:02:09 +02005108static void
5109display_destroy_inputs(struct display *display)
5110{
5111 struct input *tmp;
5112 struct input *input;
5113
5114 wl_list_for_each_safe(input, tmp, &display->input_list, link)
5115 input_destroy(input);
5116}
5117
Pekka Paalanen999c5b52011-11-30 10:52:38 +02005118void
Pekka Paalanenfe6079a2011-12-15 15:20:04 +02005119display_destroy(struct display *display)
5120{
Pekka Paalanenc2052982011-12-16 11:41:32 +02005121 if (!wl_list_empty(&display->window_list))
U. Artie Eoff44874d92012-10-02 21:12:35 -07005122 fprintf(stderr, "toytoolkit warning: %d windows exist.\n",
5123 wl_list_length(&display->window_list));
Pekka Paalanenc2052982011-12-16 11:41:32 +02005124
5125 if (!wl_list_empty(&display->deferred_list))
5126 fprintf(stderr, "toytoolkit warning: deferred tasks exist.\n");
5127
Pekka Paalanen3cbb0892012-11-19 17:16:01 +02005128 cairo_surface_destroy(display->dummy_surface);
5129 free(display->dummy_surface_data);
5130
Pekka Paalanen2c1426a2011-12-16 11:35:34 +02005131 display_destroy_outputs(display);
Pekka Paalanene1207c72011-12-16 12:02:09 +02005132 display_destroy_inputs(display);
Pekka Paalanen2c1426a2011-12-16 11:35:34 +02005133
Daniel Stone97f68542012-05-30 16:32:01 +01005134 xkb_context_unref(display->xkb_context);
Pekka Paalanen325bb602011-12-19 10:31:45 +02005135
Kristian Høgsberg5adb4802012-05-15 22:25:28 -04005136 theme_destroy(display->theme);
Ander Conselvan de Oliveirad8f527c2012-05-25 09:30:02 +03005137 destroy_cursors(display);
Pekka Paalanen325bb602011-12-19 10:31:45 +02005138
Kristian Høgsberg8f64ed02012-04-03 11:57:44 -04005139#ifdef HAVE_CAIRO_EGL
Kristian Høgsberg4e51b442013-01-07 15:47:14 -05005140 if (display->argb_device)
5141 fini_egl(display);
Kristian Høgsberg8f64ed02012-04-03 11:57:44 -04005142#endif
Pekka Paalanenfe6079a2011-12-15 15:20:04 +02005143
Pekka Paalanen35e82632013-04-25 13:57:48 +03005144 if (display->subcompositor)
5145 wl_subcompositor_destroy(display->subcompositor);
5146
Pekka Paalanenc2052982011-12-16 11:41:32 +02005147 if (display->shell)
5148 wl_shell_destroy(display->shell);
5149
5150 if (display->shm)
5151 wl_shm_destroy(display->shm);
5152
5153 if (display->data_device_manager)
5154 wl_data_device_manager_destroy(display->data_device_manager);
5155
5156 wl_compositor_destroy(display->compositor);
Pekka Paalanenaac1c132012-12-04 16:01:15 +02005157 wl_registry_destroy(display->registry);
Pekka Paalanenc2052982011-12-16 11:41:32 +02005158
5159 close(display->epoll_fd);
5160
U. Artie Eoff44874d92012-10-02 21:12:35 -07005161 if (!(display->display_fd_events & EPOLLERR) &&
5162 !(display->display_fd_events & EPOLLHUP))
5163 wl_display_flush(display->display);
5164
Kristian Høgsbergfcfc83f2012-02-28 14:29:19 -05005165 wl_display_disconnect(display->display);
Pekka Paalanenfe6079a2011-12-15 15:20:04 +02005166 free(display);
5167}
5168
5169void
Pekka Paalanen999c5b52011-11-30 10:52:38 +02005170display_set_user_data(struct display *display, void *data)
5171{
5172 display->user_data = data;
5173}
5174
5175void *
5176display_get_user_data(struct display *display)
5177{
5178 return display->user_data;
5179}
5180
Kristian Høgsberg9d69f8e2010-09-03 14:46:38 -04005181struct wl_display *
5182display_get_display(struct display *display)
5183{
5184 return display->display;
5185}
5186
Kristian Høgsbergb20b0092013-08-15 11:54:03 -07005187int
5188display_has_subcompositor(struct display *display)
5189{
5190 if (display->subcompositor)
5191 return 1;
5192
5193 wl_display_roundtrip(display->display);
5194
5195 return display->subcompositor != NULL;
5196}
5197
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -04005198cairo_device_t *
5199display_get_cairo_device(struct display *display)
5200{
5201 return display->argb_device;
5202}
5203
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -05005204struct output *
5205display_get_output(struct display *display)
5206{
5207 return container_of(display->output_list.next, struct output, link);
5208}
5209
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05005210struct wl_compositor *
5211display_get_compositor(struct display *display)
5212{
5213 return display->compositor;
Kristian Høgsberg61017b12008-11-02 18:51:48 -05005214}
Kristian Høgsberg7824d812010-06-08 14:59:44 -04005215
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04005216uint32_t
5217display_get_serial(struct display *display)
5218{
5219 return display->serial;
5220}
5221
Kristian Høgsberg7824d812010-06-08 14:59:44 -04005222EGLDisplay
5223display_get_egl_display(struct display *d)
5224{
5225 return d->dpy;
5226}
5227
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04005228struct wl_data_source *
5229display_create_data_source(struct display *display)
5230{
5231 return wl_data_device_manager_create_data_source(display->data_device_manager);
5232}
5233
Benjamin Franzkecff904e2011-02-18 23:00:55 +01005234EGLConfig
Benjamin Franzke0c991632011-09-27 21:57:31 +02005235display_get_argb_egl_config(struct display *d)
5236{
Kristian Høgsberg8e81df42012-01-11 14:24:46 -05005237 return d->argb_config;
Benjamin Franzke0c991632011-09-27 21:57:31 +02005238}
5239
Kristian Høgsberg58eec362011-01-19 14:27:42 -05005240struct wl_shell *
5241display_get_shell(struct display *display)
5242{
5243 return display->shell;
5244}
5245
Benjamin Franzke1a89f282011-10-07 09:33:06 +02005246int
Benjamin Franzkecff904e2011-02-18 23:00:55 +01005247display_acquire_window_surface(struct display *display,
5248 struct window *window,
5249 EGLContext ctx)
5250{
Pekka Paalanen811ec4f2013-02-13 16:17:14 +02005251 struct surface *surface = window->main_surface;
5252
Pekka Paalanen02bba7c2013-02-13 16:17:15 +02005253 if (surface->buffer_type != WINDOW_BUFFER_TYPE_EGL_WINDOW)
Benjamin Franzke1a89f282011-10-07 09:33:06 +02005254 return -1;
Benjamin Franzkecff904e2011-02-18 23:00:55 +01005255
Pekka Paalanen6f41b072013-02-20 13:39:17 +02005256 widget_get_cairo_surface(window->main_surface->widget);
Pekka Paalanen811ec4f2013-02-13 16:17:14 +02005257 return surface->toysurface->acquire(surface->toysurface, ctx);
Benjamin Franzkecff904e2011-02-18 23:00:55 +01005258}
5259
5260void
Benjamin Franzke0c991632011-09-27 21:57:31 +02005261display_release_window_surface(struct display *display,
5262 struct window *window)
Benjamin Franzkecff904e2011-02-18 23:00:55 +01005263{
Pekka Paalanen811ec4f2013-02-13 16:17:14 +02005264 struct surface *surface = window->main_surface;
5265
Pekka Paalanen02bba7c2013-02-13 16:17:15 +02005266 if (surface->buffer_type != WINDOW_BUFFER_TYPE_EGL_WINDOW)
Benjamin Franzke0c991632011-09-27 21:57:31 +02005267 return;
5268
Pekka Paalanen811ec4f2013-02-13 16:17:14 +02005269 surface->toysurface->release(surface->toysurface);
Benjamin Franzkecff904e2011-02-18 23:00:55 +01005270}
5271
5272void
Kristian Høgsberg3a696272011-09-14 17:33:48 -04005273display_defer(struct display *display, struct task *task)
Kristian Høgsberg7824d812010-06-08 14:59:44 -04005274{
Kristian Høgsberg3a696272011-09-14 17:33:48 -04005275 wl_list_insert(&display->deferred_list, &task->link);
5276}
5277
5278void
5279display_watch_fd(struct display *display,
5280 int fd, uint32_t events, struct task *task)
5281{
5282 struct epoll_event ep;
5283
5284 ep.events = events;
5285 ep.data.ptr = task;
5286 epoll_ctl(display->epoll_fd, EPOLL_CTL_ADD, fd, &ep);
5287}
5288
5289void
Dima Ryazanova85292e2012-11-29 00:27:09 -08005290display_unwatch_fd(struct display *display, int fd)
5291{
5292 epoll_ctl(display->epoll_fd, EPOLL_CTL_DEL, fd, NULL);
5293}
5294
5295void
Kristian Høgsberg3a696272011-09-14 17:33:48 -04005296display_run(struct display *display)
5297{
5298 struct task *task;
5299 struct epoll_event ep[16];
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04005300 int i, count, ret;
Kristian Høgsberg3a696272011-09-14 17:33:48 -04005301
Pekka Paalanen826d7952011-12-15 10:14:07 +02005302 display->running = 1;
Kristian Høgsberg3a696272011-09-14 17:33:48 -04005303 while (1) {
Kristian Høgsberg3a696272011-09-14 17:33:48 -04005304 while (!wl_list_empty(&display->deferred_list)) {
Tiago Vignatti6f093382012-09-27 14:46:23 +03005305 task = container_of(display->deferred_list.prev,
Kristian Høgsberg3a696272011-09-14 17:33:48 -04005306 struct task, link);
5307 wl_list_remove(&task->link);
5308 task->run(task, 0);
5309 }
Kristian Høgsberg9ca2d082012-01-09 18:48:14 -05005310
Kristian Høgsbergfeb3c1d2012-10-15 12:56:11 -04005311 wl_display_dispatch_pending(display->display);
5312
Kristian Høgsberg9ca2d082012-01-09 18:48:14 -05005313 if (!display->running)
5314 break;
5315
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04005316 ret = wl_display_flush(display->display);
5317 if (ret < 0 && errno == EAGAIN) {
5318 ep[0].events =
5319 EPOLLIN | EPOLLOUT | EPOLLERR | EPOLLHUP;
5320 ep[0].data.ptr = &display->display_task;
5321
5322 epoll_ctl(display->epoll_fd, EPOLL_CTL_MOD,
5323 display->display_fd, &ep[0]);
5324 } else if (ret < 0) {
5325 break;
5326 }
Kristian Høgsberg9ca2d082012-01-09 18:48:14 -05005327
5328 count = epoll_wait(display->epoll_fd,
5329 ep, ARRAY_LENGTH(ep), -1);
5330 for (i = 0; i < count; i++) {
5331 task = ep[i].data.ptr;
5332 task->run(task, ep[i].events);
5333 }
Kristian Høgsberg3a696272011-09-14 17:33:48 -04005334 }
Kristian Høgsberg7824d812010-06-08 14:59:44 -04005335}
Pekka Paalanen826d7952011-12-15 10:14:07 +02005336
5337void
5338display_exit(struct display *display)
5339{
5340 display->running = 0;
5341}
Jan Arne Petersencd997062012-11-18 19:06:44 +01005342
5343void
5344keysym_modifiers_add(struct wl_array *modifiers_map,
5345 const char *name)
5346{
5347 size_t len = strlen(name) + 1;
5348 char *p;
5349
5350 p = wl_array_add(modifiers_map, len);
5351
5352 if (p == NULL)
5353 return;
5354
5355 strncpy(p, name, len);
5356}
5357
5358static xkb_mod_index_t
5359keysym_modifiers_get_index(struct wl_array *modifiers_map,
5360 const char *name)
5361{
5362 xkb_mod_index_t index = 0;
5363 char *p = modifiers_map->data;
5364
5365 while ((const char *)p < (const char *)(modifiers_map->data + modifiers_map->size)) {
5366 if (strcmp(p, name) == 0)
5367 return index;
5368
5369 index++;
5370 p += strlen(p) + 1;
5371 }
5372
5373 return XKB_MOD_INVALID;
5374}
5375
5376xkb_mod_mask_t
5377keysym_modifiers_get_mask(struct wl_array *modifiers_map,
5378 const char *name)
5379{
5380 xkb_mod_index_t index = keysym_modifiers_get_index(modifiers_map, name);
5381
5382 if (index == XKB_MOD_INVALID)
5383 return XKB_MOD_INVALID;
5384
5385 return 1 << index;
5386}
Kristian Høgsbergce278412013-07-25 15:20:20 -07005387
5388void *
5389fail_on_null(void *p)
5390{
5391 if (p == NULL) {
Peter Hutterer3ca59d32013-08-08 17:13:47 +10005392 fprintf(stderr, "%s: out of memory\n", program_invocation_short_name);
Kristian Høgsbergce278412013-07-25 15:20:20 -07005393 exit(EXIT_FAILURE);
5394 }
5395
5396 return p;
5397}
5398
5399void *
5400xmalloc(size_t s)
5401{
5402 return fail_on_null(malloc(s));
5403}
5404
Peter Huttererf3d62272013-08-08 11:57:05 +10005405void *
5406xzalloc(size_t s)
5407{
5408 return fail_on_null(zalloc(s));
5409}
5410
Kristian Høgsbergce278412013-07-25 15:20:20 -07005411char *
5412xstrdup(const char *s)
5413{
5414 return fail_on_null(strdup(s));
5415}