blob: 18cb65581fe494b7149b9e6adf10d500d6f953b4 [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øgsbergce5325d2010-06-14 11:54:00 -040056 struct wl_event_source *xcb_source;
57 struct {
58 xcb_atom_t wm_protocols;
59 xcb_atom_t wm_normal_hints;
60 xcb_atom_t wm_size_hints;
61 xcb_atom_t wm_delete_window;
62 xcb_atom_t net_wm_name;
63 xcb_atom_t utf8_string;
64 } atom;
65};
66
67struct x11_output {
68 struct wlsc_output base;
69
70 xcb_xfixes_region_t region;
71 xcb_window_t window;
72 GLuint rbo;
73 EGLImageKHR image;
74 xcb_rectangle_t damage[16];
75 int damage_count;
76};
77
78struct x11_input {
79 struct wlsc_input_device base;
80};
81
82
Darxus55973f22010-11-22 21:24:39 -050083static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040084x11_input_create(struct x11_compositor *c)
85{
86 struct x11_input *input;
87
88 input = malloc(sizeof *input);
89 if (input == NULL)
Darxus55973f22010-11-22 21:24:39 -050090 return -1;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040091
92 memset(input, 0, sizeof *input);
93 wlsc_input_device_init(&input->base, &c->base);
94
Kristian Høgsberg9c3e8d72010-12-08 09:48:52 -050095 c->base.input_device = &input->base.input_device;
Darxus55973f22010-11-22 21:24:39 -050096
97 return 0;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040098}
99
100
101static int
102dri2_connect(struct x11_compositor *c)
103{
104 xcb_xfixes_query_version_reply_t *xfixes_query;
105 xcb_xfixes_query_version_cookie_t xfixes_query_cookie;
106 xcb_dri2_query_version_reply_t *dri2_query;
107 xcb_dri2_query_version_cookie_t dri2_query_cookie;
108 xcb_dri2_connect_reply_t *connect;
109 xcb_dri2_connect_cookie_t connect_cookie;
110 xcb_generic_error_t *error;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -0400111 char path[256];
112 int fd;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400113
114 xcb_prefetch_extension_data (c->conn, &xcb_xfixes_id);
115 xcb_prefetch_extension_data (c->conn, &xcb_dri2_id);
116
117 xfixes_query_cookie =
118 xcb_xfixes_query_version(c->conn,
119 XCB_XFIXES_MAJOR_VERSION,
120 XCB_XFIXES_MINOR_VERSION);
121
122 dri2_query_cookie =
123 xcb_dri2_query_version (c->conn,
124 XCB_DRI2_MAJOR_VERSION,
125 XCB_DRI2_MINOR_VERSION);
126
127 connect_cookie = xcb_dri2_connect_unchecked (c->conn,
128 c->screen->root,
129 XCB_DRI2_DRIVER_TYPE_DRI);
130
131 xfixes_query =
132 xcb_xfixes_query_version_reply (c->conn,
133 xfixes_query_cookie, &error);
134 if (xfixes_query == NULL ||
135 error != NULL || xfixes_query->major_version < 2) {
136 free(error);
137 return -1;
138 }
139 free(xfixes_query);
140
141 dri2_query =
142 xcb_dri2_query_version_reply (c->conn,
143 dri2_query_cookie, &error);
144 if (dri2_query == NULL || error != NULL) {
Yuval Fledel91b59992010-11-22 21:42:58 +0200145 fprintf(stderr, "DRI2: failed to query version\n");
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400146 free(error);
147 return EGL_FALSE;
148 }
149 c->dri2_major = dri2_query->major_version;
150 c->dri2_minor = dri2_query->minor_version;
151 free(dri2_query);
152
153 connect = xcb_dri2_connect_reply (c->conn,
154 connect_cookie, NULL);
155 if (connect == NULL ||
156 connect->driver_name_length + connect->device_name_length == 0) {
Yuval Fledel91b59992010-11-22 21:42:58 +0200157 fprintf(stderr, "DRI2: failed to connect, DRI2 version: %u.%u\n",
158 c->dri2_major, c->dri2_minor);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400159 return -1;
160 }
161
Chia-I Wu1b6c0ed2010-10-29 15:20:18 +0800162#ifdef XCB_DRI2_CONNECT_DEVICE_NAME_BROKEN
163 {
164 char *driver_name, *device_name;
165
166 driver_name = xcb_dri2_connect_driver_name (connect);
167 device_name = driver_name +
168 ((connect->driver_name_length + 3) & ~3);
169 snprintf(path, sizeof path, "%.*s",
170 xcb_dri2_connect_device_name_length (connect),
171 device_name);
172 }
173#else
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -0400174 snprintf(path, sizeof path, "%.*s",
175 xcb_dri2_connect_device_name_length (connect),
176 xcb_dri2_connect_device_name (connect));
Chia-I Wu1b6c0ed2010-10-29 15:20:18 +0800177#endif
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400178 free(connect);
179
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -0400180 fd = open(path, O_RDWR);
181 if (fd < 0) {
182 fprintf(stderr,
Yuval Fledel91b59992010-11-22 21:42:58 +0200183 "DRI2: could not open %s (%s)\n", path, strerror(errno));
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -0400184 return -1;
185 }
186
187 return wlsc_drm_init(&c->base, fd, path);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400188}
189
190static int
Kristian Høgsberg640609a2010-08-09 22:11:47 -0400191dri2_authenticate(struct x11_compositor *c, uint32_t magic)
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400192{
193 xcb_dri2_authenticate_reply_t *authenticate;
194 xcb_dri2_authenticate_cookie_t authenticate_cookie;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400195
196 authenticate_cookie =
197 xcb_dri2_authenticate_unchecked(c->conn,
198 c->screen->root, magic);
199 authenticate =
200 xcb_dri2_authenticate_reply(c->conn,
201 authenticate_cookie, NULL);
202 if (authenticate == NULL || !authenticate->authenticated) {
Yuval Fledel91b59992010-11-22 21:42:58 +0200203 fprintf(stderr, "DRI2: failed to authenticate\n");
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400204 free(authenticate);
205 return -1;
206 }
207
208 free(authenticate);
209
210 return 0;
211}
212
213static int
214x11_compositor_init_egl(struct x11_compositor *c)
215{
Kristian Høgsberg379b6782010-07-28 22:52:28 -0400216 EGLint major, minor;
217 const char *extensions;
Kristian Høgsberg640609a2010-08-09 22:11:47 -0400218 drm_magic_t magic;
Kristian Høgsberg2c28aa52010-07-28 23:47:54 -0400219 static const EGLint context_attribs[] = {
220 EGL_CONTEXT_CLIENT_VERSION, 2,
221 EGL_NONE
222 };
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400223
224 if (dri2_connect(c) < 0)
225 return -1;
Kristian Høgsbergf252d6a2010-07-08 20:15:10 -0400226
Kristian Høgsberg640609a2010-08-09 22:11:47 -0400227 if (drmGetMagic(c->base.drm.fd, &magic)) {
Yuval Fledel91b59992010-11-22 21:42:58 +0200228 fprintf(stderr, "DRI2: failed to get drm magic\n");
Kristian Høgsberg640609a2010-08-09 22:11:47 -0400229 return -1;
230 }
231
232 if (dri2_authenticate(c, magic) < 0)
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400233 return -1;
234
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -0400235 c->base.display = eglGetDRMDisplayMESA(c->base.drm.fd);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400236 if (c->base.display == NULL) {
237 fprintf(stderr, "failed to create display\n");
238 return -1;
239 }
240
241 if (!eglInitialize(c->base.display, &major, &minor)) {
242 fprintf(stderr, "failed to initialize display\n");
243 return -1;
244 }
245
Kristian Høgsberg379b6782010-07-28 22:52:28 -0400246 extensions = eglQueryString(c->base.display, EGL_EXTENSIONS);
247 if (!strstr(extensions, "EGL_KHR_surfaceless_opengl")) {
248 fprintf(stderr, "EGL_KHR_surfaceless_opengl not available\n");
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400249 return -1;
250 }
251
Darxus55973f22010-11-22 21:24:39 -0500252 if (!eglBindAPI(EGL_OPENGL_ES_API)) {
253 fprintf(stderr, "failed to bind EGL_OPENGL_ES_API\n");
254 return -1;
255 }
256
Kristian Høgsberg2c28aa52010-07-28 23:47:54 -0400257 c->base.context = eglCreateContext(c->base.display, NULL,
258 EGL_NO_CONTEXT, context_attribs);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400259 if (c->base.context == NULL) {
260 fprintf(stderr, "failed to create context\n");
261 return -1;
262 }
263
264 if (!eglMakeCurrent(c->base.display, EGL_NO_SURFACE,
265 EGL_NO_SURFACE, c->base.context)) {
266 fprintf(stderr, "failed to make context current\n");
267 return -1;
268 }
269
270 return 0;
271}
272
273static void
274x11_compositor_present(struct wlsc_compositor *base)
275{
276 struct x11_compositor *c = (struct x11_compositor *) base;
277 struct x11_output *output;
278 xcb_dri2_copy_region_cookie_t cookie;
279 struct timeval tv;
280 uint32_t msec;
281
282 glFlush();
283
284 wl_list_for_each(output, &c->base.output_list, base.link) {
285 cookie = xcb_dri2_copy_region_unchecked(c->conn,
286 output->window,
287 output->region,
288 XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT,
289 XCB_DRI2_ATTACHMENT_BUFFER_BACK_LEFT);
290 free(xcb_dri2_copy_region_reply(c->conn, cookie, NULL));
291 }
292
293 gettimeofday(&tv, NULL);
294 msec = tv.tv_sec * 1000 + tv.tv_usec / 1000;
295 wlsc_compositor_finish_frame(&c->base, msec);
296}
297
298static void
299x11_output_set_wm_protocols(struct x11_output *output)
300{
301 xcb_atom_t list[1];
302 struct x11_compositor *c =
303 (struct x11_compositor *) output->base.compositor;
304
305 list[0] = c->atom.wm_delete_window;
306 xcb_change_property (c->conn,
307 XCB_PROP_MODE_REPLACE,
308 output->window,
309 c->atom.wm_protocols,
310 XCB_ATOM_ATOM,
311 32,
312 ARRAY_SIZE(list),
313 list);
314}
315
316struct wm_normal_hints {
317 uint32_t flags;
318 uint32_t pad[4];
319 int32_t min_width, min_height;
320 int32_t max_width, max_height;
321 int32_t width_inc, height_inc;
322 int32_t min_aspect_x, min_aspect_y;
323 int32_t max_aspect_x, max_aspect_y;
324 int32_t base_width, base_height;
325 int32_t win_gravity;
326};
327
328#define WM_NORMAL_HINTS_MIN_SIZE 16
329#define WM_NORMAL_HINTS_MAX_SIZE 32
330
331static int
332x11_compositor_create_output(struct x11_compositor *c, int width, int height)
333{
334 static const char name[] = "Wayland Compositor";
335 struct x11_output *output;
336 xcb_dri2_dri2_buffer_t *buffers;
337 xcb_dri2_get_buffers_reply_t *reply;
338 xcb_dri2_get_buffers_cookie_t cookie;
339 xcb_screen_iterator_t iter;
340 xcb_rectangle_t rectangle;
341 struct wm_normal_hints normal_hints;
342 unsigned int attachments[] =
343 { XCB_DRI2_ATTACHMENT_BUFFER_BACK_LEFT};
344 uint32_t mask = XCB_CW_EVENT_MASK | XCB_CW_CURSOR;
345 uint32_t values[2] = {
346 XCB_EVENT_MASK_KEY_PRESS |
347 XCB_EVENT_MASK_KEY_RELEASE |
348 XCB_EVENT_MASK_BUTTON_PRESS |
349 XCB_EVENT_MASK_BUTTON_RELEASE |
350 XCB_EVENT_MASK_POINTER_MOTION |
351 XCB_EVENT_MASK_EXPOSURE |
Kristian Høgsberg86e09892010-07-07 09:51:11 -0400352 XCB_EVENT_MASK_STRUCTURE_NOTIFY |
353 XCB_EVENT_MASK_ENTER_WINDOW |
354 XCB_EVENT_MASK_LEAVE_WINDOW,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400355 0
356 };
357
358 EGLint attribs[] = {
359 EGL_WIDTH, 0,
360 EGL_HEIGHT, 0,
Kristian Høgsbergb12fcce2010-08-24 17:34:23 -0400361 EGL_DRM_BUFFER_STRIDE_MESA, 0,
362 EGL_DRM_BUFFER_FORMAT_MESA, EGL_DRM_BUFFER_FORMAT_ARGB32_MESA,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400363 EGL_NONE
364 };
365
366 output = malloc(sizeof *output);
367 if (output == NULL)
368 return -1;
369
370 memset(output, 0, sizeof *output);
371 wlsc_output_init(&output->base, &c->base, 0, 0, width, height);
372
373 values[1] = c->null_cursor;
374 output->window = xcb_generate_id(c->conn);
375 iter = xcb_setup_roots_iterator(xcb_get_setup(c->conn));
376 xcb_create_window(c->conn,
377 XCB_COPY_FROM_PARENT,
378 output->window,
379 iter.data->root,
380 0, 0,
381 width, height,
382 0,
383 XCB_WINDOW_CLASS_INPUT_OUTPUT,
384 iter.data->root_visual,
385 mask, values);
386
387 /* Don't resize me. */
388 memset(&normal_hints, 0, sizeof normal_hints);
389 normal_hints.flags =
390 WM_NORMAL_HINTS_MAX_SIZE | WM_NORMAL_HINTS_MIN_SIZE;
391 normal_hints.min_width = width;
392 normal_hints.min_height = height;
393 normal_hints.max_width = width;
394 normal_hints.max_height = height;
395 xcb_change_property (c->conn, XCB_PROP_MODE_REPLACE, output->window,
396 c->atom.wm_normal_hints,
397 c->atom.wm_size_hints, 32,
398 sizeof normal_hints / 4,
399 (uint8_t *) &normal_hints);
400
401 xcb_map_window(c->conn, output->window);
402
403 /* Set window name. Don't bother with non-EWMH WMs. */
404 xcb_change_property(c->conn, XCB_PROP_MODE_REPLACE, output->window,
405 c->atom.net_wm_name, c->atom.utf8_string, 8,
406 strlen(name), name);
407
408 rectangle.x = 0;
409 rectangle.y = 0;
410 rectangle.width = width;
411 rectangle.height = height;
412 output->region = xcb_generate_id(c->conn);
413 xcb_xfixes_create_region(c->conn, output->region, 1, &rectangle);
414
415 xcb_dri2_create_drawable (c->conn, output->window);
416
417 x11_output_set_wm_protocols(output);
418
419 cookie = xcb_dri2_get_buffers_unchecked (c->conn,
420 output->window,
421 1, 1, attachments);
422 reply = xcb_dri2_get_buffers_reply (c->conn, cookie, NULL);
423 if (reply == NULL)
424 return -1;
425 buffers = xcb_dri2_get_buffers_buffers (reply);
426 if (buffers == NULL)
427 return -1;
428
429 if (reply->count != 1) {
430 fprintf(stderr,
431 "got wrong number of buffers (%d)\n", reply->count);
432 return -1;
433 }
434
435 attribs[1] = reply->width;
436 attribs[3] = reply->height;
437 attribs[5] = buffers[0].pitch / 4;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400438 output->image =
439 eglCreateImageKHR(c->base.display, c->base.context,
Kristian Høgsbergb12fcce2010-08-24 17:34:23 -0400440 EGL_DRM_BUFFER_MESA,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400441 (EGLClientBuffer) buffers[0].name,
442 attribs);
Kristian Høgsberg8f2e6772010-07-29 14:48:13 -0400443 free(reply);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400444
445 glGenRenderbuffers(1, &output->rbo);
446 glBindRenderbuffer(GL_RENDERBUFFER, output->rbo);
447
448 glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER,
449 output->image);
450
451 glFramebufferRenderbuffer(GL_FRAMEBUFFER,
452 GL_COLOR_ATTACHMENT0,
453 GL_RENDERBUFFER,
454 output->rbo);
455
456 wl_list_insert(c->base.output_list.prev, &output->base.link);
457
458 return 0;
459}
460
461static void
462idle_repaint(void *data)
463{
464 struct x11_output *output = data;
465 struct x11_compositor *c =
466 (struct x11_compositor *) output->base.compositor;
467 xcb_xfixes_region_t region;
468 xcb_dri2_copy_region_cookie_t cookie;
469
470 if (output->damage_count <= ARRAY_SIZE(output->damage)) {
471 region = xcb_generate_id(c->conn);
472 xcb_xfixes_create_region(c->conn, region,
473 output->damage_count, output->damage);
474 } else {
475 region = output->region;
476 }
477
478 cookie = xcb_dri2_copy_region_unchecked(c->conn,
479 output->window,
480 region,
481 XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT,
482 XCB_DRI2_ATTACHMENT_BUFFER_BACK_LEFT);
483
484 if (region != output->region)
485 xcb_xfixes_destroy_region(c->conn, region);
486
487 free(xcb_dri2_copy_region_reply(c->conn, cookie, NULL));
488 output->damage_count = 0;
489}
490
491static struct x11_output *
492x11_compositor_find_output(struct x11_compositor *c, xcb_window_t window)
493{
494 struct x11_output *output;
495
496 wl_list_for_each(output, &c->base.output_list, base.link) {
497 if (output->window == window)
498 return output;
499 }
500
501 return NULL;
502}
503
504static void
505x11_compositor_handle_event(int fd, uint32_t mask, void *data)
506{
507 struct x11_compositor *c = data;
508 struct x11_output *output;
509 xcb_generic_event_t *event;
510 struct wl_event_loop *loop;
511 xcb_client_message_event_t *client_message;
512 xcb_motion_notify_event_t *motion_notify;
513 xcb_key_press_event_t *key_press;
514 xcb_button_press_event_t *button_press;
515 xcb_expose_event_t *expose;
516 xcb_rectangle_t *r;
517 xcb_atom_t atom;
518
519 loop = wl_display_get_event_loop(c->base.wl_display);
520 while (event = xcb_poll_for_event (c->conn), event != NULL) {
521 switch (event->response_type & ~0x80) {
522
523 case XCB_KEY_PRESS:
524 key_press = (xcb_key_press_event_t *) event;
525 notify_key(c->base.input_device,
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400526 key_press->time, key_press->detail - 8, 1);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400527 break;
528 case XCB_KEY_RELEASE:
529 key_press = (xcb_key_press_event_t *) event;
530 notify_key(c->base.input_device,
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400531 key_press->time, key_press->detail - 8, 0);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400532 break;
533 case XCB_BUTTON_PRESS:
534 button_press = (xcb_button_press_event_t *) event;
535 notify_button(c->base.input_device,
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400536 button_press->time,
Kristian Høgsbergf9112b22010-06-14 12:53:43 -0400537 button_press->detail + BTN_LEFT - 1, 1);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400538 break;
539 case XCB_BUTTON_RELEASE:
540 button_press = (xcb_button_press_event_t *) event;
541 notify_button(c->base.input_device,
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400542 button_press->time,
Kristian Høgsbergf9112b22010-06-14 12:53:43 -0400543 button_press->detail + BTN_LEFT - 1, 0);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400544 break;
545
546 case XCB_MOTION_NOTIFY:
547 motion_notify = (xcb_motion_notify_event_t *) event;
548 notify_motion(c->base.input_device,
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400549 motion_notify->time,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400550 motion_notify->event_x,
551 motion_notify->event_y);
552 break;
553
554 case XCB_EXPOSE:
555 expose = (xcb_expose_event_t *) event;
556 output = x11_compositor_find_output(c, expose->window);
557 if (output->damage_count == 0)
558 wl_event_loop_add_idle(loop,
559 idle_repaint, output);
560
561 r = &output->damage[output->damage_count++];
562 if (output->damage_count > 16)
563 break;
564 r->x = expose->x;
565 r->y = expose->y;
566 r->width = expose->width;
567 r->height = expose->height;
568 break;
Kristian Høgsberg86e09892010-07-07 09:51:11 -0400569
570 case XCB_ENTER_NOTIFY:
571 c->base.focus = 1;
572 wlsc_compositor_schedule_repaint(&c->base);
573 break;
574
575 case XCB_LEAVE_NOTIFY:
576 c->base.focus = 0;
577 wlsc_compositor_schedule_repaint(&c->base);
578 break;
579
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400580 case XCB_CLIENT_MESSAGE:
581 client_message = (xcb_client_message_event_t *) event;
582 atom = client_message->data.data32[0];
583 if (atom == c->atom.wm_delete_window)
Kristian Høgsberg50dc6982010-12-01 16:43:56 -0500584 wl_display_terminate(c->base.wl_display);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400585 break;
586 default:
587
588 break;
589 }
590
591 free (event);
592 }
593}
594
595#define F(field) offsetof(struct x11_compositor, field)
596
597static void
598x11_compositor_get_resources(struct x11_compositor *c)
599{
600 static const struct { const char *name; int offset; } atoms[] = {
601 { "WM_PROTOCOLS", F(atom.wm_protocols) },
602 { "WM_NORMAL_HINTS", F(atom.wm_normal_hints) },
603 { "WM_SIZE_HINTS", F(atom.wm_size_hints) },
604 { "WM_DELETE_WINDOW", F(atom.wm_delete_window) },
605 { "_NET_WM_NAME", F(atom.net_wm_name) },
606 { "UTF8_STRING", F(atom.utf8_string) },
607 };
608
609 xcb_intern_atom_cookie_t cookies[ARRAY_SIZE(atoms)];
610 xcb_intern_atom_reply_t *reply;
611 xcb_pixmap_t pixmap;
612 xcb_gc_t gc;
613 int i;
614 uint8_t data[] = { 0, 0, 0, 0 };
615
616 for (i = 0; i < ARRAY_SIZE(atoms); i++)
617 cookies[i] = xcb_intern_atom (c->conn, 0,
618 strlen(atoms[i].name),
619 atoms[i].name);
620
621 for (i = 0; i < ARRAY_SIZE(atoms); i++) {
622 reply = xcb_intern_atom_reply (c->conn, cookies[i], NULL);
623 *(xcb_atom_t *) ((char *) c + atoms[i].offset) = reply->atom;
624 free(reply);
625 }
626
627 pixmap = xcb_generate_id(c->conn);
628 gc = xcb_generate_id(c->conn);
629 xcb_create_pixmap(c->conn, 1, pixmap, c->screen->root, 1, 1);
630 xcb_create_gc(c->conn, gc, pixmap, 0, NULL);
631 xcb_put_image(c->conn, XCB_IMAGE_FORMAT_XY_PIXMAP,
632 pixmap, gc, 1, 1, 0, 0, 0, 32, sizeof data, data);
633 c->null_cursor = xcb_generate_id(c->conn);
634 xcb_create_cursor (c->conn, c->null_cursor,
635 pixmap, pixmap, 0, 0, 0, 0, 0, 0, 1, 1);
636 xcb_free_gc(c->conn, gc);
637 xcb_free_pixmap(c->conn, pixmap);
638}
639
Kristian Høgsberg640609a2010-08-09 22:11:47 -0400640static int
641x11_authenticate(struct wlsc_compositor *c, uint32_t id)
642{
643 return dri2_authenticate((struct x11_compositor *) c, id);
644}
645
Kristian Høgsbergcaa64422010-12-01 16:52:15 -0500646static void
647x11_destroy(struct wlsc_compositor *ec)
648{
649 free(ec);
650}
651
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400652struct wlsc_compositor *
Kristian Høgsberg61a82512010-10-26 11:26:44 -0400653x11_compositor_create(struct wl_display *display, int width, int height)
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400654{
655 struct x11_compositor *c;
656 struct wl_event_loop *loop;
657 xcb_screen_iterator_t s;
658
659 c = malloc(sizeof *c);
660 if (c == NULL)
661 return NULL;
662
663 memset(c, 0, sizeof *c);
664 c->conn = xcb_connect(0, 0);
665
666 if (xcb_connection_has_error(c->conn))
667 return NULL;
668
669 s = xcb_setup_roots_iterator(xcb_get_setup(c->conn));
670 c->screen = s.data;
671
672 x11_compositor_get_resources(c);
673
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -0400674 c->base.wl_display = display;
Tiago Vignatti997ce642010-11-10 02:42:35 +0200675 if (x11_compositor_init_egl(c) < 0)
Darxus55973f22010-11-22 21:24:39 -0500676 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400677
678 /* Can't init base class until we have a current egl context */
Kristian Høgsberga9468212010-06-14 21:03:11 -0400679 if (wlsc_compositor_init(&c->base, display) < 0)
680 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400681
Darxus55973f22010-11-22 21:24:39 -0500682 if (x11_compositor_create_output(c, width, height) < 0)
683 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400684
Darxus55973f22010-11-22 21:24:39 -0500685 if (x11_input_create(c) < 0)
686 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400687
688 loop = wl_display_get_event_loop(c->base.wl_display);
689
690 c->xcb_source =
691 wl_event_loop_add_fd(loop, xcb_get_file_descriptor(c->conn),
692 WL_EVENT_READABLE,
693 x11_compositor_handle_event, c);
694
Kristian Høgsbergcaa64422010-12-01 16:52:15 -0500695 c->base.destroy = x11_destroy;
Kristian Høgsberg640609a2010-08-09 22:11:47 -0400696 c->base.authenticate = x11_authenticate;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400697 c->base.present = x11_compositor_present;
698
699 return &c->base;
700}