compositor-x11.c 46 KB
Newer Older
1
/*
2 3
 * Copyright © 2008-2011 Kristian Høgsberg
 * Copyright © 2010-2011 Intel Corporation
4
 * Copyright © 2013 Vasily Khoruzhick <anarsoul@gmail.com>
5
 *
6 7 8 9 10 11 12
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
13
 *
14 15 16 17 18 19 20 21 22 23 24 25
 * The above copyright notice and this permission notice (including the
 * next paragraph) shall be included in all copies or substantial
 * portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
26 27
 */

28
#include "config.h"
Chia-I Wu's avatar
Chia-I Wu committed
29

30
#include <assert.h>
31
#include <stddef.h>
32
#include <stdint.h>
33 34 35 36 37 38
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/time.h>
39
#include <sys/shm.h>
40
#include <linux/input.h>
41 42

#include <xcb/xcb.h>
43
#include <xcb/shm.h>
44 45 46 47
#ifdef HAVE_XCB_XKB
#include <xcb/xkb.h>
#endif

48 49 50
#include <X11/Xlib.h>
#include <X11/Xlib-xcb.h>

51 52
#include <xkbcommon/xkbcommon.h>

53
#include "compositor.h"
54
#include "compositor-x11.h"
55
#include "shared/config-parser.h"
56
#include "shared/helpers.h"
57
#include "shared/image-loader.h"
58 59
#include "gl-renderer.h"
#include "pixman-renderer.h"
60
#include "presentation-time-server-protocol.h"
61
#include "linux-dmabuf.h"
62

63
#define DEFAULT_AXIS_STEP_DISTANCE 10
64

65 66 67
struct x11_backend {
	struct weston_backend	 base;
	struct weston_compositor *compositor;
68

69
	Display			*dpy;
70 71 72
	xcb_connection_t	*conn;
	xcb_screen_t		*screen;
	xcb_cursor_t		 null_cursor;
73
	struct wl_array		 keys;
74
	struct wl_event_source	*xcb_source;
75
	struct xkb_keymap	*xkb_keymap;
76 77
	unsigned int		 has_xkb;
	uint8_t			 xkb_event_base;
78
	int			 use_pixman;
79

80 81
	int			 has_net_wm_state_fullscreen;

82 83
	/* We could map multi-pointer X to multiple wayland seats, but
	 * for now we only support core X input. */
84
	struct weston_seat		 core_seat;
85 86
	double				 prev_x;
	double				 prev_y;
87

88 89 90 91 92
	struct {
		xcb_atom_t		 wm_protocols;
		xcb_atom_t		 wm_normal_hints;
		xcb_atom_t		 wm_size_hints;
		xcb_atom_t		 wm_delete_window;
93
		xcb_atom_t		 wm_class;
94
		xcb_atom_t		 net_wm_name;
95 96
		xcb_atom_t		 net_supporting_wm_check;
		xcb_atom_t		 net_supported;
97
		xcb_atom_t		 net_wm_icon;
98 99
		xcb_atom_t		 net_wm_state;
		xcb_atom_t		 net_wm_state_fullscreen;
100
		xcb_atom_t		 string;
101
		xcb_atom_t		 utf8_string;
102
		xcb_atom_t		 cardinal;
103
		xcb_atom_t		 xkb_names;
104 105 106 107
	} atom;
};

struct x11_output {
108
	struct weston_output	base;
109 110

	xcb_window_t		window;
111
	struct weston_mode	mode;
112
	struct wl_event_source *finish_frame_timer;
113 114 115 116 117 118 119

	xcb_gc_t		gc;
	xcb_shm_seg_t		segment;
	pixman_image_t	       *hw_surface;
	int			shm_id;
	void		       *buf;
	uint8_t			depth;
120
	int32_t                 scale;
121 122
};

123
struct window_delete_data {
124
	struct x11_backend	*backend;
125 126 127
	xcb_window_t		window;
};

128 129
struct gl_renderer_interface *gl_renderer;

130 131 132 133 134 135 136 137 138 139 140 141 142 143
static xcb_screen_t *
x11_compositor_get_default_screen(struct x11_backend *b)
{
	xcb_screen_iterator_t iter;
	int i, screen_nbr = XDefaultScreen(b->dpy);

	iter = xcb_setup_roots_iterator(xcb_get_setup(b->conn));
	for (i = 0; iter.rem; xcb_screen_next(&iter), i++)
		if (i == screen_nbr)
			return iter.data;

	return xcb_setup_roots_iterator(xcb_get_setup(b->conn)).data;
}

144
static struct xkb_keymap *
145
x11_backend_get_keymap(struct x11_backend *b)
146 147 148 149 150 151 152 153 154 155
{
	xcb_get_property_cookie_t cookie;
	xcb_get_property_reply_t *reply;
	struct xkb_rule_names names;
	struct xkb_keymap *ret;
	const char *value_all, *value_part;
	int length_all, length_part;

	memset(&names, 0, sizeof(names));

156 157 158
	cookie = xcb_get_property(b->conn, 0, b->screen->root,
				  b->atom.xkb_names, b->atom.string, 0, 1024);
	reply = xcb_get_property_reply(b->conn, cookie, NULL);
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
	if (reply == NULL)
		return NULL;

	value_all = xcb_get_property_value(reply);
	length_all = xcb_get_property_value_length(reply);
	value_part = value_all;

#define copy_prop_value(to) \
	length_part = strlen(value_part); \
	if (value_part + length_part < (value_all + length_all) && \
	    length_part > 0) \
		names.to = value_part; \
	value_part += length_part + 1;

	copy_prop_value(rules);
	copy_prop_value(model);
	copy_prop_value(layout);
	copy_prop_value(variant);
	copy_prop_value(options);
#undef copy_prop_value

180
	ret = xkb_keymap_new_from_names(b->compositor->xkb_context, &names, 0);
181 182 183 184

	free(reply);
	return ret;
}
185

186
static uint32_t
187
get_xkb_mod_mask(struct x11_backend *b, uint32_t in)
188
{
189 190 191
	struct weston_keyboard *keyboard =
		weston_seat_get_keyboard(&b->core_seat);
	struct weston_xkb_info *info = keyboard->xkb_info;
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
	uint32_t ret = 0;

	if ((in & ShiftMask) && info->shift_mod != XKB_MOD_INVALID)
		ret |= (1 << info->shift_mod);
	if ((in & LockMask) && info->caps_mod != XKB_MOD_INVALID)
		ret |= (1 << info->caps_mod);
	if ((in & ControlMask) && info->ctrl_mod != XKB_MOD_INVALID)
		ret |= (1 << info->ctrl_mod);
	if ((in & Mod1Mask) && info->alt_mod != XKB_MOD_INVALID)
		ret |= (1 << info->alt_mod);
	if ((in & Mod2Mask) && info->mod2_mod != XKB_MOD_INVALID)
		ret |= (1 << info->mod2_mod);
	if ((in & Mod3Mask) && info->mod3_mod != XKB_MOD_INVALID)
		ret |= (1 << info->mod3_mod);
	if ((in & Mod4Mask) && info->super_mod != XKB_MOD_INVALID)
		ret |= (1 << info->super_mod);
	if ((in & Mod5Mask) && info->mod5_mod != XKB_MOD_INVALID)
		ret |= (1 << info->mod5_mod);

	return ret;
}

214
static void
215
x11_backend_setup_xkb(struct x11_backend *b)
216 217 218
{
#ifndef HAVE_XCB_XKB
	weston_log("XCB-XKB not available during build\n");
219 220
	b->has_xkb = 0;
	b->xkb_event_base = 0;
221 222
	return;
#else
223
	struct weston_keyboard *keyboard;
224
	const xcb_query_extension_reply_t *ext;
225
	xcb_generic_error_t *error;
226
	xcb_void_cookie_t select;
227 228
	xcb_xkb_use_extension_cookie_t use_ext;
	xcb_xkb_use_extension_reply_t *use_ext_reply;
229 230
	xcb_xkb_per_client_flags_cookie_t pcf;
	xcb_xkb_per_client_flags_reply_t *pcf_reply;
231 232
	xcb_xkb_get_state_cookie_t state;
	xcb_xkb_get_state_reply_t *state_reply;
233
	uint32_t values[1] = { XCB_EVENT_MASK_PROPERTY_CHANGE };
234

235 236
	b->has_xkb = 0;
	b->xkb_event_base = 0;
237

238
	ext = xcb_get_extension_data(b->conn, &xcb_xkb_id);
239 240 241 242
	if (!ext) {
		weston_log("XKB extension not available on host X11 server\n");
		return;
	}
243
	b->xkb_event_base = ext->first_event;
244

245
	select = xcb_xkb_select_events_checked(b->conn,
246 247 248 249 250 251 252
					       XCB_XKB_ID_USE_CORE_KBD,
					       XCB_XKB_EVENT_TYPE_STATE_NOTIFY,
					       0,
					       XCB_XKB_EVENT_TYPE_STATE_NOTIFY,
					       0,
					       0,
					       NULL);
253
	error = xcb_request_check(b->conn, select);
254 255
	if (error) {
		weston_log("error: failed to select for XKB state events\n");
256
		free(error);
257 258 259
		return;
	}

260
	use_ext = xcb_xkb_use_extension(b->conn,
261 262
					XCB_XKB_MAJOR_VERSION,
					XCB_XKB_MINOR_VERSION);
263
	use_ext_reply = xcb_xkb_use_extension_reply(b->conn, use_ext, NULL);
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278
	if (!use_ext_reply) {
		weston_log("couldn't start using XKB extension\n");
		return;
	}

	if (!use_ext_reply->supported) {
		weston_log("XKB extension version on the server is too old "
			   "(want %d.%d, has %d.%d)\n",
			   XCB_XKB_MAJOR_VERSION, XCB_XKB_MINOR_VERSION,
			   use_ext_reply->serverMajor, use_ext_reply->serverMinor);
		free(use_ext_reply);
		return;
	}
	free(use_ext_reply);

279
	pcf = xcb_xkb_per_client_flags(b->conn,
280 281 282 283 284 285
				       XCB_XKB_ID_USE_CORE_KBD,
				       XCB_XKB_PER_CLIENT_FLAG_DETECTABLE_AUTO_REPEAT,
				       XCB_XKB_PER_CLIENT_FLAG_DETECTABLE_AUTO_REPEAT,
				       0,
				       0,
				       0);
286
	pcf_reply = xcb_xkb_per_client_flags_reply(b->conn, pcf, NULL);
287 288
	if (!pcf_reply ||
	    !(pcf_reply->value & XCB_XKB_PER_CLIENT_FLAG_DETECTABLE_AUTO_REPEAT)) {
289 290
		weston_log("failed to set XKB per-client flags, not using "
			   "detectable repeat\n");
291
		free(pcf_reply);
292 293
		return;
	}
294
	free(pcf_reply);
295

296 297
	state = xcb_xkb_get_state(b->conn, XCB_XKB_ID_USE_CORE_KBD);
	state_reply = xcb_xkb_get_state_reply(b->conn, state, NULL);
298
	if (!state_reply) {
299 300 301 302
		weston_log("failed to get initial XKB state\n");
		return;
	}

303 304
	keyboard = weston_seat_get_keyboard(&b->core_seat);
	xkb_state_update_mask(keyboard->xkb_state.state,
305 306 307
			      get_xkb_mod_mask(b, state_reply->baseMods),
			      get_xkb_mod_mask(b, state_reply->latchedMods),
			      get_xkb_mod_mask(b, state_reply->lockedMods),
308 309 310 311 312 313
			      0,
			      0,
			      state_reply->group);

	free(state_reply);

314
	xcb_change_window_attributes(b->conn, b->screen->root,
315 316
				     XCB_CW_EVENT_MASK, values);

317
	b->has_xkb = 1;
318 319 320
#endif
}

