mirror of
				https://gitlab.freedesktop.org/wayland/wayland.git
				synced 2025-11-03 09:01:42 -05:00 
			
		
		
		
	Add x11 backend for compositor
This still needs all the bells and whistles from the egl-kms mesa branch, but it makes it a lot easier to work on wayland.
This commit is contained in:
		
							parent
							
								
									fc783d4071
								
							
						
					
					
						commit
						ce5325d3ed
					
				
					 7 changed files with 901 additions and 184 deletions
				
			
		
							
								
								
									
										1
									
								
								Makefile
									
										
									
									
									
								
							
							
						
						
									
										1
									
								
								Makefile
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -28,6 +28,7 @@ $(libs) :
 | 
			
		|||
compositor :					\
 | 
			
		||||
	compositor.o				\
 | 
			
		||||
	compositor-drm.o			\
 | 
			
		||||
	compositor-x11.o			\
 | 
			
		||||
	screenshooter.o				\
 | 
			
		||||
	cairo-util.o
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										262
									
								
								compositor-drm.c
									
										
									
									
									
								
							
							
						
						
									
										262
									
								
								compositor-drm.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -37,8 +37,43 @@
 | 
			
		|||
#include "wayland-protocol.h"
 | 
			
		||||
#include "compositor.h"
 | 
			
		||||
 | 
			
		||||
struct drm_compositor {
 | 
			
		||||
	struct wlsc_compositor base;
 | 
			
		||||
 | 
			
		||||
	struct udev *udev;
 | 
			
		||||
	struct wl_event_source *drm_source;
 | 
			
		||||
	int drm_fd;
 | 
			
		||||
 | 
			
		||||
	struct wl_event_source *term_signal_source;
 | 
			
		||||
 | 
			
		||||
        /* tty handling state */
 | 
			
		||||
	int tty_fd;
 | 
			
		||||
	uint32_t vt_active : 1;
 | 
			
		||||
 | 
			
		||||
	struct termios terminal_attributes;
 | 
			
		||||
	struct wl_event_source *tty_input_source;
 | 
			
		||||
	struct wl_event_source *enter_vt_source;
 | 
			
		||||
	struct wl_event_source *leave_vt_source;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct drm_output {
 | 
			
		||||
	struct wlsc_output   base;
 | 
			
		||||
 | 
			
		||||
	drmModeModeInfo mode;
 | 
			
		||||
	uint32_t crtc_id;
 | 
			
		||||
	uint32_t connector_id;
 | 
			
		||||
	GLuint rbo[2];
 | 
			
		||||
	uint32_t fb_id[2];
 | 
			
		||||
	EGLImageKHR image[2];
 | 
			
