blob: 12a98cb07202e3975d2b657701142c6f61eb2848 [file] [log] [blame]
Kristian Høgsbergffd710e2008-12-02 15:15:01 -05001/*
2 * Copyright © 2008 Kristian Høgsberg
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission. The copyright holders make no representations
11 * about the suitability of this software for any purpose. It is provided "as
12 * is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20 * OF THIS SOFTWARE.
21 */
22
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -040023#define _GNU_SOURCE
24
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -040025#include "../config.h"
26
Kristian Høgsberg61017b12008-11-02 18:51:48 -050027#include <stdint.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
Kristian Høgsberg61017b12008-11-02 18:51:48 -050031#include <fcntl.h>
32#include <unistd.h>
33#include <math.h>
Benjamin Franzke0c991632011-09-27 21:57:31 +020034#include <assert.h>
Kristian Høgsberg61017b12008-11-02 18:51:48 -050035#include <time.h>
36#include <cairo.h>
Kristian Høgsberg1cbaa6a2008-11-07 15:54:48 -050037#include <glib.h>
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -040038#include <sys/mman.h>
Kristian Høgsberg3a696272011-09-14 17:33:48 -040039#include <sys/epoll.h>
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -040040
Kristian Høgsbergf02a6492012-03-12 01:05:25 -040041#include <pixman.h>
42
Kristian Høgsberg297d6dd2011-02-09 10:51:15 -050043#include <wayland-egl.h>
44
Rob Clark6396ed32012-03-11 19:48:41 -050045#ifdef USE_CAIRO_GLESV2
46#include <GLES2/gl2.h>
47#include <GLES2/gl2ext.h>
48#else
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -040049#include <GL/gl.h>
Rob Clark6396ed32012-03-11 19:48:41 -050050#endif
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -040051#include <EGL/egl.h>
52#include <EGL/eglext.h>
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -040053
Kristian Høgsberg8def2642011-01-14 17:41:33 -050054#ifdef HAVE_CAIRO_EGL
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -040055#include <cairo-gl.h>
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -040056#endif
Kristian Høgsberg61017b12008-11-02 18:51:48 -050057
Daniel Stone9d4f0302012-02-15 16:33:21 +000058#include <xkbcommon/xkbcommon.h>
Kristian Høgsberg70163132012-05-08 15:55:39 -040059#include <X11/keysym.h>
Kristian Høgsbergd6bcd7d2012-02-16 15:53:46 -050060#include <X11/X.h>
Ander Conselvan de Oliveira1493d2a2012-05-03 12:29:46 +030061#include <X11/Xcursor/Xcursor.h>
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -040062
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -050063#include <linux/input.h>
Pekka Paalanen50719bc2011-11-22 14:18:50 +020064#include <wayland-client.h>
Kristian Høgsbergb91cd102010-08-16 16:17:42 -040065#include "cairo-util.h"
Kristian Høgsberg2f2cfae2008-11-08 22:46:30 -050066
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -050067#include "window.h"
Kristian Høgsberg8a9cda82008-11-03 15:31:30 -050068
Ander Conselvan de Oliveira1493d2a2012-05-03 12:29:46 +030069struct cursor;
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -070070struct shm_pool;
Ander Conselvan de Oliveira1493d2a2012-05-03 12:29:46 +030071
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -050072struct display {
Kristian Høgsberg40979232008-11-25 22:40:39 -050073 struct wl_display *display;
Kristian Høgsbergd2412e22008-12-15 20:35:24 -050074 struct wl_compositor *compositor;
Kristian Høgsberg83fc0612010-08-04 22:44:55 -040075 struct wl_shell *shell;
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -040076 struct wl_shm *shm;
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -040077 struct wl_data_device_manager *data_device_manager;
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -040078 EGLDisplay dpy;
Kristian Høgsberg8e81df42012-01-11 14:24:46 -050079 EGLConfig argb_config;
Benjamin Franzke0c991632011-09-27 21:57:31 +020080 EGLContext argb_ctx;
Benjamin Franzke0c991632011-09-27 21:57:31 +020081 cairo_device_t *argb_device;
Kristian Høgsbergeae5de72012-04-11 22:42:15 -040082 uint32_t serial;
Kristian Høgsberg3a696272011-09-14 17:33:48 -040083
84 int display_fd;
85 uint32_t mask;
86 struct task display_task;
87
88 int epoll_fd;
89 struct wl_list deferred_list;
90
Pekka Paalanen826d7952011-12-15 10:14:07 +020091 int running;
92
Kristian Høgsberg478d9262010-06-08 20:34:11 -040093 struct wl_list window_list;
Kristian Høgsberg808fd412010-07-20 17:06:19 -040094 struct wl_list input_list;
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -050095 struct wl_list output_list;
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -040096 cairo_surface_t *active_frame, *inactive_frame, *shadow;
Kristian Høgsberg010f98b2012-02-23 17:30:45 -050097 int frame_radius;
Kristian Høgsberg70163132012-05-08 15:55:39 -040098
99 struct {
100 struct xkb_rule_names names;
101 struct xkb_keymap *keymap;
102 struct xkb_state *state;
103 struct xkb_context *context;
104 xkb_mod_mask_t control_mask;
105 xkb_mod_mask_t alt_mask;
106 xkb_mod_mask_t shift_mask;
107 } xkb;
108
Ander Conselvan de Oliveira1493d2a2012-05-03 12:29:46 +0300109 struct cursor *cursors;
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700110 struct shm_pool *cursor_shm_pool;
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -0400111
Kristian Høgsberg0d5007a2011-02-09 10:57:44 -0500112 PFNGLEGLIMAGETARGETTEXTURE2DOESPROC image_target_texture_2d;
113 PFNEGLCREATEIMAGEKHRPROC create_image;
114 PFNEGLDESTROYIMAGEKHRPROC destroy_image;
Pekka Paalanen999c5b52011-11-30 10:52:38 +0200115
116 display_output_handler_t output_configure_handler;
117
118 void *user_data;
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -0500119};
120
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400121enum {
Kristian Høgsberg407ef642012-04-27 17:17:12 -0400122 TYPE_NONE,
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400123 TYPE_TOPLEVEL,
Kristian Høgsbergf8ab46e2011-09-08 16:56:38 -0400124 TYPE_FULLSCREEN,
Kristian Høgsbergd6bcd7d2012-02-16 15:53:46 -0500125 TYPE_MAXIMIZED,
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400126 TYPE_TRANSIENT,
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -0500127 TYPE_MENU,
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400128 TYPE_CUSTOM
129};
130
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -0500131struct window {
132 struct display *display;
Kristian Høgsberg248c1b62011-01-21 18:03:15 -0500133 struct window *parent;
Kristian Høgsberg61017b12008-11-02 18:51:48 -0500134 struct wl_surface *surface;
Pekka Paalanen9d1613e2011-11-25 12:09:16 +0200135 struct wl_shell_surface *shell_surface;
Kristian Høgsberg010f98b2012-02-23 17:30:45 -0500136 struct wl_region *input_region;
137 struct wl_region *opaque_region;
Kristian Høgsbergd5fb9cc2011-01-25 12:45:37 -0500138 char *title;
Kristian Høgsberg82da52b2010-12-17 09:53:12 -0500139 struct rectangle allocation, saved_allocation, server_allocation;
Kristian Høgsberg0d1c0622012-01-31 15:30:47 -0500140 struct rectangle pending_allocation;
Kristian Høgsberg248c1b62011-01-21 18:03:15 -0500141 int x, y;
Kristian Høgsberg83fc0612010-08-04 22:44:55 -0400142 int resize_edges;
Kristian Høgsberg80d746f2010-06-14 23:52:50 -0400143 int redraw_scheduled;
Kristian Høgsberg6bd4d972012-03-24 14:42:09 -0400144 int redraw_needed;
Kristian Høgsberg3a696272011-09-14 17:33:48 -0400145 struct task redraw_task;
Kristian Høgsberg42b4f802012-03-26 13:49:29 -0400146 int resize_needed;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400147 int type;
Kristian Høgsberg3be87d12011-05-13 13:45:17 -0400148 int transparent;
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400149 struct input *keyboard_device;
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400150 enum window_buffer_type buffer_type;
Kristian Høgsberg78231c82008-11-08 15:06:01 -0500151
Kristian Høgsberg6e2a8d72012-04-10 11:23:13 -0400152 cairo_surface_t *cairo_surface;
Kristian Høgsberg8a9cda82008-11-03 15:31:30 -0500153
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700154 struct shm_pool *pool;
Kristian Høgsberg1103a1a2012-04-03 12:00:48 -0400155
Kristian Høgsberg6e83d582008-12-08 00:01:36 -0500156 window_key_handler_t key_handler;
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -0500157 window_keyboard_focus_handler_t keyboard_focus_handler;
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400158 window_data_handler_t data_handler;
159 window_drop_handler_t drop_handler;
Kristian Høgsberg4f7dcd62012-01-06 21:59:05 -0500160 window_close_handler_t close_handler;
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400161
Pekka Paalanen4dde2fc2012-01-19 13:33:50 +0200162 struct frame *frame;
Kristian Høgsberg441338c2012-01-10 13:52:34 -0500163 struct widget *widget;
Kristian Høgsberg4f7dcd62012-01-06 21:59:05 -0500164
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500165 void *user_data;
Kristian Høgsberg478d9262010-06-08 20:34:11 -0400166 struct wl_list link;
Kristian Høgsberg61017b12008-11-02 18:51:48 -0500167};
168
Kristian Høgsbergc51f7992012-01-08 15:09:53 -0500169struct widget {
Kristian Høgsberg9a13dab2012-01-08 15:18:19 -0500170 struct window *window;
Kristian Høgsberg441338c2012-01-10 13:52:34 -0500171 struct wl_list child_list;
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400172 struct wl_list link;
173 struct rectangle allocation;
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -0500174 widget_resize_handler_t resize_handler;
175 widget_redraw_handler_t redraw_handler;
Kristian Høgsbergee143232012-01-09 08:42:24 -0500176 widget_enter_handler_t enter_handler;
177 widget_leave_handler_t leave_handler;
Kristian Høgsberg04e98342012-01-09 09:36:16 -0500178 widget_motion_handler_t motion_handler;
Kristian Høgsberga8a0db32012-01-09 11:12:05 -0500179 widget_button_handler_t button_handler;
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400180 void *user_data;
Kristian Høgsberg010f98b2012-02-23 17:30:45 -0500181 int opaque;
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400182};
183
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400184struct input {
185 struct display *display;
186 struct wl_input_device *input_device;
187 struct window *pointer_focus;
188 struct window *keyboard_focus;
Ander Conselvan de Oliveira1493d2a2012-05-03 12:29:46 +0300189 int current_cursor;
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400190 uint32_t modifiers;
Kristian Høgsbergeae5de72012-04-11 22:42:15 -0400191 uint32_t pointer_enter_serial;
Daniel Stoneb230a7e2012-05-08 17:17:54 +0100192 GLfloat sx, sy;
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400193 struct wl_list link;
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400194
Kristian Høgsbergb6323512012-01-11 00:04:42 -0500195 struct widget *focus_widget;
Kristian Høgsberg831dd522012-01-10 23:46:33 -0500196 struct widget *grab;
197 uint32_t grab_button;
198
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -0400199 struct wl_data_device *data_device;
200 struct data_offer *drag_offer;
201 struct data_offer *selection_offer;
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400202};
203
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -0500204struct output {
205 struct display *display;
206 struct wl_output *output;
207 struct rectangle allocation;
208 struct wl_list link;
Pekka Paalanen999c5b52011-11-30 10:52:38 +0200209
210 display_output_handler_t destroy_handler;
211 void *user_data;
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -0500212};
213
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -0500214struct frame {
215 struct widget *widget;
216 struct widget *child;
217 int margin;
Kristian Høgsbergb8abe7e2012-03-20 23:56:05 -0400218 int width;
219 int titlebar_height;
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -0500220};
221
Kristian Høgsberg4f7dcd62012-01-06 21:59:05 -0500222struct menu {
223 struct window *window;
Kristian Høgsberg75bc6672012-01-10 09:43:58 -0500224 struct widget *widget;
Kristian Høgsberg831dd522012-01-10 23:46:33 -0500225 struct input *input;
Kristian Høgsberg4f7dcd62012-01-06 21:59:05 -0500226 const char **entries;
227 uint32_t time;
228 int current;
229 int count;
230 menu_func_t func;
231};
232
Ander Conselvan de Oliveira1493d2a2012-05-03 12:29:46 +0300233struct cursor_image {
234 cairo_surface_t *surface;
235 int width, height;
236 int hotspot_x, hotspot_y;
237 int delay;
238};
239
240struct cursor {
241 int n_images;
242 struct cursor_image *images;
243};
244
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700245struct shm_pool {
246 struct wl_shm_pool *pool;
247 size_t size;
248 size_t used;
249 void *data;
250};
251
Kristian Høgsberg7d804062010-09-07 21:50:06 -0400252enum {
253 POINTER_DEFAULT = 100,
254 POINTER_UNSET
255};
256
Kristian Høgsberg82da52b2010-12-17 09:53:12 -0500257enum window_location {
258 WINDOW_INTERIOR = 0,
259 WINDOW_RESIZING_TOP = 1,
260 WINDOW_RESIZING_BOTTOM = 2,
261 WINDOW_RESIZING_LEFT = 4,
262 WINDOW_RESIZING_TOP_LEFT = 5,
263 WINDOW_RESIZING_BOTTOM_LEFT = 6,
264 WINDOW_RESIZING_RIGHT = 8,
265 WINDOW_RESIZING_TOP_RIGHT = 9,
266 WINDOW_RESIZING_BOTTOM_RIGHT = 10,
267 WINDOW_RESIZING_MASK = 15,
268 WINDOW_EXTERIOR = 16,
269 WINDOW_TITLEBAR = 17,
270 WINDOW_CLIENT_AREA = 18,
271};
272
Kristian Høgsbergc7c60642010-08-29 21:33:39 -0400273const char *option_xkb_layout = "us";
274const char *option_xkb_variant = "";
275const char *option_xkb_options = "";
276
Kristian Høgsbergbcacef12012-03-11 21:05:57 -0400277static const struct weston_option xkb_options[] = {
278 { WESTON_OPTION_STRING, "xkb-layout", 0, &option_xkb_layout },
279 { WESTON_OPTION_STRING, "xkb-variant", 0, &option_xkb_variant },
280 { WESTON_OPTION_STRING, "xkb-options", 0, &option_xkb_options },
Kristian Høgsbergc7c60642010-08-29 21:33:39 -0400281};
282
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400283static const cairo_user_data_key_t surface_data_key;
284struct surface_data {
285 struct wl_buffer *buffer;
286};
287
Kristian Høgsberg1f5d5072010-11-29 08:13:35 -0500288#define MULT(_d,c,a,t) \
289 do { t = c * a + 0x7f; _d = ((t >> 8) + t) >> 8; } while (0)
290
Kristian Høgsberg8def2642011-01-14 17:41:33 -0500291#ifdef HAVE_CAIRO_EGL
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400292
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100293struct egl_window_surface_data {
294 struct display *display;
295 struct wl_surface *surface;
296 struct wl_egl_window *window;
297 EGLSurface surf;
298};
299
300static void
301egl_window_surface_data_destroy(void *p)
302{
303 struct egl_window_surface_data *data = p;
304 struct display *d = data->display;
305
306 eglDestroySurface(d->dpy, data->surf);
307 wl_egl_window_destroy(data->window);
308 data->surface = NULL;
309
310 free(p);
311}
312
313static cairo_surface_t *
314display_create_egl_window_surface(struct display *display,
315 struct wl_surface *surface,
Kristian Høgsbergf389cac2011-08-31 16:21:38 -0400316 uint32_t flags,
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100317 struct rectangle *rectangle)
318{
319 cairo_surface_t *cairo_surface;
320 struct egl_window_surface_data *data;
Kristian Høgsbergf389cac2011-08-31 16:21:38 -0400321 EGLConfig config;
Benjamin Franzke0c991632011-09-27 21:57:31 +0200322 cairo_device_t *device;
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100323
324 data = malloc(sizeof *data);
325 if (data == NULL)
326 return NULL;
327
328 data->display = display;
329 data->surface = surface;
330
Kristian Høgsberg067fd602012-02-29 16:15:53 -0500331 config = display->argb_config;
332 device = display->argb_device;
Kristian Høgsbergf389cac2011-08-31 16:21:38 -0400333
Kristian Høgsberg91342c62011-04-14 14:44:58 -0400334 data->window = wl_egl_window_create(surface,
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100335 rectangle->width,
Kristian Høgsbergf389cac2011-08-31 16:21:38 -0400336 rectangle->height);
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100337
Kristian Høgsbergf389cac2011-08-31 16:21:38 -0400338 data->surf = eglCreateWindowSurface(display->dpy, config,
Kristian Høgsberg8e81df42012-01-11 14:24:46 -0500339 data->window, NULL);
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100340
Benjamin Franzke0c991632011-09-27 21:57:31 +0200341 cairo_surface = cairo_gl_surface_create_for_egl(device,
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100342 data->surf,
343 rectangle->width,
344 rectangle->height);
345
346 cairo_surface_set_user_data(cairo_surface, &surface_data_key,
347 data, egl_window_surface_data_destroy);
348
349 return cairo_surface;
350}
351
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400352#endif
353
354struct wl_buffer *
355display_get_buffer_for_surface(struct display *display,
356 cairo_surface_t *surface)
357{
358 struct surface_data *data;
359
360 data = cairo_surface_get_user_data (surface, &surface_data_key);
361
362 return data->buffer;
363}
364
365struct shm_surface_data {
366 struct surface_data data;
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700367 struct shm_pool *pool;
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400368};
369
Kristian Høgsberg06bc2642010-12-01 09:50:16 -0500370static void
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700371shm_pool_destroy(struct shm_pool *pool);
372
373static void
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400374shm_surface_data_destroy(void *p)
375{
376 struct shm_surface_data *data = p;
377
378 wl_buffer_destroy(data->data.buffer);
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700379 if (data->pool)
380 shm_pool_destroy(data->pool);
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400381}
382
Ander Conselvan de Oliveira1493d2a2012-05-03 12:29:46 +0300383static void
384shm_surface_write(cairo_surface_t *surface, unsigned char *data, int count)
385{
386 void *dest = cairo_image_surface_get_data(surface);
387
388 memcpy(dest, data, count);
389}
390
Kristian Høgsberg16626282012-04-03 11:21:27 -0400391static struct wl_shm_pool *
392make_shm_pool(struct display *display, int size, void **data)
393{
394 char filename[] = "/tmp/wayland-shm-XXXXXX";
395 struct wl_shm_pool *pool;
396 int fd;
397
398 fd = mkstemp(filename);
399 if (fd < 0) {
400 fprintf(stderr, "open %s failed: %m\n", filename);
401 return NULL;
402 }
403 if (ftruncate(fd, size) < 0) {
404 fprintf(stderr, "ftruncate failed: %m\n");
405 close(fd);
406 return NULL;
407 }
408
409 *data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
410 unlink(filename);
411
412 if (*data == MAP_FAILED) {
413 fprintf(stderr, "mmap failed: %m\n");
414 close(fd);
415 return NULL;
416 }
417
418 pool = wl_shm_create_pool(display->shm, fd, size);
419
420 close(fd);
421
422 return pool;
423}
424
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700425static struct shm_pool *
426shm_pool_create(struct display *display, size_t size)
427{
428 struct shm_pool *pool = malloc(sizeof *pool);
429
430 if (!pool)
431 return NULL;
432
433 pool->pool = make_shm_pool(display, size, &pool->data);
434 if (!pool->pool) {
435 free(pool);
436 return NULL;
437 }
438
439 pool->size = size;
440 pool->used = 0;
441
442 return pool;
443}
444
445static void *
446shm_pool_allocate(struct shm_pool *pool, size_t size, int *offset)
447{
448 if (pool->used + size > pool->size)
449 return NULL;
450
451 *offset = pool->used;
452 pool->used += size;
453
454 return (char *) pool->data + *offset;
455}
456
457/* destroy the pool. this does not unmap the memory though */
458static void
459shm_pool_destroy(struct shm_pool *pool)
460{
461 munmap(pool->data, pool->size);
462 wl_shm_pool_destroy(pool->pool);
463 free(pool);
464}
465
466/* Start allocating from the beginning of the pool again */
467static void
468shm_pool_reset(struct shm_pool *pool)
469{
470 pool->used = 0;
471}
472
473static int
474data_length_for_shm_surface(struct rectangle *rect)
475{
476 int stride;
477
478 stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32,
479 rect->width);
480 return stride * rect->height;
481}
482
Kristian Høgsberg06bc2642010-12-01 09:50:16 -0500483static cairo_surface_t *
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700484display_create_shm_surface_from_pool(struct display *display,
485 struct rectangle *rectangle,
486 uint32_t flags, struct shm_pool *pool)
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400487{
488 struct shm_surface_data *data;
Kristian Høgsbergf389cac2011-08-31 16:21:38 -0400489 uint32_t format;
Kristian Høgsberg3be87d12011-05-13 13:45:17 -0400490 cairo_surface_t *surface;
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700491 int stride, length, offset;
Kristian Høgsberg1103a1a2012-04-03 12:00:48 -0400492 void *map;
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400493
494 data = malloc(sizeof *data);
495 if (data == NULL)
496 return NULL;
497
498 stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32,
499 rectangle->width);
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700500 length = stride * rectangle->height;
501 data->pool = NULL;
502 map = shm_pool_allocate(pool, length, &offset);
503
504 if (!map) {
505 free(data);
506 return NULL;
Kristian Høgsberg1103a1a2012-04-03 12:00:48 -0400507 }
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400508
Kristian Høgsberg1103a1a2012-04-03 12:00:48 -0400509 surface = cairo_image_surface_create_for_data (map,
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400510 CAIRO_FORMAT_ARGB32,
511 rectangle->width,
512 rectangle->height,
513 stride);
514
515 cairo_surface_set_user_data (surface, &surface_data_key,
516 data, shm_surface_data_destroy);
517
Kristian Høgsberg3be87d12011-05-13 13:45:17 -0400518 if (flags & SURFACE_OPAQUE)
Kristian Høgsberg8e81df42012-01-11 14:24:46 -0500519 format = WL_SHM_FORMAT_XRGB8888;
Kristian Høgsberg3be87d12011-05-13 13:45:17 -0400520 else
Kristian Høgsberg8e81df42012-01-11 14:24:46 -0500521 format = WL_SHM_FORMAT_ARGB8888;
Kristian Høgsberg3be87d12011-05-13 13:45:17 -0400522
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700523 data->data.buffer = wl_shm_pool_create_buffer(pool->pool, offset,
Kristian Høgsberg16626282012-04-03 11:21:27 -0400524 rectangle->width,
525 rectangle->height,
526 stride, format);
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400527
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700528 return surface;
529}
530
531static cairo_surface_t *
532display_create_shm_surface(struct display *display,
533 struct rectangle *rectangle, uint32_t flags,
534 struct window *window)
535{
536 struct shm_surface_data *data;
537 struct shm_pool *pool;
538 cairo_surface_t *surface;
539
540 if (window && window->pool) {
541 shm_pool_reset(window->pool);
542 surface = display_create_shm_surface_from_pool(display,
543 rectangle,
544 flags,
545 window->pool);
546 if (surface)
547 return surface;
548 }
549
550 pool = shm_pool_create(display,
551 data_length_for_shm_surface(rectangle));
552 if (!pool)
553 return NULL;
554
555 surface =
556 display_create_shm_surface_from_pool(display, rectangle,
557 flags, pool);
558
559 if (!surface) {
560 shm_pool_destroy(pool);
561 return NULL;
562 }
563
564 /* make sure we destroy the pool when the surface is destroyed */
565 data = cairo_surface_get_user_data(surface, &surface_data_key);
566 data->pool = pool;
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400567
568 return surface;
569}
570
nobled7b87cb02011-02-01 18:51:47 +0000571static int
572check_size(struct rectangle *rect)
573{
574 if (rect->width && rect->height)
575 return 0;
576
577 fprintf(stderr, "tried to create surface of "
578 "width: %d, height: %d\n", rect->width, rect->height);
579 return -1;
580}
581
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400582cairo_surface_t *
583display_create_surface(struct display *display,
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100584 struct wl_surface *surface,
Kristian Høgsberg3be87d12011-05-13 13:45:17 -0400585 struct rectangle *rectangle,
586 uint32_t flags)
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400587{
nobled7b87cb02011-02-01 18:51:47 +0000588 if (check_size(rectangle) < 0)
589 return NULL;
Kristian Høgsberg8def2642011-01-14 17:41:33 -0500590#ifdef HAVE_CAIRO_EGL
Kristian Høgsberg5990fbb2012-04-10 16:55:11 -0400591 if (display->dpy)
592 return display_create_egl_window_surface(display,
593 surface,
594 flags,
595 rectangle);
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400596#endif
Kristian Høgsberg1103a1a2012-04-03 12:00:48 -0400597 return display_create_shm_surface(display, rectangle, flags, NULL);
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400598}
599
Ander Conselvan de Oliveira1493d2a2012-05-03 12:29:46 +0300600static const char *cursors[] = {
601 "bottom_left_corner",
602 "bottom_right_corner",
603 "bottom_side",
604 "grabbing",
605 "left_ptr",
606 "left_side",
607 "right_side",
608 "top_left_corner",
609 "top_right_corner",
610 "top_side",
611 "xterm",
612 "hand1",
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400613};
614
615static void
Ander Conselvan de Oliveira1493d2a2012-05-03 12:29:46 +0300616create_cursor_from_images(struct display *display, struct cursor *cursor,
617 XcursorImages *images)
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400618{
Ander Conselvan de Oliveira1493d2a2012-05-03 12:29:46 +0300619 int i;
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400620 struct rectangle rect;
Ander Conselvan de Oliveira1493d2a2012-05-03 12:29:46 +0300621 XcursorImage *image;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400622
Ander Conselvan de Oliveira1493d2a2012-05-03 12:29:46 +0300623 cursor->images = malloc(images->nimage * sizeof *cursor->images);
624 cursor->n_images = images->nimage;
625
626 for (i = 0; i < images->nimage; i++) {
627 image = images->images[i];
628
629 rect.width = image->width;
630 rect.height = image->height;
631
632 cursor->images[i].surface =
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700633 display_create_shm_surface_from_pool(display, &rect, 0,
634 display->cursor_shm_pool);
Ander Conselvan de Oliveira1493d2a2012-05-03 12:29:46 +0300635
636 shm_surface_write(cursor->images[i].surface,
637 (unsigned char *) image->pixels,
638 image->width * image->height * sizeof image->pixels[0]);
639
640 cursor->images[i].width = image->width;
641 cursor->images[i].height = image->height;
642 cursor->images[i].hotspot_x = image->xhot;
643 cursor->images[i].hotspot_y = image->yhot;
644 cursor->images[i].delay = image->delay;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400645 }
646
647}
648
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700649static size_t
650data_length_for_cursor_images(XcursorImages *images)
651{
652 int i;
653 size_t length = 0;
654 struct rectangle rect;
655
656 for (i = 0; i < images->nimage; i++) {
657 rect.width = images->images[i]->width;
658 rect.height = images->images[i]->height;
659 length += data_length_for_shm_surface(&rect);
660 }
661
662 return length;
663}
664
Pekka Paalanen325bb602011-12-19 10:31:45 +0200665static void
Ander Conselvan de Oliveira1493d2a2012-05-03 12:29:46 +0300666create_cursors(struct display *display)
667{
668 int i, count;
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700669 size_t pool_size = 0;
Ander Conselvan de Oliveira1493d2a2012-05-03 12:29:46 +0300670 struct cursor *cursor;
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700671 XcursorImages **images;
Ander Conselvan de Oliveira1493d2a2012-05-03 12:29:46 +0300672
673 count = ARRAY_LENGTH(cursors);
674 display->cursors = malloc(count * sizeof *display->cursors);
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700675 images = malloc(count * sizeof images[0]);
Ander Conselvan de Oliveira1493d2a2012-05-03 12:29:46 +0300676
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700677 for (i = 0; i < count; i++) {
678 images[i] = XcursorLibraryLoadImages(cursors[i], NULL, 32);
Ander Conselvan de Oliveira1493d2a2012-05-03 12:29:46 +0300679 if (!images) {
680 fprintf(stderr, "Error loading cursor: %s\n",
681 cursors[i]);
682 continue;
683 }
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700684 pool_size += data_length_for_cursor_images(images[i]);
Ander Conselvan de Oliveira1493d2a2012-05-03 12:29:46 +0300685 }
686
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700687 display->cursor_shm_pool = shm_pool_create(display, pool_size);
688
689 for (i = 0; i < count; i++) {
690 if (!images)
691 continue;
692
693 cursor = &display->cursors[i];
694 create_cursor_from_images(display, cursor, images[i]);
695
696 XcursorImagesDestroy(images[i]);
697 }
698
699 free(images);
Ander Conselvan de Oliveira1493d2a2012-05-03 12:29:46 +0300700}
701
702static void
703destroy_cursor_images(struct cursor *cursor)
704{
705 int i;
706
707 for (i = 0; i < cursor->n_images; i++)
708 if (cursor->images[i].surface)
709 cairo_surface_destroy(cursor->images[i].surface);
710
711 free(cursor->images);
712}
713
714static void
715destroy_cursors(struct display *display)
Pekka Paalanen325bb602011-12-19 10:31:45 +0200716{
717 int i, count;
718
Ander Conselvan de Oliveira1493d2a2012-05-03 12:29:46 +0300719 count = ARRAY_LENGTH(cursors);
Pekka Paalanen325bb602011-12-19 10:31:45 +0200720 for (i = 0; i < count; ++i) {
Ander Conselvan de Oliveira1493d2a2012-05-03 12:29:46 +0300721 destroy_cursor_images(&display->cursors[i]);
Pekka Paalanen325bb602011-12-19 10:31:45 +0200722 }
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700723
Ander Conselvan de Oliveira1493d2a2012-05-03 12:29:46 +0300724 free(display->cursors);
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -0700725 shm_pool_destroy(display->cursor_shm_pool);
Pekka Paalanen325bb602011-12-19 10:31:45 +0200726}
727
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400728cairo_surface_t *
729display_get_pointer_surface(struct display *display, int pointer,
730 int *width, int *height,
731 int *hotspot_x, int *hotspot_y)
732{
Ander Conselvan de Oliveira1493d2a2012-05-03 12:29:46 +0300733 struct cursor *cursor = &display->cursors[pointer];
734 cairo_surface_t *surface = cursor->images[0].surface;
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400735
Ander Conselvan de Oliveira1493d2a2012-05-03 12:29:46 +0300736 /* FIXME returning information for the first image. Something better
737 * is needed for animated cursors */
738
nobledf8475c92011-01-05 17:41:55 +0000739 *width = cairo_image_surface_get_width(surface);
740 *height = cairo_image_surface_get_height(surface);
Ander Conselvan de Oliveira1493d2a2012-05-03 12:29:46 +0300741
742 *hotspot_x = cursor->images[0].hotspot_x;
743 *hotspot_y = cursor->images[0].hotspot_y;
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400744
745 return cairo_surface_reference(surface);
746}
747
Kristian Høgsberg9d69f8e2010-09-03 14:46:38 -0400748static void
Benjamin Franzke14f7ff92011-06-23 12:10:51 +0200749window_get_resize_dx_dy(struct window *window, int *x, int *y)
750{
751 if (window->resize_edges & WINDOW_RESIZING_LEFT)
752 *x = window->server_allocation.width - window->allocation.width;
753 else
754 *x = 0;
755
756 if (window->resize_edges & WINDOW_RESIZING_TOP)
757 *y = window->server_allocation.height -
758 window->allocation.height;
759 else
760 *y = 0;
761
762 window->resize_edges = 0;
763}
764
765static void
Kristian Høgsberg6a1b2012009-12-16 14:43:37 -0500766window_attach_surface(struct window *window)
767{
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -0400768 struct display *display = window->display;
769 struct wl_buffer *buffer;
Benjamin Franzke22d54812011-07-16 19:50:32 +0000770#ifdef HAVE_CAIRO_EGL
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100771 struct egl_window_surface_data *data;
Benjamin Franzke22d54812011-07-16 19:50:32 +0000772#endif
Kristian Høgsberg82da52b2010-12-17 09:53:12 -0500773 int32_t x, y;
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100774
Kristian Høgsberg407ef642012-04-27 17:17:12 -0400775 if (window->type == TYPE_NONE) {
776 window->type = TYPE_TOPLEVEL;
777 if (display->shell)
778 wl_shell_surface_set_toplevel(window->shell_surface);
779 }
780
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100781 switch (window->buffer_type) {
Benjamin Franzke22d54812011-07-16 19:50:32 +0000782#ifdef HAVE_CAIRO_EGL
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100783 case WINDOW_BUFFER_TYPE_EGL_WINDOW:
784 data = cairo_surface_get_user_data(window->cairo_surface,
785 &surface_data_key);
786
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100787 cairo_gl_surface_swapbuffers(window->cairo_surface);
788 wl_egl_window_get_attached_size(data->window,
789 &window->server_allocation.width,
790 &window->server_allocation.height);
791 break;
Benjamin Franzke22d54812011-07-16 19:50:32 +0000792#endif
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100793 case WINDOW_BUFFER_TYPE_SHM:
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100794 buffer =
795 display_get_buffer_for_surface(display,
Kristian Høgsberg6e2a8d72012-04-10 11:23:13 -0400796 window->cairo_surface);
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100797
Ander Conselvan de Oliveirae018b042012-01-27 17:17:39 +0200798 window_get_resize_dx_dy(window, &x, &y);
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100799 wl_surface_attach(window->surface, buffer, x, y);
Kristian Høgsberg6e2a8d72012-04-10 11:23:13 -0400800 wl_surface_damage(window->surface, 0, 0,
801 window->allocation.width,
802 window->allocation.height);
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100803 window->server_allocation = window->allocation;
Kristian Høgsberg6e2a8d72012-04-10 11:23:13 -0400804 cairo_surface_destroy(window->cairo_surface);
805 window->cairo_surface = NULL;
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100806 break;
Benjamin Franzke22d54812011-07-16 19:50:32 +0000807 default:
808 return;
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100809 }
Kristian Høgsberg82da52b2010-12-17 09:53:12 -0500810
Kristian Høgsberg63e5e062012-03-04 23:47:56 -0500811 if (window->input_region) {
812 wl_surface_set_input_region(window->surface,
813 window->input_region);
814 wl_region_destroy(window->input_region);
815 window->input_region = NULL;
816 }
817
818 if (window->opaque_region) {
819 wl_surface_set_opaque_region(window->surface,
820 window->opaque_region);
821 wl_region_destroy(window->opaque_region);
822 window->opaque_region = NULL;
823 }
Kristian Høgsberg6a1b2012009-12-16 14:43:37 -0500824}
825
Kristian Høgsberga341fa02010-01-24 18:10:15 -0500826void
Kristian Høgsberg9d69f8e2010-09-03 14:46:38 -0400827window_flush(struct window *window)
Kristian Høgsberga341fa02010-01-24 18:10:15 -0500828{
Kristian Høgsberg9629fe32012-03-26 15:56:39 -0400829 if (window->cairo_surface)
Benjamin Franzkebde55ec2011-03-07 15:08:09 +0100830 window_attach_surface(window);
Kristian Høgsberga341fa02010-01-24 18:10:15 -0500831}
832
Kristian Høgsberg012a0072010-10-26 00:02:20 -0400833void
834window_set_surface(struct window *window, cairo_surface_t *surface)
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400835{
Kristian Høgsberg2b43bd72010-11-08 15:45:55 -0500836 cairo_surface_reference(surface);
837
Kristian Høgsberg012a0072010-10-26 00:02:20 -0400838 if (window->cairo_surface != NULL)
839 cairo_surface_destroy(window->cairo_surface);
840
Kristian Høgsberg2b43bd72010-11-08 15:45:55 -0500841 window->cairo_surface = surface;
Kristian Høgsberg012a0072010-10-26 00:02:20 -0400842}
843
Benjamin Franzke22d54812011-07-16 19:50:32 +0000844#ifdef HAVE_CAIRO_EGL
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100845static void
846window_resize_cairo_window_surface(struct window *window)
847{
848 struct egl_window_surface_data *data;
Benjamin Franzke14f7ff92011-06-23 12:10:51 +0200849 int x, y;
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100850
851 data = cairo_surface_get_user_data(window->cairo_surface,
852 &surface_data_key);
853
Benjamin Franzke14f7ff92011-06-23 12:10:51 +0200854 window_get_resize_dx_dy(window, &x, &y),
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100855 wl_egl_window_resize(data->window,
856 window->allocation.width,
Benjamin Franzke14f7ff92011-06-23 12:10:51 +0200857 window->allocation.height,
858 x,y);
859
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100860 cairo_gl_surface_set_size(window->cairo_surface,
861 window->allocation.width,
862 window->allocation.height);
863}
Benjamin Franzke22d54812011-07-16 19:50:32 +0000864#endif
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100865
Kristian Høgsbergbcee9a42011-10-12 00:36:16 -0400866struct display *
867window_get_display(struct window *window)
868{
869 return window->display;
870}
871
Kristian Høgsberg012a0072010-10-26 00:02:20 -0400872void
873window_create_surface(struct window *window)
874{
875 cairo_surface_t *surface;
Kristian Høgsberg3be87d12011-05-13 13:45:17 -0400876 uint32_t flags = 0;
877
878 if (!window->transparent)
879 flags = SURFACE_OPAQUE;
880
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400881 switch (window->buffer_type) {
Kristian Høgsberg8def2642011-01-14 17:41:33 -0500882#ifdef HAVE_CAIRO_EGL
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100883 case WINDOW_BUFFER_TYPE_EGL_WINDOW:
884 if (window->cairo_surface) {
885 window_resize_cairo_window_surface(window);
886 return;
887 }
888 surface = display_create_surface(window->display,
889 window->surface,
Kristian Høgsberg3be87d12011-05-13 13:45:17 -0400890 &window->allocation, flags);
Benjamin Franzke6693ac22011-02-10 12:04:30 +0100891 break;
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400892#endif
893 case WINDOW_BUFFER_TYPE_SHM:
Kristian Høgsberg012a0072010-10-26 00:02:20 -0400894 surface = display_create_shm_surface(window->display,
Kristian Høgsberg1103a1a2012-04-03 12:00:48 -0400895 &window->allocation,
896 flags, window);
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400897 break;
Bryce Harrington515f63a2010-11-19 12:14:55 -0800898 default:
899 surface = NULL;
900 break;
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400901 }
Kristian Høgsberg012a0072010-10-26 00:02:20 -0400902
903 window_set_surface(window, surface);
904 cairo_surface_destroy(surface);
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400905}
906
Pekka Paalanen4dde2fc2012-01-19 13:33:50 +0200907static void frame_destroy(struct frame *frame);
908
Kristian Høgsberge968f9c2010-08-27 22:18:00 -0400909void
Kristian Høgsberg248c1b62011-01-21 18:03:15 -0500910window_destroy(struct window *window)
911{
Pekka Paalanen77cbc952011-11-15 13:34:55 +0200912 struct display *display = window->display;
913 struct input *input;
914
915 if (window->redraw_scheduled)
916 wl_list_remove(&window->redraw_task.link);
917
918 wl_list_for_each(input, &display->input_list, link) {
919 if (input->pointer_focus == window)
920 input->pointer_focus = NULL;
921 if (input->keyboard_focus == window)
922 input->keyboard_focus = NULL;
Kristian Høgsbergae6e2712012-01-26 11:09:20 -0500923 if (input->focus_widget &&
924 input->focus_widget->window == window)
925 input->focus_widget = NULL;
Pekka Paalanen77cbc952011-11-15 13:34:55 +0200926 }
927
Kristian Høgsberg010f98b2012-02-23 17:30:45 -0500928 if (window->input_region)
929 wl_region_destroy(window->input_region);
930 if (window->opaque_region)
931 wl_region_destroy(window->opaque_region);
932
Pekka Paalanen4dde2fc2012-01-19 13:33:50 +0200933 if (window->frame)
934 frame_destroy(window->frame);
935
Pekka Paalanen6b2dc912011-11-29 10:25:08 +0200936 if (window->shell_surface)
937 wl_shell_surface_destroy(window->shell_surface);
Kristian Høgsberg248c1b62011-01-21 18:03:15 -0500938 wl_surface_destroy(window->surface);
939 wl_list_remove(&window->link);
Pekka Paalanen5ec65852011-12-16 10:09:29 +0200940
941 if (window->cairo_surface != NULL)
942 cairo_surface_destroy(window->cairo_surface);
Pekka Paalanen5ec65852011-12-16 10:09:29 +0200943
944 free(window->title);
Kristian Høgsberg248c1b62011-01-21 18:03:15 -0500945 free(window);
946}
947
Kristian Høgsbergc51f7992012-01-08 15:09:53 -0500948static struct widget *
Kristian Høgsberg441338c2012-01-10 13:52:34 -0500949widget_find_widget(struct widget *widget, int32_t x, int32_t y)
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400950{
Kristian Høgsberg441338c2012-01-10 13:52:34 -0500951 struct widget *child, *target;
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400952
Kristian Høgsberg441338c2012-01-10 13:52:34 -0500953 wl_list_for_each(child, &widget->child_list, link) {
954 target = widget_find_widget(child, x, y);
955 if (target)
956 return target;
957 }
958
959 if (widget->allocation.x <= x &&
960 x < widget->allocation.x + widget->allocation.width &&
961 widget->allocation.y <= y &&
962 y < widget->allocation.y + widget->allocation.height) {
963 return widget;
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400964 }
965
966 return NULL;
967}
968
Kristian Høgsberg441338c2012-01-10 13:52:34 -0500969static struct widget *
970widget_create(struct window *window, void *data)
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400971{
Kristian Høgsbergc51f7992012-01-08 15:09:53 -0500972 struct widget *widget;
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400973
Kristian Høgsbergc51f7992012-01-08 15:09:53 -0500974 widget = malloc(sizeof *widget);
975 memset(widget, 0, sizeof *widget);
Kristian Høgsberg9a13dab2012-01-08 15:18:19 -0500976 widget->window = window;
Kristian Høgsbergc51f7992012-01-08 15:09:53 -0500977 widget->user_data = data;
Kristian Høgsberg75bc6672012-01-10 09:43:58 -0500978 widget->allocation = window->allocation;
Kristian Høgsberg441338c2012-01-10 13:52:34 -0500979 wl_list_init(&widget->child_list);
Kristian Høgsberg010f98b2012-02-23 17:30:45 -0500980 widget->opaque = 0;
Kristian Høgsberg441338c2012-01-10 13:52:34 -0500981
982 return widget;
983}
984
985struct widget *
986window_add_widget(struct window *window, void *data)
987{
988 window->widget = widget_create(window, data);
989 wl_list_init(&window->widget->link);
990
991 return window->widget;
992}
993
994struct widget *
995widget_add_widget(struct widget *parent, void *data)
996{
997 struct widget *widget;
998
999 widget = widget_create(parent->window, data);
1000 wl_list_insert(parent->child_list.prev, &widget->link);
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001001
Kristian Høgsbergc51f7992012-01-08 15:09:53 -05001002 return widget;
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001003}
1004
1005void
Kristian Høgsberg441338c2012-01-10 13:52:34 -05001006widget_destroy(struct widget *widget)
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001007{
Pekka Paalanene156fb62012-01-19 13:51:38 +02001008 struct display *display = widget->window->display;
1009 struct input *input;
1010
1011 wl_list_for_each(input, &display->input_list, link) {
1012 if (input->focus_widget == widget)
1013 input->focus_widget = NULL;
1014 }
1015
Kristian Høgsberg441338c2012-01-10 13:52:34 -05001016 wl_list_remove(&widget->link);
1017 free(widget);
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001018}
1019
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001020void
Kristian Høgsbergc51f7992012-01-08 15:09:53 -05001021widget_get_allocation(struct widget *widget, struct rectangle *allocation)
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001022{
Kristian Høgsbergc51f7992012-01-08 15:09:53 -05001023 *allocation = widget->allocation;
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001024}
1025
1026void
Kristian Høgsbergbb977002012-01-10 19:11:42 -05001027widget_set_size(struct widget *widget, int32_t width, int32_t height)
1028{
Kristian Høgsbergbb977002012-01-10 19:11:42 -05001029 widget->allocation.width = width;
1030 widget->allocation.height = height;
Kristian Høgsbergbb977002012-01-10 19:11:42 -05001031}
1032
1033void
Kristian Høgsbergc51f7992012-01-08 15:09:53 -05001034widget_set_allocation(struct widget *widget,
1035 int32_t x, int32_t y, int32_t width, int32_t height)
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001036{
Kristian Høgsbergc51f7992012-01-08 15:09:53 -05001037 widget->allocation.x = x;
1038 widget->allocation.y = y;
Tiago Vignattic5528d82012-02-09 19:06:55 +02001039 widget_set_size(widget, width, height);
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001040}
1041
Kristian Høgsberg010f98b2012-02-23 17:30:45 -05001042void
1043widget_set_transparent(struct widget *widget, int transparent)
1044{
1045 widget->opaque = !transparent;
1046}
1047
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001048void *
Kristian Høgsbergc51f7992012-01-08 15:09:53 -05001049widget_get_user_data(struct widget *widget)
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001050{
Kristian Høgsbergc51f7992012-01-08 15:09:53 -05001051 return widget->user_data;
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001052}
1053
Kristian Høgsberg248c1b62011-01-21 18:03:15 -05001054void
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -05001055widget_set_resize_handler(struct widget *widget,
1056 widget_resize_handler_t handler)
1057{
1058 widget->resize_handler = handler;
1059}
1060
1061void
1062widget_set_redraw_handler(struct widget *widget,
1063 widget_redraw_handler_t handler)
1064{
1065 widget->redraw_handler = handler;
1066}
1067
1068void
Kristian Høgsbergee143232012-01-09 08:42:24 -05001069widget_set_enter_handler(struct widget *widget, widget_enter_handler_t handler)
Kristian Høgsberg9a13dab2012-01-08 15:18:19 -05001070{
Kristian Høgsbergee143232012-01-09 08:42:24 -05001071 widget->enter_handler = handler;
1072}
1073
1074void
1075widget_set_leave_handler(struct widget *widget, widget_leave_handler_t handler)
1076{
1077 widget->leave_handler = handler;
Kristian Høgsberg9a13dab2012-01-08 15:18:19 -05001078}
1079
1080void
Kristian Høgsberg04e98342012-01-09 09:36:16 -05001081widget_set_motion_handler(struct widget *widget,
1082 widget_motion_handler_t handler)
1083{
1084 widget->motion_handler = handler;
1085}
1086
1087void
Kristian Høgsberga8a0db32012-01-09 11:12:05 -05001088widget_set_button_handler(struct widget *widget,
1089 widget_button_handler_t handler)
1090{
1091 widget->button_handler = handler;
1092}
1093
1094void
Kristian Høgsberg9a13dab2012-01-08 15:18:19 -05001095widget_schedule_redraw(struct widget *widget)
1096{
1097 window_schedule_redraw(widget->window);
1098}
1099
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -04001100cairo_surface_t *
1101window_get_surface(struct window *window)
1102{
Kristian Høgsberg012a0072010-10-26 00:02:20 -04001103 return cairo_surface_reference(window->cairo_surface);
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -04001104}
1105
Benjamin Franzkeec4d3422011-03-14 12:07:26 +01001106struct wl_surface *
1107window_get_wl_surface(struct window *window)
1108{
1109 return window->surface;
1110}
1111
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02001112struct wl_shell_surface *
1113window_get_wl_shell_surface(struct window *window)
1114{
1115 return window->shell_surface;
1116}
1117
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001118static void
1119frame_resize_handler(struct widget *widget,
1120 int32_t width, int32_t height, void *data)
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04001121{
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001122 struct frame *frame = data;
1123 struct widget *child = frame->child;
1124 struct rectangle allocation;
Kristian Høgsberg010f98b2012-02-23 17:30:45 -05001125 struct display *display = widget->window->display;
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001126 int decoration_width, decoration_height;
Kristian Høgsberg010f98b2012-02-23 17:30:45 -05001127 int opaque_margin;
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001128
Kristian Høgsbergb435e842012-03-05 20:38:08 -05001129 if (widget->window->type != TYPE_FULLSCREEN) {
Kristian Høgsbergb8abe7e2012-03-20 23:56:05 -04001130 decoration_width = (frame->width + frame->margin) * 2;
1131 decoration_height = frame->width +
1132 frame->titlebar_height + frame->margin * 2;
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001133
Kristian Høgsbergb8abe7e2012-03-20 23:56:05 -04001134 allocation.x = frame->width + frame->margin;
1135 allocation.y = frame->titlebar_height + frame->margin;
Kristian Høgsberg2675dc12012-02-16 22:57:21 -05001136 allocation.width = width - decoration_width;
1137 allocation.height = height - decoration_height;
Kristian Høgsberg010f98b2012-02-23 17:30:45 -05001138
1139 widget->window->input_region =
1140 wl_compositor_create_region(display->compositor);
1141 wl_region_add(widget->window->input_region,
1142 frame->margin, frame->margin,
1143 width - 2 * frame->margin,
1144 height - 2 * frame->margin);
1145
1146 opaque_margin = frame->margin + display->frame_radius;
Kristian Høgsberg2675dc12012-02-16 22:57:21 -05001147 } else {
1148 decoration_width = 0;
1149 decoration_height = 0;
1150
1151 allocation.x = 0;
1152 allocation.y = 0;
1153 allocation.width = width;
1154 allocation.height = height;
Kristian Høgsberg010f98b2012-02-23 17:30:45 -05001155 opaque_margin = 0;
1156 }
1157
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001158 widget_set_allocation(child, allocation.x, allocation.y,
1159 allocation.width, allocation.height);
1160
1161 if (child->resize_handler)
1162 child->resize_handler(child,
1163 allocation.width,
1164 allocation.height,
1165 child->user_data);
1166
1167 widget_set_allocation(widget, 0, 0,
1168 child->allocation.width + decoration_width,
1169 child->allocation.height + decoration_height);
Kristian Høgsbergf10df852012-02-28 21:52:12 -05001170
1171 if (child->opaque) {
1172 widget->window->opaque_region =
1173 wl_compositor_create_region(display->compositor);
1174 wl_region_add(widget->window->opaque_region,
1175 opaque_margin, opaque_margin,
1176 widget->allocation.width - 2 * opaque_margin,
1177 widget->allocation.height - 2 * opaque_margin);
1178 }
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001179}
1180
1181static void
1182frame_redraw_handler(struct widget *widget, void *data)
1183{
1184 struct frame *frame = data;
1185 cairo_t *cr;
1186 cairo_text_extents_t extents;
1187 cairo_surface_t *source;
Kristian Høgsbergec323d22012-03-21 01:07:49 -04001188 int x, y, width, height;
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001189 struct window *window = widget->window;
1190
Kristian Høgsberg2675dc12012-02-16 22:57:21 -05001191 if (window->type == TYPE_FULLSCREEN)
1192 return;
1193
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001194 width = widget->allocation.width;
1195 height = widget->allocation.height;
1196
1197 cr = cairo_create(window->cairo_surface);
1198
1199 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
1200 cairo_set_source_rgba(cr, 0, 0, 0, 0);
1201 cairo_paint(cr);
1202
Kristian Høgsbergec323d22012-03-21 01:07:49 -04001203 cairo_set_source_rgba(cr, 0, 0, 0, 0.45);
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001204 tile_mask(cr, window->display->shadow,
Kristian Høgsbergec323d22012-03-21 01:07:49 -04001205 2, 2, width + 8, height + 8,
1206 64, 64);
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001207
1208 if (window->keyboard_device)
1209 source = window->display->active_frame;
1210 else
1211 source = window->display->inactive_frame;
1212
Kristian Høgsbergec323d22012-03-21 01:07:49 -04001213 tile_source(cr, source,
1214 frame->margin, frame->margin,
1215 width - frame->margin * 2, height - frame->margin * 2,
1216 frame->width, frame->titlebar_height);
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001217
1218 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
Kristian Høgsbergb8abe7e2012-03-20 23:56:05 -04001219 cairo_select_font_face(cr, "sans",
1220 CAIRO_FONT_SLANT_NORMAL,
1221 CAIRO_FONT_WEIGHT_BOLD);
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001222 cairo_set_font_size(cr, 14);
1223 cairo_text_extents(cr, window->title, &extents);
Kristian Høgsbergb8abe7e2012-03-20 23:56:05 -04001224 x = (width - extents.width) / 2;
Kristian Høgsbergec323d22012-03-21 01:07:49 -04001225 y = frame->margin + 8 - extents.y_bearing;
Kristian Høgsbergb8abe7e2012-03-20 23:56:05 -04001226 if (window->keyboard_device) {
1227 cairo_move_to(cr, x + 1, y + 1);
1228 cairo_set_source_rgb(cr, 1, 1, 1);
1229 cairo_show_text(cr, window->title);
1230 cairo_move_to(cr, x, y);
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001231 cairo_set_source_rgb(cr, 0, 0, 0);
Kristian Høgsbergb8abe7e2012-03-20 23:56:05 -04001232 cairo_show_text(cr, window->title);
1233 } else {
1234 cairo_move_to(cr, x, y);
1235 cairo_set_source_rgb(cr, 0.4, 0.4, 0.4);
1236 cairo_show_text(cr, window->title);
1237 }
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001238
1239 cairo_destroy(cr);
1240}
1241
1242static int
1243frame_get_pointer_location(struct frame *frame, int32_t x, int32_t y)
1244{
1245 struct widget *widget = frame->widget;
Kristian Høgsberg9a686242010-08-18 15:28:04 -04001246 int vlocation, hlocation, location;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04001247 const int grip_size = 8;
1248
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001249 if (x < frame->margin)
Kristian Høgsberg9a686242010-08-18 15:28:04 -04001250 hlocation = WINDOW_EXTERIOR;
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001251 else if (frame->margin <= x && x < frame->margin + grip_size)
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04001252 hlocation = WINDOW_RESIZING_LEFT;
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001253 else if (x < widget->allocation.width - frame->margin - grip_size)
Kristian Høgsberg9a686242010-08-18 15:28:04 -04001254 hlocation = WINDOW_INTERIOR;
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001255 else if (x < widget->allocation.width - frame->margin)
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04001256 hlocation = WINDOW_RESIZING_RIGHT;
1257 else
Kristian Høgsberg9a686242010-08-18 15:28:04 -04001258 hlocation = WINDOW_EXTERIOR;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04001259
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001260 if (y < frame->margin)
Kristian Høgsberg9a686242010-08-18 15:28:04 -04001261 vlocation = WINDOW_EXTERIOR;
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001262 else if (frame->margin <= y && y < frame->margin + grip_size)
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04001263 vlocation = WINDOW_RESIZING_TOP;
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001264 else if (y < widget->allocation.height - frame->margin - grip_size)
Kristian Høgsberg9a686242010-08-18 15:28:04 -04001265 vlocation = WINDOW_INTERIOR;
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001266 else if (y < widget->allocation.height - frame->margin)
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04001267 vlocation = WINDOW_RESIZING_BOTTOM;
1268 else
Kristian Høgsberg9a686242010-08-18 15:28:04 -04001269 vlocation = WINDOW_EXTERIOR;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04001270
Kristian Høgsberg9a686242010-08-18 15:28:04 -04001271 location = vlocation | hlocation;
1272 if (location & WINDOW_EXTERIOR)
1273 location = WINDOW_EXTERIOR;
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001274 if (location == WINDOW_INTERIOR && y < frame->margin + 50)
Kristian Høgsberg9a686242010-08-18 15:28:04 -04001275 location = WINDOW_TITLEBAR;
1276 else if (location == WINDOW_INTERIOR)
1277 location = WINDOW_CLIENT_AREA;
1278
1279 return location;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04001280}
1281
Kristian Høgsbergcd9ac1d2011-12-15 09:14:34 -05001282static int
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001283frame_get_pointer_image_for_location(struct frame *frame, struct input *input)
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04001284{
Kristian Høgsberg9a686242010-08-18 15:28:04 -04001285 int location;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04001286
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001287 location = frame_get_pointer_location(frame, input->sx, input->sy);
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04001288 switch (location) {
1289 case WINDOW_RESIZING_TOP:
Kristian Høgsbergcd9ac1d2011-12-15 09:14:34 -05001290 return POINTER_TOP;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04001291 case WINDOW_RESIZING_BOTTOM:
Kristian Høgsbergcd9ac1d2011-12-15 09:14:34 -05001292 return POINTER_BOTTOM;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04001293 case WINDOW_RESIZING_LEFT:
Kristian Høgsbergcd9ac1d2011-12-15 09:14:34 -05001294 return POINTER_LEFT;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04001295 case WINDOW_RESIZING_RIGHT:
Kristian Høgsbergcd9ac1d2011-12-15 09:14:34 -05001296 return POINTER_RIGHT;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04001297 case WINDOW_RESIZING_TOP_LEFT:
Kristian Høgsbergcd9ac1d2011-12-15 09:14:34 -05001298 return POINTER_TOP_LEFT;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04001299 case WINDOW_RESIZING_TOP_RIGHT:
Kristian Høgsbergcd9ac1d2011-12-15 09:14:34 -05001300 return POINTER_TOP_RIGHT;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04001301 case WINDOW_RESIZING_BOTTOM_LEFT:
Kristian Høgsbergcd9ac1d2011-12-15 09:14:34 -05001302 return POINTER_BOTTOM_LEFT;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04001303 case WINDOW_RESIZING_BOTTOM_RIGHT:
Kristian Høgsbergcd9ac1d2011-12-15 09:14:34 -05001304 return POINTER_BOTTOM_RIGHT;
Kristian Høgsberg9a686242010-08-18 15:28:04 -04001305 case WINDOW_EXTERIOR:
1306 case WINDOW_TITLEBAR:
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04001307 default:
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001308 return POINTER_LEFT_PTR;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04001309 }
Kristian Høgsbergcd9ac1d2011-12-15 09:14:34 -05001310}
1311
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001312static void
1313frame_menu_func(struct window *window, int index, void *data)
Kristian Høgsbergcd9ac1d2011-12-15 09:14:34 -05001314{
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001315 switch (index) {
1316 case 0: /* close */
1317 if (window->close_handler)
1318 window->close_handler(window->parent,
1319 window->user_data);
1320 else
1321 display_exit(window->display);
1322 break;
1323 case 1: /* fullscreen */
1324 /* we don't have a way to get out of fullscreen for now */
1325 window_set_fullscreen(window, 1);
1326 break;
1327 case 2: /* rotate */
1328 case 3: /* scale */
1329 break;
1330 }
1331}
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04001332
Kristian Høgsbergd31fcab2012-01-31 09:53:44 -05001333void
1334window_show_frame_menu(struct window *window,
1335 struct input *input, uint32_t time)
1336{
1337 int32_t x, y;
1338
1339 static const char *entries[] = {
1340 "Close", "Fullscreen", "Rotate", "Scale"
1341 };
1342
1343 input_get_position(input, &x, &y);
1344 window_show_menu(window->display, input, time, window,
1345 x - 10, y - 10, frame_menu_func, entries, 4);
1346}
1347
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001348static int
1349frame_enter_handler(struct widget *widget,
Daniel Stoneb230a7e2012-05-08 17:17:54 +01001350 struct input *input, GLfloat x, GLfloat y, void *data)
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001351{
1352 return frame_get_pointer_image_for_location(data, input);
1353}
Kristian Høgsberg7d804062010-09-07 21:50:06 -04001354
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001355static int
1356frame_motion_handler(struct widget *widget,
1357 struct input *input, uint32_t time,
Daniel Stoneb230a7e2012-05-08 17:17:54 +01001358 GLfloat x, GLfloat y, void *data)
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001359{
1360 return frame_get_pointer_image_for_location(data, input);
1361}
Rob Bradford8bd35c72011-10-25 12:20:51 +01001362
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001363static void
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001364frame_button_handler(struct widget *widget,
1365 struct input *input, uint32_t time,
Daniel Stone5d663712012-05-04 11:21:55 +01001366 uint32_t button, uint32_t state, void *data)
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001367
1368{
1369 struct frame *frame = data;
1370 struct window *window = widget->window;
Kristian Høgsberg1103a1a2012-04-03 12:00:48 -04001371 struct display *display = window->display;
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001372 int location;
Kristian Høgsberg1103a1a2012-04-03 12:00:48 -04001373
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001374 location = frame_get_pointer_location(frame, input->sx, input->sy);
1375
1376 if (window->display->shell && button == BTN_LEFT && state == 1) {
1377 switch (location) {
1378 case WINDOW_TITLEBAR:
1379 if (!window->shell_surface)
1380 break;
1381 input_set_pointer_image(input, time, POINTER_DRAGGING);
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001382 input_ungrab(input);
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001383 wl_shell_surface_move(window->shell_surface,
1384 input_get_input_device(input),
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001385 display->serial);
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001386 break;
1387 case WINDOW_RESIZING_TOP:
1388 case WINDOW_RESIZING_BOTTOM:
1389 case WINDOW_RESIZING_LEFT:
1390 case WINDOW_RESIZING_RIGHT:
1391 case WINDOW_RESIZING_TOP_LEFT:
1392 case WINDOW_RESIZING_TOP_RIGHT:
1393 case WINDOW_RESIZING_BOTTOM_LEFT:
1394 case WINDOW_RESIZING_BOTTOM_RIGHT:
1395 if (!window->shell_surface)
1396 break;
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001397 input_ungrab(input);
Kristian Høgsberg1103a1a2012-04-03 12:00:48 -04001398
1399 if (!display->dpy) {
1400 /* If we're using shm, allocate a big
1401 pool to create buffers out of while
1402 we resize. We should probably base
1403 this number on the size of the output. */
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -07001404 window->pool =
1405 shm_pool_create(display, 6 * 1024 * 1024);
Kristian Høgsberg1103a1a2012-04-03 12:00:48 -04001406 }
1407
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001408 wl_shell_surface_resize(window->shell_surface,
1409 input_get_input_device(input),
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001410 display->serial, location);
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001411 break;
1412 }
1413 } else if (button == BTN_RIGHT && state == 1) {
Kristian Høgsbergd31fcab2012-01-31 09:53:44 -05001414 window_show_frame_menu(window, input, time);
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001415 }
1416}
1417
1418struct widget *
1419frame_create(struct window *window, void *data)
1420{
1421 struct frame *frame;
1422
1423 frame = malloc(sizeof *frame);
1424 memset(frame, 0, sizeof *frame);
1425
1426 frame->widget = window_add_widget(window, frame);
1427 frame->child = widget_add_widget(frame->widget, data);
Kristian Høgsbergec323d22012-03-21 01:07:49 -04001428 frame->margin = 32;
Kristian Høgsbergb8abe7e2012-03-20 23:56:05 -04001429 frame->width = 4;
1430 frame->titlebar_height = 30
1431;
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001432 widget_set_redraw_handler(frame->widget, frame_redraw_handler);
1433 widget_set_resize_handler(frame->widget, frame_resize_handler);
1434 widget_set_enter_handler(frame->widget, frame_enter_handler);
1435 widget_set_motion_handler(frame->widget, frame_motion_handler);
1436 widget_set_button_handler(frame->widget, frame_button_handler);
1437
Pekka Paalanen4dde2fc2012-01-19 13:33:50 +02001438 window->frame = frame;
1439
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001440 return frame->child;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04001441}
1442
Kristian Høgsberge4feb562008-11-08 18:53:37 -05001443static void
Pekka Paalanen4dde2fc2012-01-19 13:33:50 +02001444frame_destroy(struct frame *frame)
1445{
1446 /* frame->child must be destroyed by the application */
1447 widget_destroy(frame->widget);
1448 free(frame);
1449}
1450
1451static void
Kristian Høgsbergb6323512012-01-11 00:04:42 -05001452input_set_focus_widget(struct input *input, struct widget *focus,
Daniel Stoneb230a7e2012-05-08 17:17:54 +01001453 GLfloat x, GLfloat y)
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001454{
Kristian Høgsberg831dd522012-01-10 23:46:33 -05001455 struct widget *old, *widget;
Kristian Høgsbergbb901fa2012-01-09 11:22:32 -05001456 int pointer = POINTER_LEFT_PTR;
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001457
Kristian Høgsbergb6323512012-01-11 00:04:42 -05001458 if (focus == input->focus_widget)
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001459 return;
1460
Kristian Høgsbergb6323512012-01-11 00:04:42 -05001461 old = input->focus_widget;
Kristian Høgsbergee143232012-01-09 08:42:24 -05001462 if (old) {
Kristian Høgsberg831dd522012-01-10 23:46:33 -05001463 widget = old;
1464 if (input->grab)
1465 widget = input->grab;
1466 if (widget->leave_handler)
1467 widget->leave_handler(old, input, widget->user_data);
Kristian Høgsbergb6323512012-01-11 00:04:42 -05001468 input->focus_widget = NULL;
Kristian Høgsbergee143232012-01-09 08:42:24 -05001469 }
1470
1471 if (focus) {
Kristian Høgsberg831dd522012-01-10 23:46:33 -05001472 widget = focus;
1473 if (input->grab)
1474 widget = input->grab;
1475 if (widget->enter_handler)
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001476 pointer = widget->enter_handler(focus, input, x, y,
Kristian Høgsberg831dd522012-01-10 23:46:33 -05001477 widget->user_data);
Kristian Høgsbergb6323512012-01-11 00:04:42 -05001478 input->focus_widget = focus;
Kristian Høgsbergbb901fa2012-01-09 11:22:32 -05001479
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001480 input_set_pointer_image(input, input->pointer_enter_serial,
1481 pointer);
Kristian Høgsbergee143232012-01-09 08:42:24 -05001482 }
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001483}
1484
1485static void
Kristian Høgsberg8a1d10d2011-12-21 17:11:45 -05001486input_handle_motion(void *data, struct wl_input_device *input_device,
Daniel Stone103db7f2012-05-08 17:17:55 +01001487 uint32_t time, wl_fixed_t sx_w, wl_fixed_t sy_w)
Kristian Høgsberg61017b12008-11-02 18:51:48 -05001488{
Kristian Høgsberg808fd412010-07-20 17:06:19 -04001489 struct input *input = data;
Kristian Høgsberg9a686242010-08-18 15:28:04 -04001490 struct window *window = input->pointer_focus;
Kristian Høgsbergc51f7992012-01-08 15:09:53 -05001491 struct widget *widget;
Kristian Høgsberg00439612011-01-25 15:16:01 -05001492 int pointer = POINTER_LEFT_PTR;
Daniel Stone103db7f2012-05-08 17:17:55 +01001493 GLfloat sx = wl_fixed_to_double(sx_w);
1494 GLfloat sy = wl_fixed_to_double(sy_w);
Kristian Høgsberg808fd412010-07-20 17:06:19 -04001495
Kristian Høgsberg808fd412010-07-20 17:06:19 -04001496 input->sx = sx;
1497 input->sy = sy;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04001498
Kristian Høgsberg831dd522012-01-10 23:46:33 -05001499 if (!(input->grab && input->grab_button)) {
Kristian Høgsberg441338c2012-01-10 13:52:34 -05001500 widget = widget_find_widget(window->widget, sx, sy);
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001501 input_set_focus_widget(input, widget, sx, sy);
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001502 }
1503
Kristian Høgsberg831dd522012-01-10 23:46:33 -05001504 if (input->grab)
1505 widget = input->grab;
1506 else
Kristian Høgsbergb6323512012-01-11 00:04:42 -05001507 widget = input->focus_widget;
Kristian Høgsberg04e98342012-01-09 09:36:16 -05001508 if (widget && widget->motion_handler)
Kristian Høgsbergb6323512012-01-11 00:04:42 -05001509 pointer = widget->motion_handler(input->focus_widget,
Kristian Høgsberg831dd522012-01-10 23:46:33 -05001510 input, time, sx, sy,
Kristian Høgsberg04e98342012-01-09 09:36:16 -05001511 widget->user_data);
Kristian Høgsberg9a686242010-08-18 15:28:04 -04001512
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04001513 input_set_pointer_image(input, time, pointer);
Kristian Høgsberg61017b12008-11-02 18:51:48 -05001514}
1515
Kristian Høgsberg831dd522012-01-10 23:46:33 -05001516void
1517input_grab(struct input *input, struct widget *widget, uint32_t button)
1518{
1519 input->grab = widget;
1520 input->grab_button = button;
1521}
1522
1523void
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001524input_ungrab(struct input *input)
Kristian Høgsberg831dd522012-01-10 23:46:33 -05001525{
1526 struct widget *widget;
1527
1528 input->grab = NULL;
1529 if (input->pointer_focus) {
1530 widget = widget_find_widget(input->pointer_focus->widget,
1531 input->sx, input->sy);
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001532 input_set_focus_widget(input, widget, input->sx, input->sy);
Kristian Høgsberg831dd522012-01-10 23:46:33 -05001533 }
1534}
1535
Kristian Høgsberg1d7ffd32010-08-25 16:34:05 -04001536static void
Kristian Høgsberg8a1d10d2011-12-21 17:11:45 -05001537input_handle_button(void *data,
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001538 struct wl_input_device *input_device, uint32_t serial,
Kristian Høgsberg8a1d10d2011-12-21 17:11:45 -05001539 uint32_t time, uint32_t button, uint32_t state)
Kristian Høgsberg94448c02008-12-30 11:03:33 -05001540{
Kristian Høgsberg808fd412010-07-20 17:06:19 -04001541 struct input *input = data;
Kristian Høgsbergc51f7992012-01-08 15:09:53 -05001542 struct widget *widget;
Kristian Høgsbergbf6ceda2010-06-14 20:25:06 -04001543
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001544 input->display->serial = serial;
Kristian Høgsbergb6323512012-01-11 00:04:42 -05001545 if (input->focus_widget && input->grab == NULL && state)
1546 input_grab(input, input->focus_widget, button);
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001547
Neil Roberts6b28aad2012-01-23 19:11:18 +00001548 widget = input->grab;
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001549 if (widget && widget->button_handler)
Neil Roberts6b28aad2012-01-23 19:11:18 +00001550 (*widget->button_handler)(widget,
1551 input, time,
1552 button, state,
1553 input->grab->user_data);
Kristian Høgsberge28d05b2011-09-20 21:43:54 -04001554
Kristian Høgsberg831dd522012-01-10 23:46:33 -05001555 if (input->grab && input->grab_button == button && !state)
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001556 input_ungrab(input);
Kristian Høgsberg94448c02008-12-30 11:03:33 -05001557}
1558
Kristian Høgsberg99f090d2009-02-23 22:37:14 -05001559static void
Scott Moreau210d0792012-03-22 10:47:01 -06001560input_handle_axis(void *data,
1561 struct wl_input_device *input_device,
1562 uint32_t time, uint32_t axis, int32_t value)
1563{
1564}
1565
1566static void
Kristian Høgsberg8a1d10d2011-12-21 17:11:45 -05001567input_handle_key(void *data, struct wl_input_device *input_device,
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001568 uint32_t serial, uint32_t time, uint32_t key, uint32_t state)
Kristian Høgsberg99f090d2009-02-23 22:37:14 -05001569{
Kristian Høgsberg808fd412010-07-20 17:06:19 -04001570 struct input *input = data;
1571 struct window *window = input->keyboard_focus;
Pekka Paalanena03a93c2011-11-28 16:13:57 +02001572 struct display *d = input->display;
Kristian Høgsberg70163132012-05-08 15:55:39 -04001573 uint32_t code, num_syms;
1574 const xkb_keysym_t *syms;
1575 xkb_keysym_t sym;
1576 xkb_mod_mask_t mask;
Kristian Høgsberg99f090d2009-02-23 22:37:14 -05001577
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001578 input->display->serial = serial;
Daniel Stone0d5a5092012-02-16 12:48:00 +00001579 code = key + 8;
Pekka Paalanena03a93c2011-11-28 16:13:57 +02001580 if (!window || window->keyboard_device != input)
Kristian Høgsberg99f090d2009-02-23 22:37:14 -05001581 return;
1582
Kristian Høgsberg70163132012-05-08 15:55:39 -04001583 num_syms = xkb_key_get_syms(d->xkb.state, code, &syms);
1584 xkb_state_update_key(d->xkb.state, code,
1585 state ? XKB_KEY_DOWN : XKB_KEY_UP);
Kristian Høgsberg99f090d2009-02-23 22:37:14 -05001586
Kristian Høgsberg70163132012-05-08 15:55:39 -04001587 mask = xkb_state_serialise_mods(d->xkb.state,
1588 XKB_STATE_DEPRESSED |
1589 XKB_STATE_LATCHED);
1590 input->modifiers = 0;
1591 if (mask & input->display->xkb.control_mask)
1592 input->modifiers |= MOD_CONTROL_MASK;
1593 if (mask & input->display->xkb.alt_mask)
1594 input->modifiers |= MOD_ALT_MASK;
1595 if (mask & input->display->xkb.shift_mask)
1596 input->modifiers |= MOD_SHIFT_MASK;
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -04001597
Kristian Høgsberg70163132012-05-08 15:55:39 -04001598 if (num_syms == 1 && syms[0] == XK_F5 &&
1599 input->modifiers == MOD_ALT_MASK) {
Kristian Høgsbergd6bcd7d2012-02-16 15:53:46 -05001600 if (state)
1601 window_set_maximized(window,
1602 window->type != TYPE_MAXIMIZED);
1603 } else if (window->key_handler) {
Kristian Høgsberg70163132012-05-08 15:55:39 -04001604 if (num_syms == 1)
1605 sym = syms[0];
1606 else
1607 sym = NoSymbol;
1608
Kristian Høgsbergd6bcd7d2012-02-16 15:53:46 -05001609 (*window->key_handler)(window, input, time, key,
1610 sym, state, window->user_data);
1611 }
Kristian Høgsberg94448c02008-12-30 11:03:33 -05001612}
1613
Kristian Høgsbergdb6c2f32009-02-22 21:51:24 -05001614static void
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001615input_remove_pointer_focus(struct input *input)
Pekka Paalanene1207c72011-12-16 12:02:09 +02001616{
1617 struct window *window = input->pointer_focus;
1618
1619 if (!window)
1620 return;
1621
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001622 input_set_focus_widget(input, NULL, 0, 0);
Pekka Paalanene1207c72011-12-16 12:02:09 +02001623
Pekka Paalanene1207c72011-12-16 12:02:09 +02001624 input->pointer_focus = NULL;
Ander Conselvan de Oliveira1493d2a2012-05-03 12:29:46 +03001625 input->current_cursor = POINTER_UNSET;
Pekka Paalanene1207c72011-12-16 12:02:09 +02001626}
1627
1628static void
Kristian Høgsberg06d58b72012-02-23 09:59:05 -05001629input_handle_pointer_enter(void *data,
Kristian Høgsberg8a1d10d2011-12-21 17:11:45 -05001630 struct wl_input_device *input_device,
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001631 uint32_t serial, struct wl_surface *surface,
Daniel Stone103db7f2012-05-08 17:17:55 +01001632 wl_fixed_t sx_w, wl_fixed_t sy_w)
Kristian Høgsbergdb6c2f32009-02-22 21:51:24 -05001633{
Kristian Høgsberg808fd412010-07-20 17:06:19 -04001634 struct input *input = data;
Kristian Høgsberg9a686242010-08-18 15:28:04 -04001635 struct window *window;
Kristian Høgsbergc51f7992012-01-08 15:09:53 -05001636 struct widget *widget;
Daniel Stone103db7f2012-05-08 17:17:55 +01001637 GLfloat sx = wl_fixed_to_double(sx_w);
1638 GLfloat sy = wl_fixed_to_double(sy_w);
Kristian Høgsberg808fd412010-07-20 17:06:19 -04001639
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001640 input->display->serial = serial;
1641 input->pointer_enter_serial = serial;
Kristian Høgsberg06d58b72012-02-23 09:59:05 -05001642 input->pointer_focus = wl_surface_get_user_data(surface);
Kristian Høgsberg900b2262011-09-06 14:33:52 -04001643 window = input->pointer_focus;
Kristian Høgsberg900b2262011-09-06 14:33:52 -04001644
Kristian Høgsberg1103a1a2012-04-03 12:00:48 -04001645 if (window->pool) {
Ander Conselvan de Oliveira001de542012-05-07 11:34:26 -07001646 shm_pool_destroy(window->pool);
Kristian Høgsberg1103a1a2012-04-03 12:00:48 -04001647 window->pool = NULL;
1648 /* Schedule a redraw to free the pool */
1649 window_schedule_redraw(window);
1650 }
1651
Kristian Høgsberg06d58b72012-02-23 09:59:05 -05001652 input->sx = sx;
1653 input->sy = sy;
Kristian Høgsberg9a686242010-08-18 15:28:04 -04001654
Kristian Høgsberg06d58b72012-02-23 09:59:05 -05001655 widget = widget_find_widget(window->widget, sx, sy);
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001656 input_set_focus_widget(input, widget, sx, sy);
Kristian Høgsberg06d58b72012-02-23 09:59:05 -05001657}
Kristian Høgsberg59826582011-01-20 11:56:57 -05001658
Kristian Høgsberg06d58b72012-02-23 09:59:05 -05001659static void
1660input_handle_pointer_leave(void *data,
1661 struct wl_input_device *input_device,
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001662 uint32_t serial, struct wl_surface *surface)
Kristian Høgsberg06d58b72012-02-23 09:59:05 -05001663{
1664 struct input *input = data;
1665
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001666 input->display->serial = serial;
1667 input_remove_pointer_focus(input);
Kristian Høgsbergdb6c2f32009-02-22 21:51:24 -05001668}
1669
1670static void
Kristian Høgsberg8a1d10d2011-12-21 17:11:45 -05001671input_remove_keyboard_focus(struct input *input)
Pekka Paalanene1207c72011-12-16 12:02:09 +02001672{
1673 struct window *window = input->keyboard_focus;
1674
1675 if (!window)
1676 return;
1677
1678 window->keyboard_device = NULL;
1679 if (window->keyboard_focus_handler)
1680 (*window->keyboard_focus_handler)(window, NULL,
1681 window->user_data);
1682
1683 input->keyboard_focus = NULL;
1684}
1685
1686static void
Kristian Høgsberg06d58b72012-02-23 09:59:05 -05001687input_handle_keyboard_enter(void *data,
Kristian Høgsberg8a1d10d2011-12-21 17:11:45 -05001688 struct wl_input_device *input_device,
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001689 uint32_t serial,
Kristian Høgsberg8a1d10d2011-12-21 17:11:45 -05001690 struct wl_surface *surface,
1691 struct wl_array *keys)
Kristian Høgsbergdb6c2f32009-02-22 21:51:24 -05001692{
Kristian Høgsberg808fd412010-07-20 17:06:19 -04001693 struct input *input = data;
Pekka Paalanene1207c72011-12-16 12:02:09 +02001694 struct window *window;
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -05001695
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001696 input->display->serial = serial;
Kristian Høgsberg06d58b72012-02-23 09:59:05 -05001697 input->keyboard_focus = wl_surface_get_user_data(surface);
Kristian Høgsberg808fd412010-07-20 17:06:19 -04001698
Kristian Høgsberg808fd412010-07-20 17:06:19 -04001699 window = input->keyboard_focus;
Kristian Høgsberg06d58b72012-02-23 09:59:05 -05001700 window->keyboard_device = input;
1701 if (window->keyboard_focus_handler)
1702 (*window->keyboard_focus_handler)(window,
1703 window->keyboard_device,
1704 window->user_data);
1705}
1706
1707static void
1708input_handle_keyboard_leave(void *data,
1709 struct wl_input_device *input_device,
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001710 uint32_t serial,
Kristian Høgsberg06d58b72012-02-23 09:59:05 -05001711 struct wl_surface *surface)
1712{
1713 struct input *input = data;
1714
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001715 input->display->serial = serial;
Kristian Høgsberg06d58b72012-02-23 09:59:05 -05001716 input_remove_keyboard_focus(input);
Kristian Høgsbergdb6c2f32009-02-22 21:51:24 -05001717}
1718
Kristian Høgsberge04ad572011-12-21 17:14:54 -05001719static void
1720input_handle_touch_down(void *data,
1721 struct wl_input_device *wl_input_device,
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001722 uint32_t serial, uint32_t time,
1723 struct wl_surface *surface,
Daniel Stone103db7f2012-05-08 17:17:55 +01001724 int32_t id, wl_fixed_t x, wl_fixed_t y)
Kristian Høgsberge04ad572011-12-21 17:14:54 -05001725{
1726}
1727
1728static void
1729input_handle_touch_up(void *data,
1730 struct wl_input_device *wl_input_device,
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001731 uint32_t serial, uint32_t time, int32_t id)
Kristian Høgsberge04ad572011-12-21 17:14:54 -05001732{
1733}
1734
1735static void
1736input_handle_touch_motion(void *data,
1737 struct wl_input_device *wl_input_device,
Daniel Stone103db7f2012-05-08 17:17:55 +01001738 uint32_t time, int32_t id,
1739 wl_fixed_t x, wl_fixed_t y)
Kristian Høgsberge04ad572011-12-21 17:14:54 -05001740{
1741}
1742
1743static void
1744input_handle_touch_frame(void *data,
1745 struct wl_input_device *wl_input_device)
1746{
1747}
1748
1749static void
1750input_handle_touch_cancel(void *data,
1751 struct wl_input_device *wl_input_device)
1752{
1753}
1754
Kristian Høgsberg94448c02008-12-30 11:03:33 -05001755static const struct wl_input_device_listener input_device_listener = {
Kristian Høgsberg8a1d10d2011-12-21 17:11:45 -05001756 input_handle_motion,
1757 input_handle_button,
Scott Moreau210d0792012-03-22 10:47:01 -06001758 input_handle_axis,
Kristian Høgsberg8a1d10d2011-12-21 17:11:45 -05001759 input_handle_key,
Kristian Høgsberg06d58b72012-02-23 09:59:05 -05001760 input_handle_pointer_enter,
1761 input_handle_pointer_leave,
1762 input_handle_keyboard_enter,
1763 input_handle_keyboard_leave,
Kristian Høgsberge04ad572011-12-21 17:14:54 -05001764 input_handle_touch_down,
1765 input_handle_touch_up,
1766 input_handle_touch_motion,
1767 input_handle_touch_frame,
1768 input_handle_touch_cancel,
Kristian Høgsberg94448c02008-12-30 11:03:33 -05001769};
1770
Kristian Høgsberg9a686242010-08-18 15:28:04 -04001771void
1772input_get_position(struct input *input, int32_t *x, int32_t *y)
1773{
1774 *x = input->sx;
1775 *y = input->sy;
1776}
1777
Kristian Høgsberg1d7ffd32010-08-25 16:34:05 -04001778struct wl_input_device *
1779input_get_input_device(struct input *input)
1780{
1781 return input->input_device;
1782}
1783
Kristian Høgsberg67cac8a2011-01-19 14:20:33 -05001784uint32_t
1785input_get_modifiers(struct input *input)
1786{
1787 return input->modifiers;
1788}
1789
Kristian Høgsbergb6323512012-01-11 00:04:42 -05001790struct widget *
1791input_get_focus_widget(struct input *input)
1792{
1793 return input->focus_widget;
1794}
1795
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04001796struct data_offer {
1797 struct wl_data_offer *offer;
1798 struct input *input;
1799 struct wl_array types;
1800 int refcount;
Kristian Høgsberg9a686242010-08-18 15:28:04 -04001801
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04001802 struct task io_task;
1803 int fd;
1804 data_func_t func;
1805 int32_t x, y;
1806 void *user_data;
1807};
1808
1809static void
1810data_offer_offer(void *data, struct wl_data_offer *wl_data_offer, const char *type)
1811{
1812 struct data_offer *offer = data;
1813 char **p;
1814
1815 p = wl_array_add(&offer->types, sizeof *p);
1816 *p = strdup(type);
1817}
1818
1819static const struct wl_data_offer_listener data_offer_listener = {
1820 data_offer_offer,
1821};
1822
1823static void
1824data_offer_destroy(struct data_offer *offer)
1825{
1826 char **p;
1827
1828 offer->refcount--;
1829 if (offer->refcount == 0) {
1830 wl_data_offer_destroy(offer->offer);
1831 for (p = offer->types.data; *p; p++)
1832 free(*p);
1833 wl_array_release(&offer->types);
1834 free(offer);
1835 }
1836}
1837
1838static void
1839data_device_data_offer(void *data,
1840 struct wl_data_device *data_device, uint32_t id)
1841{
1842 struct data_offer *offer;
1843
1844 offer = malloc(sizeof *offer);
1845
1846 wl_array_init(&offer->types);
1847 offer->refcount = 1;
1848 offer->input = data;
1849
1850 /* FIXME: Generate typesafe wrappers for this */
1851 offer->offer = (struct wl_data_offer *)
1852 wl_proxy_create_for_id((struct wl_proxy *) data_device,
1853 id, &wl_data_offer_interface);
1854
1855 wl_data_offer_add_listener(offer->offer,
1856 &data_offer_listener, offer);
1857}
1858
1859static void
1860data_device_enter(void *data, struct wl_data_device *data_device,
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001861 uint32_t serial, struct wl_surface *surface,
Daniel Stone103db7f2012-05-08 17:17:55 +01001862 wl_fixed_t x_w, wl_fixed_t y_w,
1863 struct wl_data_offer *offer)
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04001864{
1865 struct input *input = data;
1866 struct window *window;
Daniel Stone103db7f2012-05-08 17:17:55 +01001867 GLfloat x = wl_fixed_to_double(x_w);
1868 GLfloat y = wl_fixed_to_double(y_w);
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04001869 char **p;
1870
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001871 input->pointer_enter_serial = serial;
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04001872 input->drag_offer = wl_data_offer_get_user_data(offer);
1873 window = wl_surface_get_user_data(surface);
1874 input->pointer_focus = window;
1875
1876 p = wl_array_add(&input->drag_offer->types, sizeof *p);
1877 *p = NULL;
1878
1879 window = input->pointer_focus;
1880 if (window->data_handler)
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001881 window->data_handler(window, input, x, y,
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04001882 input->drag_offer->types.data,
1883 window->user_data);
1884}
1885
1886static void
1887data_device_leave(void *data, struct wl_data_device *data_device)
1888{
1889 struct input *input = data;
1890
1891 data_offer_destroy(input->drag_offer);
1892 input->drag_offer = NULL;
1893}
1894
1895static void
1896data_device_motion(void *data, struct wl_data_device *data_device,
Daniel Stone103db7f2012-05-08 17:17:55 +01001897 uint32_t time, wl_fixed_t x_w, wl_fixed_t y_w)
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04001898{
1899 struct input *input = data;
1900 struct window *window = input->pointer_focus;
Daniel Stone103db7f2012-05-08 17:17:55 +01001901 GLfloat x = wl_fixed_to_double(x_w);
1902 GLfloat y = wl_fixed_to_double(y_w);
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04001903
1904 input->sx = x;
1905 input->sy = y;
1906
1907 if (window->data_handler)
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001908 window->data_handler(window, input, x, y,
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04001909 input->drag_offer->types.data,
1910 window->user_data);
1911}
1912
1913static void
1914data_device_drop(void *data, struct wl_data_device *data_device)
1915{
1916 struct input *input = data;
1917 struct window *window = input->pointer_focus;
1918
1919 if (window->drop_handler)
1920 window->drop_handler(window, input,
1921 input->sx, input->sy, window->user_data);
1922}
1923
1924static void
1925data_device_selection(void *data,
1926 struct wl_data_device *wl_data_device,
1927 struct wl_data_offer *offer)
1928{
1929 struct input *input = data;
1930 char **p;
1931
1932 if (input->selection_offer)
1933 data_offer_destroy(input->selection_offer);
1934
Kristian Høgsberg42c8f602012-01-27 11:04:18 -05001935 if (offer) {
1936 input->selection_offer = wl_data_offer_get_user_data(offer);
1937 p = wl_array_add(&input->selection_offer->types, sizeof *p);
1938 *p = NULL;
1939 }
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04001940}
1941
1942static const struct wl_data_device_listener data_device_listener = {
1943 data_device_data_offer,
1944 data_device_enter,
1945 data_device_leave,
1946 data_device_motion,
1947 data_device_drop,
1948 data_device_selection
1949};
1950
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001951void
1952input_set_pointer_image(struct input *input, uint32_t time, int pointer)
1953{
1954 struct display *display = input->display;
1955 struct wl_buffer *buffer;
Ander Conselvan de Oliveira1493d2a2012-05-03 12:29:46 +03001956 struct cursor_image *image;
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001957
Ander Conselvan de Oliveira1493d2a2012-05-03 12:29:46 +03001958 if (pointer == input->current_cursor)
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001959 return;
1960
Ander Conselvan de Oliveira1493d2a2012-05-03 12:29:46 +03001961 image = &display->cursors[pointer].images[0];
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001962
Ander Conselvan de Oliveira1493d2a2012-05-03 12:29:46 +03001963 if (!image->surface)
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001964 return;
1965
Ander Conselvan de Oliveira1493d2a2012-05-03 12:29:46 +03001966 input->current_cursor = pointer;
1967 buffer = display_get_buffer_for_surface(display, image->surface);
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001968 wl_input_device_attach(input->input_device, time, buffer,
Ander Conselvan de Oliveira1493d2a2012-05-03 12:29:46 +03001969 image->hotspot_x, image->hotspot_y);
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05001970}
1971
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04001972struct wl_data_device *
1973input_get_data_device(struct input *input)
1974{
1975 return input->data_device;
1976}
1977
1978void
1979input_set_selection(struct input *input,
1980 struct wl_data_source *source, uint32_t time)
1981{
1982 wl_data_device_set_selection(input->data_device, source, time);
1983}
1984
1985void
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001986input_accept(struct input *input, const char *type)
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04001987{
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001988 wl_data_offer_accept(input->drag_offer->offer,
1989 input->pointer_enter_serial, type);
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04001990}
1991
1992static void
1993offer_io_func(struct task *task, uint32_t events)
1994{
1995 struct data_offer *offer =
1996 container_of(task, struct data_offer, io_task);
1997 unsigned int len;
1998 char buffer[4096];
1999
2000 len = read(offer->fd, buffer, sizeof buffer);
2001 offer->func(buffer, len,
2002 offer->x, offer->y, offer->user_data);
2003
2004 if (len == 0) {
2005 close(offer->fd);
2006 data_offer_destroy(offer);
2007 }
2008}
2009
2010static void
2011data_offer_receive_data(struct data_offer *offer, const char *mime_type,
2012 data_func_t func, void *user_data)
2013{
2014 int p[2];
2015
Jonas Ådahl3685c3a2012-03-30 23:10:27 +02002016 if (pipe2(p, O_CLOEXEC) == -1)
2017 return;
2018
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04002019 wl_data_offer_receive(offer->offer, mime_type, p[1]);
2020 close(p[1]);
2021
2022 offer->io_task.run = offer_io_func;
2023 offer->fd = p[0];
2024 offer->func = func;
2025 offer->refcount++;
2026 offer->user_data = user_data;
2027
2028 display_watch_fd(offer->input->display,
2029 offer->fd, EPOLLIN, &offer->io_task);
2030}
2031
2032void
2033input_receive_drag_data(struct input *input, const char *mime_type,
2034 data_func_t func, void *data)
2035{
2036 data_offer_receive_data(input->drag_offer, mime_type, func, data);
2037 input->drag_offer->x = input->sx;
2038 input->drag_offer->y = input->sy;
2039}
2040
2041int
2042input_receive_selection_data(struct input *input, const char *mime_type,
2043 data_func_t func, void *data)
2044{
2045 char **p;
2046
2047 if (input->selection_offer == NULL)
2048 return -1;
2049
2050 for (p = input->selection_offer->types.data; *p; p++)
2051 if (strcmp(mime_type, *p) == 0)
2052 break;
2053
2054 if (*p == NULL)
2055 return -1;
2056
2057 data_offer_receive_data(input->selection_offer,
2058 mime_type, func, data);
2059 return 0;
Kristian Høgsberg41da9082010-11-30 14:01:07 -05002060}
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -04002061
Kristian Høgsberge7aaec32011-12-27 13:50:04 -05002062int
2063input_receive_selection_data_to_fd(struct input *input,
2064 const char *mime_type, int fd)
2065{
2066 wl_data_offer_receive(input->selection_offer->offer, mime_type, fd);
2067
2068 return 0;
2069}
2070
Kristian Høgsberg41da9082010-11-30 14:01:07 -05002071void
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04002072window_move(struct window *window, struct input *input, uint32_t serial)
Kristian Høgsberg82da52b2010-12-17 09:53:12 -05002073{
Pekka Paalanen6b2dc912011-11-29 10:25:08 +02002074 if (!window->shell_surface)
2075 return;
2076
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002077 wl_shell_surface_move(window->shell_surface,
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04002078 input->input_device, serial);
Kristian Høgsberg82da52b2010-12-17 09:53:12 -05002079}
2080
Kristian Høgsberg83fc0612010-08-04 22:44:55 -04002081static void
Kristian Høgsberg42b4f802012-03-26 13:49:29 -04002082idle_resize(struct window *window)
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -05002083{
Kristian Høgsbergbb977002012-01-10 19:11:42 -05002084 struct widget *widget;
Kristian Høgsbergbb977002012-01-10 19:11:42 -05002085
Kristian Høgsberg42b4f802012-03-26 13:49:29 -04002086 window->resize_needed = 0;
Kristian Høgsbergbb977002012-01-10 19:11:42 -05002087 widget = window->widget;
Kristian Høgsberg0d1c0622012-01-31 15:30:47 -05002088 widget_set_allocation(widget,
2089 window->pending_allocation.x,
2090 window->pending_allocation.y,
2091 window->pending_allocation.width,
2092 window->pending_allocation.height);
Kristian Høgsberg441338c2012-01-10 13:52:34 -05002093
Kristian Høgsberg010f98b2012-02-23 17:30:45 -05002094 if (window->input_region) {
2095 wl_region_destroy(window->input_region);
2096 window->input_region = NULL;
2097 }
2098
2099 if (window->opaque_region) {
2100 wl_region_destroy(window->opaque_region);
2101 window->opaque_region = NULL;
2102 }
2103
Kristian Høgsbergbb977002012-01-10 19:11:42 -05002104 if (widget->resize_handler)
2105 widget->resize_handler(widget,
Kristian Høgsberg0d1c0622012-01-31 15:30:47 -05002106 widget->allocation.width,
2107 widget->allocation.height,
Kristian Høgsbergbb977002012-01-10 19:11:42 -05002108 widget->user_data);
2109
Kristian Høgsberg8e054f72012-01-31 11:53:20 -05002110 if (window->allocation.width != widget->allocation.width ||
2111 window->allocation.height != widget->allocation.height) {
2112 window->allocation = widget->allocation;
2113 window_schedule_redraw(window);
2114 }
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -05002115}
2116
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -05002117void
2118window_schedule_resize(struct window *window, int width, int height)
2119{
Kristian Høgsberg0d1c0622012-01-31 15:30:47 -05002120 window->pending_allocation.x = 0;
2121 window->pending_allocation.y = 0;
2122 window->pending_allocation.width = width;
2123 window->pending_allocation.height = height;
2124
Kristian Høgsberg42b4f802012-03-26 13:49:29 -04002125 window->resize_needed = 1;
2126 window_schedule_redraw(window);
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -05002127}
2128
Kristian Høgsbergbb977002012-01-10 19:11:42 -05002129void
2130widget_schedule_resize(struct widget *widget, int32_t width, int32_t height)
2131{
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -05002132 window_schedule_resize(widget->window, width, height);
Kristian Høgsbergbb977002012-01-10 19:11:42 -05002133}
2134
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -05002135static void
Scott Moreauff1db4a2012-04-17 19:06:18 -06002136handle_ping(void *data, struct wl_shell_surface *shell_surface,
2137 uint32_t serial)
2138{
2139 wl_shell_surface_pong(shell_surface, serial);
2140}
2141
2142static void
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002143handle_configure(void *data, struct wl_shell_surface *shell_surface,
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04002144 uint32_t edges, int32_t width, int32_t height)
Kristian Høgsberg83fc0612010-08-04 22:44:55 -04002145{
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002146 struct window *window = data;
Kristian Høgsberg83fc0612010-08-04 22:44:55 -04002147
Kristian Høgsberg0ce24572011-01-28 15:18:33 -05002148 if (width <= 0 || height <= 0)
Tim Wiederhake8a6f7e32011-01-17 12:40:01 +01002149 return;
2150
Tim Wiederhakeb6761dc2011-01-17 17:50:07 +01002151 window->resize_edges = edges;
Kristian Høgsberg0d1c0622012-01-31 15:30:47 -05002152 window_schedule_resize(window, width, height);
Kristian Høgsberg83fc0612010-08-04 22:44:55 -04002153}
2154
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002155static void
Pekka Paalanen6d174cf2012-01-19 15:17:59 +02002156menu_destroy(struct menu *menu)
2157{
2158 widget_destroy(menu->widget);
2159 window_destroy(menu->window);
2160 free(menu);
2161}
2162
2163static void
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002164handle_popup_done(void *data, struct wl_shell_surface *shell_surface)
2165{
2166 struct window *window = data;
Kristian Høgsberg831dd522012-01-10 23:46:33 -05002167 struct menu *menu = window->widget->user_data;
2168
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002169 /* FIXME: Need more context in this event, at least the input
Kristian Høgsberg831dd522012-01-10 23:46:33 -05002170 * device. Or just use wl_callback. And this really needs to
2171 * be a window vfunc that the menu can set. And we need the
2172 * time. */
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002173
Kristian Høgsberg4f7dcd62012-01-06 21:59:05 -05002174 menu->func(window->parent, menu->current, window->parent->user_data);
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04002175 input_ungrab(menu->input);
Pekka Paalanen6d174cf2012-01-19 15:17:59 +02002176 menu_destroy(menu);
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002177}
2178
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002179static const struct wl_shell_surface_listener shell_surface_listener = {
Scott Moreauff1db4a2012-04-17 19:06:18 -06002180 handle_ping,
Kristian Høgsberg83fc0612010-08-04 22:44:55 -04002181 handle_configure,
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002182 handle_popup_done
Kristian Høgsberg83fc0612010-08-04 22:44:55 -04002183};
2184
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -05002185void
Benjamin Franzkecff904e2011-02-18 23:00:55 +01002186window_get_allocation(struct window *window,
2187 struct rectangle *allocation)
2188{
2189 *allocation = window->allocation;
2190}
2191
Kristian Høgsberg3a696272011-09-14 17:33:48 -04002192static void
Kristian Høgsberg441338c2012-01-10 13:52:34 -05002193widget_redraw(struct widget *widget)
2194{
2195 struct widget *child;
2196
2197 if (widget->redraw_handler)
2198 widget->redraw_handler(widget, widget->user_data);
2199 wl_list_for_each(child, &widget->child_list, link)
2200 widget_redraw(child);
2201}
2202
2203static void
Kristian Høgsberg6bd4d972012-03-24 14:42:09 -04002204frame_callback(void *data, struct wl_callback *callback, uint32_t time)
2205{
2206 struct window *window = data;
2207
2208 wl_callback_destroy(callback);
2209 window->redraw_scheduled = 0;
2210 if (window->redraw_needed)
2211 window_schedule_redraw(window);
2212}
2213
2214static const struct wl_callback_listener listener = {
2215 frame_callback
2216};
2217
2218static void
Kristian Høgsberg3a696272011-09-14 17:33:48 -04002219idle_redraw(struct task *task, uint32_t events)
Kristian Høgsberg80d746f2010-06-14 23:52:50 -04002220{
Kristian Høgsberg42b4f802012-03-26 13:49:29 -04002221 struct window *window = container_of(task, struct window, redraw_task);
Kristian Høgsberg6bd4d972012-03-24 14:42:09 -04002222 struct wl_callback *callback;
Kristian Høgsberg80d746f2010-06-14 23:52:50 -04002223
Kristian Høgsberg42b4f802012-03-26 13:49:29 -04002224 if (window->resize_needed)
2225 idle_resize(window);
2226
Kristian Høgsberg5d129902012-01-10 10:49:41 -05002227 window_create_surface(window);
Kristian Høgsberg441338c2012-01-10 13:52:34 -05002228 widget_redraw(window->widget);
Kristian Høgsberg5d129902012-01-10 10:49:41 -05002229 window_flush(window);
Kristian Høgsberg6bd4d972012-03-24 14:42:09 -04002230 window->redraw_needed = 0;
Kristian Høgsberg84b76c72012-04-13 12:01:18 -04002231 wl_list_init(&window->redraw_task.link);
Kristian Høgsberg6bd4d972012-03-24 14:42:09 -04002232
2233 callback = wl_surface_frame(window->surface);
2234 wl_callback_add_listener(callback, &listener, window);
Kristian Høgsberg80d746f2010-06-14 23:52:50 -04002235}
2236
2237void
2238window_schedule_redraw(struct window *window)
2239{
Kristian Høgsberg6bd4d972012-03-24 14:42:09 -04002240 window->redraw_needed = 1;
Kristian Høgsberg80d746f2010-06-14 23:52:50 -04002241 if (!window->redraw_scheduled) {
Kristian Høgsberg3a696272011-09-14 17:33:48 -04002242 window->redraw_task.run = idle_redraw;
2243 display_defer(window->display, &window->redraw_task);
Kristian Høgsberg80d746f2010-06-14 23:52:50 -04002244 window->redraw_scheduled = 1;
2245 }
2246}
2247
Kristian Høgsberg0ac16f02009-01-15 11:37:43 -05002248void
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -04002249window_set_custom(struct window *window)
2250{
2251 window->type = TYPE_CUSTOM;
2252}
2253
2254void
Kristian Høgsberg0395f302008-12-22 12:14:50 -05002255window_set_fullscreen(struct window *window, int fullscreen)
2256{
Kristian Høgsberg1517def2012-02-16 22:56:12 -05002257 if (!window->display->shell)
2258 return;
Kristian Høgsberg0ce24572011-01-28 15:18:33 -05002259
Kristian Høgsberg547da5a2011-09-13 20:58:00 -04002260 if ((window->type == TYPE_FULLSCREEN) == fullscreen)
Kristian Høgsberg0ce24572011-01-28 15:18:33 -05002261 return;
2262
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -04002263 if (fullscreen) {
2264 window->type = TYPE_FULLSCREEN;
Kristian Høgsberg0395f302008-12-22 12:14:50 -05002265 window->saved_allocation = window->allocation;
Kristian Høgsberg1517def2012-02-16 22:56:12 -05002266 wl_shell_surface_set_fullscreen(window->shell_surface,
2267 WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
2268 0, NULL);
Kristian Høgsberg0395f302008-12-22 12:14:50 -05002269 } else {
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -04002270 window->type = TYPE_TOPLEVEL;
Kristian Høgsberg1517def2012-02-16 22:56:12 -05002271 wl_shell_surface_set_toplevel(window->shell_surface);
2272 window_schedule_resize(window,
2273 window->saved_allocation.width,
2274 window->saved_allocation.height);
Kristian Høgsberg0395f302008-12-22 12:14:50 -05002275 }
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -04002276}
2277
2278void
Kristian Høgsbergd6bcd7d2012-02-16 15:53:46 -05002279window_set_maximized(struct window *window, int maximized)
2280{
2281 if (!window->display->shell)
2282 return;
2283
2284 if ((window->type == TYPE_MAXIMIZED) == maximized)
2285 return;
2286
2287 if (window->type == TYPE_TOPLEVEL) {
2288 window->saved_allocation = window->allocation;
2289 wl_shell_surface_set_maximized(window->shell_surface, NULL);
2290 window->type = TYPE_MAXIMIZED;
2291 } else {
2292 wl_shell_surface_set_toplevel(window->shell_surface);
2293 window->type = TYPE_TOPLEVEL;
2294 window_schedule_resize(window,
2295 window->saved_allocation.width,
2296 window->saved_allocation.height);
2297 }
2298}
2299
2300void
Kristian Høgsbergc8c37342010-06-25 11:19:22 -04002301window_set_user_data(struct window *window, void *data)
2302{
2303 window->user_data = data;
2304}
2305
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -04002306void *
2307window_get_user_data(struct window *window)
2308{
2309 return window->user_data;
2310}
2311
Kristian Høgsbergc8c37342010-06-25 11:19:22 -04002312void
Kristian Høgsberg6e83d582008-12-08 00:01:36 -05002313window_set_key_handler(struct window *window,
Kristian Høgsbergc8c37342010-06-25 11:19:22 -04002314 window_key_handler_t handler)
Kristian Høgsberg6e83d582008-12-08 00:01:36 -05002315{
2316 window->key_handler = handler;
Kristian Høgsberg6e83d582008-12-08 00:01:36 -05002317}
2318
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -05002319void
2320window_set_keyboard_focus_handler(struct window *window,
Kristian Høgsbergc8c37342010-06-25 11:19:22 -04002321 window_keyboard_focus_handler_t handler)
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -05002322{
2323 window->keyboard_focus_handler = handler;
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -05002324}
2325
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -04002326void
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04002327window_set_data_handler(struct window *window, window_data_handler_t handler)
2328{
2329 window->data_handler = handler;
2330}
2331
2332void
2333window_set_drop_handler(struct window *window, window_drop_handler_t handler)
2334{
2335 window->drop_handler = handler;
2336}
2337
2338void
Kristian Høgsberg4f7dcd62012-01-06 21:59:05 -05002339window_set_close_handler(struct window *window,
2340 window_close_handler_t handler)
2341{
2342 window->close_handler = handler;
2343}
2344
2345void
Callum Lowcayef57a9b2011-01-14 20:46:23 +13002346window_set_title(struct window *window, const char *title)
2347{
Kristian Høgsbergd5fb9cc2011-01-25 12:45:37 -05002348 free(window->title);
Callum Lowcayef57a9b2011-01-14 20:46:23 +13002349 window->title = strdup(title);
Kristian Høgsberg3e0fe5c2012-05-02 09:47:55 -04002350 if (window->shell_surface)
2351 wl_shell_surface_set_title(window->shell_surface, title);
Callum Lowcayef57a9b2011-01-14 20:46:23 +13002352}
2353
2354const char *
2355window_get_title(struct window *window)
2356{
2357 return window->title;
2358}
2359
2360void
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -04002361window_damage(struct window *window, int32_t x, int32_t y,
2362 int32_t width, int32_t height)
2363{
2364 wl_surface_damage(window->surface, x, y, width, height);
2365}
2366
Casey Dahlin9074db52012-04-19 22:50:09 -04002367static void
2368surface_enter(void *data,
2369 struct wl_surface *wl_surface, struct wl_output *output)
2370{
2371}
2372
2373static void
2374surface_leave(void *data,
2375 struct wl_surface *wl_surface, struct wl_output *output)
2376{
2377}
2378
2379static const struct wl_surface_listener surface_listener = {
2380 surface_enter,
2381 surface_leave
2382};
2383
Kristian Høgsberg248c1b62011-01-21 18:03:15 -05002384static struct window *
Kristian Høgsberg009ac0a2012-01-31 15:24:48 -05002385window_create_internal(struct display *display, struct window *parent)
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -05002386{
Kristian Høgsberg1cbaa6a2008-11-07 15:54:48 -05002387 struct window *window;
2388
2389 window = malloc(sizeof *window);
2390 if (window == NULL)
2391 return NULL;
2392
Kristian Høgsberg78231c82008-11-08 15:06:01 -05002393 memset(window, 0, sizeof *window);
Kristian Høgsberg40979232008-11-25 22:40:39 -05002394 window->display = display;
Kristian Høgsberg248c1b62011-01-21 18:03:15 -05002395 window->parent = parent;
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05002396 window->surface = wl_compositor_create_surface(display->compositor);
Casey Dahlin9074db52012-04-19 22:50:09 -04002397 wl_surface_add_listener(window->surface, &surface_listener, window);
Pekka Paalanen6b2dc912011-11-29 10:25:08 +02002398 if (display->shell) {
2399 window->shell_surface =
2400 wl_shell_get_shell_surface(display->shell,
2401 window->surface);
Kristian Høgsberg3e0fe5c2012-05-02 09:47:55 -04002402 if (window->title)
2403 wl_shell_surface_set_title(window->shell_surface,
2404 window->title);
Pekka Paalanen6b2dc912011-11-29 10:25:08 +02002405 }
Kristian Høgsberg82da52b2010-12-17 09:53:12 -05002406 window->allocation.x = 0;
2407 window->allocation.y = 0;
Kristian Høgsberg009ac0a2012-01-31 15:24:48 -05002408 window->allocation.width = 0;
2409 window->allocation.height = 0;
Kristian Høgsberg0395f302008-12-22 12:14:50 -05002410 window->saved_allocation = window->allocation;
Kristian Høgsberg3be87d12011-05-13 13:45:17 -04002411 window->transparent = 1;
Kristian Høgsberg407ef642012-04-27 17:17:12 -04002412 window->type = TYPE_NONE;
Kristian Høgsberg010f98b2012-02-23 17:30:45 -05002413 window->input_region = NULL;
2414 window->opaque_region = NULL;
Kristian Høgsberg87a57bb2012-01-09 10:34:35 -05002415
Kristian Høgsberg297c6312011-02-04 14:11:33 -05002416 if (display->dpy)
Benjamin Franzke22d54812011-07-16 19:50:32 +00002417#ifdef HAVE_CAIRO_EGL
Benjamin Franzke6693ac22011-02-10 12:04:30 +01002418 window->buffer_type = WINDOW_BUFFER_TYPE_EGL_WINDOW;
Benjamin Franzke22d54812011-07-16 19:50:32 +00002419#else
2420 window->buffer_type = WINDOW_BUFFER_TYPE_SHM;
2421#endif
Yuval Fledel45568f62010-12-06 09:18:12 -05002422 else
2423 window->buffer_type = WINDOW_BUFFER_TYPE_SHM;
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -04002424
Kristian Høgsberg808fd412010-07-20 17:06:19 -04002425 wl_surface_set_user_data(window->surface, window);
Kristian Høgsberg478d9262010-06-08 20:34:11 -04002426 wl_list_insert(display->window_list.prev, &window->link);
Kristian Høgsberg84b76c72012-04-13 12:01:18 -04002427 wl_list_init(&window->redraw_task.link);
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05002428
Pekka Paalanen6b2dc912011-11-29 10:25:08 +02002429 if (window->shell_surface) {
2430 wl_shell_surface_set_user_data(window->shell_surface, window);
2431 wl_shell_surface_add_listener(window->shell_surface,
2432 &shell_surface_listener, window);
2433 }
Pekka Paalanen9d1613e2011-11-25 12:09:16 +02002434
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05002435 return window;
2436}
2437
Kristian Høgsberg248c1b62011-01-21 18:03:15 -05002438struct window *
Kristian Høgsberg009ac0a2012-01-31 15:24:48 -05002439window_create(struct display *display)
Kristian Høgsberg248c1b62011-01-21 18:03:15 -05002440{
2441 struct window *window;
2442
Kristian Høgsberg009ac0a2012-01-31 15:24:48 -05002443 window = window_create_internal(display, NULL);
Kristian Høgsberg248c1b62011-01-21 18:03:15 -05002444 if (!window)
2445 return NULL;
2446
2447 return window;
2448}
2449
2450struct window *
2451window_create_transient(struct display *display, struct window *parent,
Kristian Høgsberg009ac0a2012-01-31 15:24:48 -05002452 int32_t x, int32_t y)
Kristian Høgsberg248c1b62011-01-21 18:03:15 -05002453{
2454 struct window *window;
2455
Kristian Høgsberg009ac0a2012-01-31 15:24:48 -05002456 window = window_create_internal(parent->display, parent);
Kristian Høgsberg248c1b62011-01-21 18:03:15 -05002457 if (!window)
2458 return NULL;
2459
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -04002460 window->type = TYPE_TRANSIENT;
Kristian Høgsberg248c1b62011-01-21 18:03:15 -05002461 window->x = x;
2462 window->y = y;
2463
Kristian Høgsberg1517def2012-02-16 22:56:12 -05002464 if (display->shell)
2465 wl_shell_surface_set_transient(window->shell_surface,
2466 window->parent->shell_surface,
2467 window->x, window->y, 0);
2468
Kristian Høgsberg248c1b62011-01-21 18:03:15 -05002469 return window;
2470}
2471
Kristian Høgsberg831dd522012-01-10 23:46:33 -05002472static void
Kristian Høgsberg19dd1d72012-01-09 10:42:41 -05002473menu_set_item(struct menu *menu, int sy)
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05002474{
2475 int next;
2476
2477 next = (sy - 8) / 20;
2478 if (menu->current != next) {
2479 menu->current = next;
Kristian Høgsberg75bc6672012-01-10 09:43:58 -05002480 widget_schedule_redraw(menu->widget);
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05002481 }
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05002482}
2483
2484static int
Kristian Høgsberg5f190ef2012-01-09 09:44:45 -05002485menu_motion_handler(struct widget *widget,
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05002486 struct input *input, uint32_t time,
Daniel Stoneb230a7e2012-05-08 17:17:54 +01002487 GLfloat x, GLfloat y, void *data)
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05002488{
Kristian Høgsberg831dd522012-01-10 23:46:33 -05002489 struct menu *menu = data;
2490
2491 if (widget == menu->widget)
2492 menu_set_item(data, y);
2493
2494 return POINTER_LEFT_PTR;
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05002495}
2496
Kristian Høgsbergbb901fa2012-01-09 11:22:32 -05002497static int
Kristian Høgsberg391649b2012-01-09 09:22:30 -05002498menu_enter_handler(struct widget *widget,
Daniel Stoneb230a7e2012-05-08 17:17:54 +01002499 struct input *input, GLfloat x, GLfloat y, void *data)
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05002500{
Kristian Høgsberg831dd522012-01-10 23:46:33 -05002501 struct menu *menu = data;
2502
2503 if (widget == menu->widget)
2504 menu_set_item(data, y);
2505
2506 return POINTER_LEFT_PTR;
Kristian Høgsberg391649b2012-01-09 09:22:30 -05002507}
2508
2509static void
2510menu_leave_handler(struct widget *widget, struct input *input, void *data)
2511{
Kristian Høgsberg831dd522012-01-10 23:46:33 -05002512 struct menu *menu = data;
2513
2514 if (widget == menu->widget)
2515 menu_set_item(data, -200);
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05002516}
2517
2518static void
Kristian Høgsberga8a0db32012-01-09 11:12:05 -05002519menu_button_handler(struct widget *widget,
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05002520 struct input *input, uint32_t time,
Daniel Stone5d663712012-05-04 11:21:55 +01002521 uint32_t button, uint32_t state, void *data)
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05002522
2523{
Kristian Høgsberg75bc6672012-01-10 09:43:58 -05002524 struct menu *menu = data;
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05002525
Kristian Høgsberg4f7dcd62012-01-06 21:59:05 -05002526 if (state == 0 && time - menu->time > 500) {
Kristian Høgsberg831dd522012-01-10 23:46:33 -05002527 /* Either relase after press-drag-release or
2528 * click-motion-click. */
Kristian Høgsberg75bc6672012-01-10 09:43:58 -05002529 menu->func(menu->window->parent,
2530 menu->current, menu->window->parent->user_data);
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04002531 input_ungrab(input);
Pekka Paalanen6d174cf2012-01-19 15:17:59 +02002532 menu_destroy(menu);
Kristian Høgsberg4f7dcd62012-01-06 21:59:05 -05002533 }
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05002534}
2535
2536static void
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -05002537menu_redraw_handler(struct widget *widget, void *data)
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05002538{
2539 cairo_t *cr;
2540 const int32_t r = 3, margin = 3;
2541 struct menu *menu = data;
2542 int32_t width, height, i;
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -05002543 struct window *window = widget->window;
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05002544
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05002545 cr = cairo_create(window->cairo_surface);
2546 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
2547 cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.0);
2548 cairo_paint(cr);
2549
2550 width = window->allocation.width;
2551 height = window->allocation.height;
2552 rounded_rect(cr, 0, 0, width, height, r);
Kristian Høgsberg824c6d02012-01-19 13:54:09 -05002553
2554 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05002555 cairo_set_source_rgba(cr, 0.0, 0.0, 0.4, 0.8);
2556 cairo_fill(cr);
2557
2558 for (i = 0; i < menu->count; i++) {
2559 if (i == menu->current) {
2560 cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
2561 cairo_rectangle(cr, margin, i * 20 + margin,
2562 width - 2 * margin, 20);
2563 cairo_fill(cr);
2564 cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
2565 cairo_move_to(cr, 10, i * 20 + 16);
2566 cairo_show_text(cr, menu->entries[i]);
2567 } else {
2568 cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
2569 cairo_move_to(cr, 10, i * 20 + 16);
2570 cairo_show_text(cr, menu->entries[i]);
2571 }
2572 }
2573
2574 cairo_destroy(cr);
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05002575}
2576
Pekka Paalanen6d174cf2012-01-19 15:17:59 +02002577void
2578window_show_menu(struct display *display,
2579 struct input *input, uint32_t time, struct window *parent,
2580 int32_t x, int32_t y,
2581 menu_func_t func, const char **entries, int count)
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05002582{
2583 struct window *window;
2584 struct menu *menu;
Kristian Høgsberg75bc6672012-01-10 09:43:58 -05002585 const int32_t margin = 3;
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05002586
2587 menu = malloc(sizeof *menu);
2588 if (!menu)
Pekka Paalanen6d174cf2012-01-19 15:17:59 +02002589 return;
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05002590
Kristian Høgsberg009ac0a2012-01-31 15:24:48 -05002591 window = window_create_internal(parent->display, parent);
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05002592 if (!window)
Pekka Paalanen6d174cf2012-01-19 15:17:59 +02002593 return;
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05002594
2595 menu->window = window;
Kristian Høgsberg75bc6672012-01-10 09:43:58 -05002596 menu->widget = window_add_widget(menu->window, menu);
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05002597 menu->entries = entries;
2598 menu->count = count;
Kristian Høgsberg831dd522012-01-10 23:46:33 -05002599 menu->current = -1;
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002600 menu->time = time;
Kristian Høgsberg4f7dcd62012-01-06 21:59:05 -05002601 menu->func = func;
Kristian Høgsberg831dd522012-01-10 23:46:33 -05002602 menu->input = input;
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05002603 window->type = TYPE_MENU;
2604 window->x = x;
2605 window->y = y;
2606
Kristian Høgsberga6c8b002012-04-13 12:55:45 -04002607 input_ungrab(input);
Kristian Høgsbergf2eb68a2012-04-13 12:37:19 -04002608 wl_shell_surface_set_popup(window->shell_surface, input->input_device,
2609 display_get_serial(window->display),
Kristian Høgsbergb3cca0a2012-01-04 22:19:14 -05002610 window->parent->shell_surface,
2611 window->x, window->y, 0);
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05002612
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -05002613 widget_set_redraw_handler(menu->widget, menu_redraw_handler);
Kristian Høgsberg75bc6672012-01-10 09:43:58 -05002614 widget_set_enter_handler(menu->widget, menu_enter_handler);
2615 widget_set_leave_handler(menu->widget, menu_leave_handler);
2616 widget_set_motion_handler(menu->widget, menu_motion_handler);
2617 widget_set_button_handler(menu->widget, menu_button_handler);
Kristian Høgsberg391649b2012-01-09 09:22:30 -05002618
Kristian Høgsberg831dd522012-01-10 23:46:33 -05002619 input_grab(input, menu->widget, 0);
Kristian Høgsberg009ac0a2012-01-31 15:24:48 -05002620 window_schedule_resize(window, 200, count * 20 + margin * 2);
Kristian Høgsbergbbedd7e2011-12-19 15:40:10 -05002621}
2622
Kristian Høgsberg248c1b62011-01-21 18:03:15 -05002623void
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -04002624window_set_buffer_type(struct window *window, enum window_buffer_type type)
2625{
2626 window->buffer_type = type;
2627}
2628
Kristian Høgsberg8357cd62011-05-13 13:24:56 -04002629
2630static void
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05002631display_handle_geometry(void *data,
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002632 struct wl_output *wl_output,
2633 int x, int y,
2634 int physical_width,
2635 int physical_height,
2636 int subpixel,
2637 const char *make,
2638 const char *model)
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05002639{
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -05002640 struct output *output = data;
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05002641
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -05002642 output->allocation.x = x;
2643 output->allocation.y = y;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002644}
2645
2646static void
2647display_handle_mode(void *data,
2648 struct wl_output *wl_output,
2649 uint32_t flags,
2650 int width,
2651 int height,
2652 int refresh)
2653{
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -05002654 struct output *output = data;
Pekka Paalanen999c5b52011-11-30 10:52:38 +02002655 struct display *display = output->display;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002656
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -05002657 if (flags & WL_OUTPUT_MODE_CURRENT) {
2658 output->allocation.width = width;
2659 output->allocation.height = height;
Pekka Paalanen999c5b52011-11-30 10:52:38 +02002660 if (display->output_configure_handler)
2661 (*display->output_configure_handler)(
2662 output, display->user_data);
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -05002663 }
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05002664}
2665
2666static const struct wl_output_listener output_listener = {
2667 display_handle_geometry,
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002668 display_handle_mode
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05002669};
2670
2671static void
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -05002672display_add_output(struct display *d, uint32_t id)
2673{
2674 struct output *output;
2675
2676 output = malloc(sizeof *output);
2677 if (output == NULL)
2678 return;
2679
2680 memset(output, 0, sizeof *output);
2681 output->display = d;
2682 output->output =
2683 wl_display_bind(d->display, id, &wl_output_interface);
2684 wl_list_insert(d->output_list.prev, &output->link);
2685
2686 wl_output_add_listener(output->output, &output_listener, output);
2687}
2688
Pekka Paalanen2c1426a2011-12-16 11:35:34 +02002689static void
2690output_destroy(struct output *output)
2691{
2692 if (output->destroy_handler)
2693 (*output->destroy_handler)(output, output->user_data);
2694
2695 wl_output_destroy(output->output);
2696 wl_list_remove(&output->link);
2697 free(output);
2698}
2699
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -05002700void
Pekka Paalanen999c5b52011-11-30 10:52:38 +02002701display_set_output_configure_handler(struct display *display,
2702 display_output_handler_t handler)
2703{
2704 struct output *output;
2705
2706 display->output_configure_handler = handler;
2707 if (!handler)
2708 return;
2709
2710 wl_list_for_each(output, &display->output_list, link)
2711 (*display->output_configure_handler)(output,
2712 display->user_data);
2713}
2714
2715void
2716output_set_user_data(struct output *output, void *data)
2717{
2718 output->user_data = data;
2719}
2720
2721void *
2722output_get_user_data(struct output *output)
2723{
2724 return output->user_data;
2725}
2726
2727void
2728output_set_destroy_handler(struct output *output,
2729 display_output_handler_t handler)
2730{
2731 output->destroy_handler = handler;
2732 /* FIXME: implement this, once we have way to remove outputs */
2733}
2734
2735void
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -05002736output_get_allocation(struct output *output, struct rectangle *allocation)
2737{
2738 *allocation = output->allocation;
2739}
2740
Pekka Paalanen999c5b52011-11-30 10:52:38 +02002741struct wl_output *
2742output_get_wl_output(struct output *output)
2743{
2744 return output->output;
2745}
2746
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -05002747static void
Kristian Høgsberg4fe1a3e2010-08-10 14:02:48 -04002748display_add_input(struct display *d, uint32_t id)
Kristian Høgsberg808fd412010-07-20 17:06:19 -04002749{
2750 struct input *input;
2751
2752 input = malloc(sizeof *input);
2753 if (input == NULL)
2754 return;
2755
2756 memset(input, 0, sizeof *input);
2757 input->display = d;
Kristian Høgsberga8d1fa72011-08-23 18:14:06 -04002758 input->input_device =
2759 wl_display_bind(d->display, id, &wl_input_device_interface);
Kristian Høgsberg808fd412010-07-20 17:06:19 -04002760 input->pointer_focus = NULL;
2761 input->keyboard_focus = NULL;
2762 wl_list_insert(d->input_list.prev, &input->link);
2763
2764 wl_input_device_add_listener(input->input_device,
2765 &input_device_listener, input);
Kristian Høgsberg9a686242010-08-18 15:28:04 -04002766 wl_input_device_set_user_data(input->input_device, input);
Kristian Høgsberg808fd412010-07-20 17:06:19 -04002767
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04002768 input->data_device =
2769 wl_data_device_manager_get_data_device(d->data_device_manager,
2770 input->input_device);
2771 wl_data_device_add_listener(input->data_device,
2772 &data_device_listener, input);
Kristian Høgsberg58eec362011-01-19 14:27:42 -05002773}
2774
Kristian Høgsberg808fd412010-07-20 17:06:19 -04002775static void
Pekka Paalanene1207c72011-12-16 12:02:09 +02002776input_destroy(struct input *input)
2777{
Kristian Høgsberg8a1d10d2011-12-21 17:11:45 -05002778 input_remove_keyboard_focus(input);
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04002779 input_remove_pointer_focus(input);
Pekka Paalanene1207c72011-12-16 12:02:09 +02002780
2781 if (input->drag_offer)
2782 data_offer_destroy(input->drag_offer);
2783
2784 if (input->selection_offer)
2785 data_offer_destroy(input->selection_offer);
2786
2787 wl_data_device_destroy(input->data_device);
2788 wl_list_remove(&input->link);
2789 wl_input_device_destroy(input->input_device);
2790 free(input);
2791}
2792
2793static void
Kristian Høgsberg4fe1a3e2010-08-10 14:02:48 -04002794display_handle_global(struct wl_display *display, uint32_t id,
2795 const char *interface, uint32_t version, void *data)
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05002796{
2797 struct display *d = data;
2798
Kristian Høgsberg7cbdb642011-04-20 18:53:07 -04002799 if (strcmp(interface, "wl_compositor") == 0) {
Kristian Høgsberga8d1fa72011-08-23 18:14:06 -04002800 d->compositor =
2801 wl_display_bind(display, id, &wl_compositor_interface);
Kristian Høgsberg7cbdb642011-04-20 18:53:07 -04002802 } else if (strcmp(interface, "wl_output") == 0) {
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -05002803 display_add_output(d, id);
Kristian Høgsberg7cbdb642011-04-20 18:53:07 -04002804 } else if (strcmp(interface, "wl_input_device") == 0) {
Kristian Høgsberg4fe1a3e2010-08-10 14:02:48 -04002805 display_add_input(d, id);
Kristian Høgsberg7cbdb642011-04-20 18:53:07 -04002806 } else if (strcmp(interface, "wl_shell") == 0) {
Kristian Høgsberga8d1fa72011-08-23 18:14:06 -04002807 d->shell = wl_display_bind(display, id, &wl_shell_interface);
Kristian Høgsberg7cbdb642011-04-20 18:53:07 -04002808 } else if (strcmp(interface, "wl_shm") == 0) {
Kristian Høgsberga8d1fa72011-08-23 18:14:06 -04002809 d->shm = wl_display_bind(display, id, &wl_shm_interface);
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04002810 } else if (strcmp(interface, "wl_data_device_manager") == 0) {
2811 d->data_device_manager =
2812 wl_display_bind(display, id,
2813 &wl_data_device_manager_interface);
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05002814 }
2815}
2816
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -04002817static void
2818display_render_frame(struct display *d)
2819{
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -04002820 cairo_t *cr;
Kristian Høgsbergb8abe7e2012-03-20 23:56:05 -04002821 cairo_pattern_t *pattern;
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -04002822
Kristian Høgsbergb8abe7e2012-03-20 23:56:05 -04002823 d->frame_radius = 3;
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -04002824 d->shadow = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 128, 128);
2825 cr = cairo_create(d->shadow);
2826 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
2827 cairo_set_source_rgba(cr, 0, 0, 0, 1);
Kristian Høgsbergec323d22012-03-21 01:07:49 -04002828 rounded_rect(cr, 32, 32, 96, 96, d->frame_radius);
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -04002829 cairo_fill(cr);
2830 cairo_destroy(cr);
2831 blur_surface(d->shadow, 64);
2832
2833 d->active_frame =
2834 cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 128, 128);
2835 cr = cairo_create(d->active_frame);
2836 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
Kristian Høgsbergb8abe7e2012-03-20 23:56:05 -04002837
2838 pattern = cairo_pattern_create_linear(16, 16, 16, 112);
2839 cairo_pattern_add_color_stop_rgb(pattern, 0.0, 1.0, 1.0, 1.0);
2840 cairo_pattern_add_color_stop_rgb(pattern, 0.2, 0.8, 0.8, 0.8);
2841 cairo_set_source(cr, pattern);
2842 cairo_pattern_destroy(pattern);
2843
Kristian Høgsbergec323d22012-03-21 01:07:49 -04002844 rounded_rect(cr, 0, 0, 128, 128, d->frame_radius);
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -04002845 cairo_fill(cr);
2846 cairo_destroy(cr);
2847
2848 d->inactive_frame =
2849 cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 128, 128);
2850 cr = cairo_create(d->inactive_frame);
2851 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
Kristian Høgsbergb8abe7e2012-03-20 23:56:05 -04002852 cairo_set_source_rgba(cr, 0.75, 0.75, 0.75, 1);
Kristian Høgsbergec323d22012-03-21 01:07:49 -04002853 rounded_rect(cr, 0, 0, 128, 128, d->frame_radius);
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -04002854 cairo_fill(cr);
2855 cairo_destroy(cr);
2856}
2857
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -04002858static void
2859init_xkb(struct display *d)
2860{
Kristian Høgsberg70163132012-05-08 15:55:39 -04002861 d->xkb.names.rules = "evdev";
2862 d->xkb.names.model = "pc105";
2863 d->xkb.names.layout = (char *) option_xkb_layout;
2864 d->xkb.names.variant = (char *) option_xkb_variant;
2865 d->xkb.names.options = (char *) option_xkb_options;
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -04002866
Kristian Høgsberg70163132012-05-08 15:55:39 -04002867 d->xkb.context = xkb_context_new();
2868 if (!d->xkb.context) {
2869 fprintf(stderr, "Failed to create XKB context\n");
2870 exit(1);
2871 }
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -04002872
Kristian Høgsberg70163132012-05-08 15:55:39 -04002873 d->xkb.keymap =
2874 xkb_map_new_from_names(d->xkb.context, &d->xkb.names);
2875 if (!d->xkb.keymap) {
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -04002876 fprintf(stderr, "Failed to compile keymap\n");
2877 exit(1);
2878 }
Kristian Høgsberg70163132012-05-08 15:55:39 -04002879
2880 d->xkb.state = xkb_state_new(d->xkb.keymap);
2881 if (!d->xkb.state) {
2882 fprintf(stderr, "Failed to create XKB state\n");
2883 exit(1);
2884 }
2885
2886 d->xkb.control_mask =
2887 1 << xkb_map_mod_get_index(d->xkb.keymap, "Control");
2888 d->xkb.alt_mask =
2889 1 << xkb_map_mod_get_index(d->xkb.keymap, "Mod1");
2890 d->xkb.shift_mask =
2891 1 << xkb_map_mod_get_index(d->xkb.keymap, "Shift");
2892
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -04002893}
2894
Pekka Paalanenfe6079a2011-12-15 15:20:04 +02002895static void
2896fini_xkb(struct display *display)
2897{
Kristian Høgsberg70163132012-05-08 15:55:39 -04002898 xkb_state_unref(display->xkb.state);
2899 xkb_map_unref(display->xkb.keymap);
2900 xkb_context_unref(display->xkb.context);
Pekka Paalanenfe6079a2011-12-15 15:20:04 +02002901}
2902
Kristian Høgsberg8f64ed02012-04-03 11:57:44 -04002903#ifdef HAVE_CAIRO_EGL
Yuval Fledel45568f62010-12-06 09:18:12 -05002904static int
Kristian Høgsberg297c6312011-02-04 14:11:33 -05002905init_egl(struct display *d)
Yuval Fledel45568f62010-12-06 09:18:12 -05002906{
2907 EGLint major, minor;
Benjamin Franzke6693ac22011-02-10 12:04:30 +01002908 EGLint n;
Kristian Høgsbergf389cac2011-08-31 16:21:38 -04002909
Rob Clark6396ed32012-03-11 19:48:41 -05002910#ifdef USE_CAIRO_GLESV2
2911# define GL_BIT EGL_OPENGL_ES2_BIT
2912#else
2913# define GL_BIT EGL_OPENGL_BIT
2914#endif
2915
Kristian Høgsberg8e81df42012-01-11 14:24:46 -05002916 static const EGLint argb_cfg_attribs[] = {
2917 EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PIXMAP_BIT,
Benjamin Franzke6693ac22011-02-10 12:04:30 +01002918 EGL_RED_SIZE, 1,
2919 EGL_GREEN_SIZE, 1,
2920 EGL_BLUE_SIZE, 1,
2921 EGL_ALPHA_SIZE, 1,
2922 EGL_DEPTH_SIZE, 1,
Rob Clark6396ed32012-03-11 19:48:41 -05002923 EGL_RENDERABLE_TYPE, GL_BIT,
Benjamin Franzke6693ac22011-02-10 12:04:30 +01002924 EGL_NONE
2925 };
Yuval Fledel45568f62010-12-06 09:18:12 -05002926
Kristian Høgsberg2d574392012-01-18 14:50:58 -05002927#ifdef USE_CAIRO_GLESV2
2928 static const EGLint context_attribs[] = {
2929 EGL_CONTEXT_CLIENT_VERSION, 2,
2930 EGL_NONE
2931 };
2932 EGLint api = EGL_OPENGL_ES_API;
2933#else
2934 EGLint *context_attribs = NULL;
2935 EGLint api = EGL_OPENGL_API;
2936#endif
2937
Kristian Høgsberg91342c62011-04-14 14:44:58 -04002938 d->dpy = eglGetDisplay(d->display);
Yuval Fledel45568f62010-12-06 09:18:12 -05002939 if (!eglInitialize(d->dpy, &major, &minor)) {
2940 fprintf(stderr, "failed to initialize display\n");
2941 return -1;
2942 }
2943
Kristian Høgsberg2d574392012-01-18 14:50:58 -05002944 if (!eglBindAPI(api)) {
Yuval Fledel45568f62010-12-06 09:18:12 -05002945 fprintf(stderr, "failed to bind api EGL_OPENGL_API\n");
2946 return -1;
2947 }
2948
Kristian Høgsberg8e81df42012-01-11 14:24:46 -05002949 if (!eglChooseConfig(d->dpy, argb_cfg_attribs,
2950 &d->argb_config, 1, &n) || n != 1) {
2951 fprintf(stderr, "failed to choose argb config\n");
Benjamin Franzke6693ac22011-02-10 12:04:30 +01002952 return -1;
2953 }
2954
Kristian Høgsberg8e81df42012-01-11 14:24:46 -05002955 d->argb_ctx = eglCreateContext(d->dpy, d->argb_config,
Kristian Høgsberg2d574392012-01-18 14:50:58 -05002956 EGL_NO_CONTEXT, context_attribs);
Benjamin Franzke0c991632011-09-27 21:57:31 +02002957 if (d->argb_ctx == NULL) {
Yuval Fledel45568f62010-12-06 09:18:12 -05002958 fprintf(stderr, "failed to create context\n");
2959 return -1;
2960 }
2961
Kristian Høgsberg067fd602012-02-29 16:15:53 -05002962 if (!eglMakeCurrent(d->dpy, NULL, NULL, d->argb_ctx)) {
Tim Wiederhake9c7a8cc2011-02-11 19:37:40 +01002963 fprintf(stderr, "failed to make context current\n");
Yuval Fledel45568f62010-12-06 09:18:12 -05002964 return -1;
2965 }
2966
Kristian Høgsberg8def2642011-01-14 17:41:33 -05002967#ifdef HAVE_CAIRO_EGL
Benjamin Franzke0c991632011-09-27 21:57:31 +02002968 d->argb_device = cairo_egl_device_create(d->dpy, d->argb_ctx);
2969 if (cairo_device_status(d->argb_device) != CAIRO_STATUS_SUCCESS) {
2970 fprintf(stderr, "failed to get cairo egl argb device\n");
2971 return -1;
2972 }
Yuval Fledel45568f62010-12-06 09:18:12 -05002973#endif
2974
2975 return 0;
2976}
2977
Pekka Paalanenfe6079a2011-12-15 15:20:04 +02002978static void
2979fini_egl(struct display *display)
2980{
2981#ifdef HAVE_CAIRO_EGL
2982 cairo_device_destroy(display->argb_device);
Pekka Paalanenfe6079a2011-12-15 15:20:04 +02002983#endif
2984
2985 eglMakeCurrent(display->dpy, EGL_NO_SURFACE, EGL_NO_SURFACE,
2986 EGL_NO_CONTEXT);
2987
2988 eglTerminate(display->dpy);
2989 eglReleaseThread();
2990}
Kristian Høgsberg8f64ed02012-04-03 11:57:44 -04002991#endif
Pekka Paalanenfe6079a2011-12-15 15:20:04 +02002992
Kristian Høgsberg3a696272011-09-14 17:33:48 -04002993static int
2994event_mask_update(uint32_t mask, void *data)
2995{
2996 struct display *d = data;
2997
2998 d->mask = mask;
2999
3000 return 0;
3001}
3002
3003static void
3004handle_display_data(struct task *task, uint32_t events)
3005{
3006 struct display *display =
3007 container_of(task, struct display, display_task);
3008
3009 wl_display_iterate(display->display, display->mask);
3010}
3011
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05003012struct display *
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04003013display_create(int argc, char *argv[])
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05003014{
3015 struct display *d;
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -04003016
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04003017 argc = parse_options(xkb_options,
3018 ARRAY_LENGTH(xkb_options), argc, argv);
Kristian Høgsbergc7c60642010-08-29 21:33:39 -04003019
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05003020 d = malloc(sizeof *d);
3021 if (d == NULL)
3022 return NULL;
3023
Tim Wiederhake81bd9792011-01-23 23:25:26 +01003024 memset(d, 0, sizeof *d);
3025
Kristian Høgsberg2bb3ebe2010-12-01 15:36:20 -05003026 d->display = wl_display_connect(NULL);
Kristian Høgsberg478d9262010-06-08 20:34:11 -04003027 if (d->display == NULL) {
3028 fprintf(stderr, "failed to create display: %m\n");
Kristian Høgsberg7824d812010-06-08 14:59:44 -04003029 return NULL;
3030 }
3031
Kristian Høgsberg3a696272011-09-14 17:33:48 -04003032 d->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
3033 d->display_fd = wl_display_get_fd(d->display, event_mask_update, d);
3034 d->display_task.run = handle_display_data;
3035 display_watch_fd(d, d->display_fd, EPOLLIN, &d->display_task);
3036
3037 wl_list_init(&d->deferred_list);
Kristian Høgsberg808fd412010-07-20 17:06:19 -04003038 wl_list_init(&d->input_list);
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -05003039 wl_list_init(&d->output_list);
Kristian Høgsberg808fd412010-07-20 17:06:19 -04003040
Kristian Høgsberg478d9262010-06-08 20:34:11 -04003041 /* Set up listener so we'll catch all events. */
3042 wl_display_add_global_listener(d->display,
3043 display_handle_global, d);
3044
3045 /* Process connection events. */
3046 wl_display_iterate(d->display, WL_DISPLAY_READABLE);
Kristian Høgsberg8f64ed02012-04-03 11:57:44 -04003047#ifdef HAVE_CAIRO_EGL
Kristian Høgsberg297c6312011-02-04 14:11:33 -05003048 if (init_egl(d) < 0)
Kristian Høgsberg7824d812010-06-08 14:59:44 -04003049 return NULL;
Kristian Høgsberg8f64ed02012-04-03 11:57:44 -04003050#endif
Kristian Høgsberg8a9cda82008-11-03 15:31:30 -05003051
Kristian Høgsberg0d5007a2011-02-09 10:57:44 -05003052 d->image_target_texture_2d =
3053 (void *) eglGetProcAddress("glEGLImageTargetTexture2DOES");
3054 d->create_image = (void *) eglGetProcAddress("eglCreateImageKHR");
3055 d->destroy_image = (void *) eglGetProcAddress("eglDestroyImageKHR");
3056
Ander Conselvan de Oliveira1493d2a2012-05-03 12:29:46 +03003057 create_cursors(d);
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04003058
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -04003059 display_render_frame(d);
3060
Kristian Høgsberg478d9262010-06-08 20:34:11 -04003061 wl_list_init(&d->window_list);
3062
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -04003063 init_xkb(d);
3064
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05003065 return d;
3066}
3067
Pekka Paalanen2c1426a2011-12-16 11:35:34 +02003068static void
3069display_destroy_outputs(struct display *display)
3070{
3071 struct output *tmp;
3072 struct output *output;
3073
3074 wl_list_for_each_safe(output, tmp, &display->output_list, link)
3075 output_destroy(output);
3076}
3077
Pekka Paalanene1207c72011-12-16 12:02:09 +02003078static void
3079display_destroy_inputs(struct display *display)
3080{
3081 struct input *tmp;
3082 struct input *input;
3083
3084 wl_list_for_each_safe(input, tmp, &display->input_list, link)
3085 input_destroy(input);
3086}
3087
Pekka Paalanen999c5b52011-11-30 10:52:38 +02003088void
Pekka Paalanenfe6079a2011-12-15 15:20:04 +02003089display_destroy(struct display *display)
3090{
Pekka Paalanenc2052982011-12-16 11:41:32 +02003091 if (!wl_list_empty(&display->window_list))
3092 fprintf(stderr, "toytoolkit warning: windows exist.\n");
3093
3094 if (!wl_list_empty(&display->deferred_list))
3095 fprintf(stderr, "toytoolkit warning: deferred tasks exist.\n");
3096
Pekka Paalanen2c1426a2011-12-16 11:35:34 +02003097 display_destroy_outputs(display);
Pekka Paalanene1207c72011-12-16 12:02:09 +02003098 display_destroy_inputs(display);
Pekka Paalanen2c1426a2011-12-16 11:35:34 +02003099
Pekka Paalanenfe6079a2011-12-15 15:20:04 +02003100 fini_xkb(display);
Pekka Paalanen325bb602011-12-19 10:31:45 +02003101
3102 cairo_surface_destroy(display->active_frame);
3103 cairo_surface_destroy(display->inactive_frame);
3104 cairo_surface_destroy(display->shadow);
Ander Conselvan de Oliveira1493d2a2012-05-03 12:29:46 +03003105 destroy_cursors(display);
Pekka Paalanen325bb602011-12-19 10:31:45 +02003106
Kristian Høgsberg8f64ed02012-04-03 11:57:44 -04003107#ifdef HAVE_CAIRO_EGL
Pekka Paalanenfe6079a2011-12-15 15:20:04 +02003108 fini_egl(display);
Kristian Høgsberg8f64ed02012-04-03 11:57:44 -04003109#endif
Pekka Paalanenfe6079a2011-12-15 15:20:04 +02003110
Pekka Paalanenc2052982011-12-16 11:41:32 +02003111 if (display->shell)
3112 wl_shell_destroy(display->shell);
3113
3114 if (display->shm)
3115 wl_shm_destroy(display->shm);
3116
3117 if (display->data_device_manager)
3118 wl_data_device_manager_destroy(display->data_device_manager);
3119
3120 wl_compositor_destroy(display->compositor);
3121
3122 close(display->epoll_fd);
3123
Pekka Paalanenfe6079a2011-12-15 15:20:04 +02003124 wl_display_flush(display->display);
Kristian Høgsbergfcfc83f2012-02-28 14:29:19 -05003125 wl_display_disconnect(display->display);
Pekka Paalanenfe6079a2011-12-15 15:20:04 +02003126 free(display);
3127}
3128
3129void
Pekka Paalanen999c5b52011-11-30 10:52:38 +02003130display_set_user_data(struct display *display, void *data)
3131{
3132 display->user_data = data;
3133}
3134
3135void *
3136display_get_user_data(struct display *display)
3137{
3138 return display->user_data;
3139}
3140
Kristian Høgsberg9d69f8e2010-09-03 14:46:38 -04003141struct wl_display *
3142display_get_display(struct display *display)
3143{
3144 return display->display;
3145}
3146
Kristian Høgsberg53ff2f62011-11-26 17:27:37 -05003147struct output *
3148display_get_output(struct display *display)
3149{
3150 return container_of(display->output_list.next, struct output, link);
3151}
3152
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05003153struct wl_compositor *
3154display_get_compositor(struct display *display)
3155{
3156 return display->compositor;
Kristian Høgsberg61017b12008-11-02 18:51:48 -05003157}
Kristian Høgsberg7824d812010-06-08 14:59:44 -04003158
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04003159uint32_t
3160display_get_serial(struct display *display)
3161{
3162 return display->serial;
3163}
3164
Kristian Høgsberg7824d812010-06-08 14:59:44 -04003165EGLDisplay
3166display_get_egl_display(struct display *d)
3167{
3168 return d->dpy;
3169}
3170
Kristian Høgsberg47fe08a2011-10-28 12:26:06 -04003171struct wl_data_source *
3172display_create_data_source(struct display *display)
3173{
3174 return wl_data_device_manager_create_data_source(display->data_device_manager);
3175}
3176
Benjamin Franzkecff904e2011-02-18 23:00:55 +01003177EGLConfig
Benjamin Franzke0c991632011-09-27 21:57:31 +02003178display_get_argb_egl_config(struct display *d)
3179{
Kristian Høgsberg8e81df42012-01-11 14:24:46 -05003180 return d->argb_config;
Benjamin Franzke0c991632011-09-27 21:57:31 +02003181}
3182
Kristian Høgsberg58eec362011-01-19 14:27:42 -05003183struct wl_shell *
3184display_get_shell(struct display *display)
3185{
3186 return display->shell;
3187}
3188
Benjamin Franzke1a89f282011-10-07 09:33:06 +02003189int
Benjamin Franzkecff904e2011-02-18 23:00:55 +01003190display_acquire_window_surface(struct display *display,
3191 struct window *window,
3192 EGLContext ctx)
3193{
Benjamin Franzke22d54812011-07-16 19:50:32 +00003194#ifdef HAVE_CAIRO_EGL
Benjamin Franzkecff904e2011-02-18 23:00:55 +01003195 struct egl_window_surface_data *data;
Benjamin Franzke0c991632011-09-27 21:57:31 +02003196 cairo_device_t *device;
Benjamin Franzkecff904e2011-02-18 23:00:55 +01003197
3198 if (!window->cairo_surface)
Benjamin Franzke1a89f282011-10-07 09:33:06 +02003199 return -1;
Benjamin Franzke0c991632011-09-27 21:57:31 +02003200 device = cairo_surface_get_device(window->cairo_surface);
3201 if (!device)
Benjamin Franzke1a89f282011-10-07 09:33:06 +02003202 return -1;
Benjamin Franzkecff904e2011-02-18 23:00:55 +01003203
Benjamin Franzke0c991632011-09-27 21:57:31 +02003204 if (!ctx) {
Kristian Høgsberg067fd602012-02-29 16:15:53 -05003205 if (device == display->argb_device)
Benjamin Franzke0c991632011-09-27 21:57:31 +02003206 ctx = display->argb_ctx;
3207 else
3208 assert(0);
3209 }
Benjamin Franzkecff904e2011-02-18 23:00:55 +01003210
3211 data = cairo_surface_get_user_data(window->cairo_surface,
3212 &surface_data_key);
3213
Pekka Paalanen9015ead2011-12-19 13:57:59 +02003214 cairo_device_flush(device);
Benjamin Franzke0c991632011-09-27 21:57:31 +02003215 cairo_device_acquire(device);
Benjamin Franzkecff904e2011-02-18 23:00:55 +01003216 if (!eglMakeCurrent(display->dpy, data->surf, data->surf, ctx))
3217 fprintf(stderr, "failed to make surface current\n");
Benjamin Franzke1a89f282011-10-07 09:33:06 +02003218
3219 return 0;
3220#else
3221 return -1;
Benjamin Franzke22d54812011-07-16 19:50:32 +00003222#endif
Benjamin Franzkecff904e2011-02-18 23:00:55 +01003223}
3224
3225void
Benjamin Franzke0c991632011-09-27 21:57:31 +02003226display_release_window_surface(struct display *display,
3227 struct window *window)
Benjamin Franzkecff904e2011-02-18 23:00:55 +01003228{
Benjamin Franzke0c991632011-09-27 21:57:31 +02003229#ifdef HAVE_CAIRO_EGL
3230 cairo_device_t *device;
3231
3232 device = cairo_surface_get_device(window->cairo_surface);
3233 if (!device)
3234 return;
3235
Kristian Høgsberg067fd602012-02-29 16:15:53 -05003236 if (!eglMakeCurrent(display->dpy, NULL, NULL, display->argb_ctx))
Benjamin Franzkecff904e2011-02-18 23:00:55 +01003237 fprintf(stderr, "failed to make context current\n");
Benjamin Franzke0c991632011-09-27 21:57:31 +02003238 cairo_device_release(device);
3239#endif
Benjamin Franzkecff904e2011-02-18 23:00:55 +01003240}
3241
3242void
Kristian Høgsberg3a696272011-09-14 17:33:48 -04003243display_defer(struct display *display, struct task *task)
Kristian Høgsberg7824d812010-06-08 14:59:44 -04003244{
Kristian Høgsberg3a696272011-09-14 17:33:48 -04003245 wl_list_insert(&display->deferred_list, &task->link);
3246}
3247
3248void
3249display_watch_fd(struct display *display,
3250 int fd, uint32_t events, struct task *task)
3251{
3252 struct epoll_event ep;
3253
3254 ep.events = events;
3255 ep.data.ptr = task;
3256 epoll_ctl(display->epoll_fd, EPOLL_CTL_ADD, fd, &ep);
3257}
3258
3259void
3260display_run(struct display *display)
3261{
3262 struct task *task;
3263 struct epoll_event ep[16];
3264 int i, count;
3265
Pekka Paalanen826d7952011-12-15 10:14:07 +02003266 display->running = 1;
Kristian Høgsberg3a696272011-09-14 17:33:48 -04003267 while (1) {
Kristian Høgsberg9ca2d082012-01-09 18:48:14 -05003268 wl_display_flush(display->display);
Kristian Høgsberg3a696272011-09-14 17:33:48 -04003269
3270 while (!wl_list_empty(&display->deferred_list)) {
3271 task = container_of(display->deferred_list.next,
3272 struct task, link);
3273 wl_list_remove(&task->link);
3274 task->run(task, 0);
3275 }
Kristian Høgsberg9ca2d082012-01-09 18:48:14 -05003276
3277 if (!display->running)
3278 break;
3279
3280 wl_display_flush(display->display);
3281
3282 count = epoll_wait(display->epoll_fd,
3283 ep, ARRAY_LENGTH(ep), -1);
3284 for (i = 0; i < count; i++) {
3285 task = ep[i].data.ptr;
3286 task->run(task, ep[i].events);
3287 }
Kristian Høgsberg3a696272011-09-14 17:33:48 -04003288 }
Kristian Høgsberg7824d812010-06-08 14:59:44 -04003289}
Pekka Paalanen826d7952011-12-15 10:14:07 +02003290
3291void
3292display_exit(struct display *display)
3293{
3294 display->running = 0;
3295}