321
#ifdef HAVE_XCB_XKB
322
static void
323
update_xkb_keymap(struct x11_backend *b)
324 325 326
{
	struct xkb_keymap *keymap;

327
	keymap = x11_backend_get_keymap(b);
328 329 330 331
	if (!keymap) {
		weston_log("failed to get XKB keymap\n");
		return;
	}
332
	weston_seat_update_keymap(&b->core_seat, keymap);
333 334
	xkb_keymap_unref(keymap);
}
335
#endif
336

337
static int
338
x11_input_create(struct x11_backend *b, int no_input)
339
{
340
	struct xkb_keymap *keymap;
341

342
	weston_seat_init(&b->core_seat, b->compositor, "default");
343 344 345 346

	if (no_input)
		return 0;

347
	weston_seat_init_pointer(&b->core_seat);
348

349 350
	keymap = x11_backend_get_keymap(b);
	if (weston_seat_init_keyboard(&b->core_seat, keymap) < 0)
351
		return -1;
352
	xkb_keymap_unref(keymap);
353

354
	x11_backend_setup_xkb(b);
355

356
	return 0;
357 358
}

359
static void
360
x11_input_destroy(struct x11_backend *b)
361
{
362
	weston_seat_release(&b->core_seat);
363 364
}

365 366 367
static void
x11_output_start_repaint_loop(struct weston_output *output)
{
368
	struct timespec ts;
369

370
	weston_compositor_read_presentation_clock(output->compositor, &ts);
371
	weston_output_finish_frame(output, &ts, WP_PRESENTATION_FEEDBACK_INVALID);
372 373
}

374
static int
375 376 377 378 379 380 381 382 383 384 385 386
x11_output_repaint_gl(struct weston_output *output_base,
		      pixman_region32_t *damage)
{
	struct x11_output *output = (struct x11_output *)output_base;
	struct weston_compositor *ec = output->base.compositor;

	ec->renderer->repaint_output(output_base, damage);

	pixman_region32_subtract(&ec->primary_plane.damage,
				 &ec->primary_plane.damage, damage);

	wl_event_source_timer_update(output->finish_frame_timer, 10);
387
	return 0;
388 389
}

390 391 392 393 394
static void
set_clip_for_output(struct weston_output *output_base, pixman_region32_t *region)
{
	struct x11_output *output = (struct x11_output *)output_base;
	struct weston_compositor *ec = output->base.compositor;
395
	struct x11_backend *b = (struct x11_backend *)ec->backend;
396
	pixman_region32_t transformed_region;
397 398 399
	pixman_box32_t *rects;
	xcb_rectangle_t *output_rects;
	xcb_void_cookie_t cookie;
400
	int nrects, i;
401 402
	xcb_generic_error_t *err;

403 404 405 406 407 408 409 410 411 412
	pixman_region32_init(&transformed_region);
	pixman_region32_copy(&transformed_region, region);
	pixman_region32_translate(&transformed_region,
				  -output_base->x, -output_base->y);
	weston_transformed_region(output_base->width, output_base->height,
				  output_base->transform,
				  output_base->current_scale,
				  &transformed_region, &transformed_region);

	rects = pixman_region32_rectangles(&transformed_region, &nrects);
413 414
	output_rects = calloc(nrects, sizeof(xcb_rectangle_t));

415 416
	if (output_rects == NULL) {
		pixman_region32_fini(&transformed_region);
417
		return;
418
	}
419 420

	for (i = 0; i < nrects; i++) {
421 422 423 424
		output_rects[i].x = rects[i].x1;
		output_rects[i].y = rects[i].y1;
		output_rects[i].width = rects[i].x2 - rects[i].x1;
		output_rects[i].height = rects[i].y2 - rects[i].y1;
425 426
	}

427 428
	pixman_region32_fini(&transformed_region);

429
	cookie = xcb_set_clip_rectangles_checked(b->conn, XCB_CLIP_ORDERING_UNSORTED,
430 431 432
					output->gc,
					0, 0, nrects,
					output_rects);
433
	err = xcb_request_check(b->conn, cookie);
434 435 436 437 438 439 440 441
	if (err != NULL) {
		weston_log("Failed to set clip rects, err: %d\n", err->error_code);
		free(err);
	}
	free(output_rects);
}


442
static int
443 444
x11_output_repaint_shm(struct weston_output *output_base,
		       pixman_region32_t *damage)
445
{
446
	struct x11_output *output = (struct x11_output *)output_base;
447
	struct weston_compositor *ec = output->base.compositor;
448
	struct x11_backend *b = (struct x11_backend *)ec->backend;
449 450
	xcb_void_cookie_t cookie;
	xcb_generic_error_t *err;
451

452
	pixman_renderer_output_set_buffer(output_base, output->hw_surface);
453
	ec->renderer->repaint_output(output_base, damage);
454

455 456
	pixman_region32_subtract(&ec->primary_plane.damage,
				 &ec->primary_plane.damage, damage);
457
	set_clip_for_output(output_base, damage);
458
	cookie = xcb_shm_put_image_checked(b->conn, output->window, output->gc,
459 460 461 462 463 464 465
					pixman_image_get_width(output->hw_surface),
					pixman_image_get_height(output->hw_surface),
					0, 0,
					pixman_image_get_width(output->hw_surface),
					pixman_image_get_height(output->hw_surface),
					0, 0, output->depth, XCB_IMAGE_FORMAT_Z_PIXMAP,
					0, output->segment, 0);
466
	err = xcb_request_check(b->conn, cookie);
467 468 469 470
	if (err != NULL) {
		weston_log("Failed to put shm image, err: %d\n", err->error_code);
		free(err);
	}
471

472
	wl_event_source_timer_update(output->finish_frame_timer, 10);
473
	return 0;
474 475
}

476 477 478 479
static int
finish_frame_handler(void *data)
{
	struct x11_output *output = data;
480
	struct timespec ts;
481

482
	weston_compositor_read_presentation_clock(output->base.compositor, &ts);
483
	weston_output_finish_frame(&output->base, &ts, 0);
484 485 486 487

	return 1;
}

488
static void
489
x11_output_deinit_shm(struct x11_backend *b, struct x11_output *output)
490 491 492
{
	xcb_void_cookie_t cookie;
	xcb_generic_error_t *err;
493
	xcb_free_gc(b->conn, output->gc);
494 495 496

	pixman_image_unref(output->hw_surface);
	output->hw_surface = NULL;
497 498
	cookie = xcb_shm_detach_checked(b->conn, output->segment);
	err = xcb_request_check(b->conn, cookie);
499 500 501 502 503 504 505
	if (err) {
		weston_log("xcb_shm_detach failed, error %d\n", err->error_code);
		free(err);
	}
	shmdt(output->buf);
}

Matt Roper's avatar
Matt Roper committed
506
static void
507
x11_output_destroy(struct weston_output *output_base)
Matt Roper's avatar
Matt Roper committed
508
{
509
	struct x11_output *output = (struct x11_output *)output_base;
510 511
	struct x11_backend *backend =
		(struct x11_backend *)output->base.compositor->backend;
512 513 514

	wl_event_source_remove(output->finish_frame_timer);

515
	if (backend->use_pixman) {
516
		pixman_renderer_output_destroy(output_base);
517
		x11_output_deinit_shm(backend, output);
518
	} else
519
		gl_renderer->output_destroy(output_base);
520

521
	xcb_destroy_window(backend->conn, output->window);
522

523 524
	xcb_flush(backend->conn);

525
	weston_output_destroy(&output->base);
526 527

	free(output);
Matt Roper's avatar
Matt Roper committed
528
}
529

530
static void
531
x11_output_set_wm_protocols(struct x11_backend *b,
532
			    struct x11_output *output)