		||||
	uint32_t current;	
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct drm_input {
 | 
			
		||||
	struct wlsc_input_device base;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct evdev_input_device {
 | 
			
		||||
	struct wlsc_input_device *device;
 | 
			
		||||
	struct drm_input *master;
 | 
			
		||||
	struct wl_event_source *source;
 | 
			
		||||
	int tool, new_x, new_y;
 | 
			
		||||
	int base_x, base_y;
 | 
			
		||||
| 
						 | 
				
			
			@ -47,16 +82,21 @@ struct evdev_input_device {
 | 
			
		|||
 | 
			
		||||
static void evdev_input_device_data(int fd, uint32_t mask, void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_compositor *c;
 | 
			
		||||
	struct evdev_input_device *device = data;
 | 
			
		||||
	struct input_event ev[8], *e, *end;
 | 
			
		||||
	int len, value, dx, dy, absolute_event;
 | 
			
		||||
	int x, y;
 | 
			
		||||
 | 
			
		||||
	c = (struct drm_compositor *) device->master->base.ec;
 | 
			
		||||
	if (!c->vt_active)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	dx = 0;
 | 
			
		||||
	dy = 0;
 | 
			
		||||
	absolute_event = 0;
 | 
			
		||||
	x = device->device->x;
 | 
			
		||||
	y = device->device->y;
 | 
			
		||||
	x = device->master->base.x;
 | 
			
		||||
	y = device->master->base.y;
 | 
			
		||||
 | 
			
		||||
	len = read(fd, &ev, sizeof ev);
 | 
			
		||||
	if (len < 0 || len % sizeof e[0] != 0) {
 | 
			
		||||
| 
						 | 
				
			
			@ -132,24 +172,26 @@ static void evdev_input_device_data(int fd, uint32_t mask, void *data)
 | 
			
		|||
			case BTN_FORWARD:
 | 
			
		||||
			case BTN_BACK:
 | 
			
		||||
			case BTN_TASK:
 | 
			
		||||
				notify_button(device->device, e->code, value);
 | 
			
		||||
				notify_button(&device->master->base,
 | 
			
		||||
					      e->code, value);
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			default:
 | 
			
		||||
				notify_key(device->device, e->code, value);
 | 
			
		||||
				notify_key(&device->master->base,
 | 
			
		||||
					   e->code, value);
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (dx != 0 || dy != 0)
 | 
			
		||||
		notify_motion(device->device, x + dx, y + dy);
 | 
			
		||||
		notify_motion(&device->master->base, x + dx, y + dy);
 | 
			
		||||
	if (absolute_event && device->tool)
 | 
			
		||||
		notify_motion(device->device, x, y);
 | 
			
		||||
		notify_motion(&device->master->base, x, y);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct evdev_input_device *
 | 
			
		||||
evdev_input_device_create(struct wlsc_input_device *master,
 | 
			
		||||
evdev_input_device_create(struct drm_input *master,
 | 
			
		||||
			  struct wl_display *display, const char *path)
 | 
			
		||||
{
 | 
			
		||||
	struct evdev_input_device *device;
 | 
			
		||||
| 
						 | 
				
			
			@ -162,7 +204,7 @@ evdev_input_device_create(struct wlsc_input_device *master,
 | 
			
		|||
	device->tool = 1;
 | 
			
		||||
	device->new_x = 1;
 | 
			
		||||
	device->new_y = 1;
 | 
			
		||||
	device->device = master;
 | 
			
		||||
	device->master = master;
 | 
			
		||||
 | 
			
		||||
	device->fd = open(path, O_RDONLY);
 | 
			
		||||
	if (device->fd < 0) {
 | 
			
		||||
| 
						 | 
				
			
			@ -184,13 +226,52 @@ evdev_input_device_create(struct wlsc_input_device *master,
 | 
			
		|||
	return device;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
wlsc_compositor_present_drm(struct wlsc_compositor *ec)
 | 
			
		||||
static void
 | 
			
		||||
drm_input_create(struct drm_compositor *c)
 | 
			
		||||
{
 | 
			
		||||
	struct wlsc_output *output;
 | 
			
		||||
	struct drm_input *input;
 | 
			
		||||
	struct udev_enumerate *e;
 | 
			
		||||
        struct udev_list_entry *entry;
 | 
			
		||||
	struct udev_device *device;
 | 
			
		||||
	const char *path;
 | 
			
		||||
 | 
			
		||||
	wl_list_for_each(output, &ec->output_list, link) {
 | 
			
		||||
		drmModePageFlip(ec->drm_fd, output->crtc_id,
 | 
			
		||||
	input = malloc(sizeof *input);
 | 
			
		||||
	if (input == NULL)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	memset(input, 0, sizeof *input);
 | 
			
		||||
	wlsc_input_device_init(&input->base, &c->base);
 | 
			
		||||
 | 
			
		||||
	e = udev_enumerate_new(c->udev);
 | 
			
		||||
	udev_enumerate_add_match_subsystem(e, "input");
 | 
			
		||||
	udev_enumerate_add_match_property(e, "WAYLAND_SEAT", "1");
 | 
			
		||||
        udev_enumerate_scan_devices(e);
 | 
			
		||||
        udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
 | 
			
		||||
		path = udev_list_entry_get_name(entry);
 | 
			
		||||
		device = udev_device_new_from_syspath(c->udev, path);
 | 
			
		||||
		evdev_input_device_create(input, c->base.wl_display,
 | 
			
		||||
					  udev_device_get_devnode(device));
 | 
			
		||||
	}
 | 
			
		||||
        udev_enumerate_unref(e);
 | 
			
		||||
 | 
			
		||||
	c->base.input_device = &input->base;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
drm_compositor_present(struct wlsc_compositor *ec)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_compositor *c = (struct drm_compositor *) ec;
 | 
			
		||||
	struct drm_output *output;
 | 
			
		||||
 | 
			
		||||
	wl_list_for_each(output, &ec->output_list, base.link) {
 | 
			
		||||
		output->current ^= 1;
 | 
			
		||||
 | 
			
		||||
		glFramebufferRenderbuffer(GL_FRAMEBUFFER,
 | 
			
		||||
					  GL_COLOR_ATTACHMENT0,
 | 
			
		||||
					  GL_RENDERBUFFER,
 | 
			
		||||
					  output->rbo[output->current]);
 | 
			
		||||
 | 
			
		||||
		drmModePageFlip(c->drm_fd, output->crtc_id,
 | 
			
		||||
				output->fb_id[output->current ^ 1],
 | 
			
		||||
				DRM_MODE_PAGE_FLIP_EVENT, output);
 | 
			
		||||
	}	
 | 
			
		||||
| 
						 | 
				
			
			@ -220,9 +301,8 @@ on_drm_input(int fd, uint32_t mask, void *data)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
init_egl(struct wlsc_compositor *ec, struct udev_device *device)
 | 
			
		||||
init_egl(struct drm_compositor *ec, struct udev_device *device)
 | 
			
		||||
{
 | 
			
		||||
	struct wl_event_loop *loop;
 | 
			
		||||
	EGLint major, minor, count;
 | 
			
		||||
	EGLConfig config;
 | 
			
		||||
	PFNEGLGETTYPEDDISPLAYMESA get_typed_display_mesa;
 | 
			
		||||
| 
						 | 
				
			
			@ -241,8 +321,8 @@ init_egl(struct wlsc_compositor *ec, struct udev_device *device)
 | 
			
		|||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ec->base.device = strdup(udev_device_get_devnode(device));
 | 
			
		||||
	ec->drm_fd = open(ec->base.device, O_RDWR);
 | 
			
		||||
	ec->base.base.device = strdup(udev_device_get_devnode(device));
 | 
			
		||||
	ec->drm_fd = open(ec->base.base.device, O_RDWR);
 | 
			
		||||
	if (ec->drm_fd < 0) {
 | 
			
		||||
		/* Probably permissions error */
 | 
			
		||||
		fprintf(stderr, "couldn't open %s, skipping\n",
 | 
			
		||||
| 
						 | 
				
			
			@ -250,41 +330,39 @@ init_egl(struct wlsc_compositor *ec, struct udev_device *device)
 | 
			
		|||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ec->display = get_typed_display_mesa(EGL_DRM_DISPLAY_TYPE_MESA,
 | 
			
		||||
	ec->base.display = get_typed_display_mesa(EGL_DRM_DISPLAY_TYPE_MESA,
 | 
			
		||||
						  (void *) ec->drm_fd);
 | 
			
		||||
	if (ec->display == NULL) {
 | 
			
		||||
	if (ec->base.display == NULL) {
 | 
			
		||||
		fprintf(stderr, "failed to create display\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!eglInitialize(ec->display, &major, &minor)) {
 | 
			
		||||
	if (!eglInitialize(ec->base.display, &major, &minor)) {
 | 
			
		||||
		fprintf(stderr, "failed to initialize display\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!eglChooseConfig(ec->display, config_attribs, &config, 1, &count) ||
 | 
			
		||||
	if (!eglChooseConfig(ec->base.display,
 | 
			
		||||
			     config_attribs, &config, 1, &count) ||
 | 
			
		||||
	    count == 0) {
 | 
			
		||||
		fprintf(stderr, "eglChooseConfig() failed\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	eglBindAPI(EGL_OPENGL_API);
 | 
			
		||||
	ec->context = eglCreateContext(ec->display, config, EGL_NO_CONTEXT, NULL);
 | 
			
		||||
	if (ec->context == NULL) {
 | 
			
		||||
	ec->base.context = eglCreateContext(ec->base.display,
 | 
			
		||||
					    config, EGL_NO_CONTEXT, NULL);
 | 
			
		||||
	if (ec->base.context == NULL) {
 | 
			
		||||
		fprintf(stderr, "failed to create context\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!eglMakeCurrent(ec->display, EGL_NO_SURFACE, EGL_NO_SURFACE, ec->context)) {
 | 
			
		||||
	if (!eglMakeCurrent(ec->base.display, EGL_NO_SURFACE,
 | 
			
		||||
			    EGL_NO_SURFACE, ec->base.context)) {
 | 
			
		||||
		fprintf(stderr, "failed to make context current\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	loop = wl_display_get_event_loop(ec->wl_display);
 | 
			
		||||
	ec->drm_source =
 | 
			
		||||
		wl_event_loop_add_fd(loop, ec->drm_fd,
 | 
			
		||||
				     WL_EVENT_READABLE, on_drm_input, ec);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -299,11 +377,11 @@ static drmModeModeInfo builtin_1024x768 = {
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
create_output_for_connector(struct wlsc_compositor *ec,
 | 
			
		||||
create_output_for_connector(struct drm_compositor *ec,
 | 
			
		||||
			    drmModeRes *resources,
 | 
			
		||||
			    drmModeConnector *connector)
 | 
			
		||||
{
 | 
			
		||||
	struct wlsc_output *output;
 | 
			
		||||
	struct drm_output *output;
 | 
			
		||||
	drmModeEncoder *encoder;
 | 
			
		||||
	drmModeModeInfo *mode;
 | 
			
		||||
	int i, ret;
 | 
			
		||||
| 
						 | 
				
			
			@ -339,14 +417,13 @@ create_output_for_connector(struct wlsc_compositor *ec,
 | 
			
		|||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	output->compositor = ec;
 | 
			
		||||
	memset(output, 0, sizeof *output);
 | 
			
		||||
	wlsc_output_init(&output->base, &ec->base, 0, 0,
 | 
			
		||||
			 mode->hdisplay, mode->vdisplay);
 | 
			
		||||
 | 
			
		||||
	output->crtc_id = resources->crtcs[i];
 | 
			
		||||
	output->connector_id = connector->connector_id;
 | 
			
		||||
	output->mode = *mode;
 | 
			
		||||
	output->x = 0;
 | 
			
		||||
	output->y = 0;
 | 
			
		||||
	output->width = mode->hdisplay;
 | 
			
		||||
	output->height = mode->vdisplay;
 | 
			
		||||
 | 
			
		||||
	drmModeFreeEncoder(encoder);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -354,13 +431,17 @@ create_output_for_connector(struct wlsc_compositor *ec,
 | 
			
		|||
	for (i = 0; i < 2; i++) {
 | 
			
		||||
		glBindRenderbuffer(GL_RENDERBUFFER, output->rbo[i]);
 | 
			
		||||
 | 
			
		||||
		attribs[1] = output->width;
 | 
			
		||||
		attribs[3] = output->height;
 | 
			
		||||
		output->image[i] = eglCreateDRMImageMESA(ec->display, attribs);
 | 
			
		||||
		glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, output->image[i]);
 | 
			
		||||
		eglExportDRMImageMESA(ec->display, output->image[i], NULL, &handle, &stride);
 | 
			
		||||
		attribs[1] = output->base.width;
 | 
			
		||||
		attribs[3] = output->base.height;
 | 
			
		||||
		output->image[i] =
 | 
			
		||||
			eglCreateDRMImageMESA(ec->base.display, attribs);
 | 
			
		||||
		glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER,
 | 
			
		||||
						       output->image[i]);
 | 
			
		||||
		eglExportDRMImageMESA(ec->base.display, output->image[i],
 | 
			
		||||
				      NULL, &handle, &stride);
 | 
			
		||||
 | 
			
		||||
		ret = drmModeAddFB(ec->drm_fd, output->width, output->height,
 | 
			
		||||
		ret = drmModeAddFB(ec->drm_fd,
 | 
			
		||||
				   output->base.width, output->base.height,
 | 
			
		||||
				   32, 32, stride, handle, &output->fb_id[i]);
 | 
			
		||||
		if (ret) {
 | 
			
		||||
			fprintf(stderr, "failed to add fb %d: %m\n", i);
 | 
			
		||||
| 
						 | 
				
			
			@ -381,13 +462,13 @@ create_output_for_connector(struct wlsc_compositor *ec,
 | 
			
		|||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wl_list_insert(ec->output_list.prev, &output->link);
 | 
			
		||||
	wl_list_insert(ec->base.output_list.prev, &output->base.link);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
create_outputs(struct wlsc_compositor *ec)
 | 
			
		||||
create_outputs(struct drm_compositor *ec)
 | 
			
		||||
{
 | 
			
		||||
	drmModeConnector *connector;
 | 
			
		||||
	drmModeRes *resources;
 | 
			
		||||
| 
						 | 
				
			
			@ -413,7 +494,7 @@ create_outputs(struct wlsc_compositor *ec)
 | 
			
		|||
		drmModeFreeConnector(connector);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (wl_list_empty(&ec->output_list)) {
 | 
			
		||||
	if (wl_list_empty(&ec->base.output_list)) {
 | 
			
		||||
		fprintf(stderr, "No currently active connector found.\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -425,8 +506,8 @@ create_outputs(struct wlsc_compositor *ec)
 | 
			
		|||
 | 
			
		||||
static void on_enter_vt(int signal_number, void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct wlsc_compositor *ec = data;
 | 
			
		||||
	struct wlsc_output *output;
 | 
			
		||||
	struct drm_compositor *ec = data;
 | 
			
		||||
	struct drm_output *output;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	ret = drmSetMaster(ec->drm_fd);
 | 
			
		||||
| 
						 | 
				
			
			@ -441,19 +522,20 @@ static void on_enter_vt(int signal_number, void *data)
 | 
			
		|||
	ioctl(ec->tty_fd, VT_RELDISP, VT_ACKACQ);
 | 
			
		||||
	ec->vt_active = 1;
 | 
			
		||||
 | 
			
		||||
	wl_list_for_each(output, &ec->output_list, link) {
 | 
			
		||||
	wl_list_for_each(output, &ec->base.output_list, base.link) {
 | 
			
		||||
		ret = drmModeSetCrtc(ec->drm_fd, output->crtc_id,
 | 
			
		||||
				     output->fb_id[output->current ^ 1], 0, 0,
 | 
			
		||||
				     &output->connector_id, 1, &output->mode);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			fprintf(stderr, "failed to set mode for connector %d: %m\n",
 | 
			
		||||
			fprintf(stderr,
 | 
			
		||||
				"failed to set mode for connector %d: %m\n",
 | 
			
		||||
				output->connector_id);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void on_leave_vt(int signal_number, void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct wlsc_compositor *ec = data;
 | 
			
		||||
	struct drm_compositor *ec = data;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	ret = drmDropMaster(ec->drm_fd);
 | 
			
		||||
| 
						 | 
				
			
			@ -470,7 +552,7 @@ static void on_leave_vt(int signal_number, void *data)
 | 
			
		|||
static void
 | 
			
		||||
on_tty_input(int fd, uint32_t mask, void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct wlsc_compositor *ec = data;
 | 
			
		||||
	struct drm_compositor *ec = data;
 | 
			
		||||
 | 
			
		||||
	/* Ignore input to tty.  We get keyboard events from evdev
 | 
			
		||||
	 */
 | 
			
		||||
| 
						 | 
				
			
			@ -479,7 +561,7 @@ on_tty_input(int fd, uint32_t mask, void *data)
 | 
			
		|||
 | 
			
		||||
static void on_term_signal(int signal_number, void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct wlsc_compositor *ec = data;
 | 
			
		||||
	struct drm_compositor *ec = data;
 | 
			
		||||
 | 
			
		||||
	if (tcsetattr(ec->tty_fd, TCSANOW, &ec->terminal_attributes) < 0)
 | 
			
		||||
		fprintf(stderr, "could not restore terminal to canonical mode\n");
 | 
			
		||||
| 
						 | 
				
			
			@ -487,7 +569,7 @@ static void on_term_signal(int signal_number, void *data)
 | 
			
		|||
	exit(0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int setup_tty(struct wlsc_compositor *ec, struct wl_event_loop *loop)
 | 
			
		||||
static int setup_tty(struct drm_compositor *ec, struct wl_event_loop *loop)
 | 
			
		||||
{
 | 
			
		||||
	struct termios raw_attributes;
 | 
			
		||||
	struct vt_mode mode = { 0 };
 | 
			
		||||
| 
						 | 
				
			
			@ -536,59 +618,65 @@ static int setup_tty(struct wlsc_compositor *ec, struct wl_event_loop *loop)
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
wlsc_compositor_init_drm(struct wlsc_compositor *ec)
 | 
			
		||||
struct wlsc_compositor *
 | 
			
		||||
drm_compositor_create(struct wl_display *display)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_compositor *ec;
 | 
			
		||||
	struct udev_enumerate *e;
 | 
			
		||||
        struct udev_list_entry *entry;
 | 
			
		||||
	struct udev_device *device;
 | 
			
		||||
	const char *path;
 | 
			
		||||
	struct wlsc_input_device *input_device;
 | 
			
		||||
	struct wl_event_loop *loop;
 | 
			
		||||
 | 
			
		||||
	ec = malloc(sizeof *ec);
 | 
			
		||||
	if (ec == NULL)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	memset(ec, 0, sizeof *ec);
 | 
			
		||||
	ec->udev = udev_new();
 | 
			
		||||
	if (ec->udev == NULL) {
 | 
			
		||||
		fprintf(stderr, "failed to initialize udev context\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	input_device = wlsc_input_device_create(ec);
 | 
			
		||||
	ec->input_device = input_device;
 | 
			
		||||
 | 
			
		||||
	e = udev_enumerate_new(ec->udev);
 | 
			
		||||
	udev_enumerate_add_match_subsystem(e, "input");
 | 
			
		||||
	udev_enumerate_add_match_property(e, "WAYLAND_SEAT", "1");
 | 
			
		||||
        udev_enumerate_scan_devices(e);
 | 
			
		||||
        udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
 | 
			
		||||
		path = udev_list_entry_get_name(entry);
 | 
			
		||||
		device = udev_device_new_from_syspath(ec->udev, path);
 | 
			
		||||
		evdev_input_device_create(input_device, ec->wl_display,
 | 
			
		||||
					  udev_device_get_devnode(device));
 | 
			
		||||
	}
 | 
			
		||||
        udev_enumerate_unref(e);
 | 
			
		||||
 | 
			
		||||
	e = udev_enumerate_new(ec->udev);
 | 
			
		||||
	udev_enumerate_add_match_subsystem(e, "drm");
 | 
			
		||||
	udev_enumerate_add_match_property(e, "WAYLAND_SEAT", "1");
 | 
			
		||||
        udev_enumerate_scan_devices(e);
 | 
			
		||||
	device = NULL;
 | 
			
		||||
        udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
 | 
			
		||||
		path = udev_list_entry_get_name(entry);
 | 
			
		||||
		device = udev_device_new_from_syspath(ec->udev, path);
 | 
			
		||||
		fprintf(stderr, "creating output for %s\n", path);
 | 
			
		||||
 | 
			
		||||
		if (init_egl(ec, device) < 0) {
 | 
			
		||||
			fprintf(stderr, "failed to initialize egl\n");
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
		if (create_outputs(ec) < 0) {
 | 
			
		||||
			fprintf(stderr, "failed to create output for %s\n", path);
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
        udev_enumerate_unref(e);
 | 
			
		||||
 | 
			
		||||
	loop = wl_display_get_event_loop(ec->wl_display);
 | 
			
		||||
	setup_tty(ec, loop);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
	if (device == NULL) {
 | 
			
		||||
		fprintf(stderr, "no drm device found\n");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (init_egl(ec, device) < 0) {
 | 
			
		||||
		fprintf(stderr, "failed to initialize egl\n");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	/* Can't init base class until we have a current egl context */
 | 
			
		||||
	wlsc_compositor_init(&ec->base, display);
 | 
			
		||||
 | 
			
		||||
	if (create_outputs(ec) < 0) {
 | 
			
		||||
		fprintf(stderr, "failed to create output for %s\n", path);
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	drm_input_create(ec);
 | 
			
		||||
 | 
			
		||||
	loop = wl_display_get_event_loop(ec->base.wl_display);
 | 
			
		||||
	ec->drm_source =
 | 
			
		||||
		wl_event_loop_add_fd(loop, ec->drm_fd,
 | 
			
		||||
				     WL_EVENT_READABLE, on_drm_input, ec);
 | 
			
		||||
	setup_tty(ec, loop);
 | 
			
		||||
	ec->base.present = drm_compositor_present;
 | 
			
		||||
 | 
			
		||||
	return &ec->base;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										666
									
								
								compositor-x11.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										666
									
								
								compositor-x11.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,666 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright © 2008-2010 Kristian Høgsberg
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software Foundation,
 | 
			
		||||
 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
 | 
			
		||||
#include <xcb/xcb.h>
 | 
			
		||||
#include <xcb/dri2.h>
 | 
			
		||||
#include <xcb/xfixes.h>
 | 
			
		||||
 | 
			
		||||
#define GL_GLEXT_PROTOTYPES
 | 
			
		||||
#define EGL_EGLEXT_PROTOTYPES
 | 
			
		||||
#include <GLES2/gl2.h>
 | 
			
		||||
#include <GLES2/gl2ext.h>
 | 
			
		||||
#include <EGL/egl.h>
 | 
			
		||||
#include <EGL/eglext.h>
 | 
			
		||||
 | 
			
		||||
#include "wayland.h"
 | 
			
		||||
#include "wayland-protocol.h"
 | 
			
		||||
#include "compositor.h"
 | 
			
		||||
 | 
			
		||||
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
 | 
			
		||||
 | 
			
		||||
struct x11_compositor {
 | 
			
		||||
	struct wlsc_compositor	 base;
 | 
			
		||||
 | 
			
		||||
	xcb_connection_t	*conn;
 | 
			
		||||
	xcb_screen_t		*screen;
 | 
			
		||||
	xcb_cursor_t		 null_cursor;
 | 
			
		||||
	int			 dri2_major;
 | 
			
		||||
	int			 dri2_minor;
 | 
			
		||||
	int			 drm_fd;
 | 
			
		||||
	struct wl_event_source	*xcb_source;
 | 
			
		||||
	struct {
 | 
			
		||||
		xcb_atom_t		 wm_protocols;
 | 
			
		||||
		xcb_atom_t		 wm_normal_hints;
 | 
			
		||||
		xcb_atom_t		 wm_size_hints;
 | 
			
		||||
		xcb_atom_t		 wm_delete_window;
 | 
			
		||||
		xcb_atom_t		 net_wm_name;
 | 
			
		||||
		xcb_atom_t		 utf8_string;
 | 
			
		||||
	} atom;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct x11_output {
 | 
			
		||||
	struct wlsc_output	base;
 | 
			
		||||
 | 
			
		||||
	xcb_xfixes_region_t	region;
 | 
			
		||||
	xcb_window_t		window;
 | 
			
		||||
	GLuint			rbo;
 | 
			
		||||
	EGLImageKHR		image;
 | 
			
		||||
	xcb_rectangle_t		damage[16];
 | 
			
		||||
	int			damage_count;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct x11_input {
 | 
			
		||||
	struct wlsc_input_device base;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
x11_input_create(struct x11_compositor *c)
 | 
			
		||||
{
 | 
			
		||||
	struct x11_input *input;
 | 
			
		||||
 | 
			
		||||
	input = malloc(sizeof *input);
 | 
			
		||||
	if (input == NULL)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	memset(input, 0, sizeof *input);
 | 
			
		||||
	wlsc_input_device_init(&input->base, &c->base);
 | 
			
		||||
 | 
			
		||||
	c->base.input_device = &input->base;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
dri2_connect(struct x11_compositor *c)
 | 
			
		||||
{
 | 
			
		||||
	xcb_xfixes_query_version_reply_t *xfixes_query;
 | 
			
		||||
	xcb_xfixes_query_version_cookie_t xfixes_query_cookie;
 | 
			
		||||
	xcb_dri2_query_version_reply_t *dri2_query;
 | 
			
		||||
	xcb_dri2_query_version_cookie_t dri2_query_cookie;
 | 
			
		||||
	xcb_dri2_connect_reply_t *connect;
 | 
			
		||||
	xcb_dri2_connect_cookie_t connect_cookie;
 | 
			
		||||
	xcb_generic_error_t *error;
 | 
			
		||||
 | 
			
		||||
	xcb_prefetch_extension_data (c->conn, &xcb_xfixes_id);
 | 
			
		||||
	xcb_prefetch_extension_data (c->conn, &xcb_dri2_id);
 | 
			
		||||
 | 
			
		||||
	xfixes_query_cookie =
 | 
			
		||||
		xcb_xfixes_query_version(c->conn,
 | 
			
		||||
					 XCB_XFIXES_MAJOR_VERSION,
 | 
			
		||||
					 XCB_XFIXES_MINOR_VERSION);
 | 
			
		||||
   
 | 
			
		||||
	dri2_query_cookie =
 | 
			
		||||
		xcb_dri2_query_version (c->conn,
 | 
			
		||||
					XCB_DRI2_MAJOR_VERSION,
 | 
			
		||||
					XCB_DRI2_MINOR_VERSION);
 | 
			
		||||
 | 
			
		||||
	connect_cookie = xcb_dri2_connect_unchecked (c->conn,
 | 
			
		||||
						     c->screen->root,
 | 
			
		||||
						     XCB_DRI2_DRIVER_TYPE_DRI);
 | 
			
		||||
   
 | 
			
		||||
	xfixes_query =
 | 
			
		||||
		xcb_xfixes_query_version_reply (c->conn,
 | 
			
		||||
						xfixes_query_cookie, &error);
 | 
			
		||||
	if (xfixes_query == NULL ||
 | 
			
		||||
	    error != NULL || xfixes_query->major_version < 2) {
 | 
			
		||||
		free(error);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	free(xfixes_query);
 | 
			
		||||
 | 
			
		||||
	dri2_query =
 | 
			
		||||
		xcb_dri2_query_version_reply (c->conn,
 | 
			
		||||
					      dri2_query_cookie, &error);
 | 
			
		||||
	if (dri2_query == NULL || error != NULL) {
 | 
			
		||||
		fprintf(stderr, "DRI2: failed to query version");
 | 
			
		||||
		free(error);
 | 
			
		||||
		return EGL_FALSE;
 | 
			
		||||
	}
 | 
			
		||||
	c->dri2_major = dri2_query->major_version;
 | 
			
		||||
	c->dri2_minor = dri2_query->minor_version;
 | 
			
		||||
	free(dri2_query);
 | 
			
		||||
 | 
			
		||||
	connect = xcb_dri2_connect_reply (c->conn,
 | 
			
		||||
					  connect_cookie, NULL);
 | 
			
		||||
	if (connect == NULL ||
 | 
			
		||||
	    connect->driver_name_length + connect->device_name_length == 0) {
 | 
			
		||||
		fprintf(stderr, "DRI2: failed to authenticate");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c->base.base.device =
 | 
			
		||||
		strndup(xcb_dri2_connect_device_name (connect),
 | 
			
		||||
			xcb_dri2_connect_device_name_length (connect));
 | 
			
		||||
		   
 | 
			
		||||
	if (c->base.base.device == NULL) {
 | 
			
		||||
		free(connect);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	free(connect);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
dri2_authenticate(struct x11_compositor *c)
 | 
			
		||||
{
 | 
			
		||||
	xcb_dri2_authenticate_reply_t *authenticate;
 | 
			
		||||
	xcb_dri2_authenticate_cookie_t authenticate_cookie;
 | 
			
		||||
	drm_magic_t magic;
 | 
			
		||||
 | 
			
		||||
	if (drmGetMagic(c->drm_fd, &magic)) {
 | 
			
		||||
		fprintf(stderr, "DRI2: failed to get drm magic");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	authenticate_cookie =
 | 
			
		||||
		xcb_dri2_authenticate_unchecked(c->conn,
 | 
			
		||||
						c->screen->root, magic);
 | 
			
		||||
	authenticate =
 | 
			
		||||
		xcb_dri2_authenticate_reply(c->conn,
 | 
			
		||||
					    authenticate_cookie, NULL);
 | 
			
		||||
	if (authenticate == NULL || !authenticate->authenticated) {
 | 
			
		||||
		fprintf(stderr, "DRI2: failed to authenticate");
 | 
			
		||||
		free(authenticate);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	free(authenticate);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
x11_compositor_init_egl(struct x11_compositor *c)
 | 
			
		||||
{
 | 
			
		||||
	PFNEGLGETTYPEDDISPLAYMESA get_typed_display_mesa;
 | 
			
		||||
	EGLint major, minor, count;
 | 
			
		||||
	EGLConfig config;
 | 
			
		||||
 | 
			
		||||
	static const EGLint config_attribs[] = {
 | 
			
		||||
		EGL_SURFACE_TYPE,		0,
 | 
			
		||||
		EGL_NO_SURFACE_CAPABLE_MESA,	EGL_OPENGL_BIT,
 | 
			
		||||
		EGL_RENDERABLE_TYPE,		EGL_OPENGL_BIT,
 | 
			
		||||
		EGL_NONE
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	if (dri2_connect(c) < 0)
 | 
			
		||||
		return -1;
 | 
			
		||||
	
 | 
			
		||||
	c->drm_fd = open(c->base.base.device, O_RDWR);
 | 
			
		||||
	if (c->drm_fd == -1) {
 | 
			
		||||
		fprintf(stderr,
 | 
			
		||||
			"DRI2: could not open %s (%s)", c->base.base.device,
 | 
			
		||||
			strerror(errno));
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (dri2_authenticate(c) < 0)
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	get_typed_display_mesa =
 | 
			
		||||
		(PFNEGLGETTYPEDDISPLAYMESA)
 | 
			
		||||
		eglGetProcAddress("eglGetTypedDisplayMESA");
 | 
			
		||||
	if (get_typed_display_mesa == NULL) {
 | 
			
		||||
		fprintf(stderr, "eglGetTypedDisplayMESA() not found\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c->base.display = get_typed_display_mesa(EGL_DRM_DISPLAY_TYPE_MESA,
 | 
			
		||||
						 (void *) c->drm_fd);
 | 
			
		||||
	if (c->base.display == NULL) {
 | 
			
		||||
		fprintf(stderr, "failed to create display\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!eglInitialize(c->base.display, &major, &minor)) {
 | 
			
		||||
		fprintf(stderr, "failed to initialize display\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!eglChooseConfig(c->base.display,
 | 
			
		||||
			     config_attribs, &config, 1, &count) ||
 | 
			
		||||
	    count == 0) {
 | 
			
		||||
		fprintf(stderr, "eglChooseConfig() failed\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	eglBindAPI(EGL_OPENGL_API);
 | 
			
		||||
	c->base.context = eglCreateContext(c->base.display,
 | 
			
		||||
					   config, EGL_NO_CONTEXT, NULL);
 | 
			
		||||
	if (c->base.context == NULL) {
 | 
			
		||||
		fprintf(stderr, "failed to create context\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!eglMakeCurrent(c->base.display, EGL_NO_SURFACE,
 | 
			
		||||
			    EGL_NO_SURFACE, c->base.context)) {
 | 
			
		||||
		fprintf(stderr, "failed to make context current\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
x11_compositor_present(struct wlsc_compositor *base)
 | 
			
		||||
{
 | 
			
		||||
	struct x11_compositor *c = (struct x11_compositor *) base;
 | 
			
		||||
	struct x11_output *output;
 | 
			
		||||
	xcb_dri2_copy_region_cookie_t cookie;
 | 
			
		||||
	struct timeval tv;
 | 
			
		||||
	uint32_t msec;
 | 
			
		||||
 | 
			
		||||
	glFlush();
 | 
			
		||||
 | 
			
		||||
	wl_list_for_each(output, &c->base.output_list, base.link) {
 | 
			
		||||
		cookie = xcb_dri2_copy_region_unchecked(c->conn,
 | 
			
		||||
							output->window,
 | 
			
		||||
							output->region,
 | 
			
		||||
							XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT,
 | 
			
		||||
							XCB_DRI2_ATTACHMENT_BUFFER_BACK_LEFT);
 | 
			
		||||
		free(xcb_dri2_copy_region_reply(c->conn, cookie, NULL));
 | 
			
		||||
	}	
 | 
			
		||||
 | 
			
		||||
	gettimeofday(&tv, NULL);
 | 
			
		||||
	msec = tv.tv_sec * 1000 + tv.tv_usec / 1000;
 | 
			
		||||
	wlsc_compositor_finish_frame(&c->base, msec);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
x11_output_set_wm_protocols(struct x11_output *output)
 | 
			
		||||
{
 | 
			
		||||
	xcb_atom_t list[1];
 | 
			
		||||
	struct x11_compositor *c =
 | 
			
		||||
		(struct x11_compositor *) output->base.compositor;
 | 
			
		||||
 | 
			
		||||
	list[0] = c->atom.wm_delete_window;
 | 
			
		||||
	xcb_change_property (c->conn, 
 | 
			
		||||
			     XCB_PROP_MODE_REPLACE,
 | 
			
		||||
			     output->window,
 | 
			
		||||
			     c->atom.wm_protocols,
 | 
			
		||||
			     XCB_ATOM_ATOM,
 | 
			
		||||
			     32,
 | 
			
		||||
			     ARRAY_SIZE(list),
 | 
			
		||||
			     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
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
x11_compositor_create_output(struct x11_compositor *c, int width, int height)
 | 
			
		||||
{
 | 
			
		||||
	static const char name[] = "Wayland Compositor";
 | 
			
		||||
	struct x11_output *output;
 | 
			
		||||
	xcb_dri2_dri2_buffer_t *buffers;
 | 
			
		||||
	xcb_dri2_get_buffers_reply_t *reply;
 | 
			
		||||
	xcb_dri2_get_buffers_cookie_t cookie;
 | 
			
		||||
	xcb_screen_iterator_t iter;
 | 
			
		||||
	xcb_rectangle_t rectangle;
 | 
			
		||||
	struct wm_normal_hints normal_hints;
 | 
			
		||||
	unsigned int attachments[] =
 | 
			
		||||
		{ XCB_DRI2_ATTACHMENT_BUFFER_BACK_LEFT};
 | 
			
		||||
	uint32_t mask = XCB_CW_EVENT_MASK | XCB_CW_CURSOR;
 | 
			
		||||
	uint32_t values[2] = { 
 | 
			
		||||
		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_EXPOSURE |
 | 
			
		||||
		XCB_EVENT_MASK_STRUCTURE_NOTIFY,
 | 
			
		||||
		0
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	EGLint attribs[] = {
 | 
			
		||||
		EGL_WIDTH,		0,
 | 
			
		||||
		EGL_HEIGHT,		0,
 | 
			
		||||
		EGL_IMAGE_STRIDE_MESA,	0,
 | 
			
		||||
		EGL_IMAGE_FORMAT_MESA,	EGL_IMAGE_FORMAT_ARGB8888_MESA,
 | 
			
		||||
		EGL_NONE
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	output = malloc(sizeof *output);
 | 
			
		||||
	if (output == NULL)
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	memset(output, 0, sizeof *output);
 | 
			
		||||
	wlsc_output_init(&output->base, &c->base, 0, 0, width, height);
 | 
			
		||||
 | 
			
		||||
	values[1] = c->null_cursor;
 | 
			
		||||
	output->window = xcb_generate_id(c->conn);
 | 
			
		||||
	iter = xcb_setup_roots_iterator(xcb_get_setup(c->conn));
 | 
			
		||||
	xcb_create_window(c->conn,
 | 
			
		||||
			  XCB_COPY_FROM_PARENT,
 | 
			
		||||
			  output->window,
 | 
			
		||||
			  iter.data->root,
 | 
			
		||||
			  0, 0,
 | 
			
		||||
			  width, height,
 | 
			
		||||
			  0,
 | 
			
		||||
			  XCB_WINDOW_CLASS_INPUT_OUTPUT,
 | 
			
		||||
			  iter.data->root_visual,
 | 
			
		||||
			  mask, values);
 | 
			
		||||
 | 
			
		||||
	/* Don't resize me. */
 | 
			
		||||
	memset(&normal_hints, 0, sizeof normal_hints);
 | 
			
		||||
	normal_hints.flags =
 | 
			
		||||
		WM_NORMAL_HINTS_MAX_SIZE | WM_NORMAL_HINTS_MIN_SIZE;
 | 
			
		||||
	normal_hints.min_width = width;
 | 
			
		||||
	normal_hints.min_height = height;
 | 
			
		||||
	normal_hints.max_width = width;
 | 
			
		||||
	normal_hints.max_height = height;
 | 
			
		||||
	xcb_change_property (c->conn, XCB_PROP_MODE_REPLACE, output->window,
 | 
			
		||||
			     c->atom.wm_normal_hints,
 | 
			
		||||
			     c->atom.wm_size_hints, 32,
 | 
			
		||||
			     sizeof normal_hints / 4,
 | 
			
		||||
			     (uint8_t *) &normal_hints);
 | 
			
		||||
 | 
			
		||||
        xcb_map_window(c->conn, output->window);
 | 
			
		||||
 | 
			
		||||
	/* Set window name.  Don't bother with non-EWMH WMs. */
 | 
			
		||||
	xcb_change_property(c->conn, XCB_PROP_MODE_REPLACE, output->window,
 | 
			
		||||
			    c->atom.net_wm_name, c->atom.utf8_string, 8,
 | 
			
		||||
			    strlen(name), name);
 | 
			
		||||
 | 
			
		||||
	rectangle.x = 0;
 | 
			
		||||
	rectangle.y = 0;
 | 
			
		||||
	rectangle.width = width;
 | 
			
		||||
	rectangle.height = height;
 | 
			
		||||
	output->region = xcb_generate_id(c->conn);
 | 
			
		||||
	xcb_xfixes_create_region(c->conn, output->region, 1, &rectangle);
 | 
			
		||||
 | 
			
		||||
	xcb_dri2_create_drawable (c->conn, output->window);
 | 
			
		||||
 | 
			
		||||
	x11_output_set_wm_protocols(output);
 | 
			
		||||
 | 
			
		||||
	cookie = xcb_dri2_get_buffers_unchecked (c->conn,
 | 
			
		||||
						 output->window,
 | 
			
		||||
						 1, 1, attachments);
 | 
			
		||||
	reply = xcb_dri2_get_buffers_reply (c->conn, cookie, NULL);
 | 
			
		||||
	if (reply == NULL)
 | 
			
		||||
		return -1;
 | 
			
		||||
	buffers = xcb_dri2_get_buffers_buffers (reply);
 | 
			
		||||
	if (buffers == NULL)
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	if (reply->count != 1) {
 | 
			
		||||
		fprintf(stderr,
 | 
			
		||||
			"got wrong number of buffers (%d)\n", reply->count);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	attribs[1] = reply->width;
 | 
			
		||||
	attribs[3] = reply->height;
 | 
			
		||||
	attribs[5] = buffers[0].pitch / 4;
 | 
			
		||||
	free(reply);
 | 
			
		||||
 | 
			
		||||
	output->image =
 | 
			
		||||
		eglCreateImageKHR(c->base.display, c->base.context,
 | 
			
		||||
				  EGL_DRM_IMAGE_MESA,
 | 
			
		||||
				  (EGLClientBuffer) buffers[0].name,
 | 
			
		||||
				  attribs);
 | 
			
		||||
 | 
			
		||||
	glGenRenderbuffers(1, &output->rbo);
 | 
			
		||||
	glBindRenderbuffer(GL_RENDERBUFFER, output->rbo);
 | 
			
		||||
 | 
			
		||||
	glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER,
 | 
			
		||||
					       output->image);
 | 
			
		||||
 | 
			
		||||
	glFramebufferRenderbuffer(GL_FRAMEBUFFER,
 | 
			
		||||
				  GL_COLOR_ATTACHMENT0,
 | 
			
		||||
				  GL_RENDERBUFFER,
 | 
			
		||||
				  output->rbo);
 | 
			
		||||
 | 
			
		||||
	wl_list_insert(c->base.output_list.prev, &output->base.link);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
idle_repaint(void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct x11_output *output = data;
 | 
			
		||||
	struct x11_compositor *c =
 | 
			
		||||
		(struct x11_compositor *) output->base.compositor;
 | 
			
		||||
	xcb_xfixes_region_t region;
 | 
			
		||||
	xcb_dri2_copy_region_cookie_t cookie;
 | 
			
		||||
	
 | 
			
		||||
	if (output->damage_count <= ARRAY_SIZE(output->damage)) {
 | 
			
		||||
		region = xcb_generate_id(c->conn);
 | 
			
		||||
		xcb_xfixes_create_region(c->conn, region,
 | 
			
		||||
					 output->damage_count, output->damage);
 | 
			
		||||
	} else {
 | 
			
		||||
		region = output->region;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cookie = xcb_dri2_copy_region_unchecked(c->conn,
 | 
			
		||||
						output->window,
 | 
			
		||||
						region,
 | 
			
		||||
						XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT,
 | 
			
		||||
						XCB_DRI2_ATTACHMENT_BUFFER_BACK_LEFT);
 | 
			
		||||
 | 
			
		||||
	if (region != output->region)
 | 
			
		||||
		xcb_xfixes_destroy_region(c->conn, region);
 | 
			
		||||
 | 
			
		||||
	free(xcb_dri2_copy_region_reply(c->conn, cookie, NULL));
 | 
			
		||||
	output->damage_count = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct x11_output *
 | 
			
		||||
x11_compositor_find_output(struct x11_compositor *c, xcb_window_t window)
 | 
			
		||||
{
 | 
			
		||||
	struct x11_output *output;
 | 
			
		||||
 | 
			
		||||
	wl_list_for_each(output, &c->base.output_list, base.link) {
 | 
			
		||||
		if (output->window == window)
 | 
			
		||||
			return output;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
x11_compositor_handle_event(int fd, uint32_t mask, void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct x11_compositor *c = data;
 | 
			
		||||
	struct x11_output *output;
 | 
			
		||||
        xcb_generic_event_t *event;
 | 
			
		||||
	struct wl_event_loop *loop;
 | 
			
		||||
	xcb_client_message_event_t *client_message;
 | 
			
		||||
	xcb_motion_notify_event_t *motion_notify;
 | 
			
		||||
	xcb_key_press_event_t *key_press;
 | 
			
		||||
	xcb_button_press_event_t *button_press;
 | 
			
		||||
	xcb_expose_event_t *expose;
 | 
			
		||||
	xcb_rectangle_t *r;
 | 
			
		||||
	xcb_atom_t atom;
 | 
			
		||||
 | 
			
		||||
	loop = wl_display_get_event_loop(c->base.wl_display);
 | 
			
		||||
        while (event = xcb_poll_for_event (c->conn), event != NULL) {
 | 
			
		||||
		switch (event->response_type & ~0x80) {
 | 
			
		||||
 | 
			
		||||
		case XCB_KEY_PRESS:
 | 
			
		||||
			key_press = (xcb_key_press_event_t *) event;
 | 
			
		||||
			notify_key(c->base.input_device,
 | 
			
		||||
				   key_press->detail, 1);
 | 
			
		||||
 | 
			
		||||
			fprintf(stderr, "code %d, sequence %d\n",
 | 
			
		||||
				key_press->detail, key_press->sequence);
 | 
			
		||||
 | 
			
		||||
			break;
 | 
			
		||||
		case XCB_KEY_RELEASE:
 | 
			
		||||
			key_press = (xcb_key_press_event_t *) event;
 | 
			
		||||
			notify_key(c->base.input_device,
 | 
			
		||||
				   key_press->detail, 0);
 | 
			
		||||
			break;
 | 
			
		||||
		case XCB_BUTTON_PRESS:
 | 
			
		||||
			button_press = (xcb_button_press_event_t *) event;
 | 
			
		||||
			notify_button(c->base.input_device,
 | 
			
		||||
				      button_press->detail, 1);
 | 
			
		||||
			break;
 | 
			
		||||
		case XCB_BUTTON_RELEASE:
 | 
			
		||||
			button_press = (xcb_button_press_event_t *) event;
 | 
			
		||||
			notify_button(c->base.input_device,
 | 
			
		||||
				      button_press->detail, 0);
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case XCB_MOTION_NOTIFY:
 | 
			
		||||
			motion_notify = (xcb_motion_notify_event_t *) event;
 | 
			
		||||
			notify_motion(c->base.input_device,
 | 
			
		||||
				      motion_notify->event_x,
 | 
			
		||||
				      motion_notify->event_y);
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case XCB_EXPOSE:
 | 
			
		||||
			expose = (xcb_expose_event_t *) event;
 | 
			
		||||
			output = x11_compositor_find_output(c, expose->window);
 | 
			
		||||
			if (output->damage_count == 0)
 | 
			
		||||
				wl_event_loop_add_idle(loop,
 | 
			
		||||
						       idle_repaint, output);
 | 
			
		||||
 | 
			
		||||
			r = &output->damage[output->damage_count++];
 | 
			
		||||
			if (output->damage_count > 16)
 | 
			
		||||
				break;
 | 
			
		||||
			r->x = expose->x;
 | 
			
		||||
			r->y = expose->y;
 | 
			
		||||
			r->width = expose->width;
 | 
			
		||||
			r->height = expose->height;
 | 
			
		||||
			break;
 | 
			
		||||
		case XCB_CLIENT_MESSAGE:
 | 
			
		||||
			client_message = (xcb_client_message_event_t *) event;
 | 
			
		||||
			atom = client_message->data.data32[0];
 | 
			
		||||
			if (atom == c->atom.wm_delete_window)
 | 
			
		||||
				exit(1);
 | 
			
		||||
			break;
 | 
			
		||||
		default: 
 | 
			
		||||
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		free (event);
 | 
			
		||||
        }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define F(field) offsetof(struct x11_compositor, field)
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
x11_compositor_get_resources(struct x11_compositor *c)
 | 
			
		||||
{
 | 
			
		||||
	static const struct { const char *name; int offset; } atoms[] = {
 | 
			
		||||
		{ "WM_PROTOCOLS",	F(atom.wm_protocols) },
 | 
			
		||||
		{ "WM_NORMAL_HINTS",	F(atom.wm_normal_hints) },
 | 
			
		||||
		{ "WM_SIZE_HINTS",	F(atom.wm_size_hints) },
 | 
			
		||||
		{ "WM_DELETE_WINDOW",	F(atom.wm_delete_window) },
 | 
			
		||||
		{ "_NET_WM_NAME",	F(atom.net_wm_name) },
 | 
			
		||||
		{ "UTF8_STRING",	F(atom.utf8_string) },
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	xcb_intern_atom_cookie_t cookies[ARRAY_SIZE(atoms)];
 | 
			
		||||
	xcb_intern_atom_reply_t *reply;
 | 
			
		||||
	xcb_pixmap_t pixmap;
 | 
			
		||||
	xcb_gc_t gc;
 | 
			
		||||
	int i;
 | 
			
		||||
	uint8_t data[] = { 0, 0, 0, 0 };
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < ARRAY_SIZE(atoms); i++)
 | 
			
		||||
		cookies[i] = xcb_intern_atom (c->conn, 0,
 | 
			
		||||
					      strlen(atoms[i].name),
 | 
			
		||||
					      atoms[i].name);
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < ARRAY_SIZE(atoms); i++) {
 | 
			
		||||
		reply = xcb_intern_atom_reply (c->conn, cookies[i], NULL);
 | 
			
		||||
		*(xcb_atom_t *) ((char *) c + atoms[i].offset) = reply->atom;
 | 
			
		||||
		free(reply);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pixmap = xcb_generate_id(c->conn);
 | 
			
		||||
	gc = xcb_generate_id(c->conn);
 | 
			
		||||
	xcb_create_pixmap(c->conn, 1, pixmap, c->screen->root, 1, 1);
 | 
			
		||||
	xcb_create_gc(c->conn, gc, pixmap, 0, NULL);
 | 
			
		||||
	xcb_put_image(c->conn, XCB_IMAGE_FORMAT_XY_PIXMAP,
 | 
			
		||||
		      pixmap, gc, 1, 1, 0, 0, 0, 32, sizeof data, data);
 | 
			
		||||
	c->null_cursor = xcb_generate_id(c->conn);
 | 
			
		||||
	xcb_create_cursor (c->conn, c->null_cursor,
 | 
			
		||||
			   pixmap, pixmap, 0, 0, 0,  0, 0, 0,  1, 1);
 | 
			
		||||
	xcb_free_gc(c->conn, gc);
 | 
			
		||||
	xcb_free_pixmap(c->conn, pixmap);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct wlsc_compositor *
 | 
			
		||||
x11_compositor_create(struct wl_display *display)
 | 
			
		||||
{
 | 
			
		||||
	struct x11_compositor *c;
 | 
			
		||||
	struct wl_event_loop *loop;
 | 
			
		||||
	xcb_screen_iterator_t s;
 | 
			
		||||
 | 
			
		||||
	c = malloc(sizeof *c);
 | 
			
		||||
	if (c == NULL)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	memset(c, 0, sizeof *c);
 | 
			
		||||
	c->conn = xcb_connect(0, 0);
 | 
			
		||||
 | 
			
		||||
	if (xcb_connection_has_error(c->conn))
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	s = xcb_setup_roots_iterator(xcb_get_setup(c->conn));
 | 
			
		||||
	c->screen = s.data;
 | 
			
		||||
 | 
			
		||||
	x11_compositor_get_resources(c);
 | 
			
		||||
 | 
			
		||||
	x11_compositor_init_egl(c);
 | 
			
		||||
 | 
			
		||||
	/* Can't init base class until we have a current egl context */
 | 
			
		||||
	wlsc_compositor_init(&c->base, display);
 | 
			
		||||
 | 
			
		||||
	x11_compositor_create_output(c, 1024, 640);
 | 
			
		||||
 | 
			
		||||
	x11_input_create(c);
 | 
			
		||||
 | 
			
		||||
	loop = wl_display_get_event_loop(c->base.wl_display);
 | 
			
		||||
 | 
			
		||||
	c->xcb_source =
 | 
			
		||||
		wl_event_loop_add_fd(loop, xcb_get_file_descriptor(c->conn),
 | 
			
		||||
				     WL_EVENT_READABLE,
 | 
			
		||||
				     x11_compositor_handle_event, c);
 | 
			
		||||
 | 
			
		||||
	c->base.present = x11_compositor_present;
 | 
			
		||||
 | 
			
		||||
	return &c->base;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										108
									
								
								compositor.c
									
										
									
									
									
								
							
							
						
						
									
										108
									
								
								compositor.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -355,8 +355,6 @@ wlsc_compositor_finish_frame(struct wlsc_compositor *compositor, int msecs)
 | 
			
		|||
			      compositor->current_frame, msecs);
 | 
			
		||||
 | 
			
		||||
	wl_event_source_timer_update(compositor->timer_source, 5);
 | 
			
		||||
	compositor->repaint_on_timeout = 1;
 | 
			
		||||
 | 
			
		||||
	compositor->current_frame++;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -379,13 +377,6 @@ wlsc_output_repaint(struct wlsc_output *output)
 | 
			
		|||
 | 
			
		||||
	wl_list_for_each(eid, &ec->input_device_list, link)
 | 
			
		||||
		wlsc_surface_draw(eid->sprite, output);
 | 
			
		||||
 | 
			
		||||
	output->current ^= 1;
 | 
			
		||||
 | 
			
		||||
	glFramebufferRenderbuffer(GL_FRAMEBUFFER,
 | 
			
		||||
				  GL_COLOR_ATTACHMENT0,
 | 
			
		||||
				  GL_RENDERBUFFER,
 | 
			
		||||
				  output->rbo[output->current]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
| 
						 | 
				
			
			@ -402,7 +393,7 @@ repaint(void *data)
 | 
			
		|||
	wl_list_for_each(output, &ec->output_list, link)
 | 
			
		||||
		wlsc_output_repaint(output);
 | 
			
		||||
 | 
			
		||||
	wlsc_compositor_present_drm(ec);
 | 
			
		||||
	ec->present(ec);
 | 
			
		||||
 | 
			
		||||
	ec->repaint_needed = 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -628,9 +619,6 @@ notify_motion(struct wlsc_input_device *device, int x, int y)
 | 
			
		|||
	const int hotspot_x = 16, hotspot_y = 16;
 | 
			
		||||
	int32_t sx, sy;
 | 
			
		||||
 | 
			
		||||
	if (!ec->vt_active)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	/* FIXME: We need some multi head love here. */
 | 
			
		||||
	output = container_of(ec->output_list.next, struct wlsc_output, link);
 | 
			
		||||
	if (x < output->x)
 | 
			
		||||
| 
						 | 
				
			
			@ -668,8 +656,7 @@ notify_button(struct wlsc_input_device *device,
 | 
			
		|||
	struct wlsc_compositor *compositor = device->ec;
 | 
			
		||||
	int32_t sx, sy;
 | 
			
		||||
 | 
			
		||||
	if (!compositor->vt_active)
 | 
			
		||||
		return;
 | 
			
		||||
	fprintf(stderr, "notify button: button %d, state %d\n", button, state);
 | 
			
		||||
 | 
			
		||||
	surface = pick_surface(device, &sx, &sy);
 | 
			
		||||
	if (surface) {
 | 
			
		||||
| 
						 | 
				
			
			@ -700,9 +687,6 @@ notify_key(struct wlsc_input_device *device,
 | 
			
		|||
	uint32_t *k, *end;
 | 
			
		||||
	uint32_t modifier;
 | 
			
		||||
 | 
			
		||||
	if (!compositor->vt_active)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	switch (key | compositor->modifier_state) {
 | 
			
		||||
	case KEY_BACKSPACE | MODIFIER_CTRL | MODIFIER_ALT:
 | 
			
		||||
		kill(0, SIGTERM);
 | 
			
		||||
| 
						 | 
				
			
			@ -769,16 +753,10 @@ handle_surface_destroy(struct wlsc_listener *listener,
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct wlsc_input_device *
 | 
			
		||||
wlsc_input_device_create(struct wlsc_compositor *ec)
 | 
			
		||||
void
 | 
			
		||||
wlsc_input_device_init(struct wlsc_input_device *device,
 | 
			
		||||
		       struct wlsc_compositor *ec)
 | 
			
		||||
{
 | 
			
		||||
	struct wlsc_input_device *device;
 | 
			
		||||
 | 
			
		||||
	device = malloc(sizeof *device);
 | 
			
		||||
	if (device == NULL)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	memset(device, 0, sizeof *device);
 | 
			
		||||
	device->base.interface = &wl_input_device_interface;
 | 
			
		||||
	device->base.implementation = NULL;
 | 
			
		||||
	wl_display_add_object(ec->wl_display, &device->base);
 | 
			
		||||
| 
						 | 
				
			
			@ -786,13 +764,12 @@ wlsc_input_device_create(struct wlsc_compositor *ec)
 | 
			
		|||
	device->x = 100;
 | 
			
		||||
	device->y = 100;
 | 
			
		||||
	device->ec = ec;
 | 
			
		||||
	device->sprite = pointer_create(ec, device->x, device->y, 64, 64);
 | 
			
		||||
 | 
			
		||||
	device->listener.func = handle_surface_destroy;
 | 
			
		||||
	wl_list_insert(ec->surface_destroy_listener_list.prev,
 | 
			
		||||
		       &device->listener.link);
 | 
			
		||||
	wl_list_insert(ec->input_device_list.prev, &device->link);
 | 
			
		||||
 | 
			
		||||
	return device;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
| 
						 | 
				
			
			@ -916,18 +893,37 @@ add_visuals(struct wlsc_compositor *ec)
 | 
			
		|||
	wl_display_add_global(ec->wl_display, &ec->rgb_visual.base, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct wlsc_compositor *
 | 
			
		||||
wlsc_compositor_create(struct wl_display *display)
 | 
			
		||||
void
 | 
			
		||||
wlsc_output_init(struct wlsc_output *output, struct wlsc_compositor *c,
 | 
			
		||||
		 int x, int y, int width, int height)
 | 
			
		||||
{
 | 
			
		||||
	output->compositor = c;
 | 
			
		||||
	output->x = x;
 | 
			
		||||
	output->y = y;
 | 
			
		||||
	output->width = width;
 | 
			
		||||
	output->height = height;
 | 
			
		||||
 | 
			
		||||
	output->background =
 | 
			
		||||
		background_create(output, option_background);
 | 
			
		||||
 | 
			
		||||
	wlsc_matrix_init(&output->matrix);
 | 
			
		||||
	wlsc_matrix_translate(&output->matrix,
 | 
			
		||||
			      -output->x - output->width / 2.0,
 | 
			
		||||
			      -output->y - output->height / 2.0, 0);
 | 
			
		||||
	wlsc_matrix_scale(&output->matrix,
 | 
			
		||||
			  2.0 / output->width, 2.0 / output->height, 1);
 | 
			
		||||
 | 
			
		||||
	output->base.interface = &wl_output_interface;
 | 
			
		||||
	wl_display_add_object(c->wl_display, &output->base);
 | 
			
		||||
	wl_display_add_global(c->wl_display, &output->base,
 | 
			
		||||
			      wlsc_output_post_geometry);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
wlsc_compositor_init(struct wlsc_compositor *ec, struct wl_display *display)
 | 
			
		||||
{
 | 
			
		||||
	struct wlsc_compositor *ec;
 | 
			
		||||
	struct wl_event_loop *loop;
 | 
			
		||||
	struct wlsc_output *output;
 | 
			
		||||
 | 
			
		||||
	ec = malloc(sizeof *ec);
 | 
			
		||||
	if (ec == NULL)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	memset(ec, 0, sizeof *ec);
 | 
			
		||||
	ec->wl_display = display;
 | 
			
		||||
 | 
			
		||||
	wl_display_set_compositor(display, &ec->base, &compositor_interface); 
 | 
			
		||||
| 
						 | 
				
			
			@ -941,34 +937,6 @@ wlsc_compositor_create(struct wl_display *display)
 | 
			
		|||
 | 
			
		||||
	screenshooter_create(ec);
 | 
			
		||||
 | 
			
		||||
	if (wlsc_compositor_init_drm(ec) < 0) {
 | 
			
		||||
		fprintf(stderr, "failed to initialize devices\n");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Create the pointer and background surfaces now that we have
 | 
			
		||||
	 * a current EGL context. */
 | 
			
		||||
	ec->input_device->sprite =
 | 
			
		||||
		pointer_create(ec, 
 | 
			
		||||
			       ec->input_device->x,
 | 
			
		||||
			       ec->input_device->y, 64, 64);
 | 
			
		||||
	wl_list_for_each(output, &ec->output_list, link) {
 | 
			
		||||
		output->background = background_create(output,
 | 
			
		||||
						       option_background);
 | 
			
		||||
 | 
			
		||||
		wlsc_matrix_init(&output->matrix);
 | 
			
		||||
 | 
			
		||||
		wlsc_matrix_translate(&output->matrix,
 | 
			
		||||
				      -output->x - output->width / 2.0,
 | 
			
		||||
				      -output->y - output->height / 2.0, 0);
 | 
			
		||||
		wlsc_matrix_scale(&output->matrix,
 | 
			
		||||
				  2.0 / output->width, 2.0 / output->height, 1);
 | 
			
		||||
		output->base.interface = &wl_output_interface;
 | 
			
		||||
		wl_display_add_object(ec->wl_display, &output->base);
 | 
			
		||||
		wl_display_add_global(ec->wl_display, &output->base,
 | 
			
		||||
				      wlsc_output_post_geometry);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	glGenFramebuffers(1, &ec->fbo);
 | 
			
		||||
	glBindFramebuffer(GL_FRAMEBUFFER, ec->fbo);
 | 
			
		||||
	glActiveTexture(GL_TEXTURE0);
 | 
			
		||||
| 
						 | 
				
			
			@ -978,7 +946,7 @@ wlsc_compositor_create(struct wl_display *display)
 | 
			
		|||
	ec->timer_source = wl_event_loop_add_timer(loop, repaint, ec);
 | 
			
		||||
	wlsc_compositor_schedule_repaint(ec);
 | 
			
		||||
 | 
			
		||||
	return ec;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* The plan here is to generate a random anonymous socket name and
 | 
			
		||||
| 
						 | 
				
			
			@ -1002,7 +970,11 @@ int main(int argc, char *argv[])
 | 
			
		|||
 | 
			
		||||
	display = wl_display_create();
 | 
			
		||||
 | 
			
		||||
	ec = wlsc_compositor_create(display);
 | 
			
		||||
	if (getenv("DISPLAY"))
 | 
			
		||||
		ec = x11_compositor_create(display);
 | 
			
		||||
	else
 | 
			
		||||
		ec = drm_compositor_create(display);
 | 
			
		||||
 | 
			
		||||
	if (ec == NULL) {
 | 
			
		||||
		fprintf(stderr, "failed to create compositor\n");
 | 
			
		||||
		exit(EXIT_FAILURE);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										45
									
								
								compositor.h
									
										
									
									
									
								
							
							
						
						
									
										45
									
								
								compositor.h
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -54,15 +54,6 @@ struct wlsc_output {
 | 
			
		|||
	struct wlsc_surface *background;
 | 
			
		||||
	struct wlsc_matrix matrix;
 | 
			
		||||
	int32_t x, y, width, height;
 | 
			
		||||
 | 
			
		||||
	drmModeModeInfo mode;
 | 
			
		||||
	uint32_t crtc_id;
 | 
			
		||||
	uint32_t connector_id;
 | 
			
		||||
 | 
			
		||||
	GLuint rbo[2];
 | 
			
		||||
	uint32_t fb_id[2];
 | 
			
		||||
	EGLImageKHR image[2];
 | 
			
		||||
	uint32_t current;	
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct wlsc_input_device {
 | 
			
		||||
| 
						 | 
				
			
			@ -87,7 +78,6 @@ struct wlsc_compositor {
 | 
			
		|||
 | 
			
		||||
	EGLDisplay display;
 | 
			
		||||
	EGLContext context;
 | 
			
		||||
	int drm_fd;
 | 
			
		||||
	GLuint fbo, vbo;
 | 
			
		||||
	GLuint proj_uniform, tex_uniform;
 | 
			
		||||
	struct wl_display *wl_display;
 | 
			
		||||
| 
						 | 
				
			
			@ -101,28 +91,16 @@ struct wlsc_compositor {
 | 
			
		|||
 | 
			
		||||
	struct wl_list surface_destroy_listener_list;
 | 
			
		||||
 | 
			
		||||
	struct wl_event_source *term_signal_source;
 | 
			
		||||
 | 
			
		||||
        /* tty handling state */
 | 
			
		||||
	int tty_fd;
 | 
			
		||||
	uint32_t vt_active : 1;
 | 
			
		||||
 | 
			
		||||
	struct termios terminal_attributes;
 | 
			
		||||
	struct wl_event_source *tty_input_source;
 | 
			
		||||
	struct wl_event_source *enter_vt_source;
 | 
			
		||||
	struct wl_event_source *leave_vt_source;
 | 
			
		||||
 | 
			
		||||
	struct udev *udev;
 | 
			
		||||
 | 
			
		||||
	/* Repaint state. */
 | 
			
		||||
	struct wl_event_source *timer_source;
 | 
			
		||||
	int repaint_needed;
 | 
			
		||||
	int repaint_on_timeout;
 | 
			
		||||
	struct timespec previous_swap;
 | 
			
		||||
	uint32_t current_frame;
 | 
			
		||||
	struct wl_event_source *drm_source;
 | 
			
		||||
 | 
			
		||||
	uint32_t modifier_state;
 | 
			
		||||
 | 
			
		||||
	void (*present)(struct wlsc_compositor *c);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define MODIFIER_CTRL	(1 << 8)
 | 
			
		||||
| 
						 | 
				
			
			@ -151,15 +129,26 @@ notify_button(struct wlsc_input_device *device, int32_t button, int32_t state);
 | 
			
		|||
void
 | 
			
		||||
notify_key(struct wlsc_input_device *device, uint32_t key, uint32_t state);
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
wlsc_compositor_present_drm(struct wlsc_compositor *wlsc);
 | 
			
		||||
int
 | 
			
		||||
wlsc_compositor_init_drm(struct wlsc_compositor *ec);
 | 
			
		||||
void
 | 
			
		||||
wlsc_compositor_finish_frame(struct wlsc_compositor *compositor, int msecs);
 | 
			
		||||
struct wlsc_input_device *
 | 
			
		||||
wlsc_input_device_create(struct wlsc_compositor *ec);
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
wlsc_compositor_init(struct wlsc_compositor *ec, struct wl_display *display);
 | 
			
		||||
void
 | 
			
		||||
wlsc_output_init(struct wlsc_output *output, struct wlsc_compositor *c,
 | 
			
		||||
		 int x, int y, int width, int height);
 | 
			
		||||
void
 | 
			
		||||
wlsc_input_device_init(struct wlsc_input_device *device,
 | 
			
		||||
		       struct wlsc_compositor *ec);
 | 
			
		||||
 | 
			
		||||
struct wlsc_compositor *
 | 
			
		||||
x11_compositor_create(struct wl_display *display);
 | 
			
		||||
 | 
			
		||||
struct wlsc_compositor *
 | 
			
		||||
drm_compositor_create(struct wl_display *display);
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
screenshooter_create(struct wlsc_compositor *ec);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,7 +5,7 @@ PKG_PROG_PKG_CONFIG()
 | 
			
		|||
PKG_CHECK_MODULES(FFI, [libffi])
 | 
			
		||||
 | 
			
		||||
PKG_CHECK_MODULES(COMPOSITOR,
 | 
			
		||||
		  [egl gl libpng cairo gdk-pixbuf-2.0 libudev >= 136 libdrm >= 2.4.17])
 | 
			
		||||
		  [egl gl libpng cairo gdk-pixbuf-2.0 libudev >= 136 libdrm >= 2.4.17] xcb-dri2 xcb-xfixes)
 | 
			
		||||
PKG_CHECK_MODULES(CLIENT, [egl gl cairo-gl gdk-pixbuf-2.0 glib-2.0 gobject-2.0])
 | 
			
		||||
PKG_CHECK_MODULES(POPPLER, [poppler-glib gdk-2.0])
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -342,6 +342,7 @@ wl_event_source_idle_remove(struct wl_event_source *source)
 | 
			
		|||
		(struct wl_event_source_idle *) source;
 | 
			
		||||
 | 
			
		||||
	wl_list_remove(&idle_source->link);
 | 
			
		||||
	free(source);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue