blob: 4365c0acd6264025f341158e3dd56cc0ee4115f3 [file] [log] [blame]
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001/*
2 * Copyright © 2008-2010 Kristian Høgsberg
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
Chia-I Wu1b6c0ed2010-10-29 15:20:18 +080019#ifdef HAVE_CONFIG_H
20#include <config.h>
21#endif
22
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040023#include <stddef.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <fcntl.h>
28#include <unistd.h>
29#include <errno.h>
30#include <sys/time.h>
Kristian Høgsbergf9112b22010-06-14 12:53:43 -040031#include <linux/input.h>
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040032
33#include <xcb/xcb.h>
34#include <xcb/dri2.h>
35#include <xcb/xfixes.h>
36
37#define GL_GLEXT_PROTOTYPES
38#define EGL_EGLEXT_PROTOTYPES
39#include <GLES2/gl2.h>
40#include <GLES2/gl2ext.h>
41#include <EGL/egl.h>
42#include <EGL/eglext.h>
43
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040044#include "compositor.h"
45
46#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
47
48struct x11_compositor {
49 struct wlsc_compositor base;
50
51 xcb_connection_t *conn;
52 xcb_screen_t *screen;
53 xcb_cursor_t null_cursor;
54 int dri2_major;
55 int dri2_minor;
Kristian Høgsberg3ba48582011-01-27 11:57:19 -050056 struct wl_array keys;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040057 struct wl_event_source *xcb_source;
58 struct {
59 xcb_atom_t wm_protocols;
60 xcb_atom_t wm_normal_hints;
61 xcb_atom_t wm_size_hints;
62 xcb_atom_t wm_delete_window;
Kristian Høgsberg24ed6212011-01-26 14:02:31 -050063 xcb_atom_t wm_class;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040064 xcb_atom_t net_wm_name;
Kristian Høgsbergf58d8ca2011-01-26 14:37:07 -050065 xcb_atom_t net_wm_icon;
Kristian Høgsberg24ed6212011-01-26 14:02:31 -050066 xcb_atom_t string;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040067 xcb_atom_t utf8_string;
Kristian Høgsbergf58d8ca2011-01-26 14:37:07 -050068 xcb_atom_t cardinal;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040069 } atom;
70};
71
72struct x11_output {
73 struct wlsc_output base;
74
75 xcb_xfixes_region_t region;
76 xcb_window_t window;
77 GLuint rbo;
78 EGLImageKHR image;
79 xcb_rectangle_t damage[16];
80 int damage_count;
81};
82
83struct x11_input {
84 struct wlsc_input_device base;
85};
86
87
Darxus55973f22010-11-22 21:24:39 -050088static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040089x11_input_create(struct x11_compositor *c)
90{
91 struct x11_input *input;
92
93 input = malloc(sizeof *input);
94 if (input == NULL)
Darxus55973f22010-11-22 21:24:39 -050095 return -1;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040096
97 memset(input, 0, sizeof *input);
98 wlsc_input_device_init(&input->base, &c->base);
99
Kristian Høgsberg9c3e8d72010-12-08 09:48:52 -0500100 c->base.input_device = &input->base.input_device;
Darxus55973f22010-11-22 21:24:39 -0500101
102 return 0;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400103}
104
105
106static int
107dri2_connect(struct x11_compositor *c)
108{
109 xcb_xfixes_query_version_reply_t *xfixes_query;
110 xcb_xfixes_query_version_cookie_t xfixes_query_cookie;
111 xcb_dri2_query_version_reply_t *dri2_query;
112 xcb_dri2_query_version_cookie_t dri2_query_cookie;
113 xcb_dri2_connect_reply_t *connect;
114 xcb_dri2_connect_cookie_t connect_cookie;
115 xcb_generic_error_t *error;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -0400116 char path[256];
117 int fd;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400118
119 xcb_prefetch_extension_data (c->conn, &xcb_xfixes_id);
120 xcb_prefetch_extension_data (c->conn, &xcb_dri2_id);
121
122 xfixes_query_cookie =
123 xcb_xfixes_query_version(c->conn,
124 XCB_XFIXES_MAJOR_VERSION,
125 XCB_XFIXES_MINOR_VERSION);
126
127 dri2_query_cookie =
128 xcb_dri2_query_version (c->conn,
129 XCB_DRI2_MAJOR_VERSION,
130 XCB_DRI2_MINOR_VERSION);
131
132 connect_cookie = xcb_dri2_connect_unchecked (c->conn,
133 c->screen->root,
134 XCB_DRI2_DRIVER_TYPE_DRI);
135
136 xfixes_query =
137 xcb_xfixes_query_version_reply (c->conn,
138 xfixes_query_cookie, &error);
139 if (xfixes_query == NULL ||
140 error != NULL || xfixes_query->major_version < 2) {
141 free(error);
142 return -1;
143 }
144 free(xfixes_query);
145
146 dri2_query =
147 xcb_dri2_query_version_reply (c->conn,
148 dri2_query_cookie, &error);
149 if (dri2_query == NULL || error != NULL) {
Yuval Fledel91b59992010-11-22 21:42:58 +0200150 fprintf(stderr, "DRI2: failed to query version\n");
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400151 free(error);
152 return EGL_FALSE;
153 }
154 c->dri2_major = dri2_query->major_version;
155 c->dri2_minor = dri2_query->minor_version;
156 free(dri2_query);
157
158 connect = xcb_dri2_connect_reply (c->conn,
159 connect_cookie, NULL);
160 if (connect == NULL ||
161 connect->driver_name_length + connect->device_name_length == 0) {
Yuval Fledel91b59992010-11-22 21:42:58 +0200162 fprintf(stderr, "DRI2: failed to connect, DRI2 version: %u.%u\n",
163 c->dri2_major, c->dri2_minor);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400164 return -1;
165 }
166
Chia-I Wu1b6c0ed2010-10-29 15:20:18 +0800167#ifdef XCB_DRI2_CONNECT_DEVICE_NAME_BROKEN
168 {
169 char *driver_name, *device_name;
170
171 driver_name = xcb_dri2_connect_driver_name (connect);
172 device_name = driver_name +
173 ((connect->driver_name_length + 3) & ~3);
174 snprintf(path, sizeof path, "%.*s",
175 xcb_dri2_connect_device_name_length (connect),
176 device_name);
177 }
178#else
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -0400179 snprintf(path, sizeof path, "%.*s",
180 xcb_dri2_connect_device_name_length (connect),
181 xcb_dri2_connect_device_name (connect));
Chia-I Wu1b6c0ed2010-10-29 15:20:18 +0800182#endif
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400183 free(connect);
184
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -0400185 fd = open(path, O_RDWR);
186 if (fd < 0) {
187 fprintf(stderr,
Yuval Fledel91b59992010-11-22 21:42:58 +0200188 "DRI2: could not open %s (%s)\n", path, strerror(errno));
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -0400189 return -1;
190 }
191
192 return wlsc_drm_init(&c->base, fd, path);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400193}
194
195static int
Kristian Høgsberg640609a2010-08-09 22:11:47 -0400196dri2_authenticate(struct x11_compositor *c, uint32_t magic)
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400197{
198 xcb_dri2_authenticate_reply_t *authenticate;
199 xcb_dri2_authenticate_cookie_t authenticate_cookie;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400200
201 authenticate_cookie =
202 xcb_dri2_authenticate_unchecked(c->conn,
203 c->screen->root, magic);
204 authenticate =
205 xcb_dri2_authenticate_reply(c->conn,
206 authenticate_cookie, NULL);
207 if (authenticate == NULL || !authenticate->authenticated) {
Yuval Fledel91b59992010-11-22 21:42:58 +0200208 fprintf(stderr, "DRI2: failed to authenticate\n");
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400209 free(authenticate);
210 return -1;
211 }
212
213 free(authenticate);
214
215 return 0;
216}
217
218static int
219x11_compositor_init_egl(struct x11_compositor *c)
220{
Kristian Høgsberg379b6782010-07-28 22:52:28 -0400221 EGLint major, minor;
222 const char *extensions;
Kristian Høgsberg640609a2010-08-09 22:11:47 -0400223 drm_magic_t magic;
Kristian Høgsberg2c28aa52010-07-28 23:47:54 -0400224 static const EGLint context_attribs[] = {
225 EGL_CONTEXT_CLIENT_VERSION, 2,
226 EGL_NONE
227 };
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400228
229 if (dri2_connect(c) < 0)
230 return -1;
Kristian Høgsbergf252d6a2010-07-08 20:15:10 -0400231
Kristian Høgsberg640609a2010-08-09 22:11:47 -0400232 if (drmGetMagic(c->base.drm.fd, &magic)) {
Yuval Fledel91b59992010-11-22 21:42:58 +0200233 fprintf(stderr, "DRI2: failed to get drm magic\n");
Kristian Høgsberg640609a2010-08-09 22:11:47 -0400234 return -1;
235 }
236
237 if (dri2_authenticate(c, magic) < 0)
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400238 return -1;
239
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -0400240 c->base.display = eglGetDRMDisplayMESA(c->base.drm.fd);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400241 if (c->base.display == NULL) {
242 fprintf(stderr, "failed to create display\n");
243 return -1;
244 }
245
246 if (!eglInitialize(c->base.display, &major, &minor)) {
247 fprintf(stderr, "failed to initialize display\n");
248 return -1;
249 }
250
Kristian Høgsberg379b6782010-07-28 22:52:28 -0400251 extensions = eglQueryString(c->base.display, EGL_EXTENSIONS);
252 if (!strstr(extensions, "EGL_KHR_surfaceless_opengl")) {
253 fprintf(stderr, "EGL_KHR_surfaceless_opengl not available\n");
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400254 return -1;
255 }
256
Darxus55973f22010-11-22 21:24:39 -0500257 if (!eglBindAPI(EGL_OPENGL_ES_API)) {
258 fprintf(stderr, "failed to bind EGL_OPENGL_ES_API\n");
259 return -1;
260 }
261
Kristian Høgsberg2c28aa52010-07-28 23:47:54 -0400262 c->base.context = eglCreateContext(c->base.display, NULL,
263 EGL_NO_CONTEXT, context_attribs);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400264 if (c->base.context == NULL) {
265 fprintf(stderr, "failed to create context\n");
266 return -1;
267 }
268
269 if (!eglMakeCurrent(c->base.display, EGL_NO_SURFACE,
270 EGL_NO_SURFACE, c->base.context)) {
271 fprintf(stderr, "failed to make context current\n");
272 return -1;
273 }
274
275 return 0;
276}
277
278static void
279x11_compositor_present(struct wlsc_compositor *base)
280{
281 struct x11_compositor *c = (struct x11_compositor *) base;
282 struct x11_output *output;
283 xcb_dri2_copy_region_cookie_t cookie;
284 struct timeval tv;
285 uint32_t msec;
286
287 glFlush();
288
289 wl_list_for_each(output, &c->base.output_list, base.link) {
290 cookie = xcb_dri2_copy_region_unchecked(c->conn,
291 output->window,
292 output->region,
293 XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT,
294 XCB_DRI2_ATTACHMENT_BUFFER_BACK_LEFT);
295 free(xcb_dri2_copy_region_reply(c->conn, cookie, NULL));
Kristian Høgsberg8f66a572011-01-07 08:38:56 -0500296 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400297
298 gettimeofday(&tv, NULL);
299 msec = tv.tv_sec * 1000 + tv.tv_usec / 1000;
300 wlsc_compositor_finish_frame(&c->base, msec);
301}
302
303static void
304x11_output_set_wm_protocols(struct x11_output *output)
305{
306 xcb_atom_t list[1];
307 struct x11_compositor *c =
308 (struct x11_compositor *) output->base.compositor;
309
310 list[0] = c->atom.wm_delete_window;
311 xcb_change_property (c->conn,
312 XCB_PROP_MODE_REPLACE,
313 output->window,
314 c->atom.wm_protocols,
315 XCB_ATOM_ATOM,
316 32,
317 ARRAY_SIZE(list),
318 list);
319}
320
321struct wm_normal_hints {
322 uint32_t flags;
323 uint32_t pad[4];
324 int32_t min_width, min_height;
325 int32_t max_width, max_height;
326 int32_t width_inc, height_inc;
327 int32_t min_aspect_x, min_aspect_y;
328 int32_t max_aspect_x, max_aspect_y;
329 int32_t base_width, base_height;
330 int32_t win_gravity;
331};
332
333#define WM_NORMAL_HINTS_MIN_SIZE 16
334#define WM_NORMAL_HINTS_MAX_SIZE 32
335
Kristian Høgsbergf58d8ca2011-01-26 14:37:07 -0500336static void
337x11_output_set_icon(struct x11_compositor *c, struct x11_output *output,
338 const char *filename, int width, int height)
339{
340 uint32_t *icon, *pixels;
341
342 pixels = wlsc_load_image(filename, width, height);
343 if (!pixels)
344 return;
345 icon = malloc(width * height * 4 + 8);
346 if (!icon) {
347 free(pixels);
348 return;
349 }
350
351 icon[0] = width;
352 icon[1] = height;
353 memcpy(icon + 2, pixels, width * height * 4);
354 xcb_change_property(c->conn, XCB_PROP_MODE_REPLACE, output->window,
355 c->atom.net_wm_icon, c->atom.cardinal, 32,
356 width * height + 2, icon);
357 free(icon);
358 free(pixels);
359}
360
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400361static int
362x11_compositor_create_output(struct x11_compositor *c, int width, int height)
363{
364 static const char name[] = "Wayland Compositor";
Kristian Høgsberg24ed6212011-01-26 14:02:31 -0500365 static const char class[] = "wayland-1\0Wayland Compositor";
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400366 struct x11_output *output;
367 xcb_dri2_dri2_buffer_t *buffers;
368 xcb_dri2_get_buffers_reply_t *reply;
369 xcb_dri2_get_buffers_cookie_t cookie;
370 xcb_screen_iterator_t iter;
371 xcb_rectangle_t rectangle;
372 struct wm_normal_hints normal_hints;
373 unsigned int attachments[] =
374 { XCB_DRI2_ATTACHMENT_BUFFER_BACK_LEFT};
375 uint32_t mask = XCB_CW_EVENT_MASK | XCB_CW_CURSOR;
376 uint32_t values[2] = {
377 XCB_EVENT_MASK_KEY_PRESS |
378 XCB_EVENT_MASK_KEY_RELEASE |
379 XCB_EVENT_MASK_BUTTON_PRESS |
380 XCB_EVENT_MASK_BUTTON_RELEASE |
381 XCB_EVENT_MASK_POINTER_MOTION |
382 XCB_EVENT_MASK_EXPOSURE |
Kristian Høgsberg86e09892010-07-07 09:51:11 -0400383 XCB_EVENT_MASK_STRUCTURE_NOTIFY |
384 XCB_EVENT_MASK_ENTER_WINDOW |
Kristian Høgsberg3ba48582011-01-27 11:57:19 -0500385 XCB_EVENT_MASK_LEAVE_WINDOW |
386 XCB_EVENT_MASK_KEYMAP_STATE |
387 XCB_EVENT_MASK_FOCUS_CHANGE,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400388 0
389 };
390
391 EGLint attribs[] = {
392 EGL_WIDTH, 0,
393 EGL_HEIGHT, 0,
Kristian Høgsbergb12fcce2010-08-24 17:34:23 -0400394 EGL_DRM_BUFFER_STRIDE_MESA, 0,
395 EGL_DRM_BUFFER_FORMAT_MESA, EGL_DRM_BUFFER_FORMAT_ARGB32_MESA,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400396 EGL_NONE
397 };
398
399 output = malloc(sizeof *output);
400 if (output == NULL)
401 return -1;
402
403 memset(output, 0, sizeof *output);
404 wlsc_output_init(&output->base, &c->base, 0, 0, width, height);
405
406 values[1] = c->null_cursor;
407 output->window = xcb_generate_id(c->conn);
408 iter = xcb_setup_roots_iterator(xcb_get_setup(c->conn));
409 xcb_create_window(c->conn,
410 XCB_COPY_FROM_PARENT,
411 output->window,
412 iter.data->root,
413 0, 0,
414 width, height,
415 0,
416 XCB_WINDOW_CLASS_INPUT_OUTPUT,
417 iter.data->root_visual,
418 mask, values);
419
420 /* Don't resize me. */
421 memset(&normal_hints, 0, sizeof normal_hints);
422 normal_hints.flags =
423 WM_NORMAL_HINTS_MAX_SIZE | WM_NORMAL_HINTS_MIN_SIZE;
424 normal_hints.min_width = width;
425 normal_hints.min_height = height;
426 normal_hints.max_width = width;
427 normal_hints.max_height = height;
428 xcb_change_property (c->conn, XCB_PROP_MODE_REPLACE, output->window,
429 c->atom.wm_normal_hints,
430 c->atom.wm_size_hints, 32,
431 sizeof normal_hints / 4,
432 (uint8_t *) &normal_hints);
433
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400434 /* Set window name. Don't bother with non-EWMH WMs. */
435 xcb_change_property(c->conn, XCB_PROP_MODE_REPLACE, output->window,
436 c->atom.net_wm_name, c->atom.utf8_string, 8,
437 strlen(name), name);
Kristian Høgsberg24ed6212011-01-26 14:02:31 -0500438 xcb_change_property(c->conn, XCB_PROP_MODE_REPLACE, output->window,
439 c->atom.wm_class, c->atom.string, 8,
440 sizeof class, class);
441
Kristian Høgsbergf58d8ca2011-01-26 14:37:07 -0500442 x11_output_set_icon(c, output,
443 DATADIR "/wayland/wayland.png", 128, 128);
444
Kristian Høgsberg24ed6212011-01-26 14:02:31 -0500445 xcb_map_window(c->conn, output->window);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400446
447 rectangle.x = 0;
448 rectangle.y = 0;
449 rectangle.width = width;
450 rectangle.height = height;
451 output->region = xcb_generate_id(c->conn);
452 xcb_xfixes_create_region(c->conn, output->region, 1, &rectangle);
453
454 xcb_dri2_create_drawable (c->conn, output->window);
455
456 x11_output_set_wm_protocols(output);
457
458 cookie = xcb_dri2_get_buffers_unchecked (c->conn,
459 output->window,
460 1, 1, attachments);
461 reply = xcb_dri2_get_buffers_reply (c->conn, cookie, NULL);
462 if (reply == NULL)
463 return -1;
464 buffers = xcb_dri2_get_buffers_buffers (reply);
465 if (buffers == NULL)
466 return -1;
467
468 if (reply->count != 1) {
469 fprintf(stderr,
470 "got wrong number of buffers (%d)\n", reply->count);
471 return -1;
472 }
473
474 attribs[1] = reply->width;
475 attribs[3] = reply->height;
476 attribs[5] = buffers[0].pitch / 4;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400477 output->image =
Kristian Høgsberg175e6ce2011-01-06 15:45:19 -0500478 eglCreateImageKHR(c->base.display,
479 EGL_NO_CONTEXT,
Kristian Høgsbergb12fcce2010-08-24 17:34:23 -0400480 EGL_DRM_BUFFER_MESA,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400481 (EGLClientBuffer) buffers[0].name,
482 attribs);
Kristian Høgsberg8f2e6772010-07-29 14:48:13 -0400483 free(reply);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400484
485 glGenRenderbuffers(1, &output->rbo);
486 glBindRenderbuffer(GL_RENDERBUFFER, output->rbo);
487
488 glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER,
489 output->image);
490
491 glFramebufferRenderbuffer(GL_FRAMEBUFFER,
492 GL_COLOR_ATTACHMENT0,
493 GL_RENDERBUFFER,
494 output->rbo);
495
496 wl_list_insert(c->base.output_list.prev, &output->base.link);
497
498 return 0;
499}
500
501static void
502idle_repaint(void *data)
503{
504 struct x11_output *output = data;
505 struct x11_compositor *c =
506 (struct x11_compositor *) output->base.compositor;
507 xcb_xfixes_region_t region;
508 xcb_dri2_copy_region_cookie_t cookie;
509
510 if (output->damage_count <= ARRAY_SIZE(output->damage)) {
511 region = xcb_generate_id(c->conn);
512 xcb_xfixes_create_region(c->conn, region,
513 output->damage_count, output->damage);
514 } else {
515 region = output->region;
516 }
517
518 cookie = xcb_dri2_copy_region_unchecked(c->conn,
519 output->window,
520 region,
521 XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT,
522 XCB_DRI2_ATTACHMENT_BUFFER_BACK_LEFT);
523
524 if (region != output->region)
525 xcb_xfixes_destroy_region(c->conn, region);
526
527 free(xcb_dri2_copy_region_reply(c->conn, cookie, NULL));
528 output->damage_count = 0;
529}
530
531static struct x11_output *
532x11_compositor_find_output(struct x11_compositor *c, xcb_window_t window)
533{
534 struct x11_output *output;
535
536 wl_list_for_each(output, &c->base.output_list, base.link) {
537 if (output->window == window)
538 return output;
539 }
540
541 return NULL;
542}
543
544static void
545x11_compositor_handle_event(int fd, uint32_t mask, void *data)
546{
547 struct x11_compositor *c = data;
548 struct x11_output *output;
549 xcb_generic_event_t *event;
550 struct wl_event_loop *loop;
551 xcb_client_message_event_t *client_message;
552 xcb_motion_notify_event_t *motion_notify;
Kristian Høgsberg93331ff2011-01-26 20:35:07 -0500553 xcb_enter_notify_event_t *enter_notify;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400554 xcb_key_press_event_t *key_press;
555 xcb_button_press_event_t *button_press;
Kristian Høgsberg3ba48582011-01-27 11:57:19 -0500556 xcb_keymap_notify_event_t *keymap_notify;
557 xcb_focus_in_event_t *focus_in;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400558 xcb_expose_event_t *expose;
559 xcb_rectangle_t *r;
560 xcb_atom_t atom;
Kristian Høgsberg3ba48582011-01-27 11:57:19 -0500561 uint32_t *k;
562 int i, set;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400563
564 loop = wl_display_get_event_loop(c->base.wl_display);
565 while (event = xcb_poll_for_event (c->conn), event != NULL) {
566 switch (event->response_type & ~0x80) {
567
568 case XCB_KEY_PRESS:
569 key_press = (xcb_key_press_event_t *) event;
570 notify_key(c->base.input_device,
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400571 key_press->time, key_press->detail - 8, 1);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400572 break;
573 case XCB_KEY_RELEASE:
574 key_press = (xcb_key_press_event_t *) event;
575 notify_key(c->base.input_device,
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400576 key_press->time, key_press->detail - 8, 0);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400577 break;
578 case XCB_BUTTON_PRESS:
579 button_press = (xcb_button_press_event_t *) event;
580 notify_button(c->base.input_device,
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400581 button_press->time,
Kristian Høgsbergf9112b22010-06-14 12:53:43 -0400582 button_press->detail + BTN_LEFT - 1, 1);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400583 break;
584 case XCB_BUTTON_RELEASE:
585 button_press = (xcb_button_press_event_t *) event;
586 notify_button(c->base.input_device,
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400587 button_press->time,
Kristian Høgsbergf9112b22010-06-14 12:53:43 -0400588 button_press->detail + BTN_LEFT - 1, 0);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400589 break;
590
591 case XCB_MOTION_NOTIFY:
592 motion_notify = (xcb_motion_notify_event_t *) event;
593 notify_motion(c->base.input_device,
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400594 motion_notify->time,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400595 motion_notify->event_x,
596 motion_notify->event_y);
597 break;
598
599 case XCB_EXPOSE:
600 expose = (xcb_expose_event_t *) event;
601 output = x11_compositor_find_output(c, expose->window);
602 if (output->damage_count == 0)
603 wl_event_loop_add_idle(loop,
604 idle_repaint, output);
605
606 r = &output->damage[output->damage_count++];
607 if (output->damage_count > 16)
608 break;
609 r->x = expose->x;
610 r->y = expose->y;
611 r->width = expose->width;
612 r->height = expose->height;
613 break;
Kristian Høgsberg86e09892010-07-07 09:51:11 -0400614
615 case XCB_ENTER_NOTIFY:
Kristian Høgsberg93331ff2011-01-26 20:35:07 -0500616 enter_notify = (xcb_enter_notify_event_t *) event;
Kristian Høgsberg2dfe6262011-02-08 11:59:53 -0500617 if (enter_notify->state >= Button1Mask)
618 break;
Kristian Høgsberg93331ff2011-01-26 20:35:07 -0500619 output = x11_compositor_find_output(c, enter_notify->event);
620 notify_pointer_focus(c->base.input_device,
621 enter_notify->time,
622 &output->base,
623 enter_notify->event_x,
624 enter_notify->event_y);
Kristian Høgsberg86e09892010-07-07 09:51:11 -0400625 break;
626
627 case XCB_LEAVE_NOTIFY:
Kristian Høgsberg93331ff2011-01-26 20:35:07 -0500628 enter_notify = (xcb_enter_notify_event_t *) event;
Kristian Høgsberg2dfe6262011-02-08 11:59:53 -0500629 if (enter_notify->state >= Button1Mask)
630 break;
Kristian Høgsberg93331ff2011-01-26 20:35:07 -0500631 notify_pointer_focus(c->base.input_device,
632 enter_notify->time,
633 NULL,
634 enter_notify->event_x,
635 enter_notify->event_y);
Kristian Høgsberg86e09892010-07-07 09:51:11 -0400636 break;
637
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400638 case XCB_CLIENT_MESSAGE:
639 client_message = (xcb_client_message_event_t *) event;
640 atom = client_message->data.data32[0];
641 if (atom == c->atom.wm_delete_window)
Kristian Høgsberg50dc6982010-12-01 16:43:56 -0500642 wl_display_terminate(c->base.wl_display);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400643 break;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400644
Kristian Høgsberg3ba48582011-01-27 11:57:19 -0500645 case XCB_FOCUS_IN:
646 focus_in = (xcb_focus_in_event_t *) event;
647 if (focus_in->mode == XCB_NOTIFY_MODE_WHILE_GRABBED)
648 break;
649
650 output = x11_compositor_find_output(c, focus_in->event);
651 notify_keyboard_focus(c->base.input_device,
652 get_time(),
653 &output->base, &c->keys);
654 break;
655
656 case XCB_FOCUS_OUT:
657 focus_in = (xcb_focus_in_event_t *) event;
658 if (focus_in->mode == XCB_NOTIFY_MODE_WHILE_GRABBED)
659 break;
660 notify_keyboard_focus(c->base.input_device,
661 get_time(), NULL, NULL);
662 break;
663
664 case XCB_KEYMAP_NOTIFY:
665 keymap_notify = (xcb_keymap_notify_event_t *) event;
666 c->keys.size = 0;
667 for (i = 0; i < ARRAY_LENGTH(keymap_notify->keys) * 8; i++) {
668 set = keymap_notify->keys[i >> 3] &
669 (1 << (i & 7));
670 if (set) {
671 k = wl_array_add(&c->keys, sizeof *k);
672 *k = i;
673 }
674 }
675 break;
676 default:
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400677 break;
678 }
679
680 free (event);
Kristian Høgsberg3ba48582011-01-27 11:57:19 -0500681 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400682}
683
684#define F(field) offsetof(struct x11_compositor, field)
685
686static void
687x11_compositor_get_resources(struct x11_compositor *c)
688{
689 static const struct { const char *name; int offset; } atoms[] = {
690 { "WM_PROTOCOLS", F(atom.wm_protocols) },
691 { "WM_NORMAL_HINTS", F(atom.wm_normal_hints) },
692 { "WM_SIZE_HINTS", F(atom.wm_size_hints) },
693 { "WM_DELETE_WINDOW", F(atom.wm_delete_window) },
Kristian Høgsberg24ed6212011-01-26 14:02:31 -0500694 { "WM_CLASS", F(atom.wm_class) },
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400695 { "_NET_WM_NAME", F(atom.net_wm_name) },
Kristian Høgsbergf58d8ca2011-01-26 14:37:07 -0500696 { "_NET_WM_ICON", F(atom.net_wm_icon) },
Kristian Høgsberg24ed6212011-01-26 14:02:31 -0500697 { "STRING", F(atom.string) },
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400698 { "UTF8_STRING", F(atom.utf8_string) },
Kristian Høgsbergf58d8ca2011-01-26 14:37:07 -0500699 { "CARDINAL", F(atom.cardinal) },
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400700 };
701
702 xcb_intern_atom_cookie_t cookies[ARRAY_SIZE(atoms)];
703 xcb_intern_atom_reply_t *reply;
704 xcb_pixmap_t pixmap;
705 xcb_gc_t gc;
706 int i;
707 uint8_t data[] = { 0, 0, 0, 0 };
708
709 for (i = 0; i < ARRAY_SIZE(atoms); i++)
710 cookies[i] = xcb_intern_atom (c->conn, 0,
711 strlen(atoms[i].name),
712 atoms[i].name);
713
714 for (i = 0; i < ARRAY_SIZE(atoms); i++) {
715 reply = xcb_intern_atom_reply (c->conn, cookies[i], NULL);
716 *(xcb_atom_t *) ((char *) c + atoms[i].offset) = reply->atom;
717 free(reply);
718 }
719
720 pixmap = xcb_generate_id(c->conn);
721 gc = xcb_generate_id(c->conn);
722 xcb_create_pixmap(c->conn, 1, pixmap, c->screen->root, 1, 1);
723 xcb_create_gc(c->conn, gc, pixmap, 0, NULL);
724 xcb_put_image(c->conn, XCB_IMAGE_FORMAT_XY_PIXMAP,
725 pixmap, gc, 1, 1, 0, 0, 0, 32, sizeof data, data);
726 c->null_cursor = xcb_generate_id(c->conn);
727 xcb_create_cursor (c->conn, c->null_cursor,
728 pixmap, pixmap, 0, 0, 0, 0, 0, 0, 1, 1);
729 xcb_free_gc(c->conn, gc);
730 xcb_free_pixmap(c->conn, pixmap);
731}
732
Kristian Høgsberg640609a2010-08-09 22:11:47 -0400733static int
734x11_authenticate(struct wlsc_compositor *c, uint32_t id)
735{
736 return dri2_authenticate((struct x11_compositor *) c, id);
737}
738
Kristian Høgsbergcaa64422010-12-01 16:52:15 -0500739static void
740x11_destroy(struct wlsc_compositor *ec)
741{
742 free(ec);
743}
744
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400745struct wlsc_compositor *
Kristian Høgsberg61a82512010-10-26 11:26:44 -0400746x11_compositor_create(struct wl_display *display, int width, int height)
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400747{
748 struct x11_compositor *c;
749 struct wl_event_loop *loop;
750 xcb_screen_iterator_t s;
751
752 c = malloc(sizeof *c);
753 if (c == NULL)
754 return NULL;
755
756 memset(c, 0, sizeof *c);
757 c->conn = xcb_connect(0, 0);
758
759 if (xcb_connection_has_error(c->conn))
760 return NULL;
761
762 s = xcb_setup_roots_iterator(xcb_get_setup(c->conn));
763 c->screen = s.data;
Kristian Høgsberg3ba48582011-01-27 11:57:19 -0500764 wl_array_init(&c->keys);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400765
766 x11_compositor_get_resources(c);
767
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -0400768 c->base.wl_display = display;
Tiago Vignatti997ce642010-11-10 02:42:35 +0200769 if (x11_compositor_init_egl(c) < 0)
Darxus55973f22010-11-22 21:24:39 -0500770 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400771
Kristian Høgsberg8525a502011-01-14 16:20:21 -0500772 c->base.destroy = x11_destroy;
773 c->base.authenticate = x11_authenticate;
774 c->base.present = x11_compositor_present;
775 c->base.create_buffer = wlsc_drm_buffer_create;
776
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400777 /* Can't init base class until we have a current egl context */
Kristian Høgsberga9468212010-06-14 21:03:11 -0400778 if (wlsc_compositor_init(&c->base, display) < 0)
779 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400780
Darxus55973f22010-11-22 21:24:39 -0500781 if (x11_compositor_create_output(c, width, height) < 0)
782 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400783
Darxus55973f22010-11-22 21:24:39 -0500784 if (x11_input_create(c) < 0)
785 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400786
787 loop = wl_display_get_event_loop(c->base.wl_display);
788
789 c->xcb_source =
790 wl_event_loop_add_fd(loop, xcb_get_file_descriptor(c->conn),
791 WL_EVENT_READABLE,
792 x11_compositor_handle_event, c);
793
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400794 return &c->base;
795}