533 534 535
{
	xcb_atom_t list[1];

536 537
	list[0] = b->atom.wm_delete_window;
	xcb_change_property (b->conn,
538 539
			     XCB_PROP_MODE_REPLACE,
			     output->window,
540
			     b->atom.wm_protocols,
541 542
			     XCB_ATOM_ATOM,
			     32,
543
			     ARRAY_LENGTH(list),
544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561
			     list);
}

struct wm_normal_hints {
    	uint32_t flags;
	uint32_t pad[4];
	int32_t min_width, min_height;
	int32_t max_width, max_height;
    	int32_t width_inc, height_inc;
    	int32_t min_aspect_x, min_aspect_y;
    	int32_t max_aspect_x, max_aspect_y;
	int32_t base_width, base_height;
	int32_t win_gravity;
};

#define WM_NORMAL_HINTS_MIN_SIZE	16
#define WM_NORMAL_HINTS_MAX_SIZE	32

562
static void
563
x11_output_set_icon(struct x11_backend *b,
564
		    struct x11_output *output, const char *filename)
565
{
566
	uint32_t *icon;
567
	int32_t width, height;
568
	pixman_image_t *image;
569

570 571
	image = load_image(filename);
	if (!image)
572
		return;
573 574
	width = pixman_image_get_width(image);
	height = pixman_image_get_height(image);
575 576
	icon = malloc(width * height * 4 + 8);
	if (!icon) {
577
		pixman_image_unref(image);
578 579 580 581 582
		return;
	}

	icon[0] = width;
	icon[1] = height;
583
	memcpy(icon + 2, pixman_image_get_data(image), width * height * 4);
584 585
	xcb_change_property(b->conn, XCB_PROP_MODE_REPLACE, output->window,
			    b->atom.net_wm_icon, b->atom.cardinal, 32,
586 587
			    width * height + 2, icon);
	free(icon);
588
	pixman_image_unref(image);
589 590
}

591
static void
592
x11_output_wait_for_map(struct x11_backend *b, struct x11_output *output)
593 594 595 596
{
	xcb_map_notify_event_t *map_notify;
	xcb_configure_notify_event_t *configure_notify;
	xcb_generic_event_t *event;
597
	int mapped = 0, configured = 0;
598 599 600
	uint8_t response_type;

	/* This isn't the nicest way to do this.  Ideally, we could
601
	 * just go back to the main loop and once we get the configure
602 603
	 * notify, we add the output to the compositor.  While we do
	 * support output hotplug, we can't start up with no outputs.
604 605 606 607 608 609 610 611
	 * We could add the output and then resize once we get the
	 * configure notify, but we don't want to start up and
	 * immediately resize the output.
	 *
	 * Also, some window managers don't give us our final
	 * fullscreen size before map_notify, so if we don't get a
	 * configure_notify before map_notify, we just wait for the
	 * first one and hope that's our size. */
612

613
	xcb_flush(b->conn);
614

615
	while (!mapped || !configured) {
616
		event = xcb_wait_for_event(b->conn);
617 618 619 620 621 622 623 624 625 626 627 628 629
		response_type = event->response_type & ~0x80;

		switch (response_type) {
		case XCB_MAP_NOTIFY:
			map_notify = (xcb_map_notify_event_t *) event;
			if (map_notify->window == output->window)
				mapped = 1;
			break;

		case XCB_CONFIGURE_NOTIFY:
			configure_notify =
				(xcb_configure_notify_event_t *) event;

630 631 632 633

			if (configure_notify->width % output->scale != 0 ||
			    configure_notify->height % output->scale != 0)
				weston_log("Resolution is not a multiple of screen size, rounding\n");
634 635
			output->mode.width = configure_notify->width;
			output->mode.height = configure_notify->height;
636
			configured = 1;
637 638 639 640 641
			break;
		}
	}
}

642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680
static xcb_visualtype_t *
find_visual_by_id(xcb_screen_t *screen,
		   xcb_visualid_t id)
{
	xcb_depth_iterator_t i;
	xcb_visualtype_iterator_t j;
	for (i = xcb_screen_allowed_depths_iterator(screen);
	     i.rem;
	     xcb_depth_next(&i)) {
		for (j = xcb_depth_visuals_iterator(i.data);
		     j.rem;
		     xcb_visualtype_next(&j)) {
			if (j.data->visual_id == id)
				return j.data;
		}
	}
	return 0;
}

static uint8_t
get_depth_of_visual(xcb_screen_t *screen,
		   xcb_visualid_t id)
{
	xcb_depth_iterator_t i;
	xcb_visualtype_iterator_t j;
	for (i = xcb_screen_allowed_depths_iterator(screen);
	     i.rem;
	     xcb_depth_next(&i)) {
		for (j = xcb_depth_visuals_iterator(i.data);
		     j.rem;
		     xcb_visualtype_next(&j)) {
			if (j.data->visual_id == id)
				return i.data->depth;
		}
	}
	return 0;
}

