blob: 1c1526b97dee306ed690d7160217ca78100979b7 [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øgsbergd0c3b9d2010-10-25 11:40:03 -040023#include "../config.h"
24
Kristian Høgsberg61017b12008-11-02 18:51:48 -050025#include <stdint.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
Kristian Høgsberg61017b12008-11-02 18:51:48 -050029#include <fcntl.h>
30#include <unistd.h>
31#include <math.h>
32#include <time.h>
33#include <cairo.h>
Kristian Høgsberg1cbaa6a2008-11-07 15:54:48 -050034#include <glib.h>
Kristian Høgsberg478d9262010-06-08 20:34:11 -040035#include <glib-object.h>
Kristian Høgsbergda275dd2010-08-16 17:47:07 -040036#include <gdk-pixbuf/gdk-pixbuf.h>
Kristian Høgsberg640609a2010-08-09 22:11:47 -040037#include <xf86drm.h>
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -040038#include <sys/mman.h>
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -040039
40#define EGL_EGLEXT_PROTOTYPES 1
41#define GL_GLEXT_PROTOTYPES 1
42#include <GL/gl.h>
43#include <EGL/egl.h>
44#include <EGL/eglext.h>
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -040045
46#ifdef HAVE_CAIRO_GL
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -040047#include <cairo-gl.h>
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -040048#endif
Kristian Høgsberg61017b12008-11-02 18:51:48 -050049
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -040050#include <X11/extensions/XKBcommon.h>
51
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -050052#include <linux/input.h>
Kristian Høgsberg3c38fa02009-02-23 22:30:29 -050053#include "wayland-util.h"
Kristian Høgsberg61017b12008-11-02 18:51:48 -050054#include "wayland-client.h"
Kristian Høgsberg1cbaa6a2008-11-07 15:54:48 -050055#include "wayland-glib.h"
Kristian Høgsbergb91cd102010-08-16 16:17:42 -040056#include "cairo-util.h"
Kristian Høgsberg2f2cfae2008-11-08 22:46:30 -050057
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -050058#include "window.h"
Kristian Høgsberg8a9cda82008-11-03 15:31:30 -050059
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -050060struct display {
Kristian Høgsberg40979232008-11-25 22:40:39 -050061 struct wl_display *display;
Kristian Høgsbergd2412e22008-12-15 20:35:24 -050062 struct wl_compositor *compositor;
Kristian Høgsberg83fc0612010-08-04 22:44:55 -040063 struct wl_shell *shell;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -040064 struct wl_drm *drm;
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -040065 struct wl_shm *shm;
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -050066 struct wl_output *output;
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -050067 struct rectangle screen_allocation;
Kristian Høgsberg640609a2010-08-09 22:11:47 -040068 int authenticated;
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -040069 EGLDisplay dpy;
70 EGLContext ctx;
Janusz Lewandowskid923e9d2010-01-31 03:01:26 +010071 cairo_device_t *device;
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -050072 int fd;
Kristian Høgsberg7824d812010-06-08 14:59:44 -040073 GMainLoop *loop;
74 GSource *source;
Kristian Høgsberg478d9262010-06-08 20:34:11 -040075 struct wl_list window_list;
Kristian Høgsberg808fd412010-07-20 17:06:19 -040076 struct wl_list input_list;
Kristian Høgsberg478d9262010-06-08 20:34:11 -040077 char *device_name;
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -040078 cairo_surface_t *active_frame, *inactive_frame, *shadow;
Kristian Høgsberg3e6e7e62010-07-02 15:12:02 -040079 struct xkb_desc *xkb;
Kristian Høgsberg9a686242010-08-18 15:28:04 -040080 cairo_surface_t **pointer_surfaces;
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -040081
82 display_drag_offer_handler_t drag_offer_handler;
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -050083};
84
85struct window {
86 struct display *display;
Kristian Høgsberg61017b12008-11-02 18:51:48 -050087 struct wl_surface *surface;
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -050088 const char *title;
Kristian Høgsberg83fc0612010-08-04 22:44:55 -040089 struct rectangle allocation, saved_allocation, pending_allocation;
90 int resize_edges;
Kristian Høgsberg80d746f2010-06-14 23:52:50 -040091 int redraw_scheduled;
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -050092 int minimum_width, minimum_height;
Kristian Høgsberg40979232008-11-25 22:40:39 -050093 int margin;
Kristian Høgsberg0395f302008-12-22 12:14:50 -050094 int fullscreen;
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -040095 int decoration;
Kristian Høgsberg808fd412010-07-20 17:06:19 -040096 struct input *grab_device;
97 struct input *keyboard_device;
Kristian Høgsberg61017b12008-11-02 18:51:48 -050098 uint32_t name;
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -040099 enum window_buffer_type buffer_type;
Kristian Høgsberg78231c82008-11-08 15:06:01 -0500100
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -0400101 EGLImageKHR *image;
Kristian Høgsberg6a1b2012009-12-16 14:43:37 -0500102 cairo_surface_t *cairo_surface, *pending_surface;
Kristian Høgsberg8a9cda82008-11-03 15:31:30 -0500103
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500104 window_resize_handler_t resize_handler;
Kristian Høgsberg80d746f2010-06-14 23:52:50 -0400105 window_redraw_handler_t redraw_handler;
Kristian Høgsberg6e83d582008-12-08 00:01:36 -0500106 window_key_handler_t key_handler;
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400107 window_button_handler_t button_handler;
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -0500108 window_keyboard_focus_handler_t keyboard_focus_handler;
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400109 window_motion_handler_t motion_handler;
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -0400110
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500111 void *user_data;
Kristian Høgsberg478d9262010-06-08 20:34:11 -0400112 struct wl_list link;
Kristian Høgsberg61017b12008-11-02 18:51:48 -0500113};
114
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400115struct input {
116 struct display *display;
117 struct wl_input_device *input_device;
118 struct window *pointer_focus;
119 struct window *keyboard_focus;
Kristian Høgsberg7d804062010-09-07 21:50:06 -0400120 uint32_t current_pointer_image;
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400121 uint32_t modifiers;
122 int32_t x, y, sx, sy;
123 struct wl_list link;
124};
125
Kristian Høgsberg7d804062010-09-07 21:50:06 -0400126enum {
127 POINTER_DEFAULT = 100,
128 POINTER_UNSET
129};
130
Kristian Høgsbergc7c60642010-08-29 21:33:39 -0400131const char *option_xkb_layout = "us";
132const char *option_xkb_variant = "";
133const char *option_xkb_options = "";
134
135static const GOptionEntry xkb_option_entries[] = {
136 { "xkb-layout", 0, 0, G_OPTION_ARG_STRING,
137 &option_xkb_layout, "XKB Layout" },
138 { "xkb-variant", 0, 0, G_OPTION_ARG_STRING,
139 &option_xkb_variant, "XKB Variant" },
140 { "xkb-options", 0, 0, G_OPTION_ARG_STRING,
141 &option_xkb_options, "XKB Options" },
142 { NULL }
143};
144
Kristian Høgsberge4feb562008-11-08 18:53:37 -0500145static void
146rounded_rect(cairo_t *cr, int x0, int y0, int x1, int y1, int radius)
147{
148 cairo_move_to(cr, x0, y0 + radius);
149 cairo_arc(cr, x0 + radius, y0 + radius, radius, M_PI, 3 * M_PI / 2);
150 cairo_line_to(cr, x1 - radius, y0);
151 cairo_arc(cr, x1 - radius, y0 + radius, radius, 3 * M_PI / 2, 2 * M_PI);
152 cairo_line_to(cr, x1, y1 - radius);
153 cairo_arc(cr, x1 - radius, y1 - radius, radius, 0, M_PI / 2);
154 cairo_line_to(cr, x0 + radius, y1);
155 cairo_arc(cr, x0 + radius, y1 - radius, radius, M_PI / 2, M_PI);
156 cairo_close_path(cr);
157}
158
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400159static const cairo_user_data_key_t surface_data_key;
160struct surface_data {
161 struct wl_buffer *buffer;
162};
163
164#ifdef HAVE_CAIRO_GL
165
166struct drm_surface_data {
167 struct surface_data data;
168 EGLImageKHR image;
169 GLuint texture;
170 EGLDisplay dpy;
171};
172
173static void
174drm_surface_data_destroy(void *p)
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400175{
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400176 struct drm_surface_data *data = p;
177
178 glDeleteTextures(1, &data->texture);
179 eglDestroyImageKHR(data->dpy, data->image);
180 wl_buffer_destroy(data->data.buffer);
181}
182
183cairo_surface_t *
184display_create_drm_surface(struct display *display,
185 struct rectangle *rectangle)
186{
187 struct drm_surface_data *data;
188 EGLDisplay dpy = display->dpy;
189 cairo_surface_t *surface;
190 struct wl_visual *visual;
191 struct wl_buffer *buffer;
192 EGLint name, stride;
193
194 EGLint image_attribs[] = {
195 EGL_WIDTH, 0,
196 EGL_HEIGHT, 0,
197 EGL_DRM_BUFFER_FORMAT_MESA, EGL_DRM_BUFFER_FORMAT_ARGB32_MESA,
198 EGL_DRM_BUFFER_USE_MESA, EGL_DRM_BUFFER_USE_SCANOUT_MESA,
199 EGL_NONE
200 };
201
202 data = malloc(sizeof *data);
203 if (data == NULL)
204 return NULL;
205
206 image_attribs[1] = rectangle->width;
207 image_attribs[3] = rectangle->height;
208 data->image = eglCreateDRMImageMESA(dpy, image_attribs);
209 glGenTextures(1, &data->texture);
210 data->dpy = dpy;
211 glBindTexture(GL_TEXTURE_2D, data->texture);
212 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, data->image);
213
214 eglExportDRMImageMESA(display->dpy, data->image, &name, NULL, &stride);
215
216 visual = wl_display_get_premultiplied_argb_visual(display->display);
217 data->data.buffer =
218 wl_drm_create_buffer(display->drm, name, rectangle->width,
219 rectangle->height, stride, visual);
220
221 surface = cairo_gl_surface_create_for_texture(display->device,
222 CAIRO_CONTENT_COLOR_ALPHA,
223 data->texture,
224 rectangle->width,
225 rectangle->height);
226
227 cairo_surface_set_user_data (surface, &surface_data_key,
228 data, drm_surface_data_destroy);
229
230 return surface;
231}
232
233cairo_surface_t *
234display_create_drm_surface_from_file(struct display *display,
235 const char *filename,
236 struct rectangle *rect)
237{
238 cairo_surface_t *surface;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400239 GdkPixbuf *pixbuf;
240 GError *error = NULL;
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400241 int stride, i;
242 unsigned char *pixels, *p, *end;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400243
244 pixbuf = gdk_pixbuf_new_from_file_at_scale(filename,
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400245 rect->width, rect->height,
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400246 FALSE, &error);
247 if (error != NULL)
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400248 return NULL;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400249
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400250 if (!gdk_pixbuf_get_has_alpha(pixbuf) ||
251 gdk_pixbuf_get_n_channels(pixbuf) != 4) {
252 gdk_pixbuf_unref(pixbuf);
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400253 return NULL;
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400254 }
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400255
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400256
257 stride = gdk_pixbuf_get_rowstride(pixbuf);
258 pixels = gdk_pixbuf_get_pixels(pixbuf);
259
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400260 for (i = 0; i < rect->height; i++) {
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400261 p = pixels + i * stride;
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400262 end = p + rect->width * 4;
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400263 while (p < end) {
264 unsigned int t;
265
266#define MULT(d,c,a,t) \
267 do { t = c * a + 0x7f; d = ((t >> 8) + t) >> 8; } while (0)
268
269 MULT(p[0], p[0], p[3], t);
270 MULT(p[1], p[1], p[3], t);
271 MULT(p[2], p[2], p[3], t);
272 p += 4;
273
274 }
275 }
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400276
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400277 surface = display_create_drm_surface(display, rect);
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400278 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400279 rect->width, rect->height,
280 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400281
282 gdk_pixbuf_unref(pixbuf);
283
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400284 return surface;
285}
286
287#endif
288
289struct wl_buffer *
290display_get_buffer_for_surface(struct display *display,
291 cairo_surface_t *surface)
292{
293 struct surface_data *data;
294
295 data = cairo_surface_get_user_data (surface, &surface_data_key);
296
297 return data->buffer;
298}
299
300struct shm_surface_data {
301 struct surface_data data;
302 void *map;
303 size_t length;
304};
305
306void
307shm_surface_data_destroy(void *p)
308{
309 struct shm_surface_data *data = p;
310
311 wl_buffer_destroy(data->data.buffer);
312 munmap(data->map, data->length);
313}
314
315cairo_surface_t *
316display_create_shm_surface(struct display *display,
317 struct rectangle *rectangle)
318{
319 struct shm_surface_data *data;
320 cairo_surface_t *surface;
321 struct wl_visual *visual;
322 int stride, alloc, fd;
323 char filename[] = "/tmp/wayland-shm-XXXXXX";
324
325 data = malloc(sizeof *data);
326 if (data == NULL)
327 return NULL;
328
329 stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32,
330 rectangle->width);
331 data->length = stride * rectangle->height;
332 fd = mkstemp(filename);
333 if (fd < 0) {
334 fprintf(stderr, "open %s failed: %m", filename);
335 return NULL;
336 }
337 if (ftruncate(fd, data->length) < 0) {
338 fprintf(stderr, "ftruncate failed: %m");
339 close(fd);
340 return NULL;
341 }
342
343 data->map = mmap(NULL, data->length,
344 PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
345 unlink(filename);
346
347 if (data->map == MAP_FAILED) {
348 fprintf(stderr, "mmap failed: %m");
349 close(fd);
350 return NULL;
351 }
352
353 surface = cairo_image_surface_create_for_data (data->map,
354 CAIRO_FORMAT_ARGB32,
355 rectangle->width,
356 rectangle->height,
357 stride);
358
359 cairo_surface_set_user_data (surface, &surface_data_key,
360 data, shm_surface_data_destroy);
361
362 visual = wl_display_get_premultiplied_argb_visual(display->display);
363 data->data.buffer = wl_shm_create_buffer(display->shm,
364 fd,
365 rectangle->width,
366 rectangle->height,
367 stride, visual);
368
369 close(fd);
370
371 return surface;
372}
373
374cairo_surface_t *
375display_create_shm_surface_from_file(struct display *display,
376 const char *filename,
377 struct rectangle *rect)
378{
379 cairo_surface_t *surface;
380 GdkPixbuf *pixbuf;
381 GError *error = NULL;
382 int stride, i;
383 unsigned char *pixels, *p, *end, *dest_data;
384 int dest_stride;
385 uint32_t *d;
386
387 pixbuf = gdk_pixbuf_new_from_file_at_scale(filename,
388 rect->width, rect->height,
389 FALSE, &error);
390 if (error != NULL)
391 return NULL;
392
393 if (!gdk_pixbuf_get_has_alpha(pixbuf) ||
394 gdk_pixbuf_get_n_channels(pixbuf) != 4) {
395 gdk_pixbuf_unref(pixbuf);
396 return NULL;
397 }
398
399 stride = gdk_pixbuf_get_rowstride(pixbuf);
400 pixels = gdk_pixbuf_get_pixels(pixbuf);
401
402 surface = display_create_shm_surface(display, rect);
403 dest_data = cairo_image_surface_get_data (surface);
404 dest_stride = cairo_image_surface_get_stride (surface);
405
406 for (i = 0; i < rect->height; i++) {
407 d = (uint32_t *) (dest_data + i * dest_stride);
408 p = pixels + i * stride;
409 end = p + rect->width * 4;
410 while (p < end) {
411 unsigned int t;
412 unsigned char a, r, g, b;
413
414#define MULT(_d,c,a,t) \
415 do { t = c * a + 0x7f; _d = ((t >> 8) + t) >> 8; } while (0)
416
417 a = p[3];
418 MULT(r, p[0], a, t);
419 MULT(g, p[1], a, t);
420 MULT(b, p[2], a, t);
421 p += 4;
422 *d++ = (a << 24) | (r << 16) | (g << 8) | b;
423 }
424 }
425
426 gdk_pixbuf_unref(pixbuf);
427
428 return surface;
429}
430
431cairo_surface_t *
432display_create_surface(struct display *display,
433 struct rectangle *rectangle)
434{
435#ifdef HAVE_CAIRO_GL
436 display_create_drm_surface(display, rectangle);
437#else
438 display_create_shm_surface(display, rectangle);
439#endif
440}
441
442cairo_surface_t *
443display_create_surface_from_file(struct display *display,
444 const char *filename,
445 struct rectangle *rectangle)
446{
447#ifdef HAVE_CAIRO_GL
448 display_create_drm_surface_from_file(display, filename, rectangle);
449#else
450 display_create_shm_surface_from_file(display, filename, rectangle);
451#endif
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400452}
453
454static const struct {
455 const char *filename;
456 int hotspot_x, hotspot_y;
457} pointer_images[] = {
458 { DATADIR "/wayland/bottom_left_corner.png", 6, 30 },
459 { DATADIR "/wayland/bottom_right_corner.png", 28, 28 },
460 { DATADIR "/wayland/bottom_side.png", 16, 20 },
461 { DATADIR "/wayland/grabbing.png", 20, 17 },
462 { DATADIR "/wayland/left_ptr.png", 10, 5 },
463 { DATADIR "/wayland/left_side.png", 10, 20 },
464 { DATADIR "/wayland/right_side.png", 30, 19 },
465 { DATADIR "/wayland/top_left_corner.png", 8, 8 },
466 { DATADIR "/wayland/top_right_corner.png", 26, 8 },
467 { DATADIR "/wayland/top_side.png", 18, 8 },
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400468 { DATADIR "/wayland/xterm.png", 15, 15 },
469 { DATADIR "/wayland/hand1.png", 18, 11 }
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400470};
471
472static void
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400473create_pointer_surfaces(struct display *display)
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400474{
475 int i, count;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400476 const int width = 32, height = 32;
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400477 struct rectangle rect;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400478
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400479 count = ARRAY_LENGTH(pointer_images);
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400480 display->pointer_surfaces =
481 malloc(count * sizeof *display->pointer_surfaces);
482 rect.width = width;
483 rect.height = height;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400484 for (i = 0; i < count; i++) {
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400485 display->pointer_surfaces[i] =
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400486 display_create_surface_from_file(display,
487 pointer_images[i].filename,
488 &rect);
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400489 }
490
491}
492
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400493cairo_surface_t *
494display_get_pointer_surface(struct display *display, int pointer,
495 int *width, int *height,
496 int *hotspot_x, int *hotspot_y)
497{
498 cairo_surface_t *surface;
499
500 surface = display->pointer_surfaces[pointer];
501 *width = cairo_gl_surface_get_width(surface);
502 *height = cairo_gl_surface_get_height(surface);
503 *hotspot_x = pointer_images[pointer].hotspot_x;
504 *hotspot_y = pointer_images[pointer].hotspot_y;
505
506 return cairo_surface_reference(surface);
507}
508
Kristian Høgsberg9d69f8e2010-09-03 14:46:38 -0400509
510static void
511window_attach_surface(struct window *window);
512
513static void
514free_surface(void *data)
515{
516 struct window *window = data;
517
518 cairo_surface_destroy(window->pending_surface);
519 window->pending_surface = NULL;
520 if (window->cairo_surface)
521 window_attach_surface(window);
522}
523
Kristian Høgsberg0395f302008-12-22 12:14:50 -0500524static void
Kristian Høgsberg6a1b2012009-12-16 14:43:37 -0500525window_attach_surface(struct window *window)
526{
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -0400527 struct display *display = window->display;
528 struct wl_buffer *buffer;
Kristian Høgsberg6a1b2012009-12-16 14:43:37 -0500529
Kristian Høgsberg2aac3022009-12-21 10:04:53 -0500530 if (window->pending_surface != NULL)
531 return;
532
Kristian Høgsberg09531622010-06-14 23:22:15 -0400533 window->pending_surface = window->cairo_surface;
534 window->cairo_surface = NULL;
Kristian Høgsberg2aac3022009-12-21 10:04:53 -0500535
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400536 buffer = display_get_buffer_for_surface(display,
537 window->pending_surface);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -0400538 wl_surface_attach(window->surface, buffer);
Kristian Høgsberg6a1b2012009-12-16 14:43:37 -0500539
540 wl_surface_map(window->surface,
Kristian Høgsberg83fc0612010-08-04 22:44:55 -0400541 window->allocation.x,
542 window->allocation.y,
543 window->allocation.width,
544 window->allocation.height);
Kristian Høgsberg09531622010-06-14 23:22:15 -0400545
Kristian Høgsberg9d69f8e2010-09-03 14:46:38 -0400546 wl_display_sync_callback(display->display, free_surface, window);
Kristian Høgsberg6a1b2012009-12-16 14:43:37 -0500547}
548
Kristian Høgsberga341fa02010-01-24 18:10:15 -0500549void
Kristian Høgsberg9d69f8e2010-09-03 14:46:38 -0400550window_flush(struct window *window)
Kristian Høgsberga341fa02010-01-24 18:10:15 -0500551{
Kristian Høgsberg9d69f8e2010-09-03 14:46:38 -0400552 if (window->cairo_surface)
553 window_attach_surface(window);
Kristian Høgsberga341fa02010-01-24 18:10:15 -0500554}
555
Kristian Høgsberg6a1b2012009-12-16 14:43:37 -0500556static void
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400557window_create_surface(struct window *window, struct rectangle *allocation)
558{
559 switch (window->buffer_type) {
560#ifdef HAVE_CAIRO_GL
561 case WINDOW_BUFFER_TYPE_DRM:
562 window->cairo_surface =
563 display_create_surface(window->display, allocation);
564 break;
565#endif
566 case WINDOW_BUFFER_TYPE_SHM:
567 window->cairo_surface =
568 display_create_shm_surface(window->display, allocation);
569 break;
570 }
571}
572
573static void
Kristian Høgsberg0395f302008-12-22 12:14:50 -0500574window_draw_decorations(struct window *window)
Kristian Høgsberg61017b12008-11-02 18:51:48 -0500575{
Kristian Høgsberg61017b12008-11-02 18:51:48 -0500576 cairo_t *cr;
Kristian Høgsbergca1d1f62008-11-03 06:59:52 -0500577 cairo_text_extents_t extents;
Kristian Høgsberg2d6b7c12010-06-25 16:51:57 -0400578 cairo_pattern_t *outline, *bright, *dim;
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400579 cairo_surface_t *frame;
580 int width, height, shadow_dx = 3, shadow_dy = 3;
Kristian Høgsberg61017b12008-11-02 18:51:48 -0500581
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400582 window_create_surface(window, &window->allocation);
583
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -0400584 width = window->allocation.width;
585 height = window->allocation.height;
Kristian Høgsberg61017b12008-11-02 18:51:48 -0500586
Kristian Høgsberge4feb562008-11-08 18:53:37 -0500587 outline = cairo_pattern_create_rgb(0.1, 0.1, 0.1);
Kristian Høgsberge9d550b2008-11-19 00:49:39 -0500588 bright = cairo_pattern_create_rgb(0.8, 0.8, 0.8);
Kristian Høgsberge4feb562008-11-08 18:53:37 -0500589 dim = cairo_pattern_create_rgb(0.4, 0.4, 0.4);
590
Kristian Høgsberg0ac16f02009-01-15 11:37:43 -0500591 cr = cairo_create(window->cairo_surface);
Kristian Høgsberg2f2cfae2008-11-08 22:46:30 -0500592
Kristian Høgsberg09531622010-06-14 23:22:15 -0400593 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -0400594 cairo_set_source_rgba(cr, 0, 0, 0, 0);
Kristian Høgsberg09531622010-06-14 23:22:15 -0400595 cairo_paint(cr);
596
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -0400597 cairo_set_source_rgba(cr, 0, 0, 0, 0.6);
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400598 tile_mask(cr, window->display->shadow,
599 shadow_dx, shadow_dy, width, height,
600 window->margin + 10 - shadow_dx,
601 window->margin + 10 - shadow_dy);
Kristian Høgsberg0ac16f02009-01-15 11:37:43 -0500602
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -0400603 if (window->keyboard_device)
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400604 frame = window->display->active_frame;
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -0400605 else
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400606 frame = window->display->inactive_frame;
607
608 tile_source(cr, frame, 0, 0, width, height,
609 window->margin + 10, window->margin + 50);
Kristian Høgsberge4feb562008-11-08 18:53:37 -0500610
Kristian Høgsberge4feb562008-11-08 18:53:37 -0500611 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
612 cairo_set_font_size(cr, 14);
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500613 cairo_text_extents(cr, window->title, &extents);
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -0400614 cairo_move_to(cr, (width - extents.width) / 2, 32 - extents.y_bearing);
Kristian Høgsberge4feb562008-11-08 18:53:37 -0500615 cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
616 cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
617 cairo_set_line_width (cr, 4);
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -0400618 if (window->keyboard_device)
619 cairo_set_source_rgb(cr, 0, 0, 0);
620 else
Kristian Høgsberg7d7b5db2009-09-21 13:43:46 -0400621 cairo_set_source_rgb(cr, 0.8, 0.8, 0.8);
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -0400622 cairo_show_text(cr, window->title);
623
Kristian Høgsberg61017b12008-11-02 18:51:48 -0500624 cairo_destroy(cr);
Kristian Høgsberg10ddbd22010-08-16 21:08:52 -0400625
626 cairo_device_flush (window->display->device);
Kristian Høgsberg0395f302008-12-22 12:14:50 -0500627}
628
Kristian Høgsberge968f9c2010-08-27 22:18:00 -0400629void
630display_flush_cairo_device(struct display *display)
631{
632 cairo_device_flush (display->device);
633}
634
Kristian Høgsberg0395f302008-12-22 12:14:50 -0500635static void
636window_draw_fullscreen(struct window *window)
637{
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400638 window_create_surface(window, &window->allocation);
Kristian Høgsberg0395f302008-12-22 12:14:50 -0500639}
640
641void
642window_draw(struct window *window)
643{
Kristian Høgsberg2aac3022009-12-21 10:04:53 -0500644 if (window->cairo_surface != NULL)
645 cairo_surface_destroy(window->cairo_surface);
646
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -0400647 if (window->fullscreen || !window->decoration)
Kristian Høgsberg0395f302008-12-22 12:14:50 -0500648 window_draw_fullscreen(window);
649 else
650 window_draw_decorations(window);
Kristian Høgsberg44f36e32008-11-26 12:57:31 -0500651}
652
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -0400653cairo_surface_t *
654window_get_surface(struct window *window)
655{
656 return window->cairo_surface;
657}
658
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400659enum window_location {
660 WINDOW_INTERIOR = 0,
Kristian Høgsbergbf6ceda2010-06-14 20:25:06 -0400661 WINDOW_RESIZING_TOP = 1,
662 WINDOW_RESIZING_BOTTOM = 2,
663 WINDOW_RESIZING_LEFT = 4,
664 WINDOW_RESIZING_TOP_LEFT = 5,
665 WINDOW_RESIZING_BOTTOM_LEFT = 6,
666 WINDOW_RESIZING_RIGHT = 8,
667 WINDOW_RESIZING_TOP_RIGHT = 9,
668 WINDOW_RESIZING_BOTTOM_RIGHT = 10,
669 WINDOW_RESIZING_MASK = 15,
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400670 WINDOW_EXTERIOR = 16,
671 WINDOW_TITLEBAR = 17,
672 WINDOW_CLIENT_AREA = 18,
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400673};
674
675static int
676get_pointer_location(struct window *window, int32_t x, int32_t y)
677{
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400678 int vlocation, hlocation, location;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400679 const int grip_size = 8;
680
681 if (x < window->margin)
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400682 hlocation = WINDOW_EXTERIOR;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400683 else if (window->margin <= x && x < window->margin + grip_size)
684 hlocation = WINDOW_RESIZING_LEFT;
685 else if (x < window->allocation.width - window->margin - grip_size)
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400686 hlocation = WINDOW_INTERIOR;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400687 else if (x < window->allocation.width - window->margin)
688 hlocation = WINDOW_RESIZING_RIGHT;
689 else
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400690 hlocation = WINDOW_EXTERIOR;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400691
692 if (y < window->margin)
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400693 vlocation = WINDOW_EXTERIOR;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400694 else if (window->margin <= y && y < window->margin + grip_size)
695 vlocation = WINDOW_RESIZING_TOP;
696 else if (y < window->allocation.height - window->margin - grip_size)
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400697 vlocation = WINDOW_INTERIOR;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400698 else if (y < window->allocation.height - window->margin)
699 vlocation = WINDOW_RESIZING_BOTTOM;
700 else
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400701 vlocation = WINDOW_EXTERIOR;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400702
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400703 location = vlocation | hlocation;
704 if (location & WINDOW_EXTERIOR)
705 location = WINDOW_EXTERIOR;
706 if (location == WINDOW_INTERIOR && y < window->margin + 50)
707 location = WINDOW_TITLEBAR;
708 else if (location == WINDOW_INTERIOR)
709 location = WINDOW_CLIENT_AREA;
710
711 return location;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400712}
713
714static void
Kristian Høgsbergce457ba2010-09-14 15:39:45 -0400715set_pointer_image(struct input *input, uint32_t time, int pointer)
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400716{
717 struct display *display = input->display;
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400718 struct wl_buffer *buffer;
719 cairo_surface_t *surface;
720 int location;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400721
722 location = get_pointer_location(input->pointer_focus,
723 input->sx, input->sy);
724 switch (location) {
725 case WINDOW_RESIZING_TOP:
726 pointer = POINTER_TOP;
727 break;
728 case WINDOW_RESIZING_BOTTOM:
729 pointer = POINTER_BOTTOM;
730 break;
731 case WINDOW_RESIZING_LEFT:
732 pointer = POINTER_LEFT;
733 break;
734 case WINDOW_RESIZING_RIGHT:
735 pointer = POINTER_RIGHT;
736 break;
737 case WINDOW_RESIZING_TOP_LEFT:
738 pointer = POINTER_TOP_LEFT;
739 break;
740 case WINDOW_RESIZING_TOP_RIGHT:
741 pointer = POINTER_TOP_RIGHT;
742 break;
743 case WINDOW_RESIZING_BOTTOM_LEFT:
744 pointer = POINTER_BOTTOM_LEFT;
745 break;
746 case WINDOW_RESIZING_BOTTOM_RIGHT:
747 pointer = POINTER_BOTTOM_RIGHT;
748 break;
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400749 case WINDOW_EXTERIOR:
750 case WINDOW_TITLEBAR:
Kristian Høgsberg7d804062010-09-07 21:50:06 -0400751 if (input->current_pointer_image == POINTER_DEFAULT)
752 return;
753
Kristian Høgsbergce457ba2010-09-14 15:39:45 -0400754 wl_input_device_attach(input->input_device, time, NULL, 0, 0);
Kristian Høgsberg7d804062010-09-07 21:50:06 -0400755 input->current_pointer_image = POINTER_DEFAULT;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400756 return;
757 default:
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400758 break;
759 }
760
Kristian Høgsberg7d804062010-09-07 21:50:06 -0400761 if (pointer == input->current_pointer_image)
762 return;
763
764 input->current_pointer_image = pointer;
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400765 surface = display->pointer_surfaces[pointer];
766 buffer = display_get_buffer_for_surface(display, surface);
Kristian Høgsbergce457ba2010-09-14 15:39:45 -0400767 wl_input_device_attach(input->input_device, time, buffer,
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400768 pointer_images[pointer].hotspot_x,
769 pointer_images[pointer].hotspot_y);
770}
771
Kristian Høgsberge4feb562008-11-08 18:53:37 -0500772static void
Kristian Høgsberg94448c02008-12-30 11:03:33 -0500773window_handle_motion(void *data, struct wl_input_device *input_device,
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400774 uint32_t time,
Kristian Høgsberg94448c02008-12-30 11:03:33 -0500775 int32_t x, int32_t y, int32_t sx, int32_t sy)
Kristian Høgsberg61017b12008-11-02 18:51:48 -0500776{
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400777 struct input *input = data;
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400778 struct window *window = input->pointer_focus;
779 int location, pointer = POINTER_LEFT_PTR;
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400780
781 input->x = x;
782 input->y = y;
783 input->sx = sx;
784 input->sy = sy;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400785
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400786 location = get_pointer_location(window, input->sx, input->sy);
787
788 if (window->motion_handler)
789 pointer = (*window->motion_handler)(window, input, time,
790 x, y, sx, sy,
791 window->user_data);
792
Kristian Høgsbergce457ba2010-09-14 15:39:45 -0400793 set_pointer_image(input, time, pointer);
Kristian Høgsberg61017b12008-11-02 18:51:48 -0500794}
795
Kristian Høgsberg1d7ffd32010-08-25 16:34:05 -0400796static void
797window_handle_button(void *data,
798 struct wl_input_device *input_device,
799 uint32_t time, uint32_t button, uint32_t state)
Kristian Høgsberg94448c02008-12-30 11:03:33 -0500800{
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400801 struct input *input = data;
802 struct window *window = input->pointer_focus;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400803 int location;
Kristian Høgsbergbf6ceda2010-06-14 20:25:06 -0400804
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400805 location = get_pointer_location(window, input->sx, input->sy);
Kristian Høgsberg94448c02008-12-30 11:03:33 -0500806
807 if (button == BTN_LEFT && state == 1) {
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400808 switch (location) {
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400809 case WINDOW_TITLEBAR:
Kristian Høgsberg83fc0612010-08-04 22:44:55 -0400810 wl_shell_move(window->display->shell,
811 window->surface, input_device, time);
Kristian Høgsberg94448c02008-12-30 11:03:33 -0500812 break;
Kristian Høgsbergbf6ceda2010-06-14 20:25:06 -0400813 case WINDOW_RESIZING_TOP:
814 case WINDOW_RESIZING_BOTTOM:
815 case WINDOW_RESIZING_LEFT:
816 case WINDOW_RESIZING_RIGHT:
817 case WINDOW_RESIZING_TOP_LEFT:
818 case WINDOW_RESIZING_TOP_RIGHT:
819 case WINDOW_RESIZING_BOTTOM_LEFT:
820 case WINDOW_RESIZING_BOTTOM_RIGHT:
Kristian Høgsberg83fc0612010-08-04 22:44:55 -0400821 wl_shell_resize(window->display->shell,
822 window->surface, input_device, time,
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400823 location);
Kristian Høgsberg94448c02008-12-30 11:03:33 -0500824 break;
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400825 case WINDOW_CLIENT_AREA:
826 if (window->button_handler)
827 (*window->button_handler)(window,
828 input, time,
829 button, state,
830 window->user_data);
831 break;
Kristian Høgsberg94448c02008-12-30 11:03:33 -0500832 }
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400833 } else {
834 if (window->button_handler)
835 (*window->button_handler)(window,
836 input, time,
837 button, state,
838 window->user_data);
Kristian Høgsberg94448c02008-12-30 11:03:33 -0500839 }
840}
841
Kristian Høgsberg99f090d2009-02-23 22:37:14 -0500842static void
843window_handle_key(void *data, struct wl_input_device *input_device,
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400844 uint32_t time, uint32_t key, uint32_t state)
Kristian Høgsberg99f090d2009-02-23 22:37:14 -0500845{
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400846 struct input *input = data;
847 struct window *window = input->keyboard_focus;
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -0400848 struct display *d = window->display;
849 uint32_t code, sym, level;
Kristian Høgsberg99f090d2009-02-23 22:37:14 -0500850
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -0400851 code = key + d->xkb->min_key_code;
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400852 if (window->keyboard_device != input)
Kristian Høgsberg99f090d2009-02-23 22:37:14 -0500853 return;
854
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -0400855 level = 0;
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400856 if (input->modifiers & WINDOW_MODIFIER_SHIFT &&
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -0400857 XkbKeyGroupWidth(d->xkb, code, 0) > 1)
858 level = 1;
Kristian Høgsberg99f090d2009-02-23 22:37:14 -0500859
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -0400860 sym = XkbKeySymEntry(d->xkb, code, level, 0);
861
862 if (state)
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400863 input->modifiers |= d->xkb->map->modmap[code];
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -0400864 else
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400865 input->modifiers &= ~d->xkb->map->modmap[code];
Kristian Høgsberg94448c02008-12-30 11:03:33 -0500866
867 if (window->key_handler)
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -0400868 (*window->key_handler)(window, key, sym, state,
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400869 input->modifiers, window->user_data);
Kristian Høgsberg94448c02008-12-30 11:03:33 -0500870}
871
Kristian Høgsbergdb6c2f32009-02-22 21:51:24 -0500872static void
873window_handle_pointer_focus(void *data,
874 struct wl_input_device *input_device,
Kristian Høgsberg6d702022010-08-06 15:12:22 -0400875 uint32_t time, struct wl_surface *surface,
876 int32_t x, int32_t y, int32_t sx, int32_t sy)
Kristian Høgsbergdb6c2f32009-02-22 21:51:24 -0500877{
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400878 struct input *input = data;
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400879 struct window *window;
880 int pointer;
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400881
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400882 if (surface) {
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400883 input->pointer_focus = wl_surface_get_user_data(surface);
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400884 window = input->pointer_focus;
885
886 pointer = POINTER_LEFT_PTR;
887 if (window->motion_handler)
888 pointer = (*window->motion_handler)(window,
889 input, time,
890 x, y, sx, sy,
891 window->user_data);
892
Kristian Høgsbergce457ba2010-09-14 15:39:45 -0400893 set_pointer_image(input, time, pointer);
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400894 } else {
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400895 input->pointer_focus = NULL;
Kristian Høgsberg7d804062010-09-07 21:50:06 -0400896 input->current_pointer_image = POINTER_UNSET;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400897 }
Kristian Høgsbergdb6c2f32009-02-22 21:51:24 -0500898}
899
900static void
901window_handle_keyboard_focus(void *data,
902 struct wl_input_device *input_device,
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400903 uint32_t time,
Kristian Høgsberg3c38fa02009-02-23 22:30:29 -0500904 struct wl_surface *surface,
905 struct wl_array *keys)
Kristian Høgsbergdb6c2f32009-02-22 21:51:24 -0500906{
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400907 struct input *input = data;
908 struct window *window = input->keyboard_focus;
909 struct display *d = input->display;
Kristian Høgsberg99f090d2009-02-23 22:37:14 -0500910 uint32_t *k, *end;
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -0500911
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400912 window = input->keyboard_focus;
913 if (window) {
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -0500914 window->keyboard_device = NULL;
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400915 if (window->keyboard_focus_handler)
916 (*window->keyboard_focus_handler)(window, NULL,
917 window->user_data);
Kristian Høgsberg99f090d2009-02-23 22:37:14 -0500918 }
919
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400920 if (surface)
921 input->keyboard_focus = wl_surface_get_user_data(surface);
922 else
923 input->keyboard_focus = NULL;
924
925 end = keys->data + keys->size;
926 for (k = keys->data; k < end; k++)
927 input->modifiers |= d->xkb->map->modmap[*k];
928
929 window = input->keyboard_focus;
930 if (window) {
931 window->keyboard_device = input;
932 if (window->keyboard_focus_handler)
933 (*window->keyboard_focus_handler)(window,
934 window->keyboard_device,
935 window->user_data);
936 }
Kristian Høgsbergdb6c2f32009-02-22 21:51:24 -0500937}
938
Kristian Høgsberg94448c02008-12-30 11:03:33 -0500939static const struct wl_input_device_listener input_device_listener = {
940 window_handle_motion,
941 window_handle_button,
942 window_handle_key,
Kristian Høgsbergdb6c2f32009-02-22 21:51:24 -0500943 window_handle_pointer_focus,
944 window_handle_keyboard_focus,
Kristian Høgsberg94448c02008-12-30 11:03:33 -0500945};
946
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400947void
948input_get_position(struct input *input, int32_t *x, int32_t *y)
949{
950 *x = input->sx;
951 *y = input->sy;
952}
953
Kristian Høgsberg1d7ffd32010-08-25 16:34:05 -0400954struct wl_input_device *
955input_get_input_device(struct input *input)
956{
957 return input->input_device;
958}
959
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -0400960struct wl_drag *
961window_start_drag(struct window *window, struct input *input, uint32_t time,
962 const struct wl_drag_listener *listener, void *data)
Kristian Høgsberg506e20e2010-08-19 17:26:02 -0400963{
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -0400964 struct wl_drag *drag;
Kristian Høgsberg506e20e2010-08-19 17:26:02 -0400965
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400966 cairo_device_flush (window->display->device);
967
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -0400968 drag = wl_shell_create_drag(window->display->shell);
969 wl_drag_offer(drag, "text/plain");
970 wl_drag_offer(drag, "text/html");
971 wl_drag_activate(drag, window->surface, input->input_device, time);
972 wl_drag_add_listener(drag, listener, data);
973
974 return drag;
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400975}
976
Kristian Høgsberg83fc0612010-08-04 22:44:55 -0400977static void
978handle_configure(void *data, struct wl_shell *shell,
979 uint32_t time, uint32_t edges,
980 struct wl_surface *surface,
981 int32_t x, int32_t y, int32_t width, int32_t height)
982{
983 struct window *window = wl_surface_get_user_data(surface);
984
985 window->resize_edges = edges;
986 window->pending_allocation.x = x;
987 window->pending_allocation.y = y;
988 window->pending_allocation.width = width;
989 window->pending_allocation.height = height;
990
991 if (!(edges & 15))
992 return;
993
994 if (window->resize_handler)
995 (*window->resize_handler)(window,
996 window->user_data);
997 else if (window->redraw_handler)
998 window_schedule_redraw(window);
999}
1000
1001static const struct wl_shell_listener shell_listener = {
1002 handle_configure,
1003};
1004
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -05001005void
1006window_get_child_rectangle(struct window *window,
1007 struct rectangle *rectangle)
Kristian Høgsberg8a9cda82008-11-03 15:31:30 -05001008{
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -04001009 if (window->fullscreen && !window->decoration) {
Kristian Høgsberg0395f302008-12-22 12:14:50 -05001010 *rectangle = window->allocation;
1011 } else {
1012 rectangle->x = window->margin + 10;
1013 rectangle->y = window->margin + 50;
1014 rectangle->width = window->allocation.width - 20 - window->margin * 2;
1015 rectangle->height = window->allocation.height - 60 - window->margin * 2;
1016 }
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -05001017}
1018
1019void
Kristian Høgsberg22106762008-12-08 13:50:07 -05001020window_set_child_size(struct window *window,
1021 struct rectangle *rectangle)
1022{
Kristian Høgsbergbf6ceda2010-06-14 20:25:06 -04001023 int32_t width, height;
1024
Kristian Høgsberg0395f302008-12-22 12:14:50 -05001025 if (!window->fullscreen) {
Kristian Høgsbergbf6ceda2010-06-14 20:25:06 -04001026 width = rectangle->width + 20 + window->margin * 2;
1027 height = rectangle->height + 60 + window->margin * 2;
Kristian Høgsberg83fc0612010-08-04 22:44:55 -04001028
1029 if (window->resize_edges & WINDOW_RESIZING_LEFT)
1030 window->allocation.x +=
1031 window->allocation.width - width;
1032 if (window->resize_edges & WINDOW_RESIZING_TOP)
1033 window->allocation.y +=
1034 window->allocation.height - height;
1035
Kristian Høgsbergbf6ceda2010-06-14 20:25:06 -04001036 window->allocation.width = width;
1037 window->allocation.height = height;
Kristian Høgsberg0395f302008-12-22 12:14:50 -05001038 }
Kristian Høgsberg22106762008-12-08 13:50:07 -05001039}
1040
1041void
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -04001042window_copy_image(struct window *window,
1043 struct rectangle *rectangle, EGLImageKHR image)
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -05001044{
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -04001045 /* set image as read buffer, copy pixels or something... */
Kristian Høgsberg0395f302008-12-22 12:14:50 -05001046}
1047
1048void
Kristian Høgsberg0ac16f02009-01-15 11:37:43 -05001049window_copy_surface(struct window *window,
1050 struct rectangle *rectangle,
1051 cairo_surface_t *surface)
1052{
Kristian Høgsberg2aac3022009-12-21 10:04:53 -05001053 cairo_t *cr;
1054
1055 cr = cairo_create (window->cairo_surface);
1056
1057 cairo_set_source_surface (cr,
1058 surface,
1059 rectangle->x, rectangle->y);
1060
1061 cairo_paint (cr);
1062 cairo_destroy (cr);
Kristian Høgsberg0ac16f02009-01-15 11:37:43 -05001063}
1064
Kristian Høgsberg80d746f2010-06-14 23:52:50 -04001065static gboolean
1066idle_redraw(void *data)
1067{
1068 struct window *window = data;
1069
Kristian Høgsberg83fc0612010-08-04 22:44:55 -04001070 if (window->resize_edges)
1071 window->allocation = window->pending_allocation;
1072
Kristian Høgsberg80d746f2010-06-14 23:52:50 -04001073 window->redraw_handler(window, window->user_data);
Kristian Høgsberg83fc0612010-08-04 22:44:55 -04001074
Kristian Høgsberg80d746f2010-06-14 23:52:50 -04001075 window->redraw_scheduled = 0;
Kristian Høgsberg83fc0612010-08-04 22:44:55 -04001076 window->resize_edges = 0;
Kristian Høgsberg80d746f2010-06-14 23:52:50 -04001077
1078 return FALSE;
1079}
1080
1081void
1082window_schedule_redraw(struct window *window)
1083{
1084 if (!window->redraw_scheduled) {
1085 g_idle_add(idle_redraw, window);
1086 window->redraw_scheduled = 1;
1087 }
1088}
1089
Kristian Høgsberg0ac16f02009-01-15 11:37:43 -05001090void
Kristian Høgsberg0395f302008-12-22 12:14:50 -05001091window_set_fullscreen(struct window *window, int fullscreen)
1092{
1093 window->fullscreen = fullscreen;
1094 if (window->fullscreen) {
1095 window->saved_allocation = window->allocation;
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05001096 window->allocation = window->display->screen_allocation;
Kristian Høgsberg0395f302008-12-22 12:14:50 -05001097 } else {
1098 window->allocation = window->saved_allocation;
1099 }
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -05001100}
1101
1102void
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -04001103window_set_decoration(struct window *window, int decoration)
1104{
1105 window->decoration = decoration;
1106}
1107
1108void
Kristian Høgsbergc8c37342010-06-25 11:19:22 -04001109window_set_user_data(struct window *window, void *data)
1110{
1111 window->user_data = data;
1112}
1113
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -04001114void *
1115window_get_user_data(struct window *window)
1116{
1117 return window->user_data;
1118}
1119
Kristian Høgsbergc8c37342010-06-25 11:19:22 -04001120void
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -05001121window_set_resize_handler(struct window *window,
Kristian Høgsbergc8c37342010-06-25 11:19:22 -04001122 window_resize_handler_t handler)
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -05001123{
1124 window->resize_handler = handler;
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -05001125}
1126
1127void
Kristian Høgsberg80d746f2010-06-14 23:52:50 -04001128window_set_redraw_handler(struct window *window,
Kristian Høgsbergc8c37342010-06-25 11:19:22 -04001129 window_redraw_handler_t handler)
Kristian Høgsberg80d746f2010-06-14 23:52:50 -04001130{
1131 window->redraw_handler = handler;
Kristian Høgsberg80d746f2010-06-14 23:52:50 -04001132}
1133
1134void
Kristian Høgsberg6e83d582008-12-08 00:01:36 -05001135window_set_key_handler(struct window *window,
Kristian Høgsbergc8c37342010-06-25 11:19:22 -04001136 window_key_handler_t handler)
Kristian Høgsberg6e83d582008-12-08 00:01:36 -05001137{
1138 window->key_handler = handler;
Kristian Høgsberg6e83d582008-12-08 00:01:36 -05001139}
1140
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -05001141void
Kristian Høgsberg9a686242010-08-18 15:28:04 -04001142window_set_button_handler(struct window *window,
1143 window_button_handler_t handler)
1144{
1145 window->button_handler = handler;
1146}
1147
1148void
Kristian Høgsberg9a686242010-08-18 15:28:04 -04001149window_set_motion_handler(struct window *window,
1150 window_motion_handler_t handler)
1151{
1152 window->motion_handler = handler;
1153}
1154
1155void
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -05001156window_set_keyboard_focus_handler(struct window *window,
Kristian Høgsbergc8c37342010-06-25 11:19:22 -04001157 window_keyboard_focus_handler_t handler)
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -05001158{
1159 window->keyboard_focus_handler = handler;
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -05001160}
1161
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -04001162void
1163window_move(struct window *window, int32_t x, int32_t y)
1164{
1165 window->allocation.x = x;
1166 window->allocation.y = y;
1167
1168 wl_surface_map(window->surface,
1169 window->allocation.x - window->margin,
1170 window->allocation.y - window->margin,
1171 window->allocation.width,
1172 window->allocation.height);
1173}
1174
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -04001175void
1176window_damage(struct window *window, int32_t x, int32_t y,
1177 int32_t width, int32_t height)
1178{
1179 wl_surface_damage(window->surface, x, y, width, height);
1180}
1181
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -05001182struct window *
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05001183window_create(struct display *display, const char *title,
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -05001184 int32_t x, int32_t y, int32_t width, int32_t height)
1185{
Kristian Høgsberg1cbaa6a2008-11-07 15:54:48 -05001186 struct window *window;
1187
1188 window = malloc(sizeof *window);
1189 if (window == NULL)
1190 return NULL;
1191
Kristian Høgsberg78231c82008-11-08 15:06:01 -05001192 memset(window, 0, sizeof *window);
Kristian Høgsberg40979232008-11-25 22:40:39 -05001193 window->display = display;
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -05001194 window->title = strdup(title);
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05001195 window->surface = wl_compositor_create_surface(display->compositor);
Kristian Høgsberg0395f302008-12-22 12:14:50 -05001196 window->allocation.x = x;
1197 window->allocation.y = y;
1198 window->allocation.width = width;
1199 window->allocation.height = height;
1200 window->saved_allocation = window->allocation;
Kristian Høgsberg40979232008-11-25 22:40:39 -05001201 window->margin = 16;
Kristian Høgsberg7824d812010-06-08 14:59:44 -04001202 window->decoration = 1;
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05001203
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -04001204#ifdef HAVE_CAIRO_GL
1205 window->buffer_type = WINDOW_BUFFER_TYPE_DRM;
1206#else
1207 window->buffer_type = WINDOW_BUFFER_TYPE_SHM;
1208#endif
1209
Kristian Høgsberg808fd412010-07-20 17:06:19 -04001210 wl_surface_set_user_data(window->surface, window);
Kristian Høgsberg478d9262010-06-08 20:34:11 -04001211 wl_list_insert(display->window_list.prev, &window->link);
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05001212
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05001213 return window;
1214}
1215
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -04001216void
1217window_set_buffer_type(struct window *window, enum window_buffer_type type)
1218{
1219 window->buffer_type = type;
1220}
1221
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05001222static void
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001223drm_handle_device(void *data, struct wl_drm *drm, const char *device)
Kristian Høgsberg478d9262010-06-08 20:34:11 -04001224{
1225 struct display *d = data;
1226
1227 d->device_name = strdup(device);
1228}
1229
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001230static void drm_handle_authenticated(void *data, struct wl_drm *drm)
1231{
Kristian Høgsberg640609a2010-08-09 22:11:47 -04001232 struct display *d = data;
1233
1234 d->authenticated = 1;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001235}
1236
1237static const struct wl_drm_listener drm_listener = {
1238 drm_handle_device,
1239 drm_handle_authenticated
1240};
1241
Kristian Høgsberg478d9262010-06-08 20:34:11 -04001242static void
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05001243display_handle_geometry(void *data,
1244 struct wl_output *output,
1245 int32_t width, int32_t height)
1246{
1247 struct display *display = data;
1248
1249 display->screen_allocation.x = 0;
1250 display->screen_allocation.y = 0;
1251 display->screen_allocation.width = width;
1252 display->screen_allocation.height = height;
1253}
1254
1255static const struct wl_output_listener output_listener = {
1256 display_handle_geometry,
1257};
1258
1259static void
Kristian Høgsberg4fe1a3e2010-08-10 14:02:48 -04001260display_add_input(struct display *d, uint32_t id)
Kristian Høgsberg808fd412010-07-20 17:06:19 -04001261{
1262 struct input *input;
1263
1264 input = malloc(sizeof *input);
1265 if (input == NULL)
1266 return;
1267
1268 memset(input, 0, sizeof *input);
1269 input->display = d;
Kristian Høgsberg4fe1a3e2010-08-10 14:02:48 -04001270 input->input_device = wl_input_device_create(d->display, id);
Kristian Høgsberg808fd412010-07-20 17:06:19 -04001271 input->pointer_focus = NULL;
1272 input->keyboard_focus = NULL;
1273 wl_list_insert(d->input_list.prev, &input->link);
1274
1275 wl_input_device_add_listener(input->input_device,
1276 &input_device_listener, input);
Kristian Høgsberg9a686242010-08-18 15:28:04 -04001277 wl_input_device_set_user_data(input->input_device, input);
Kristian Høgsberg808fd412010-07-20 17:06:19 -04001278}
1279
1280static void
Kristian Høgsberg4fe1a3e2010-08-10 14:02:48 -04001281display_handle_global(struct wl_display *display, uint32_t id,
1282 const char *interface, uint32_t version, void *data)
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05001283{
1284 struct display *d = data;
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -04001285 struct wl_drag_offer *offer;
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05001286
Kristian Høgsberg4fe1a3e2010-08-10 14:02:48 -04001287 if (strcmp(interface, "compositor") == 0) {
1288 d->compositor = wl_compositor_create(display, id);
Kristian Høgsberg4fe1a3e2010-08-10 14:02:48 -04001289 } else if (strcmp(interface, "output") == 0) {
1290 d->output = wl_output_create(display, id);
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05001291 wl_output_add_listener(d->output, &output_listener, d);
Kristian Høgsberg4fe1a3e2010-08-10 14:02:48 -04001292 } else if (strcmp(interface, "input_device") == 0) {
1293 display_add_input(d, id);
1294 } else if (strcmp(interface, "shell") == 0) {
1295 d->shell = wl_shell_create(display, id);
Kristian Høgsberg83fc0612010-08-04 22:44:55 -04001296 wl_shell_add_listener(d->shell, &shell_listener, d);
Kristian Høgsberg4fe1a3e2010-08-10 14:02:48 -04001297 } else if (strcmp(interface, "drm") == 0) {
1298 d->drm = wl_drm_create(display, id);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001299 wl_drm_add_listener(d->drm, &drm_listener, d);
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -04001300 } else if (strcmp(interface, "shm") == 0) {
1301 d->shm = wl_shm_create(display, id);
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -04001302 } else if (strcmp(interface, "drag_offer") == 0) {
1303 offer = wl_drag_offer_create(display, id);
1304 d->drag_offer_handler(offer, d);
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05001305 }
1306}
1307
Kristian Høgsberg7824d812010-06-08 14:59:44 -04001308static const char socket_name[] = "\0wayland";
1309
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -04001310static void
1311display_render_frame(struct display *d)
1312{
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -04001313 int radius = 8;
1314 cairo_t *cr;
1315
1316 d->shadow = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 128, 128);
1317 cr = cairo_create(d->shadow);
1318 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
1319 cairo_set_source_rgba(cr, 0, 0, 0, 1);
1320 rounded_rect(cr, 16, 16, 112, 112, radius);
1321 cairo_fill(cr);
1322 cairo_destroy(cr);
1323 blur_surface(d->shadow, 64);
1324
1325 d->active_frame =
1326 cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 128, 128);
1327 cr = cairo_create(d->active_frame);
1328 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
1329 cairo_set_source_rgba(cr, 0.8, 0.8, 0.4, 1);
1330 rounded_rect(cr, 16, 16, 112, 112, radius);
1331 cairo_fill(cr);
1332 cairo_destroy(cr);
1333
1334 d->inactive_frame =
1335 cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 128, 128);
1336 cr = cairo_create(d->inactive_frame);
1337 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
1338 cairo_set_source_rgba(cr, 0.6, 0.6, 0.6, 1);
1339 rounded_rect(cr, 16, 16, 112, 112, radius);
1340 cairo_fill(cr);
1341 cairo_destroy(cr);
1342}
1343
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -04001344static void
1345init_xkb(struct display *d)
1346{
Kristian Høgsberg3e6e7e62010-07-02 15:12:02 -04001347 struct xkb_rule_names names;
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -04001348
Kristian Høgsberg3e6e7e62010-07-02 15:12:02 -04001349 names.rules = "evdev";
1350 names.model = "pc105";
Kristian Høgsbergc7c60642010-08-29 21:33:39 -04001351 names.layout = option_xkb_layout;
1352 names.variant = option_xkb_variant;
1353 names.options = option_xkb_options;
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -04001354
Kristian Høgsberg3e6e7e62010-07-02 15:12:02 -04001355 d->xkb = xkb_compile_keymap_from_rules(&names);
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -04001356 if (!d->xkb) {
1357 fprintf(stderr, "Failed to compile keymap\n");
1358 exit(1);
1359 }
1360}
1361
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05001362struct display *
Kristian Høgsberg7824d812010-06-08 14:59:44 -04001363display_create(int *argc, char **argv[], const GOptionEntry *option_entries)
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05001364{
1365 struct display *d;
Kristian Høgsberg379b6782010-07-28 22:52:28 -04001366 EGLint major, minor;
Kristian Høgsberg7824d812010-06-08 14:59:44 -04001367 int fd;
1368 GOptionContext *context;
Kristian Høgsbergc7c60642010-08-29 21:33:39 -04001369 GOptionGroup *xkb_option_group;
Kristian Høgsberg7824d812010-06-08 14:59:44 -04001370 GError *error;
Kristian Høgsberg640609a2010-08-09 22:11:47 -04001371 drm_magic_t magic;
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -04001372
Kristian Høgsberg478d9262010-06-08 20:34:11 -04001373 g_type_init();
1374
Kristian Høgsberg7824d812010-06-08 14:59:44 -04001375 context = g_option_context_new(NULL);
Kristian Høgsbergc7c60642010-08-29 21:33:39 -04001376 if (option_entries)
Kristian Høgsberg7824d812010-06-08 14:59:44 -04001377 g_option_context_add_main_entries(context, option_entries, "Wayland View");
Kristian Høgsbergc7c60642010-08-29 21:33:39 -04001378
1379 xkb_option_group = g_option_group_new("xkb",
1380 "Keyboard options",
1381 "Show all XKB options",
1382 NULL, NULL);
1383 g_option_group_add_entries(xkb_option_group, xkb_option_entries);
1384 g_option_context_add_group (context, xkb_option_group);
1385
1386 if (!g_option_context_parse(context, argc, argv, &error)) {
1387 fprintf(stderr, "option parsing failed: %s\n", error->message);
1388 exit(EXIT_FAILURE);
Kristian Høgsberg7824d812010-06-08 14:59:44 -04001389 }
1390
Kristian Høgsbergc7c60642010-08-29 21:33:39 -04001391
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05001392 d = malloc(sizeof *d);
1393 if (d == NULL)
1394 return NULL;
1395
Kristian Høgsberg478d9262010-06-08 20:34:11 -04001396 d->display = wl_display_create(socket_name, sizeof socket_name);
1397 if (d->display == NULL) {
1398 fprintf(stderr, "failed to create display: %m\n");
Kristian Høgsberg7824d812010-06-08 14:59:44 -04001399 return NULL;
1400 }
1401
Kristian Høgsberg808fd412010-07-20 17:06:19 -04001402 wl_list_init(&d->input_list);
1403
Kristian Høgsberg478d9262010-06-08 20:34:11 -04001404 /* Set up listener so we'll catch all events. */
1405 wl_display_add_global_listener(d->display,
1406 display_handle_global, d);
1407
1408 /* Process connection events. */
1409 wl_display_iterate(d->display, WL_DISPLAY_READABLE);
1410
1411 fd = open(d->device_name, O_RDWR);
1412 if (fd < 0) {
1413 fprintf(stderr, "drm open failed: %m\n");
Kristian Høgsberg7824d812010-06-08 14:59:44 -04001414 return NULL;
1415 }
1416
Kristian Høgsberg640609a2010-08-09 22:11:47 -04001417 if (drmGetMagic(fd, &magic)) {
1418 fprintf(stderr, "DRI2: failed to get drm magic");
1419 return NULL;
1420 }
1421
1422 /* Wait for authenticated event */
1423 wl_drm_authenticate(d->drm, magic);
1424 wl_display_iterate(d->display, WL_DISPLAY_WRITABLE);
1425 while (!d->authenticated)
1426 wl_display_iterate(d->display, WL_DISPLAY_READABLE);
1427
Kristian Høgsbergf252d6a2010-07-08 20:15:10 -04001428 d->dpy = eglGetDRMDisplayMESA(fd);
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -04001429 if (!eglInitialize(d->dpy, &major, &minor)) {
1430 fprintf(stderr, "failed to initialize display\n");
1431 return NULL;
1432 }
1433
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -04001434 eglBindAPI(EGL_OPENGL_API);
1435
Kristian Høgsberg379b6782010-07-28 22:52:28 -04001436 d->ctx = eglCreateContext(d->dpy, NULL, EGL_NO_CONTEXT, NULL);
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -04001437 if (d->ctx == NULL) {
1438 fprintf(stderr, "failed to create context\n");
1439 return NULL;
1440 }
1441
1442 if (!eglMakeCurrent(d->dpy, NULL, NULL, d->ctx)) {
1443 fprintf(stderr, "faile to make context current\n");
1444 return NULL;
1445 }
1446
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -04001447 d->device = cairo_egl_device_create(d->dpy, d->ctx);
Kristian Høgsberg26449102009-05-28 20:23:31 -04001448 if (d->device == NULL) {
1449 fprintf(stderr, "failed to get cairo drm device\n");
Kristian Høgsberg0ac16f02009-01-15 11:37:43 -05001450 return NULL;
1451 }
Kristian Høgsberg8a9cda82008-11-03 15:31:30 -05001452
Kristian Høgsberg9a686242010-08-18 15:28:04 -04001453 create_pointer_surfaces(d);
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04001454
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -04001455 display_render_frame(d);
1456
Kristian Høgsberg7824d812010-06-08 14:59:44 -04001457 d->loop = g_main_loop_new(NULL, FALSE);
Kristian Høgsberg478d9262010-06-08 20:34:11 -04001458 d->source = wl_glib_source_new(d->display);
Kristian Høgsberg7824d812010-06-08 14:59:44 -04001459 g_source_attach(d->source, NULL);
1460
Kristian Høgsberg478d9262010-06-08 20:34:11 -04001461 wl_list_init(&d->window_list);
1462
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -04001463 init_xkb(d);
1464
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05001465 return d;
1466}
1467
Kristian Høgsberg9d69f8e2010-09-03 14:46:38 -04001468struct wl_display *
1469display_get_display(struct display *display)
1470{
1471 return display->display;
1472}
1473
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05001474struct wl_compositor *
1475display_get_compositor(struct display *display)
1476{
1477 return display->compositor;
Kristian Høgsberg61017b12008-11-02 18:51:48 -05001478}
Kristian Høgsberg7824d812010-06-08 14:59:44 -04001479
1480EGLDisplay
1481display_get_egl_display(struct display *d)
1482{
1483 return d->dpy;
1484}
1485
1486void
1487display_run(struct display *d)
1488{
1489 g_main_loop_run(d->loop);
1490}
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -04001491
1492void
1493display_set_drag_offer_handler(struct display *display,
1494 display_drag_offer_handler_t handler)
1495{
1496 display->drag_offer_handler = handler;
1497}