blob: 24ec5b0e03c328a357b48b68a8f1ddf769e71f5e [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øgsberg012a0072010-10-26 00:02:20 -0400556void
557window_set_surface(struct window *window, cairo_surface_t *surface)
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400558{
Kristian Høgsberg012a0072010-10-26 00:02:20 -0400559 if (window->cairo_surface != NULL)
560 cairo_surface_destroy(window->cairo_surface);
561
562 window->cairo_surface = cairo_surface_reference(surface);
563}
564
565void
566window_create_surface(struct window *window)
567{
568 cairo_surface_t *surface;
569
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400570 switch (window->buffer_type) {
571#ifdef HAVE_CAIRO_GL
572 case WINDOW_BUFFER_TYPE_DRM:
Kristian Høgsberg012a0072010-10-26 00:02:20 -0400573 surface = display_create_surface(window->display,
574 &window->allocation);
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400575 break;
576#endif
577 case WINDOW_BUFFER_TYPE_SHM:
Kristian Høgsberg012a0072010-10-26 00:02:20 -0400578 surface = display_create_shm_surface(window->display,
579 &window->allocation);
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400580 break;
581 }
Kristian Høgsberg012a0072010-10-26 00:02:20 -0400582
583 window_set_surface(window, surface);
584 cairo_surface_destroy(surface);
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400585}
586
587static void
Kristian Høgsberg0395f302008-12-22 12:14:50 -0500588window_draw_decorations(struct window *window)
Kristian Høgsberg61017b12008-11-02 18:51:48 -0500589{
Kristian Høgsberg61017b12008-11-02 18:51:48 -0500590 cairo_t *cr;
Kristian Høgsbergca1d1f62008-11-03 06:59:52 -0500591 cairo_text_extents_t extents;
Kristian Høgsberg2d6b7c12010-06-25 16:51:57 -0400592 cairo_pattern_t *outline, *bright, *dim;
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400593 cairo_surface_t *frame;
594 int width, height, shadow_dx = 3, shadow_dy = 3;
Kristian Høgsberg61017b12008-11-02 18:51:48 -0500595
Kristian Høgsberg012a0072010-10-26 00:02:20 -0400596 window_create_surface(window);
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -0400597
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -0400598 width = window->allocation.width;
599 height = window->allocation.height;
Kristian Høgsberg61017b12008-11-02 18:51:48 -0500600
Kristian Høgsberge4feb562008-11-08 18:53:37 -0500601 outline = cairo_pattern_create_rgb(0.1, 0.1, 0.1);
Kristian Høgsberge9d550b2008-11-19 00:49:39 -0500602 bright = cairo_pattern_create_rgb(0.8, 0.8, 0.8);
Kristian Høgsberge4feb562008-11-08 18:53:37 -0500603 dim = cairo_pattern_create_rgb(0.4, 0.4, 0.4);
604
Kristian Høgsberg0ac16f02009-01-15 11:37:43 -0500605 cr = cairo_create(window->cairo_surface);
Kristian Høgsberg2f2cfae2008-11-08 22:46:30 -0500606
Kristian Høgsberg09531622010-06-14 23:22:15 -0400607 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -0400608 cairo_set_source_rgba(cr, 0, 0, 0, 0);
Kristian Høgsberg09531622010-06-14 23:22:15 -0400609 cairo_paint(cr);
610
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -0400611 cairo_set_source_rgba(cr, 0, 0, 0, 0.6);
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400612 tile_mask(cr, window->display->shadow,
613 shadow_dx, shadow_dy, width, height,
614 window->margin + 10 - shadow_dx,
615 window->margin + 10 - shadow_dy);
Kristian Høgsberg0ac16f02009-01-15 11:37:43 -0500616
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -0400617 if (window->keyboard_device)
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400618 frame = window->display->active_frame;
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -0400619 else
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400620 frame = window->display->inactive_frame;
621
622 tile_source(cr, frame, 0, 0, width, height,
623 window->margin + 10, window->margin + 50);
Kristian Høgsberge4feb562008-11-08 18:53:37 -0500624
Kristian Høgsberge4feb562008-11-08 18:53:37 -0500625 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
626 cairo_set_font_size(cr, 14);
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500627 cairo_text_extents(cr, window->title, &extents);
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -0400628 cairo_move_to(cr, (width - extents.width) / 2, 32 - extents.y_bearing);
Kristian Høgsberge4feb562008-11-08 18:53:37 -0500629 cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
630 cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
631 cairo_set_line_width (cr, 4);
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -0400632 if (window->keyboard_device)
633 cairo_set_source_rgb(cr, 0, 0, 0);
634 else
Kristian Høgsberg7d7b5db2009-09-21 13:43:46 -0400635 cairo_set_source_rgb(cr, 0.8, 0.8, 0.8);
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -0400636 cairo_show_text(cr, window->title);
637
Kristian Høgsberg61017b12008-11-02 18:51:48 -0500638 cairo_destroy(cr);
Kristian Høgsberg10ddbd22010-08-16 21:08:52 -0400639
640 cairo_device_flush (window->display->device);
Kristian Høgsberg0395f302008-12-22 12:14:50 -0500641}
642
Kristian Høgsberge968f9c2010-08-27 22:18:00 -0400643void
644display_flush_cairo_device(struct display *display)
645{
646 cairo_device_flush (display->device);
647}
648
Kristian Høgsberg0395f302008-12-22 12:14:50 -0500649void
650window_draw(struct window *window)
651{
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -0400652 if (window->fullscreen || !window->decoration)
Kristian Høgsberg012a0072010-10-26 00:02:20 -0400653 window_create_surface(window);
Kristian Høgsberg0395f302008-12-22 12:14:50 -0500654 else
655 window_draw_decorations(window);
Kristian Høgsberg44f36e32008-11-26 12:57:31 -0500656}
657
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -0400658cairo_surface_t *
659window_get_surface(struct window *window)
660{
Kristian Høgsberg012a0072010-10-26 00:02:20 -0400661 return cairo_surface_reference(window->cairo_surface);
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -0400662}
663
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400664enum window_location {
665 WINDOW_INTERIOR = 0,
Kristian Høgsbergbf6ceda2010-06-14 20:25:06 -0400666 WINDOW_RESIZING_TOP = 1,
667 WINDOW_RESIZING_BOTTOM = 2,
668 WINDOW_RESIZING_LEFT = 4,
669 WINDOW_RESIZING_TOP_LEFT = 5,
670 WINDOW_RESIZING_BOTTOM_LEFT = 6,
671 WINDOW_RESIZING_RIGHT = 8,
672 WINDOW_RESIZING_TOP_RIGHT = 9,
673 WINDOW_RESIZING_BOTTOM_RIGHT = 10,
674 WINDOW_RESIZING_MASK = 15,
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400675 WINDOW_EXTERIOR = 16,
676 WINDOW_TITLEBAR = 17,
677 WINDOW_CLIENT_AREA = 18,
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400678};
679
680static int
681get_pointer_location(struct window *window, int32_t x, int32_t y)
682{
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400683 int vlocation, hlocation, location;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400684 const int grip_size = 8;
685
686 if (x < window->margin)
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400687 hlocation = WINDOW_EXTERIOR;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400688 else if (window->margin <= x && x < window->margin + grip_size)
689 hlocation = WINDOW_RESIZING_LEFT;
690 else if (x < window->allocation.width - window->margin - grip_size)
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400691 hlocation = WINDOW_INTERIOR;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400692 else if (x < window->allocation.width - window->margin)
693 hlocation = WINDOW_RESIZING_RIGHT;
694 else
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400695 hlocation = WINDOW_EXTERIOR;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400696
697 if (y < window->margin)
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400698 vlocation = WINDOW_EXTERIOR;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400699 else if (window->margin <= y && y < window->margin + grip_size)
700 vlocation = WINDOW_RESIZING_TOP;
701 else if (y < window->allocation.height - window->margin - grip_size)
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400702 vlocation = WINDOW_INTERIOR;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400703 else if (y < window->allocation.height - window->margin)
704 vlocation = WINDOW_RESIZING_BOTTOM;
705 else
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400706 vlocation = WINDOW_EXTERIOR;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400707
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400708 location = vlocation | hlocation;
709 if (location & WINDOW_EXTERIOR)
710 location = WINDOW_EXTERIOR;
711 if (location == WINDOW_INTERIOR && y < window->margin + 50)
712 location = WINDOW_TITLEBAR;
713 else if (location == WINDOW_INTERIOR)
714 location = WINDOW_CLIENT_AREA;
715
716 return location;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400717}
718
719static void
Kristian Høgsbergce457ba2010-09-14 15:39:45 -0400720set_pointer_image(struct input *input, uint32_t time, int pointer)
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400721{
722 struct display *display = input->display;
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400723 struct wl_buffer *buffer;
724 cairo_surface_t *surface;
725 int location;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400726
727 location = get_pointer_location(input->pointer_focus,
728 input->sx, input->sy);
729 switch (location) {
730 case WINDOW_RESIZING_TOP:
731 pointer = POINTER_TOP;
732 break;
733 case WINDOW_RESIZING_BOTTOM:
734 pointer = POINTER_BOTTOM;
735 break;
736 case WINDOW_RESIZING_LEFT:
737 pointer = POINTER_LEFT;
738 break;
739 case WINDOW_RESIZING_RIGHT:
740 pointer = POINTER_RIGHT;
741 break;
742 case WINDOW_RESIZING_TOP_LEFT:
743 pointer = POINTER_TOP_LEFT;
744 break;
745 case WINDOW_RESIZING_TOP_RIGHT:
746 pointer = POINTER_TOP_RIGHT;
747 break;
748 case WINDOW_RESIZING_BOTTOM_LEFT:
749 pointer = POINTER_BOTTOM_LEFT;
750 break;
751 case WINDOW_RESIZING_BOTTOM_RIGHT:
752 pointer = POINTER_BOTTOM_RIGHT;
753 break;
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400754 case WINDOW_EXTERIOR:
755 case WINDOW_TITLEBAR:
Kristian Høgsberg7d804062010-09-07 21:50:06 -0400756 if (input->current_pointer_image == POINTER_DEFAULT)
757 return;
758
Kristian Høgsbergce457ba2010-09-14 15:39:45 -0400759 wl_input_device_attach(input->input_device, time, NULL, 0, 0);
Kristian Høgsberg7d804062010-09-07 21:50:06 -0400760 input->current_pointer_image = POINTER_DEFAULT;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400761 return;
762 default:
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400763 break;
764 }
765
Kristian Høgsberg7d804062010-09-07 21:50:06 -0400766 if (pointer == input->current_pointer_image)
767 return;
768
769 input->current_pointer_image = pointer;
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400770 surface = display->pointer_surfaces[pointer];
771 buffer = display_get_buffer_for_surface(display, surface);
Kristian Høgsbergce457ba2010-09-14 15:39:45 -0400772 wl_input_device_attach(input->input_device, time, buffer,
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400773 pointer_images[pointer].hotspot_x,
774 pointer_images[pointer].hotspot_y);
775}
776
Kristian Høgsberge4feb562008-11-08 18:53:37 -0500777static void
Kristian Høgsberg94448c02008-12-30 11:03:33 -0500778window_handle_motion(void *data, struct wl_input_device *input_device,
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400779 uint32_t time,
Kristian Høgsberg94448c02008-12-30 11:03:33 -0500780 int32_t x, int32_t y, int32_t sx, int32_t sy)
Kristian Høgsberg61017b12008-11-02 18:51:48 -0500781{
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400782 struct input *input = data;
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400783 struct window *window = input->pointer_focus;
784 int location, pointer = POINTER_LEFT_PTR;
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400785
786 input->x = x;
787 input->y = y;
788 input->sx = sx;
789 input->sy = sy;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400790
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400791 location = get_pointer_location(window, input->sx, input->sy);
792
793 if (window->motion_handler)
794 pointer = (*window->motion_handler)(window, input, time,
795 x, y, sx, sy,
796 window->user_data);
797
Kristian Høgsbergce457ba2010-09-14 15:39:45 -0400798 set_pointer_image(input, time, pointer);
Kristian Høgsberg61017b12008-11-02 18:51:48 -0500799}
800
Kristian Høgsberg1d7ffd32010-08-25 16:34:05 -0400801static void
802window_handle_button(void *data,
803 struct wl_input_device *input_device,
804 uint32_t time, uint32_t button, uint32_t state)
Kristian Høgsberg94448c02008-12-30 11:03:33 -0500805{
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400806 struct input *input = data;
807 struct window *window = input->pointer_focus;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400808 int location;
Kristian Høgsbergbf6ceda2010-06-14 20:25:06 -0400809
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400810 location = get_pointer_location(window, input->sx, input->sy);
Kristian Høgsberg94448c02008-12-30 11:03:33 -0500811
812 if (button == BTN_LEFT && state == 1) {
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400813 switch (location) {
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400814 case WINDOW_TITLEBAR:
Kristian Høgsberg83fc0612010-08-04 22:44:55 -0400815 wl_shell_move(window->display->shell,
816 window->surface, input_device, time);
Kristian Høgsberg94448c02008-12-30 11:03:33 -0500817 break;
Kristian Høgsbergbf6ceda2010-06-14 20:25:06 -0400818 case WINDOW_RESIZING_TOP:
819 case WINDOW_RESIZING_BOTTOM:
820 case WINDOW_RESIZING_LEFT:
821 case WINDOW_RESIZING_RIGHT:
822 case WINDOW_RESIZING_TOP_LEFT:
823 case WINDOW_RESIZING_TOP_RIGHT:
824 case WINDOW_RESIZING_BOTTOM_LEFT:
825 case WINDOW_RESIZING_BOTTOM_RIGHT:
Kristian Høgsberg83fc0612010-08-04 22:44:55 -0400826 wl_shell_resize(window->display->shell,
827 window->surface, input_device, time,
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400828 location);
Kristian Høgsberg94448c02008-12-30 11:03:33 -0500829 break;
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400830 case WINDOW_CLIENT_AREA:
831 if (window->button_handler)
832 (*window->button_handler)(window,
833 input, time,
834 button, state,
835 window->user_data);
836 break;
Kristian Høgsberg94448c02008-12-30 11:03:33 -0500837 }
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400838 } else {
839 if (window->button_handler)
840 (*window->button_handler)(window,
841 input, time,
842 button, state,
843 window->user_data);
Kristian Høgsberg94448c02008-12-30 11:03:33 -0500844 }
845}
846
Kristian Høgsberg99f090d2009-02-23 22:37:14 -0500847static void
848window_handle_key(void *data, struct wl_input_device *input_device,
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400849 uint32_t time, uint32_t key, uint32_t state)
Kristian Høgsberg99f090d2009-02-23 22:37:14 -0500850{
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400851 struct input *input = data;
852 struct window *window = input->keyboard_focus;
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -0400853 struct display *d = window->display;
854 uint32_t code, sym, level;
Kristian Høgsberg99f090d2009-02-23 22:37:14 -0500855
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -0400856 code = key + d->xkb->min_key_code;
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400857 if (window->keyboard_device != input)
Kristian Høgsberg99f090d2009-02-23 22:37:14 -0500858 return;
859
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -0400860 level = 0;
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400861 if (input->modifiers & WINDOW_MODIFIER_SHIFT &&
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -0400862 XkbKeyGroupWidth(d->xkb, code, 0) > 1)
863 level = 1;
Kristian Høgsberg99f090d2009-02-23 22:37:14 -0500864
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -0400865 sym = XkbKeySymEntry(d->xkb, code, level, 0);
866
867 if (state)
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400868 input->modifiers |= d->xkb->map->modmap[code];
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -0400869 else
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400870 input->modifiers &= ~d->xkb->map->modmap[code];
Kristian Høgsberg94448c02008-12-30 11:03:33 -0500871
872 if (window->key_handler)
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -0400873 (*window->key_handler)(window, key, sym, state,
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400874 input->modifiers, window->user_data);
Kristian Høgsberg94448c02008-12-30 11:03:33 -0500875}
876
Kristian Høgsbergdb6c2f32009-02-22 21:51:24 -0500877static void
878window_handle_pointer_focus(void *data,
879 struct wl_input_device *input_device,
Kristian Høgsberg6d702022010-08-06 15:12:22 -0400880 uint32_t time, struct wl_surface *surface,
881 int32_t x, int32_t y, int32_t sx, int32_t sy)
Kristian Høgsbergdb6c2f32009-02-22 21:51:24 -0500882{
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400883 struct input *input = data;
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400884 struct window *window;
885 int pointer;
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400886
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400887 if (surface) {
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400888 input->pointer_focus = wl_surface_get_user_data(surface);
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400889 window = input->pointer_focus;
890
891 pointer = POINTER_LEFT_PTR;
892 if (window->motion_handler)
893 pointer = (*window->motion_handler)(window,
894 input, time,
895 x, y, sx, sy,
896 window->user_data);
897
Kristian Høgsbergce457ba2010-09-14 15:39:45 -0400898 set_pointer_image(input, time, pointer);
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400899 } else {
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400900 input->pointer_focus = NULL;
Kristian Høgsberg7d804062010-09-07 21:50:06 -0400901 input->current_pointer_image = POINTER_UNSET;
Kristian Høgsbergda275dd2010-08-16 17:47:07 -0400902 }
Kristian Høgsbergdb6c2f32009-02-22 21:51:24 -0500903}
904
905static void
906window_handle_keyboard_focus(void *data,
907 struct wl_input_device *input_device,
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400908 uint32_t time,
Kristian Høgsberg3c38fa02009-02-23 22:30:29 -0500909 struct wl_surface *surface,
910 struct wl_array *keys)
Kristian Høgsbergdb6c2f32009-02-22 21:51:24 -0500911{
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400912 struct input *input = data;
913 struct window *window = input->keyboard_focus;
914 struct display *d = input->display;
Kristian Høgsberg99f090d2009-02-23 22:37:14 -0500915 uint32_t *k, *end;
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -0500916
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400917 window = input->keyboard_focus;
918 if (window) {
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -0500919 window->keyboard_device = NULL;
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400920 if (window->keyboard_focus_handler)
921 (*window->keyboard_focus_handler)(window, NULL,
922 window->user_data);
Kristian Høgsberg99f090d2009-02-23 22:37:14 -0500923 }
924
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400925 if (surface)
926 input->keyboard_focus = wl_surface_get_user_data(surface);
927 else
928 input->keyboard_focus = NULL;
929
930 end = keys->data + keys->size;
931 for (k = keys->data; k < end; k++)
932 input->modifiers |= d->xkb->map->modmap[*k];
933
934 window = input->keyboard_focus;
935 if (window) {
936 window->keyboard_device = input;
937 if (window->keyboard_focus_handler)
938 (*window->keyboard_focus_handler)(window,
939 window->keyboard_device,
940 window->user_data);
941 }
Kristian Høgsbergdb6c2f32009-02-22 21:51:24 -0500942}
943
Kristian Høgsberg94448c02008-12-30 11:03:33 -0500944static const struct wl_input_device_listener input_device_listener = {
945 window_handle_motion,
946 window_handle_button,
947 window_handle_key,
Kristian Høgsbergdb6c2f32009-02-22 21:51:24 -0500948 window_handle_pointer_focus,
949 window_handle_keyboard_focus,
Kristian Høgsberg94448c02008-12-30 11:03:33 -0500950};
951
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400952void
953input_get_position(struct input *input, int32_t *x, int32_t *y)
954{
955 *x = input->sx;
956 *y = input->sy;
957}
958
Kristian Høgsberg1d7ffd32010-08-25 16:34:05 -0400959struct wl_input_device *
960input_get_input_device(struct input *input)
961{
962 return input->input_device;
963}
964
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -0400965struct wl_drag *
966window_start_drag(struct window *window, struct input *input, uint32_t time,
967 const struct wl_drag_listener *listener, void *data)
Kristian Høgsberg506e20e2010-08-19 17:26:02 -0400968{
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -0400969 struct wl_drag *drag;
Kristian Høgsberg506e20e2010-08-19 17:26:02 -0400970
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400971 cairo_device_flush (window->display->device);
972
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -0400973 drag = wl_shell_create_drag(window->display->shell);
974 wl_drag_offer(drag, "text/plain");
975 wl_drag_offer(drag, "text/html");
976 wl_drag_activate(drag, window->surface, input->input_device, time);
977 wl_drag_add_listener(drag, listener, data);
978
979 return drag;
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400980}
981
Kristian Høgsberg83fc0612010-08-04 22:44:55 -0400982static void
983handle_configure(void *data, struct wl_shell *shell,
984 uint32_t time, uint32_t edges,
985 struct wl_surface *surface,
986 int32_t x, int32_t y, int32_t width, int32_t height)
987{
988 struct window *window = wl_surface_get_user_data(surface);
989
990 window->resize_edges = edges;
991 window->pending_allocation.x = x;
992 window->pending_allocation.y = y;
993 window->pending_allocation.width = width;
994 window->pending_allocation.height = height;
995
996 if (!(edges & 15))
997 return;
998
999 if (window->resize_handler)
1000 (*window->resize_handler)(window,
1001 window->user_data);
1002 else if (window->redraw_handler)
1003 window_schedule_redraw(window);
1004}
1005
1006static const struct wl_shell_listener shell_listener = {
1007 handle_configure,
1008};
1009
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -05001010void
1011window_get_child_rectangle(struct window *window,
1012 struct rectangle *rectangle)
Kristian Høgsberg8a9cda82008-11-03 15:31:30 -05001013{
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -04001014 if (window->fullscreen && !window->decoration) {
Kristian Høgsberg0395f302008-12-22 12:14:50 -05001015 *rectangle = window->allocation;
1016 } else {
1017 rectangle->x = window->margin + 10;
1018 rectangle->y = window->margin + 50;
1019 rectangle->width = window->allocation.width - 20 - window->margin * 2;
1020 rectangle->height = window->allocation.height - 60 - window->margin * 2;
1021 }
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -05001022}
1023
1024void
Kristian Høgsberg22106762008-12-08 13:50:07 -05001025window_set_child_size(struct window *window,
1026 struct rectangle *rectangle)
1027{
Kristian Høgsbergbf6ceda2010-06-14 20:25:06 -04001028 int32_t width, height;
1029
Kristian Høgsberg0395f302008-12-22 12:14:50 -05001030 if (!window->fullscreen) {
Kristian Høgsbergbf6ceda2010-06-14 20:25:06 -04001031 width = rectangle->width + 20 + window->margin * 2;
1032 height = rectangle->height + 60 + window->margin * 2;
Kristian Høgsberg83fc0612010-08-04 22:44:55 -04001033
1034 if (window->resize_edges & WINDOW_RESIZING_LEFT)
1035 window->allocation.x +=
1036 window->allocation.width - width;
1037 if (window->resize_edges & WINDOW_RESIZING_TOP)
1038 window->allocation.y +=
1039 window->allocation.height - height;
1040
Kristian Høgsbergbf6ceda2010-06-14 20:25:06 -04001041 window->allocation.width = width;
1042 window->allocation.height = height;
Kristian Høgsberg0395f302008-12-22 12:14:50 -05001043 }
Kristian Høgsberg22106762008-12-08 13:50:07 -05001044}
1045
1046void
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -04001047window_copy_image(struct window *window,
1048 struct rectangle *rectangle, EGLImageKHR image)
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -05001049{
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -04001050 /* set image as read buffer, copy pixels or something... */
Kristian Høgsberg0395f302008-12-22 12:14:50 -05001051}
1052
1053void
Kristian Høgsberg0ac16f02009-01-15 11:37:43 -05001054window_copy_surface(struct window *window,
1055 struct rectangle *rectangle,
1056 cairo_surface_t *surface)
1057{
Kristian Høgsberg2aac3022009-12-21 10:04:53 -05001058 cairo_t *cr;
1059
1060 cr = cairo_create (window->cairo_surface);
1061
1062 cairo_set_source_surface (cr,
1063 surface,
1064 rectangle->x, rectangle->y);
1065
1066 cairo_paint (cr);
1067 cairo_destroy (cr);
Kristian Høgsberg0ac16f02009-01-15 11:37:43 -05001068}
1069
Kristian Høgsberg80d746f2010-06-14 23:52:50 -04001070static gboolean
1071idle_redraw(void *data)
1072{
1073 struct window *window = data;
1074
Kristian Høgsberg83fc0612010-08-04 22:44:55 -04001075 if (window->resize_edges)
1076 window->allocation = window->pending_allocation;
1077
Kristian Høgsberg80d746f2010-06-14 23:52:50 -04001078 window->redraw_handler(window, window->user_data);
Kristian Høgsberg83fc0612010-08-04 22:44:55 -04001079
Kristian Høgsberg80d746f2010-06-14 23:52:50 -04001080 window->redraw_scheduled = 0;
Kristian Høgsberg83fc0612010-08-04 22:44:55 -04001081 window->resize_edges = 0;
Kristian Høgsberg80d746f2010-06-14 23:52:50 -04001082
1083 return FALSE;
1084}
1085
1086void
1087window_schedule_redraw(struct window *window)
1088{
1089 if (!window->redraw_scheduled) {
1090 g_idle_add(idle_redraw, window);
1091 window->redraw_scheduled = 1;
1092 }
1093}
1094
Kristian Høgsberg0ac16f02009-01-15 11:37:43 -05001095void
Kristian Høgsberg0395f302008-12-22 12:14:50 -05001096window_set_fullscreen(struct window *window, int fullscreen)
1097{
1098 window->fullscreen = fullscreen;
1099 if (window->fullscreen) {
1100 window->saved_allocation = window->allocation;
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05001101 window->allocation = window->display->screen_allocation;
Kristian Høgsberg0395f302008-12-22 12:14:50 -05001102 } else {
1103 window->allocation = window->saved_allocation;
1104 }
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -05001105}
1106
1107void
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -04001108window_set_decoration(struct window *window, int decoration)
1109{
1110 window->decoration = decoration;
1111}
1112
1113void
Kristian Høgsbergc8c37342010-06-25 11:19:22 -04001114window_set_user_data(struct window *window, void *data)
1115{
1116 window->user_data = data;
1117}
1118
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -04001119void *
1120window_get_user_data(struct window *window)
1121{
1122 return window->user_data;
1123}
1124
Kristian Høgsbergc8c37342010-06-25 11:19:22 -04001125void
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -05001126window_set_resize_handler(struct window *window,
Kristian Høgsbergc8c37342010-06-25 11:19:22 -04001127 window_resize_handler_t handler)
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -05001128{
1129 window->resize_handler = handler;
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -05001130}
1131
1132void
Kristian Høgsberg80d746f2010-06-14 23:52:50 -04001133window_set_redraw_handler(struct window *window,
Kristian Høgsbergc8c37342010-06-25 11:19:22 -04001134 window_redraw_handler_t handler)
Kristian Høgsberg80d746f2010-06-14 23:52:50 -04001135{
1136 window->redraw_handler = handler;
Kristian Høgsberg80d746f2010-06-14 23:52:50 -04001137}
1138
1139void
Kristian Høgsberg6e83d582008-12-08 00:01:36 -05001140window_set_key_handler(struct window *window,
Kristian Høgsbergc8c37342010-06-25 11:19:22 -04001141 window_key_handler_t handler)
Kristian Høgsberg6e83d582008-12-08 00:01:36 -05001142{
1143 window->key_handler = handler;
Kristian Høgsberg6e83d582008-12-08 00:01:36 -05001144}
1145
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -05001146void
Kristian Høgsberg9a686242010-08-18 15:28:04 -04001147window_set_button_handler(struct window *window,
1148 window_button_handler_t handler)
1149{
1150 window->button_handler = handler;
1151}
1152
1153void
Kristian Høgsberg9a686242010-08-18 15:28:04 -04001154window_set_motion_handler(struct window *window,
1155 window_motion_handler_t handler)
1156{
1157 window->motion_handler = handler;
1158}
1159
1160void
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -05001161window_set_keyboard_focus_handler(struct window *window,
Kristian Høgsbergc8c37342010-06-25 11:19:22 -04001162 window_keyboard_focus_handler_t handler)
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -05001163{
1164 window->keyboard_focus_handler = handler;
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -05001165}
1166
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -04001167void
1168window_move(struct window *window, int32_t x, int32_t y)
1169{
1170 window->allocation.x = x;
1171 window->allocation.y = y;
1172
1173 wl_surface_map(window->surface,
1174 window->allocation.x - window->margin,
1175 window->allocation.y - window->margin,
1176 window->allocation.width,
1177 window->allocation.height);
1178}
1179
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -04001180void
1181window_damage(struct window *window, int32_t x, int32_t y,
1182 int32_t width, int32_t height)
1183{
1184 wl_surface_damage(window->surface, x, y, width, height);
1185}
1186
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -05001187struct window *
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05001188window_create(struct display *display, const char *title,
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -05001189 int32_t x, int32_t y, int32_t width, int32_t height)
1190{
Kristian Høgsberg1cbaa6a2008-11-07 15:54:48 -05001191 struct window *window;
1192
1193 window = malloc(sizeof *window);
1194 if (window == NULL)
1195 return NULL;
1196
Kristian Høgsberg78231c82008-11-08 15:06:01 -05001197 memset(window, 0, sizeof *window);
Kristian Høgsberg40979232008-11-25 22:40:39 -05001198 window->display = display;
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -05001199 window->title = strdup(title);
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05001200 window->surface = wl_compositor_create_surface(display->compositor);
Kristian Høgsberg0395f302008-12-22 12:14:50 -05001201 window->allocation.x = x;
1202 window->allocation.y = y;
1203 window->allocation.width = width;
1204 window->allocation.height = height;
1205 window->saved_allocation = window->allocation;
Kristian Høgsberg40979232008-11-25 22:40:39 -05001206 window->margin = 16;
Kristian Høgsberg7824d812010-06-08 14:59:44 -04001207 window->decoration = 1;
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05001208
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -04001209#ifdef HAVE_CAIRO_GL
1210 window->buffer_type = WINDOW_BUFFER_TYPE_DRM;
1211#else
1212 window->buffer_type = WINDOW_BUFFER_TYPE_SHM;
1213#endif
1214
Kristian Høgsberg808fd412010-07-20 17:06:19 -04001215 wl_surface_set_user_data(window->surface, window);
Kristian Høgsberg478d9262010-06-08 20:34:11 -04001216 wl_list_insert(display->window_list.prev, &window->link);
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05001217
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05001218 return window;
1219}
1220
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -04001221void
1222window_set_buffer_type(struct window *window, enum window_buffer_type type)
1223{
1224 window->buffer_type = type;
1225}
1226
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05001227static void
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001228drm_handle_device(void *data, struct wl_drm *drm, const char *device)
Kristian Høgsberg478d9262010-06-08 20:34:11 -04001229{
1230 struct display *d = data;
1231
1232 d->device_name = strdup(device);
1233}
1234
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001235static void drm_handle_authenticated(void *data, struct wl_drm *drm)
1236{
Kristian Høgsberg640609a2010-08-09 22:11:47 -04001237 struct display *d = data;
1238
1239 d->authenticated = 1;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001240}
1241
1242static const struct wl_drm_listener drm_listener = {
1243 drm_handle_device,
1244 drm_handle_authenticated
1245};
1246
Kristian Høgsberg478d9262010-06-08 20:34:11 -04001247static void
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05001248display_handle_geometry(void *data,
1249 struct wl_output *output,
1250 int32_t width, int32_t height)
1251{
1252 struct display *display = data;
1253
1254 display->screen_allocation.x = 0;
1255 display->screen_allocation.y = 0;
1256 display->screen_allocation.width = width;
1257 display->screen_allocation.height = height;
1258}
1259
1260static const struct wl_output_listener output_listener = {
1261 display_handle_geometry,
1262};
1263
1264static void
Kristian Høgsberg4fe1a3e2010-08-10 14:02:48 -04001265display_add_input(struct display *d, uint32_t id)
Kristian Høgsberg808fd412010-07-20 17:06:19 -04001266{
1267 struct input *input;
1268
1269 input = malloc(sizeof *input);
1270 if (input == NULL)
1271 return;
1272
1273 memset(input, 0, sizeof *input);
1274 input->display = d;
Kristian Høgsberg4fe1a3e2010-08-10 14:02:48 -04001275 input->input_device = wl_input_device_create(d->display, id);
Kristian Høgsberg808fd412010-07-20 17:06:19 -04001276 input->pointer_focus = NULL;
1277 input->keyboard_focus = NULL;
1278 wl_list_insert(d->input_list.prev, &input->link);
1279
1280 wl_input_device_add_listener(input->input_device,
1281 &input_device_listener, input);
Kristian Høgsberg9a686242010-08-18 15:28:04 -04001282 wl_input_device_set_user_data(input->input_device, input);
Kristian Høgsberg808fd412010-07-20 17:06:19 -04001283}
1284
1285static void
Kristian Høgsberg4fe1a3e2010-08-10 14:02:48 -04001286display_handle_global(struct wl_display *display, uint32_t id,
1287 const char *interface, uint32_t version, void *data)
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05001288{
1289 struct display *d = data;
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -04001290 struct wl_drag_offer *offer;
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05001291
Kristian Høgsberg4fe1a3e2010-08-10 14:02:48 -04001292 if (strcmp(interface, "compositor") == 0) {
1293 d->compositor = wl_compositor_create(display, id);
Kristian Høgsberg4fe1a3e2010-08-10 14:02:48 -04001294 } else if (strcmp(interface, "output") == 0) {
1295 d->output = wl_output_create(display, id);
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05001296 wl_output_add_listener(d->output, &output_listener, d);
Kristian Høgsberg4fe1a3e2010-08-10 14:02:48 -04001297 } else if (strcmp(interface, "input_device") == 0) {
1298 display_add_input(d, id);
1299 } else if (strcmp(interface, "shell") == 0) {
1300 d->shell = wl_shell_create(display, id);
Kristian Høgsberg83fc0612010-08-04 22:44:55 -04001301 wl_shell_add_listener(d->shell, &shell_listener, d);
Kristian Høgsberg4fe1a3e2010-08-10 14:02:48 -04001302 } else if (strcmp(interface, "drm") == 0) {
1303 d->drm = wl_drm_create(display, id);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001304 wl_drm_add_listener(d->drm, &drm_listener, d);
Kristian Høgsbergd0c3b9d2010-10-25 11:40:03 -04001305 } else if (strcmp(interface, "shm") == 0) {
1306 d->shm = wl_shm_create(display, id);
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -04001307 } else if (strcmp(interface, "drag_offer") == 0) {
1308 offer = wl_drag_offer_create(display, id);
1309 d->drag_offer_handler(offer, d);
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05001310 }
1311}
1312
Kristian Høgsberg7824d812010-06-08 14:59:44 -04001313static const char socket_name[] = "\0wayland";
1314
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -04001315static void
1316display_render_frame(struct display *d)
1317{
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -04001318 int radius = 8;
1319 cairo_t *cr;
1320
1321 d->shadow = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 128, 128);
1322 cr = cairo_create(d->shadow);
1323 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
1324 cairo_set_source_rgba(cr, 0, 0, 0, 1);
1325 rounded_rect(cr, 16, 16, 112, 112, radius);
1326 cairo_fill(cr);
1327 cairo_destroy(cr);
1328 blur_surface(d->shadow, 64);
1329
1330 d->active_frame =
1331 cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 128, 128);
1332 cr = cairo_create(d->active_frame);
1333 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
1334 cairo_set_source_rgba(cr, 0.8, 0.8, 0.4, 1);
1335 rounded_rect(cr, 16, 16, 112, 112, radius);
1336 cairo_fill(cr);
1337 cairo_destroy(cr);
1338
1339 d->inactive_frame =
1340 cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 128, 128);
1341 cr = cairo_create(d->inactive_frame);
1342 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
1343 cairo_set_source_rgba(cr, 0.6, 0.6, 0.6, 1);
1344 rounded_rect(cr, 16, 16, 112, 112, radius);
1345 cairo_fill(cr);
1346 cairo_destroy(cr);
1347}
1348
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -04001349static void
1350init_xkb(struct display *d)
1351{
Kristian Høgsberg3e6e7e62010-07-02 15:12:02 -04001352 struct xkb_rule_names names;
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -04001353
Kristian Høgsberg3e6e7e62010-07-02 15:12:02 -04001354 names.rules = "evdev";
1355 names.model = "pc105";
Kristian Høgsbergc7c60642010-08-29 21:33:39 -04001356 names.layout = option_xkb_layout;
1357 names.variant = option_xkb_variant;
1358 names.options = option_xkb_options;
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -04001359
Kristian Høgsberg3e6e7e62010-07-02 15:12:02 -04001360 d->xkb = xkb_compile_keymap_from_rules(&names);
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -04001361 if (!d->xkb) {
1362 fprintf(stderr, "Failed to compile keymap\n");
1363 exit(1);
1364 }
1365}
1366
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05001367struct display *
Kristian Høgsberg7824d812010-06-08 14:59:44 -04001368display_create(int *argc, char **argv[], const GOptionEntry *option_entries)
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05001369{
1370 struct display *d;
Kristian Høgsberg379b6782010-07-28 22:52:28 -04001371 EGLint major, minor;
Kristian Høgsberg7824d812010-06-08 14:59:44 -04001372 int fd;
1373 GOptionContext *context;
Kristian Høgsbergc7c60642010-08-29 21:33:39 -04001374 GOptionGroup *xkb_option_group;
Kristian Høgsberg7824d812010-06-08 14:59:44 -04001375 GError *error;
Kristian Høgsberg640609a2010-08-09 22:11:47 -04001376 drm_magic_t magic;
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -04001377
Kristian Høgsberg478d9262010-06-08 20:34:11 -04001378 g_type_init();
1379
Kristian Høgsberg7824d812010-06-08 14:59:44 -04001380 context = g_option_context_new(NULL);
Kristian Høgsbergc7c60642010-08-29 21:33:39 -04001381 if (option_entries)
Kristian Høgsberg7824d812010-06-08 14:59:44 -04001382 g_option_context_add_main_entries(context, option_entries, "Wayland View");
Kristian Høgsbergc7c60642010-08-29 21:33:39 -04001383
1384 xkb_option_group = g_option_group_new("xkb",
1385 "Keyboard options",
1386 "Show all XKB options",
1387 NULL, NULL);
1388 g_option_group_add_entries(xkb_option_group, xkb_option_entries);
1389 g_option_context_add_group (context, xkb_option_group);
1390
1391 if (!g_option_context_parse(context, argc, argv, &error)) {
1392 fprintf(stderr, "option parsing failed: %s\n", error->message);
1393 exit(EXIT_FAILURE);
Kristian Høgsberg7824d812010-06-08 14:59:44 -04001394 }
1395
Kristian Høgsbergc7c60642010-08-29 21:33:39 -04001396
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05001397 d = malloc(sizeof *d);
1398 if (d == NULL)
1399 return NULL;
1400
Kristian Høgsberg478d9262010-06-08 20:34:11 -04001401 d->display = wl_display_create(socket_name, sizeof socket_name);
1402 if (d->display == NULL) {
1403 fprintf(stderr, "failed to create display: %m\n");
Kristian Høgsberg7824d812010-06-08 14:59:44 -04001404 return NULL;
1405 }
1406
Kristian Høgsberg808fd412010-07-20 17:06:19 -04001407 wl_list_init(&d->input_list);
1408
Kristian Høgsberg478d9262010-06-08 20:34:11 -04001409 /* Set up listener so we'll catch all events. */
1410 wl_display_add_global_listener(d->display,
1411 display_handle_global, d);
1412
1413 /* Process connection events. */
1414 wl_display_iterate(d->display, WL_DISPLAY_READABLE);
1415
1416 fd = open(d->device_name, O_RDWR);
1417 if (fd < 0) {
1418 fprintf(stderr, "drm open failed: %m\n");
Kristian Høgsberg7824d812010-06-08 14:59:44 -04001419 return NULL;
1420 }
1421
Kristian Høgsberg640609a2010-08-09 22:11:47 -04001422 if (drmGetMagic(fd, &magic)) {
1423 fprintf(stderr, "DRI2: failed to get drm magic");
1424 return NULL;
1425 }
1426
1427 /* Wait for authenticated event */
1428 wl_drm_authenticate(d->drm, magic);
1429 wl_display_iterate(d->display, WL_DISPLAY_WRITABLE);
1430 while (!d->authenticated)
1431 wl_display_iterate(d->display, WL_DISPLAY_READABLE);
1432
Kristian Høgsbergf252d6a2010-07-08 20:15:10 -04001433 d->dpy = eglGetDRMDisplayMESA(fd);
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -04001434 if (!eglInitialize(d->dpy, &major, &minor)) {
1435 fprintf(stderr, "failed to initialize display\n");
1436 return NULL;
1437 }
1438
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -04001439 eglBindAPI(EGL_OPENGL_API);
1440
Kristian Høgsberg379b6782010-07-28 22:52:28 -04001441 d->ctx = eglCreateContext(d->dpy, NULL, EGL_NO_CONTEXT, NULL);
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -04001442 if (d->ctx == NULL) {
1443 fprintf(stderr, "failed to create context\n");
1444 return NULL;
1445 }
1446
1447 if (!eglMakeCurrent(d->dpy, NULL, NULL, d->ctx)) {
1448 fprintf(stderr, "faile to make context current\n");
1449 return NULL;
1450 }
1451
Kristian Høgsberg012a0072010-10-26 00:02:20 -04001452#ifdef HAVE_CAIRO_GL
Kristian Høgsberga85fe3c2010-06-08 14:08:30 -04001453 d->device = cairo_egl_device_create(d->dpy, d->ctx);
Kristian Høgsberg26449102009-05-28 20:23:31 -04001454 if (d->device == NULL) {
1455 fprintf(stderr, "failed to get cairo drm device\n");
Kristian Høgsberg0ac16f02009-01-15 11:37:43 -05001456 return NULL;
1457 }
Kristian Høgsberg012a0072010-10-26 00:02:20 -04001458#endif
Kristian Høgsberg8a9cda82008-11-03 15:31:30 -05001459
Kristian Høgsberg9a686242010-08-18 15:28:04 -04001460 create_pointer_surfaces(d);
Kristian Høgsbergda275dd2010-08-16 17:47:07 -04001461
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -04001462 display_render_frame(d);
1463
Kristian Høgsberg7824d812010-06-08 14:59:44 -04001464 d->loop = g_main_loop_new(NULL, FALSE);
Kristian Høgsberg478d9262010-06-08 20:34:11 -04001465 d->source = wl_glib_source_new(d->display);
Kristian Høgsberg7824d812010-06-08 14:59:44 -04001466 g_source_attach(d->source, NULL);
1467
Kristian Høgsberg478d9262010-06-08 20:34:11 -04001468 wl_list_init(&d->window_list);
1469
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -04001470 init_xkb(d);
1471
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05001472 return d;
1473}
1474
Kristian Høgsberg9d69f8e2010-09-03 14:46:38 -04001475struct wl_display *
1476display_get_display(struct display *display)
1477{
1478 return display->display;
1479}
1480
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05001481struct wl_compositor *
1482display_get_compositor(struct display *display)
1483{
1484 return display->compositor;
Kristian Høgsberg61017b12008-11-02 18:51:48 -05001485}
Kristian Høgsberg7824d812010-06-08 14:59:44 -04001486
1487EGLDisplay
1488display_get_egl_display(struct display *d)
1489{
1490 return d->dpy;
1491}
1492
1493void
1494display_run(struct display *d)
1495{
1496 g_main_loop_run(d->loop);
1497}
Kristian Høgsberge9d37bd2010-09-02 20:22:42 -04001498
1499void
1500display_set_drag_offer_handler(struct display *display,
1501 display_drag_offer_handler_t handler)
1502{
1503 display->drag_offer_handler = handler;
1504}