static int
681
x11_output_init_shm(struct x11_backend *b, struct x11_output *output,
682 683 684
	int width, int height)
{
	xcb_visualtype_t *visual_type;
685
	xcb_screen_t *screen;
686 687 688 689 690 691 692 693
	xcb_format_iterator_t fmt;
	xcb_void_cookie_t cookie;
	xcb_generic_error_t *err;
	const xcb_query_extension_reply_t *ext;
	int bitsperpixel = 0;
	pixman_format_code_t pixman_format;

	/* Check if SHM is available */
694
	ext = xcb_get_extension_data(b->conn, &xcb_shm_id);
695 696 697 698 699 700 701
	if (ext == NULL || !ext->present) {
		/* SHM is missing */
		weston_log("SHM extension is not available\n");
		errno = ENOENT;
		return -1;
	}

702 703
	screen = x11_compositor_get_default_screen(b);
	visual_type = find_visual_by_id(screen, screen->root_visual);
704 705 706 707 708 709 710 711 712 713
	if (!visual_type) {
		weston_log("Failed to lookup visual for root window\n");
		errno = ENOENT;
		return -1;
	}
	weston_log("Found visual, bits per value: %d, red_mask: %.8x, green_mask: %.8x, blue_mask: %.8x\n",
		visual_type->bits_per_rgb_value,
		visual_type->red_mask,
		visual_type->green_mask,
		visual_type->blue_mask);
714
	output->depth = get_depth_of_visual(screen, screen->root_visual);
715 716
	weston_log("Visual depth is %d\n", output->depth);

717
	for (fmt = xcb_setup_pixmap_formats_iterator(xcb_get_setup(b->conn));
718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733
	     fmt.rem;
	     xcb_format_next(&fmt)) {
		if (fmt.data->depth == output->depth) {
			bitsperpixel = fmt.data->bits_per_pixel;
			break;
		}
	}
	weston_log("Found format for depth %d, bpp: %d\n",
		output->depth, bitsperpixel);

	if  (bitsperpixel == 32 &&
	     visual_type->red_mask == 0xff0000 &&
	     visual_type->green_mask == 0x00ff00 &&
	     visual_type->blue_mask == 0x0000ff) {
		weston_log("Will use x8r8g8b8 format for SHM surfaces\n");
		pixman_format = PIXMAN_x8r8g8b8;
734 735 736 737 738 739
	} else if (bitsperpixel == 16 &&
	           visual_type->red_mask == 0x00f800 &&
	           visual_type->green_mask == 0x0007e0 &&
	           visual_type->blue_mask == 0x00001f) {
		weston_log("Will use r5g6b5 format for SHM surfaces\n");
		pixman_format = PIXMAN_r5g6b5;
740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757
	} else {
		weston_log("Can't find appropriate format for SHM pixmap\n");
		errno = ENOTSUP;
		return -1;
	}


	/* Create SHM segment and attach it */
	output->shm_id = shmget(IPC_PRIVATE, width * height * (bitsperpixel / 8), IPC_CREAT | S_IRWXU);
	if (output->shm_id == -1) {
		weston_log("x11shm: failed to allocate SHM segment\n");
		return -1;
	}
	output->buf = shmat(output->shm_id, NULL, 0 /* read/write */);
	if (-1 == (long)output->buf) {
		weston_log("x11shm: failed to attach SHM segment\n");
		return -1;
	}
758 759 760
	output->segment = xcb_generate_id(b->conn);
	cookie = xcb_shm_attach_checked(b->conn, output->segment, output->shm_id, 1);
	err = xcb_request_check(b->conn, cookie);
761
	if (err) {
762 763
		weston_log("x11shm: xcb_shm_attach error %d, op code %d, resource id %d\n",
			   err->error_code, err->major_code, err->minor_code);
764 765 766 767 768 769 770 771 772 773
		free(err);
		return -1;
	}

	shmctl(output->shm_id, IPC_RMID, NULL);

	/* Now create pixman image */
	output->hw_surface = pixman_image_create_bits(pixman_format, width, height, output->buf,
		width * (bitsperpixel / 8));

774 775
	output->gc = xcb_generate_id(b->conn);
	xcb_create_gc(b->conn, output->gc, output->window, 0, NULL);
776 777 778 779

	return 0;
}

780
static struct x11_output *
781
x11_backend_create_output(struct x11_backend *b, int x, int y,
782
			     int width, int height, int fullscreen,
783
			     int no_input, char *configured_name,
784
			     uint32_t transform, int32_t scale)
785
{
786
	static const char name[] = "Weston Compositor";
787
	static const char class[] = "weston-1\0Weston Compositor";
788
	char *title = NULL;
789
	struct x11_output *output;
790
	xcb_screen_t *screen;
791
	struct wm_normal_hints normal_hints;
792
	struct wl_event_loop *loop;
793
	int output_width, output_height, width_mm, height_mm;
794
	int ret;
795
	uint32_t mask = XCB_CW_EVENT_MASK | XCB_CW_CURSOR;
796
	xcb_atom_t atom_list[1];
797
	uint32_t values[2] = {
798
		XCB_EVENT_MASK_EXPOSURE |
799
		XCB_EVENT_MASK_STRUCTURE_NOTIFY,
800 801 802
		0
	};

803 804 805
	output_width = width * scale;
	output_height = height * scale;

806 807 808 809 810 811 812 813 814 815 816 817
	if (!no_input)
		values[0] |=
			XCB_EVENT_MASK_KEY_PRESS |
			XCB_EVENT_MASK_KEY_RELEASE |
			XCB_EVENT_MASK_BUTTON_PRESS |
			XCB_EVENT_MASK_BUTTON_RELEASE |
			XCB_EVENT_MASK_POINTER_MOTION |
			XCB_EVENT_MASK_ENTER_WINDOW |
			XCB_EVENT_MASK_LEAVE_WINDOW |
			XCB_EVENT_MASK_KEYMAP_STATE |
			XCB_EVENT_MASK_FOCUS_CHANGE;

Peter Hutterer's avatar
Peter Hutterer committed
818
	output = zalloc(sizeof *output);
819 820
	if (output == NULL) {
		perror("zalloc");
821
		return NULL;
822
	}
823

824 825
	output->mode.flags =
		WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
826

827 828
	output->mode.width = output_width;
	output->mode.height = output_height;
829
	output->mode.refresh = 60000;
830
	output->scale = scale;
831 832 833
	wl_list_init(&output->base.mode_list);
	wl_list_insert(&output->base.mode_list, &output->mode.link);

834 835
	values[1] = b->null_cursor;
	output->window = xcb_generate_id(b->conn);
836
	screen = x11_compositor_get_default_screen(b);
837
	xcb_create_window(b->conn,
838 839
			  XCB_COPY_FROM_PARENT,
			  output->window,
840
			  screen->root,
841
			  0, 0,
842
			  output_width, output_height,
843 844
			  0,
			  XCB_WINDOW_CLASS_INPUT_OUTPUT,
845
			  screen->root_visual,
846 847
			  mask, values);

848
	if (fullscreen) {
849 850
		atom_list[0] = b->atom.net_wm_state_fullscreen;
		xcb_change_property(b->conn, XCB_PROP_MODE_REPLACE,
851
				    output->window,
852
				    b->atom.net_wm_state,
853 854 855 856 857 858 859
				    XCB_ATOM_ATOM, 32,
				    ARRAY_LENGTH(atom_list), atom_list);
	} else {
		/* Don't resize me. */
		memset(&normal_hints, 0, sizeof normal_hints);
		normal_hints.flags =
			WM_NORMAL_HINTS_MAX_SIZE | WM_NORMAL_HINTS_MIN_SIZE;
860 861 862 863
		normal_hints.min_width = output_width;
		normal_hints.min_height = output_height;
		normal_hints.max_width = output_width;
		normal_hints.max_height = output_height;
864 865 866
		xcb_change_property(b->conn, XCB_PROP_MODE_REPLACE, output->window,
				    b->atom.wm_normal_hints,
				    b->atom.wm_size_hints, 32,
867 868 869
				    sizeof normal_hints / 4,
				    (uint8_t *) &normal_hints);
	}
870 871

	/* Set window name.  Don't bother with non-EWMH WMs. */
872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889
	if (configured_name) {
		if (asprintf(&title, "%s - %s", name, configured_name) < 0)
			title = NULL;
	} else {
		title = strdup(name);
	}

	if (title) {
		xcb_change_property(b->conn, XCB_PROP_MODE_REPLACE, output->window,
				    b->atom.net_wm_name, b->atom.utf8_string, 8,
				    strlen(title), title);
		free(title);
	} else {
		xcb_destroy_window(b->conn, output->window);
		free(output);
		return NULL;
	}

890 891
	xcb_change_property(b->conn, XCB_PROP_MODE_REPLACE, output->window,
			    b->atom.wm_class, b->atom.string, 8,
892 893
			    sizeof class, class);

894
	x11_output_set_icon(b, output, DATADIR "/weston/wayland.png");
895

896
	x11_output_set_wm_protocols(b, output);
897

898
	xcb_map_window(b->conn, output->window);
899

900
	if (fullscreen)
901
		x11_output_wait_for_map(b, output);
902

903
	output->base.start_repaint_loop = x11_output_start_repaint_loop;
904
	if (b->use_pixman)
905 906 907
		output->base.repaint = x11_output_repaint_shm;
	else
		output->base.repaint = x11_output_repaint_gl;
Matt Roper's avatar
Matt Roper committed
908
	output->base.destroy = x11_output_destroy;
909
	output->base.assign_planes = NULL;
910 911
	output->base.set_backlight = NULL;
	output->base.set_dpms = NULL;
912
	output->base.switch_mode = NULL;
913
	output->base.current_mode = &output->mode;
914
	output->base.make = "weston-X11";
915
	output->base.model = "none";
916 917 918 919

	if (configured_name)
		output->base.name = strdup(configured_name);

920 921 922 923 924
	width_mm = width * b->screen->width_in_millimeters /
		b->screen->width_in_pixels;
	height_mm = height * b->screen->height_in_millimeters /
		b->screen->height_in_pixels;
	weston_output_init(&output->base, b->compositor,
925
			   x, y, width_mm, height_mm, transform, scale);
926

927 928
	if (b->use_pixman) {
		if (x11_output_init_shm(b, output,
929
					output->mode.width,
930 931
					output->mode.height) < 0) {
			weston_log("Failed to initialize SHM for the X11 output\n");
932
			return NULL;
933
		}
934
		if (pixman_renderer_output_create(&output->base) < 0) {
935
			weston_log("Failed to create pixman renderer for output\n");
936
			x11_output_deinit_shm(b, output);
937 938 939
			return NULL;
		}
	} else {
940 941 942 943
		/* eglCreatePlatformWindowSurfaceEXT takes a Window*
		 * but eglCreateWindowSurface takes a Window. */
		Window xid = (Window) output->window;

944
		ret = gl_renderer->output_create(&output->base,
945
						 (EGLNativeWindowType) output->window,
946
						 &xid,
947
						 gl_renderer->opaque_attribs,
948 949
						 NULL,
						 0);
950
		if (ret < 0)
951 952
			return NULL;
	}
953

954
	loop = wl_display_get_event_loop(b->compositor->wl_display);
955 956 957
	output->finish_frame_timer =
		wl_event_loop_add_timer(loop, finish_frame_handler, output);

958
	weston_compositor_add_output(b->compositor, &output->base);
959

960 961 962
	weston_log("x11 output %dx%d, window id %d\n",
		   width, height, output->window);

963
	return output;
964 965 966
}

static struct x11_output *
967
x11_backend_find_output(struct x11_backend *b, xcb_window_t window)
968 969 970
{
	struct x11_output *output;

971
	wl_list_for_each(output, &b->compositor->output_list, base.link) {
972 973 974 975
		if (output->window == window)
			return output;
	}

976
	return NULL;
977 978
}

979
static void
980
x11_backend_delete_window(struct x11_backend *b, xcb_window_t window)
981
{
982
	struct x11_output *output;
983

984
	output = x11_backend_find_output(b, window);
985 986
	if (output)
		x11_output_destroy(&output->base);
987

988
	if (wl_list_empty(&b->compositor->output_list))
989
		weston_compositor_exit(b->compositor);
990 991
}

992 993 994 995
static void delete_cb(void *data)
{
	struct window_delete_data *wd = data;

996
	x11_backend_delete_window(wd->backend, wd->window);
997 998 999
	free(wd);
}

1000
#ifdef HAVE_XCB_XKB
1001
static void
1002
update_xkb_state(struct x11_backend *b, xcb_xkb_state_notify_event_t *state)
1003
{
1004 1005 1006 1007
	struct weston_keyboard *keyboard =
		weston_seat_get_keyboard(&b->core_seat);

	xkb_state_update_mask(keyboard->xkb_state.state,
1008 1009 1010
			      get_xkb_mod_mask(b, state->baseMods),
			      get_xkb_mod_mask(b, state->latchedMods),
			      get_xkb_mod_mask(b, state->lockedMods),
1011 1012 1013 1014
			      0,
			      0,
			      state->group);

1015 1016
	notify_modifiers(&b->core_seat,
			 wl_display_next_serial(b->compositor->wl_display));
1017 1018 1019
}
#endif

1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031
/**
 * This is monumentally unpleasant.  If we don't have XCB-XKB bindings,
 * the best we can do (given that XCB also lacks XI2 support), is to take
 * the state from the core key events.  Unfortunately that only gives us
 * the effective (i.e. union of depressed/latched/locked) state, and we
 * need the granularity.
 *
 * So we still update the state with every key event we see, but also use
 * the state field from X11 events as a mask so we don't get any stuck
 * modifiers.
 */
static void
1032
update_xkb_state_from_core(struct x11_backend *b, uint16_t x11_mask)
1033
{
1034
	uint32_t mask = get_xkb_mod_mask(b, x11_mask);
1035 1036
	struct weston_keyboard *keyboard
		= weston_seat_get_keyboard(&b->core_seat);
1037

1038
	xkb_state_update_mask(keyboard->xkb_state.state,
1039 1040 1041 1042 1043 1044
			      keyboard->modifiers.mods_depressed & mask,
			      keyboard->modifiers.mods_latched & mask,
			      keyboard->modifiers.mods_locked & mask,
			      0,
			      0,
			      (x11_mask >> 13) & 3);
1045 1046
	notify_modifiers(&b->core_seat,
			 wl_display_next_serial(b->compositor->wl_display));
1047 1048
}

1049
static void
1050 1051
x11_backend_deliver_button_event(struct x11_backend *b,
				 xcb_generic_event_t *event, int state)
1052 1053 1054
{
	xcb_button_press_event_t *button_event =
		(xcb_button_press_event_t *) event;