blob: 3870898c2ec80d3aa6469a5f3e654023d4383d3b [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
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -040024#define _GNU_SOURCE
25
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -040026#include "../config.h"
27
Kristian Høgsberg61017b12008-11-02 18:51:48 -050028#include <stdint.h>
29#include <stdio.h>
30#include <stdlib.h>
Pekka Paalanen71233882013-04-25 13:57:53 +030031#include <stdarg.h>
Kristian Høgsberg61017b12008-11-02 18:51:48 -050032#include <string.h>
Kristian Høgsberg61017b12008-11-02 18:51:48 -050033#include <fcntl.h>
34#include <unistd.h>
Kristian Høgsbergfa80e112012-10-10 21:34:26 -040035#include <errno.h>
Kristian Høgsberg61017b12008-11-02 18:51:48 -050036#include <math.h>
Benjamin Franzke0c991632011-09-27 21:57:31 +020037#include <assert.h>
Kristian Høgsberg61017b12008-11-02 18:51:48 -050038#include <time.h>
39#include <cairo.h>
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -040040#include <sys/mman.h>
Kristian Høgsberg3a696272011-09-14 17:33:48 -040041#include <sys/epoll.h>
Tiago Vignatti82db9d82012-05-23 22:06:27 +030042#include <sys/timerfd.h>
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -040043
Pekka Paalanenfb39d8d2012-10-16 17:27:19 +030044#ifdef HAVE_CAIRO_EGL
Kristian Høgsberg297d6dd2011-02-09 10:51:15 -050045#include <wayland-egl.h>
46
Rob Clark6396ed32012-03-11 19:48:41 -050047#ifdef USE_CAIRO_GLESV2
48#include <GLES2/gl2.h>
49#include <GLES2/gl2ext.h>
50#else
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -040051#include <GL/gl.h>
Rob Clark6396ed32012-03-11 19:48:41 -050052#endif
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -040053#include <EGL/egl.h>
54#include <EGL/eglext.h>
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -040055
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -040056#include <cairo-gl.h>
Pekka Paalanenfb39d8d2012-10-16 17:27:19 +030057#else /* HAVE_CAIRO_EGL */
58typedef void *EGLDisplay;
59typedef void *EGLConfig;
60typedef void *EGLContext;
61#define EGL_NO_DISPLAY ((EGLDisplay)0)
62#endif /* no HAVE_CAIRO_EGL */
Kristian Høgsberg61017b12008-11-02 18:51:48 -050063
Daniel Stone9d4f0302012-02-15 16:33:21 +000064#include <xkbcommon/xkbcommon.h>
Ander Conselvan de Oliveira1042dc12012-05-22 15:39:42 +030065#include <wayland-cursor.h>
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -040066
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -050067#include <linux/input.h>
Pekka Paalanen50719bc2011-11-22 14:18:50 +020068#include <wayland-client.h>
Kristian Høgsberg5a315bc2012-05-15 22:33:43 -040069#include "../shared/cairo-util.h"
Scott Moreau7a1b32a2012-05-27 14:25:02 -060070#include "text-cursor-position-client-protocol.h"
Jonas Ådahl14c92ff2012-08-29 22:13:02 +020071#include "workspaces-client-protocol.h"
Pekka Paalanen647f2bf2012-05-30 15:53:43 +030072#include "../shared/os-compatibility.h"
Kristian Høgsberg2f2cfae2008-11-08 22:46:30 -050073
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -050074#include "window.h"
Kristian Høgsberg8a9cda82008-11-03 15:31:30 -050075
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -070076struct shm_pool;
Ander Conselvan de Oliveira1493d2a2012-05-03 12:29:46 +030077
Kristian Høgsbergfa80e112012-10-10 21:34:26 -040078struct global {
79 uint32_t name;
80 char *interface;
81 uint32_t version;
82 struct wl_list link;
83};
84
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -050085struct display {
Kristian Høgsberg40979232008-11-25 22:40:39 -050086 struct wl_display *display;
Kristian Høgsbergfa80e112012-10-10 21:34:26 -040087 struct wl_registry *registry;
Kristian Høgsbergd2412e22008-12-15 20:35:24 -050088 struct wl_compositor *compositor;
Pekka Paalanen35e82632013-04-25 13:57:48 +030089 struct wl_subcompositor *subcompositor;
Kristian Høgsberg83fc0612010-08-04 22:44:55 -040090 struct wl_shell *shell;
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -040091 struct wl_shm *shm;
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -040092 struct wl_data_device_manager *data_device_manager;
Scott Moreau7a1b32a2012-05-27 14:25:02 -060093 struct text_cursor_position *text_cursor_position;
Jonas Ådahl14c92ff2012-08-29 22:13:02 +020094 struct workspace_manager *workspace_manager;
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -040095 EGLDisplay dpy;
Kristian Høgsberg8e81df42012-01-11 14:24:46 -050096 EGLConfig argb_config;
Benjamin Franzke0c991632011-09-27 21:57:31 +020097 EGLContext argb_ctx;
Benjamin Franzke0c991632011-09-27 21:57:31 +020098 cairo_device_t *argb_device;
Kristian Høgsbergeae5de72012-04-11 22:42:15 -040099 uint32_t serial;
Kristian Høgsberg3a696272011-09-14 17:33:48 -0400100
101 int display_fd;
U. Artie Eoff44874d92012-10-02 21:12:35 -0700102 uint32_t display_fd_events;
Kristian Høgsberg3a696272011-09-14 17:33:48 -0400103 struct task display_task;
104
105 int epoll_fd;
106 struct wl_list deferred_list;
107
Pekka Paalanen826d7952011-12-15 10:14:07 +0200108 int running;
109
Kristian Høgsbergfa80e112012-10-10 21:34:26 -0400110 struct wl_list global_list;
Kristian Høgsberg478d9262010-06-08 20:34:11 -0400111 struct wl_list window_list;
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400112 struct wl_list input_list;
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -0500113 struct wl_list output_list;
Kristian Høgsberg291c69c2012-05-15 22:12:54 -0400114
Kristian Høgsberg5adb4802012-05-15 22:25:28 -0400115 struct theme *theme;
Kristian Høgsberg70163132012-05-08 15:55:39 -0400116
Ander Conselvan de Oliveira1042dc12012-05-22 15:39:42 +0300117 struct wl_cursor_theme *cursor_theme;
Ander Conselvan de Oliveirad8f527c2012-05-25 09:30:02 +0300118 struct wl_cursor **cursors;
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -0400119
Pekka Paalanen999c5b52011-11-30 10:52:38 +0200120 display_output_handler_t output_configure_handler;
Kristian Høgsbergfa80e112012-10-10 21:34:26 -0400121 display_global_handler_t global_handler;
Pekka Paalanen999c5b52011-11-30 10:52:38 +0200122
123 void *user_data;
Daniel Stone97f68542012-05-30 16:32:01 +0100124
125 struct xkb_context *xkb_context;
Jonas Ådahl14c92ff2012-08-29 22:13:02 +0200126
127 uint32_t workspace;
128 uint32_t workspace_count;
Pekka Paalanen3cbb0892012-11-19 17:16:01 +0200129
130 /* A hack to get text extents for tooltips */
131 cairo_surface_t *dummy_surface;
132 void *dummy_surface_data;
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -0500133};
134
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400135enum {
Kristian Høgsberg407ef642012-04-27 17:17:12 -0400136 TYPE_NONE,
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400137 TYPE_TOPLEVEL,
Kristian Høgsbergf8ab46e2011-09-08 16:56:38 -0400138 TYPE_FULLSCREEN,
Kristian Høgsbergd6bcd7d2012-02-16 15:53:46 -0500139 TYPE_MAXIMIZED,
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400140 TYPE_TRANSIENT,
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -0500141 TYPE_MENU,
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400142 TYPE_CUSTOM
143};
Rob Bradford7507b572012-05-15 17:55:34 +0100144
145struct window_output {
146 struct output *output;
147 struct wl_list link;
148};
149
Pekka Paalanen03fc3162012-11-19 17:15:58 +0200150struct toysurface {
151 /*
152 * Prepare the surface for drawing. Makes sure there is a surface
153 * of the right size available for rendering, and returns it.
154 * dx,dy are the x,y of wl_surface.attach.
Alexander Larsson5e9b6522013-05-22 14:41:28 +0200155 * width,height are the new buffer size.
Pekka Paalanenec076692012-11-30 13:37:27 +0200156 * If flags has SURFACE_HINT_RESIZE set, the user is
157 * doing continuous resizing.
Pekka Paalanen03fc3162012-11-19 17:15:58 +0200158 * Returns the Cairo surface to draw to.
159 */
160 cairo_surface_t *(*prepare)(struct toysurface *base, int dx, int dy,
Alexander Larsson1818e312013-05-22 14:41:31 +0200161 int32_t width, int32_t height, uint32_t flags,
Alexander Larssonedddbd12013-05-24 13:09:43 +0200162 enum wl_output_transform buffer_transform, int32_t buffer_scale);
Pekka Paalanen03fc3162012-11-19 17:15:58 +0200163
164 /*
165 * Post the surface to the server, returning the server allocation
166 * rectangle. The Cairo surface from prepare() must be destroyed
167 * after calling this.
168 */
169 void (*swap)(struct toysurface *base,
Alexander Larssonedddbd12013-05-24 13:09:43 +0200170 enum wl_output_transform buffer_transform, int32_t buffer_scale,
Pekka Paalanen03fc3162012-11-19 17:15:58 +0200171 struct rectangle *server_allocation);
172
173 /*
174 * Make the toysurface current with the given EGL context.
175 * Returns 0 on success, and negative of failure.
176 */
177 int (*acquire)(struct toysurface *base, EGLContext ctx);
178
179 /*
180 * Release the toysurface from the EGL context, returning control
181 * to Cairo.
182 */
183 void (*release)(struct toysurface *base);
184
185 /*
186 * Destroy the toysurface, including the Cairo surface, any
187 * backing storage, and the Wayland protocol objects.
188 */
189 void (*destroy)(struct toysurface *base);
190};
191
Pekka Paalanen4e373742013-02-13 16:17:13 +0200192struct surface {
193 struct window *window;
194
195 struct wl_surface *surface;
Pekka Paalanen35e82632013-04-25 13:57:48 +0300196 struct wl_subsurface *subsurface;
197 int synchronized;
198 int synchronized_default;
Pekka Paalanen811ec4f2013-02-13 16:17:14 +0200199 struct toysurface *toysurface;
Pekka Paalanenac95f3e2013-02-13 16:17:17 +0200200 struct widget *widget;
Pekka Paalanen40cb67b2013-04-25 13:57:49 +0300201 int redraw_needed;
202 struct wl_callback *frame_cb;
Pekka Paalanen7ff7a802013-04-25 13:57:50 +0300203 uint32_t last_time;
Pekka Paalanen811ec4f2013-02-13 16:17:14 +0200204
205 struct rectangle allocation;
206 struct rectangle server_allocation;
Pekka Paalanen02bba7c2013-02-13 16:17:15 +0200207
Pekka Paalanenb1cd9b12013-02-13 16:17:18 +0200208 struct wl_region *input_region;
209 struct wl_region *opaque_region;
210
Pekka Paalanen02bba7c2013-02-13 16:17:15 +0200211 enum window_buffer_type buffer_type;
212 enum wl_output_transform buffer_transform;
Alexander Larssonedddbd12013-05-24 13:09:43 +0200213 int32_t buffer_scale;
Pekka Paalanen89dee002013-02-13 16:17:20 +0200214
215 cairo_surface_t *cairo_surface;
Pekka Paalanen35e82632013-04-25 13:57:48 +0300216
217 struct wl_list link;
Pekka Paalanen4e373742013-02-13 16:17:13 +0200218};
219
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -0500220struct window {
221 struct display *display;
Kristian Høgsberg248c1b62011-01-21 18:03:15 -0500222 struct window *parent;
Rob Bradford7507b572012-05-15 17:55:34 +0100223 struct wl_list window_output_list;
Kristian Høgsbergd5fb9cc2011-01-25 12:45:37 -0500224 char *title;
Pekka Paalanen811ec4f2013-02-13 16:17:14 +0200225 struct rectangle saved_allocation;
Kristian Høgsbergd3a19652012-07-20 11:32:51 -0400226 struct rectangle min_allocation;
Kristian Høgsberg0d1c0622012-01-31 15:30:47 -0500227 struct rectangle pending_allocation;
Kristian Høgsberg248c1b62011-01-21 18:03:15 -0500228 int x, y;
Kristian Høgsberg83fc0612010-08-04 22:44:55 -0400229 int resize_edges;
Kristian Høgsberg6bd4d972012-03-24 14:42:09 -0400230 int redraw_needed;
Pekka Paalanen40cb67b2013-04-25 13:57:49 +0300231 int redraw_task_scheduled;
Kristian Høgsberg3a696272011-09-14 17:33:48 -0400232 struct task redraw_task;
Kristian Høgsberg42b4f802012-03-26 13:49:29 -0400233 int resize_needed;
Rafal Mielniczukc1a3cd12013-03-11 19:26:56 +0100234 int saved_type;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400235 int type;
Kristian Høgsberg86adef92012-08-13 22:25:53 -0400236 int focus_count;
237
Pekka Paalanen99436862012-11-19 17:15:59 +0200238 int resizing;
Ander Conselvan de Oliveira5403f522012-12-14 13:37:23 -0200239 int fullscreen_method;
MoD063a8822013-03-02 23:43:57 +0000240 int configure_requests;
Kristian Høgsberg1103a1a2012-04-03 12:00:48 -0400241
Kristian Høgsberg6e83d582008-12-08 00:01:36 -0500242 window_key_handler_t key_handler;
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -0500243 window_keyboard_focus_handler_t keyboard_focus_handler;
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400244 window_data_handler_t data_handler;
245 window_drop_handler_t drop_handler;
Kristian Høgsberg4f7dcd62012-01-06 21:59:05 -0500246 window_close_handler_t close_handler;
Kristian Høgsberg67ace202012-07-23 21:56:31 -0400247 window_fullscreen_handler_t fullscreen_handler;
Ander Conselvan de Oliveira15256f62012-11-30 17:34:25 +0200248 window_output_handler_t output_handler;
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400249
Pekka Paalanen4e373742013-02-13 16:17:13 +0200250 struct surface *main_surface;
251 struct wl_shell_surface *shell_surface;
Pekka Vuorela6e1e3852012-09-17 22:15:57 +0300252
Pekka Paalanen4dde2fc2012-01-19 13:33:50 +0200253 struct frame *frame;
Kristian Høgsberg4f7dcd62012-01-06 21:59:05 -0500254
Pekka Paalanen35e82632013-04-25 13:57:48 +0300255 /* struct surface::link, contains also main_surface */
256 struct wl_list subsurface_list;
257
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500258 void *user_data;
Kristian Høgsberg478d9262010-06-08 20:34:11 -0400259 struct wl_list link;
Kristian Høgsberg61017b12008-11-02 18:51:48 -0500260};
261
Kristian Høgsbergc51f7992012-01-08 15:09:53 -0500262struct widget {
Kristian Høgsberg9a13dab2012-01-08 15:18:19 -0500263 struct window *window;
Pekka Paalanen2d8a32a2013-02-13 16:17:19 +0200264 struct surface *surface;
Tiago Vignatti82db9d82012-05-23 22:06:27 +0300265 struct tooltip *tooltip;
Kristian Høgsberg441338c2012-01-10 13:52:34 -0500266 struct wl_list child_list;
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400267 struct wl_list link;
268 struct rectangle allocation;
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -0500269 widget_resize_handler_t resize_handler;
270 widget_redraw_handler_t redraw_handler;
Kristian Høgsbergee143232012-01-09 08:42:24 -0500271 widget_enter_handler_t enter_handler;
272 widget_leave_handler_t leave_handler;
Kristian Høgsberg04e98342012-01-09 09:36:16 -0500273 widget_motion_handler_t motion_handler;
Kristian Høgsberga8a0db32012-01-09 11:12:05 -0500274 widget_button_handler_t button_handler;
Philipp Brüschweiler7e0cc542012-08-14 11:02:41 +0200275 widget_axis_handler_t axis_handler;
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400276 void *user_data;
Kristian Høgsberg010f98b2012-02-23 17:30:45 -0500277 int opaque;
Tiago Vignatti82db9d82012-05-23 22:06:27 +0300278 int tooltip_count;
Kristian Høgsbergbf74d522012-11-30 14:54:35 -0500279 int default_cursor;
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400280};
281
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400282struct input {
283 struct display *display;
Daniel Stone37816df2012-05-16 18:45:18 +0100284 struct wl_seat *seat;
285 struct wl_pointer *pointer;
286 struct wl_keyboard *keyboard;
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400287 struct window *pointer_focus;
288 struct window *keyboard_focus;
Ander Conselvan de Oliveira1493d2a2012-05-03 12:29:46 +0300289 int current_cursor;
Ander Conselvan de Oliveira80620072012-06-15 17:27:36 +0300290 uint32_t cursor_anim_start;
291 struct wl_callback *cursor_frame_cb;
Ander Conselvan de Oliveira37ffc3c2012-06-15 17:27:35 +0300292 struct wl_surface *pointer_surface;
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400293 uint32_t modifiers;
Kristian Høgsbergeae5de72012-04-11 22:42:15 -0400294 uint32_t pointer_enter_serial;
Kristian Høgsberg11f600d2012-06-22 10:52:58 -0400295 uint32_t cursor_serial;
Kristian Høgsberg80680c72012-05-10 12:21:37 -0400296 float sx, sy;
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400297 struct wl_list link;
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400298
Kristian Høgsbergb6323512012-01-11 00:04:42 -0500299 struct widget *focus_widget;
Kristian Høgsberg831dd522012-01-10 23:46:33 -0500300 struct widget *grab;
301 uint32_t grab_button;
302
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400303 struct wl_data_device *data_device;
304 struct data_offer *drag_offer;
305 struct data_offer *selection_offer;
Daniel Stone97f68542012-05-30 16:32:01 +0100306
307 struct {
Daniel Stone97f68542012-05-30 16:32:01 +0100308 struct xkb_keymap *keymap;
309 struct xkb_state *state;
310 xkb_mod_mask_t control_mask;
311 xkb_mod_mask_t alt_mask;
312 xkb_mod_mask_t shift_mask;
313 } xkb;
Kristian Høgsbergcf4d2442012-06-20 14:52:12 -0400314
315 struct task repeat_task;
316 int repeat_timer_fd;
317 uint32_t repeat_sym;
318 uint32_t repeat_key;
319 uint32_t repeat_time;
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400320};
321
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -0500322struct output {
323 struct display *display;
324 struct wl_output *output;
325 struct rectangle allocation;
326 struct wl_list link;
Scott Moreau4e072362012-09-29 02:03:11 -0600327 int transform;
Alexander Larssonafd319a2013-05-22 14:41:27 +0200328 int scale;
Pekka Paalanen999c5b52011-11-30 10:52:38 +0200329
330 display_output_handler_t destroy_handler;
331 void *user_data;
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -0500332};
333
Martin Minarik1998b152012-05-10 02:04:35 +0200334enum frame_button_action {
335 FRAME_BUTTON_NULL = 0,
336 FRAME_BUTTON_ICON = 1,
337 FRAME_BUTTON_CLOSE = 2,
338 FRAME_BUTTON_MINIMIZE = 3,
339 FRAME_BUTTON_MAXIMIZE = 4,
340};
341
342enum frame_button_pointer {
343 FRAME_BUTTON_DEFAULT = 0,
344 FRAME_BUTTON_OVER = 1,
345 FRAME_BUTTON_ACTIVE = 2,
346};
347
348enum frame_button_align {
349 FRAME_BUTTON_RIGHT = 0,
350 FRAME_BUTTON_LEFT = 1,
351};
352
353enum frame_button_decoration {
354 FRAME_BUTTON_NONE = 0,
355 FRAME_BUTTON_FANCY = 1,
356};
357
358struct frame_button {
359 struct widget *widget;
360 struct frame *frame;
361 cairo_surface_t *icon;
362 enum frame_button_action type;
363 enum frame_button_pointer state;
364 struct wl_list link; /* buttons_list */
365 enum frame_button_align align;
366 enum frame_button_decoration decoration;
367};
368
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -0500369struct frame {
370 struct widget *widget;
371 struct widget *child;
Martin Minarik1998b152012-05-10 02:04:35 +0200372 struct wl_list buttons_list;
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -0500373};
374
Kristian Høgsberg4f7dcd62012-01-06 21:59:05 -0500375struct menu {
376 struct window *window;
Kristian Høgsberg75bc6672012-01-10 09:43:58 -0500377 struct widget *widget;
Kristian Høgsberg831dd522012-01-10 23:46:33 -0500378 struct input *input;
Kristian Høgsberg4f7dcd62012-01-06 21:59:05 -0500379 const char **entries;
380 uint32_t time;
381 int current;
382 int count;
Kristian Høgsbergd2fbb382012-10-30 13:45:22 -0400383 int release_count;
Kristian Høgsberg4f7dcd62012-01-06 21:59:05 -0500384 menu_func_t func;
385};
386
Tiago Vignatti82db9d82012-05-23 22:06:27 +0300387struct tooltip {
388 struct widget *parent;
389 struct window *window;
390 struct widget *widget;
391 char *entry;
392 struct task tooltip_task;
393 int tooltip_fd;
394 float x, y;
395};
396
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700397struct shm_pool {
398 struct wl_shm_pool *pool;
399 size_t size;
400 size_t used;
401 void *data;
402};
403
Kristian Høgsberg7d804062010-09-07 21:50:06 -0400404enum {
Ander Conselvan de Oliveiradc8c8fc2012-05-25 16:01:41 +0300405 CURSOR_DEFAULT = 100,
406 CURSOR_UNSET
Kristian Høgsberg7d804062010-09-07 21:50:06 -0400407};
408
Kristian Høgsberg82da52b2010-12-17 09:53:12 -0500409enum window_location {
410 WINDOW_INTERIOR = 0,
411 WINDOW_RESIZING_TOP = 1,
412 WINDOW_RESIZING_BOTTOM = 2,
413 WINDOW_RESIZING_LEFT = 4,
414 WINDOW_RESIZING_TOP_LEFT = 5,
415 WINDOW_RESIZING_BOTTOM_LEFT = 6,
416 WINDOW_RESIZING_RIGHT = 8,
417 WINDOW_RESIZING_TOP_RIGHT = 9,
418 WINDOW_RESIZING_BOTTOM_RIGHT = 10,
419 WINDOW_RESIZING_MASK = 15,
420 WINDOW_EXTERIOR = 16,
421 WINDOW_TITLEBAR = 17,
422 WINDOW_CLIENT_AREA = 18,
423};
424
Pekka Paalanen32127ca2012-11-19 15:32:51 +0200425static const cairo_user_data_key_t shm_surface_data_key;
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400426
Pekka Paalanen97777442013-05-22 10:20:05 +0300427/* #define DEBUG */
428
429#ifdef DEBUG
Pekka Paalanen71233882013-04-25 13:57:53 +0300430
431static void
432debug_print(void *proxy, int line, const char *func, const char *fmt, ...)
433__attribute__ ((format (printf, 4, 5)));
434
435static void
436debug_print(void *proxy, int line, const char *func, const char *fmt, ...)
437{
438 va_list ap;
439 struct timeval tv;
440
441 gettimeofday(&tv, NULL);
442 fprintf(stderr, "%8ld.%03ld ",
443 (long)tv.tv_sec & 0xffff, (long)tv.tv_usec / 1000);
444
445 if (proxy)
446 fprintf(stderr, "%s@%d ",
447 wl_proxy_get_class(proxy), wl_proxy_get_id(proxy));
448
449 /*fprintf(stderr, __FILE__ ":%d:%s ", line, func);*/
450 fprintf(stderr, "%s ", func);
451
452 va_start(ap, fmt);
453 vfprintf(stderr, fmt, ap);
454 va_end(ap);
455}
456
457#define DBG(fmt, ...) \
458 debug_print(NULL, __LINE__, __func__, fmt, ##__VA_ARGS__)
459
460#define DBG_OBJ(obj, fmt, ...) \
461 debug_print(obj, __LINE__, __func__, fmt, ##__VA_ARGS__)
462
463#else
464
465#define DBG(...) do {} while (0)
466#define DBG_OBJ(...) do {} while (0)
467
468#endif
469
Alexander Larsson1818e312013-05-22 14:41:31 +0200470static void
Alexander Larssonedddbd12013-05-24 13:09:43 +0200471surface_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 +0200472{
473 int32_t tmp;
474
475 switch (buffer_transform) {
476 case WL_OUTPUT_TRANSFORM_90:
477 case WL_OUTPUT_TRANSFORM_270:
478 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
479 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
480 tmp = *width;
481 *width = *height;
482 *height = tmp;
483 break;
484 default:
485 break;
486 }
487
488 *width *= buffer_scale;
489 *height *= buffer_scale;
490}
491
492static void
Alexander Larssonedddbd12013-05-24 13:09:43 +0200493buffer_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 +0200494{
495 int32_t tmp;
496
497 switch (buffer_transform) {
498 case WL_OUTPUT_TRANSFORM_90:
499 case WL_OUTPUT_TRANSFORM_270:
500 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
501 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
502 tmp = *width;
503 *width = *height;
504 *height = tmp;
505 break;
506 default:
507 break;
508 }
509
510 *width /= buffer_scale;
511 *height /= buffer_scale;
512}
513
Kristian Høgsberg8def2642011-01-14 17:41:33 -0500514#ifdef HAVE_CAIRO_EGL
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400515
Pekka Paalanen03fc3162012-11-19 17:15:58 +0200516struct egl_window_surface {
517 struct toysurface base;
518 cairo_surface_t *cairo_surface;
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100519 struct display *display;
520 struct wl_surface *surface;
Pekka Paalanen03fc3162012-11-19 17:15:58 +0200521 struct wl_egl_window *egl_window;
522 EGLSurface egl_surface;
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100523};
524
Pekka Paalanen03fc3162012-11-19 17:15:58 +0200525static struct egl_window_surface *
526to_egl_window_surface(struct toysurface *base)
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100527{
Pekka Paalanen03fc3162012-11-19 17:15:58 +0200528 return container_of(base, struct egl_window_surface, base);
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100529}
530
531static cairo_surface_t *
Pekka Paalanen03fc3162012-11-19 17:15:58 +0200532egl_window_surface_prepare(struct toysurface *base, int dx, int dy,
Alexander Larsson1818e312013-05-22 14:41:31 +0200533 int32_t width, int32_t height, uint32_t flags,
Alexander Larssonedddbd12013-05-24 13:09:43 +0200534 enum wl_output_transform buffer_transform, int32_t buffer_scale)
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100535{
Pekka Paalanen03fc3162012-11-19 17:15:58 +0200536 struct egl_window_surface *surface = to_egl_window_surface(base);
537
Alexander Larsson1818e312013-05-22 14:41:31 +0200538 surface_to_buffer_size (buffer_transform, buffer_scale, &width, &height);
539
Pekka Paalanen03fc3162012-11-19 17:15:58 +0200540 wl_egl_window_resize(surface->egl_window, width, height, dx, dy);
541 cairo_gl_surface_set_size(surface->cairo_surface, width, height);
542
543 return cairo_surface_reference(surface->cairo_surface);
544}
545
546static void
547egl_window_surface_swap(struct toysurface *base,
Alexander Larssonedddbd12013-05-24 13:09:43 +0200548 enum wl_output_transform buffer_transform, int32_t buffer_scale,
Pekka Paalanen03fc3162012-11-19 17:15:58 +0200549 struct rectangle *server_allocation)
550{
551 struct egl_window_surface *surface = to_egl_window_surface(base);
552
553 cairo_gl_surface_swapbuffers(surface->cairo_surface);
554 wl_egl_window_get_attached_size(surface->egl_window,
555 &server_allocation->width,
556 &server_allocation->height);
Alexander Larsson1818e312013-05-22 14:41:31 +0200557
558 buffer_to_surface_size (buffer_transform, buffer_scale,
559 &server_allocation->width,
560 &server_allocation->height);
Pekka Paalanen03fc3162012-11-19 17:15:58 +0200561}
562
563static int
564egl_window_surface_acquire(struct toysurface *base, EGLContext ctx)
565{
566 struct egl_window_surface *surface = to_egl_window_surface(base);
Benjamin Franzke0c991632011-09-27 21:57:31 +0200567 cairo_device_t *device;
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100568
Pekka Paalanen03fc3162012-11-19 17:15:58 +0200569 device = cairo_surface_get_device(surface->cairo_surface);
570 if (!device)
571 return -1;
572
573 if (!ctx) {
574 if (device == surface->display->argb_device)
575 ctx = surface->display->argb_ctx;
576 else
577 assert(0);
578 }
579
580 cairo_device_flush(device);
581 cairo_device_acquire(device);
582 if (!eglMakeCurrent(surface->display->dpy, surface->egl_surface,
583 surface->egl_surface, ctx))
584 fprintf(stderr, "failed to make surface current\n");
585
586 return 0;
587}
588
589static void
590egl_window_surface_release(struct toysurface *base)
591{
592 struct egl_window_surface *surface = to_egl_window_surface(base);
593 cairo_device_t *device;
594
595 device = cairo_surface_get_device(surface->cairo_surface);
596 if (!device)
597 return;
598
599 if (!eglMakeCurrent(surface->display->dpy, NULL, NULL,
600 surface->display->argb_ctx))
601 fprintf(stderr, "failed to make context current\n");
602
603 cairo_device_release(device);
604}
605
606static void
607egl_window_surface_destroy(struct toysurface *base)
608{
609 struct egl_window_surface *surface = to_egl_window_surface(base);
610 struct display *d = surface->display;
611
612 cairo_surface_destroy(surface->cairo_surface);
613 eglDestroySurface(d->dpy, surface->egl_surface);
614 wl_egl_window_destroy(surface->egl_window);
615 surface->surface = NULL;
616
617 free(surface);
618}
619
620static struct toysurface *
621egl_window_surface_create(struct display *display,
622 struct wl_surface *wl_surface,
623 uint32_t flags,
624 struct rectangle *rectangle)
625{
626 struct egl_window_surface *surface;
627
Pekka Paalanenb3627362012-11-19 17:16:00 +0200628 if (display->dpy == EGL_NO_DISPLAY)
629 return NULL;
630
Pekka Paalanen03fc3162012-11-19 17:15:58 +0200631 surface = calloc(1, sizeof *surface);
632 if (!surface)
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100633 return NULL;
634
Pekka Paalanen03fc3162012-11-19 17:15:58 +0200635 surface->base.prepare = egl_window_surface_prepare;
636 surface->base.swap = egl_window_surface_swap;
637 surface->base.acquire = egl_window_surface_acquire;
638 surface->base.release = egl_window_surface_release;
639 surface->base.destroy = egl_window_surface_destroy;
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100640
Pekka Paalanen03fc3162012-11-19 17:15:58 +0200641 surface->display = display;
642 surface->surface = wl_surface;
Kristian Høgsbergf389cac2011-08-31 16:21:38 -0400643
Pekka Paalanen03fc3162012-11-19 17:15:58 +0200644 surface->egl_window = wl_egl_window_create(surface->surface,
645 rectangle->width,
646 rectangle->height);
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100647
Pekka Paalanen03fc3162012-11-19 17:15:58 +0200648 surface->egl_surface = eglCreateWindowSurface(display->dpy,
649 display->argb_config,
650 surface->egl_window,
651 NULL);
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100652
Pekka Paalanen03fc3162012-11-19 17:15:58 +0200653 surface->cairo_surface =
654 cairo_gl_surface_create_for_egl(display->argb_device,
655 surface->egl_surface,
656 rectangle->width,
657 rectangle->height);
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100658
Pekka Paalanen03fc3162012-11-19 17:15:58 +0200659 return &surface->base;
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100660}
661
Pekka Paalanenb3627362012-11-19 17:16:00 +0200662#else
663
664static struct toysurface *
665egl_window_surface_create(struct display *display,
666 struct wl_surface *wl_surface,
667 uint32_t flags,
668 struct rectangle *rectangle)
669{
670 return NULL;
671}
672
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400673#endif
674
Pekka Paalanen0c6a3432012-11-19 15:32:50 +0200675struct shm_surface_data {
676 struct wl_buffer *buffer;
677 struct shm_pool *pool;
678};
679
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400680struct wl_buffer *
681display_get_buffer_for_surface(struct display *display,
682 cairo_surface_t *surface)
683{
Pekka Paalanen0c6a3432012-11-19 15:32:50 +0200684 struct shm_surface_data *data;
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400685
Pekka Paalanen32127ca2012-11-19 15:32:51 +0200686 data = cairo_surface_get_user_data(surface, &shm_surface_data_key);
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400687
688 return data->buffer;
689}
690
Kristian Høgsberg06bc2642010-12-01 09:50:16 -0500691static void
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700692shm_pool_destroy(struct shm_pool *pool);
693
694static void
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400695shm_surface_data_destroy(void *p)
696{
697 struct shm_surface_data *data = p;
698
Pekka Paalanen0c6a3432012-11-19 15:32:50 +0200699 wl_buffer_destroy(data->buffer);
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700700 if (data->pool)
701 shm_pool_destroy(data->pool);
Ander Conselvan de Oliveira2a3cd282012-06-19 13:45:55 +0300702
703 free(data);
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400704}
705
Kristian Høgsberg16626282012-04-03 11:21:27 -0400706static struct wl_shm_pool *
707make_shm_pool(struct display *display, int size, void **data)
708{
Kristian Høgsberg16626282012-04-03 11:21:27 -0400709 struct wl_shm_pool *pool;
710 int fd;
711
Pekka Paalanen1da1b8f2012-06-06 16:59:43 +0300712 fd = os_create_anonymous_file(size);
Kristian Høgsberg16626282012-04-03 11:21:27 -0400713 if (fd < 0) {
Pekka Paalanen1da1b8f2012-06-06 16:59:43 +0300714 fprintf(stderr, "creating a buffer file for %d B failed: %m\n",
715 size);
Kristian Høgsberg16626282012-04-03 11:21:27 -0400716 return NULL;
717 }
718
719 *data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
Kristian Høgsberg16626282012-04-03 11:21:27 -0400720 if (*data == MAP_FAILED) {
721 fprintf(stderr, "mmap failed: %m\n");
722 close(fd);
723 return NULL;
724 }
725
726 pool = wl_shm_create_pool(display->shm, fd, size);
727
728 close(fd);
729
730 return pool;
731}
732
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700733static struct shm_pool *
734shm_pool_create(struct display *display, size_t size)
735{
736 struct shm_pool *pool = malloc(sizeof *pool);
737
738 if (!pool)
739 return NULL;
740
741 pool->pool = make_shm_pool(display, size, &pool->data);
742 if (!pool->pool) {
743 free(pool);
744 return NULL;
745 }
746
747 pool->size = size;
748 pool->used = 0;
749
750 return pool;
751}
752
753static void *
754shm_pool_allocate(struct shm_pool *pool, size_t size, int *offset)
755{
756 if (pool->used + size > pool->size)
757 return NULL;
758
759 *offset = pool->used;
760 pool->used += size;
761
762 return (char *) pool->data + *offset;
763}
764
765/* destroy the pool. this does not unmap the memory though */
766static void
767shm_pool_destroy(struct shm_pool *pool)
768{
769 munmap(pool->data, pool->size);
770 wl_shm_pool_destroy(pool->pool);
771 free(pool);
772}
773
774/* Start allocating from the beginning of the pool again */
775static void
776shm_pool_reset(struct shm_pool *pool)
777{
778 pool->used = 0;
779}
780
781static int
782data_length_for_shm_surface(struct rectangle *rect)
783{
784 int stride;
785
786 stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32,
787 rect->width);
788 return stride * rect->height;
789}
790
Kristian Høgsberg06bc2642010-12-01 09:50:16 -0500791static cairo_surface_t *
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700792display_create_shm_surface_from_pool(struct display *display,
793 struct rectangle *rectangle,
794 uint32_t flags, struct shm_pool *pool)
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400795{
796 struct shm_surface_data *data;
Kristian Høgsbergf389cac2011-08-31 16:21:38 -0400797 uint32_t format;
Kristian Høgsberg3be87d12011-05-13 13:45:17 -0400798 cairo_surface_t *surface;
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700799 int stride, length, offset;
Kristian Høgsberg1103a1a2012-04-03 12:00:48 -0400800 void *map;
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400801
802 data = malloc(sizeof *data);
803 if (data == NULL)
804 return NULL;
805
806 stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32,
807 rectangle->width);
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700808 length = stride * rectangle->height;
809 data->pool = NULL;
810 map = shm_pool_allocate(pool, length, &offset);
811
812 if (!map) {
813 free(data);
814 return NULL;
Kristian Høgsberg1103a1a2012-04-03 12:00:48 -0400815 }
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400816
Kristian Høgsberg1103a1a2012-04-03 12:00:48 -0400817 surface = cairo_image_surface_create_for_data (map,
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400818 CAIRO_FORMAT_ARGB32,
819 rectangle->width,
820 rectangle->height,
821 stride);
822
Pekka Paalanen32127ca2012-11-19 15:32:51 +0200823 cairo_surface_set_user_data(surface, &shm_surface_data_key,
824 data, shm_surface_data_destroy);
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400825
Kristian Høgsberg3be87d12011-05-13 13:45:17 -0400826 if (flags & SURFACE_OPAQUE)
Kristian Høgsberg8e81df42012-01-11 14:24:46 -0500827 format = WL_SHM_FORMAT_XRGB8888;
Kristian Høgsberg3be87d12011-05-13 13:45:17 -0400828 else
Kristian Høgsberg8e81df42012-01-11 14:24:46 -0500829 format = WL_SHM_FORMAT_ARGB8888;
Kristian Høgsberg3be87d12011-05-13 13:45:17 -0400830
Pekka Paalanen0c6a3432012-11-19 15:32:50 +0200831 data->buffer = wl_shm_pool_create_buffer(pool->pool, offset,
832 rectangle->width,
833 rectangle->height,
834 stride, format);
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400835
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700836 return surface;
837}
838
839static cairo_surface_t *
840display_create_shm_surface(struct display *display,
841 struct rectangle *rectangle, uint32_t flags,
Pekka Paalanen99436862012-11-19 17:15:59 +0200842 struct shm_pool *alternate_pool,
843 struct shm_surface_data **data_ret)
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700844{
845 struct shm_surface_data *data;
846 struct shm_pool *pool;
847 cairo_surface_t *surface;
848
Pekka Paalanen99436862012-11-19 17:15:59 +0200849 if (alternate_pool) {
850 shm_pool_reset(alternate_pool);
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700851 surface = display_create_shm_surface_from_pool(display,
852 rectangle,
853 flags,
Pekka Paalanen99436862012-11-19 17:15:59 +0200854 alternate_pool);
855 if (surface) {
856 data = cairo_surface_get_user_data(surface,
857 &shm_surface_data_key);
858 goto out;
859 }
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700860 }
861
862 pool = shm_pool_create(display,
863 data_length_for_shm_surface(rectangle));
864 if (!pool)
865 return NULL;
866
867 surface =
868 display_create_shm_surface_from_pool(display, rectangle,
869 flags, pool);
870
871 if (!surface) {
872 shm_pool_destroy(pool);
873 return NULL;
874 }
875
876 /* make sure we destroy the pool when the surface is destroyed */
Pekka Paalanen32127ca2012-11-19 15:32:51 +0200877 data = cairo_surface_get_user_data(surface, &shm_surface_data_key);
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700878 data->pool = pool;
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400879
Pekka Paalanen99436862012-11-19 17:15:59 +0200880out:
881 if (data_ret)
882 *data_ret = data;
883
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400884 return surface;
885}
886
nobled7b87cb02011-02-01 18:51:47 +0000887static int
888check_size(struct rectangle *rect)
889{
890 if (rect->width && rect->height)
891 return 0;
892
893 fprintf(stderr, "tried to create surface of "
894 "width: %d, height: %d\n", rect->width, rect->height);
895 return -1;
896}
897
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400898cairo_surface_t *
899display_create_surface(struct display *display,
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100900 struct wl_surface *surface,
Kristian Høgsberg3be87d12011-05-13 13:45:17 -0400901 struct rectangle *rectangle,
902 uint32_t flags)
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400903{
nobled7b87cb02011-02-01 18:51:47 +0000904 if (check_size(rectangle) < 0)
905 return NULL;
Pekka Paalanen768117f2012-11-19 17:15:57 +0200906
907 assert(flags & SURFACE_SHM);
Pekka Paalanen99436862012-11-19 17:15:59 +0200908 return display_create_shm_surface(display, rectangle, flags,
909 NULL, NULL);
910}
911
Pekka Paalanena4eda732012-11-19 17:16:02 +0200912struct shm_surface_leaf {
913 cairo_surface_t *cairo_surface;
914 /* 'data' is automatically destroyed, when 'cairo_surface' is */
915 struct shm_surface_data *data;
916
917 struct shm_pool *resize_pool;
918 int busy;
919};
920
921static void
922shm_surface_leaf_release(struct shm_surface_leaf *leaf)
923{
924 if (leaf->cairo_surface)
925 cairo_surface_destroy(leaf->cairo_surface);
926 /* leaf->data already destroyed via cairo private */
927
928 if (leaf->resize_pool)
929 shm_pool_destroy(leaf->resize_pool);
Pekka Paalanen550d66b2013-02-13 16:17:12 +0200930
931 memset(leaf, 0, sizeof *leaf);
Pekka Paalanena4eda732012-11-19 17:16:02 +0200932}
933
Pekka Paalanenaef02542013-04-25 13:57:47 +0300934#define MAX_LEAVES 3
935
Pekka Paalanen99436862012-11-19 17:15:59 +0200936struct shm_surface {
937 struct toysurface base;
938 struct display *display;
939 struct wl_surface *surface;
940 uint32_t flags;
941 int dx, dy;
942
Pekka Paalanenaef02542013-04-25 13:57:47 +0300943 struct shm_surface_leaf leaf[MAX_LEAVES];
Pekka Paalanena4eda732012-11-19 17:16:02 +0200944 struct shm_surface_leaf *current;
Pekka Paalanen99436862012-11-19 17:15:59 +0200945};
946
947static struct shm_surface *
948to_shm_surface(struct toysurface *base)
949{
950 return container_of(base, struct shm_surface, base);
951}
952
Pekka Paalanena4eda732012-11-19 17:16:02 +0200953static void
Pekka Paalanen97777442013-05-22 10:20:05 +0300954shm_surface_buffer_state_debug(struct shm_surface *surface, const char *msg)
955{
956#ifdef DEBUG
957 struct shm_surface_leaf *leaf;
958 char bufs[MAX_LEAVES + 1];
959 int i;
960
961 for (i = 0; i < MAX_LEAVES; i++) {
962 leaf = &surface->leaf[i];
963
964 if (leaf->busy)
965 bufs[i] = 'b';
966 else if (leaf->cairo_surface)
967 bufs[i] = 'a';
968 else
969 bufs[i] = ' ';
970 }
971
972 bufs[MAX_LEAVES] = '\0';
973 DBG_OBJ(surface->surface, "%s, leaves [%s]\n", msg, bufs);
974#endif
975}
976
977static void
Pekka Paalanena4eda732012-11-19 17:16:02 +0200978shm_surface_buffer_release(void *data, struct wl_buffer *buffer)
979{
Pekka Paalanen550d66b2013-02-13 16:17:12 +0200980 struct shm_surface *surface = data;
Pekka Paalanenaef02542013-04-25 13:57:47 +0300981 struct shm_surface_leaf *leaf;
982 int i;
983 int free_found;
Pekka Paalanen97777442013-05-22 10:20:05 +0300984
985 shm_surface_buffer_state_debug(surface, "buffer_release before");
Pekka Paalanena4eda732012-11-19 17:16:02 +0200986
Pekka Paalanenaef02542013-04-25 13:57:47 +0300987 for (i = 0; i < MAX_LEAVES; i++) {
988 leaf = &surface->leaf[i];
989 if (leaf->data && leaf->data->buffer == buffer) {
990 leaf->busy = 0;
991 break;
992 }
993 }
994 assert(i < MAX_LEAVES && "unknown buffer released");
Pekka Paalanen4dd0c412012-12-04 16:01:16 +0200995
Pekka Paalanenaef02542013-04-25 13:57:47 +0300996 /* Leave one free leaf with storage, release others */
997 free_found = 0;
998 for (i = 0; i < MAX_LEAVES; i++) {
999 leaf = &surface->leaf[i];
1000
1001 if (!leaf->cairo_surface || leaf->busy)
1002 continue;
1003
1004 if (!free_found)
1005 free_found = 1;
Pekka Paalanen97777442013-05-22 10:20:05 +03001006 else
Pekka Paalanenaef02542013-04-25 13:57:47 +03001007 shm_surface_leaf_release(leaf);
1008 }
Pekka Paalanen71233882013-04-25 13:57:53 +03001009
Pekka Paalanen97777442013-05-22 10:20:05 +03001010 shm_surface_buffer_state_debug(surface, "buffer_release after");
Pekka Paalanena4eda732012-11-19 17:16:02 +02001011}
1012
1013static const struct wl_buffer_listener shm_surface_buffer_listener = {
1014 shm_surface_buffer_release
1015};
1016
Pekka Paalanen99436862012-11-19 17:15:59 +02001017static cairo_surface_t *
1018shm_surface_prepare(struct toysurface *base, int dx, int dy,
Alexander Larsson1818e312013-05-22 14:41:31 +02001019 int32_t width, int32_t height, uint32_t flags,
Alexander Larssonedddbd12013-05-24 13:09:43 +02001020 enum wl_output_transform buffer_transform, int32_t buffer_scale)
Pekka Paalanen99436862012-11-19 17:15:59 +02001021{
Pekka Paalanenec076692012-11-30 13:37:27 +02001022 int resize_hint = !!(flags & SURFACE_HINT_RESIZE);
Pekka Paalanen99436862012-11-19 17:15:59 +02001023 struct shm_surface *surface = to_shm_surface(base);
Alexander Larsson1818e312013-05-22 14:41:31 +02001024 struct rectangle rect = { 0};
Pekka Paalanenaef02542013-04-25 13:57:47 +03001025 struct shm_surface_leaf *leaf = NULL;
1026 int i;
Pekka Paalanen99436862012-11-19 17:15:59 +02001027
1028 surface->dx = dx;
1029 surface->dy = dy;
1030
Pekka Paalanenaef02542013-04-25 13:57:47 +03001031 /* pick a free buffer, preferrably one that already has storage */
1032 for (i = 0; i < MAX_LEAVES; i++) {
1033 if (surface->leaf[i].busy)
1034 continue;
Pekka Paalanen4dd0c412012-12-04 16:01:16 +02001035
Pekka Paalanenaef02542013-04-25 13:57:47 +03001036 if (!leaf || surface->leaf[i].cairo_surface)
1037 leaf = &surface->leaf[i];
1038 }
Pekka Paalanen71233882013-04-25 13:57:53 +03001039 DBG_OBJ(surface->surface, "pick leaf %d\n",
1040 (int)(leaf - &surface->leaf[0]));
1041
Pekka Paalanenaef02542013-04-25 13:57:47 +03001042 if (!leaf) {
1043 fprintf(stderr, "%s: all buffers are held by the server.\n",
Pekka Paalanena4eda732012-11-19 17:16:02 +02001044 __func__);
Pekka Paalanen71233882013-04-25 13:57:53 +03001045 exit(1);
Pekka Paalanena4eda732012-11-19 17:16:02 +02001046 return NULL;
Pekka Paalanen99436862012-11-19 17:15:59 +02001047 }
1048
Pekka Paalanena4eda732012-11-19 17:16:02 +02001049 if (!resize_hint && leaf->resize_pool) {
1050 cairo_surface_destroy(leaf->cairo_surface);
1051 leaf->cairo_surface = NULL;
1052 shm_pool_destroy(leaf->resize_pool);
1053 leaf->resize_pool = NULL;
1054 }
1055
Alexander Larsson1818e312013-05-22 14:41:31 +02001056 surface_to_buffer_size (buffer_transform, buffer_scale, &width, &height);
1057
Pekka Paalanena4eda732012-11-19 17:16:02 +02001058 if (leaf->cairo_surface &&
1059 cairo_image_surface_get_width(leaf->cairo_surface) == width &&
1060 cairo_image_surface_get_height(leaf->cairo_surface) == height)
Pekka Paalanen99436862012-11-19 17:15:59 +02001061 goto out;
1062
Pekka Paalanena4eda732012-11-19 17:16:02 +02001063 if (leaf->cairo_surface)
1064 cairo_surface_destroy(leaf->cairo_surface);
Pekka Paalanen99436862012-11-19 17:15:59 +02001065
Louis-Francis Ratté-Boulianne6cd1de32013-05-22 18:03:11 +03001066#ifdef USE_RESIZE_POOL
Pekka Paalanena4eda732012-11-19 17:16:02 +02001067 if (resize_hint && !leaf->resize_pool) {
Pekka Paalanen99436862012-11-19 17:15:59 +02001068 /* Create a big pool to allocate from, while continuously
1069 * resizing. Mmapping a new pool in the server
1070 * is relatively expensive, so reusing a pool performs
1071 * better, but may temporarily reserve unneeded memory.
1072 */
1073 /* We should probably base this number on the output size. */
Pekka Paalanena4eda732012-11-19 17:16:02 +02001074 leaf->resize_pool = shm_pool_create(surface->display,
1075 6 * 1024 * 1024);
Pekka Paalanen99436862012-11-19 17:15:59 +02001076 }
Louis-Francis Ratté-Boulianne6cd1de32013-05-22 18:03:11 +03001077#endif
Pekka Paalanen99436862012-11-19 17:15:59 +02001078
Alexander Larsson1818e312013-05-22 14:41:31 +02001079 rect.width = width;
1080 rect.height = height;
1081
Pekka Paalanena4eda732012-11-19 17:16:02 +02001082 leaf->cairo_surface =
Pekka Paalanen99436862012-11-19 17:15:59 +02001083 display_create_shm_surface(surface->display, &rect,
1084 surface->flags,
Pekka Paalanena4eda732012-11-19 17:16:02 +02001085 leaf->resize_pool,
1086 &leaf->data);
1087 wl_buffer_add_listener(leaf->data->buffer,
Pekka Paalanen550d66b2013-02-13 16:17:12 +02001088 &shm_surface_buffer_listener, surface);
Pekka Paalanen99436862012-11-19 17:15:59 +02001089
1090out:
Pekka Paalanena4eda732012-11-19 17:16:02 +02001091 surface->current = leaf;
1092
1093 return cairo_surface_reference(leaf->cairo_surface);
Pekka Paalanen99436862012-11-19 17:15:59 +02001094}
1095
1096static void
1097shm_surface_swap(struct toysurface *base,
Alexander Larssonedddbd12013-05-24 13:09:43 +02001098 enum wl_output_transform buffer_transform, int32_t buffer_scale,
Pekka Paalanen99436862012-11-19 17:15:59 +02001099 struct rectangle *server_allocation)
1100{
1101 struct shm_surface *surface = to_shm_surface(base);
Pekka Paalanena4eda732012-11-19 17:16:02 +02001102 struct shm_surface_leaf *leaf = surface->current;
Pekka Paalanen99436862012-11-19 17:15:59 +02001103
1104 server_allocation->width =
Pekka Paalanena4eda732012-11-19 17:16:02 +02001105 cairo_image_surface_get_width(leaf->cairo_surface);
Pekka Paalanen99436862012-11-19 17:15:59 +02001106 server_allocation->height =
Pekka Paalanena4eda732012-11-19 17:16:02 +02001107 cairo_image_surface_get_height(leaf->cairo_surface);
Pekka Paalanen99436862012-11-19 17:15:59 +02001108
Alexander Larsson1818e312013-05-22 14:41:31 +02001109 buffer_to_surface_size (buffer_transform, buffer_scale,
1110 &server_allocation->width,
1111 &server_allocation->height);
1112
Pekka Paalanena4eda732012-11-19 17:16:02 +02001113 wl_surface_attach(surface->surface, leaf->data->buffer,
Pekka Paalanen99436862012-11-19 17:15:59 +02001114 surface->dx, surface->dy);
1115 wl_surface_damage(surface->surface, 0, 0,
1116 server_allocation->width, server_allocation->height);
1117 wl_surface_commit(surface->surface);
Pekka Paalanena4eda732012-11-19 17:16:02 +02001118
Pekka Paalanen71233882013-04-25 13:57:53 +03001119 DBG_OBJ(surface->surface, "leaf %d busy\n",
1120 (int)(leaf - &surface->leaf[0]));
1121
Pekka Paalanena4eda732012-11-19 17:16:02 +02001122 leaf->busy = 1;
1123 surface->current = NULL;
Pekka Paalanen99436862012-11-19 17:15:59 +02001124}
1125
1126static int
1127shm_surface_acquire(struct toysurface *base, EGLContext ctx)
1128{
1129 return -1;
1130}
1131
1132static void
1133shm_surface_release(struct toysurface *base)
1134{
1135}
1136
1137static void
1138shm_surface_destroy(struct toysurface *base)
1139{
1140 struct shm_surface *surface = to_shm_surface(base);
Pekka Paalanenaef02542013-04-25 13:57:47 +03001141 int i;
Pekka Paalanen99436862012-11-19 17:15:59 +02001142
Pekka Paalanenaef02542013-04-25 13:57:47 +03001143 for (i = 0; i < MAX_LEAVES; i++)
1144 shm_surface_leaf_release(&surface->leaf[i]);
Pekka Paalanen99436862012-11-19 17:15:59 +02001145
1146 free(surface);
1147}
1148
1149static struct toysurface *
1150shm_surface_create(struct display *display, struct wl_surface *wl_surface,
1151 uint32_t flags, struct rectangle *rectangle)
1152{
1153 struct shm_surface *surface;
Pekka Paalanen71233882013-04-25 13:57:53 +03001154 DBG_OBJ(wl_surface, "\n");
Pekka Paalanen99436862012-11-19 17:15:59 +02001155
1156 surface = calloc(1, sizeof *surface);
1157 if (!surface)
1158 return NULL;
1159
1160 surface->base.prepare = shm_surface_prepare;
1161 surface->base.swap = shm_surface_swap;
1162 surface->base.acquire = shm_surface_acquire;
1163 surface->base.release = shm_surface_release;
1164 surface->base.destroy = shm_surface_destroy;
1165
1166 surface->display = display;
1167 surface->surface = wl_surface;
1168 surface->flags = flags;
Pekka Paalanen99436862012-11-19 17:15:59 +02001169
1170 return &surface->base;
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -04001171}
1172
Philipp Brüschweilerbd3f2192012-08-21 20:36:16 +02001173/*
1174 * The following correspondences between file names and cursors was copied
1175 * from: https://bugs.kde.org/attachment.cgi?id=67313
1176 */
1177
1178static const char *bottom_left_corners[] = {
Ander Conselvan de Oliveirad8f527c2012-05-25 09:30:02 +03001179 "bottom_left_corner",
Dima Ryazanovf6128fc2013-05-13 23:51:11 -07001180 "sw-resize",
1181 "size_bdiag"
Philipp Brüschweilerbd3f2192012-08-21 20:36:16 +02001182};
1183
1184static const char *bottom_right_corners[] = {
Ander Conselvan de Oliveirad8f527c2012-05-25 09:30:02 +03001185 "bottom_right_corner",
Dima Ryazanovf6128fc2013-05-13 23:51:11 -07001186 "se-resize",
1187 "size_fdiag"
Philipp Brüschweilerbd3f2192012-08-21 20:36:16 +02001188};
1189
1190static const char *bottom_sides[] = {
Ander Conselvan de Oliveirad8f527c2012-05-25 09:30:02 +03001191 "bottom_side",
Dima Ryazanovf6128fc2013-05-13 23:51:11 -07001192 "s-resize",
1193 "size_ver"
Philipp Brüschweilerbd3f2192012-08-21 20:36:16 +02001194};
1195
1196static const char *grabbings[] = {
Ander Conselvan de Oliveirad8f527c2012-05-25 09:30:02 +03001197 "grabbing",
Philipp Brüschweilerbd3f2192012-08-21 20:36:16 +02001198 "closedhand",
1199 "208530c400c041818281048008011002"
1200};
1201
1202static const char *left_ptrs[] = {
Ander Conselvan de Oliveirad8f527c2012-05-25 09:30:02 +03001203 "left_ptr",
Philipp Brüschweilerbd3f2192012-08-21 20:36:16 +02001204 "default",
1205 "top_left_arrow",
1206 "left-arrow"
1207};
1208
1209static const char *left_sides[] = {
Ander Conselvan de Oliveirad8f527c2012-05-25 09:30:02 +03001210 "left_side",
Dima Ryazanovf6128fc2013-05-13 23:51:11 -07001211 "w-resize",
1212 "size_hor"
Philipp Brüschweilerbd3f2192012-08-21 20:36:16 +02001213};
1214
1215static const char *right_sides[] = {
Ander Conselvan de Oliveirad8f527c2012-05-25 09:30:02 +03001216 "right_side",
Dima Ryazanovf6128fc2013-05-13 23:51:11 -07001217 "e-resize",
1218 "size_hor"
Philipp Brüschweilerbd3f2192012-08-21 20:36:16 +02001219};
1220
1221static const char *top_left_corners[] = {
Ander Conselvan de Oliveirad8f527c2012-05-25 09:30:02 +03001222 "top_left_corner",
Dima Ryazanovf6128fc2013-05-13 23:51:11 -07001223 "nw-resize",
1224 "size_fdiag"
Philipp Brüschweilerbd3f2192012-08-21 20:36:16 +02001225};
1226
1227static const char *top_right_corners[] = {
Ander Conselvan de Oliveirad8f527c2012-05-25 09:30:02 +03001228 "top_right_corner",
Dima Ryazanovf6128fc2013-05-13 23:51:11 -07001229 "ne-resize",
1230 "size_bdiag"
Philipp Brüschweilerbd3f2192012-08-21 20:36:16 +02001231};
1232
1233static const char *top_sides[] = {
Ander Conselvan de Oliveirad8f527c2012-05-25 09:30:02 +03001234 "top_side",
Dima Ryazanovf6128fc2013-05-13 23:51:11 -07001235 "n-resize",
1236 "size_ver"
Philipp Brüschweilerbd3f2192012-08-21 20:36:16 +02001237};
1238
1239static const char *xterms[] = {
Ander Conselvan de Oliveirad8f527c2012-05-25 09:30:02 +03001240 "xterm",
Philipp Brüschweilerbd3f2192012-08-21 20:36:16 +02001241 "ibeam",
1242 "text"
1243};
1244
1245static const char *hand1s[] = {
Ander Conselvan de Oliveirad8f527c2012-05-25 09:30:02 +03001246 "hand1",
Philipp Brüschweilerbd3f2192012-08-21 20:36:16 +02001247 "pointer",
1248 "pointing_hand",
1249 "e29285e634086352946a0e7090d73106"
1250};
1251
1252static const char *watches[] = {
Kristian Høgsberg8591dbf2012-06-04 16:10:40 -04001253 "watch",
Philipp Brüschweilerbd3f2192012-08-21 20:36:16 +02001254 "wait",
1255 "0426c94ea35c87780ff01dc239897213"
1256};
1257
1258struct cursor_alternatives {
1259 const char **names;
1260 size_t count;
1261};
1262
1263static const struct cursor_alternatives cursors[] = {
1264 {bottom_left_corners, ARRAY_LENGTH(bottom_left_corners)},
1265 {bottom_right_corners, ARRAY_LENGTH(bottom_right_corners)},
1266 {bottom_sides, ARRAY_LENGTH(bottom_sides)},
1267 {grabbings, ARRAY_LENGTH(grabbings)},
1268 {left_ptrs, ARRAY_LENGTH(left_ptrs)},
1269 {left_sides, ARRAY_LENGTH(left_sides)},
1270 {right_sides, ARRAY_LENGTH(right_sides)},
1271 {top_left_corners, ARRAY_LENGTH(top_left_corners)},
1272 {top_right_corners, ARRAY_LENGTH(top_right_corners)},
1273 {top_sides, ARRAY_LENGTH(top_sides)},
1274 {xterms, ARRAY_LENGTH(xterms)},
1275 {hand1s, ARRAY_LENGTH(hand1s)},
1276 {watches, ARRAY_LENGTH(watches)},
Ander Conselvan de Oliveirad8f527c2012-05-25 09:30:02 +03001277};
1278
1279static void
1280create_cursors(struct display *display)
1281{
Ossama Othmana50e6e42013-05-14 09:48:26 -07001282 int config_fd;
Christopher Michaelac3e5f22012-08-11 15:12:09 +01001283 char *theme = NULL;
Emilio Pozuelo Monfortab44b0c2013-03-14 17:23:37 +01001284 unsigned int size = 32;
Philipp Brüschweilerbd3f2192012-08-21 20:36:16 +02001285 unsigned int i, j;
1286 struct wl_cursor *cursor;
Christopher Michaelac3e5f22012-08-11 15:12:09 +01001287 struct config_key shell_keys[] = {
1288 { "cursor-theme", CONFIG_KEY_STRING, &theme },
Emilio Pozuelo Monfortab44b0c2013-03-14 17:23:37 +01001289 { "cursor-size", CONFIG_KEY_UNSIGNED_INTEGER, &size },
Christopher Michaelac3e5f22012-08-11 15:12:09 +01001290 };
1291 struct config_section cs[] = {
1292 { "shell", shell_keys, ARRAY_LENGTH(shell_keys), NULL },
1293 };
Ander Conselvan de Oliveirad8f527c2012-05-25 09:30:02 +03001294
Ossama Othmana50e6e42013-05-14 09:48:26 -07001295 config_fd = open_config_file("weston.ini");
1296 parse_config_file(config_fd, cs, ARRAY_LENGTH(cs), NULL);
1297 close(config_fd);
Christopher Michaelac3e5f22012-08-11 15:12:09 +01001298
Emilio Pozuelo Monfortab44b0c2013-03-14 17:23:37 +01001299 display->cursor_theme = wl_cursor_theme_load(theme, size, display->shm);
Ander Conselvan de Oliveirad8f527c2012-05-25 09:30:02 +03001300 display->cursors =
1301 malloc(ARRAY_LENGTH(cursors) * sizeof display->cursors[0]);
1302
Pekka Paalanene288a0f2012-07-31 13:21:09 +03001303 for (i = 0; i < ARRAY_LENGTH(cursors); i++) {
Philipp Brüschweilerbd3f2192012-08-21 20:36:16 +02001304 cursor = NULL;
1305 for (j = 0; !cursor && j < cursors[i].count; ++j)
1306 cursor = wl_cursor_theme_get_cursor(
1307 display->cursor_theme, cursors[i].names[j]);
1308
1309 if (!cursor)
Pekka Paalanene288a0f2012-07-31 13:21:09 +03001310 fprintf(stderr, "could not load cursor '%s'\n",
Philipp Brüschweilerbd3f2192012-08-21 20:36:16 +02001311 cursors[i].names[0]);
1312
1313 display->cursors[i] = cursor;
Pekka Paalanene288a0f2012-07-31 13:21:09 +03001314 }
Ander Conselvan de Oliveirad8f527c2012-05-25 09:30:02 +03001315}
1316
1317static void
1318destroy_cursors(struct display *display)
1319{
1320 wl_cursor_theme_destroy(display->cursor_theme);
Yan Wanga261f7e2012-05-28 14:07:25 +08001321 free(display->cursors);
Ander Conselvan de Oliveirad8f527c2012-05-25 09:30:02 +03001322}
1323
Ander Conselvan de Oliveira1042dc12012-05-22 15:39:42 +03001324struct wl_cursor_image *
1325display_get_pointer_image(struct display *display, int pointer)
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04001326{
Philipp Brüschweilerbd3f2192012-08-21 20:36:16 +02001327 struct wl_cursor *cursor = display->cursors[pointer];
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04001328
Ander Conselvan de Oliveira1042dc12012-05-22 15:39:42 +03001329 return cursor ? cursor->images[0] : NULL;
Kristian Høgsberg9a686242010-08-18 15:28:04 -04001330}
1331
Kristian Høgsberg9d69f8e2010-09-03 14:46:38 -04001332static void
Pekka Paalanen89dee002013-02-13 16:17:20 +02001333surface_flush(struct surface *surface)
Pekka Paalanen811ec4f2013-02-13 16:17:14 +02001334{
Pekka Paalanen89dee002013-02-13 16:17:20 +02001335 if (!surface->cairo_surface)
1336 return;
1337
Pekka Paalanenb1cd9b12013-02-13 16:17:18 +02001338 if (surface->opaque_region) {
1339 wl_surface_set_opaque_region(surface->surface,
1340 surface->opaque_region);
1341 wl_region_destroy(surface->opaque_region);
1342 surface->opaque_region = NULL;
1343 }
1344
1345 if (surface->input_region) {
1346 wl_surface_set_input_region(surface->surface,
1347 surface->input_region);
1348 wl_region_destroy(surface->input_region);
1349 surface->input_region = NULL;
1350 }
1351
Pekka Paalanen811ec4f2013-02-13 16:17:14 +02001352 surface->toysurface->swap(surface->toysurface,
Alexander Larsson1818e312013-05-22 14:41:31 +02001353 surface->buffer_transform, surface->buffer_scale,
Pekka Paalanen811ec4f2013-02-13 16:17:14 +02001354 &surface->server_allocation);
Pekka Paalanen811ec4f2013-02-13 16:17:14 +02001355
Pekka Paalanen89dee002013-02-13 16:17:20 +02001356 cairo_surface_destroy(surface->cairo_surface);
1357 surface->cairo_surface = NULL;
Kristian Høgsberg6a1b2012009-12-16 14:43:37 -05001358}
1359
Kristian Høgsberg86adef92012-08-13 22:25:53 -04001360int
1361window_has_focus(struct window *window)
1362{
1363 return window->focus_count > 0;
1364}
1365
Pekka Paalanena8d4c842012-11-19 15:32:48 +02001366static void
Kristian Høgsberg9d69f8e2010-09-03 14:46:38 -04001367window_flush(struct window *window)
Kristian Høgsberga341fa02010-01-24 18:10:15 -05001368{
Pekka Paalanen35e82632013-04-25 13:57:48 +03001369 struct surface *surface;
1370
Pekka Paalanen89dee002013-02-13 16:17:20 +02001371 if (window->type == TYPE_NONE) {
1372 window->type = TYPE_TOPLEVEL;
1373 if (window->shell_surface)
1374 wl_shell_surface_set_toplevel(window->shell_surface);
1375 }
Pekka Paalanen03fc3162012-11-19 17:15:58 +02001376
Pekka Paalanen35e82632013-04-25 13:57:48 +03001377 wl_list_for_each(surface, &window->subsurface_list, link) {
1378 if (surface == window->main_surface)
1379 continue;
1380
1381 surface_flush(surface);
1382 }
1383
Pekka Paalanen89dee002013-02-13 16:17:20 +02001384 surface_flush(window->main_surface);
Kristian Høgsberga341fa02010-01-24 18:10:15 -05001385}
1386
Kristian Høgsbergbcee9a42011-10-12 00:36:16 -04001387struct display *
1388window_get_display(struct window *window)
1389{
1390 return window->display;
1391}
1392
Pekka Paalanen89dee002013-02-13 16:17:20 +02001393static void
Pekka Paalanen02bba7c2013-02-13 16:17:15 +02001394surface_create_surface(struct surface *surface, int dx, int dy, uint32_t flags)
Kristian Høgsberg012a0072010-10-26 00:02:20 -04001395{
Pekka Paalanen02bba7c2013-02-13 16:17:15 +02001396 struct display *display = surface->window->display;
Pekka Paalanen811ec4f2013-02-13 16:17:14 +02001397 struct rectangle allocation = surface->allocation;
Pekka Paalanen03fc3162012-11-19 17:15:58 +02001398
Pekka Paalanen02bba7c2013-02-13 16:17:15 +02001399 if (!surface->toysurface && display->dpy &&
1400 surface->buffer_type == WINDOW_BUFFER_TYPE_EGL_WINDOW) {
Pekka Paalanen811ec4f2013-02-13 16:17:14 +02001401 surface->toysurface =
Pekka Paalanen02bba7c2013-02-13 16:17:15 +02001402 egl_window_surface_create(display,
Pekka Paalanen811ec4f2013-02-13 16:17:14 +02001403 surface->surface,
Pekka Paalanen4e373742013-02-13 16:17:13 +02001404 flags,
Ander Conselvan de Oliveira6d4cb4e2012-11-30 17:34:24 +02001405 &allocation);
Pekka Paalanenb3627362012-11-19 17:16:00 +02001406 }
Pekka Paalanen03fc3162012-11-19 17:15:58 +02001407
Pekka Paalanen811ec4f2013-02-13 16:17:14 +02001408 if (!surface->toysurface)
Pekka Paalanen02bba7c2013-02-13 16:17:15 +02001409 surface->toysurface = shm_surface_create(display,
Pekka Paalanen811ec4f2013-02-13 16:17:14 +02001410 surface->surface,
1411 flags, &allocation);
Kristian Høgsberg012a0072010-10-26 00:02:20 -04001412
Pekka Paalanen89dee002013-02-13 16:17:20 +02001413 surface->cairo_surface = surface->toysurface->prepare(
1414 surface->toysurface, dx, dy,
Alexander Larsson1818e312013-05-22 14:41:31 +02001415 allocation.width, allocation.height, flags,
1416 surface->buffer_transform, surface->buffer_scale);
Pekka Paalanen02bba7c2013-02-13 16:17:15 +02001417}
1418
1419static void
Pekka Paalanen0c4445b2013-02-13 16:17:23 +02001420window_create_main_surface(struct window *window)
Pekka Paalanen02bba7c2013-02-13 16:17:15 +02001421{
Pekka Paalanen7bcfead2013-02-13 16:17:16 +02001422 struct surface *surface = window->main_surface;
Pekka Paalanen02bba7c2013-02-13 16:17:15 +02001423 uint32_t flags = 0;
Pekka Paalanen7bcfead2013-02-13 16:17:16 +02001424 int dx = 0;
1425 int dy = 0;
Pekka Paalanen02bba7c2013-02-13 16:17:15 +02001426
Pekka Paalanenec076692012-11-30 13:37:27 +02001427 if (window->resizing)
Pekka Paalanen02bba7c2013-02-13 16:17:15 +02001428 flags |= SURFACE_HINT_RESIZE;
Pekka Paalanenec076692012-11-30 13:37:27 +02001429
Pekka Paalanen7bcfead2013-02-13 16:17:16 +02001430 if (window->resize_edges & WINDOW_RESIZING_LEFT)
1431 dx = surface->server_allocation.width -
1432 surface->allocation.width;
1433
1434 if (window->resize_edges & WINDOW_RESIZING_TOP)
1435 dy = surface->server_allocation.height -
1436 surface->allocation.height;
1437
1438 window->resize_edges = 0;
1439
Pekka Paalanen89dee002013-02-13 16:17:20 +02001440 surface_create_surface(surface, dx, dy, flags);
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -04001441}
1442
Ander Conselvan de Oliveira6d4cb4e2012-11-30 17:34:24 +02001443int
1444window_get_buffer_transform(struct window *window)
1445{
Pekka Paalanen02bba7c2013-02-13 16:17:15 +02001446 return window->main_surface->buffer_transform;
Ander Conselvan de Oliveira6d4cb4e2012-11-30 17:34:24 +02001447}
1448
1449void
1450window_set_buffer_transform(struct window *window,
1451 enum wl_output_transform transform)
1452{
Pekka Paalanen02bba7c2013-02-13 16:17:15 +02001453 window->main_surface->buffer_transform = transform;
Pekka Paalanen4e373742013-02-13 16:17:13 +02001454 wl_surface_set_buffer_transform(window->main_surface->surface,
1455 transform);
Ander Conselvan de Oliveira6d4cb4e2012-11-30 17:34:24 +02001456}
1457
Alexander Larsson5e9b6522013-05-22 14:41:28 +02001458void
1459window_set_buffer_scale(struct window *window,
Alexander Larssonedddbd12013-05-24 13:09:43 +02001460 int32_t scale)
Alexander Larsson5e9b6522013-05-22 14:41:28 +02001461{
1462 window->main_surface->buffer_scale = scale;
1463 wl_surface_set_buffer_scale(window->main_surface->surface,
1464 scale);
1465}
1466
1467uint32_t
1468window_get_buffer_scale(struct window *window)
1469{
1470 return window->main_surface->buffer_scale;
1471}
1472
Alexander Larssond68f5232013-05-22 14:41:33 +02001473uint32_t
1474window_get_output_scale(struct window *window)
1475{
1476 struct window_output *window_output;
1477 struct window_output *window_output_tmp;
1478 int scale = 1;
1479
1480 wl_list_for_each_safe(window_output, window_output_tmp,
1481 &window->window_output_list, link) {
1482 if (window_output->output->scale > scale)
1483 scale = window_output->output->scale;
1484 }
1485
1486 return scale;
1487}
1488
Pekka Paalanen4dde2fc2012-01-19 13:33:50 +02001489static void frame_destroy(struct frame *frame);
1490
Pekka Paalanen4e373742013-02-13 16:17:13 +02001491static void
1492surface_destroy(struct surface *surface)
1493{
Pekka Paalanen40cb67b2013-04-25 13:57:49 +03001494 if (surface->frame_cb)
1495 wl_callback_destroy(surface->frame_cb);
1496
Pekka Paalanenb1cd9b12013-02-13 16:17:18 +02001497 if (surface->input_region)
1498 wl_region_destroy(surface->input_region);
1499
1500 if (surface->opaque_region)
1501 wl_region_destroy(surface->opaque_region);
1502
Pekka Paalanen35e82632013-04-25 13:57:48 +03001503 if (surface->subsurface)
1504 wl_subsurface_destroy(surface->subsurface);
1505
Pekka Paalanen4e373742013-02-13 16:17:13 +02001506 wl_surface_destroy(surface->surface);
Pekka Paalanen811ec4f2013-02-13 16:17:14 +02001507
1508 if (surface->toysurface)
1509 surface->toysurface->destroy(surface->toysurface);
1510
Pekka Paalanen35e82632013-04-25 13:57:48 +03001511 wl_list_remove(&surface->link);
Pekka Paalanen4e373742013-02-13 16:17:13 +02001512 free(surface);
1513}
1514
Kristian Høgsberge968f9c2010-08-27 22:18:00 -04001515void
Kristian Høgsberg248c1b62011-01-21 18:03:15 -05001516window_destroy(struct window *window)
1517{
Pekka Paalanen77cbc952011-11-15 13:34:55 +02001518 struct display *display = window->display;
1519 struct input *input;
Rob Bradford7507b572012-05-15 17:55:34 +01001520 struct window_output *window_output;
1521 struct window_output *window_output_tmp;
Pekka Paalanen77cbc952011-11-15 13:34:55 +02001522
Pekka Paalanen40cb67b2013-04-25 13:57:49 +03001523 wl_list_remove(&window->redraw_task.link);
Pekka Paalanen77cbc952011-11-15 13:34:55 +02001524
1525 wl_list_for_each(input, &display->input_list, link) {
1526 if (input->pointer_focus == window)
1527 input->pointer_focus = NULL;
1528 if (input->keyboard_focus == window)
1529 input->keyboard_focus = NULL;
Kristian Høgsbergae6e2712012-01-26 11:09:20 -05001530 if (input->focus_widget &&
1531 input->focus_widget->window == window)
1532 input->focus_widget = NULL;
Pekka Paalanen77cbc952011-11-15 13:34:55 +02001533 }
1534
Rob Bradford7507b572012-05-15 17:55:34 +01001535 wl_list_for_each_safe(window_output, window_output_tmp,
1536 &window->window_output_list, link) {
1537 free (window_output);
1538 }
1539
Pekka Paalanen4dde2fc2012-01-19 13:33:50 +02001540 if (window->frame)
1541 frame_destroy(window->frame);
1542
Pekka Paalanen6b2dc912011-11-29 10:25:08 +02001543 if (window->shell_surface)
1544 wl_shell_surface_destroy(window->shell_surface);
Pekka Paalanen4e373742013-02-13 16:17:13 +02001545
1546 surface_destroy(window->main_surface);
1547
Kristian Høgsberg248c1b62011-01-21 18:03:15 -05001548 wl_list_remove(&window->link);
Pekka Paalanen5ec65852011-12-16 10:09:29 +02001549
Pekka Paalanen5ec65852011-12-16 10:09:29 +02001550 free(window->title);
Kristian Høgsberg248c1b62011-01-21 18:03:15 -05001551 free(window);
1552}
1553
Kristian Høgsbergc51f7992012-01-08 15:09:53 -05001554static struct widget *
Kristian Høgsberg441338c2012-01-10 13:52:34 -05001555widget_find_widget(struct widget *widget, int32_t x, int32_t y)
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001556{
Kristian Høgsberg441338c2012-01-10 13:52:34 -05001557 struct widget *child, *target;
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001558
Kristian Høgsberg441338c2012-01-10 13:52:34 -05001559 wl_list_for_each(child, &widget->child_list, link) {
1560 target = widget_find_widget(child, x, y);
1561 if (target)
1562 return target;
1563 }
1564
1565 if (widget->allocation.x <= x &&
1566 x < widget->allocation.x + widget->allocation.width &&
1567 widget->allocation.y <= y &&
1568 y < widget->allocation.y + widget->allocation.height) {
1569 return widget;
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001570 }
1571
1572 return NULL;
1573}
1574
Kristian Høgsberg441338c2012-01-10 13:52:34 -05001575static struct widget *
Pekka Paalanenac95f3e2013-02-13 16:17:17 +02001576window_find_widget(struct window *window, int32_t x, int32_t y)
1577{
Pekka Paalanen35e82632013-04-25 13:57:48 +03001578 struct surface *surface;
1579 struct widget *widget;
1580
1581 wl_list_for_each(surface, &window->subsurface_list, link) {
1582 widget = widget_find_widget(surface->widget, x, y);
1583 if (widget)
1584 return widget;
1585 }
1586
1587 return NULL;
Pekka Paalanenac95f3e2013-02-13 16:17:17 +02001588}
1589
1590static struct widget *
Pekka Paalanen2d8a32a2013-02-13 16:17:19 +02001591widget_create(struct window *window, struct surface *surface, void *data)
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001592{
Kristian Høgsbergc51f7992012-01-08 15:09:53 -05001593 struct widget *widget;
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001594
Kristian Høgsbergc51f7992012-01-08 15:09:53 -05001595 widget = malloc(sizeof *widget);
1596 memset(widget, 0, sizeof *widget);
Kristian Høgsberg9a13dab2012-01-08 15:18:19 -05001597 widget->window = window;
Pekka Paalanen2d8a32a2013-02-13 16:17:19 +02001598 widget->surface = surface;
Kristian Høgsbergc51f7992012-01-08 15:09:53 -05001599 widget->user_data = data;
Pekka Paalanen2d8a32a2013-02-13 16:17:19 +02001600 widget->allocation = surface->allocation;
Kristian Høgsberg441338c2012-01-10 13:52:34 -05001601 wl_list_init(&widget->child_list);
Kristian Høgsberg010f98b2012-02-23 17:30:45 -05001602 widget->opaque = 0;
Tiago Vignatti82db9d82012-05-23 22:06:27 +03001603 widget->tooltip = NULL;
1604 widget->tooltip_count = 0;
Kristian Høgsbergbf74d522012-11-30 14:54:35 -05001605 widget->default_cursor = CURSOR_LEFT_PTR;
Kristian Høgsberg441338c2012-01-10 13:52:34 -05001606
1607 return widget;
1608}
1609
1610struct widget *
1611window_add_widget(struct window *window, void *data)
1612{
Pekka Paalanenac95f3e2013-02-13 16:17:17 +02001613 struct widget *widget;
Kristian Høgsberg441338c2012-01-10 13:52:34 -05001614
Pekka Paalanen2d8a32a2013-02-13 16:17:19 +02001615 widget = widget_create(window, window->main_surface, data);
Pekka Paalanenac95f3e2013-02-13 16:17:17 +02001616 wl_list_init(&widget->link);
1617 window->main_surface->widget = widget;
1618
1619 return widget;
Kristian Høgsberg441338c2012-01-10 13:52:34 -05001620}
1621
1622struct widget *
1623widget_add_widget(struct widget *parent, void *data)
1624{
1625 struct widget *widget;
1626
Pekka Paalanen2d8a32a2013-02-13 16:17:19 +02001627 widget = widget_create(parent->window, parent->surface, data);
Kristian Høgsberg441338c2012-01-10 13:52:34 -05001628 wl_list_insert(parent->child_list.prev, &widget->link);
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001629
Kristian Høgsbergc51f7992012-01-08 15:09:53 -05001630 return widget;
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001631}
1632
1633void
Kristian Høgsberg441338c2012-01-10 13:52:34 -05001634widget_destroy(struct widget *widget)
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001635{
Pekka Paalanene156fb62012-01-19 13:51:38 +02001636 struct display *display = widget->window->display;
Pekka Paalanen35e82632013-04-25 13:57:48 +03001637 struct surface *surface = widget->surface;
Pekka Paalanene156fb62012-01-19 13:51:38 +02001638 struct input *input;
1639
Pekka Paalanen35e82632013-04-25 13:57:48 +03001640 /* Destroy the sub-surface along with the root widget */
1641 if (surface->widget == widget && surface->subsurface)
1642 surface_destroy(widget->surface);
1643
Tiago Vignatti82db9d82012-05-23 22:06:27 +03001644 if (widget->tooltip) {
1645 free(widget->tooltip);
1646 widget->tooltip = NULL;
1647 }
1648
Pekka Paalanene156fb62012-01-19 13:51:38 +02001649 wl_list_for_each(input, &display->input_list, link) {
1650 if (input->focus_widget == widget)
1651 input->focus_widget = NULL;
1652 }
1653
Kristian Høgsberg441338c2012-01-10 13:52:34 -05001654 wl_list_remove(&widget->link);
1655 free(widget);
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001656}
1657
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001658void
Kristian Høgsbergbf74d522012-11-30 14:54:35 -05001659widget_set_default_cursor(struct widget *widget, int cursor)
1660{
1661 widget->default_cursor = cursor;
1662}
1663
1664void
Kristian Høgsbergc51f7992012-01-08 15:09:53 -05001665widget_get_allocation(struct widget *widget, struct rectangle *allocation)
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001666{
Kristian Høgsbergc51f7992012-01-08 15:09:53 -05001667 *allocation = widget->allocation;
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001668}
1669
1670void
Kristian Høgsbergbb977002012-01-10 19:11:42 -05001671widget_set_size(struct widget *widget, int32_t width, int32_t height)
1672{
Kristian Høgsbergbb977002012-01-10 19:11:42 -05001673 widget->allocation.width = width;
1674 widget->allocation.height = height;
Kristian Høgsbergbb977002012-01-10 19:11:42 -05001675}
1676
1677void
Kristian Høgsbergc51f7992012-01-08 15:09:53 -05001678widget_set_allocation(struct widget *widget,
1679 int32_t x, int32_t y, int32_t width, int32_t height)
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001680{
Kristian Høgsbergc51f7992012-01-08 15:09:53 -05001681 widget->allocation.x = x;
1682 widget->allocation.y = y;
Tiago Vignattic5528d82012-02-09 19:06:55 +02001683 widget_set_size(widget, width, height);
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001684}
1685
Kristian Høgsberg010f98b2012-02-23 17:30:45 -05001686void
1687widget_set_transparent(struct widget *widget, int transparent)
1688{
1689 widget->opaque = !transparent;
1690}
1691
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001692void *
Kristian Høgsbergc51f7992012-01-08 15:09:53 -05001693widget_get_user_data(struct widget *widget)
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001694{
Kristian Høgsbergc51f7992012-01-08 15:09:53 -05001695 return widget->user_data;
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001696}
1697
Pekka Paalanen0c4445b2013-02-13 16:17:23 +02001698static cairo_surface_t *
1699widget_get_cairo_surface(struct widget *widget)
1700{
1701 struct surface *surface = widget->surface;
1702 struct window *window = widget->window;
1703
1704 if (!surface->cairo_surface) {
1705 if (surface == window->main_surface)
1706 window_create_main_surface(window);
1707 else
1708 surface_create_surface(surface, 0, 0, 0);
1709 }
1710
1711 return surface->cairo_surface;
1712}
1713
Alexander Larsson15901f02013-05-22 14:41:25 +02001714static void
1715widget_cairo_update_transform(struct widget *widget, cairo_t *cr)
1716{
1717 struct surface *surface = widget->surface;
1718 double angle;
1719 cairo_matrix_t m;
1720 enum wl_output_transform transform;
1721 int surface_width, surface_height;
1722 int translate_x, translate_y;
Alexander Larssonedddbd12013-05-24 13:09:43 +02001723 int32_t scale;
Alexander Larsson15901f02013-05-22 14:41:25 +02001724
1725 surface_width = surface->allocation.width;
1726 surface_height = surface->allocation.height;
1727
Alexander Larsson5e9b6522013-05-22 14:41:28 +02001728 transform = surface->buffer_transform;
Alexander Larsson2aaa8b72013-05-22 14:41:29 +02001729 scale = surface->buffer_scale;
Alexander Larsson5e9b6522013-05-22 14:41:28 +02001730
Alexander Larsson15901f02013-05-22 14:41:25 +02001731 switch (transform) {
1732 case WL_OUTPUT_TRANSFORM_FLIPPED:
1733 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
1734 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
1735 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
1736 cairo_matrix_init(&m, -1, 0, 0, 1, 0, 0);
1737 break;
1738 default:
1739 cairo_matrix_init_identity(&m);
1740 break;
1741 }
1742
1743 switch (transform) {
1744 case WL_OUTPUT_TRANSFORM_NORMAL:
1745 default:
1746 angle = 0;
1747 translate_x = 0;
1748 translate_y = 0;
1749 break;
1750 case WL_OUTPUT_TRANSFORM_FLIPPED:
1751 angle = 0;
1752 translate_x = surface_width;
1753 translate_y = 0;
1754 break;
1755 case WL_OUTPUT_TRANSFORM_90:
1756 angle = M_PI_2;
1757 translate_x = surface_height;
1758 translate_y = 0;
1759 break;
1760 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
1761 angle = M_PI_2;
1762 translate_x = surface_height;
1763 translate_y = surface_width;
1764 break;
1765 case WL_OUTPUT_TRANSFORM_180:
1766 angle = M_PI;
1767 translate_x = surface_width;
1768 translate_y = surface_height;
1769 break;
1770 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
1771 angle = M_PI;
1772 translate_x = 0;
1773 translate_y = surface_height;
1774 break;
1775 case WL_OUTPUT_TRANSFORM_270:
1776 angle = M_PI + M_PI_2;
1777 translate_x = 0;
1778 translate_y = surface_width;
1779 break;
1780 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
1781 angle = M_PI + M_PI_2;
1782 translate_x = 0;
1783 translate_y = 0;
1784 break;
1785 }
1786
Alexander Larsson2aaa8b72013-05-22 14:41:29 +02001787 cairo_scale(cr, scale, scale);
Alexander Larsson15901f02013-05-22 14:41:25 +02001788 cairo_translate(cr, translate_x, translate_y);
1789 cairo_rotate(cr, angle);
1790 cairo_transform(cr, &m);
1791}
1792
Pekka Paalanen0c4445b2013-02-13 16:17:23 +02001793cairo_t *
1794widget_cairo_create(struct widget *widget)
1795{
Pekka Paalanen35e82632013-04-25 13:57:48 +03001796 struct surface *surface = widget->surface;
Pekka Paalanen0c4445b2013-02-13 16:17:23 +02001797 cairo_surface_t *cairo_surface;
1798 cairo_t *cr;
1799
1800 cairo_surface = widget_get_cairo_surface(widget);
1801 cr = cairo_create(cairo_surface);
1802
Alexander Larsson15901f02013-05-22 14:41:25 +02001803 widget_cairo_update_transform(widget, cr);
1804
Pekka Paalanen35e82632013-04-25 13:57:48 +03001805 cairo_translate(cr, -surface->allocation.x, -surface->allocation.y);
1806
Pekka Paalanen0c4445b2013-02-13 16:17:23 +02001807 return cr;
1808}
1809
Pekka Paalanen7ff7a802013-04-25 13:57:50 +03001810struct wl_surface *
1811widget_get_wl_surface(struct widget *widget)
1812{
1813 return widget->surface->surface;
1814}
1815
1816uint32_t
1817widget_get_last_time(struct widget *widget)
1818{
1819 return widget->surface->last_time;
1820}
1821
1822void
1823widget_input_region_add(struct widget *widget, const struct rectangle *rect)
1824{
1825 struct wl_compositor *comp = widget->window->display->compositor;
1826 struct surface *surface = widget->surface;
1827
1828 if (!surface->input_region)
1829 surface->input_region = wl_compositor_create_region(comp);
1830
1831 if (rect) {
1832 wl_region_add(surface->input_region,
1833 rect->x, rect->y, rect->width, rect->height);
1834 }
1835}
1836
Kristian Høgsberg248c1b62011-01-21 18:03:15 -05001837void
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -05001838widget_set_resize_handler(struct widget *widget,
1839 widget_resize_handler_t handler)
1840{
1841 widget->resize_handler = handler;
1842}
1843
1844void
1845widget_set_redraw_handler(struct widget *widget,
1846 widget_redraw_handler_t handler)
1847{
1848 widget->redraw_handler = handler;
1849}
1850
1851void
Kristian Høgsbergee143232012-01-09 08:42:24 -05001852widget_set_enter_handler(struct widget *widget, widget_enter_handler_t handler)
Kristian Høgsberg9a13dab2012-01-08 15:18:19 -05001853{
Kristian Høgsbergee143232012-01-09 08:42:24 -05001854 widget->enter_handler = handler;
1855}
1856
1857void
1858widget_set_leave_handler(struct widget *widget, widget_leave_handler_t handler)
1859{
1860 widget->leave_handler = handler;
Kristian Høgsberg9a13dab2012-01-08 15:18:19 -05001861}
1862
1863void
Kristian Høgsberg04e98342012-01-09 09:36:16 -05001864widget_set_motion_handler(struct widget *widget,
1865 widget_motion_handler_t handler)
1866{
1867 widget->motion_handler = handler;
1868}
1869
1870void
Kristian Høgsberga8a0db32012-01-09 11:12:05 -05001871widget_set_button_handler(struct widget *widget,
1872 widget_button_handler_t handler)
1873{
1874 widget->button_handler = handler;
1875}
1876
1877void
Philipp Brüschweiler7e0cc542012-08-14 11:02:41 +02001878widget_set_axis_handler(struct widget *widget,
1879 widget_axis_handler_t handler)
1880{
1881 widget->axis_handler = handler;
1882}
1883
Pekka Paalanen40cb67b2013-04-25 13:57:49 +03001884static void
1885window_schedule_redraw_task(struct window *window);
1886
Philipp Brüschweiler7e0cc542012-08-14 11:02:41 +02001887void
Kristian Høgsberg9a13dab2012-01-08 15:18:19 -05001888widget_schedule_redraw(struct widget *widget)
1889{
Pekka Paalanen71233882013-04-25 13:57:53 +03001890 DBG_OBJ(widget->surface->surface, "widget %p\n", widget);
Pekka Paalanen40cb67b2013-04-25 13:57:49 +03001891 widget->surface->redraw_needed = 1;
1892 window_schedule_redraw_task(widget->window);
Kristian Høgsberg9a13dab2012-01-08 15:18:19 -05001893}
1894
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -04001895cairo_surface_t *
1896window_get_surface(struct window *window)
1897{
Pekka Paalanen0c4445b2013-02-13 16:17:23 +02001898 cairo_surface_t *cairo_surface;
1899
1900 cairo_surface = widget_get_cairo_surface(window->main_surface->widget);
1901
1902 return cairo_surface_reference(cairo_surface);
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -04001903}
1904
Benjamin Franzkeec4d3422011-03-14 12:07:26 +01001905struct wl_surface *
1906window_get_wl_surface(struct window *window)
1907{
Pekka Paalanen4e373742013-02-13 16:17:13 +02001908 return window->main_surface->surface;
Benjamin Franzkeec4d3422011-03-14 12:07:26 +01001909}
1910
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001911struct wl_shell_surface *
1912window_get_wl_shell_surface(struct window *window)
1913{
1914 return window->shell_surface;
1915}
1916
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001917static void
Tiago Vignatti82db9d82012-05-23 22:06:27 +03001918tooltip_redraw_handler(struct widget *widget, void *data)
1919{
1920 cairo_t *cr;
1921 const int32_t r = 3;
1922 struct tooltip *tooltip = data;
1923 int32_t width, height;
Tiago Vignatti82db9d82012-05-23 22:06:27 +03001924
Pekka Paalanen0c4445b2013-02-13 16:17:23 +02001925 cr = widget_cairo_create(widget);
Tiago Vignatti82db9d82012-05-23 22:06:27 +03001926 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
1927 cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.0);
1928 cairo_paint(cr);
1929
Pekka Paalanen0a9686f2013-02-13 16:17:22 +02001930 width = widget->allocation.width;
1931 height = widget->allocation.height;
Tiago Vignatti82db9d82012-05-23 22:06:27 +03001932 rounded_rect(cr, 0, 0, width, height, r);
1933
1934 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
1935 cairo_set_source_rgba(cr, 0.0, 0.0, 0.4, 0.8);
1936 cairo_fill(cr);
1937
1938 cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
1939 cairo_move_to(cr, 10, 16);
1940 cairo_show_text(cr, tooltip->entry);
1941 cairo_destroy(cr);
1942}
1943
1944static cairo_text_extents_t
1945get_text_extents(struct tooltip *tooltip)
1946{
Tiago Vignatti82db9d82012-05-23 22:06:27 +03001947 cairo_t *cr;
1948 cairo_text_extents_t extents;
1949
Pekka Paalanen3cbb0892012-11-19 17:16:01 +02001950 /* Use the dummy_surface because tooltip's surface was not
1951 * created yet, and parent does not have a valid surface
1952 * outside repaint, either.
1953 */
1954 cr = cairo_create(tooltip->window->display->dummy_surface);
Tiago Vignatti82db9d82012-05-23 22:06:27 +03001955 cairo_text_extents(cr, tooltip->entry, &extents);
1956 cairo_destroy(cr);
1957
1958 return extents;
1959}
1960
1961static int
1962window_create_tooltip(struct tooltip *tooltip)
1963{
1964 struct widget *parent = tooltip->parent;
1965 struct display *display = parent->window->display;
1966 struct window *window;
1967 const int offset_y = 27;
1968 const int margin = 3;
1969 cairo_text_extents_t extents;
1970
1971 if (tooltip->widget)
1972 return 0;
1973
1974 window = window_create_transient(display, parent->window, tooltip->x,
1975 tooltip->y + offset_y,
1976 WL_SHELL_SURFACE_TRANSIENT_INACTIVE);
1977 if (!window)
1978 return -1;
1979
1980 tooltip->window = window;
1981 tooltip->widget = window_add_widget(tooltip->window, tooltip);
1982
1983 extents = get_text_extents(tooltip);
1984 widget_set_redraw_handler(tooltip->widget, tooltip_redraw_handler);
1985 window_schedule_resize(window, extents.width + 20, 20 + margin * 2);
1986
1987 return 0;
1988}
1989
1990void
1991widget_destroy_tooltip(struct widget *parent)
1992{
1993 struct tooltip *tooltip = parent->tooltip;
1994
1995 parent->tooltip_count = 0;
1996 if (!tooltip)
1997 return;
1998
1999 if (tooltip->widget) {
2000 widget_destroy(tooltip->widget);
2001 window_destroy(tooltip->window);
2002 tooltip->widget = NULL;
2003 tooltip->window = NULL;
2004 }
2005
2006 close(tooltip->tooltip_fd);
2007 free(tooltip->entry);
2008 free(tooltip);
2009 parent->tooltip = NULL;
2010}
2011
2012static void
2013tooltip_func(struct task *task, uint32_t events)
2014{
2015 struct tooltip *tooltip =
2016 container_of(task, struct tooltip, tooltip_task);
2017 uint64_t exp;
2018
Martin Olsson8df662a2012-07-08 03:03:47 +02002019 if (read(tooltip->tooltip_fd, &exp, sizeof (uint64_t)) != sizeof (uint64_t))
2020 abort();
Tiago Vignatti82db9d82012-05-23 22:06:27 +03002021 window_create_tooltip(tooltip);
2022}
2023
2024#define TOOLTIP_TIMEOUT 500
2025static int
2026tooltip_timer_reset(struct tooltip *tooltip)
2027{
2028 struct itimerspec its;
2029
2030 its.it_interval.tv_sec = 0;
2031 its.it_interval.tv_nsec = 0;
2032 its.it_value.tv_sec = TOOLTIP_TIMEOUT / 1000;
2033 its.it_value.tv_nsec = (TOOLTIP_TIMEOUT % 1000) * 1000 * 1000;
2034 if (timerfd_settime(tooltip->tooltip_fd, 0, &its, NULL) < 0) {
2035 fprintf(stderr, "could not set timerfd\n: %m");
2036 return -1;
2037 }
2038
2039 return 0;
2040}
2041
2042int
2043widget_set_tooltip(struct widget *parent, char *entry, float x, float y)
2044{
2045 struct tooltip *tooltip = parent->tooltip;
2046
2047 parent->tooltip_count++;
2048 if (tooltip) {
2049 tooltip->x = x;
2050 tooltip->y = y;
2051 tooltip_timer_reset(tooltip);
2052 return 0;
2053 }
2054
2055 /* the handler might be triggered too fast via input device motion, so
2056 * we need this check here to make sure tooltip is fully initialized */
2057 if (parent->tooltip_count > 1)
2058 return 0;
2059
2060 tooltip = malloc(sizeof *tooltip);
2061 if (!tooltip)
2062 return -1;
2063
2064 parent->tooltip = tooltip;
2065 tooltip->parent = parent;
2066 tooltip->widget = NULL;
2067 tooltip->window = NULL;
2068 tooltip->x = x;
2069 tooltip->y = y;
2070 tooltip->entry = strdup(entry);
2071 tooltip->tooltip_fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
2072 if (tooltip->tooltip_fd < 0) {
2073 fprintf(stderr, "could not create timerfd\n: %m");
2074 return -1;
2075 }
2076
2077 tooltip->tooltip_task.run = tooltip_func;
2078 display_watch_fd(parent->window->display, tooltip->tooltip_fd,
2079 EPOLLIN, &tooltip->tooltip_task);
2080 tooltip_timer_reset(tooltip);
2081
2082 return 0;
2083}
2084
2085static void
Jonas Ådahl14c92ff2012-08-29 22:13:02 +02002086workspace_manager_state(void *data,
2087 struct workspace_manager *workspace_manager,
2088 uint32_t current,
2089 uint32_t count)
2090{
2091 struct display *display = data;
2092
2093 display->workspace = current;
2094 display->workspace_count = count;
2095}
2096
2097static const struct workspace_manager_listener workspace_manager_listener = {
2098 workspace_manager_state
2099};
2100
2101static void
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002102frame_resize_handler(struct widget *widget,
2103 int32_t width, int32_t height, void *data)
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04002104{
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002105 struct frame *frame = data;
2106 struct widget *child = frame->child;
2107 struct rectangle allocation;
Kristian Høgsberg010f98b2012-02-23 17:30:45 -05002108 struct display *display = widget->window->display;
Pekka Paalanen2d8a32a2013-02-13 16:17:19 +02002109 struct surface *surface = widget->surface;
Martin Minarik1998b152012-05-10 02:04:35 +02002110 struct frame_button * button;
Kristian Høgsberg5adb4802012-05-15 22:25:28 -04002111 struct theme *t = display->theme;
Martin Minarik1998b152012-05-10 02:04:35 +02002112 int x_l, x_r, y, w, h;
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002113 int decoration_width, decoration_height;
Scott Moreauc6a7e4b2012-09-28 02:45:06 -06002114 int opaque_margin, shadow_margin;
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002115
Scott Moreauc6a7e4b2012-09-28 02:45:06 -06002116 switch (widget->window->type) {
2117 case TYPE_FULLSCREEN:
2118 decoration_width = 0;
2119 decoration_height = 0;
2120
2121 allocation.x = 0;
2122 allocation.y = 0;
2123 allocation.width = width;
2124 allocation.height = height;
2125 opaque_margin = 0;
2126
2127 wl_list_for_each(button, &frame->buttons_list, link)
2128 button->widget->opaque = 1;
2129 break;
2130 case TYPE_MAXIMIZED:
2131 decoration_width = t->width * 2;
2132 decoration_height = t->width + t->titlebar_height;
2133
2134 allocation.x = t->width;
2135 allocation.y = t->titlebar_height;
2136 allocation.width = width - decoration_width;
2137 allocation.height = height - decoration_height;
2138
2139 opaque_margin = 0;
2140
2141 wl_list_for_each(button, &frame->buttons_list, link)
2142 button->widget->opaque = 0;
2143 break;
2144 default:
Kristian Høgsberg291c69c2012-05-15 22:12:54 -04002145 decoration_width = (t->width + t->margin) * 2;
2146 decoration_height = t->width +
2147 t->titlebar_height + t->margin * 2;
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002148
Kristian Høgsberg291c69c2012-05-15 22:12:54 -04002149 allocation.x = t->width + t->margin;
2150 allocation.y = t->titlebar_height + t->margin;
Kristian Høgsberg2675dc12012-02-16 22:57:21 -05002151 allocation.width = width - decoration_width;
2152 allocation.height = height - decoration_height;
Kristian Høgsberg010f98b2012-02-23 17:30:45 -05002153
Kristian Høgsberg291c69c2012-05-15 22:12:54 -04002154 opaque_margin = t->margin + t->frame_radius;
Martin Minarik1998b152012-05-10 02:04:35 +02002155
2156 wl_list_for_each(button, &frame->buttons_list, link)
2157 button->widget->opaque = 0;
Scott Moreauc6a7e4b2012-09-28 02:45:06 -06002158 break;
Kristian Høgsberg010f98b2012-02-23 17:30:45 -05002159 }
2160
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002161 widget_set_allocation(child, allocation.x, allocation.y,
2162 allocation.width, allocation.height);
2163
2164 if (child->resize_handler)
2165 child->resize_handler(child,
2166 allocation.width,
2167 allocation.height,
2168 child->user_data);
2169
Scott Moreauf7e498c2012-05-14 11:39:29 -06002170 width = child->allocation.width + decoration_width;
2171 height = child->allocation.height + decoration_height;
2172
Scott Moreauc6a7e4b2012-09-28 02:45:06 -06002173 shadow_margin = widget->window->type == TYPE_MAXIMIZED ? 0 : t->margin;
2174
Pekka Paalanenb1cd9b12013-02-13 16:17:18 +02002175 surface->input_region =
Kristian Høgsberg3fb613e2012-10-15 15:01:24 -04002176 wl_compositor_create_region(display->compositor);
Kristian Høgsberg023be102012-07-31 11:59:12 -04002177 if (widget->window->type != TYPE_FULLSCREEN) {
Pekka Paalanenb1cd9b12013-02-13 16:17:18 +02002178 wl_region_add(surface->input_region,
Scott Moreauc6a7e4b2012-09-28 02:45:06 -06002179 shadow_margin, shadow_margin,
2180 width - 2 * shadow_margin,
2181 height - 2 * shadow_margin);
Kristian Høgsberg3fb613e2012-10-15 15:01:24 -04002182 } else {
Pekka Paalanenb1cd9b12013-02-13 16:17:18 +02002183 wl_region_add(surface->input_region, 0, 0, width, height);
Kristian Høgsberg023be102012-07-31 11:59:12 -04002184 }
2185
Scott Moreauf7e498c2012-05-14 11:39:29 -06002186 widget_set_allocation(widget, 0, 0, width, height);
Kristian Høgsbergf10df852012-02-28 21:52:12 -05002187
Ander Conselvan de Oliveiraddd3e272012-11-30 17:34:23 +02002188 if (child->opaque)
Pekka Paalanenb1cd9b12013-02-13 16:17:18 +02002189 wl_region_add(surface->opaque_region,
Kristian Høgsbergf10df852012-02-28 21:52:12 -05002190 opaque_margin, opaque_margin,
2191 widget->allocation.width - 2 * opaque_margin,
2192 widget->allocation.height - 2 * opaque_margin);
Martin Minarik1998b152012-05-10 02:04:35 +02002193
2194 /* frame internal buttons */
Scott Moreauc6a7e4b2012-09-28 02:45:06 -06002195 x_r = frame->widget->allocation.width - t->width - shadow_margin;
2196 x_l = t->width + shadow_margin;
2197 y = t->width + shadow_margin;
Martin Minarik1998b152012-05-10 02:04:35 +02002198 wl_list_for_each(button, &frame->buttons_list, link) {
2199 const int button_padding = 4;
2200 w = cairo_image_surface_get_width(button->icon);
2201 h = cairo_image_surface_get_height(button->icon);
2202
2203 if (button->decoration == FRAME_BUTTON_FANCY)
2204 w += 10;
2205
2206 if (button->align == FRAME_BUTTON_LEFT) {
2207 widget_set_allocation(button->widget,
2208 x_l, y , w + 1, h + 1);
2209 x_l += w;
2210 x_l += button_padding;
2211 } else {
2212 x_r -= w;
2213 widget_set_allocation(button->widget,
2214 x_r, y , w + 1, h + 1);
2215 x_r -= button_padding;
2216 }
2217 }
2218}
2219
2220static int
2221frame_button_enter_handler(struct widget *widget,
2222 struct input *input, float x, float y, void *data)
2223{
2224 struct frame_button *frame_button = data;
2225
2226 widget_schedule_redraw(frame_button->widget);
2227 frame_button->state = FRAME_BUTTON_OVER;
2228
Ander Conselvan de Oliveiradc8c8fc2012-05-25 16:01:41 +03002229 return CURSOR_LEFT_PTR;
Martin Minarik1998b152012-05-10 02:04:35 +02002230}
2231
2232static void
2233frame_button_leave_handler(struct widget *widget, struct input *input, void *data)
2234{
2235 struct frame_button *frame_button = data;
2236
2237 widget_schedule_redraw(frame_button->widget);
2238 frame_button->state = FRAME_BUTTON_DEFAULT;
2239}
2240
2241static void
2242frame_button_button_handler(struct widget *widget,
2243 struct input *input, uint32_t time,
Daniel Stone4dbadb12012-05-30 16:31:51 +01002244 uint32_t button,
2245 enum wl_pointer_button_state state, void *data)
Martin Minarik1998b152012-05-10 02:04:35 +02002246{
2247 struct frame_button *frame_button = data;
2248 struct window *window = widget->window;
Pekka Vuorela4e363d22012-09-26 15:05:45 +03002249 int was_pressed = (frame_button->state == FRAME_BUTTON_ACTIVE);
Martin Minarik1998b152012-05-10 02:04:35 +02002250
2251 if (button != BTN_LEFT)
2252 return;
2253
2254 switch (state) {
Daniel Stone4dbadb12012-05-30 16:31:51 +01002255 case WL_POINTER_BUTTON_STATE_PRESSED:
Martin Minarik1998b152012-05-10 02:04:35 +02002256 frame_button->state = FRAME_BUTTON_ACTIVE;
2257 widget_schedule_redraw(frame_button->widget);
2258
2259 if (frame_button->type == FRAME_BUTTON_ICON)
2260 window_show_frame_menu(window, input, time);
2261 return;
Daniel Stone4dbadb12012-05-30 16:31:51 +01002262 case WL_POINTER_BUTTON_STATE_RELEASED:
Martin Minarik1998b152012-05-10 02:04:35 +02002263 frame_button->state = FRAME_BUTTON_DEFAULT;
2264 widget_schedule_redraw(frame_button->widget);
2265 break;
2266 }
2267
Pekka Vuorela4e363d22012-09-26 15:05:45 +03002268 if (!was_pressed)
2269 return;
2270
Martin Minarik1998b152012-05-10 02:04:35 +02002271 switch (frame_button->type) {
2272 case FRAME_BUTTON_CLOSE:
2273 if (window->close_handler)
2274 window->close_handler(window->parent,
2275 window->user_data);
2276 else
2277 display_exit(window->display);
2278 break;
2279 case FRAME_BUTTON_MINIMIZE:
2280 fprintf(stderr,"Minimize stub\n");
2281 break;
2282 case FRAME_BUTTON_MAXIMIZE:
2283 window_set_maximized(window, window->type != TYPE_MAXIMIZED);
2284 break;
2285 default:
2286 /* Unknown operation */
2287 break;
2288 }
2289}
2290
Pekka Vuorela4e363d22012-09-26 15:05:45 +03002291static int
2292frame_button_motion_handler(struct widget *widget,
2293 struct input *input, uint32_t time,
2294 float x, float y, void *data)
2295{
2296 struct frame_button *frame_button = data;
2297 enum frame_button_pointer previous_button_state = frame_button->state;
2298
2299 /* only track state for a pressed button */
2300 if (input->grab != widget)
2301 return CURSOR_LEFT_PTR;
2302
2303 if (x > widget->allocation.x &&
2304 x < (widget->allocation.x + widget->allocation.width) &&
2305 y > widget->allocation.y &&
2306 y < (widget->allocation.y + widget->allocation.height)) {
2307 frame_button->state = FRAME_BUTTON_ACTIVE;
2308 } else {
2309 frame_button->state = FRAME_BUTTON_DEFAULT;
2310 }
2311
2312 if (frame_button->state != previous_button_state)
2313 widget_schedule_redraw(frame_button->widget);
2314
2315 return CURSOR_LEFT_PTR;
2316}
2317
Martin Minarik1998b152012-05-10 02:04:35 +02002318static void
2319frame_button_redraw_handler(struct widget *widget, void *data)
2320{
2321 struct frame_button *frame_button = data;
2322 cairo_t *cr;
2323 int width, height, x, y;
Martin Minarik1998b152012-05-10 02:04:35 +02002324
2325 x = widget->allocation.x;
2326 y = widget->allocation.y;
2327 width = widget->allocation.width;
2328 height = widget->allocation.height;
2329
2330 if (!width)
2331 return;
2332 if (!height)
2333 return;
2334 if (widget->opaque)
2335 return;
2336
Pekka Paalanen0c4445b2013-02-13 16:17:23 +02002337 cr = widget_cairo_create(widget);
Martin Minarik1998b152012-05-10 02:04:35 +02002338
2339 if (frame_button->decoration == FRAME_BUTTON_FANCY) {
2340 cairo_set_line_width(cr, 1);
2341
2342 cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
2343 cairo_rectangle (cr, x, y, 25, 16);
2344
2345 cairo_stroke_preserve(cr);
2346
2347 switch (frame_button->state) {
2348 case FRAME_BUTTON_DEFAULT:
2349 cairo_set_source_rgb(cr, 0.88, 0.88, 0.88);
2350 break;
2351 case FRAME_BUTTON_OVER:
2352 cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
2353 break;
2354 case FRAME_BUTTON_ACTIVE:
2355 cairo_set_source_rgb(cr, 0.7, 0.7, 0.7);
2356 break;
2357 }
2358
2359 cairo_fill (cr);
2360
2361 x += 4;
2362 }
2363
2364 cairo_set_source_surface(cr, frame_button->icon, x, y);
2365 cairo_paint(cr);
2366
2367 cairo_destroy(cr);
2368}
2369
2370static struct widget *
2371frame_button_create(struct frame *frame, void *data, enum frame_button_action type,
2372 enum frame_button_align align, enum frame_button_decoration style)
2373{
2374 struct frame_button *frame_button;
2375 const char *icon = data;
2376
2377 frame_button = malloc (sizeof *frame_button);
2378 memset(frame_button, 0, sizeof *frame_button);
2379
2380 frame_button->icon = cairo_image_surface_create_from_png(icon);
2381 frame_button->widget = widget_add_widget(frame->widget, frame_button);
2382 frame_button->frame = frame;
2383 frame_button->type = type;
2384 frame_button->align = align;
2385 frame_button->decoration = style;
2386
2387 wl_list_insert(frame->buttons_list.prev, &frame_button->link);
2388
2389 widget_set_redraw_handler(frame_button->widget, frame_button_redraw_handler);
2390 widget_set_enter_handler(frame_button->widget, frame_button_enter_handler);
2391 widget_set_leave_handler(frame_button->widget, frame_button_leave_handler);
2392 widget_set_button_handler(frame_button->widget, frame_button_button_handler);
Pekka Vuorela4e363d22012-09-26 15:05:45 +03002393 widget_set_motion_handler(frame_button->widget, frame_button_motion_handler);
Martin Minarik1998b152012-05-10 02:04:35 +02002394 return frame_button->widget;
2395}
2396
2397static void
2398frame_button_destroy(struct frame_button *frame_button)
2399{
2400 widget_destroy(frame_button->widget);
2401 wl_list_remove(&frame_button->link);
2402 cairo_surface_destroy(frame_button->icon);
2403 free(frame_button);
2404
2405 return;
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002406}
2407
2408static void
2409frame_redraw_handler(struct widget *widget, void *data)
2410{
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002411 cairo_t *cr;
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002412 struct window *window = widget->window;
Kristian Høgsberg5adb4802012-05-15 22:25:28 -04002413 struct theme *t = window->display->theme;
2414 uint32_t flags = 0;
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002415
Kristian Høgsberg2675dc12012-02-16 22:57:21 -05002416 if (window->type == TYPE_FULLSCREEN)
2417 return;
2418
Pekka Paalanen0c4445b2013-02-13 16:17:23 +02002419 cr = widget_cairo_create(widget);
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002420
Kristian Høgsberg86adef92012-08-13 22:25:53 -04002421 if (window->focus_count)
Kristian Høgsberg5adb4802012-05-15 22:25:28 -04002422 flags |= THEME_FRAME_ACTIVE;
Scott Moreauc6a7e4b2012-09-28 02:45:06 -06002423 if (window->type == TYPE_MAXIMIZED)
2424 flags |= THEME_FRAME_MAXIMIZED;
Kristian Høgsberg5adb4802012-05-15 22:25:28 -04002425 theme_render_frame(t, cr, widget->allocation.width,
2426 widget->allocation.height, window->title, flags);
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002427
2428 cairo_destroy(cr);
2429}
2430
2431static int
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002432frame_get_pointer_image_for_location(struct frame *frame, struct input *input)
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04002433{
Kristian Høgsbergf96e6c02012-05-22 16:38:53 -04002434 struct theme *t = frame->widget->window->display->theme;
Scott Moreauc6a7e4b2012-09-28 02:45:06 -06002435 struct window *window = frame->widget->window;
Kristian Høgsberg9a686242010-08-18 15:28:04 -04002436 int location;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04002437
Kristian Høgsberge994edd2013-02-14 16:31:42 -05002438 if (window->type != TYPE_TOPLEVEL)
2439 return CURSOR_LEFT_PTR;
2440
Kristian Høgsbergf96e6c02012-05-22 16:38:53 -04002441 location = theme_get_location(t, input->sx, input->sy,
2442 frame->widget->allocation.width,
Scott Moreauc6a7e4b2012-09-28 02:45:06 -06002443 frame->widget->allocation.height,
2444 window->type == TYPE_MAXIMIZED ?
2445 THEME_FRAME_MAXIMIZED : 0);
Kristian Høgsbergf96e6c02012-05-22 16:38:53 -04002446
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04002447 switch (location) {
Kristian Høgsbergf96e6c02012-05-22 16:38:53 -04002448 case THEME_LOCATION_RESIZING_TOP:
Ander Conselvan de Oliveiradc8c8fc2012-05-25 16:01:41 +03002449 return CURSOR_TOP;
Kristian Høgsbergf96e6c02012-05-22 16:38:53 -04002450 case THEME_LOCATION_RESIZING_BOTTOM:
Ander Conselvan de Oliveiradc8c8fc2012-05-25 16:01:41 +03002451 return CURSOR_BOTTOM;
Kristian Høgsbergf96e6c02012-05-22 16:38:53 -04002452 case THEME_LOCATION_RESIZING_LEFT:
Ander Conselvan de Oliveiradc8c8fc2012-05-25 16:01:41 +03002453 return CURSOR_LEFT;
Kristian Høgsbergf96e6c02012-05-22 16:38:53 -04002454 case THEME_LOCATION_RESIZING_RIGHT:
Ander Conselvan de Oliveiradc8c8fc2012-05-25 16:01:41 +03002455 return CURSOR_RIGHT;
Kristian Høgsbergf96e6c02012-05-22 16:38:53 -04002456 case THEME_LOCATION_RESIZING_TOP_LEFT:
Ander Conselvan de Oliveiradc8c8fc2012-05-25 16:01:41 +03002457 return CURSOR_TOP_LEFT;
Kristian Høgsbergf96e6c02012-05-22 16:38:53 -04002458 case THEME_LOCATION_RESIZING_TOP_RIGHT:
Ander Conselvan de Oliveiradc8c8fc2012-05-25 16:01:41 +03002459 return CURSOR_TOP_RIGHT;
Kristian Høgsbergf96e6c02012-05-22 16:38:53 -04002460 case THEME_LOCATION_RESIZING_BOTTOM_LEFT:
Ander Conselvan de Oliveiradc8c8fc2012-05-25 16:01:41 +03002461 return CURSOR_BOTTOM_LEFT;
Kristian Høgsbergf96e6c02012-05-22 16:38:53 -04002462 case THEME_LOCATION_RESIZING_BOTTOM_RIGHT:
Ander Conselvan de Oliveiradc8c8fc2012-05-25 16:01:41 +03002463 return CURSOR_BOTTOM_RIGHT;
Kristian Høgsbergf96e6c02012-05-22 16:38:53 -04002464 case THEME_LOCATION_EXTERIOR:
2465 case THEME_LOCATION_TITLEBAR:
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04002466 default:
Ander Conselvan de Oliveiradc8c8fc2012-05-25 16:01:41 +03002467 return CURSOR_LEFT_PTR;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04002468 }
Kristian Høgsbergcd9ac1d2011-12-15 09:14:34 -05002469}
2470
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002471static void
2472frame_menu_func(struct window *window, int index, void *data)
Kristian Høgsbergcd9ac1d2011-12-15 09:14:34 -05002473{
Jonas Ådahl14c92ff2012-08-29 22:13:02 +02002474 struct display *display;
2475
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002476 switch (index) {
2477 case 0: /* close */
2478 if (window->close_handler)
2479 window->close_handler(window->parent,
2480 window->user_data);
2481 else
2482 display_exit(window->display);
2483 break;
Kristian Høgsbergefb94882012-10-30 18:07:02 -04002484 case 1: /* move to workspace above */
Jonas Ådahl14c92ff2012-08-29 22:13:02 +02002485 display = window->display;
2486 if (display->workspace > 0)
Pekka Paalanen4e373742013-02-13 16:17:13 +02002487 workspace_manager_move_surface(
2488 display->workspace_manager,
2489 window->main_surface->surface,
2490 display->workspace - 1);
Jonas Ådahl14c92ff2012-08-29 22:13:02 +02002491 break;
Kristian Høgsbergefb94882012-10-30 18:07:02 -04002492 case 2: /* move to workspace below */
Jonas Ådahl14c92ff2012-08-29 22:13:02 +02002493 display = window->display;
Philipp Brüschweiler067abf62012-09-01 16:03:05 +02002494 if (display->workspace < display->workspace_count - 1)
Pekka Paalanen4e373742013-02-13 16:17:13 +02002495 workspace_manager_move_surface(
2496 display->workspace_manager,
2497 window->main_surface->surface,
2498 display->workspace + 1);
Kristian Høgsberg0f7a2852012-11-05 20:20:53 -05002499 break;
Kristian Høgsbergefb94882012-10-30 18:07:02 -04002500 case 3: /* fullscreen */
2501 /* we don't have a way to get out of fullscreen for now */
2502 if (window->fullscreen_handler)
2503 window->fullscreen_handler(window, window->user_data);
2504 break;
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002505 }
2506}
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04002507
Kristian Høgsbergd31fcab2012-01-31 09:53:44 -05002508void
2509window_show_frame_menu(struct window *window,
2510 struct input *input, uint32_t time)
2511{
2512 int32_t x, y;
Kristian Høgsbergefb94882012-10-30 18:07:02 -04002513 int count;
Kristian Høgsbergd31fcab2012-01-31 09:53:44 -05002514
2515 static const char *entries[] = {
Kristian Høgsbergefb94882012-10-30 18:07:02 -04002516 "Close",
2517 "Move to workspace above", "Move to workspace below",
2518 "Fullscreen"
Kristian Høgsbergd31fcab2012-01-31 09:53:44 -05002519 };
2520
Kristian Høgsbergefb94882012-10-30 18:07:02 -04002521 if (window->fullscreen_handler)
2522 count = ARRAY_LENGTH(entries);
2523 else
2524 count = ARRAY_LENGTH(entries) - 1;
2525
Kristian Høgsbergd31fcab2012-01-31 09:53:44 -05002526 input_get_position(input, &x, &y);
2527 window_show_menu(window->display, input, time, window,
Kristian Høgsbergefb94882012-10-30 18:07:02 -04002528 x - 10, y - 10, frame_menu_func, entries, count);
Kristian Høgsbergd31fcab2012-01-31 09:53:44 -05002529}
2530
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002531static int
2532frame_enter_handler(struct widget *widget,
Kristian Høgsberg80680c72012-05-10 12:21:37 -04002533 struct input *input, float x, float y, void *data)
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002534{
2535 return frame_get_pointer_image_for_location(data, input);
2536}
Kristian Høgsberg7d804062010-09-07 21:50:06 -04002537
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002538static int
2539frame_motion_handler(struct widget *widget,
2540 struct input *input, uint32_t time,
Kristian Høgsberg80680c72012-05-10 12:21:37 -04002541 float x, float y, void *data)
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002542{
2543 return frame_get_pointer_image_for_location(data, input);
2544}
Rob Bradford8bd35c72011-10-25 12:20:51 +01002545
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002546static void
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002547frame_button_handler(struct widget *widget,
2548 struct input *input, uint32_t time,
Daniel Stone4dbadb12012-05-30 16:31:51 +01002549 uint32_t button, enum wl_pointer_button_state state,
2550 void *data)
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002551
2552{
2553 struct frame *frame = data;
2554 struct window *window = widget->window;
Kristian Høgsberg1103a1a2012-04-03 12:00:48 -04002555 struct display *display = window->display;
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002556 int location;
Kristian Høgsberg1103a1a2012-04-03 12:00:48 -04002557
Kristian Høgsberge994edd2013-02-14 16:31:42 -05002558 if (window->type != TYPE_TOPLEVEL)
2559 return;
2560
Kristian Høgsbergf96e6c02012-05-22 16:38:53 -04002561 location = theme_get_location(display->theme, input->sx, input->sy,
2562 frame->widget->allocation.width,
Scott Moreauc6a7e4b2012-09-28 02:45:06 -06002563 frame->widget->allocation.height,
2564 window->type == TYPE_MAXIMIZED ?
2565 THEME_FRAME_MAXIMIZED : 0);
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002566
Daniel Stone4dbadb12012-05-30 16:31:51 +01002567 if (window->display->shell && button == BTN_LEFT &&
2568 state == WL_POINTER_BUTTON_STATE_PRESSED) {
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002569 switch (location) {
Kristian Høgsbergf96e6c02012-05-22 16:38:53 -04002570 case THEME_LOCATION_TITLEBAR:
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002571 if (!window->shell_surface)
2572 break;
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04002573 input_ungrab(input);
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002574 wl_shell_surface_move(window->shell_surface,
Daniel Stone37816df2012-05-16 18:45:18 +01002575 input_get_seat(input),
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04002576 display->serial);
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002577 break;
Kristian Høgsbergf96e6c02012-05-22 16:38:53 -04002578 case THEME_LOCATION_RESIZING_TOP:
2579 case THEME_LOCATION_RESIZING_BOTTOM:
2580 case THEME_LOCATION_RESIZING_LEFT:
2581 case THEME_LOCATION_RESIZING_RIGHT:
2582 case THEME_LOCATION_RESIZING_TOP_LEFT:
2583 case THEME_LOCATION_RESIZING_TOP_RIGHT:
2584 case THEME_LOCATION_RESIZING_BOTTOM_LEFT:
2585 case THEME_LOCATION_RESIZING_BOTTOM_RIGHT:
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002586 if (!window->shell_surface)
2587 break;
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04002588 input_ungrab(input);
Kristian Høgsberg1103a1a2012-04-03 12:00:48 -04002589
Pekka Paalanen99436862012-11-19 17:15:59 +02002590 window->resizing = 1;
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002591 wl_shell_surface_resize(window->shell_surface,
Daniel Stone37816df2012-05-16 18:45:18 +01002592 input_get_seat(input),
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04002593 display->serial, location);
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002594 break;
2595 }
Daniel Stone4dbadb12012-05-30 16:31:51 +01002596 } else if (button == BTN_RIGHT &&
2597 state == WL_POINTER_BUTTON_STATE_PRESSED) {
Kristian Høgsbergd31fcab2012-01-31 09:53:44 -05002598 window_show_frame_menu(window, input, time);
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002599 }
2600}
2601
2602struct widget *
2603frame_create(struct window *window, void *data)
2604{
2605 struct frame *frame;
2606
2607 frame = malloc(sizeof *frame);
2608 memset(frame, 0, sizeof *frame);
2609
2610 frame->widget = window_add_widget(window, frame);
2611 frame->child = widget_add_widget(frame->widget, data);
Martin Minarik1998b152012-05-10 02:04:35 +02002612
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002613 widget_set_redraw_handler(frame->widget, frame_redraw_handler);
2614 widget_set_resize_handler(frame->widget, frame_resize_handler);
2615 widget_set_enter_handler(frame->widget, frame_enter_handler);
2616 widget_set_motion_handler(frame->widget, frame_motion_handler);
2617 widget_set_button_handler(frame->widget, frame_button_handler);
2618
Martin Minarik1998b152012-05-10 02:04:35 +02002619 /* Create empty list for frame buttons */
2620 wl_list_init(&frame->buttons_list);
2621
2622 frame_button_create(frame, DATADIR "/weston/icon_window.png",
2623 FRAME_BUTTON_ICON, FRAME_BUTTON_LEFT, FRAME_BUTTON_NONE);
2624
2625 frame_button_create(frame, DATADIR "/weston/sign_close.png",
2626 FRAME_BUTTON_CLOSE, FRAME_BUTTON_RIGHT, FRAME_BUTTON_FANCY);
2627
2628 frame_button_create(frame, DATADIR "/weston/sign_maximize.png",
2629 FRAME_BUTTON_MAXIMIZE, FRAME_BUTTON_RIGHT, FRAME_BUTTON_FANCY);
2630
2631 frame_button_create(frame, DATADIR "/weston/sign_minimize.png",
2632 FRAME_BUTTON_MINIMIZE, FRAME_BUTTON_RIGHT, FRAME_BUTTON_FANCY);
2633
Pekka Paalanen4dde2fc2012-01-19 13:33:50 +02002634 window->frame = frame;
2635
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002636 return frame->child;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04002637}
2638
Kristian Høgsberga1627922012-06-20 17:30:03 -04002639void
2640frame_set_child_size(struct widget *widget, int child_width, int child_height)
2641{
2642 struct display *display = widget->window->display;
2643 struct theme *t = display->theme;
2644 int decoration_width, decoration_height;
2645 int width, height;
Scott Moreauc6a7e4b2012-09-28 02:45:06 -06002646 int margin = widget->window->type == TYPE_MAXIMIZED ? 0 : t->margin;
Kristian Høgsberga1627922012-06-20 17:30:03 -04002647
2648 if (widget->window->type != TYPE_FULLSCREEN) {
Scott Moreauc6a7e4b2012-09-28 02:45:06 -06002649 decoration_width = (t->width + margin) * 2;
Kristian Høgsberga1627922012-06-20 17:30:03 -04002650 decoration_height = t->width +
Scott Moreauc6a7e4b2012-09-28 02:45:06 -06002651 t->titlebar_height + margin * 2;
Kristian Høgsberga1627922012-06-20 17:30:03 -04002652
2653 width = child_width + decoration_width;
2654 height = child_height + decoration_height;
2655 } else {
2656 width = child_width;
2657 height = child_height;
2658 }
2659
2660 window_schedule_resize(widget->window, width, height);
2661}
2662
Kristian Høgsberge4feb562008-11-08 18:53:37 -05002663static void
Pekka Paalanen4dde2fc2012-01-19 13:33:50 +02002664frame_destroy(struct frame *frame)
2665{
Martin Minarik1998b152012-05-10 02:04:35 +02002666 struct frame_button *button, *tmp;
2667
2668 wl_list_for_each_safe(button, tmp, &frame->buttons_list, link)
2669 frame_button_destroy(button);
2670
Pekka Paalanen4dde2fc2012-01-19 13:33:50 +02002671 /* frame->child must be destroyed by the application */
2672 widget_destroy(frame->widget);
2673 free(frame);
2674}
2675
2676static void
Kristian Høgsbergb6323512012-01-11 00:04:42 -05002677input_set_focus_widget(struct input *input, struct widget *focus,
Kristian Høgsberg80680c72012-05-10 12:21:37 -04002678 float x, float y)
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04002679{
Kristian Høgsberg831dd522012-01-10 23:46:33 -05002680 struct widget *old, *widget;
Kristian Høgsbergbf74d522012-11-30 14:54:35 -05002681 int cursor;
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04002682
Kristian Høgsbergb6323512012-01-11 00:04:42 -05002683 if (focus == input->focus_widget)
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04002684 return;
2685
Kristian Høgsbergb6323512012-01-11 00:04:42 -05002686 old = input->focus_widget;
Kristian Høgsbergee143232012-01-09 08:42:24 -05002687 if (old) {
Kristian Høgsberg831dd522012-01-10 23:46:33 -05002688 widget = old;
2689 if (input->grab)
2690 widget = input->grab;
2691 if (widget->leave_handler)
2692 widget->leave_handler(old, input, widget->user_data);
Kristian Høgsbergb6323512012-01-11 00:04:42 -05002693 input->focus_widget = NULL;
Kristian Høgsbergee143232012-01-09 08:42:24 -05002694 }
2695
2696 if (focus) {
Kristian Høgsberg831dd522012-01-10 23:46:33 -05002697 widget = focus;
2698 if (input->grab)
2699 widget = input->grab;
Kristian Høgsbergf33984e2012-06-04 23:36:32 -04002700 input->focus_widget = focus;
Kristian Høgsberg831dd522012-01-10 23:46:33 -05002701 if (widget->enter_handler)
Kristian Høgsbergbf74d522012-11-30 14:54:35 -05002702 cursor = widget->enter_handler(focus, input, x, y,
2703 widget->user_data);
2704 else
2705 cursor = widget->default_cursor;
Kristian Høgsbergbb901fa2012-01-09 11:22:32 -05002706
Kristian Høgsbergbf74d522012-11-30 14:54:35 -05002707 input_set_pointer_image(input, cursor);
Kristian Høgsbergee143232012-01-09 08:42:24 -05002708 }
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04002709}
2710
Kristian Høgsbergb29798b2012-08-11 14:56:08 -04002711void
2712input_grab(struct input *input, struct widget *widget, uint32_t button)
2713{
2714 input->grab = widget;
2715 input->grab_button = button;
2716}
2717
2718void
2719input_ungrab(struct input *input)
2720{
2721 struct widget *widget;
2722
2723 input->grab = NULL;
2724 if (input->pointer_focus) {
Pekka Paalanenac95f3e2013-02-13 16:17:17 +02002725 widget = window_find_widget(input->pointer_focus,
Kristian Høgsbergb29798b2012-08-11 14:56:08 -04002726 input->sx, input->sy);
2727 input_set_focus_widget(input, widget, input->sx, input->sy);
2728 }
2729}
2730
2731static void
2732input_remove_pointer_focus(struct input *input)
2733{
2734 struct window *window = input->pointer_focus;
2735
2736 if (!window)
2737 return;
2738
2739 input_set_focus_widget(input, NULL, 0, 0);
2740
2741 input->pointer_focus = NULL;
2742 input->current_cursor = CURSOR_UNSET;
2743}
2744
2745static void
2746pointer_handle_enter(void *data, struct wl_pointer *pointer,
2747 uint32_t serial, struct wl_surface *surface,
2748 wl_fixed_t sx_w, wl_fixed_t sy_w)
2749{
2750 struct input *input = data;
2751 struct window *window;
2752 struct widget *widget;
2753 float sx = wl_fixed_to_double(sx_w);
2754 float sy = wl_fixed_to_double(sy_w);
2755
2756 if (!surface) {
2757 /* enter event for a window we've just destroyed */
2758 return;
2759 }
2760
2761 input->display->serial = serial;
2762 input->pointer_enter_serial = serial;
2763 input->pointer_focus = wl_surface_get_user_data(surface);
2764 window = input->pointer_focus;
2765
Pekka Paalanen99436862012-11-19 17:15:59 +02002766 if (window->resizing) {
2767 window->resizing = 0;
Kristian Høgsbergb29798b2012-08-11 14:56:08 -04002768 /* Schedule a redraw to free the pool */
2769 window_schedule_redraw(window);
2770 }
2771
2772 input->sx = sx;
2773 input->sy = sy;
2774
Pekka Paalanenac95f3e2013-02-13 16:17:17 +02002775 widget = window_find_widget(window, sx, sy);
Kristian Høgsbergb29798b2012-08-11 14:56:08 -04002776 input_set_focus_widget(input, widget, sx, sy);
2777}
2778
2779static void
2780pointer_handle_leave(void *data, struct wl_pointer *pointer,
2781 uint32_t serial, struct wl_surface *surface)
2782{
2783 struct input *input = data;
2784
2785 input->display->serial = serial;
2786 input_remove_pointer_focus(input);
2787}
2788
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04002789static void
Daniel Stone37816df2012-05-16 18:45:18 +01002790pointer_handle_motion(void *data, struct wl_pointer *pointer,
2791 uint32_t time, wl_fixed_t sx_w, wl_fixed_t sy_w)
Kristian Høgsberg61017b12008-11-02 18:51:48 -05002792{
Kristian Høgsberg808fd412010-07-20 17:06:19 -04002793 struct input *input = data;
Kristian Høgsberg9a686242010-08-18 15:28:04 -04002794 struct window *window = input->pointer_focus;
Kristian Høgsbergc51f7992012-01-08 15:09:53 -05002795 struct widget *widget;
Kristian Høgsbergbf74d522012-11-30 14:54:35 -05002796 int cursor;
Kristian Høgsberg80680c72012-05-10 12:21:37 -04002797 float sx = wl_fixed_to_double(sx_w);
2798 float sy = wl_fixed_to_double(sy_w);
Kristian Høgsberg808fd412010-07-20 17:06:19 -04002799
Kristian Høgsberg808fd412010-07-20 17:06:19 -04002800 input->sx = sx;
2801 input->sy = sy;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04002802
Pekka Vuorela6e1e3852012-09-17 22:15:57 +03002803 if (!window)
2804 return;
2805
Kristian Høgsberg831dd522012-01-10 23:46:33 -05002806 if (!(input->grab && input->grab_button)) {
Pekka Paalanenac95f3e2013-02-13 16:17:17 +02002807 widget = window_find_widget(window, sx, sy);
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04002808 input_set_focus_widget(input, widget, sx, sy);
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04002809 }
2810
Kristian Høgsberg831dd522012-01-10 23:46:33 -05002811 if (input->grab)
2812 widget = input->grab;
2813 else
Kristian Høgsbergb6323512012-01-11 00:04:42 -05002814 widget = input->focus_widget;
Kristian Høgsberg04e98342012-01-09 09:36:16 -05002815 if (widget && widget->motion_handler)
Jonas Ådahlf461eee2012-10-19 19:56:02 +02002816 cursor = widget->motion_handler(input->focus_widget,
Daniel Stone37816df2012-05-16 18:45:18 +01002817 input, time, sx, sy,
2818 widget->user_data);
Kristian Høgsbergbf74d522012-11-30 14:54:35 -05002819 else
2820 cursor = input->focus_widget->default_cursor;
Kristian Høgsberg9a686242010-08-18 15:28:04 -04002821
Kristian Høgsberg5a4e9ff2012-06-04 16:04:07 -04002822 input_set_pointer_image(input, cursor);
Kristian Høgsberg61017b12008-11-02 18:51:48 -05002823}
2824
Kristian Høgsberg1d7ffd32010-08-25 16:34:05 -04002825static void
Daniel Stone37816df2012-05-16 18:45:18 +01002826pointer_handle_button(void *data, struct wl_pointer *pointer, uint32_t serial,
Daniel Stone4dbadb12012-05-30 16:31:51 +01002827 uint32_t time, uint32_t button, uint32_t state_w)
Kristian Høgsberg94448c02008-12-30 11:03:33 -05002828{
Kristian Høgsberg808fd412010-07-20 17:06:19 -04002829 struct input *input = data;
Kristian Høgsbergc51f7992012-01-08 15:09:53 -05002830 struct widget *widget;
Daniel Stone4dbadb12012-05-30 16:31:51 +01002831 enum wl_pointer_button_state state = state_w;
Kristian Høgsbergbf6ceda2010-06-14 20:25:06 -04002832
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04002833 input->display->serial = serial;
Daniel Stone4dbadb12012-05-30 16:31:51 +01002834 if (input->focus_widget && input->grab == NULL &&
2835 state == WL_POINTER_BUTTON_STATE_PRESSED)
Kristian Høgsbergb6323512012-01-11 00:04:42 -05002836 input_grab(input, input->focus_widget, button);
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04002837
Neil Roberts6b28aad2012-01-23 19:11:18 +00002838 widget = input->grab;
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002839 if (widget && widget->button_handler)
Neil Roberts6b28aad2012-01-23 19:11:18 +00002840 (*widget->button_handler)(widget,
2841 input, time,
2842 button, state,
2843 input->grab->user_data);
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04002844
Daniel Stone4dbadb12012-05-30 16:31:51 +01002845 if (input->grab && input->grab_button == button &&
2846 state == WL_POINTER_BUTTON_STATE_RELEASED)
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04002847 input_ungrab(input);
Kristian Høgsberg94448c02008-12-30 11:03:33 -05002848}
2849
Kristian Høgsberg99f090d2009-02-23 22:37:14 -05002850static void
Daniel Stone37816df2012-05-16 18:45:18 +01002851pointer_handle_axis(void *data, struct wl_pointer *pointer,
Daniel Stone2fce4022012-05-30 16:32:00 +01002852 uint32_t time, uint32_t axis, wl_fixed_t value)
Scott Moreau210d0792012-03-22 10:47:01 -06002853{
Philipp Brüschweiler7e0cc542012-08-14 11:02:41 +02002854 struct input *input = data;
2855 struct widget *widget;
2856
2857 widget = input->focus_widget;
2858 if (input->grab)
2859 widget = input->grab;
2860 if (widget && widget->axis_handler)
2861 (*widget->axis_handler)(widget,
2862 input, time,
2863 axis, value,
2864 widget->user_data);
Scott Moreau210d0792012-03-22 10:47:01 -06002865}
2866
Kristian Høgsbergb29798b2012-08-11 14:56:08 -04002867static const struct wl_pointer_listener pointer_listener = {
2868 pointer_handle_enter,
2869 pointer_handle_leave,
2870 pointer_handle_motion,
2871 pointer_handle_button,
2872 pointer_handle_axis,
2873};
2874
2875static void
2876input_remove_keyboard_focus(struct input *input)
2877{
2878 struct window *window = input->keyboard_focus;
2879 struct itimerspec its;
2880
2881 its.it_interval.tv_sec = 0;
2882 its.it_interval.tv_nsec = 0;
2883 its.it_value.tv_sec = 0;
2884 its.it_value.tv_nsec = 0;
2885 timerfd_settime(input->repeat_timer_fd, 0, &its, NULL);
2886
2887 if (!window)
2888 return;
2889
Kristian Høgsberg86adef92012-08-13 22:25:53 -04002890 window->focus_count--;
Kristian Høgsbergb29798b2012-08-11 14:56:08 -04002891 if (window->keyboard_focus_handler)
2892 (*window->keyboard_focus_handler)(window, NULL,
2893 window->user_data);
2894
2895 input->keyboard_focus = NULL;
2896}
2897
2898static void
2899keyboard_repeat_func(struct task *task, uint32_t events)
2900{
2901 struct input *input =
2902 container_of(task, struct input, repeat_task);
2903 struct window *window = input->keyboard_focus;
2904 uint64_t exp;
2905
2906 if (read(input->repeat_timer_fd, &exp, sizeof exp) != sizeof exp)
2907 /* If we change the timer between the fd becoming
2908 * readable and getting here, there'll be nothing to
2909 * read and we get EAGAIN. */
2910 return;
2911
2912 if (window && window->key_handler) {
2913 (*window->key_handler)(window, input, input->repeat_time,
2914 input->repeat_key, input->repeat_sym,
2915 WL_KEYBOARD_KEY_STATE_PRESSED,
2916 window->user_data);
2917 }
2918}
2919
2920static void
2921keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
2922 uint32_t format, int fd, uint32_t size)
2923{
2924 struct input *input = data;
2925 char *map_str;
2926
2927 if (!data) {
2928 close(fd);
2929 return;
2930 }
2931
2932 if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
2933 close(fd);
2934 return;
2935 }
2936
2937 map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
2938 if (map_str == MAP_FAILED) {
2939 close(fd);
2940 return;
2941 }
2942
2943 input->xkb.keymap = xkb_map_new_from_string(input->display->xkb_context,
2944 map_str,
2945 XKB_KEYMAP_FORMAT_TEXT_V1,
2946 0);
2947 munmap(map_str, size);
2948 close(fd);
2949
2950 if (!input->xkb.keymap) {
2951 fprintf(stderr, "failed to compile keymap\n");
2952 return;
2953 }
2954
2955 input->xkb.state = xkb_state_new(input->xkb.keymap);
2956 if (!input->xkb.state) {
2957 fprintf(stderr, "failed to create XKB state\n");
2958 xkb_map_unref(input->xkb.keymap);
2959 input->xkb.keymap = NULL;
2960 return;
2961 }
2962
2963 input->xkb.control_mask =
2964 1 << xkb_map_mod_get_index(input->xkb.keymap, "Control");
2965 input->xkb.alt_mask =
2966 1 << xkb_map_mod_get_index(input->xkb.keymap, "Mod1");
2967 input->xkb.shift_mask =
2968 1 << xkb_map_mod_get_index(input->xkb.keymap, "Shift");
2969}
2970
2971static void
2972keyboard_handle_enter(void *data, struct wl_keyboard *keyboard,
2973 uint32_t serial, struct wl_surface *surface,
2974 struct wl_array *keys)
2975{
2976 struct input *input = data;
2977 struct window *window;
2978
2979 input->display->serial = serial;
2980 input->keyboard_focus = wl_surface_get_user_data(surface);
2981
2982 window = input->keyboard_focus;
Kristian Høgsberg86adef92012-08-13 22:25:53 -04002983 window->focus_count++;
Kristian Høgsbergb29798b2012-08-11 14:56:08 -04002984 if (window->keyboard_focus_handler)
2985 (*window->keyboard_focus_handler)(window,
Kristian Høgsberg86adef92012-08-13 22:25:53 -04002986 input, window->user_data);
Kristian Høgsbergb29798b2012-08-11 14:56:08 -04002987}
2988
2989static void
2990keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
2991 uint32_t serial, struct wl_surface *surface)
2992{
2993 struct input *input = data;
2994
2995 input->display->serial = serial;
2996 input_remove_keyboard_focus(input);
2997}
2998
Scott Moreau210d0792012-03-22 10:47:01 -06002999static void
Daniel Stone37816df2012-05-16 18:45:18 +01003000keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
Daniel Stonec9785ea2012-05-30 16:31:52 +01003001 uint32_t serial, uint32_t time, uint32_t key,
3002 uint32_t state_w)
Kristian Høgsberg99f090d2009-02-23 22:37:14 -05003003{
Kristian Høgsberg808fd412010-07-20 17:06:19 -04003004 struct input *input = data;
3005 struct window *window = input->keyboard_focus;
Kristian Høgsberg70163132012-05-08 15:55:39 -04003006 uint32_t code, num_syms;
Daniel Stonec9785ea2012-05-30 16:31:52 +01003007 enum wl_keyboard_key_state state = state_w;
Kristian Høgsberg70163132012-05-08 15:55:39 -04003008 const xkb_keysym_t *syms;
3009 xkb_keysym_t sym;
Kristian Høgsbergcf4d2442012-06-20 14:52:12 -04003010 struct itimerspec its;
Kristian Høgsberg99f090d2009-02-23 22:37:14 -05003011
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04003012 input->display->serial = serial;
Daniel Stone0d5a5092012-02-16 12:48:00 +00003013 code = key + 8;
Kristian Høgsberg86adef92012-08-13 22:25:53 -04003014 if (!window || !input->xkb.state)
Kristian Høgsberg99f090d2009-02-23 22:37:14 -05003015 return;
3016
Daniel Stone97f68542012-05-30 16:32:01 +01003017 num_syms = xkb_key_get_syms(input->xkb.state, code, &syms);
Kristian Høgsberg99f090d2009-02-23 22:37:14 -05003018
Kristian Høgsbergcf4d2442012-06-20 14:52:12 -04003019 sym = XKB_KEY_NoSymbol;
3020 if (num_syms == 1)
3021 sym = syms[0];
3022
3023 if (sym == XKB_KEY_F5 && input->modifiers == MOD_ALT_MASK) {
Daniel Stonec9785ea2012-05-30 16:31:52 +01003024 if (state == WL_KEYBOARD_KEY_STATE_PRESSED)
Kristian Høgsbergd6bcd7d2012-02-16 15:53:46 -05003025 window_set_maximized(window,
3026 window->type != TYPE_MAXIMIZED);
Kristian Høgsberg67ace202012-07-23 21:56:31 -04003027 } else if (sym == XKB_KEY_F11 &&
3028 window->fullscreen_handler &&
3029 state == WL_KEYBOARD_KEY_STATE_PRESSED) {
3030 window->fullscreen_handler(window, window->user_data);
Kristian Høgsberg4fc15352012-07-25 16:35:28 -04003031 } else if (sym == XKB_KEY_F4 &&
3032 input->modifiers == MOD_ALT_MASK &&
3033 state == WL_KEYBOARD_KEY_STATE_PRESSED) {
3034 if (window->close_handler)
3035 window->close_handler(window->parent,
3036 window->user_data);
3037 else
3038 display_exit(window->display);
Kristian Høgsbergd6bcd7d2012-02-16 15:53:46 -05003039 } else if (window->key_handler) {
3040 (*window->key_handler)(window, input, time, key,
3041 sym, state, window->user_data);
3042 }
Kristian Høgsbergcf4d2442012-06-20 14:52:12 -04003043
3044 if (state == WL_KEYBOARD_KEY_STATE_RELEASED &&
3045 key == input->repeat_key) {
3046 its.it_interval.tv_sec = 0;
3047 its.it_interval.tv_nsec = 0;
3048 its.it_value.tv_sec = 0;
3049 its.it_value.tv_nsec = 0;
3050 timerfd_settime(input->repeat_timer_fd, 0, &its, NULL);
3051 } else if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
3052 input->repeat_sym = sym;
3053 input->repeat_key = key;
3054 input->repeat_time = time;
3055 its.it_interval.tv_sec = 0;
3056 its.it_interval.tv_nsec = 25 * 1000 * 1000;
3057 its.it_value.tv_sec = 0;
3058 its.it_value.tv_nsec = 400 * 1000 * 1000;
3059 timerfd_settime(input->repeat_timer_fd, 0, &its, NULL);
3060 }
3061}
3062
3063static void
Daniel Stone351eb612012-05-31 15:27:47 -04003064keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard,
3065 uint32_t serial, uint32_t mods_depressed,
3066 uint32_t mods_latched, uint32_t mods_locked,
3067 uint32_t group)
3068{
3069 struct input *input = data;
Jonas Ådahld9f6b072012-09-27 18:40:45 +02003070 xkb_mod_mask_t mask;
Daniel Stone351eb612012-05-31 15:27:47 -04003071
Daniel Stoneb7452fe2012-06-01 12:14:06 +01003072 xkb_state_update_mask(input->xkb.state, mods_depressed, mods_latched,
3073 mods_locked, 0, 0, group);
Jonas Ådahld9f6b072012-09-27 18:40:45 +02003074 mask = xkb_state_serialize_mods(input->xkb.state,
3075 XKB_STATE_DEPRESSED |
3076 XKB_STATE_LATCHED);
3077 input->modifiers = 0;
3078 if (mask & input->xkb.control_mask)
3079 input->modifiers |= MOD_CONTROL_MASK;
3080 if (mask & input->xkb.alt_mask)
3081 input->modifiers |= MOD_ALT_MASK;
3082 if (mask & input->xkb.shift_mask)
3083 input->modifiers |= MOD_SHIFT_MASK;
Daniel Stone351eb612012-05-31 15:27:47 -04003084}
3085
Daniel Stone37816df2012-05-16 18:45:18 +01003086static const struct wl_keyboard_listener keyboard_listener = {
Daniel Stoneb7452fe2012-06-01 12:14:06 +01003087 keyboard_handle_keymap,
Daniel Stone37816df2012-05-16 18:45:18 +01003088 keyboard_handle_enter,
3089 keyboard_handle_leave,
3090 keyboard_handle_key,
Daniel Stone351eb612012-05-31 15:27:47 -04003091 keyboard_handle_modifiers,
Daniel Stone37816df2012-05-16 18:45:18 +01003092};
Kristian Høgsberge04ad572011-12-21 17:14:54 -05003093
3094static void
Daniel Stone37816df2012-05-16 18:45:18 +01003095seat_handle_capabilities(void *data, struct wl_seat *seat,
3096 enum wl_seat_capability caps)
Kristian Høgsberge04ad572011-12-21 17:14:54 -05003097{
Daniel Stone37816df2012-05-16 18:45:18 +01003098 struct input *input = data;
3099
3100 if ((caps & WL_SEAT_CAPABILITY_POINTER) && !input->pointer) {
3101 input->pointer = wl_seat_get_pointer(seat);
3102 wl_pointer_set_user_data(input->pointer, input);
3103 wl_pointer_add_listener(input->pointer, &pointer_listener,
3104 input);
3105 } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && input->pointer) {
3106 wl_pointer_destroy(input->pointer);
3107 input->pointer = NULL;
3108 }
3109
3110 if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !input->keyboard) {
3111 input->keyboard = wl_seat_get_keyboard(seat);
3112 wl_keyboard_set_user_data(input->keyboard, input);
3113 wl_keyboard_add_listener(input->keyboard, &keyboard_listener,
3114 input);
3115 } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && input->keyboard) {
3116 wl_keyboard_destroy(input->keyboard);
3117 input->keyboard = NULL;
3118 }
Kristian Høgsberge04ad572011-12-21 17:14:54 -05003119}
3120
Daniel Stone37816df2012-05-16 18:45:18 +01003121static const struct wl_seat_listener seat_listener = {
3122 seat_handle_capabilities,
Kristian Høgsberg94448c02008-12-30 11:03:33 -05003123};
3124
Kristian Høgsberg9a686242010-08-18 15:28:04 -04003125void
3126input_get_position(struct input *input, int32_t *x, int32_t *y)
3127{
3128 *x = input->sx;
3129 *y = input->sy;
3130}
3131
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04003132struct display *
3133input_get_display(struct input *input)
3134{
3135 return input->display;
3136}
3137
Daniel Stone37816df2012-05-16 18:45:18 +01003138struct wl_seat *
3139input_get_seat(struct input *input)
Kristian Høgsberg1d7ffd32010-08-25 16:34:05 -04003140{
Daniel Stone37816df2012-05-16 18:45:18 +01003141 return input->seat;
Kristian Høgsberg1d7ffd32010-08-25 16:34:05 -04003142}
3143
Kristian Høgsberg67cac8a2011-01-19 14:20:33 -05003144uint32_t
3145input_get_modifiers(struct input *input)
3146{
3147 return input->modifiers;
3148}
3149
Kristian Høgsbergb6323512012-01-11 00:04:42 -05003150struct widget *
3151input_get_focus_widget(struct input *input)
3152{
3153 return input->focus_widget;
3154}
3155
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04003156struct data_offer {
3157 struct wl_data_offer *offer;
3158 struct input *input;
3159 struct wl_array types;
3160 int refcount;
Kristian Høgsberg9a686242010-08-18 15:28:04 -04003161
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04003162 struct task io_task;
3163 int fd;
3164 data_func_t func;
3165 int32_t x, y;
3166 void *user_data;
3167};
3168
3169static void
3170data_offer_offer(void *data, struct wl_data_offer *wl_data_offer, const char *type)
3171{
3172 struct data_offer *offer = data;
3173 char **p;
3174
3175 p = wl_array_add(&offer->types, sizeof *p);
3176 *p = strdup(type);
3177}
3178
3179static const struct wl_data_offer_listener data_offer_listener = {
3180 data_offer_offer,
3181};
3182
3183static void
3184data_offer_destroy(struct data_offer *offer)
3185{
3186 char **p;
3187
3188 offer->refcount--;
3189 if (offer->refcount == 0) {
3190 wl_data_offer_destroy(offer->offer);
3191 for (p = offer->types.data; *p; p++)
3192 free(*p);
3193 wl_array_release(&offer->types);
3194 free(offer);
3195 }
3196}
3197
3198static void
3199data_device_data_offer(void *data,
Kristian Høgsberg8733b332012-06-28 22:04:06 -04003200 struct wl_data_device *data_device,
3201 struct wl_data_offer *_offer)
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04003202{
3203 struct data_offer *offer;
3204
3205 offer = malloc(sizeof *offer);
3206
3207 wl_array_init(&offer->types);
3208 offer->refcount = 1;
3209 offer->input = data;
Kristian Høgsberg8733b332012-06-28 22:04:06 -04003210 offer->offer = _offer;
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04003211 wl_data_offer_add_listener(offer->offer,
3212 &data_offer_listener, offer);
3213}
3214
3215static void
3216data_device_enter(void *data, struct wl_data_device *data_device,
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04003217 uint32_t serial, struct wl_surface *surface,
Daniel Stone103db7f2012-05-08 17:17:55 +01003218 wl_fixed_t x_w, wl_fixed_t y_w,
3219 struct wl_data_offer *offer)
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04003220{
3221 struct input *input = data;
3222 struct window *window;
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +03003223 void *types_data;
Kristian Høgsberg80680c72012-05-10 12:21:37 -04003224 float x = wl_fixed_to_double(x_w);
3225 float y = wl_fixed_to_double(y_w);
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04003226 char **p;
3227
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04003228 input->pointer_enter_serial = serial;
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04003229 window = wl_surface_get_user_data(surface);
3230 input->pointer_focus = window;
3231
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +03003232 if (offer) {
3233 input->drag_offer = wl_data_offer_get_user_data(offer);
3234
3235 p = wl_array_add(&input->drag_offer->types, sizeof *p);
3236 *p = NULL;
3237
3238 types_data = input->drag_offer->types.data;
3239 } else {
3240 input->drag_offer = NULL;
3241 types_data = NULL;
3242 }
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04003243
3244 window = input->pointer_focus;
3245 if (window->data_handler)
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +03003246 window->data_handler(window, input, x, y, types_data,
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04003247 window->user_data);
3248}
3249
3250static void
3251data_device_leave(void *data, struct wl_data_device *data_device)
3252{
3253 struct input *input = data;
3254
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +03003255 if (input->drag_offer) {
3256 data_offer_destroy(input->drag_offer);
3257 input->drag_offer = NULL;
3258 }
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04003259}
3260
3261static void
3262data_device_motion(void *data, struct wl_data_device *data_device,
Daniel Stone103db7f2012-05-08 17:17:55 +01003263 uint32_t time, wl_fixed_t x_w, wl_fixed_t y_w)
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04003264{
3265 struct input *input = data;
3266 struct window *window = input->pointer_focus;
Kristian Høgsberg80680c72012-05-10 12:21:37 -04003267 float x = wl_fixed_to_double(x_w);
3268 float y = wl_fixed_to_double(y_w);
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +03003269 void *types_data;
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04003270
3271 input->sx = x;
3272 input->sy = y;
3273
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +03003274 if (input->drag_offer)
3275 types_data = input->drag_offer->types.data;
3276 else
3277 types_data = NULL;
3278
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04003279 if (window->data_handler)
Ander Conselvan de Oliveira08bcf142012-05-29 10:58:27 +03003280 window->data_handler(window, input, x, y, types_data,
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04003281 window->user_data);
3282}
3283
3284static void
3285data_device_drop(void *data, struct wl_data_device *data_device)
3286{
3287 struct input *input = data;
3288 struct window *window = input->pointer_focus;
3289
3290 if (window->drop_handler)
3291 window->drop_handler(window, input,
3292 input->sx, input->sy, window->user_data);
3293}
3294
3295static void
3296data_device_selection(void *data,
3297 struct wl_data_device *wl_data_device,
3298 struct wl_data_offer *offer)
3299{
3300 struct input *input = data;
3301 char **p;
3302
3303 if (input->selection_offer)
3304 data_offer_destroy(input->selection_offer);
3305
Kristian Høgsberg42c8f602012-01-27 11:04:18 -05003306 if (offer) {
3307 input->selection_offer = wl_data_offer_get_user_data(offer);
3308 p = wl_array_add(&input->selection_offer->types, sizeof *p);
3309 *p = NULL;
Kristian Høgsberga4b3d0e2012-05-31 23:30:32 -04003310 } else {
3311 input->selection_offer = NULL;
Kristian Høgsberg42c8f602012-01-27 11:04:18 -05003312 }
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04003313}
3314
3315static const struct wl_data_device_listener data_device_listener = {
3316 data_device_data_offer,
3317 data_device_enter,
3318 data_device_leave,
3319 data_device_motion,
3320 data_device_drop,
3321 data_device_selection
3322};
3323
Ander Conselvan de Oliveira80620072012-06-15 17:27:36 +03003324static void
3325input_set_pointer_image_index(struct input *input, int index)
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05003326{
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05003327 struct wl_buffer *buffer;
Ander Conselvan de Oliveira1042dc12012-05-22 15:39:42 +03003328 struct wl_cursor *cursor;
3329 struct wl_cursor_image *image;
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05003330
Daniel Stone80972742012-11-07 17:51:39 +11003331 if (!input->pointer)
3332 return;
3333
Ander Conselvan de Oliveira80620072012-06-15 17:27:36 +03003334 cursor = input->display->cursors[input->current_cursor];
Ander Conselvan de Oliveira1042dc12012-05-22 15:39:42 +03003335 if (!cursor)
Dima Ryazanovff1c2d72012-05-08 21:02:33 -07003336 return;
3337
Kristian Høgsberg7cee1972012-06-04 23:37:42 -04003338 if (index >= (int) cursor->image_count) {
3339 fprintf(stderr, "cursor index out of range\n");
3340 return;
3341 }
3342
3343 image = cursor->images[index];
Ander Conselvan de Oliveira1042dc12012-05-22 15:39:42 +03003344 buffer = wl_cursor_image_get_buffer(image);
3345 if (!buffer)
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05003346 return;
3347
Kristian Høgsbergae277372012-08-01 09:41:08 -04003348 wl_pointer_set_cursor(input->pointer, input->pointer_enter_serial,
Ander Conselvan de Oliveira37ffc3c2012-06-15 17:27:35 +03003349 input->pointer_surface,
3350 image->hotspot_x, image->hotspot_y);
3351 wl_surface_attach(input->pointer_surface, buffer, 0, 0);
3352 wl_surface_damage(input->pointer_surface, 0, 0,
3353 image->width, image->height);
Pekka Paalanenc9e00c02012-10-10 12:49:24 +03003354 wl_surface_commit(input->pointer_surface);
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05003355}
3356
Ander Conselvan de Oliveira80620072012-06-15 17:27:36 +03003357static const struct wl_callback_listener pointer_surface_listener;
3358
3359static void
3360pointer_surface_frame_callback(void *data, struct wl_callback *callback,
3361 uint32_t time)
3362{
3363 struct input *input = data;
Daniel Stonea494f1d2012-06-18 19:31:12 +01003364 struct wl_cursor *cursor;
Ander Conselvan de Oliveira80620072012-06-15 17:27:36 +03003365 int i;
3366
3367 if (callback) {
3368 assert(callback == input->cursor_frame_cb);
3369 wl_callback_destroy(callback);
3370 input->cursor_frame_cb = NULL;
3371 }
3372
Daniel Stone80972742012-11-07 17:51:39 +11003373 if (!input->pointer)
3374 return;
3375
Kristian Høgsbergf3370522012-06-20 23:04:41 -04003376 if (input->current_cursor == CURSOR_BLANK) {
Kristian Høgsbergae277372012-08-01 09:41:08 -04003377 wl_pointer_set_cursor(input->pointer,
3378 input->pointer_enter_serial,
Kristian Høgsbergf3370522012-06-20 23:04:41 -04003379 NULL, 0, 0);
3380 return;
3381 }
3382
Ander Conselvan de Oliveira80620072012-06-15 17:27:36 +03003383 if (input->current_cursor == CURSOR_UNSET)
3384 return;
Daniel Stonea494f1d2012-06-18 19:31:12 +01003385 cursor = input->display->cursors[input->current_cursor];
3386 if (!cursor)
3387 return;
Ander Conselvan de Oliveira80620072012-06-15 17:27:36 +03003388
3389 /* FIXME We don't have the current time on the first call so we set
3390 * the animation start to the time of the first frame callback. */
3391 if (time == 0)
3392 input->cursor_anim_start = 0;
3393 else if (input->cursor_anim_start == 0)
3394 input->cursor_anim_start = time;
3395
3396 if (time == 0 || input->cursor_anim_start == 0)
3397 i = 0;
3398 else
3399 i = wl_cursor_frame(cursor, time - input->cursor_anim_start);
3400
Pekka Paalanenbc106382012-10-10 12:49:31 +03003401 if (cursor->image_count > 1) {
3402 input->cursor_frame_cb =
3403 wl_surface_frame(input->pointer_surface);
3404 wl_callback_add_listener(input->cursor_frame_cb,
3405 &pointer_surface_listener, input);
3406 }
3407
Ander Conselvan de Oliveira80620072012-06-15 17:27:36 +03003408 input_set_pointer_image_index(input, i);
Ander Conselvan de Oliveira80620072012-06-15 17:27:36 +03003409}
3410
3411static const struct wl_callback_listener pointer_surface_listener = {
3412 pointer_surface_frame_callback
3413};
3414
Kristian Høgsberg7cee1972012-06-04 23:37:42 -04003415void
3416input_set_pointer_image(struct input *input, int pointer)
3417{
Ander Conselvan de Oliveiraddca4962012-07-16 14:15:49 +03003418 int force = 0;
3419
Kristian Høgsberge530a0a2012-10-29 16:42:26 -04003420 if (!input->pointer)
3421 return;
3422
Ander Conselvan de Oliveiraddca4962012-07-16 14:15:49 +03003423 if (input->pointer_enter_serial > input->cursor_serial)
3424 force = 1;
3425
3426 if (!force && pointer == input->current_cursor)
Kristian Høgsberg7cee1972012-06-04 23:37:42 -04003427 return;
3428
Ander Conselvan de Oliveira80620072012-06-15 17:27:36 +03003429 input->current_cursor = pointer;
Kristian Høgsberg11f600d2012-06-22 10:52:58 -04003430 input->cursor_serial = input->pointer_enter_serial;
Ander Conselvan de Oliveira80620072012-06-15 17:27:36 +03003431 if (!input->cursor_frame_cb)
3432 pointer_surface_frame_callback(input, NULL, 0);
Ander Conselvan de Oliveiraddca4962012-07-16 14:15:49 +03003433 else if (force) {
3434 /* The current frame callback may be stuck if, for instance,
3435 * the set cursor request was processed by the server after
3436 * this client lost the focus. In this case the cursor surface
3437 * might not be mapped and the frame callback wouldn't ever
3438 * complete. Send a set_cursor and attach to try to map the
3439 * cursor surface again so that the callback will finish */
3440 input_set_pointer_image_index(input, 0);
3441 }
Kristian Høgsberg7cee1972012-06-04 23:37:42 -04003442}
3443
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04003444struct wl_data_device *
3445input_get_data_device(struct input *input)
3446{
3447 return input->data_device;
3448}
3449
3450void
3451input_set_selection(struct input *input,
3452 struct wl_data_source *source, uint32_t time)
3453{
3454 wl_data_device_set_selection(input->data_device, source, time);
3455}
3456
3457void
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04003458input_accept(struct input *input, const char *type)
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04003459{
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04003460 wl_data_offer_accept(input->drag_offer->offer,
3461 input->pointer_enter_serial, type);
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04003462}
3463
3464static void
3465offer_io_func(struct task *task, uint32_t events)
3466{
3467 struct data_offer *offer =
3468 container_of(task, struct data_offer, io_task);
3469 unsigned int len;
3470 char buffer[4096];
3471
3472 len = read(offer->fd, buffer, sizeof buffer);
3473 offer->func(buffer, len,
3474 offer->x, offer->y, offer->user_data);
3475
3476 if (len == 0) {
3477 close(offer->fd);
3478 data_offer_destroy(offer);
3479 }
3480}
3481
3482static void
3483data_offer_receive_data(struct data_offer *offer, const char *mime_type,
3484 data_func_t func, void *user_data)
3485{
3486 int p[2];
3487
Jonas Ådahl3685c3a2012-03-30 23:10:27 +02003488 if (pipe2(p, O_CLOEXEC) == -1)
3489 return;
3490
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04003491 wl_data_offer_receive(offer->offer, mime_type, p[1]);
3492 close(p[1]);
3493
3494 offer->io_task.run = offer_io_func;
3495 offer->fd = p[0];
3496 offer->func = func;
3497 offer->refcount++;
3498 offer->user_data = user_data;
3499
3500 display_watch_fd(offer->input->display,
3501 offer->fd, EPOLLIN, &offer->io_task);
3502}
3503
3504void
3505input_receive_drag_data(struct input *input, const char *mime_type,
3506 data_func_t func, void *data)
3507{
3508 data_offer_receive_data(input->drag_offer, mime_type, func, data);
3509 input->drag_offer->x = input->sx;
3510 input->drag_offer->y = input->sy;
3511}
3512
3513int
3514input_receive_selection_data(struct input *input, const char *mime_type,
3515 data_func_t func, void *data)
3516{
3517 char **p;
3518
3519 if (input->selection_offer == NULL)
3520 return -1;
3521
3522 for (p = input->selection_offer->types.data; *p; p++)
3523 if (strcmp(mime_type, *p) == 0)
3524 break;
3525
3526 if (*p == NULL)
3527 return -1;
3528
3529 data_offer_receive_data(input->selection_offer,
3530 mime_type, func, data);
3531 return 0;
Kristian Høgsberg41da9082010-11-30 14:01:07 -05003532}
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -04003533
Kristian Høgsberge7aaec32011-12-27 13:50:04 -05003534int
3535input_receive_selection_data_to_fd(struct input *input,
3536 const char *mime_type, int fd)
3537{
Kristian Høgsberga4b3d0e2012-05-31 23:30:32 -04003538 if (input->selection_offer)
3539 wl_data_offer_receive(input->selection_offer->offer,
3540 mime_type, fd);
Kristian Høgsberge7aaec32011-12-27 13:50:04 -05003541
3542 return 0;
3543}
3544
Kristian Høgsberg41da9082010-11-30 14:01:07 -05003545void
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04003546window_move(struct window *window, struct input *input, uint32_t serial)
Kristian Høgsberg82da52b2010-12-17 09:53:12 -05003547{
Pekka Paalanen6b2dc912011-11-29 10:25:08 +02003548 if (!window->shell_surface)
3549 return;
3550
Daniel Stone37816df2012-05-16 18:45:18 +01003551 wl_shell_surface_move(window->shell_surface, input->seat, serial);
Kristian Høgsberg82da52b2010-12-17 09:53:12 -05003552}
3553
Kristian Høgsberg83fc0612010-08-04 22:44:55 -04003554static void
Pekka Paalanen35e82632013-04-25 13:57:48 +03003555surface_set_synchronized(struct surface *surface)
3556{
3557 if (!surface->subsurface)
3558 return;
3559
3560 if (surface->synchronized)
3561 return;
3562
3563 wl_subsurface_set_sync(surface->subsurface);
3564 surface->synchronized = 1;
3565}
3566
3567static void
3568surface_set_synchronized_default(struct surface *surface)
3569{
3570 if (!surface->subsurface)
3571 return;
3572
3573 if (surface->synchronized == surface->synchronized_default)
3574 return;
3575
3576 if (surface->synchronized_default)
3577 wl_subsurface_set_sync(surface->subsurface);
3578 else
3579 wl_subsurface_set_desync(surface->subsurface);
3580
3581 surface->synchronized = surface->synchronized_default;
3582}
3583
3584static void
Pekka Paalanenb1cd9b12013-02-13 16:17:18 +02003585surface_resize(struct surface *surface)
Pekka Paalanen811ec4f2013-02-13 16:17:14 +02003586{
Pekka Paalanenb1cd9b12013-02-13 16:17:18 +02003587 struct widget *widget = surface->widget;
3588 struct wl_compositor *compositor = widget->window->display->compositor;
Pekka Paalanen811ec4f2013-02-13 16:17:14 +02003589
Pekka Paalanenb1cd9b12013-02-13 16:17:18 +02003590 if (surface->input_region) {
3591 wl_region_destroy(surface->input_region);
3592 surface->input_region = NULL;
Kristian Høgsberg010f98b2012-02-23 17:30:45 -05003593 }
3594
Pekka Paalanenb1cd9b12013-02-13 16:17:18 +02003595 if (surface->opaque_region)
3596 wl_region_destroy(surface->opaque_region);
Ander Conselvan de Oliveiraddd3e272012-11-30 17:34:23 +02003597
Pekka Paalanenb1cd9b12013-02-13 16:17:18 +02003598 surface->opaque_region = wl_compositor_create_region(compositor);
Kristian Høgsberg010f98b2012-02-23 17:30:45 -05003599
Kristian Høgsbergbb977002012-01-10 19:11:42 -05003600 if (widget->resize_handler)
3601 widget->resize_handler(widget,
Kristian Høgsberg0d1c0622012-01-31 15:30:47 -05003602 widget->allocation.width,
3603 widget->allocation.height,
Kristian Høgsbergbb977002012-01-10 19:11:42 -05003604 widget->user_data);
3605
Pekka Paalanen35e82632013-04-25 13:57:48 +03003606 if (surface->subsurface &&
3607 (surface->allocation.x != widget->allocation.x ||
3608 surface->allocation.y != widget->allocation.y)) {
3609 wl_subsurface_set_position(surface->subsurface,
3610 widget->allocation.x,
3611 widget->allocation.y);
3612 }
Pekka Paalanenb1cd9b12013-02-13 16:17:18 +02003613 if (surface->allocation.width != widget->allocation.width ||
3614 surface->allocation.height != widget->allocation.height) {
Pekka Paalanenb1cd9b12013-02-13 16:17:18 +02003615 window_schedule_redraw(widget->window);
3616 }
Pekka Paalanen35e82632013-04-25 13:57:48 +03003617 surface->allocation = widget->allocation;
Ander Conselvan de Oliveiraddd3e272012-11-30 17:34:23 +02003618
3619 if (widget->opaque)
Pekka Paalanenb1cd9b12013-02-13 16:17:18 +02003620 wl_region_add(surface->opaque_region, 0, 0,
Ander Conselvan de Oliveiraddd3e272012-11-30 17:34:23 +02003621 widget->allocation.width,
3622 widget->allocation.height);
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -05003623}
3624
Pekka Paalanenb1cd9b12013-02-13 16:17:18 +02003625static void
Pekka Paalanene9297f82013-04-25 13:57:51 +03003626hack_prevent_EGL_sub_surface_deadlock(struct window *window)
3627{
3628 /*
3629 * This hack should be removed, when EGL respects
3630 * eglSwapInterval(0).
3631 *
3632 * If this window has sub-surfaces, especially a free-running
3633 * EGL-widget, we need to post the parent surface once with
3634 * all the old state to guarantee, that the EGL-widget will
3635 * receive its frame callback soon. Otherwise, a forced call
3636 * to eglSwapBuffers may end up blocking, waiting for a frame
3637 * event that will never come, because we will commit the parent
3638 * surface with all new state only after eglSwapBuffers returns.
3639 *
3640 * This assumes, that:
3641 * 1. When the EGL widget's resize hook is called, it pauses.
3642 * 2. When the EGL widget's redraw hook is called, it forces a
3643 * repaint and a call to eglSwapBuffers(), and maybe resumes.
3644 * In a single threaded application condition 1 is a no-op.
3645 *
3646 * XXX: This should actually be after the surface_resize() calls,
3647 * but cannot, because then it would commit the incomplete state
3648 * accumulated from the widget resize hooks.
3649 */
3650 if (window->subsurface_list.next != &window->main_surface->link ||
3651 window->subsurface_list.prev != &window->main_surface->link)
3652 wl_surface_commit(window->main_surface->surface);
3653}
3654
3655static void
Pekka Paalanenb1cd9b12013-02-13 16:17:18 +02003656idle_resize(struct window *window)
3657{
Pekka Paalanen35e82632013-04-25 13:57:48 +03003658 struct surface *surface;
3659
Pekka Paalanenb1cd9b12013-02-13 16:17:18 +02003660 window->resize_needed = 0;
Pekka Paalanen40cb67b2013-04-25 13:57:49 +03003661 window->redraw_needed = 1;
Pekka Paalanenb1cd9b12013-02-13 16:17:18 +02003662
Pekka Paalanen71233882013-04-25 13:57:53 +03003663 DBG("from %dx%d to %dx%d\n",
3664 window->main_surface->server_allocation.width,
3665 window->main_surface->server_allocation.height,
3666 window->pending_allocation.width,
3667 window->pending_allocation.height);
3668
Pekka Paalanene9297f82013-04-25 13:57:51 +03003669 hack_prevent_EGL_sub_surface_deadlock(window);
3670
Pekka Paalanenb1cd9b12013-02-13 16:17:18 +02003671 widget_set_allocation(window->main_surface->widget,
3672 window->pending_allocation.x,
3673 window->pending_allocation.y,
3674 window->pending_allocation.width,
3675 window->pending_allocation.height);
3676
3677 surface_resize(window->main_surface);
Pekka Paalanen35e82632013-04-25 13:57:48 +03003678
3679 /* The main surface is in the list, too. Main surface's
3680 * resize_handler is responsible for calling widget_set_allocation()
3681 * on all sub-surface root widgets, so they will be resized
3682 * properly.
3683 */
3684 wl_list_for_each(surface, &window->subsurface_list, link) {
3685 if (surface == window->main_surface)
3686 continue;
3687
3688 surface_set_synchronized(surface);
3689 surface_resize(surface);
3690 }
Pekka Paalanenb1cd9b12013-02-13 16:17:18 +02003691}
3692
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -05003693void
3694window_schedule_resize(struct window *window, int width, int height)
3695{
Kristian Høgsberg0d1c0622012-01-31 15:30:47 -05003696 window->pending_allocation.x = 0;
3697 window->pending_allocation.y = 0;
3698 window->pending_allocation.width = width;
3699 window->pending_allocation.height = height;
3700
Kristian Høgsbergd3a19652012-07-20 11:32:51 -04003701 if (window->min_allocation.width == 0)
3702 window->min_allocation = window->pending_allocation;
3703 if (window->pending_allocation.width < window->min_allocation.width)
3704 window->pending_allocation.width = window->min_allocation.width;
3705 if (window->pending_allocation.height < window->min_allocation.height)
3706 window->pending_allocation.height = window->min_allocation.height;
3707
Kristian Høgsberg42b4f802012-03-26 13:49:29 -04003708 window->resize_needed = 1;
3709 window_schedule_redraw(window);
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -05003710}
3711
Kristian Høgsbergbb977002012-01-10 19:11:42 -05003712void
3713widget_schedule_resize(struct widget *widget, int32_t width, int32_t height)
3714{
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05003715 window_schedule_resize(widget->window, width, height);
Kristian Høgsbergbb977002012-01-10 19:11:42 -05003716}
3717
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -05003718static void
Scott Moreauff1db4a2012-04-17 19:06:18 -06003719handle_ping(void *data, struct wl_shell_surface *shell_surface,
3720 uint32_t serial)
3721{
3722 wl_shell_surface_pong(shell_surface, serial);
3723}
3724
3725static void
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003726handle_configure(void *data, struct wl_shell_surface *shell_surface,
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04003727 uint32_t edges, int32_t width, int32_t height)
Kristian Høgsberg83fc0612010-08-04 22:44:55 -04003728{
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003729 struct window *window = data;
Kristian Høgsberg83fc0612010-08-04 22:44:55 -04003730
Tim Wiederhakeb6761dc2011-01-17 17:50:07 +01003731 window->resize_edges = edges;
Kristian Høgsberg0d1c0622012-01-31 15:30:47 -05003732 window_schedule_resize(window, width, height);
Kristian Høgsberg83fc0612010-08-04 22:44:55 -04003733}
3734
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05003735static void
Pekka Paalanen6d174cf2012-01-19 15:17:59 +02003736menu_destroy(struct menu *menu)
3737{
3738 widget_destroy(menu->widget);
3739 window_destroy(menu->window);
3740 free(menu);
3741}
3742
3743static void
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05003744handle_popup_done(void *data, struct wl_shell_surface *shell_surface)
3745{
3746 struct window *window = data;
Pekka Paalanenac95f3e2013-02-13 16:17:17 +02003747 struct menu *menu = window->main_surface->widget->user_data;
Kristian Høgsberg831dd522012-01-10 23:46:33 -05003748
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05003749 /* FIXME: Need more context in this event, at least the input
Kristian Høgsberg831dd522012-01-10 23:46:33 -05003750 * device. Or just use wl_callback. And this really needs to
3751 * be a window vfunc that the menu can set. And we need the
3752 * time. */
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05003753
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04003754 input_ungrab(menu->input);
Pekka Paalanen6d174cf2012-01-19 15:17:59 +02003755 menu_destroy(menu);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05003756}
3757
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02003758static const struct wl_shell_surface_listener shell_surface_listener = {
Scott Moreauff1db4a2012-04-17 19:06:18 -06003759 handle_ping,
Kristian Høgsberg83fc0612010-08-04 22:44:55 -04003760 handle_configure,
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05003761 handle_popup_done
Kristian Høgsberg83fc0612010-08-04 22:44:55 -04003762};
3763
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -05003764void
Benjamin Franzkecff904e2011-02-18 23:00:55 +01003765window_get_allocation(struct window *window,
3766 struct rectangle *allocation)
3767{
Pekka Paalanen811ec4f2013-02-13 16:17:14 +02003768 *allocation = window->main_surface->allocation;
Benjamin Franzkecff904e2011-02-18 23:00:55 +01003769}
3770
Kristian Høgsberg3a696272011-09-14 17:33:48 -04003771static void
Kristian Høgsberg441338c2012-01-10 13:52:34 -05003772widget_redraw(struct widget *widget)
3773{
3774 struct widget *child;
3775
3776 if (widget->redraw_handler)
3777 widget->redraw_handler(widget, widget->user_data);
3778 wl_list_for_each(child, &widget->child_list, link)
3779 widget_redraw(child);
3780}
3781
3782static void
Kristian Høgsberg6bd4d972012-03-24 14:42:09 -04003783frame_callback(void *data, struct wl_callback *callback, uint32_t time)
3784{
Pekka Paalanen40cb67b2013-04-25 13:57:49 +03003785 struct surface *surface = data;
Kristian Høgsberg6bd4d972012-03-24 14:42:09 -04003786
Pekka Paalanen40cb67b2013-04-25 13:57:49 +03003787 assert(callback == surface->frame_cb);
Pekka Paalanen71233882013-04-25 13:57:53 +03003788 DBG_OBJ(callback, "done\n");
Kristian Høgsberg6bd4d972012-03-24 14:42:09 -04003789 wl_callback_destroy(callback);
Pekka Paalanen40cb67b2013-04-25 13:57:49 +03003790 surface->frame_cb = NULL;
3791
Pekka Paalanen7ff7a802013-04-25 13:57:50 +03003792 surface->last_time = time;
3793
Pekka Paalanen71233882013-04-25 13:57:53 +03003794 if (surface->redraw_needed || surface->window->redraw_needed) {
3795 DBG_OBJ(surface->surface, "window_schedule_redraw_task\n");
Pekka Paalanen40cb67b2013-04-25 13:57:49 +03003796 window_schedule_redraw_task(surface->window);
Pekka Paalanen71233882013-04-25 13:57:53 +03003797 }
Kristian Høgsberg6bd4d972012-03-24 14:42:09 -04003798}
3799
3800static const struct wl_callback_listener listener = {
3801 frame_callback
3802};
3803
3804static void
Pekka Paalanen40cb67b2013-04-25 13:57:49 +03003805surface_redraw(struct surface *surface)
3806{
Pekka Paalanen71233882013-04-25 13:57:53 +03003807 DBG_OBJ(surface->surface, "begin\n");
3808
Pekka Paalanen40cb67b2013-04-25 13:57:49 +03003809 if (!surface->window->redraw_needed && !surface->redraw_needed)
3810 return;
3811
3812 /* Whole-window redraw forces a redraw even if the previous has
3813 * not yet hit the screen.
3814 */
3815 if (surface->frame_cb) {
3816 if (!surface->window->redraw_needed)
3817 return;
3818
Pekka Paalanen71233882013-04-25 13:57:53 +03003819 DBG_OBJ(surface->frame_cb, "cancelled\n");
Pekka Paalanen40cb67b2013-04-25 13:57:49 +03003820 wl_callback_destroy(surface->frame_cb);
3821 }
3822
3823 surface->frame_cb = wl_surface_frame(surface->surface);
3824 wl_callback_add_listener(surface->frame_cb, &listener, surface);
Pekka Paalanen71233882013-04-25 13:57:53 +03003825 DBG_OBJ(surface->frame_cb, "new\n");
Pekka Paalanen40cb67b2013-04-25 13:57:49 +03003826
3827 surface->redraw_needed = 0;
Pekka Paalanen71233882013-04-25 13:57:53 +03003828 DBG_OBJ(surface->surface, "-> widget_redraw\n");
Pekka Paalanen40cb67b2013-04-25 13:57:49 +03003829 widget_redraw(surface->widget);
Pekka Paalanen71233882013-04-25 13:57:53 +03003830 DBG_OBJ(surface->surface, "done\n");
Pekka Paalanen40cb67b2013-04-25 13:57:49 +03003831}
3832
3833static void
Kristian Høgsberg3a696272011-09-14 17:33:48 -04003834idle_redraw(struct task *task, uint32_t events)
Kristian Høgsberg80d746f2010-06-14 23:52:50 -04003835{
Kristian Høgsberg42b4f802012-03-26 13:49:29 -04003836 struct window *window = container_of(task, struct window, redraw_task);
Pekka Paalanen35e82632013-04-25 13:57:48 +03003837 struct surface *surface;
Kristian Høgsberg80d746f2010-06-14 23:52:50 -04003838
Pekka Paalanen71233882013-04-25 13:57:53 +03003839 DBG(" --------- \n");
3840
Pekka Paalaneneebff542013-04-25 13:57:52 +03003841 wl_list_init(&window->redraw_task.link);
3842 window->redraw_task_scheduled = 0;
3843
3844 if (window->resize_needed) {
3845 /* throttle resizing to the main surface display */
Pekka Paalanen71233882013-04-25 13:57:53 +03003846 if (window->main_surface->frame_cb) {
3847 DBG_OBJ(window->main_surface->frame_cb, "pending\n");
Pekka Paalaneneebff542013-04-25 13:57:52 +03003848 return;
Pekka Paalanen71233882013-04-25 13:57:53 +03003849 }
Pekka Paalaneneebff542013-04-25 13:57:52 +03003850
Kristian Høgsberg42b4f802012-03-26 13:49:29 -04003851 idle_resize(window);
Pekka Paalaneneebff542013-04-25 13:57:52 +03003852 }
Kristian Høgsberg42b4f802012-03-26 13:49:29 -04003853
Pekka Paalanen35e82632013-04-25 13:57:48 +03003854 wl_list_for_each(surface, &window->subsurface_list, link)
Pekka Paalanen40cb67b2013-04-25 13:57:49 +03003855 surface_redraw(surface);
Pekka Paalanen35e82632013-04-25 13:57:48 +03003856
Kristian Høgsberg6bd4d972012-03-24 14:42:09 -04003857 window->redraw_needed = 0;
Pekka Paalanenbc106382012-10-10 12:49:31 +03003858 window_flush(window);
Pekka Paalanen35e82632013-04-25 13:57:48 +03003859
3860 wl_list_for_each(surface, &window->subsurface_list, link)
3861 surface_set_synchronized_default(surface);
Kristian Høgsberg80d746f2010-06-14 23:52:50 -04003862}
3863
Pekka Paalanen40cb67b2013-04-25 13:57:49 +03003864static void
3865window_schedule_redraw_task(struct window *window)
3866{
3867 if (window->configure_requests)
3868 return;
3869 if (!window->redraw_task_scheduled) {
3870 window->redraw_task.run = idle_redraw;
3871 display_defer(window->display, &window->redraw_task);
3872 window->redraw_task_scheduled = 1;
3873 }
3874}
3875
Kristian Høgsberg80d746f2010-06-14 23:52:50 -04003876void
3877window_schedule_redraw(struct window *window)
3878{
Pekka Paalanen40cb67b2013-04-25 13:57:49 +03003879 struct surface *surface;
3880
Pekka Paalanen71233882013-04-25 13:57:53 +03003881 DBG_OBJ(window->main_surface->surface, "window %p\n", window);
3882
Pekka Paalanen40cb67b2013-04-25 13:57:49 +03003883 wl_list_for_each(surface, &window->subsurface_list, link)
3884 surface->redraw_needed = 1;
3885
3886 window_schedule_redraw_task(window);
Kristian Høgsberg80d746f2010-06-14 23:52:50 -04003887}
3888
Kristian Høgsberg1671e112012-10-10 11:36:24 -04003889int
3890window_is_fullscreen(struct window *window)
3891{
3892 return window->type == TYPE_FULLSCREEN;
3893}
3894
MoD063a8822013-03-02 23:43:57 +00003895static void
3896configure_request_completed(void *data, struct wl_callback *callback, uint32_t time)
3897{
3898 struct window *window = data;
3899
3900 wl_callback_destroy(callback);
3901 window->configure_requests--;
3902
3903 if (!window->configure_requests)
3904 window_schedule_redraw(window);
3905}
3906
3907static struct wl_callback_listener configure_request_listener = {
3908 configure_request_completed,
3909};
3910
3911static void
3912window_defer_redraw_until_configure(struct window* window)
3913{
3914 struct wl_callback *callback;
3915
Pekka Paalanen40cb67b2013-04-25 13:57:49 +03003916 if (window->redraw_task_scheduled) {
MoD063a8822013-03-02 23:43:57 +00003917 wl_list_remove(&window->redraw_task.link);
Pekka Paalanen40cb67b2013-04-25 13:57:49 +03003918 window->redraw_task_scheduled = 0;
MoD063a8822013-03-02 23:43:57 +00003919 }
3920
3921 callback = wl_display_sync(window->display->display);
3922 wl_callback_add_listener(callback, &configure_request_listener, window);
3923 window->configure_requests++;
3924}
3925
Kristian Høgsberg0ac16f02009-01-15 11:37:43 -05003926void
Kristian Høgsberg0395f302008-12-22 12:14:50 -05003927window_set_fullscreen(struct window *window, int fullscreen)
3928{
Kristian Høgsberg1517def2012-02-16 22:56:12 -05003929 if (!window->display->shell)
3930 return;
Kristian Høgsberg0ce24572011-01-28 15:18:33 -05003931
Kristian Høgsberg547da5a2011-09-13 20:58:00 -04003932 if ((window->type == TYPE_FULLSCREEN) == fullscreen)
Kristian Høgsberg0ce24572011-01-28 15:18:33 -05003933 return;
3934
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -04003935 if (fullscreen) {
Rafal Mielniczukc1a3cd12013-03-11 19:26:56 +01003936 window->saved_type = window->type;
Rafal Mielniczukfc22be02013-03-11 19:26:55 +01003937 if (window->type == TYPE_TOPLEVEL) {
3938 window->saved_allocation = window->main_surface->allocation;
3939 }
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -04003940 window->type = TYPE_FULLSCREEN;
Kristian Høgsberg1517def2012-02-16 22:56:12 -05003941 wl_shell_surface_set_fullscreen(window->shell_surface,
Ander Conselvan de Oliveira5403f522012-12-14 13:37:23 -02003942 window->fullscreen_method,
Kristian Høgsberg1517def2012-02-16 22:56:12 -05003943 0, NULL);
MoD063a8822013-03-02 23:43:57 +00003944 window_defer_redraw_until_configure (window);
Kristian Høgsberg0395f302008-12-22 12:14:50 -05003945 } else {
Rafal Mielniczukc1a3cd12013-03-11 19:26:56 +01003946 if (window->saved_type == TYPE_MAXIMIZED) {
3947 window_set_maximized(window, 1);
3948 } else {
3949 window->type = TYPE_TOPLEVEL;
3950 wl_shell_surface_set_toplevel(window->shell_surface);
3951 window_schedule_resize(window,
3952 window->saved_allocation.width,
3953 window->saved_allocation.height);
3954 }
3955
Kristian Høgsberg0395f302008-12-22 12:14:50 -05003956 }
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -04003957}
3958
Ander Conselvan de Oliveira5403f522012-12-14 13:37:23 -02003959void
3960window_set_fullscreen_method(struct window *window,
3961 enum wl_shell_surface_fullscreen_method method)
3962{
3963 window->fullscreen_method = method;
3964}
3965
Kristian Høgsberg1671e112012-10-10 11:36:24 -04003966int
3967window_is_maximized(struct window *window)
3968{
3969 return window->type == TYPE_MAXIMIZED;
3970}
3971
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -04003972void
Kristian Høgsbergd6bcd7d2012-02-16 15:53:46 -05003973window_set_maximized(struct window *window, int maximized)
3974{
3975 if (!window->display->shell)
3976 return;
3977
3978 if ((window->type == TYPE_MAXIMIZED) == maximized)
3979 return;
3980
3981 if (window->type == TYPE_TOPLEVEL) {
Pekka Paalanen811ec4f2013-02-13 16:17:14 +02003982 window->saved_allocation = window->main_surface->allocation;
Kristian Høgsbergd6bcd7d2012-02-16 15:53:46 -05003983 wl_shell_surface_set_maximized(window->shell_surface, NULL);
3984 window->type = TYPE_MAXIMIZED;
MoD063a8822013-03-02 23:43:57 +00003985 window_defer_redraw_until_configure(window);
Rafal Mielniczukc1a3cd12013-03-11 19:26:56 +01003986 } else if (window->type == TYPE_FULLSCREEN) {
3987 wl_shell_surface_set_maximized(window->shell_surface, NULL);
3988 window->type = TYPE_MAXIMIZED;
MoD063a8822013-03-02 23:43:57 +00003989 window_defer_redraw_until_configure(window);
Kristian Høgsbergd6bcd7d2012-02-16 15:53:46 -05003990 } else {
3991 wl_shell_surface_set_toplevel(window->shell_surface);
3992 window->type = TYPE_TOPLEVEL;
3993 window_schedule_resize(window,
3994 window->saved_allocation.width,
3995 window->saved_allocation.height);
3996 }
3997}
3998
3999void
Kristian Høgsbergc8c37342010-06-25 11:19:22 -04004000window_set_user_data(struct window *window, void *data)
4001{
4002 window->user_data = data;
4003}
4004
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -04004005void *
4006window_get_user_data(struct window *window)
4007{
4008 return window->user_data;
4009}
4010
Kristian Høgsbergc8c37342010-06-25 11:19:22 -04004011void
Kristian Høgsberg6e83d582008-12-08 00:01:36 -05004012window_set_key_handler(struct window *window,
Kristian Høgsbergc8c37342010-06-25 11:19:22 -04004013 window_key_handler_t handler)
Kristian Høgsberg6e83d582008-12-08 00:01:36 -05004014{
4015 window->key_handler = handler;
Kristian Høgsberg6e83d582008-12-08 00:01:36 -05004016}
4017
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -05004018void
4019window_set_keyboard_focus_handler(struct window *window,
Kristian Høgsbergc8c37342010-06-25 11:19:22 -04004020 window_keyboard_focus_handler_t handler)
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -05004021{
4022 window->keyboard_focus_handler = handler;
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -05004023}
4024
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -04004025void
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04004026window_set_data_handler(struct window *window, window_data_handler_t handler)
4027{
4028 window->data_handler = handler;
4029}
4030
4031void
4032window_set_drop_handler(struct window *window, window_drop_handler_t handler)
4033{
4034 window->drop_handler = handler;
4035}
4036
4037void
Kristian Høgsberg4f7dcd62012-01-06 21:59:05 -05004038window_set_close_handler(struct window *window,
4039 window_close_handler_t handler)
4040{
4041 window->close_handler = handler;
4042}
4043
4044void
Kristian Høgsberg67ace202012-07-23 21:56:31 -04004045window_set_fullscreen_handler(struct window *window,
4046 window_fullscreen_handler_t handler)
4047{
4048 window->fullscreen_handler = handler;
4049}
4050
4051void
Ander Conselvan de Oliveira15256f62012-11-30 17:34:25 +02004052window_set_output_handler(struct window *window,
4053 window_output_handler_t handler)
4054{
4055 window->output_handler = handler;
4056}
4057
4058void
Callum Lowcayef57a9b2011-01-14 20:46:23 +13004059window_set_title(struct window *window, const char *title)
4060{
Kristian Høgsbergd5fb9cc2011-01-25 12:45:37 -05004061 free(window->title);
Callum Lowcayef57a9b2011-01-14 20:46:23 +13004062 window->title = strdup(title);
Kristian Høgsberg3e0fe5c2012-05-02 09:47:55 -04004063 if (window->shell_surface)
4064 wl_shell_surface_set_title(window->shell_surface, title);
Callum Lowcayef57a9b2011-01-14 20:46:23 +13004065}
4066
4067const char *
4068window_get_title(struct window *window)
4069{
4070 return window->title;
4071}
4072
4073void
Scott Moreau7a1b32a2012-05-27 14:25:02 -06004074window_set_text_cursor_position(struct window *window, int32_t x, int32_t y)
4075{
4076 struct text_cursor_position *text_cursor_position =
4077 window->display->text_cursor_position;
4078
Scott Moreau9295ce02012-06-01 12:46:10 -06004079 if (!text_cursor_position)
Scott Moreau7a1b32a2012-05-27 14:25:02 -06004080 return;
4081
4082 text_cursor_position_notify(text_cursor_position,
Pekka Paalanen4e373742013-02-13 16:17:13 +02004083 window->main_surface->surface,
4084 wl_fixed_from_int(x),
4085 wl_fixed_from_int(y));
Scott Moreau7a1b32a2012-05-27 14:25:02 -06004086}
4087
4088void
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -04004089window_damage(struct window *window, int32_t x, int32_t y,
4090 int32_t width, int32_t height)
4091{
Pekka Paalanen4e373742013-02-13 16:17:13 +02004092 wl_surface_damage(window->main_surface->surface, x, y, width, height);
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -04004093}
4094
Casey Dahlin9074db52012-04-19 22:50:09 -04004095static void
4096surface_enter(void *data,
Rob Bradford7507b572012-05-15 17:55:34 +01004097 struct wl_surface *wl_surface, struct wl_output *wl_output)
Casey Dahlin9074db52012-04-19 22:50:09 -04004098{
Rob Bradford7507b572012-05-15 17:55:34 +01004099 struct window *window = data;
4100 struct output *output;
4101 struct output *output_found = NULL;
4102 struct window_output *window_output;
4103
4104 wl_list_for_each(output, &window->display->output_list, link) {
4105 if (output->output == wl_output) {
4106 output_found = output;
4107 break;
4108 }
4109 }
4110
4111 if (!output_found)
4112 return;
4113
4114 window_output = malloc (sizeof *window_output);
4115 window_output->output = output_found;
4116
4117 wl_list_insert (&window->window_output_list, &window_output->link);
Ander Conselvan de Oliveira15256f62012-11-30 17:34:25 +02004118
4119 if (window->output_handler)
4120 window->output_handler(window, output_found, 1,
4121 window->user_data);
Casey Dahlin9074db52012-04-19 22:50:09 -04004122}
4123
4124static void
4125surface_leave(void *data,
4126 struct wl_surface *wl_surface, struct wl_output *output)
4127{
Rob Bradford7507b572012-05-15 17:55:34 +01004128 struct window *window = data;
4129 struct window_output *window_output;
4130 struct window_output *window_output_found = NULL;
4131
4132 wl_list_for_each(window_output, &window->window_output_list, link) {
4133 if (window_output->output->output == output) {
4134 window_output_found = window_output;
4135 break;
4136 }
4137 }
4138
4139 if (window_output_found) {
4140 wl_list_remove(&window_output_found->link);
Ander Conselvan de Oliveira15256f62012-11-30 17:34:25 +02004141
4142 if (window->output_handler)
4143 window->output_handler(window, window_output->output,
4144 0, window->user_data);
4145
Rob Bradford7507b572012-05-15 17:55:34 +01004146 free(window_output_found);
4147 }
Casey Dahlin9074db52012-04-19 22:50:09 -04004148}
4149
4150static const struct wl_surface_listener surface_listener = {
4151 surface_enter,
4152 surface_leave
4153};
4154
Pekka Paalanen4e373742013-02-13 16:17:13 +02004155static struct surface *
4156surface_create(struct window *window)
4157{
4158 struct display *display = window->display;
4159 struct surface *surface;
4160
4161 surface = calloc(1, sizeof *surface);
4162 if (!surface)
4163 return NULL;
4164
4165 surface->window = window;
4166 surface->surface = wl_compositor_create_surface(display->compositor);
Alexander Larsson5e9b6522013-05-22 14:41:28 +02004167 surface->buffer_scale = 1;
Pekka Paalanen4e373742013-02-13 16:17:13 +02004168 wl_surface_add_listener(surface->surface, &surface_listener, window);
4169
Pekka Paalanen35e82632013-04-25 13:57:48 +03004170 wl_list_insert(&window->subsurface_list, &surface->link);
4171
Pekka Paalanen4e373742013-02-13 16:17:13 +02004172 return surface;
4173}
4174
Kristian Høgsberg248c1b62011-01-21 18:03:15 -05004175static struct window *
Kristian Høgsberg962342c2012-06-26 16:29:50 -04004176window_create_internal(struct display *display,
4177 struct window *parent, int type)
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -05004178{
Kristian Høgsberg1cbaa6a2008-11-07 15:54:48 -05004179 struct window *window;
Pekka Paalanen02bba7c2013-02-13 16:17:15 +02004180 struct surface *surface;
Kristian Høgsberg1cbaa6a2008-11-07 15:54:48 -05004181
4182 window = malloc(sizeof *window);
4183 if (window == NULL)
4184 return NULL;
4185
Kristian Høgsberg78231c82008-11-08 15:06:01 -05004186 memset(window, 0, sizeof *window);
Pekka Paalanen35e82632013-04-25 13:57:48 +03004187 wl_list_init(&window->subsurface_list);
Kristian Høgsberg40979232008-11-25 22:40:39 -05004188 window->display = display;
Kristian Høgsberg248c1b62011-01-21 18:03:15 -05004189 window->parent = parent;
Pekka Paalanen02bba7c2013-02-13 16:17:15 +02004190
4191 surface = surface_create(window);
4192 window->main_surface = surface;
4193
Kristian Høgsberg962342c2012-06-26 16:29:50 -04004194 if (type != TYPE_CUSTOM && display->shell) {
Pekka Paalanen6b2dc912011-11-29 10:25:08 +02004195 window->shell_surface =
4196 wl_shell_get_shell_surface(display->shell,
Pekka Paalanen02bba7c2013-02-13 16:17:15 +02004197 surface->surface);
Pekka Paalanen6b2dc912011-11-29 10:25:08 +02004198 }
Pekka Paalanen811ec4f2013-02-13 16:17:14 +02004199
Kristian Høgsberg962342c2012-06-26 16:29:50 -04004200 window->type = type;
Ander Conselvan de Oliveira5403f522012-12-14 13:37:23 -02004201 window->fullscreen_method = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT;
MoD063a8822013-03-02 23:43:57 +00004202 window->configure_requests = 0;
Kristian Høgsberg87a57bb2012-01-09 10:34:35 -05004203
Kristian Høgsberg4e51b442013-01-07 15:47:14 -05004204 if (display->argb_device)
Benjamin Franzke22d54812011-07-16 19:50:32 +00004205#ifdef HAVE_CAIRO_EGL
Pekka Paalanen02bba7c2013-02-13 16:17:15 +02004206 surface->buffer_type = WINDOW_BUFFER_TYPE_EGL_WINDOW;
Benjamin Franzke22d54812011-07-16 19:50:32 +00004207#else
Pekka Paalanen02bba7c2013-02-13 16:17:15 +02004208 surface->buffer_type = WINDOW_BUFFER_TYPE_SHM;
Benjamin Franzke22d54812011-07-16 19:50:32 +00004209#endif
Yuval Fledel45568f62010-12-06 09:18:12 -05004210 else
Pekka Paalanen02bba7c2013-02-13 16:17:15 +02004211 surface->buffer_type = WINDOW_BUFFER_TYPE_SHM;
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -04004212
Pekka Paalanen02bba7c2013-02-13 16:17:15 +02004213 wl_surface_set_user_data(surface->surface, window);
Kristian Høgsberg478d9262010-06-08 20:34:11 -04004214 wl_list_insert(display->window_list.prev, &window->link);
Kristian Høgsberg84b76c72012-04-13 12:01:18 -04004215 wl_list_init(&window->redraw_task.link);
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05004216
Pekka Paalanen6b2dc912011-11-29 10:25:08 +02004217 if (window->shell_surface) {
4218 wl_shell_surface_set_user_data(window->shell_surface, window);
4219 wl_shell_surface_add_listener(window->shell_surface,
4220 &shell_surface_listener, window);
4221 }
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02004222
Rob Bradford7507b572012-05-15 17:55:34 +01004223 wl_list_init (&window->window_output_list);
4224
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05004225 return window;
4226}
4227
Kristian Høgsberg248c1b62011-01-21 18:03:15 -05004228struct window *
Kristian Høgsberg009ac0a2012-01-31 15:24:48 -05004229window_create(struct display *display)
Kristian Høgsberg248c1b62011-01-21 18:03:15 -05004230{
4231 struct window *window;
4232
Kristian Høgsberg962342c2012-06-26 16:29:50 -04004233 window = window_create_internal(display, NULL, TYPE_NONE);
4234 if (!window)
4235 return NULL;
4236
4237 return window;
4238}
4239
4240struct window *
4241window_create_custom(struct display *display)
4242{
4243 struct window *window;
4244
4245 window = window_create_internal(display, NULL, TYPE_CUSTOM);
Kristian Høgsberg248c1b62011-01-21 18:03:15 -05004246 if (!window)
4247 return NULL;
4248
4249 return window;
4250}
4251
4252struct window *
4253window_create_transient(struct display *display, struct window *parent,
Tiago Vignattidec76582012-05-21 16:47:46 +03004254 int32_t x, int32_t y, uint32_t flags)
Kristian Høgsberg248c1b62011-01-21 18:03:15 -05004255{
4256 struct window *window;
4257
Kristian Høgsberg962342c2012-06-26 16:29:50 -04004258 window = window_create_internal(parent->display,
4259 parent, TYPE_TRANSIENT);
Kristian Høgsberg248c1b62011-01-21 18:03:15 -05004260 if (!window)
4261 return NULL;
4262
4263 window->x = x;
4264 window->y = y;
4265
Kristian Høgsberg1517def2012-02-16 22:56:12 -05004266 if (display->shell)
Pekka Paalanen4e373742013-02-13 16:17:13 +02004267 wl_shell_surface_set_transient(
4268 window->shell_surface,
4269 window->parent->main_surface->surface,
4270 window->x, window->y, flags);
Kristian Høgsberg1517def2012-02-16 22:56:12 -05004271
Kristian Høgsberg248c1b62011-01-21 18:03:15 -05004272 return window;
4273}
4274
Kristian Høgsberg831dd522012-01-10 23:46:33 -05004275static void
Kristian Høgsberg19dd1d72012-01-09 10:42:41 -05004276menu_set_item(struct menu *menu, int sy)
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004277{
4278 int next;
4279
4280 next = (sy - 8) / 20;
4281 if (menu->current != next) {
4282 menu->current = next;
Kristian Høgsberg75bc6672012-01-10 09:43:58 -05004283 widget_schedule_redraw(menu->widget);
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004284 }
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004285}
4286
4287static int
Kristian Høgsberg5f190ef2012-01-09 09:44:45 -05004288menu_motion_handler(struct widget *widget,
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004289 struct input *input, uint32_t time,
Kristian Høgsberg80680c72012-05-10 12:21:37 -04004290 float x, float y, void *data)
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004291{
Kristian Høgsberg831dd522012-01-10 23:46:33 -05004292 struct menu *menu = data;
4293
4294 if (widget == menu->widget)
4295 menu_set_item(data, y);
4296
Ander Conselvan de Oliveiradc8c8fc2012-05-25 16:01:41 +03004297 return CURSOR_LEFT_PTR;
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004298}
4299
Kristian Høgsbergbb901fa2012-01-09 11:22:32 -05004300static int
Kristian Høgsberg391649b2012-01-09 09:22:30 -05004301menu_enter_handler(struct widget *widget,
Kristian Høgsberg80680c72012-05-10 12:21:37 -04004302 struct input *input, float x, float y, void *data)
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004303{
Kristian Høgsberg831dd522012-01-10 23:46:33 -05004304 struct menu *menu = data;
4305
4306 if (widget == menu->widget)
4307 menu_set_item(data, y);
4308
Ander Conselvan de Oliveiradc8c8fc2012-05-25 16:01:41 +03004309 return CURSOR_LEFT_PTR;
Kristian Høgsberg391649b2012-01-09 09:22:30 -05004310}
4311
4312static void
4313menu_leave_handler(struct widget *widget, struct input *input, void *data)
4314{
Kristian Høgsberg831dd522012-01-10 23:46:33 -05004315 struct menu *menu = data;
4316
4317 if (widget == menu->widget)
4318 menu_set_item(data, -200);
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004319}
4320
4321static void
Kristian Høgsberga8a0db32012-01-09 11:12:05 -05004322menu_button_handler(struct widget *widget,
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004323 struct input *input, uint32_t time,
Daniel Stone4dbadb12012-05-30 16:31:51 +01004324 uint32_t button, enum wl_pointer_button_state state,
4325 void *data)
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004326
4327{
Kristian Høgsberg75bc6672012-01-10 09:43:58 -05004328 struct menu *menu = data;
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004329
Kristian Høgsbergd2fbb382012-10-30 13:45:22 -04004330 if (state == WL_POINTER_BUTTON_STATE_RELEASED &&
4331 (menu->release_count > 0 || time - menu->time > 500)) {
Kristian Høgsberg831dd522012-01-10 23:46:33 -05004332 /* Either relase after press-drag-release or
4333 * click-motion-click. */
Kristian Høgsberg75bc6672012-01-10 09:43:58 -05004334 menu->func(menu->window->parent,
4335 menu->current, menu->window->parent->user_data);
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04004336 input_ungrab(input);
Pekka Paalanen6d174cf2012-01-19 15:17:59 +02004337 menu_destroy(menu);
Kristian Høgsberge77d7572012-10-30 18:10:30 -04004338 } else if (state == WL_POINTER_BUTTON_STATE_RELEASED) {
Kristian Høgsbergd2fbb382012-10-30 13:45:22 -04004339 menu->release_count++;
Kristian Høgsberge77d7572012-10-30 18:10:30 -04004340 }
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004341}
4342
4343static void
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -05004344menu_redraw_handler(struct widget *widget, void *data)
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004345{
4346 cairo_t *cr;
4347 const int32_t r = 3, margin = 3;
4348 struct menu *menu = data;
4349 int32_t width, height, i;
4350
Pekka Paalanen0c4445b2013-02-13 16:17:23 +02004351 cr = widget_cairo_create(widget);
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004352 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
4353 cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.0);
4354 cairo_paint(cr);
4355
Pekka Paalanen0a9686f2013-02-13 16:17:22 +02004356 width = widget->allocation.width;
4357 height = widget->allocation.height;
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004358 rounded_rect(cr, 0, 0, width, height, r);
Kristian Høgsberg824c6d02012-01-19 13:54:09 -05004359
4360 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004361 cairo_set_source_rgba(cr, 0.0, 0.0, 0.4, 0.8);
4362 cairo_fill(cr);
4363
4364 for (i = 0; i < menu->count; i++) {
4365 if (i == menu->current) {
4366 cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
4367 cairo_rectangle(cr, margin, i * 20 + margin,
4368 width - 2 * margin, 20);
4369 cairo_fill(cr);
4370 cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
4371 cairo_move_to(cr, 10, i * 20 + 16);
4372 cairo_show_text(cr, menu->entries[i]);
4373 } else {
4374 cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
4375 cairo_move_to(cr, 10, i * 20 + 16);
4376 cairo_show_text(cr, menu->entries[i]);
4377 }
4378 }
4379
4380 cairo_destroy(cr);
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004381}
4382
Pekka Paalanen6d174cf2012-01-19 15:17:59 +02004383void
4384window_show_menu(struct display *display,
4385 struct input *input, uint32_t time, struct window *parent,
4386 int32_t x, int32_t y,
4387 menu_func_t func, const char **entries, int count)
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004388{
4389 struct window *window;
4390 struct menu *menu;
Kristian Høgsberg75bc6672012-01-10 09:43:58 -05004391 const int32_t margin = 3;
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004392
4393 menu = malloc(sizeof *menu);
4394 if (!menu)
Pekka Paalanen6d174cf2012-01-19 15:17:59 +02004395 return;
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004396
Kristian Høgsberg962342c2012-06-26 16:29:50 -04004397 window = window_create_internal(parent->display, parent, TYPE_MENU);
Martin Olsson444799a2012-07-08 03:03:40 +02004398 if (!window) {
4399 free(menu);
Pekka Paalanen6d174cf2012-01-19 15:17:59 +02004400 return;
Martin Olsson444799a2012-07-08 03:03:40 +02004401 }
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004402
4403 menu->window = window;
Kristian Høgsberg75bc6672012-01-10 09:43:58 -05004404 menu->widget = window_add_widget(menu->window, menu);
Alexander Larssond68f5232013-05-22 14:41:33 +02004405 window_set_buffer_scale (menu->window, window_get_buffer_scale (parent));
4406 window_set_buffer_transform (menu->window, window_get_buffer_transform (parent));
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004407 menu->entries = entries;
4408 menu->count = count;
Kristian Høgsbergd2fbb382012-10-30 13:45:22 -04004409 menu->release_count = 0;
Kristian Høgsberg831dd522012-01-10 23:46:33 -05004410 menu->current = -1;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05004411 menu->time = time;
Kristian Høgsberg4f7dcd62012-01-06 21:59:05 -05004412 menu->func = func;
Kristian Høgsberg831dd522012-01-10 23:46:33 -05004413 menu->input = input;
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004414 window->type = TYPE_MENU;
4415 window->x = x;
4416 window->y = y;
4417
Kristian Høgsberga6c8b002012-04-13 12:55:45 -04004418 input_ungrab(input);
Daniel Stone37816df2012-05-16 18:45:18 +01004419 wl_shell_surface_set_popup(window->shell_surface, input->seat,
Kristian Høgsbergf2eb68a2012-04-13 12:37:19 -04004420 display_get_serial(window->display),
Pekka Paalanen4e373742013-02-13 16:17:13 +02004421 window->parent->main_surface->surface,
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05004422 window->x, window->y, 0);
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004423
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -05004424 widget_set_redraw_handler(menu->widget, menu_redraw_handler);
Kristian Høgsberg75bc6672012-01-10 09:43:58 -05004425 widget_set_enter_handler(menu->widget, menu_enter_handler);
4426 widget_set_leave_handler(menu->widget, menu_leave_handler);
4427 widget_set_motion_handler(menu->widget, menu_motion_handler);
4428 widget_set_button_handler(menu->widget, menu_button_handler);
Kristian Høgsberg391649b2012-01-09 09:22:30 -05004429
Kristian Høgsberg831dd522012-01-10 23:46:33 -05004430 input_grab(input, menu->widget, 0);
Kristian Høgsberg009ac0a2012-01-31 15:24:48 -05004431 window_schedule_resize(window, 200, count * 20 + margin * 2);
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05004432}
4433
Kristian Høgsberg248c1b62011-01-21 18:03:15 -05004434void
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -04004435window_set_buffer_type(struct window *window, enum window_buffer_type type)
4436{
Pekka Paalanen02bba7c2013-02-13 16:17:15 +02004437 window->main_surface->buffer_type = type;
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -04004438}
4439
Pekka Paalanen35e82632013-04-25 13:57:48 +03004440struct widget *
4441window_add_subsurface(struct window *window, void *data,
4442 enum subsurface_mode default_mode)
4443{
4444 struct widget *widget;
4445 struct surface *surface;
4446 struct wl_surface *parent;
4447 struct wl_subcompositor *subcompo = window->display->subcompositor;
4448
4449 if (!subcompo)
4450 return NULL;
4451
4452 surface = surface_create(window);
4453 widget = widget_create(window, surface, data);
4454 wl_list_init(&widget->link);
4455 surface->widget = widget;
4456
4457 parent = window->main_surface->surface;
4458 surface->subsurface = wl_subcompositor_get_subsurface(subcompo,
4459 surface->surface,
4460 parent);
4461 surface->synchronized = 1;
4462
4463 switch (default_mode) {
4464 case SUBSURFACE_SYNCHRONIZED:
4465 surface->synchronized_default = 1;
4466 break;
4467 case SUBSURFACE_DESYNCHRONIZED:
4468 surface->synchronized_default = 0;
4469 break;
4470 default:
4471 assert(!"bad enum subsurface_mode");
4472 }
4473
4474 return widget;
4475}
Kristian Høgsberg8357cd62011-05-13 13:24:56 -04004476
4477static void
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05004478display_handle_geometry(void *data,
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04004479 struct wl_output *wl_output,
4480 int x, int y,
4481 int physical_width,
4482 int physical_height,
4483 int subpixel,
4484 const char *make,
Kristian Høgsberg0e696472012-07-22 15:49:57 -04004485 const char *model,
4486 int transform)
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05004487{
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -05004488 struct output *output = data;
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05004489
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -05004490 output->allocation.x = x;
4491 output->allocation.y = y;
Scott Moreau4e072362012-09-29 02:03:11 -06004492 output->transform = transform;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04004493}
4494
4495static void
Alexander Larssonafd319a2013-05-22 14:41:27 +02004496display_handle_done(void *data,
4497 struct wl_output *wl_output)
4498{
4499}
4500
4501static void
4502display_handle_scale(void *data,
4503 struct wl_output *wl_output,
Alexander Larssonedddbd12013-05-24 13:09:43 +02004504 int32_t scale)
Alexander Larssonafd319a2013-05-22 14:41:27 +02004505{
4506 struct output *output = data;
4507
4508 output->scale = scale;
4509}
4510
4511static void
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04004512display_handle_mode(void *data,
4513 struct wl_output *wl_output,
4514 uint32_t flags,
4515 int width,
4516 int height,
4517 int refresh)
4518{
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -05004519 struct output *output = data;
Pekka Paalanen999c5b52011-11-30 10:52:38 +02004520 struct display *display = output->display;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04004521
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -05004522 if (flags & WL_OUTPUT_MODE_CURRENT) {
4523 output->allocation.width = width;
4524 output->allocation.height = height;
Pekka Paalanen999c5b52011-11-30 10:52:38 +02004525 if (display->output_configure_handler)
4526 (*display->output_configure_handler)(
4527 output, display->user_data);
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -05004528 }
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05004529}
4530
4531static const struct wl_output_listener output_listener = {
4532 display_handle_geometry,
Alexander Larssonafd319a2013-05-22 14:41:27 +02004533 display_handle_mode,
4534 display_handle_done,
4535 display_handle_scale
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05004536};
4537
4538static void
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -05004539display_add_output(struct display *d, uint32_t id)
4540{
4541 struct output *output;
4542
4543 output = malloc(sizeof *output);
4544 if (output == NULL)
4545 return;
4546
4547 memset(output, 0, sizeof *output);
4548 output->display = d;
Alexander Larssonafd319a2013-05-22 14:41:27 +02004549 output->scale = 1;
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -05004550 output->output =
Alexander Larssonafd319a2013-05-22 14:41:27 +02004551 wl_registry_bind(d->registry, id, &wl_output_interface, 2);
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -05004552 wl_list_insert(d->output_list.prev, &output->link);
4553
4554 wl_output_add_listener(output->output, &output_listener, output);
4555}
4556
Pekka Paalanen2c1426a2011-12-16 11:35:34 +02004557static void
4558output_destroy(struct output *output)
4559{
4560 if (output->destroy_handler)
4561 (*output->destroy_handler)(output, output->user_data);
4562
4563 wl_output_destroy(output->output);
4564 wl_list_remove(&output->link);
4565 free(output);
4566}
4567
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -05004568void
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04004569display_set_global_handler(struct display *display,
4570 display_global_handler_t handler)
4571{
4572 struct global *global;
4573
4574 display->global_handler = handler;
4575 if (!handler)
4576 return;
4577
4578 wl_list_for_each(global, &display->global_list, link)
4579 display->global_handler(display,
4580 global->name, global->interface,
4581 global->version, display->user_data);
4582}
4583
4584void
Pekka Paalanen999c5b52011-11-30 10:52:38 +02004585display_set_output_configure_handler(struct display *display,
4586 display_output_handler_t handler)
4587{
4588 struct output *output;
4589
4590 display->output_configure_handler = handler;
4591 if (!handler)
4592 return;
4593
Pekka Paalanenb2f957a2012-10-15 12:06:53 +03004594 wl_list_for_each(output, &display->output_list, link) {
4595 if (output->allocation.width == 0 &&
4596 output->allocation.height == 0)
4597 continue;
4598
Pekka Paalanen999c5b52011-11-30 10:52:38 +02004599 (*display->output_configure_handler)(output,
4600 display->user_data);
Pekka Paalanenb2f957a2012-10-15 12:06:53 +03004601 }
Pekka Paalanen999c5b52011-11-30 10:52:38 +02004602}
4603
4604void
4605output_set_user_data(struct output *output, void *data)
4606{
4607 output->user_data = data;
4608}
4609
4610void *
4611output_get_user_data(struct output *output)
4612{
4613 return output->user_data;
4614}
4615
4616void
4617output_set_destroy_handler(struct output *output,
4618 display_output_handler_t handler)
4619{
4620 output->destroy_handler = handler;
4621 /* FIXME: implement this, once we have way to remove outputs */
4622}
4623
4624void
Scott Moreau4e072362012-09-29 02:03:11 -06004625output_get_allocation(struct output *output, struct rectangle *base)
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -05004626{
Scott Moreau4e072362012-09-29 02:03:11 -06004627 struct rectangle allocation = output->allocation;
4628
4629 switch (output->transform) {
4630 case WL_OUTPUT_TRANSFORM_90:
4631 case WL_OUTPUT_TRANSFORM_270:
4632 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
4633 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
4634 /* Swap width and height */
4635 allocation.width = output->allocation.height;
4636 allocation.height = output->allocation.width;
4637 break;
4638 }
4639
4640 *base = allocation;
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -05004641}
4642
Pekka Paalanen999c5b52011-11-30 10:52:38 +02004643struct wl_output *
4644output_get_wl_output(struct output *output)
4645{
4646 return output->output;
4647}
4648
Ander Conselvan de Oliveira15256f62012-11-30 17:34:25 +02004649enum wl_output_transform
4650output_get_transform(struct output *output)
4651{
4652 return output->transform;
4653}
4654
Alexander Larssonafd319a2013-05-22 14:41:27 +02004655uint32_t
4656output_get_scale(struct output *output)
4657{
4658 return output->scale;
4659}
4660
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -05004661static void
Daniel Stone97f68542012-05-30 16:32:01 +01004662fini_xkb(struct input *input)
4663{
4664 xkb_state_unref(input->xkb.state);
4665 xkb_map_unref(input->xkb.keymap);
4666}
4667
4668static void
Kristian Høgsberg4fe1a3e2010-08-10 14:02:48 -04004669display_add_input(struct display *d, uint32_t id)
Kristian Høgsberg808fd412010-07-20 17:06:19 -04004670{
4671 struct input *input;
4672
4673 input = malloc(sizeof *input);
4674 if (input == NULL)
4675 return;
4676
4677 memset(input, 0, sizeof *input);
4678 input->display = d;
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04004679 input->seat = wl_registry_bind(d->registry, id, &wl_seat_interface, 1);
Kristian Høgsberg808fd412010-07-20 17:06:19 -04004680 input->pointer_focus = NULL;
4681 input->keyboard_focus = NULL;
4682 wl_list_insert(d->input_list.prev, &input->link);
4683
Daniel Stone37816df2012-05-16 18:45:18 +01004684 wl_seat_add_listener(input->seat, &seat_listener, input);
4685 wl_seat_set_user_data(input->seat, input);
Kristian Høgsberg808fd412010-07-20 17:06:19 -04004686
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04004687 input->data_device =
4688 wl_data_device_manager_get_data_device(d->data_device_manager,
Daniel Stone37816df2012-05-16 18:45:18 +01004689 input->seat);
4690 wl_data_device_add_listener(input->data_device, &data_device_listener,
4691 input);
Ander Conselvan de Oliveira37ffc3c2012-06-15 17:27:35 +03004692
4693 input->pointer_surface = wl_compositor_create_surface(d->compositor);
Kristian Høgsbergcf4d2442012-06-20 14:52:12 -04004694
Kristian Høgsberg8b19c642012-06-20 18:00:13 -04004695 input->repeat_timer_fd = timerfd_create(CLOCK_MONOTONIC,
4696 TFD_CLOEXEC | TFD_NONBLOCK);
Kristian Høgsbergcf4d2442012-06-20 14:52:12 -04004697 input->repeat_task.run = keyboard_repeat_func;
4698 display_watch_fd(d, input->repeat_timer_fd,
4699 EPOLLIN, &input->repeat_task);
Kristian Høgsberg58eec362011-01-19 14:27:42 -05004700}
4701
Kristian Høgsberg808fd412010-07-20 17:06:19 -04004702static void
Pekka Paalanene1207c72011-12-16 12:02:09 +02004703input_destroy(struct input *input)
4704{
Kristian Høgsberg8a1d10d2011-12-21 17:11:45 -05004705 input_remove_keyboard_focus(input);
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04004706 input_remove_pointer_focus(input);
Pekka Paalanene1207c72011-12-16 12:02:09 +02004707
4708 if (input->drag_offer)
4709 data_offer_destroy(input->drag_offer);
4710
4711 if (input->selection_offer)
4712 data_offer_destroy(input->selection_offer);
4713
4714 wl_data_device_destroy(input->data_device);
Daniel Stone97f68542012-05-30 16:32:01 +01004715 fini_xkb(input);
4716
Ander Conselvan de Oliveira37ffc3c2012-06-15 17:27:35 +03004717 wl_surface_destroy(input->pointer_surface);
4718
Pekka Paalanene1207c72011-12-16 12:02:09 +02004719 wl_list_remove(&input->link);
Daniel Stone37816df2012-05-16 18:45:18 +01004720 wl_seat_destroy(input->seat);
Kristian Høgsbergcf4d2442012-06-20 14:52:12 -04004721 close(input->repeat_timer_fd);
Pekka Paalanene1207c72011-12-16 12:02:09 +02004722 free(input);
4723}
4724
4725static void
Jonas Ådahl14c92ff2012-08-29 22:13:02 +02004726init_workspace_manager(struct display *d, uint32_t id)
4727{
4728 d->workspace_manager =
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04004729 wl_registry_bind(d->registry, id,
4730 &workspace_manager_interface, 1);
Jonas Ådahl14c92ff2012-08-29 22:13:02 +02004731 if (d->workspace_manager != NULL)
4732 workspace_manager_add_listener(d->workspace_manager,
4733 &workspace_manager_listener,
4734 d);
4735}
4736
4737static void
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04004738registry_handle_global(void *data, struct wl_registry *registry, uint32_t id,
4739 const char *interface, uint32_t version)
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05004740{
4741 struct display *d = data;
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04004742 struct global *global;
4743
4744 global = malloc(sizeof *global);
4745 global->name = id;
4746 global->interface = strdup(interface);
4747 global->version = version;
4748 wl_list_insert(d->global_list.prev, &global->link);
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05004749
Kristian Høgsberg7cbdb642011-04-20 18:53:07 -04004750 if (strcmp(interface, "wl_compositor") == 0) {
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04004751 d->compositor = wl_registry_bind(registry, id,
4752 &wl_compositor_interface, 1);
Kristian Høgsberg7cbdb642011-04-20 18:53:07 -04004753 } else if (strcmp(interface, "wl_output") == 0) {
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -05004754 display_add_output(d, id);
Daniel Stone37816df2012-05-16 18:45:18 +01004755 } else if (strcmp(interface, "wl_seat") == 0) {
Kristian Høgsberg4fe1a3e2010-08-10 14:02:48 -04004756 display_add_input(d, id);
Kristian Høgsberg7cbdb642011-04-20 18:53:07 -04004757 } else if (strcmp(interface, "wl_shell") == 0) {
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04004758 d->shell = wl_registry_bind(registry,
4759 id, &wl_shell_interface, 1);
Kristian Høgsberg7cbdb642011-04-20 18:53:07 -04004760 } else if (strcmp(interface, "wl_shm") == 0) {
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04004761 d->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04004762 } else if (strcmp(interface, "wl_data_device_manager") == 0) {
4763 d->data_device_manager =
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04004764 wl_registry_bind(registry, id,
4765 &wl_data_device_manager_interface, 1);
Scott Moreau7a1b32a2012-05-27 14:25:02 -06004766 } else if (strcmp(interface, "text_cursor_position") == 0) {
4767 d->text_cursor_position =
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04004768 wl_registry_bind(registry, id,
4769 &text_cursor_position_interface, 1);
Jonas Ådahl14c92ff2012-08-29 22:13:02 +02004770 } else if (strcmp(interface, "workspace_manager") == 0) {
4771 init_workspace_manager(d, id);
Pekka Paalanen35e82632013-04-25 13:57:48 +03004772 } else if (strcmp(interface, "wl_subcompositor") == 0) {
4773 d->subcompositor =
4774 wl_registry_bind(registry, id,
4775 &wl_subcompositor_interface, 1);
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05004776 }
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04004777
4778 if (d->global_handler)
4779 d->global_handler(d, id, interface, version, d->user_data);
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05004780}
4781
Pekka Paalanen0eab05d2013-01-22 14:53:55 +02004782static void
4783registry_handle_global_remove(void *data, struct wl_registry *registry,
4784 uint32_t name)
4785{
4786 struct display *d = data;
4787 struct global *global;
4788 struct global *tmp;
4789
4790 wl_list_for_each_safe(global, tmp, &d->global_list, link) {
4791 if (global->name != name)
4792 continue;
4793
4794 /* XXX: Should destroy bound globals, and call
4795 * the counterpart of display::global_handler
4796 */
4797 wl_list_remove(&global->link);
4798 free(global->interface);
4799 free(global);
4800 }
4801}
4802
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04004803void *
4804display_bind(struct display *display, uint32_t name,
4805 const struct wl_interface *interface, uint32_t version)
4806{
4807 return wl_registry_bind(display->registry, name, interface, version);
4808}
4809
4810static const struct wl_registry_listener registry_listener = {
Pekka Paalanen0eab05d2013-01-22 14:53:55 +02004811 registry_handle_global,
4812 registry_handle_global_remove
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04004813};
4814
Kristian Høgsberg8f64ed02012-04-03 11:57:44 -04004815#ifdef HAVE_CAIRO_EGL
Yuval Fledel45568f62010-12-06 09:18:12 -05004816static int
Kristian Høgsberg297c6312011-02-04 14:11:33 -05004817init_egl(struct display *d)
Yuval Fledel45568f62010-12-06 09:18:12 -05004818{
4819 EGLint major, minor;
Benjamin Franzke6693ac22011-02-10 12:04:30 +01004820 EGLint n;
Kristian Høgsbergf389cac2011-08-31 16:21:38 -04004821
Rob Clark6396ed32012-03-11 19:48:41 -05004822#ifdef USE_CAIRO_GLESV2
4823# define GL_BIT EGL_OPENGL_ES2_BIT
4824#else
4825# define GL_BIT EGL_OPENGL_BIT
4826#endif
4827
Kristian Høgsberg8e81df42012-01-11 14:24:46 -05004828 static const EGLint argb_cfg_attribs[] = {
Kristian Høgsberg31467562012-10-16 15:31:31 -04004829 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
Benjamin Franzke6693ac22011-02-10 12:04:30 +01004830 EGL_RED_SIZE, 1,
4831 EGL_GREEN_SIZE, 1,
4832 EGL_BLUE_SIZE, 1,
4833 EGL_ALPHA_SIZE, 1,
4834 EGL_DEPTH_SIZE, 1,
Rob Clark6396ed32012-03-11 19:48:41 -05004835 EGL_RENDERABLE_TYPE, GL_BIT,
Benjamin Franzke6693ac22011-02-10 12:04:30 +01004836 EGL_NONE
4837 };
Yuval Fledel45568f62010-12-06 09:18:12 -05004838
Kristian Høgsberg2d574392012-01-18 14:50:58 -05004839#ifdef USE_CAIRO_GLESV2
4840 static const EGLint context_attribs[] = {
4841 EGL_CONTEXT_CLIENT_VERSION, 2,
4842 EGL_NONE
4843 };
4844 EGLint api = EGL_OPENGL_ES_API;
4845#else
4846 EGLint *context_attribs = NULL;
4847 EGLint api = EGL_OPENGL_API;
4848#endif
4849
Kristian Høgsberg91342c62011-04-14 14:44:58 -04004850 d->dpy = eglGetDisplay(d->display);
Yuval Fledel45568f62010-12-06 09:18:12 -05004851 if (!eglInitialize(d->dpy, &major, &minor)) {
Pekka Paalanen4e106542013-02-14 11:49:12 +02004852 fprintf(stderr, "failed to initialize EGL\n");
Yuval Fledel45568f62010-12-06 09:18:12 -05004853 return -1;
4854 }
4855
Kristian Høgsberg2d574392012-01-18 14:50:58 -05004856 if (!eglBindAPI(api)) {
Pekka Paalanen4e106542013-02-14 11:49:12 +02004857 fprintf(stderr, "failed to bind EGL client API\n");
Yuval Fledel45568f62010-12-06 09:18:12 -05004858 return -1;
4859 }
4860
Kristian Høgsberg8e81df42012-01-11 14:24:46 -05004861 if (!eglChooseConfig(d->dpy, argb_cfg_attribs,
4862 &d->argb_config, 1, &n) || n != 1) {
Pekka Paalanen4e106542013-02-14 11:49:12 +02004863 fprintf(stderr, "failed to choose argb EGL config\n");
Benjamin Franzke6693ac22011-02-10 12:04:30 +01004864 return -1;
4865 }
4866
Kristian Høgsberg8e81df42012-01-11 14:24:46 -05004867 d->argb_ctx = eglCreateContext(d->dpy, d->argb_config,
Kristian Høgsberg2d574392012-01-18 14:50:58 -05004868 EGL_NO_CONTEXT, context_attribs);
Benjamin Franzke0c991632011-09-27 21:57:31 +02004869 if (d->argb_ctx == NULL) {
Pekka Paalanen4e106542013-02-14 11:49:12 +02004870 fprintf(stderr, "failed to create EGL context\n");
Yuval Fledel45568f62010-12-06 09:18:12 -05004871 return -1;
4872 }
4873
Kristian Høgsberg067fd602012-02-29 16:15:53 -05004874 if (!eglMakeCurrent(d->dpy, NULL, NULL, d->argb_ctx)) {
Pekka Paalanen4e106542013-02-14 11:49:12 +02004875 fprintf(stderr, "failed to make EGL context current\n");
Yuval Fledel45568f62010-12-06 09:18:12 -05004876 return -1;
4877 }
4878
Benjamin Franzke0c991632011-09-27 21:57:31 +02004879 d->argb_device = cairo_egl_device_create(d->dpy, d->argb_ctx);
4880 if (cairo_device_status(d->argb_device) != CAIRO_STATUS_SUCCESS) {
Pekka Paalanen4e106542013-02-14 11:49:12 +02004881 fprintf(stderr, "failed to get cairo EGL argb device\n");
Benjamin Franzke0c991632011-09-27 21:57:31 +02004882 return -1;
4883 }
Yuval Fledel45568f62010-12-06 09:18:12 -05004884
4885 return 0;
4886}
4887
Pekka Paalanenfe6079a2011-12-15 15:20:04 +02004888static void
4889fini_egl(struct display *display)
4890{
Pekka Paalanenfe6079a2011-12-15 15:20:04 +02004891 cairo_device_destroy(display->argb_device);
Pekka Paalanenfe6079a2011-12-15 15:20:04 +02004892
4893 eglMakeCurrent(display->dpy, EGL_NO_SURFACE, EGL_NO_SURFACE,
4894 EGL_NO_CONTEXT);
4895
4896 eglTerminate(display->dpy);
4897 eglReleaseThread();
4898}
Kristian Høgsberg8f64ed02012-04-03 11:57:44 -04004899#endif
Pekka Paalanenfe6079a2011-12-15 15:20:04 +02004900
Kristian Høgsberg3a696272011-09-14 17:33:48 -04004901static void
Pekka Paalanen3cbb0892012-11-19 17:16:01 +02004902init_dummy_surface(struct display *display)
4903{
4904 int len;
4905 void *data;
4906
4907 len = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, 1);
4908 data = malloc(len);
4909 display->dummy_surface =
4910 cairo_image_surface_create_for_data(data, CAIRO_FORMAT_ARGB32,
4911 1, 1, len);
4912 display->dummy_surface_data = data;
4913}
4914
4915static void
Kristian Høgsberg3a696272011-09-14 17:33:48 -04004916handle_display_data(struct task *task, uint32_t events)
4917{
4918 struct display *display =
4919 container_of(task, struct display, display_task);
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04004920 struct epoll_event ep;
4921 int ret;
U. Artie Eoff44874d92012-10-02 21:12:35 -07004922
4923 display->display_fd_events = events;
4924
4925 if (events & EPOLLERR || events & EPOLLHUP) {
4926 display_exit(display);
4927 return;
4928 }
4929
Kristian Høgsberga17f7a12012-10-16 13:16:10 -04004930 if (events & EPOLLIN) {
4931 ret = wl_display_dispatch(display->display);
4932 if (ret == -1) {
4933 display_exit(display);
4934 return;
4935 }
4936 }
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04004937
4938 if (events & EPOLLOUT) {
4939 ret = wl_display_flush(display->display);
4940 if (ret == 0) {
4941 ep.events = EPOLLIN | EPOLLERR | EPOLLHUP;
4942 ep.data.ptr = &display->display_task;
4943 epoll_ctl(display->epoll_fd, EPOLL_CTL_MOD,
4944 display->display_fd, &ep);
4945 } else if (ret == -1 && errno != EAGAIN) {
4946 display_exit(display);
4947 return;
4948 }
4949 }
Kristian Høgsberg3a696272011-09-14 17:33:48 -04004950}
4951
Kristian Høgsberg2e437202013-04-16 11:21:48 -04004952static void
4953log_handler(const char *format, va_list args)
4954{
4955 vfprintf(stderr, format, args);
4956}
4957
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05004958struct display *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05004959display_create(int *argc, char *argv[])
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05004960{
4961 struct display *d;
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -04004962
Kristian Høgsberg2e437202013-04-16 11:21:48 -04004963 wl_log_set_handler_client(log_handler);
4964
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05004965 d = malloc(sizeof *d);
4966 if (d == NULL)
4967 return NULL;
4968
Tim Wiederhake81bd9792011-01-23 23:25:26 +01004969 memset(d, 0, sizeof *d);
4970
Kristian Høgsberg2bb3ebe2010-12-01 15:36:20 -05004971 d->display = wl_display_connect(NULL);
Kristian Høgsberg478d9262010-06-08 20:34:11 -04004972 if (d->display == NULL) {
Pekka Paalanen4e106542013-02-14 11:49:12 +02004973 fprintf(stderr, "failed to connect to Wayland display: %m\n");
Rob Bradfordf0a1af92013-01-10 19:48:54 +00004974 free(d);
Kristian Høgsberg7824d812010-06-08 14:59:44 -04004975 return NULL;
4976 }
4977
Pekka Paalanen647f2bf2012-05-30 15:53:43 +03004978 d->epoll_fd = os_epoll_create_cloexec();
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04004979 d->display_fd = wl_display_get_fd(d->display);
Kristian Høgsberg3a696272011-09-14 17:33:48 -04004980 d->display_task.run = handle_display_data;
U. Artie Eoff44874d92012-10-02 21:12:35 -07004981 display_watch_fd(d, d->display_fd, EPOLLIN | EPOLLERR | EPOLLHUP,
4982 &d->display_task);
Kristian Høgsberg3a696272011-09-14 17:33:48 -04004983
4984 wl_list_init(&d->deferred_list);
Kristian Høgsberg808fd412010-07-20 17:06:19 -04004985 wl_list_init(&d->input_list);
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -05004986 wl_list_init(&d->output_list);
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04004987 wl_list_init(&d->global_list);
Kristian Høgsberg808fd412010-07-20 17:06:19 -04004988
Daniel Stone97f68542012-05-30 16:32:01 +01004989 d->xkb_context = xkb_context_new(0);
Daniel Stoneb7452fe2012-06-01 12:14:06 +01004990 if (d->xkb_context == NULL) {
4991 fprintf(stderr, "Failed to create XKB context\n");
Daniel Stone97f68542012-05-30 16:32:01 +01004992 return NULL;
4993 }
4994
Jonas Ådahlf77beeb2012-10-08 22:49:04 +02004995 d->workspace = 0;
4996 d->workspace_count = 1;
4997
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04004998 d->registry = wl_display_get_registry(d->display);
4999 wl_registry_add_listener(d->registry, &registry_listener, d);
Pekka Paalanen33a68ea2013-02-14 12:18:00 +02005000
5001 if (wl_display_dispatch(d->display) < 0) {
5002 fprintf(stderr, "Failed to process Wayland connection: %m\n");
5003 return NULL;
5004 }
5005
Kristian Høgsberg8f64ed02012-04-03 11:57:44 -04005006#ifdef HAVE_CAIRO_EGL
Pekka Paalanen4e106542013-02-14 11:49:12 +02005007 if (init_egl(d) < 0)
5008 fprintf(stderr, "EGL does not seem to work, "
5009 "falling back to software rendering and wl_shm.\n");
Kristian Høgsberg8f64ed02012-04-03 11:57:44 -04005010#endif
Kristian Høgsberg8a9cda82008-11-03 15:31:30 -05005011
Ander Conselvan de Oliveirad8f527c2012-05-25 09:30:02 +03005012 create_cursors(d);
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04005013
Kristian Høgsberg5adb4802012-05-15 22:25:28 -04005014 d->theme = theme_create();
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -04005015
Kristian Høgsberg478d9262010-06-08 20:34:11 -04005016 wl_list_init(&d->window_list);
5017
Pekka Paalanen3cbb0892012-11-19 17:16:01 +02005018 init_dummy_surface(d);
5019
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05005020 return d;
5021}
5022
Pekka Paalanen2c1426a2011-12-16 11:35:34 +02005023static void
5024display_destroy_outputs(struct display *display)
5025{
5026 struct output *tmp;
5027 struct output *output;
5028
5029 wl_list_for_each_safe(output, tmp, &display->output_list, link)
5030 output_destroy(output);
5031}
5032
Pekka Paalanene1207c72011-12-16 12:02:09 +02005033static void
5034display_destroy_inputs(struct display *display)
5035{
5036 struct input *tmp;
5037 struct input *input;
5038
5039 wl_list_for_each_safe(input, tmp, &display->input_list, link)
5040 input_destroy(input);
5041}
5042
Pekka Paalanen999c5b52011-11-30 10:52:38 +02005043void
Pekka Paalanenfe6079a2011-12-15 15:20:04 +02005044display_destroy(struct display *display)
5045{
Pekka Paalanenc2052982011-12-16 11:41:32 +02005046 if (!wl_list_empty(&display->window_list))
U. Artie Eoff44874d92012-10-02 21:12:35 -07005047 fprintf(stderr, "toytoolkit warning: %d windows exist.\n",
5048 wl_list_length(&display->window_list));
Pekka Paalanenc2052982011-12-16 11:41:32 +02005049
5050 if (!wl_list_empty(&display->deferred_list))
5051 fprintf(stderr, "toytoolkit warning: deferred tasks exist.\n");
5052
Pekka Paalanen3cbb0892012-11-19 17:16:01 +02005053 cairo_surface_destroy(display->dummy_surface);
5054 free(display->dummy_surface_data);
5055
Pekka Paalanen2c1426a2011-12-16 11:35:34 +02005056 display_destroy_outputs(display);
Pekka Paalanene1207c72011-12-16 12:02:09 +02005057 display_destroy_inputs(display);
Pekka Paalanen2c1426a2011-12-16 11:35:34 +02005058
Daniel Stone97f68542012-05-30 16:32:01 +01005059 xkb_context_unref(display->xkb_context);
Pekka Paalanen325bb602011-12-19 10:31:45 +02005060
Kristian Høgsberg5adb4802012-05-15 22:25:28 -04005061 theme_destroy(display->theme);
Ander Conselvan de Oliveirad8f527c2012-05-25 09:30:02 +03005062 destroy_cursors(display);
Pekka Paalanen325bb602011-12-19 10:31:45 +02005063
Kristian Høgsberg8f64ed02012-04-03 11:57:44 -04005064#ifdef HAVE_CAIRO_EGL
Kristian Høgsberg4e51b442013-01-07 15:47:14 -05005065 if (display->argb_device)
5066 fini_egl(display);
Kristian Høgsberg8f64ed02012-04-03 11:57:44 -04005067#endif
Pekka Paalanenfe6079a2011-12-15 15:20:04 +02005068
Pekka Paalanen35e82632013-04-25 13:57:48 +03005069 if (display->subcompositor)
5070 wl_subcompositor_destroy(display->subcompositor);
5071
Pekka Paalanenc2052982011-12-16 11:41:32 +02005072 if (display->shell)
5073 wl_shell_destroy(display->shell);
5074
5075 if (display->shm)
5076 wl_shm_destroy(display->shm);
5077
5078 if (display->data_device_manager)
5079 wl_data_device_manager_destroy(display->data_device_manager);
5080
5081 wl_compositor_destroy(display->compositor);
Pekka Paalanenaac1c132012-12-04 16:01:15 +02005082 wl_registry_destroy(display->registry);
Pekka Paalanenc2052982011-12-16 11:41:32 +02005083
5084 close(display->epoll_fd);
5085
U. Artie Eoff44874d92012-10-02 21:12:35 -07005086 if (!(display->display_fd_events & EPOLLERR) &&
5087 !(display->display_fd_events & EPOLLHUP))
5088 wl_display_flush(display->display);
5089
Kristian Høgsbergfcfc83f2012-02-28 14:29:19 -05005090 wl_display_disconnect(display->display);
Pekka Paalanenfe6079a2011-12-15 15:20:04 +02005091 free(display);
5092}
5093
5094void
Pekka Paalanen999c5b52011-11-30 10:52:38 +02005095display_set_user_data(struct display *display, void *data)
5096{
5097 display->user_data = data;
5098}
5099
5100void *
5101display_get_user_data(struct display *display)
5102{
5103 return display->user_data;
5104}
5105
Kristian Høgsberg9d69f8e2010-09-03 14:46:38 -04005106struct wl_display *
5107display_get_display(struct display *display)
5108{
5109 return display->display;
5110}
5111
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -05005112struct output *
5113display_get_output(struct display *display)
5114{
5115 return container_of(display->output_list.next, struct output, link);
5116}
5117
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05005118struct wl_compositor *
5119display_get_compositor(struct display *display)
5120{
5121 return display->compositor;
Kristian Høgsberg61017b12008-11-02 18:51:48 -05005122}
Kristian Høgsberg7824d812010-06-08 14:59:44 -04005123
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04005124uint32_t
5125display_get_serial(struct display *display)
5126{
5127 return display->serial;
5128}
5129
Kristian Høgsberg7824d812010-06-08 14:59:44 -04005130EGLDisplay
5131display_get_egl_display(struct display *d)
5132{
5133 return d->dpy;
5134}
5135
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04005136struct wl_data_source *
5137display_create_data_source(struct display *display)
5138{
5139 return wl_data_device_manager_create_data_source(display->data_device_manager);
5140}
5141
Benjamin Franzkecff904e2011-02-18 23:00:55 +01005142EGLConfig
Benjamin Franzke0c991632011-09-27 21:57:31 +02005143display_get_argb_egl_config(struct display *d)
5144{
Kristian Høgsberg8e81df42012-01-11 14:24:46 -05005145 return d->argb_config;
Benjamin Franzke0c991632011-09-27 21:57:31 +02005146}
5147
Kristian Høgsberg58eec362011-01-19 14:27:42 -05005148struct wl_shell *
5149display_get_shell(struct display *display)
5150{
5151 return display->shell;
5152}
5153
Benjamin Franzke1a89f282011-10-07 09:33:06 +02005154int
Benjamin Franzkecff904e2011-02-18 23:00:55 +01005155display_acquire_window_surface(struct display *display,
5156 struct window *window,
5157 EGLContext ctx)
5158{
Pekka Paalanen811ec4f2013-02-13 16:17:14 +02005159 struct surface *surface = window->main_surface;
5160
Pekka Paalanen02bba7c2013-02-13 16:17:15 +02005161 if (surface->buffer_type != WINDOW_BUFFER_TYPE_EGL_WINDOW)
Benjamin Franzke1a89f282011-10-07 09:33:06 +02005162 return -1;
Benjamin Franzkecff904e2011-02-18 23:00:55 +01005163
Pekka Paalanen6f41b072013-02-20 13:39:17 +02005164 widget_get_cairo_surface(window->main_surface->widget);
Pekka Paalanen811ec4f2013-02-13 16:17:14 +02005165 return surface->toysurface->acquire(surface->toysurface, ctx);
Benjamin Franzkecff904e2011-02-18 23:00:55 +01005166}
5167
5168void
Benjamin Franzke0c991632011-09-27 21:57:31 +02005169display_release_window_surface(struct display *display,
5170 struct window *window)
Benjamin Franzkecff904e2011-02-18 23:00:55 +01005171{
Pekka Paalanen811ec4f2013-02-13 16:17:14 +02005172 struct surface *surface = window->main_surface;
5173
Pekka Paalanen02bba7c2013-02-13 16:17:15 +02005174 if (surface->buffer_type != WINDOW_BUFFER_TYPE_EGL_WINDOW)
Benjamin Franzke0c991632011-09-27 21:57:31 +02005175 return;
5176
Pekka Paalanen811ec4f2013-02-13 16:17:14 +02005177 surface->toysurface->release(surface->toysurface);
Benjamin Franzkecff904e2011-02-18 23:00:55 +01005178}
5179
5180void
Kristian Høgsberg3a696272011-09-14 17:33:48 -04005181display_defer(struct display *display, struct task *task)
Kristian Høgsberg7824d812010-06-08 14:59:44 -04005182{
Kristian Høgsberg3a696272011-09-14 17:33:48 -04005183 wl_list_insert(&display->deferred_list, &task->link);
5184}
5185
5186void
5187display_watch_fd(struct display *display,
5188 int fd, uint32_t events, struct task *task)
5189{
5190 struct epoll_event ep;
5191
5192 ep.events = events;
5193 ep.data.ptr = task;
5194 epoll_ctl(display->epoll_fd, EPOLL_CTL_ADD, fd, &ep);
5195}
5196
5197void
Dima Ryazanova85292e2012-11-29 00:27:09 -08005198display_unwatch_fd(struct display *display, int fd)
5199{
5200 epoll_ctl(display->epoll_fd, EPOLL_CTL_DEL, fd, NULL);
5201}
5202
5203void
Kristian Høgsberg3a696272011-09-14 17:33:48 -04005204display_run(struct display *display)
5205{
5206 struct task *task;
5207 struct epoll_event ep[16];
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04005208 int i, count, ret;
Kristian Høgsberg3a696272011-09-14 17:33:48 -04005209
Pekka Paalanen826d7952011-12-15 10:14:07 +02005210 display->running = 1;
Kristian Høgsberg3a696272011-09-14 17:33:48 -04005211 while (1) {
Kristian Høgsberg3a696272011-09-14 17:33:48 -04005212 while (!wl_list_empty(&display->deferred_list)) {
Tiago Vignatti6f093382012-09-27 14:46:23 +03005213 task = container_of(display->deferred_list.prev,
Kristian Høgsberg3a696272011-09-14 17:33:48 -04005214 struct task, link);
5215 wl_list_remove(&task->link);
5216 task->run(task, 0);
5217 }
Kristian Høgsberg9ca2d082012-01-09 18:48:14 -05005218
Kristian Høgsbergfeb3c1d2012-10-15 12:56:11 -04005219 wl_display_dispatch_pending(display->display);
5220
Kristian Høgsberg9ca2d082012-01-09 18:48:14 -05005221 if (!display->running)
5222 break;
5223
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04005224 ret = wl_display_flush(display->display);
5225 if (ret < 0 && errno == EAGAIN) {
5226 ep[0].events =
5227 EPOLLIN | EPOLLOUT | EPOLLERR | EPOLLHUP;
5228 ep[0].data.ptr = &display->display_task;
5229
5230 epoll_ctl(display->epoll_fd, EPOLL_CTL_MOD,
5231 display->display_fd, &ep[0]);
5232 } else if (ret < 0) {
5233 break;
5234 }
Kristian Høgsberg9ca2d082012-01-09 18:48:14 -05005235
5236 count = epoll_wait(display->epoll_fd,
5237 ep, ARRAY_LENGTH(ep), -1);
5238 for (i = 0; i < count; i++) {
5239 task = ep[i].data.ptr;
5240 task->run(task, ep[i].events);
5241 }
Kristian Høgsberg3a696272011-09-14 17:33:48 -04005242 }
Kristian Høgsberg7824d812010-06-08 14:59:44 -04005243}
Pekka Paalanen826d7952011-12-15 10:14:07 +02005244
5245void
5246display_exit(struct display *display)
5247{
5248 display->running = 0;
5249}
Jan Arne Petersencd997062012-11-18 19:06:44 +01005250
5251void
5252keysym_modifiers_add(struct wl_array *modifiers_map,
5253 const char *name)
5254{
5255 size_t len = strlen(name) + 1;
5256 char *p;
5257
5258 p = wl_array_add(modifiers_map, len);
5259
5260 if (p == NULL)
5261 return;
5262
5263 strncpy(p, name, len);
5264}
5265
5266static xkb_mod_index_t
5267keysym_modifiers_get_index(struct wl_array *modifiers_map,
5268 const char *name)
5269{
5270 xkb_mod_index_t index = 0;
5271 char *p = modifiers_map->data;
5272
5273 while ((const char *)p < (const char *)(modifiers_map->data + modifiers_map->size)) {
5274 if (strcmp(p, name) == 0)
5275 return index;
5276
5277 index++;
5278 p += strlen(p) + 1;
5279 }
5280
5281 return XKB_MOD_INVALID;
5282}
5283
5284xkb_mod_mask_t
5285keysym_modifiers_get_mask(struct wl_array *modifiers_map,
5286 const char *name)
5287{
5288 xkb_mod_index_t index = keysym_modifiers_get_index(modifiers_map, name);
5289
5290 if (index == XKB_MOD_INVALID)
5291 return XKB_MOD_INVALID;
5292
5293 return 1 << index;
5294}