From ed64311b6c8cddb4e1183e5598a477c47ca82650 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Fri, 14 Jan 2011 14:33:49 -0500 Subject: [PATCH 01/30] Pick up input devices of type ID_INPUT_TABLET as well --- compositor/70-wayland.rules | 1 + 1 file changed, 1 insertion(+) diff --git a/compositor/70-wayland.rules b/compositor/70-wayland.rules index 49442dee..1b7ca661 100644 --- a/compositor/70-wayland.rules +++ b/compositor/70-wayland.rules @@ -2,5 +2,6 @@ KERNEL=="event*", ENV{ID_INPUT_KEYBOARD}=="1", ENV{WAYLAND_SEAT}="1" KERNEL=="event*", ENV{ID_INPUT_MOUSE}=="1", ENV{WAYLAND_SEAT}="1" KERNEL=="event*", ENV{ID_INPUT_TOUCHPAD}=="1", ENV{WAYLAND_SEAT}="1" KERNEL=="event*", ENV{ID_INPUT_TOUCHSCREEN}=="1", ENV{WAYLAND_SEAT}="1" +KERNEL=="event*", ENV{ID_INPUT_TABLET}=="1", ENV{WAYLAND_SEAT}="1" KERNEL=="card0", ENV{WAYLAND_SEAT}="1" From 43db4015f98133687c62508180e0d8e0819bd911 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Fri, 14 Jan 2011 14:45:42 -0500 Subject: [PATCH 02/30] Split out evdev handling to its own file --- compositor/Makefile.am | 1 + compositor/compositor-drm.c | 195 +------------------------------ compositor/compositor.h | 3 + compositor/evdev.c | 223 ++++++++++++++++++++++++++++++++++++ 4 files changed, 228 insertions(+), 194 deletions(-) create mode 100644 compositor/evdev.c diff --git a/compositor/Makefile.am b/compositor/Makefile.am index 0b28cade..dca3b71c 100644 --- a/compositor/Makefile.am +++ b/compositor/Makefile.am @@ -22,6 +22,7 @@ compositor_SOURCES = \ screenshooter.c \ screenshooter-protocol.c \ screenshooter-server-protocol.h \ + evdev.c \ drm.c \ shm.c diff --git a/compositor/compositor-drm.c b/compositor/compositor-drm.c index de15bfed..42a21388 100644 --- a/compositor/compositor-drm.c +++ b/compositor/compositor-drm.c @@ -64,199 +64,6 @@ struct drm_output { uint32_t current; }; -struct drm_input { - struct wlsc_input_device base; -}; - -struct evdev_input_device { - struct drm_input *master; - struct wl_event_source *source; - int tool, new_x, new_y; - int base_x, base_y; - int fd; -}; - -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; - uint32_t time; - - c = (struct drm_compositor *) - device->master->base.input_device.compositor; - if (!c->vt_active) - return; - - dx = 0; - dy = 0; - absolute_event = 0; - x = device->master->base.input_device.x; - y = device->master->base.input_device.y; - - len = read(fd, &ev, sizeof ev); - if (len < 0 || len % sizeof e[0] != 0) { - /* FIXME: handle error... reopen device? */; - return; - } - - e = ev; - end = (void *) ev + len; - for (e = ev; e < end; e++) { - /* Get the signed value, earlier kernels had this as unsigned */ - value = e->value; - time = e->time.tv_sec * 1000 + e->time.tv_usec / 1000; - - switch (e->type) { - case EV_REL: - switch (e->code) { - case REL_X: - dx += value; - break; - - case REL_Y: - dy += value; - break; - } - break; - - case EV_ABS: - absolute_event = 1; - switch (e->code) { - case ABS_X: - if (device->new_x) { - device->base_x = x - value; - device->new_x = 0; - } - x = device->base_x + value; - break; - case ABS_Y: - if (device->new_y) { - device->base_y = y - value; - device->new_y = 0; - } - y = device->base_y + value; - break; - } - break; - - case EV_KEY: - if (value == 2) - break; - - switch (e->code) { - case BTN_TOUCH: - case BTN_TOOL_PEN: - case BTN_TOOL_RUBBER: - case BTN_TOOL_BRUSH: - case BTN_TOOL_PENCIL: - case BTN_TOOL_AIRBRUSH: - case BTN_TOOL_FINGER: - case BTN_TOOL_MOUSE: - case BTN_TOOL_LENS: - if (device->tool == 0 && value) { - device->new_x = 1; - device->new_y = 1; - } - device->tool = value ? e->code : 0; - break; - - case BTN_LEFT: - case BTN_RIGHT: - case BTN_MIDDLE: - case BTN_SIDE: - case BTN_EXTRA: - case BTN_FORWARD: - case BTN_BACK: - case BTN_TASK: - notify_button(&device->master->base.input_device, - time, e->code, value); - break; - - default: - notify_key(&device->master->base.input_device, - time, e->code, value); - break; - } - } - } - - if (dx != 0 || dy != 0) - notify_motion(&device->master->base.input_device, - time, x + dx, y + dy); - if (absolute_event && device->tool) - notify_motion(&device->master->base.input_device, time, x, y); -} - -static struct evdev_input_device * -evdev_input_device_create(struct drm_input *master, - struct wl_display *display, const char *path) -{ - struct evdev_input_device *device; - struct wl_event_loop *loop; - - device = malloc(sizeof *device); - if (device == NULL) - return NULL; - - device->tool = 1; - device->new_x = 1; - device->new_y = 1; - device->master = master; - - device->fd = open(path, O_RDONLY); - if (device->fd < 0) { - free(device); - fprintf(stderr, "couldn't create pointer for %s: %m\n", path); - return NULL; - } - - loop = wl_display_get_event_loop(display); - device->source = wl_event_loop_add_fd(loop, device->fd, - WL_EVENT_READABLE, - evdev_input_device_data, device); - if (device->source == NULL) { - close(device->fd); - free(device); - return NULL; - } - - return device; -} - -static void -drm_input_create(struct drm_compositor *c) -{ - struct drm_input *input; - struct udev_enumerate *e; - struct udev_list_entry *entry; - struct udev_device *device; - const char *path; - - 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.input_device; -} - static void drm_compositor_present(struct wlsc_compositor *ec) { @@ -683,7 +490,7 @@ drm_compositor_create(struct wl_display *display, int connector) return NULL; } - drm_input_create(ec); + evdev_input_add_devices(&ec->base, ec->udev); loop = wl_display_get_event_loop(ec->base.wl_display); ec->drm_source = diff --git a/compositor/compositor.h b/compositor/compositor.h index 99035c71..c6b9f26a 100644 --- a/compositor/compositor.h +++ b/compositor/compositor.h @@ -195,6 +195,9 @@ drm_compositor_create(struct wl_display *display, int connector); struct wlsc_compositor * wayland_compositor_create(struct wl_display *display, int width, int height); +void +evdev_input_add_devices(struct wlsc_compositor *c, struct udev *udev); + void screenshooter_create(struct wlsc_compositor *ec); diff --git a/compositor/evdev.c b/compositor/evdev.c new file mode 100644 index 00000000..2b5ab6bf --- /dev/null +++ b/compositor/evdev.c @@ -0,0 +1,223 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the copyright holders not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. The copyright holders make + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#include "compositor.h" + +struct evdev_input { + struct wlsc_input_device base; +}; + +struct evdev_input_device { + struct evdev_input *master; + struct wl_event_source *source; + int tool, new_x, new_y; + int base_x, base_y; + int fd; +}; + +static void evdev_input_device_data(int fd, uint32_t mask, void *data) +{ + struct wlsc_compositor *ec; + struct evdev_input_device *device = data; + struct input_event ev[8], *e, *end; + int len, value, dx, dy, absolute_event; + int x, y; + uint32_t time; + + ec = (struct wlsc_compositor *) + device->master->base.input_device.compositor; + if (!ec->focus) + return; + + dx = 0; + dy = 0; + absolute_event = 0; + x = device->master->base.input_device.x; + y = device->master->base.input_device.y; + + len = read(fd, &ev, sizeof ev); + if (len < 0 || len % sizeof e[0] != 0) { + /* FIXME: handle error... reopen device? */; + return; + } + + e = ev; + end = (void *) ev + len; + for (e = ev; e < end; e++) { + /* Get the signed value, earlier kernels had this as unsigned */ + value = e->value; + time = e->time.tv_sec * 1000 + e->time.tv_usec / 1000; + + switch (e->type) { + case EV_REL: + switch (e->code) { + case REL_X: + dx += value; + break; + + case REL_Y: + dy += value; + break; + } + break; + + case EV_ABS: + absolute_event = 1; + switch (e->code) { + case ABS_X: + if (device->new_x) { + device->base_x = x - value; + device->new_x = 0; + } + x = device->base_x + value; + break; + case ABS_Y: + if (device->new_y) { + device->base_y = y - value; + device->new_y = 0; + } + y = device->base_y + value; + break; + } + break; + + case EV_KEY: + if (value == 2) + break; + + switch (e->code) { + case BTN_TOUCH: + case BTN_TOOL_PEN: + case BTN_TOOL_RUBBER: + case BTN_TOOL_BRUSH: + case BTN_TOOL_PENCIL: + case BTN_TOOL_AIRBRUSH: + case BTN_TOOL_FINGER: + case BTN_TOOL_MOUSE: + case BTN_TOOL_LENS: + if (device->tool == 0 && value) { + device->new_x = 1; + device->new_y = 1; + } + device->tool = value ? e->code : 0; + break; + + case BTN_LEFT: + case BTN_RIGHT: + case BTN_MIDDLE: + case BTN_SIDE: + case BTN_EXTRA: + case BTN_FORWARD: + case BTN_BACK: + case BTN_TASK: + notify_button(&device->master->base.input_device, + time, e->code, value); + break; + + default: + notify_key(&device->master->base.input_device, + time, e->code, value); + break; + } + } + } + + if (dx != 0 || dy != 0) + notify_motion(&device->master->base.input_device, + time, x + dx, y + dy); + if (absolute_event && device->tool) + notify_motion(&device->master->base.input_device, time, x, y); +} + +static struct evdev_input_device * +evdev_input_device_create(struct evdev_input *master, + struct wl_display *display, const char *path) +{ + struct evdev_input_device *device; + struct wl_event_loop *loop; + + device = malloc(sizeof *device); + if (device == NULL) + return NULL; + + device->tool = 1; + device->new_x = 1; + device->new_y = 1; + device->master = master; + + device->fd = open(path, O_RDONLY); + if (device->fd < 0) { + free(device); + fprintf(stderr, "couldn't create pointer for %s: %m\n", path); + return NULL; + } + + loop = wl_display_get_event_loop(display); + device->source = wl_event_loop_add_fd(loop, device->fd, + WL_EVENT_READABLE, + evdev_input_device_data, device); + if (device->source == NULL) { + close(device->fd); + free(device); + return NULL; + } + + return device; +} + +void +evdev_input_add_devices(struct wlsc_compositor *c, struct udev *udev) +{ + struct evdev_input *input; + struct udev_enumerate *e; + struct udev_list_entry *entry; + struct udev_device *device; + const char *path; + + input = malloc(sizeof *input); + if (input == NULL) + return; + + memset(input, 0, sizeof *input); + wlsc_input_device_init(&input->base, c); + + e = udev_enumerate_new(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(udev, path); + evdev_input_device_create(input, c->wl_display, + udev_device_get_devnode(device)); + } + udev_enumerate_unref(e); + + c->input_device = &input->base.input_device; +} From 96c8be98a65621a4cceb8be93c2228ca0324c103 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Fri, 14 Jan 2011 14:49:46 -0500 Subject: [PATCH 03/30] Some kind of support for touchscreen --- compositor/evdev.c | 48 ++++++++++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/compositor/evdev.c b/compositor/evdev.c index 2b5ab6bf..6ff7b699 100644 --- a/compositor/evdev.c +++ b/compositor/evdev.c @@ -39,6 +39,7 @@ struct evdev_input_device { int tool, new_x, new_y; int base_x, base_y; int fd; + int min_x, max_x, min_y, max_y; }; static void evdev_input_device_data(int fd, uint32_t mask, void *data) @@ -50,6 +51,10 @@ static void evdev_input_device_data(int fd, uint32_t mask, void *data) int x, y; uint32_t time; + /* FIXME: Obviously we need to not hardcode these here, but + * instead get the values from the output it's associated with. */ + const int screen_width = 1024, screen_height = 600; + ec = (struct wlsc_compositor *) device->master->base.input_device.compositor; if (!ec->focus) @@ -88,21 +93,16 @@ static void evdev_input_device_data(int fd, uint32_t mask, void *data) break; case EV_ABS: - absolute_event = 1; switch (e->code) { case ABS_X: - if (device->new_x) { - device->base_x = x - value; - device->new_x = 0; - } - x = device->base_x + value; + absolute_event = device->tool; + x = (value - device->min_x) * screen_width / + (device->max_x - device->min_x); break; case ABS_Y: - if (device->new_y) { - device->base_y = y - value; - device->new_y = 0; - } - y = device->base_y + value; + absolute_event = device->tool; + y = (value - device->min_y) * screen_height / + (device->max_y - device->min_y); break; } break; @@ -121,10 +121,6 @@ static void evdev_input_device_data(int fd, uint32_t mask, void *data) case BTN_TOOL_FINGER: case BTN_TOOL_MOUSE: case BTN_TOOL_LENS: - if (device->tool == 0 && value) { - device->new_x = 1; - device->new_y = 1; - } device->tool = value ? e->code : 0; break; @@ -151,16 +147,21 @@ static void evdev_input_device_data(int fd, uint32_t mask, void *data) if (dx != 0 || dy != 0) notify_motion(&device->master->base.input_device, time, x + dx, y + dy); - if (absolute_event && device->tool) + if (absolute_event) notify_motion(&device->master->base.input_device, time, x, y); } +#define TEST_BIT(b, i) (b[(i) / 32] & (1 << (i & 31))) + static struct evdev_input_device * evdev_input_device_create(struct evdev_input *master, struct wl_display *display, const char *path) { struct evdev_input_device *device; struct wl_event_loop *loop; + struct input_absinfo absinfo; + uint32_t ev_bits[EV_MAX]; + uint32_t key_bits[KEY_MAX]; device = malloc(sizeof *device); if (device == NULL) @@ -178,6 +179,21 @@ evdev_input_device_create(struct evdev_input *master, return NULL; } + ioctl(device->fd, EVIOCGBIT(0, EV_MAX), ev_bits); + if (TEST_BIT(ev_bits, EV_ABS)) { + ioctl(device->fd, EVIOCGBIT(EV_ABS, EV_MAX), key_bits); + if (TEST_BIT(key_bits, ABS_X)) { + ioctl(device->fd, EVIOCGABS(ABS_X), &absinfo); + device->min_x = absinfo.minimum; + device->max_x = absinfo.maximum; + } + if (TEST_BIT(key_bits, ABS_Y)) { + ioctl(device->fd, EVIOCGABS(ABS_Y), &absinfo); + device->min_y = absinfo.minimum; + device->max_y = absinfo.maximum; + } + } + loop = wl_display_get_event_loop(display); device->source = wl_event_loop_add_fd(loop, device->fd, WL_EVENT_READABLE, From e4762a6ac1801ab1887c56e0051fa6335ba50ae2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Fri, 14 Jan 2011 14:59:13 -0500 Subject: [PATCH 04/30] Move tty and vt handling out in its own file --- compositor/Makefile.am | 1 + compositor/compositor-drm.c | 134 +---------------------------- compositor/compositor.h | 7 +- compositor/tty.c | 163 ++++++++++++++++++++++++++++++++++++ 4 files changed, 174 insertions(+), 131 deletions(-) create mode 100644 compositor/tty.c diff --git a/compositor/Makefile.am b/compositor/Makefile.am index dca3b71c..ded71e0b 100644 --- a/compositor/Makefile.am +++ b/compositor/Makefile.am @@ -22,6 +22,7 @@ compositor_SOURCES = \ screenshooter.c \ screenshooter-protocol.c \ screenshooter-server-protocol.h \ + tty.c \ evdev.c \ drm.c \ shm.c diff --git a/compositor/compositor-drm.c b/compositor/compositor-drm.c index 42a21388..a0829231 100644 --- a/compositor/compositor-drm.c +++ b/compositor/compositor-drm.c @@ -22,11 +22,6 @@ #include #include -#include -#include -#include -#include - #define GL_GLEXT_PROTOTYPES #define EGL_EGLEXT_PROTOTYPES #include @@ -42,14 +37,7 @@ struct drm_compositor { struct udev *udev; struct wl_event_source *drm_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 tty *tty; }; struct drm_output { @@ -305,118 +293,6 @@ create_outputs(struct drm_compositor *ec, int option_connector) return 0; } -static void on_enter_vt(int signal_number, void *data) -{ - struct drm_compositor *ec = data; - struct drm_output *output; - int ret; - - ret = drmSetMaster(ec->base.drm.fd); - if (ret) { - fprintf(stderr, "failed to set drm master\n"); - kill(0, SIGTERM); - return; - } - - fprintf(stderr, "enter vt\n"); - - ioctl(ec->tty_fd, VT_RELDISP, VT_ACKACQ); - ret = ioctl(ec->tty_fd, KDSETMODE, KD_GRAPHICS); - if (ret) - fprintf(stderr, "failed to set KD_GRAPHICS mode on console: %m\n"); - ec->vt_active = 1; - - wl_list_for_each(output, &ec->base.output_list, base.link) { - ret = drmModeSetCrtc(ec->base.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", - output->connector_id); - } -} - -static void on_leave_vt(int signal_number, void *data) -{ - struct drm_compositor *ec = data; - int ret; - - ret = drmDropMaster(ec->base.drm.fd); - if (ret) { - fprintf(stderr, "failed to drop drm master\n"); - kill(0, SIGTERM); - return; - } - - ioctl (ec->tty_fd, VT_RELDISP, 1); - ret = ioctl(ec->tty_fd, KDSETMODE, KD_TEXT); - if (ret) - fprintf(stderr, "failed to set KD_TEXT mode on console: %m\n"); - ec->vt_active = 0; -} - -static void -on_tty_input(int fd, uint32_t mask, void *data) -{ - struct drm_compositor *ec = data; - - /* Ignore input to tty. We get keyboard events from evdev - */ - tcflush(ec->tty_fd, TCIFLUSH); -} - -static int setup_tty(struct drm_compositor *ec, struct wl_event_loop *loop) -{ - struct termios raw_attributes; - struct vt_mode mode = { 0 }; - int ret; - - ec->tty_fd = open("/dev/tty0", O_RDWR | O_NOCTTY); - if (ec->tty_fd <= 0) { - fprintf(stderr, "failed to open active tty: %m\n"); - return -1; - } - - if (tcgetattr(ec->tty_fd, &ec->terminal_attributes) < 0) { - fprintf(stderr, "could not get terminal attributes: %m\n"); - return -1; - } - - /* Ignore control characters and disable echo */ - raw_attributes = ec->terminal_attributes; - cfmakeraw(&raw_attributes); - - /* Fix up line endings to be normal (cfmakeraw hoses them) */ - raw_attributes.c_oflag |= OPOST | OCRNL; - - if (tcsetattr(ec->tty_fd, TCSANOW, &raw_attributes) < 0) - fprintf(stderr, "could not put terminal into raw mode: %m\n"); - - ec->tty_input_source = - wl_event_loop_add_fd(loop, ec->tty_fd, - WL_EVENT_READABLE, on_tty_input, ec); - - ret = ioctl(ec->tty_fd, KDSETMODE, KD_GRAPHICS); - if (ret) - fprintf(stderr, "failed to set KD_GRAPHICS mode on tty: %m\n"); - - ec->vt_active = 1; - mode.mode = VT_PROCESS; - mode.relsig = SIGUSR1; - mode.acqsig = SIGUSR2; - if (!ioctl(ec->tty_fd, VT_SETMODE, &mode) < 0) { - fprintf(stderr, "failed to take control of vt handling\n"); - } - - ec->leave_vt_source = - wl_event_loop_add_signal(loop, SIGUSR1, on_leave_vt, ec); - ec->enter_vt_source = - wl_event_loop_add_signal(loop, SIGUSR2, on_enter_vt, ec); - - return 0; -} - static int drm_authenticate(struct wlsc_compositor *c, uint32_t id) { @@ -430,11 +306,9 @@ drm_destroy(struct wlsc_compositor *ec) { struct drm_compositor *d = (struct drm_compositor *) ec; - if (tcsetattr(d->tty_fd, TCSANOW, &d->terminal_attributes) < 0) - fprintf(stderr, - "could not restore terminal to canonical mode\n"); + tty_destroy(d->tty); - free(ec); + free(d); } struct wlsc_compositor * @@ -496,7 +370,7 @@ drm_compositor_create(struct wl_display *display, int connector) ec->drm_source = wl_event_loop_add_fd(loop, ec->base.drm.fd, WL_EVENT_READABLE, on_drm_input, ec); - setup_tty(ec, loop); + ec->tty = tty_create(&ec->base); ec->base.destroy = drm_destroy; ec->base.authenticate = drm_authenticate; ec->base.present = drm_compositor_present; diff --git a/compositor/compositor.h b/compositor/compositor.h index c6b9f26a..277f8cd3 100644 --- a/compositor/compositor.h +++ b/compositor/compositor.h @@ -19,7 +19,6 @@ #ifndef _WAYLAND_SYSTEM_COMPOSITOR_H_ #define _WAYLAND_SYSTEM_COMPOSITOR_H_ -#include #include #include #include @@ -198,6 +197,12 @@ wayland_compositor_create(struct wl_display *display, int width, int height); void evdev_input_add_devices(struct wlsc_compositor *c, struct udev *udev); +struct tty * +tty_create(struct wlsc_compositor *compositor); + +void +tty_destroy(struct tty *tty); + void screenshooter_create(struct wlsc_compositor *ec); diff --git a/compositor/tty.c b/compositor/tty.c new file mode 100644 index 00000000..70c319da --- /dev/null +++ b/compositor/tty.c @@ -0,0 +1,163 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the copyright holders not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. The copyright holders make + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "compositor.h" + +struct tty { + struct wlsc_compositor *compositor; + int fd; + struct termios terminal_attributes; + + struct wl_event_source *input_source; + struct wl_event_source *enter_vt_source; + struct wl_event_source *leave_vt_source; +}; + +static void on_enter_vt(int signal_number, void *data) +{ + struct tty *tty = data; + int ret; + + fprintf(stderr, "enter vt\n"); + + ioctl(tty->fd, VT_RELDISP, VT_ACKACQ); + ret = ioctl(tty->fd, KDSETMODE, KD_GRAPHICS); + if (ret) + fprintf(stderr, "failed to set KD_GRAPHICS mode on console: %m\n"); + tty->compositor->focus = 1; +} + +static void on_leave_vt(int signal_number, void *data) +{ + struct tty *tty = data; + int ret; + + ioctl (tty->fd, VT_RELDISP, 1); + ret = ioctl(tty->fd, KDSETMODE, KD_TEXT); + if (ret) + fprintf(stderr, + "failed to set KD_TEXT mode on console: %m\n"); + + tty->compositor->focus = 0; +} + +static void +on_tty_input(int fd, uint32_t mask, void *data) +{ + struct tty *tty = data; + + /* Ignore input to tty. We get keyboard events from evdev + */ + tcflush(tty->fd, TCIFLUSH); +} + +struct tty * +tty_create(struct wlsc_compositor *compositor) +{ + struct termios raw_attributes; + struct vt_mode mode = { 0 }; + int ret; + struct tty *tty; + struct wl_event_loop *loop; + + tty = malloc(sizeof *tty); + if (tty == NULL) + return NULL; + + memset(tty, 0, sizeof *tty); + tty->compositor = compositor; + tty->fd = open("/dev/tty0", O_RDWR | O_NOCTTY); + if (tty->fd <= 0) { + fprintf(stderr, "failed to open active tty: %m\n"); + return NULL; + } + + if (tcgetattr(tty->fd, &tty->terminal_attributes) < 0) { + fprintf(stderr, "could not get terminal attributes: %m\n"); + return NULL; + } + + /* Ignore control characters and disable echo */ + raw_attributes = tty->terminal_attributes; + cfmakeraw(&raw_attributes); + + /* Fix up line endings to be normal (cfmakeraw hoses them) */ + raw_attributes.c_oflag |= OPOST | OCRNL; + + if (tcsetattr(tty->fd, TCSANOW, &raw_attributes) < 0) + fprintf(stderr, "could not put terminal into raw mode: %m\n"); + + loop = wl_display_get_event_loop(compositor->wl_display); + tty->input_source = + wl_event_loop_add_fd(loop, tty->fd, + WL_EVENT_READABLE, on_tty_input, tty); + + ret = ioctl(tty->fd, KDSETMODE, KD_GRAPHICS); + if (ret) { + fprintf(stderr, "failed to set KD_GRAPHICS mode on tty: %m\n"); + return NULL; + } + + tty->compositor->focus = 1; + mode.mode = VT_PROCESS; + mode.relsig = SIGUSR1; + mode.acqsig = SIGUSR2; + if (!ioctl(tty->fd, VT_SETMODE, &mode) < 0) { + fprintf(stderr, "failed to take control of vt handling\n"); + return NULL; + } + + tty->leave_vt_source = + wl_event_loop_add_signal(loop, SIGUSR1, on_leave_vt, tty); + tty->enter_vt_source = + wl_event_loop_add_signal(loop, SIGUSR2, on_enter_vt, tty); + + return tty; +} + +void +tty_destroy(struct tty *tty) +{ + int ret; + + ret = ioctl(tty->fd, KDSETMODE, KD_TEXT); + if (ret) + fprintf(stderr, + "failed to set KD_GRAPHICS mode on tty: %m\n"); + + if (tcsetattr(tty->fd, TCSANOW, &tty->terminal_attributes) < 0) + fprintf(stderr, + "could not restore terminal to canonical mode\n"); + + free(tty); +} From 8525a5036243212987b48eaf354d921e1d3e528a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Fri, 14 Jan 2011 16:20:21 -0500 Subject: [PATCH 05/30] Move buffer creation and buffer details into drm.c and shm.c --- compositor/compositor-drm.c | 12 ++-- compositor/compositor-wayland.c | 14 +--- compositor/compositor-x11.c | 9 +-- compositor/compositor.c | 118 ++++++++++++++++++-------------- compositor/compositor.h | 22 +++--- compositor/drm.c | 28 ++++++-- compositor/shm.c | 6 ++ 7 files changed, 118 insertions(+), 91 deletions(-) diff --git a/compositor/compositor-drm.c b/compositor/compositor-drm.c index a0829231..6df6b34c 100644 --- a/compositor/compositor-drm.c +++ b/compositor/compositor-drm.c @@ -354,7 +354,13 @@ drm_compositor_create(struct wl_display *display, int connector) fprintf(stderr, "failed to initialize egl\n"); return NULL; } - + + ec->base.destroy = drm_destroy; + ec->base.authenticate = drm_authenticate; + ec->base.present = drm_compositor_present; + ec->base.create_buffer = wlsc_drm_buffer_create; + ec->base.focus = 1; + /* Can't init base class until we have a current egl context */ if (wlsc_compositor_init(&ec->base, display) < 0) return NULL; @@ -371,10 +377,6 @@ drm_compositor_create(struct wl_display *display, int connector) wl_event_loop_add_fd(loop, ec->base.drm.fd, WL_EVENT_READABLE, on_drm_input, ec); ec->tty = tty_create(&ec->base); - ec->base.destroy = drm_destroy; - ec->base.authenticate = drm_authenticate; - ec->base.present = drm_compositor_present; - ec->base.focus = 1; return &ec->base; } diff --git a/compositor/compositor-wayland.c b/compositor/compositor-wayland.c index a7a7874f..ed8a2bab 100644 --- a/compositor/compositor-wayland.c +++ b/compositor/compositor-wayland.c @@ -278,9 +278,7 @@ wayland_compositor_create_output(struct wayland_compositor *c, static struct wl_buffer * create_invisible_pointer(struct wayland_compositor *c) { - struct wlsc_drm_buffer *wlsc_buffer; struct wl_buffer *buffer; - int name, stride; struct wl_visual *visual; GLuint texture; const int width = 1, height = 1; @@ -294,18 +292,8 @@ create_invisible_pointer(struct wayland_compositor *c) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); visual = wl_display_get_premultiplied_argb_visual(c->parent.display); - wlsc_buffer = wlsc_drm_buffer_create(&c->base, width, height, visual); + buffer = c->base.create_buffer(&c->base, width, height, visual, data); - glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, wlsc_buffer->image); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, - GL_RGBA, GL_UNSIGNED_BYTE, data); - - eglExportDRMImageMESA(c->base.display, wlsc_buffer->image, - &name, NULL, &stride); - - buffer = wl_drm_create_buffer(c->parent.drm, name, - width, height, - stride, visual); return buffer; } diff --git a/compositor/compositor-x11.c b/compositor/compositor-x11.c index 722bd944..7e7c8ca1 100644 --- a/compositor/compositor-x11.c +++ b/compositor/compositor-x11.c @@ -676,6 +676,11 @@ x11_compositor_create(struct wl_display *display, int width, int height) if (x11_compositor_init_egl(c) < 0) return NULL; + c->base.destroy = x11_destroy; + c->base.authenticate = x11_authenticate; + c->base.present = x11_compositor_present; + c->base.create_buffer = wlsc_drm_buffer_create; + /* Can't init base class until we have a current egl context */ if (wlsc_compositor_init(&c->base, display) < 0) return NULL; @@ -693,9 +698,5 @@ x11_compositor_create(struct wl_display *display, int width, int height) WL_EVENT_READABLE, x11_compositor_handle_event, c); - c->base.destroy = x11_destroy; - c->base.authenticate = x11_authenticate; - c->base.present = x11_compositor_present; - return &c->base; } diff --git a/compositor/compositor.c b/compositor/compositor.c index 1e6f2efe..df73b60b 100644 --- a/compositor/compositor.c +++ b/compositor/compositor.c @@ -188,33 +188,76 @@ destroy_surface(struct wl_resource *resource, struct wl_client *client) wlsc_compositor_schedule_repaint(compositor); } -static int -texture_from_png(const char *filename, int width, int height) +static struct wl_buffer * +create_buffer_from_png(struct wlsc_compositor *ec, + const char *filename, int width, int height) { GdkPixbuf *pixbuf; GError *error = NULL; - void *data; - GLenum format; + int stride, i, n_channels; + unsigned char *pixels, *end, *argb_pixels, *s, *d; + struct wl_buffer *buffer; pixbuf = gdk_pixbuf_new_from_file_at_scale(filename, width, height, FALSE, &error); if (error != NULL) - return -1; + return NULL; - data = gdk_pixbuf_get_pixels(pixbuf); + stride = gdk_pixbuf_get_rowstride(pixbuf); + pixels = gdk_pixbuf_get_pixels(pixbuf); + n_channels = gdk_pixbuf_get_n_channels(pixbuf); - if (gdk_pixbuf_get_has_alpha(pixbuf)) - format = GL_RGBA; - else - format = GL_RGB; + argb_pixels = malloc (height * width * 4); + if (argb_pixels == NULL) { + gdk_pixbuf_unref(pixbuf); + return NULL; + } - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, - format, GL_UNSIGNED_BYTE, data); + if (n_channels == 4) { + for (i = 0; i < height; i++) { + s = pixels + i * stride; + end = s + width * 4; + d = argb_pixels + i * width * 4; + while (s < end) { + unsigned int t; + +#define MULT(_d,c,a,t) \ + do { t = c * a + 0x7f; _d = ((t >> 8) + t) >> 8; } while (0) + + MULT(d[0], s[2], s[3], t); + MULT(d[1], s[1], s[3], t); + MULT(d[2], s[0], s[3], t); + d[3] = s[3]; + s += 4; + d += 4; + } + } + } else if (n_channels == 3) { + for (i = 0; i < height; i++) { + s = pixels + i * stride; + end = s + width * 3; + d = argb_pixels + i * width * 4; + while (s < end) { + d[0] = s[2]; + d[1] = s[1]; + d[2] = s[0]; + d[3] = 0xff; + s += 3; + d += 4; + } + } + } gdk_pixbuf_unref(pixbuf); - return 0; + buffer = ec->create_buffer(ec, width, height, + &ec->compositor.premultiplied_argb_visual, + argb_pixels); + + free(argb_pixels); + + return buffer; } static const struct { @@ -238,25 +281,15 @@ static void create_pointer_images(struct wlsc_compositor *ec) { int i, count; - GLuint texture; const int width = 32, height = 32; - glGenTextures(1, &texture); - glBindTexture(GL_TEXTURE_2D, texture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - count = ARRAY_LENGTH(pointer_images); ec->pointer_buffers = malloc(count * sizeof *ec->pointer_buffers); for (i = 0; i < count; i++) { ec->pointer_buffers[i] = - wlsc_drm_buffer_create(ec, width, height, - &ec->compositor.argb_visual); - glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, - ec->pointer_buffers[i]->image); - texture_from_png(pointer_images[i].filename, width, height); + create_buffer_from_png(ec, + pointer_images[i].filename, + width, height); } } @@ -264,37 +297,20 @@ static struct wlsc_surface * background_create(struct wlsc_output *output, const char *filename) { struct wlsc_surface *background; - GdkPixbuf *pixbuf; - GError *error = NULL; - void *data; - GLenum format; + struct wlsc_compositor *ec = output->compositor; + struct wl_buffer *buffer; background = wlsc_surface_create(output->compositor, - &output->compositor->compositor.rgb_visual, + &ec->compositor.premultiplied_argb_visual, output->x, output->y, output->width, output->height); if (background == NULL) return NULL; - pixbuf = gdk_pixbuf_new_from_file_at_scale(filename, - output->width, - output->height, - FALSE, &error); - if (error != NULL) { - free(background); - return NULL; - } - - data = gdk_pixbuf_get_pixels(pixbuf); - - if (gdk_pixbuf_get_has_alpha(pixbuf)) - format = GL_RGBA; - else - format = GL_RGB; - - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, - output->width, output->height, 0, - format, GL_UNSIGNED_BYTE, data); + buffer = create_buffer_from_png(output->compositor, + filename, + output->width, output->height); + buffer->attach(buffer, &background->surface); return background; } @@ -500,7 +516,7 @@ wlsc_input_device_set_pointer_image(struct wlsc_input_device *device, (struct wlsc_compositor *) device->input_device.compositor; wlsc_input_device_attach(device, - &compositor->pointer_buffers[type]->buffer, + compositor->pointer_buffers[type], pointer_images[type].hotspot_x, pointer_images[type].hotspot_y); } diff --git a/compositor/compositor.h b/compositor/compositor.h index 277f8cd3..dd7f5340 100644 --- a/compositor/compositor.h +++ b/compositor/compositor.h @@ -77,21 +77,10 @@ struct wlsc_drm { char *filename; }; -struct wlsc_drm_buffer { - struct wl_buffer buffer; - EGLImageKHR image; -}; - struct wlsc_shm { struct wl_object object; }; -struct wlsc_shm_buffer { - struct wl_buffer buffer; - int32_t stride; - void *data; -}; - struct wlsc_compositor { struct wl_compositor compositor; @@ -101,7 +90,7 @@ struct wlsc_compositor { EGLContext context; GLuint fbo, vbo; GLuint proj_uniform, tex_uniform; - struct wlsc_drm_buffer **pointer_buffers; + struct wl_buffer **pointer_buffers; struct wl_display *wl_display; /* We implement the shell interface. */ @@ -125,6 +114,10 @@ struct wlsc_compositor { void (*destroy)(struct wlsc_compositor *ec); int (*authenticate)(struct wlsc_compositor *c, uint32_t id); void (*present)(struct wlsc_compositor *c); + struct wl_buffer *(*create_buffer)(struct wlsc_compositor *c, + int32_t width, int32_t height, + struct wl_visual *visual, + const void *data); }; #define MODIFIER_CTRL (1 << 8) @@ -163,9 +156,10 @@ wlsc_compositor_finish_frame(struct wlsc_compositor *compositor, int msecs); void wlsc_compositor_schedule_repaint(struct wlsc_compositor *compositor); -struct wlsc_drm_buffer * +struct wl_buffer * wlsc_drm_buffer_create(struct wlsc_compositor *ec, - int width, int height, struct wl_visual *visual); + int width, int height, + struct wl_visual *visual, const void *data); int wlsc_compositor_init(struct wlsc_compositor *ec, struct wl_display *display); diff --git a/compositor/drm.c b/compositor/drm.c index 0c3b1296..9e25d339 100644 --- a/compositor/drm.c +++ b/compositor/drm.c @@ -22,6 +22,11 @@ #include "compositor.h" +struct wlsc_drm_buffer { + struct wl_buffer buffer; + EGLImageKHR image; +}; + static void drm_authenticate(struct wl_client *client, struct wl_drm *drm_base, uint32_t id) @@ -197,12 +202,13 @@ wlsc_drm_init(struct wlsc_compositor *ec, int fd, const char *filename) return 0; } -struct wlsc_drm_buffer * -wlsc_drm_buffer_create(struct wlsc_compositor *ec, - int width, int height, struct wl_visual *visual) +struct wl_buffer * +wlsc_drm_buffer_create(struct wlsc_compositor *ec, int width, int height, + struct wl_visual *visual, const void *data) { struct wlsc_drm_buffer *buffer; EGLImageKHR image; + GLuint texture; EGLint image_attribs[] = { EGL_WIDTH, 0, @@ -222,5 +228,19 @@ wlsc_drm_buffer_create(struct wlsc_compositor *ec, buffer = wlsc_drm_buffer_create_for_image(ec, image, width, height, visual); - return buffer; + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, buffer->image); + + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, + GL_BGRA_EXT, GL_UNSIGNED_BYTE, data); + + glDeleteTextures(1, &texture); + + return &buffer->buffer; } diff --git a/compositor/shm.c b/compositor/shm.c index 52585f82..62eca2c5 100644 --- a/compositor/shm.c +++ b/compositor/shm.c @@ -24,6 +24,12 @@ #include "compositor.h" +struct wlsc_shm_buffer { + struct wl_buffer buffer; + int32_t stride; + void *data; +}; + static void destroy_buffer(struct wl_resource *resource, struct wl_client *client) { From c5d6be95304ff89db452ac48444be978bb2aa116 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Fri, 14 Jan 2011 16:22:37 -0500 Subject: [PATCH 06/30] Remove unused visual argument to wlsc_surface_create() --- compositor/compositor.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/compositor/compositor.c b/compositor/compositor.c index df73b60b..a92f7d73 100644 --- a/compositor/compositor.c +++ b/compositor/compositor.c @@ -119,7 +119,6 @@ wlsc_matrix_transform(struct wlsc_matrix *matrix, struct wlsc_vector *v) static struct wlsc_surface * wlsc_surface_create(struct wlsc_compositor *compositor, - struct wl_visual *visual, int32_t x, int32_t y, int32_t width, int32_t height) { struct wlsc_surface *surface; @@ -140,7 +139,7 @@ wlsc_surface_create(struct wlsc_compositor *compositor, glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); surface->compositor = compositor; - surface->visual = visual; + surface->visual = NULL; surface->x = x; surface->y = y; surface->width = width; @@ -297,11 +296,9 @@ static struct wlsc_surface * background_create(struct wlsc_output *output, const char *filename) { struct wlsc_surface *background; - struct wlsc_compositor *ec = output->compositor; struct wl_buffer *buffer; background = wlsc_surface_create(output->compositor, - &ec->compositor.premultiplied_argb_visual, output->x, output->y, output->width, output->height); if (background == NULL) @@ -770,7 +767,7 @@ compositor_create_surface(struct wl_client *client, struct wlsc_compositor *ec = (struct wlsc_compositor *) compositor; struct wlsc_surface *surface; - surface = wlsc_surface_create(ec, NULL, 0, 0, 0, 0); + surface = wlsc_surface_create(ec, 0, 0, 0, 0); if (surface == NULL) { wl_client_post_no_memory(client); return; @@ -1244,7 +1241,7 @@ wlsc_input_device_init(struct wlsc_input_device *device, wl_display_add_object(ec->wl_display, &device->input_device.object); wl_display_add_global(ec->wl_display, &device->input_device.object, NULL); - device->sprite = wlsc_surface_create(ec, &ec->compositor.argb_visual, + device->sprite = wlsc_surface_create(ec, device->input_device.x, device->input_device.y, 32, 32); device->hotspot_x = 16; From a9410223720329a90d1b41de2fbb6e5b1e53f5c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Fri, 14 Jan 2011 17:22:35 -0500 Subject: [PATCH 07/30] Make it possible to enable/disable the various compositors from configure --- compositor/Makefile.am | 27 ++++++++++++++++++++------- compositor/compositor.c | 16 ++++++++++++++-- configure.ac | 25 +++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 9 deletions(-) diff --git a/compositor/Makefile.am b/compositor/Makefile.am index ded71e0b..56a2e7ee 100644 --- a/compositor/Makefile.am +++ b/compositor/Makefile.am @@ -13,19 +13,32 @@ compositor_LDADD = \ $(top_builddir)/wayland/libwayland-client.la \ $(COMPOSITOR_LIBS) +if ENABLE_DRM_COMPOSITOR +drm_compositor_sources = compositor-drm.c tty.c evdev.c +drm_sources = drm.c +endif + +if ENABLE_X11_COMPOSITOR +x11_compositor_sources = compositor-x11.c +drm_sources = drm.c +endif + +if ENABLE_WAYLAND_COMPOSITOR +wayland_compositor_sources = compositor-wayland.c +drm_sources = drm.c +endif + compositor_SOURCES = \ compositor.c \ compositor.h \ - compositor-drm.c \ - compositor-x11.c \ - compositor-wayland.c \ screenshooter.c \ screenshooter-protocol.c \ screenshooter-server-protocol.h \ - tty.c \ - evdev.c \ - drm.c \ - shm.c + shm.c \ + $(drm_compositor_sources) \ + $(x11_compositor_sources) \ + $(wayland_compositor_sources) \ + $(drm_sources) udevrulesddir = $(sysconfdir)/udev/rules.d diff --git a/compositor/compositor.c b/compositor/compositor.c index a92f7d73..8659344f 100644 --- a/compositor/compositor.c +++ b/compositor/compositor.c @@ -18,6 +18,8 @@ #define _GNU_SOURCE +#include "config.h" + #include #include #include @@ -1462,12 +1464,22 @@ int main(int argc, char *argv[]) display = wl_display_create(); + ec = NULL; + +#if BUILD_WAYLAND_COMPOSITOR if (getenv("WAYLAND_DISPLAY")) ec = wayland_compositor_create(display, width, height); - else if (getenv("DISPLAY")) +#endif + +#if BUILD_X11_COMPOSITOR + if (ec == NULL && getenv("DISPLAY")) ec = x11_compositor_create(display, width, height); - else +#endif + +#if BUILD_DRM_COMPOSITOR + if (ec == NULL) ec = drm_compositor_create(display, option_connector); +#endif if (ec == NULL) { fprintf(stderr, "failed to create compositor\n"); diff --git a/configure.ac b/configure.ac index 31654a6d..e3c33361 100644 --- a/configure.ac +++ b/configure.ac @@ -29,6 +29,31 @@ PKG_CHECK_MODULES(POPPLER, [poppler-glib gdk-2.0], [have_poppler=yes], [have_poppler=no]) AM_CONDITIONAL(HAVE_POPPLER, test "x$have_poppler" = "xyes") + +AC_ARG_ENABLE(x11-compositor, [ --enable-x11-compositor],, + enable_x11_compositor=yes) +AM_CONDITIONAL(ENABLE_X11_COMPOSITOR, test x$enable_x11_compositor == xyes) +if test x$enable_x11_compositor == xyes; then + AC_DEFINE([BUILD_X11_COMPOSITOR], [1], [Build the X11 compositor]) +fi + + +AC_ARG_ENABLE(drm-compositor, [ --enable-drm-compositor]) +AM_CONDITIONAL(ENABLE_DRM_COMPOSITOR, test x$enable_drm_compositor == xyes) +if test x$enable_drm_compositor == xyes; then + AC_DEFINE([BUILD_DRM_COMPOSITOR], [1], [Build the DRM compositor]) +fi + + +AC_ARG_ENABLE(wayland-compositor, [ --enable-wayland-compositor]) +AM_CONDITIONAL(ENABLE_WAYLAND_COMPOSITOR, + test x$enable_wayland_compositor == xyes) +if test x$enable_wayland_compositor == xyes; then + AC_DEFINE([BUILD_WAYLAND_COMPOSITOR], [1], + [Build the Wayland (nested) compositor]) +fi + + PKG_CHECK_MODULES(CAIRO_GL, [cairo-gl], [have_cairo_gl=yes], [have_cairo_gl=no]) AS_IF([test "x$have_cairo_gl" = "xyes"], From 1101b63d49db538916e9e6521b6fdf08542623f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Fri, 14 Jan 2011 17:27:24 -0500 Subject: [PATCH 08/30] Both internalFormat and format should be GL_BGRA_EXT --- compositor/shm.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compositor/shm.c b/compositor/shm.c index 62eca2c5..6b96a5b6 100644 --- a/compositor/shm.c +++ b/compositor/shm.c @@ -63,8 +63,7 @@ shm_buffer_attach(struct wl_buffer *buffer_base, struct wl_surface *surface) * overwrite it.*/ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, NULL); - - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, + glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT, buffer->buffer.width, buffer->buffer.height, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, buffer->data); es->visual = buffer->buffer.visual; From d711d0cd662f0a3160b56a0a46079ca95308231a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Fri, 14 Jan 2011 17:28:21 -0500 Subject: [PATCH 09/30] Check for GL_EXT_texture_format_BGRA8888 --- compositor/compositor.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/compositor/compositor.c b/compositor/compositor.c index 8659344f..7261dc29 100644 --- a/compositor/compositor.c +++ b/compositor/compositor.c @@ -1398,6 +1398,7 @@ int wlsc_compositor_init(struct wlsc_compositor *ec, struct wl_display *display) { struct wl_event_loop *loop; + const char *extensions; ec->wl_display = display; @@ -1419,6 +1420,13 @@ wlsc_compositor_init(struct wlsc_compositor *ec, struct wl_display *display) screenshooter_create(ec); + extensions = (const char *) glGetString(GL_EXTENSIONS); + if (!strstr(extensions, "GL_EXT_texture_format_BGRA8888")) { + fprintf(stderr, + "GL_EXT_texture_format_BGRA8888 not available\n"); + return -1; + } + glGenFramebuffers(1, &ec->fbo); glBindFramebuffer(GL_FRAMEBUFFER, ec->fbo); glActiveTexture(GL_TEXTURE0); From 8def2642417740cac46cb6c9cca957239865dd97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Fri, 14 Jan 2011 17:41:33 -0500 Subject: [PATCH 10/30] Check for cairo-egl instead of just cairo-gl --- clients/gears.c | 2 +- clients/window.c | 14 +++++++------- clients/window.h | 2 +- configure.ac | 8 ++++---- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/clients/gears.c b/clients/gears.c index b8e6cca0..f2eae9c9 100644 --- a/clients/gears.c +++ b/clients/gears.c @@ -212,7 +212,7 @@ allocate_buffer(struct gears *gears) window_draw(gears->window); gears->surface[gears->current] = window_get_surface(gears->window); -#ifdef HAVE_CAIRO_GL +#ifdef HAVE_CAIRO_EGL image = display_get_image_for_drm_surface(gears->display, gears->surface[gears->current]); #else /* XXX: hack to make Wayland compile, even if this example doesn't run */ diff --git a/clients/window.c b/clients/window.c index efd8fa44..84d0418f 100644 --- a/clients/window.c +++ b/clients/window.c @@ -43,7 +43,7 @@ #include #include -#ifdef HAVE_CAIRO_GL +#ifdef HAVE_CAIRO_EGL #include #endif @@ -181,7 +181,7 @@ struct surface_data { #define MULT(_d,c,a,t) \ do { t = c * a + 0x7f; _d = ((t >> 8) + t) >> 8; } while (0) -#ifdef HAVE_CAIRO_GL +#ifdef HAVE_CAIRO_EGL struct drm_surface_data { struct surface_data data; @@ -469,7 +469,7 @@ cairo_surface_t * display_create_surface(struct display *display, struct rectangle *rectangle) { -#ifdef HAVE_CAIRO_GL +#ifdef HAVE_CAIRO_EGL if (display->drm) { return display_create_drm_surface(display, rectangle); } @@ -482,7 +482,7 @@ display_create_surface_from_file(struct display *display, const char *filename, struct rectangle *rectangle) { -#ifdef HAVE_CAIRO_GL +#ifdef HAVE_CAIRO_EGL if (display->drm) { return display_create_drm_surface_from_file(display, filename, rectangle); } @@ -536,7 +536,7 @@ display_get_pointer_surface(struct display *display, int pointer, cairo_surface_t *surface; surface = display->pointer_surfaces[pointer]; -#if HAVE_CAIRO_GL +#if HAVE_CAIRO_EGL *width = cairo_gl_surface_get_width(surface); *height = cairo_gl_surface_get_height(surface); #else @@ -630,7 +630,7 @@ window_create_surface(struct window *window) cairo_surface_t *surface; switch (window->buffer_type) { -#ifdef HAVE_CAIRO_GL +#ifdef HAVE_CAIRO_EGL case WINDOW_BUFFER_TYPE_DRM: surface = display_create_surface(window->display, &window->allocation); @@ -1439,7 +1439,7 @@ init_drm(struct display *d) return -1; } -#ifdef HAVE_CAIRO_GL +#ifdef HAVE_CAIRO_EGL d->device = cairo_egl_device_create(d->dpy, d->ctx); if (d->device == NULL) { fprintf(stderr, "failed to get cairo drm device\n"); diff --git a/clients/window.h b/clients/window.h index e775127a..2709917a 100644 --- a/clients/window.h +++ b/clients/window.h @@ -51,7 +51,7 @@ display_get_compositor(struct display *display); EGLDisplay display_get_egl_display(struct display *d); -#ifdef HAVE_CAIRO_GL +#ifdef HAVE_CAIRO_EGL EGLImageKHR display_get_image_for_drm_surface(struct display *display, cairo_surface_t *surface); diff --git a/configure.ac b/configure.ac index e3c33361..8ff535f2 100644 --- a/configure.ac +++ b/configure.ac @@ -54,10 +54,10 @@ if test x$enable_wayland_compositor == xyes; then fi -PKG_CHECK_MODULES(CAIRO_GL, [cairo-gl], - [have_cairo_gl=yes], [have_cairo_gl=no]) -AS_IF([test "x$have_cairo_gl" = "xyes"], - [AC_DEFINE([HAVE_CAIRO_GL], [1], [Have cairo-gl])]) +PKG_CHECK_MODULES(CAIRO_EGL, [cairo-egl], + [have_cairo_egl=yes], [have_cairo_egl=no]) +AS_IF([test "x$have_cairo_egl" = "xyes"], + [AC_DEFINE([HAVE_CAIRO_EGL], [1], [Have cairo-egl])]) if test $CC = gcc; then GCC_CFLAGS="-Wall -g -Wstrict-prototypes -Wmissing-prototypes -fvisibility=hidden" From ac4326884b181a4da9491f371be61f181e0a9115 Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Sat, 15 Jan 2011 00:40:00 +0100 Subject: [PATCH 11/30] connection: Write before reading connection data --- wayland/connection.c | 60 ++++++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/wayland/connection.c b/wayland/connection.c index dadf2c39..e8e8357c 100644 --- a/wayland/connection.c +++ b/wayland/connection.c @@ -251,36 +251,6 @@ wl_connection_data(struct wl_connection *connection, uint32_t mask) char cmsg[128]; int len, count, clen; - if (mask & WL_CONNECTION_READABLE) { - wl_buffer_put_iov(&connection->in, iov, &count); - - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_iov = iov; - msg.msg_iovlen = count; - msg.msg_control = cmsg; - msg.msg_controllen = sizeof cmsg; - msg.msg_flags = 0; - - do { - len = recvmsg(connection->fd, &msg, 0); - } while (len < 0 && errno == EINTR); - - if (len < 0) { - fprintf(stderr, - "read error from connection %p: %m (%d)\n", - connection, errno); - return -1; - } else if (len == 0) { - /* FIXME: Handle this better? */ - return -1; - } - - decode_cmsg(&connection->fds_in, &msg); - - connection->in.head += len; - } - if (mask & WL_CONNECTION_WRITABLE) { wl_buffer_get_iov(&connection->out, iov, &count); @@ -314,6 +284,36 @@ wl_connection_data(struct wl_connection *connection, uint32_t mask) connection->data); } + if (mask & WL_CONNECTION_READABLE) { + wl_buffer_put_iov(&connection->in, iov, &count); + + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = iov; + msg.msg_iovlen = count; + msg.msg_control = cmsg; + msg.msg_controllen = sizeof cmsg; + msg.msg_flags = 0; + + do { + len = recvmsg(connection->fd, &msg, 0); + } while (len < 0 && errno == EINTR); + + if (len < 0) { + fprintf(stderr, + "read error from connection %p: %m (%d)\n", + connection, errno); + return -1; + } else if (len == 0) { + /* FIXME: Handle this better? */ + return -1; + } + + decode_cmsg(&connection->fds_in, &msg); + + connection->in.head += len; + } + return connection->in.head - connection->in.tail; } From aabdce027f7cd9af41a20a9574b3529a337c49d0 Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Sat, 15 Jan 2011 00:40:17 +0100 Subject: [PATCH 12/30] Add a simple client --- clients/Makefile.am | 4 +- clients/simple-client.c | 389 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 392 insertions(+), 1 deletion(-) create mode 100644 clients/simple-client.c diff --git a/clients/Makefile.am b/clients/Makefile.am index 37135f28..9f9ceca7 100644 --- a/clients/Makefile.am +++ b/clients/Makefile.am @@ -7,7 +7,8 @@ noinst_PROGRAMS = \ $(poppler_programs) \ dnd \ smoke \ - resizor + resizor \ + simple-client noinst_LTLIBRARIES = libtoytoolkit.la @@ -39,6 +40,7 @@ terminal_SOURCES = terminal.c image_SOURCES = image.c dnd_SOURCES = dnd.c resizor_SOURCES = resizor.c +simple_client_SOURCES = simple-client.c BUILT_SOURCES = \ screenshooter-client-protocol.h \ diff --git a/clients/simple-client.c b/clients/simple-client.c new file mode 100644 index 00000000..91c55994 --- /dev/null +++ b/clients/simple-client.c @@ -0,0 +1,389 @@ +/* + * Copyright © 2011 Benjamin Franzke + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#define GL_GLEXT_PROTOTYPES +#define EGL_EGLEXT_PROTOTYPES +#include +#include +#include +#include + +struct display { + struct wl_display *display; + struct { + struct wl_compositor *compositor; + struct wl_drm *drm; + } interface; + struct { + EGLDisplay dpy; + EGLContext ctx; + } egl; + struct { + int fd; + const char *device_name; + bool authenticated; + } drm; + uint32_t mask; +}; + +struct window { + struct display *display; + struct { + int width, height; + } geometry; + struct { + GLuint fbo; + GLuint color_rbo; + + GLuint program; + GLuint rotation_uniform; + + GLuint pos; + GLuint col; + } gl; + struct { + struct wl_buffer *buffer; + struct wl_surface *surface; + EGLImageKHR image; + } drm_surface; +}; + +static const char *vert_shader_text = + "uniform mat4 rotation;\n" + "attribute vec4 pos;\n" + "attribute vec4 color;\n" + "varying vec4 v_color;\n" + "void main() {\n" + " gl_Position = rotation * pos;\n" + " v_color = color;\n" + "}\n"; + +static const char *frag_shader_text = + "varying vec4 v_color;\n" + "void main() {\n" + " gl_FragColor = v_color;\n" + "}\n"; + +static void +init_egl(struct display *display) +{ + EGLint major, minor; + EGLBoolean ret; + + display->egl.dpy = eglGetDRMDisplayMESA(display->drm.fd); + assert(display->egl.dpy); + + ret = eglInitialize(display->egl.dpy, &major, &minor); + assert(ret == EGL_TRUE); + ret = eglBindAPI(EGL_OPENGL_API); + assert(ret == EGL_TRUE); + + display->egl.ctx = eglCreateContext(display->egl.dpy, NULL, + EGL_NO_CONTEXT, NULL); + assert(display->egl.ctx); + ret = eglMakeCurrent(display->egl.dpy, NULL, NULL, display->egl.ctx); + assert(ret == EGL_TRUE); +} + +static GLuint +create_shader(struct window *window, const char *source, GLenum shader_type) +{ + GLuint shader; + GLint status; + + shader = glCreateShader(shader_type); + assert(shader != 0); + + glShaderSource(shader, 1, (const char **) &source, NULL); + glCompileShader(shader); + + glGetShaderiv(shader, GL_COMPILE_STATUS, &status); + if (!status) { + char log[1000]; + GLsizei len; + glGetShaderInfoLog(shader, 1000, &len, log); + fprintf(stderr, "Error: compiling %s: %*s\n", + shader_type == GL_VERTEX_SHADER ? "vertex" : "fragment", + len, log); + exit(1); + } + + return shader; +} + +static void +init_gl(struct window *window) +{ + GLfloat ar; + GLuint frag, vert; + GLint status; + + glGenFramebuffers(1, &window->gl.fbo); + glBindFramebuffer(GL_FRAMEBUFFER, window->gl.fbo); + + glGenRenderbuffers(1, &window->gl.color_rbo); + + glViewport(0, 0, window->geometry.width, window->geometry.height); + ar = (GLfloat)window->geometry.width / (GLfloat)window->geometry.height; + + frag = create_shader(window, frag_shader_text, GL_FRAGMENT_SHADER); + vert = create_shader(window, vert_shader_text, GL_VERTEX_SHADER); + + window->gl.program = glCreateProgram(); + glAttachShader(window->gl.program, frag); + glAttachShader(window->gl.program, vert); + glLinkProgram(window->gl.program); + + glGetProgramiv(window->gl.program, GL_LINK_STATUS, &status); + if (!status) { + char log[1000]; + GLsizei len; + glGetProgramInfoLog(window->gl.program, 1000, &len, log); + fprintf(stderr, "Error: linking:\n%*s\n", len, log); + exit(1); + } + + glUseProgram(window->gl.program); + + window->gl.pos = 0; + window->gl.pos = 1; + + glBindAttribLocation(window->gl.program, window->gl.pos, "pos"); + glBindAttribLocation(window->gl.program, window->gl.col, "color"); + glLinkProgram(window->gl.program); + + window->gl.rotation_uniform = + glGetUniformLocation(window->gl.program, "rotation"); +} + +static void +create_surface(struct window *window) +{ + struct display *display = window->display; + struct wl_visual *visual; + EGLint name, stride; + EGLint image_attribs[] = { + EGL_WIDTH, 0, + EGL_HEIGHT, 0, + EGL_DRM_BUFFER_FORMAT_MESA, EGL_DRM_BUFFER_FORMAT_ARGB32_MESA, + EGL_DRM_BUFFER_USE_MESA, EGL_DRM_BUFFER_USE_SCANOUT_MESA, + EGL_NONE + }; + + window->drm_surface.surface = + wl_compositor_create_surface(display->interface.compositor); + + image_attribs[1] = window->geometry.width; + image_attribs[3] = window->geometry.height; + + window->drm_surface.image = eglCreateDRMImageMESA(display->egl.dpy, + image_attribs); + eglExportDRMImageMESA(display->egl.dpy, window->drm_surface.image, + &name, NULL, &stride); + visual = wl_display_get_premultiplied_argb_visual(display->display); + + window->drm_surface.buffer = + wl_drm_create_buffer(display->interface.drm, name, + window->geometry.width, + window->geometry.height, + stride, visual); + /* Process wl_drm_create_buffer. */ + wl_display_iterate(display->display, WL_DISPLAY_WRITABLE); + + wl_surface_attach(window->drm_surface.surface, + window->drm_surface.buffer, 0, 0); + wl_surface_map_toplevel(window->drm_surface.surface); + + glBindRenderbuffer(GL_RENDERBUFFER, window->gl.color_rbo); + glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, + window->drm_surface.image); + + glFramebufferRenderbuffer(GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_RENDERBUFFER, + window->gl.color_rbo); + + assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == + GL_FRAMEBUFFER_COMPLETE); +} + +static void +redraw(void *data, uint32_t time) +{ + struct window *window = data; + static const GLfloat verts[3][2] = { + { -0.5, -0.5 }, + { 0.5, -0.5 }, + { 0, 0.5 } + }; + static const GLfloat colors[3][3] = { + { 1, 0, 0 }, + { 0, 1, 0 }, + { 0, 0, 1 } + }; + GLfloat angle; + GLfloat rotation[4][4] = { + { 1, 0, 0, 0 }, + { 0, 1, 0, 0 }, + { 0, 0, 1, 0 }, + { 0, 0, 0, 1 } + }; + static const int32_t speed_div = 5; + static uint32_t start_time = 0; + + if (start_time == 0) + start_time = time; + + angle = ((time-start_time) / speed_div) % 360 * M_PI / 180.0; + rotation[0][0] = cos(angle); + rotation[0][2] = sin(angle); + rotation[2][0] = -sin(angle); + rotation[2][2] = cos(angle); + + glUniformMatrix4fv(window->gl.rotation_uniform, 1, GL_FALSE, + (GLfloat *) rotation); + + glClearColor(0.0, 0.0, 0.0, 0.5); + glClear(GL_COLOR_BUFFER_BIT); + + glVertexAttribPointer(window->gl.pos, 2, GL_FLOAT, GL_FALSE, 0, verts); + glVertexAttribPointer(window->gl.col, 3, GL_FLOAT, GL_FALSE, 0, colors); + glEnableVertexAttribArray(window->gl.pos); + glEnableVertexAttribArray(window->gl.col); + + glDrawArrays(GL_TRIANGLES, 0, 3); + + glDisableVertexAttribArray(window->gl.pos); + glDisableVertexAttribArray(window->gl.col); + + glFlush(); + + wl_surface_damage(window->drm_surface.surface, 0, 0, + window->geometry.width, window->geometry.height); + + wl_display_frame_callback(window->display->display, redraw, window); +} + +static void +drm_handle_device(void *data, struct wl_drm *drm, const char *device) +{ + struct display *d = data; + + d->drm.device_name = strdup(device); +} + +static void +drm_handle_authenticated(void *data, struct wl_drm *drm) +{ + struct display *d = data; + + d->drm.authenticated = true; +} + +static const struct wl_drm_listener drm_listener = { + drm_handle_device, + drm_handle_authenticated +}; + +static void +display_handle_global(struct wl_display *display, uint32_t id, + const char *interface, uint32_t version, void *data) +{ + struct display *d = data; + + if (strcmp(interface, "compositor") == 0) { + d->interface.compositor = wl_compositor_create(display, id); + } else if (strcmp(interface, "drm") == 0) { + d->interface.drm = wl_drm_create(display, id); + wl_drm_add_listener(d->interface.drm, &drm_listener, d); + } +} + +static int +event_mask_update(uint32_t mask, void *data) +{ + struct display *d = data; + + d->mask = mask; + + return 0; +} + +int +main(int argc, char **argv) +{ + struct display display = { 0 }; + struct window window = { 0 }; + drm_magic_t magic; + int ret; + + memset(&display, 0, sizeof display); + memset(&window, 0, sizeof window); + + window.display = &display; + window.geometry.width = 250; + window.geometry.height = 250; + + display.display = wl_display_connect(NULL); + assert(display.display); + + wl_display_add_global_listener(display.display, + display_handle_global, &display); + /* process connection events */ + wl_display_iterate(display.display, WL_DISPLAY_READABLE); + + display.drm.fd = open(display.drm.device_name, O_RDWR); + assert(display.drm.fd >= 0); + + ret = drmGetMagic(display.drm.fd, &magic); + assert(ret == 0); + wl_drm_authenticate(display.interface.drm, magic); + wl_display_iterate(display.display, WL_DISPLAY_WRITABLE); + while (!display.drm.authenticated) + wl_display_iterate(display.display, WL_DISPLAY_READABLE); + + init_egl(&display); + init_gl(&window); + create_surface(&window); + + wl_display_frame_callback(display.display, redraw, &window); + + wl_display_get_fd(display.display, event_mask_update, &display); + while (true) + wl_display_iterate(display.display, display.mask); + + return 0; +} From a1015b9e8c135820080549006c61a8450aca688f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Fri, 14 Jan 2011 20:38:35 -0500 Subject: [PATCH 13/30] Link simple-client against libGLESv2.so, not full GL --- clients/Makefile.am | 46 ++++++++++++++++++++++++++++++--------------- configure.ac | 1 + 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/clients/Makefile.am b/clients/Makefile.am index 9f9ceca7..a259b6a6 100644 --- a/clients/Makefile.am +++ b/clients/Makefile.am @@ -12,17 +12,12 @@ noinst_PROGRAMS = \ noinst_LTLIBRARIES = libtoytoolkit.la -INCLUDES = \ - -I$(top_srcdir)/wayland \ - -I$(top_builddir)/wayland \ - $(CLIENT_CFLAGS) - -LDADD = libtoytoolkit.la \ - $(top_builddir)/wayland/libwayland-client.la \ - $(CLIENT_LIBS) -lrt -lm - AM_CFLAGS = $(GCC_CFLAGS) -AM_CPPFLAGS = -DDATADIR='"$(datadir)"' +AM_CPPFLAGS = \ + -DDATADIR='"$(datadir)"' \ + -I$(top_srcdir)/wayland \ + -I$(top_builddir)/wayland \ + $(CLIENT_CFLAGS) libtoytoolkit_la_SOURCES = \ window.c \ @@ -32,15 +27,38 @@ libtoytoolkit_la_SOURCES = \ cairo-util.c \ cairo-util.h -flower_SOURCES = flower.c -smoke_SOURCES = smoke.c +toolkit_libs = \ + libtoytoolkit.la \ + $(top_builddir)/wayland/libwayland-client.la \ + $(CLIENT_LIBS) -lrt -lm + gears_SOURCES = gears.c +gears_LDADD = $(toolkit_libs) + +flower_SOURCES = flower.c +flower_LDADD = $(toolkit_libs) + screenshot_SOURCES = screenshot.c screenshooter-protocol.c +screenshot_LDADD = $(toolkit_libs) + terminal_SOURCES = terminal.c +terminal_LDADD = $(toolkit_libs) -lutil + image_SOURCES = image.c +image_LDADD = $(toolkit_libs) + dnd_SOURCES = dnd.c +dnd_LDADD = $(toolkit_libs) + +smoke_SOURCES = smoke.c +smoke_LDADD = $(toolkit_libs) + resizor_SOURCES = resizor.c +resizor_LDADD = $(toolkit_libs) + simple_client_SOURCES = simple-client.c +simple_client_LDADD = \ + $(top_builddir)/wayland/libwayland-client.la -lm $(GLES2_LIBS) BUILT_SOURCES = \ screenshooter-client-protocol.h \ @@ -50,11 +68,9 @@ CLEANFILES = $(BUILT_SOURCES) include $(top_srcdir)/wayland/scanner.mk -terminal_LDADD = $(LDADD) -lutil - if HAVE_POPPLER poppler_programs = view view_SOURCES = view.c -view_LDADD = $(LDADD) $(POPPLER_LIBS) +view_LDADD = $(toolkit_libs) $(POPPLER_LIBS) view_CPPFLAGS = $(POPPLER_CFLAGS) endif diff --git a/configure.ac b/configure.ac index 8ff535f2..bcc1e834 100644 --- a/configure.ac +++ b/configure.ac @@ -24,6 +24,7 @@ PKG_CHECK_MODULES(FFI, [libffi]) PKG_CHECK_MODULES(COMPOSITOR, [egl glesv2 gdk-pixbuf-2.0 libudev >= 136 libdrm >= 2.4.17] xcb-dri2 xcb-xfixes) +PKG_CHECK_MODULES(GLES2, [egl glesv2 libdrm]) PKG_CHECK_MODULES(CLIENT, [egl gl cairo gdk-pixbuf-2.0 glib-2.0 gobject-2.0 xkbcommon libdrm]) PKG_CHECK_MODULES(POPPLER, [poppler-glib gdk-2.0], [have_poppler=yes], [have_poppler=no]) From 1a11fac8fa7503e3c32c4cf94b81721cb644ee02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Fri, 14 Jan 2011 20:39:21 -0500 Subject: [PATCH 14/30] simple-client: Create GLES2 context --- clients/simple-client.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/clients/simple-client.c b/clients/simple-client.c index 91c55994..0ae2924e 100644 --- a/clients/simple-client.c +++ b/clients/simple-client.c @@ -92,6 +92,7 @@ static const char *vert_shader_text = "}\n"; static const char *frag_shader_text = + "precision mediump float;\n" "varying vec4 v_color;\n" "void main() {\n" " gl_FragColor = v_color;\n" @@ -100,6 +101,11 @@ static const char *frag_shader_text = static void init_egl(struct display *display) { + static const EGLint context_attribs[] = { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE + }; + EGLint major, minor; EGLBoolean ret; @@ -108,11 +114,11 @@ init_egl(struct display *display) ret = eglInitialize(display->egl.dpy, &major, &minor); assert(ret == EGL_TRUE); - ret = eglBindAPI(EGL_OPENGL_API); + ret = eglBindAPI(EGL_OPENGL_ES_API); assert(ret == EGL_TRUE); display->egl.ctx = eglCreateContext(display->egl.dpy, NULL, - EGL_NO_CONTEXT, NULL); + EGL_NO_CONTEXT, context_attribs); assert(display->egl.ctx); ret = eglMakeCurrent(display->egl.dpy, NULL, NULL, display->egl.ctx); assert(ret == EGL_TRUE); From ad67af1bcc6537dc46bc4fd0c5cd15bf0b664b57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Fri, 14 Jan 2011 20:45:23 -0500 Subject: [PATCH 15/30] simple-client: Remove unnecessary flush --- clients/simple-client.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/clients/simple-client.c b/clients/simple-client.c index 0ae2924e..3a9b4a12 100644 --- a/clients/simple-client.c +++ b/clients/simple-client.c @@ -226,8 +226,6 @@ create_surface(struct window *window) window->geometry.width, window->geometry.height, stride, visual); - /* Process wl_drm_create_buffer. */ - wl_display_iterate(display->display, WL_DISPLAY_WRITABLE); wl_surface_attach(window->drm_surface.surface, window->drm_surface.buffer, 0, 0); From ecfb2b93f3f0a9bd79b4155acf5e8c6efc5516df Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Sat, 15 Jan 2011 12:34:48 +0100 Subject: [PATCH 16/30] compositor-wayland: Assign func pointers pre init --- compositor/compositor-wayland.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/compositor/compositor-wayland.c b/compositor/compositor-wayland.c index ed8a2bab..8a40137d 100644 --- a/compositor/compositor-wayland.c +++ b/compositor/compositor-wayland.c @@ -530,6 +530,11 @@ wayland_compositor_create(struct wl_display *display, int width, int height) if (wayland_compositor_init_egl(c) < 0) return NULL; + c->base.destroy = wayland_destroy; + c->base.authenticate = wayland_authenticate; + c->base.present = wayland_compositor_present; + c->base.create_buffer = wlsc_drm_buffer_create; + /* Can't init base class until we have a current egl context */ if (wlsc_compositor_init(&c->base, display) < 0) return NULL; @@ -549,9 +554,5 @@ wayland_compositor_create(struct wl_display *display, int width, int height) if (c->parent.wl_source == NULL) return NULL; - c->base.destroy = wayland_destroy; - c->base.authenticate = wayland_authenticate; - c->base.present = wayland_compositor_present; - return &c->base; } From d3b023ed7dbd7f2a5464121bce1ba184ee747744 Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Sat, 15 Jan 2011 12:34:49 +0100 Subject: [PATCH 17/30] compositor: Attach only valid background buffers If a background is not found, create_buffer_from_png will return NULL. Do not attach these buffers. --- compositor/compositor.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compositor/compositor.c b/compositor/compositor.c index 7261dc29..cd13e4db 100644 --- a/compositor/compositor.c +++ b/compositor/compositor.c @@ -309,6 +309,10 @@ background_create(struct wlsc_output *output, const char *filename) buffer = create_buffer_from_png(output->compositor, filename, output->width, output->height); + if (buffer == NULL) { + free(background); + return NULL; + } buffer->attach(buffer, &background->surface); return background; From 25f0ba4be1c8b12e3cac1a2bdd4bf021dd8d413c Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Sat, 15 Jan 2011 15:06:37 +0100 Subject: [PATCH 18/30] clients/Makefile: Add AM_CPPFLAGS to view's CPPFLAGS --- clients/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clients/Makefile.am b/clients/Makefile.am index a259b6a6..86a3359d 100644 --- a/clients/Makefile.am +++ b/clients/Makefile.am @@ -72,5 +72,5 @@ if HAVE_POPPLER poppler_programs = view view_SOURCES = view.c view_LDADD = $(toolkit_libs) $(POPPLER_LIBS) -view_CPPFLAGS = $(POPPLER_CFLAGS) +view_CPPFLAGS = $(AM_CPPFLAGS) $(POPPLER_CFLAGS) endif From 4cca34934998eae779e0f2b33d751759407b51e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Tue, 18 Jan 2011 07:53:49 -0500 Subject: [PATCH 19/30] Split shell object out from compositor.c into its own file --- compositor/Makefile.am | 1 + compositor/compositor.c | 454 +------------------------------------ compositor/compositor.h | 25 +++ compositor/shell.c | 479 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 511 insertions(+), 448 deletions(-) create mode 100644 compositor/shell.c diff --git a/compositor/Makefile.am b/compositor/Makefile.am index 56a2e7ee..89ea4434 100644 --- a/compositor/Makefile.am +++ b/compositor/Makefile.am @@ -31,6 +31,7 @@ endif compositor_SOURCES = \ compositor.c \ compositor.h \ + shell.c \ screenshooter.c \ screenshooter-protocol.c \ screenshooter-server-protocol.h \ diff --git a/compositor/compositor.c b/compositor/compositor.c index cd13e4db..31f70cff 100644 --- a/compositor/compositor.c +++ b/compositor/compositor.c @@ -32,7 +32,7 @@ #include #include -#include "wayland-server-protocol.h" +#include "wayland-server.h" #include "compositor.h" /* The plan here is to generate a random anonymous socket name and @@ -157,7 +157,7 @@ wlsc_surface_create(struct wlsc_compositor *compositor, return surface; } -static uint32_t +uint32_t get_time(void) { struct timeval tv; @@ -359,7 +359,7 @@ wlsc_surface_raise(struct wlsc_surface *surface) wl_list_insert(&compositor->surface_list, &surface->link); } -static void +void wlsc_surface_update_matrix(struct wlsc_surface *es) { wlsc_matrix_init(&es->matrix); @@ -511,7 +511,7 @@ wlsc_input_device_attach(struct wlsc_input_device *device, } -static void +void wlsc_input_device_set_pointer_image(struct wlsc_input_device *device, enum wlsc_pointer_type type) { @@ -524,248 +524,6 @@ wlsc_input_device_set_pointer_image(struct wlsc_input_device *device, pointer_images[type].hotspot_y); } -struct wlsc_move_grab { - struct wl_grab grab; - int32_t dx, dy; -}; - -static void -move_grab_motion(struct wl_grab *grab, - uint32_t time, int32_t x, int32_t y) -{ - struct wlsc_move_grab *move = (struct wlsc_move_grab *) grab; - struct wlsc_surface *es = - (struct wlsc_surface *) grab->input_device->pointer_focus; - - es->x = x + move->dx; - es->y = y + move->dy; - wlsc_surface_update_matrix(es); -} - -static void -move_grab_button(struct wl_grab *grab, - uint32_t time, int32_t button, int32_t state) -{ -} - -static void -move_grab_end(struct wl_grab *grab, uint32_t time) -{ - free(grab); -} - -static const struct wl_grab_interface move_grab_interface = { - move_grab_motion, - move_grab_button, - move_grab_end -}; - -static void -shell_move(struct wl_client *client, struct wl_shell *shell, - struct wl_surface *surface, - struct wl_input_device *device, uint32_t time) -{ - struct wlsc_input_device *wd = (struct wlsc_input_device *) device; - struct wlsc_surface *es = (struct wlsc_surface *) surface; - struct wlsc_move_grab *move; - - move = malloc(sizeof *move); - if (!move) { - wl_client_post_no_memory(client); - return; - } - - move->grab.interface = &move_grab_interface; - move->dx = es->x - wd->input_device.grab_x; - move->dy = es->y - wd->input_device.grab_y; - - if (wl_input_device_update_grab(&wd->input_device, - &move->grab, surface, time) < 0) - return; - - wlsc_input_device_set_pointer_image(wd, WLSC_POINTER_DRAGGING); -} - -struct wlsc_resize_grab { - struct wl_grab grab; - uint32_t edges; - int32_t dx, dy, width, height; -}; - -static void -resize_grab_motion(struct wl_grab *grab, - uint32_t time, int32_t x, int32_t y) -{ - struct wlsc_resize_grab *resize = (struct wlsc_resize_grab *) grab; - struct wl_input_device *device = grab->input_device; - struct wlsc_compositor *ec = - (struct wlsc_compositor *) device->compositor; - struct wl_surface *surface = device->pointer_focus; - int32_t width, height; - - if (resize->edges & WL_GRAB_RESIZE_LEFT) { - width = device->grab_x - x + resize->width; - } else if (resize->edges & WL_GRAB_RESIZE_RIGHT) { - width = x - device->grab_x + resize->width; - } else { - width = resize->width; - } - - if (resize->edges & WL_GRAB_RESIZE_TOP) { - height = device->grab_y - y + resize->height; - } else if (resize->edges & WL_GRAB_RESIZE_BOTTOM) { - height = y - device->grab_y + resize->height; - } else { - height = resize->height; - } - - wl_client_post_event(surface->client, &ec->shell.object, - WL_SHELL_CONFIGURE, time, resize->edges, - surface, width, height); -} - -static void -resize_grab_button(struct wl_grab *grab, - uint32_t time, int32_t button, int32_t state) -{ -} - -static void -resize_grab_end(struct wl_grab *grab, uint32_t time) -{ - free(grab); -} - -static const struct wl_grab_interface resize_grab_interface = { - resize_grab_motion, - resize_grab_button, - resize_grab_end -}; - -static void -shell_resize(struct wl_client *client, struct wl_shell *shell, - struct wl_surface *surface, - struct wl_input_device *device, uint32_t time, uint32_t edges) -{ - struct wlsc_input_device *wd = (struct wlsc_input_device *) device; - struct wlsc_resize_grab *resize; - enum wlsc_pointer_type pointer = WLSC_POINTER_LEFT_PTR; - struct wlsc_surface *es = (struct wlsc_surface *) surface; - - resize = malloc(sizeof *resize); - if (!resize) { - wl_client_post_no_memory(client); - return; - } - - resize->grab.interface = &resize_grab_interface; - resize->edges = edges; - resize->dx = es->x - wd->input_device.grab_x; - resize->dy = es->y - wd->input_device.grab_y; - resize->width = es->width; - resize->height = es->height; - - if (edges == 0 || edges > 15 || - (edges & 3) == 3 || (edges & 12) == 12) - return; - - switch (edges) { - case WL_GRAB_RESIZE_TOP: - pointer = WLSC_POINTER_TOP; - break; - case WL_GRAB_RESIZE_BOTTOM: - pointer = WLSC_POINTER_BOTTOM; - break; - case WL_GRAB_RESIZE_LEFT: - pointer = WLSC_POINTER_LEFT; - break; - case WL_GRAB_RESIZE_TOP_LEFT: - pointer = WLSC_POINTER_TOP_LEFT; - break; - case WL_GRAB_RESIZE_BOTTOM_LEFT: - pointer = WLSC_POINTER_BOTTOM_LEFT; - break; - case WL_GRAB_RESIZE_RIGHT: - pointer = WLSC_POINTER_RIGHT; - break; - case WL_GRAB_RESIZE_TOP_RIGHT: - pointer = WLSC_POINTER_TOP_RIGHT; - break; - case WL_GRAB_RESIZE_BOTTOM_RIGHT: - pointer = WLSC_POINTER_BOTTOM_RIGHT; - break; - } - - if (wl_input_device_update_grab(&wd->input_device, - &resize->grab, surface, time) < 0) - return; - - wlsc_input_device_set_pointer_image(wd, pointer); -} - -static void -wl_drag_set_pointer_focus(struct wl_drag *drag, - struct wl_surface *surface, uint32_t time, - int32_t x, int32_t y, int32_t sx, int32_t sy); - -static void -destroy_drag(struct wl_resource *resource, struct wl_client *client) -{ - struct wl_drag *drag = - container_of(resource, struct wl_drag, resource); - - wl_list_remove(&drag->drag_focus_listener.link); - if (drag->grab.input_device) - wl_input_device_end_grab(drag->grab.input_device, get_time()); - - free(drag); -} - -const static struct wl_drag_interface drag_interface; - -static void -drag_handle_surface_destroy(struct wl_listener *listener, - struct wl_surface *surface, uint32_t time) -{ - struct wl_drag *drag = - container_of(listener, struct wl_drag, drag_focus_listener); - - if (drag->drag_focus == surface) - wl_drag_set_pointer_focus(drag, NULL, time, 0, 0, 0, 0); -} - -static void -shell_create_drag(struct wl_client *client, - struct wl_shell *shell, uint32_t id) -{ - struct wl_drag *drag; - - drag = malloc(sizeof *drag); - if (drag == NULL) { - wl_client_post_no_memory(client); - return; - } - - memset(drag, 0, sizeof *drag); - drag->resource.object.id = id; - drag->resource.object.interface = &wl_drag_interface; - drag->resource.object.implementation = - (void (**)(void)) &drag_interface; - - drag->resource.destroy = destroy_drag; - - drag->drag_focus_listener.func = drag_handle_surface_destroy; - wl_list_init(&drag->drag_focus_listener.link); - - wl_client_add_resource(client, &drag->resource); -} - -const static struct wl_shell_interface shell_interface = { - shell_move, - shell_resize, - shell_create_drag -}; - static void compositor_create_surface(struct wl_client *client, struct wl_compositor *compositor, uint32_t id) @@ -805,7 +563,7 @@ wlsc_surface_transform(struct wlsc_surface *surface, *sy = v.f[1] * surface->height; } -static struct wlsc_surface * +struct wlsc_surface * pick_surface(struct wl_input_device *device, int32_t *sx, int32_t *sy) { struct wlsc_compositor *ec = @@ -1009,202 +767,6 @@ notify_key(struct wl_input_device *device, WL_INPUT_DEVICE_KEY, time, key, state); } -static void -wl_drag_set_pointer_focus(struct wl_drag *drag, - struct wl_surface *surface, uint32_t time, - int32_t x, int32_t y, int32_t sx, int32_t sy) -{ - char **p, **end; - - if (drag->drag_focus == surface) - return; - - if (drag->drag_focus && - (!surface || drag->drag_focus->client != surface->client)) - wl_client_post_event(drag->drag_focus->client, - &drag->drag_offer.object, - WL_DRAG_OFFER_POINTER_FOCUS, - time, NULL, 0, 0, 0, 0); - - if (surface && - (!drag->drag_focus || - drag->drag_focus->client != surface->client)) { - wl_client_post_global(surface->client, - &drag->drag_offer.object); - - end = drag->types.data + drag->types.size; - for (p = drag->types.data; p < end; p++) - wl_client_post_event(surface->client, - &drag->drag_offer.object, - WL_DRAG_OFFER_OFFER, *p); - } - - if (surface) { - wl_client_post_event(surface->client, - &drag->drag_offer.object, - WL_DRAG_OFFER_POINTER_FOCUS, - time, surface, - x, y, sx, sy); - - } - - drag->drag_focus = surface; - drag->pointer_focus_time = time; - drag->target = NULL; - - wl_list_remove(&drag->drag_focus_listener.link); - if (surface) - wl_list_insert(surface->destroy_listener_list.prev, - &drag->drag_focus_listener.link); -} - -static void -drag_offer_accept(struct wl_client *client, - struct wl_drag_offer *offer, uint32_t time, const char *type) -{ - struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer); - char **p, **end; - - /* If the client responds to drag pointer_focus or motion - * events after the pointer has left the surface, we just - * discard the accept requests. The drag source just won't - * get the corresponding 'target' events and eventually the - * next surface/root will start sending events. */ - if (time < drag->pointer_focus_time) - return; - - drag->target = client; - drag->type = NULL; - end = drag->types.data + drag->types.size; - for (p = drag->types.data; p < end; p++) - if (type && strcmp(*p, type) == 0) - drag->type = *p; - - wl_client_post_event(drag->source->client, &drag->resource.object, - WL_DRAG_TARGET, drag->type); -} - -static void -drag_offer_receive(struct wl_client *client, - struct wl_drag_offer *offer, int fd) -{ - struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer); - - wl_client_post_event(drag->source->client, &drag->resource.object, - WL_DRAG_FINISH, fd); - close(fd); -} - -static void -drag_offer_reject(struct wl_client *client, struct wl_drag_offer *offer) -{ - struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer); - - wl_client_post_event(drag->source->client, &drag->resource.object, - WL_DRAG_REJECT); -} - -static const struct wl_drag_offer_interface drag_offer_interface = { - drag_offer_accept, - drag_offer_receive, - drag_offer_reject -}; - -static void -drag_offer(struct wl_client *client, struct wl_drag *drag, const char *type) -{ - char **p; - - p = wl_array_add(&drag->types, sizeof *p); - if (p) - *p = strdup(type); - if (!p || !*p) - wl_client_post_no_memory(client); -} - -static void -drag_grab_motion(struct wl_grab *grab, - uint32_t time, int32_t x, int32_t y) -{ - struct wl_drag *drag = container_of(grab, struct wl_drag, grab); - struct wlsc_surface *es; - int32_t sx, sy; - - es = pick_surface(grab->input_device, &sx, &sy); - wl_drag_set_pointer_focus(drag, &es->surface, time, x, y, sx, sy); - if (es) - wl_client_post_event(es->surface.client, - &drag->drag_offer.object, - WL_DRAG_OFFER_MOTION, - time, x, y, sx, sy); -} - -static void -drag_grab_button(struct wl_grab *grab, - uint32_t time, int32_t button, int32_t state) -{ -} - -static void -drag_grab_end(struct wl_grab *grab, uint32_t time) -{ - struct wl_drag *drag = container_of(grab, struct wl_drag, grab); - - if (drag->target) - wl_client_post_event(drag->target, - &drag->drag_offer.object, - WL_DRAG_OFFER_DROP); - - wl_drag_set_pointer_focus(drag, NULL, time, 0, 0, 0, 0); -} - -static const struct wl_grab_interface drag_grab_interface = { - drag_grab_motion, - drag_grab_button, - drag_grab_end -}; - -static void -drag_activate(struct wl_client *client, - struct wl_drag *drag, - struct wl_surface *surface, - struct wl_input_device *device, uint32_t time) -{ - struct wl_display *display = wl_client_get_display (client); - struct wlsc_surface *target; - int32_t sx, sy; - - if (wl_input_device_update_grab(device, - &drag->grab, surface, time) < 0) - return; - - drag->grab.interface = &drag_grab_interface; - - drag->source = surface; - - drag->drag_offer.object.interface = &wl_drag_offer_interface; - drag->drag_offer.object.implementation = - (void (**)(void)) &drag_offer_interface; - - wl_display_add_object(display, &drag->drag_offer.object); - - target = pick_surface(device, &sx, &sy); - wl_drag_set_pointer_focus(drag, &target->surface, time, - device->x, device->y, sx, sy); -} - -static void -drag_destroy(struct wl_client *client, struct wl_drag *drag) -{ - wl_resource_destroy(&drag->resource, client); -} - -static const struct wl_drag_interface drag_interface = { - drag_offer, - drag_activate, - drag_destroy, -}; - static void input_device_attach(struct wl_client *client, struct wl_input_device *device_base, @@ -1410,11 +972,7 @@ wlsc_compositor_init(struct wlsc_compositor *ec, struct wl_display *display) wlsc_shm_init(ec); - ec->shell.object.interface = &wl_shell_interface; - ec->shell.object.implementation = (void (**)(void)) &shell_interface; - wl_display_add_object(display, &ec->shell.object); - if (wl_display_add_global(display, &ec->shell.object, NULL)) - return -1; + wlsc_shell_init(ec); wl_list_init(&ec->surface_list); wl_list_init(&ec->input_device_list); diff --git a/compositor/compositor.h b/compositor/compositor.h index dd7f5340..6ca72427 100644 --- a/compositor/compositor.h +++ b/compositor/compositor.h @@ -141,6 +141,9 @@ struct wlsc_surface { int mapped; }; +void +wlsc_surface_update_matrix(struct wlsc_surface *es); + void notify_motion(struct wl_input_device *device, uint32_t time, int x, int y); @@ -156,6 +159,15 @@ wlsc_compositor_finish_frame(struct wlsc_compositor *compositor, int msecs); void wlsc_compositor_schedule_repaint(struct wlsc_compositor *compositor); +void +wlsc_input_device_set_pointer_image(struct wlsc_input_device *device, + enum wlsc_pointer_type type); +struct wlsc_surface * +pick_surface(struct wl_input_device *device, int32_t *sx, int32_t *sy); + +uint32_t +get_time(void); + struct wl_buffer * wlsc_drm_buffer_create(struct wlsc_compositor *ec, int width, int height, @@ -175,6 +187,19 @@ wlsc_drm_init(struct wlsc_compositor *ec, int fd, const char *filename); int wlsc_shm_init(struct wlsc_compositor *ec); +int +wlsc_shell_init(struct wlsc_compositor *ec); + +void +shell_move(struct wl_client *client, struct wl_shell *shell, + struct wl_surface *surface, + struct wl_input_device *device, uint32_t time); + +void +shell_resize(struct wl_client *client, struct wl_shell *shell, + struct wl_surface *surface, + struct wl_input_device *device, uint32_t time, uint32_t edges); + struct wl_buffer * wl_buffer_create_drm(struct wlsc_compositor *compositor, struct wl_visual *visual); diff --git a/compositor/shell.c b/compositor/shell.c new file mode 100644 index 00000000..a0331e2c --- /dev/null +++ b/compositor/shell.c @@ -0,0 +1,479 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the copyright holders not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. The copyright holders make + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include "wayland-server.h" +#include "compositor.h" + +struct wlsc_move_grab { + struct wl_grab grab; + int32_t dx, dy; +}; + +static void +move_grab_motion(struct wl_grab *grab, + uint32_t time, int32_t x, int32_t y) +{ + struct wlsc_move_grab *move = (struct wlsc_move_grab *) grab; + struct wlsc_surface *es = + (struct wlsc_surface *) grab->input_device->pointer_focus; + + es->x = x + move->dx; + es->y = y + move->dy; + wlsc_surface_update_matrix(es); +} + +static void +move_grab_button(struct wl_grab *grab, + uint32_t time, int32_t button, int32_t state) +{ +} + +static void +move_grab_end(struct wl_grab *grab, uint32_t time) +{ + free(grab); +} + +static const struct wl_grab_interface move_grab_interface = { + move_grab_motion, + move_grab_button, + move_grab_end +}; + +void +shell_move(struct wl_client *client, struct wl_shell *shell, + struct wl_surface *surface, + struct wl_input_device *device, uint32_t time) +{ + struct wlsc_input_device *wd = (struct wlsc_input_device *) device; + struct wlsc_surface *es = (struct wlsc_surface *) surface; + struct wlsc_move_grab *move; + + move = malloc(sizeof *move); + if (!move) { + wl_client_post_no_memory(client); + return; + } + + move->grab.interface = &move_grab_interface; + move->dx = es->x - wd->input_device.grab_x; + move->dy = es->y - wd->input_device.grab_y; + + if (wl_input_device_update_grab(&wd->input_device, + &move->grab, surface, time) < 0) + return; + + wlsc_input_device_set_pointer_image(wd, WLSC_POINTER_DRAGGING); +} + +struct wlsc_resize_grab { + struct wl_grab grab; + uint32_t edges; + int32_t dx, dy, width, height; +}; + +static void +resize_grab_motion(struct wl_grab *grab, + uint32_t time, int32_t x, int32_t y) +{ + struct wlsc_resize_grab *resize = (struct wlsc_resize_grab *) grab; + struct wl_input_device *device = grab->input_device; + struct wlsc_compositor *ec = + (struct wlsc_compositor *) device->compositor; + struct wl_surface *surface = device->pointer_focus; + int32_t width, height; + + if (resize->edges & WL_GRAB_RESIZE_LEFT) { + width = device->grab_x - x + resize->width; + } else if (resize->edges & WL_GRAB_RESIZE_RIGHT) { + width = x - device->grab_x + resize->width; + } else { + width = resize->width; + } + + if (resize->edges & WL_GRAB_RESIZE_TOP) { + height = device->grab_y - y + resize->height; + } else if (resize->edges & WL_GRAB_RESIZE_BOTTOM) { + height = y - device->grab_y + resize->height; + } else { + height = resize->height; + } + + wl_client_post_event(surface->client, &ec->shell.object, + WL_SHELL_CONFIGURE, time, resize->edges, + surface, width, height); +} + +static void +resize_grab_button(struct wl_grab *grab, + uint32_t time, int32_t button, int32_t state) +{ +} + +static void +resize_grab_end(struct wl_grab *grab, uint32_t time) +{ + free(grab); +} + +static const struct wl_grab_interface resize_grab_interface = { + resize_grab_motion, + resize_grab_button, + resize_grab_end +}; + +void +shell_resize(struct wl_client *client, struct wl_shell *shell, + struct wl_surface *surface, + struct wl_input_device *device, uint32_t time, uint32_t edges) +{ + struct wlsc_input_device *wd = (struct wlsc_input_device *) device; + struct wlsc_resize_grab *resize; + enum wlsc_pointer_type pointer = WLSC_POINTER_LEFT_PTR; + struct wlsc_surface *es = (struct wlsc_surface *) surface; + + resize = malloc(sizeof *resize); + if (!resize) { + wl_client_post_no_memory(client); + return; + } + + resize->grab.interface = &resize_grab_interface; + resize->edges = edges; + resize->dx = es->x - wd->input_device.grab_x; + resize->dy = es->y - wd->input_device.grab_y; + resize->width = es->width; + resize->height = es->height; + + if (edges == 0 || edges > 15 || + (edges & 3) == 3 || (edges & 12) == 12) + return; + + switch (edges) { + case WL_GRAB_RESIZE_TOP: + pointer = WLSC_POINTER_TOP; + break; + case WL_GRAB_RESIZE_BOTTOM: + pointer = WLSC_POINTER_BOTTOM; + break; + case WL_GRAB_RESIZE_LEFT: + pointer = WLSC_POINTER_LEFT; + break; + case WL_GRAB_RESIZE_TOP_LEFT: + pointer = WLSC_POINTER_TOP_LEFT; + break; + case WL_GRAB_RESIZE_BOTTOM_LEFT: + pointer = WLSC_POINTER_BOTTOM_LEFT; + break; + case WL_GRAB_RESIZE_RIGHT: + pointer = WLSC_POINTER_RIGHT; + break; + case WL_GRAB_RESIZE_TOP_RIGHT: + pointer = WLSC_POINTER_TOP_RIGHT; + break; + case WL_GRAB_RESIZE_BOTTOM_RIGHT: + pointer = WLSC_POINTER_BOTTOM_RIGHT; + break; + } + + if (wl_input_device_update_grab(&wd->input_device, + &resize->grab, surface, time) < 0) + return; + + wlsc_input_device_set_pointer_image(wd, pointer); +} + +static void +wl_drag_set_pointer_focus(struct wl_drag *drag, + struct wl_surface *surface, uint32_t time, + int32_t x, int32_t y, int32_t sx, int32_t sy); + +static void +destroy_drag(struct wl_resource *resource, struct wl_client *client) +{ + struct wl_drag *drag = + container_of(resource, struct wl_drag, resource); + + wl_list_remove(&drag->drag_focus_listener.link); + if (drag->grab.input_device) + wl_input_device_end_grab(drag->grab.input_device, get_time()); + + free(drag); +} + + +static void +wl_drag_set_pointer_focus(struct wl_drag *drag, + struct wl_surface *surface, uint32_t time, + int32_t x, int32_t y, int32_t sx, int32_t sy) +{ + char **p, **end; + + if (drag->drag_focus == surface) + return; + + if (drag->drag_focus && + (!surface || drag->drag_focus->client != surface->client)) + wl_client_post_event(drag->drag_focus->client, + &drag->drag_offer.object, + WL_DRAG_OFFER_POINTER_FOCUS, + time, NULL, 0, 0, 0, 0); + + if (surface && + (!drag->drag_focus || + drag->drag_focus->client != surface->client)) { + wl_client_post_global(surface->client, + &drag->drag_offer.object); + + end = drag->types.data + drag->types.size; + for (p = drag->types.data; p < end; p++) + wl_client_post_event(surface->client, + &drag->drag_offer.object, + WL_DRAG_OFFER_OFFER, *p); + } + + if (surface) { + wl_client_post_event(surface->client, + &drag->drag_offer.object, + WL_DRAG_OFFER_POINTER_FOCUS, + time, surface, + x, y, sx, sy); + + } + + drag->drag_focus = surface; + drag->pointer_focus_time = time; + drag->target = NULL; + + wl_list_remove(&drag->drag_focus_listener.link); + if (surface) + wl_list_insert(surface->destroy_listener_list.prev, + &drag->drag_focus_listener.link); +} + +static void +drag_offer_accept(struct wl_client *client, + struct wl_drag_offer *offer, uint32_t time, const char *type) +{ + struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer); + char **p, **end; + + /* If the client responds to drag pointer_focus or motion + * events after the pointer has left the surface, we just + * discard the accept requests. The drag source just won't + * get the corresponding 'target' events and eventually the + * next surface/root will start sending events. */ + if (time < drag->pointer_focus_time) + return; + + drag->target = client; + drag->type = NULL; + end = drag->types.data + drag->types.size; + for (p = drag->types.data; p < end; p++) + if (type && strcmp(*p, type) == 0) + drag->type = *p; + + wl_client_post_event(drag->source->client, &drag->resource.object, + WL_DRAG_TARGET, drag->type); +} + +static void +drag_offer_receive(struct wl_client *client, + struct wl_drag_offer *offer, int fd) +{ + struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer); + + wl_client_post_event(drag->source->client, &drag->resource.object, + WL_DRAG_FINISH, fd); + close(fd); +} + +static void +drag_offer_reject(struct wl_client *client, struct wl_drag_offer *offer) +{ + struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer); + + wl_client_post_event(drag->source->client, &drag->resource.object, + WL_DRAG_REJECT); +} + +static const struct wl_drag_offer_interface drag_offer_interface = { + drag_offer_accept, + drag_offer_receive, + drag_offer_reject +}; + +static void +drag_offer(struct wl_client *client, struct wl_drag *drag, const char *type) +{ + char **p; + + p = wl_array_add(&drag->types, sizeof *p); + if (p) + *p = strdup(type); + if (!p || !*p) + wl_client_post_no_memory(client); +} + +static void +drag_grab_motion(struct wl_grab *grab, + uint32_t time, int32_t x, int32_t y) +{ + struct wl_drag *drag = container_of(grab, struct wl_drag, grab); + struct wlsc_surface *es; + int32_t sx, sy; + + es = pick_surface(grab->input_device, &sx, &sy); + wl_drag_set_pointer_focus(drag, &es->surface, time, x, y, sx, sy); + if (es) + wl_client_post_event(es->surface.client, + &drag->drag_offer.object, + WL_DRAG_OFFER_MOTION, + time, x, y, sx, sy); +} + +static void +drag_grab_button(struct wl_grab *grab, + uint32_t time, int32_t button, int32_t state) +{ +} + +static void +drag_grab_end(struct wl_grab *grab, uint32_t time) +{ + struct wl_drag *drag = container_of(grab, struct wl_drag, grab); + + if (drag->target) + wl_client_post_event(drag->target, + &drag->drag_offer.object, + WL_DRAG_OFFER_DROP); + + wl_drag_set_pointer_focus(drag, NULL, time, 0, 0, 0, 0); +} + +static const struct wl_grab_interface drag_grab_interface = { + drag_grab_motion, + drag_grab_button, + drag_grab_end +}; + +static void +drag_activate(struct wl_client *client, + struct wl_drag *drag, + struct wl_surface *surface, + struct wl_input_device *device, uint32_t time) +{ + struct wl_display *display = wl_client_get_display (client); + struct wlsc_surface *target; + int32_t sx, sy; + + if (wl_input_device_update_grab(device, + &drag->grab, surface, time) < 0) + return; + + drag->grab.interface = &drag_grab_interface; + + drag->source = surface; + + drag->drag_offer.object.interface = &wl_drag_offer_interface; + drag->drag_offer.object.implementation = + (void (**)(void)) &drag_offer_interface; + + wl_display_add_object(display, &drag->drag_offer.object); + + target = pick_surface(device, &sx, &sy); + wl_drag_set_pointer_focus(drag, &target->surface, time, + device->x, device->y, sx, sy); +} + +static void +drag_destroy(struct wl_client *client, struct wl_drag *drag) +{ + wl_resource_destroy(&drag->resource, client); +} + +static const struct wl_drag_interface drag_interface = { + drag_offer, + drag_activate, + drag_destroy, +}; + +static void +drag_handle_surface_destroy(struct wl_listener *listener, + struct wl_surface *surface, uint32_t time) +{ + struct wl_drag *drag = + container_of(listener, struct wl_drag, drag_focus_listener); + + if (drag->drag_focus == surface) + wl_drag_set_pointer_focus(drag, NULL, time, 0, 0, 0, 0); +} + +static void +shell_create_drag(struct wl_client *client, + struct wl_shell *shell, uint32_t id) +{ + struct wl_drag *drag; + + drag = malloc(sizeof *drag); + if (drag == NULL) { + wl_client_post_no_memory(client); + return; + } + + memset(drag, 0, sizeof *drag); + drag->resource.object.id = id; + drag->resource.object.interface = &wl_drag_interface; + drag->resource.object.implementation = + (void (**)(void)) &drag_interface; + + drag->resource.destroy = destroy_drag; + + drag->drag_focus_listener.func = drag_handle_surface_destroy; + wl_list_init(&drag->drag_focus_listener.link); + + wl_client_add_resource(client, &drag->resource); +} + +const static struct wl_shell_interface shell_interface = { + shell_move, + shell_resize, + shell_create_drag +}; + +int +wlsc_shell_init(struct wlsc_compositor *ec) +{ + struct wl_shell *shell = &ec->shell; + + shell->object.interface = &wl_shell_interface; + shell->object.implementation = (void (**)(void)) &shell_interface; + wl_display_add_object(ec->wl_display, &shell->object); + if (wl_display_add_global(ec->wl_display, &shell->object, NULL)) + return -1; + + return 0; +} From ae6c8a6d731b3543bdea0f40757206908d75d6f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Tue, 18 Jan 2011 09:08:53 -0500 Subject: [PATCH 20/30] First attempt at selection support --- compositor/compositor.c | 4 + compositor/compositor.h | 5 ++ compositor/shell.c | 173 +++++++++++++++++++++++++++++++++++++-- protocol/wayland.xml | 51 ++++++++++++ wayland/wayland-server.h | 15 ++++ 5 files changed, 242 insertions(+), 6 deletions(-) diff --git a/compositor/compositor.c b/compositor/compositor.c index 31f70cff..72a3878c 100644 --- a/compositor/compositor.c +++ b/compositor/compositor.c @@ -682,6 +682,10 @@ notify_button(struct wl_input_device *device, if (state && device->grab == NULL) { wlsc_surface_raise(surface); + if (wd->selection) + wlsc_selection_set_focus(wd->selection, + &surface->surface, time); + wl_input_device_start_grab(device, &device->motion_grab, button, time); diff --git a/compositor/compositor.h b/compositor/compositor.h index 6ca72427..ac826ed8 100644 --- a/compositor/compositor.h +++ b/compositor/compositor.h @@ -69,6 +69,7 @@ struct wlsc_input_device { int32_t hotspot_x, hotspot_y; struct wl_list link; uint32_t modifier_state; + struct wl_selection *selection; }; struct wlsc_drm { @@ -165,6 +166,10 @@ wlsc_input_device_set_pointer_image(struct wlsc_input_device *device, struct wlsc_surface * pick_surface(struct wl_input_device *device, int32_t *sx, int32_t *sy); +void +wlsc_selection_set_focus(struct wl_selection *selection, + struct wl_surface *surface, uint32_t time); + uint32_t get_time(void); diff --git a/compositor/shell.c b/compositor/shell.c index a0331e2c..d50a3d69 100644 --- a/compositor/shell.c +++ b/compositor/shell.c @@ -206,11 +206,6 @@ shell_resize(struct wl_client *client, struct wl_shell *shell, wlsc_input_device_set_pointer_image(wd, pointer); } -static void -wl_drag_set_pointer_focus(struct wl_drag *drag, - struct wl_surface *surface, uint32_t time, - int32_t x, int32_t y, int32_t sx, int32_t sy); - static void destroy_drag(struct wl_resource *resource, struct wl_client *client) { @@ -458,10 +453,176 @@ shell_create_drag(struct wl_client *client, wl_client_add_resource(client, &drag->resource); } +void +wlsc_selection_set_focus(struct wl_selection *selection, + struct wl_surface *surface, uint32_t time) +{ + char **p, **end; + + if (selection->selection_focus == surface) + return; + + if (selection->selection_focus != NULL) + wl_client_post_event(selection->selection_focus->client, + &selection->selection_offer.object, + WL_SELECTION_OFFER_KEYBOARD_FOCUS, + NULL); + + if (surface) { + wl_client_post_global(surface->client, + &selection->selection_offer.object); + + end = selection->types.data + selection->types.size; + for (p = selection->types.data; p < end; p++) + wl_client_post_event(surface->client, + &selection->selection_offer.object, + WL_SELECTION_OFFER_OFFER, *p); + + wl_list_remove(&selection->selection_focus_listener.link); + wl_list_insert(surface->destroy_listener_list.prev, + &selection->selection_focus_listener.link); + + wl_client_post_event(surface->client, + &selection->selection_offer.object, + WL_SELECTION_OFFER_KEYBOARD_FOCUS, + selection->input_device); + } + + selection->selection_focus = surface; + + wl_list_remove(&selection->selection_focus_listener.link); + if (surface) + wl_list_insert(surface->destroy_listener_list.prev, + &selection->selection_focus_listener.link); +} + +static void +selection_offer_receive(struct wl_client *client, + struct wl_selection_offer *offer, + const char *mime_type, int fd) +{ + struct wl_selection *selection = + container_of(offer, struct wl_selection, selection_offer); + + wl_client_post_event(selection->client, + &selection->resource.object, + WL_SELECTION_SEND, mime_type, fd); + close(fd); +} + +static const struct wl_selection_offer_interface selection_offer_interface = { + selection_offer_receive +}; + +static void +selection_offer(struct wl_client *client, + struct wl_selection *selection, const char *type) +{ + char **p; + + p = wl_array_add(&selection->types, sizeof *p); + if (p) + *p = strdup(type); + if (!p || !*p) + wl_client_post_no_memory(client); +} + +static void +selection_activate(struct wl_client *client, + struct wl_selection *selection, + struct wl_input_device *device, uint32_t time) +{ + struct wlsc_input_device *wd = (struct wlsc_input_device *) device; + struct wl_display *display = wl_client_get_display (client); + + selection->input_device = device; + + selection->selection_offer.object.interface = + &wl_selection_offer_interface; + selection->selection_offer.object.implementation = + (void (**)(void)) &selection_offer_interface; + + wl_display_add_object(display, &selection->selection_offer.object); + + if (wd->selection) { + wl_client_post_event(wd->selection->client, + &wd->selection->resource.object, + WL_SELECTION_CANCELLED); + } + wd->selection = selection; + + wlsc_selection_set_focus(selection, device->keyboard_focus, time); +} + +static void +selection_destroy(struct wl_client *client, struct wl_selection *selection) +{ + wl_resource_destroy(&selection->resource, client); +} + +static const struct wl_selection_interface selection_interface = { + selection_offer, + selection_activate, + selection_destroy +}; + +static void +destroy_selection(struct wl_resource *resource, struct wl_client *client) +{ + struct wl_selection *selection = + container_of(resource, struct wl_selection, resource); + struct wlsc_input_device *wd = + (struct wlsc_input_device *) selection->input_device; + + if (wd && wd->selection == selection) { + wd->selection = NULL; + wlsc_selection_set_focus(selection, NULL, get_time()); + } + + wl_list_remove(&selection->selection_focus_listener.link); + free(selection); +} + +static void +selection_handle_surface_destroy(struct wl_listener *listener, + struct wl_surface *surface, uint32_t time) +{ +} + +static void +shell_create_selection(struct wl_client *client, + struct wl_shell *shell, uint32_t id) +{ + struct wl_selection *selection; + + selection = malloc(sizeof *selection); + if (selection == NULL) { + wl_client_post_no_memory(client); + return; + } + + memset(selection, 0, sizeof *selection); + selection->resource.object.id = id; + selection->resource.object.interface = &wl_selection_interface; + selection->resource.object.implementation = + (void (**)(void)) &selection_interface; + + selection->client = client; + selection->resource.destroy = destroy_selection; + selection->selection_focus = NULL; + + selection->selection_focus_listener.func = + selection_handle_surface_destroy; + wl_list_init(&selection->selection_focus_listener.link); + + wl_client_add_resource(client, &selection->resource); +} + const static struct wl_shell_interface shell_interface = { shell_move, shell_resize, - shell_create_drag + shell_create_drag, + shell_create_selection }; int diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 8799a64e..75ccb5bd 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -164,6 +164,10 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +