Rename wayland-compositor to weston

This rename addresses a few problems around the split between core
Wayland and the wayland-demos repository.

1) Initially, we had one big repository with protocol code, sample
compositor and sample clients.  We split that repository to make it
possible to implement the protocol without pulling in the sample/demo
code.  At this point, the compositor is more than just a "demo" and
wayland-demos doesn't send the right message.  The sample compositor
is a useful, self-contained project in it's own right, and we want to
move away from the "demos" label.

2) Another problem is that the wayland-demos compositor is often
called "the wayland compsitor", but it's really just one possible
compositor.  Existing X11 compositors are expected to add Wayland
support and then gradually phase out/modularize the X11 support, for
example.  Conversely, it's hard to talk about the wayland-demos
compositor specifically as opposed to, eg, the wayland protocol or a
wayland compositor in general.

We are also renaming the repo to weston, and the compositor
subdirectory to src/, to emphasize that the main "output" is the
compositor.
This commit is contained in:
Kristian Høgsberg
2012-01-03 10:29:47 -05:00
parent 4c61747a1f
commit 8334bc1ef9
26 changed files with 1273 additions and 1269 deletions
-9
View File
@@ -1,9 +0,0 @@
wayland-compositor
screenshooter-protocol.c
screenshooter-server-protocol.h
tablet-shell-protocol.c
tablet-shell-server-protocol.h
xserver-protocol.c
xserver-server-protocol.h
desktop-shell-protocol.c
desktop-shell-server-protocol.h
-113
View File
@@ -1,113 +0,0 @@
bin_PROGRAMS = wayland-compositor
AM_CPPFLAGS = \
-DDATADIR='"$(datadir)"' \
-DMODULEDIR='"$(moduledir)"' \
-DLIBEXECDIR='"$(libexecdir)"' \
-DXSERVER_PATH='"@XSERVER_PATH@"' \
$(COMPOSITOR_CFLAGS)
wayland_compositor_LDFLAGS = -export-dynamic
wayland_compositor_CFLAGS = $(GCC_CFLAGS)
wayland_compositor_LDADD = \
$(COMPOSITOR_LIBS) $(DLOPEN_LIBS) $(XSERVER_LAUNCHER_LIBS)
wayland_compositor_SOURCES = \
compositor.c \
compositor.h \
image-loader.c \
data-device.c \
screenshooter.c \
screenshooter-protocol.c \
screenshooter-server-protocol.h \
util.c \
$(xserver_launcher_sources)
if ENABLE_XSERVER_LAUNCHER
xserver_launcher_sources = \
xserver-launcher.c \
xserver-protocol.c \
xserver-server-protocol.h \
hash.c \
hash.h
endif
moduledir = @libdir@/wayland
module_LTLIBRARIES = \
$(desktop_shell) \
$(tablet_shell) \
$(x11_backend) \
$(drm_backend) \
$(wayland_backend) \
$(openwfd_backend)
if ENABLE_X11_COMPOSITOR
x11_backend = x11-backend.la
x11_backend_la_LDFLAGS = -module -avoid-version
x11_backend_la_LIBADD = $(COMPOSITOR_LIBS) $(X11_COMPOSITOR_LIBS)
x11_backend_la_CFLAGS = $(X11_COMPOSITOR_CFLAGS) $(GCC_CFLAGS)
x11_backend_la_SOURCES = compositor-x11.c
endif
if ENABLE_DRM_COMPOSITOR
drm_backend = drm-backend.la
drm_backend_la_LDFLAGS = -module -avoid-version
drm_backend_la_LIBADD = $(COMPOSITOR_LIBS) $(DRM_COMPOSITOR_LIBS)
drm_backend_la_CFLAGS = $(DRM_COMPOSITOR_CFLAGS) $(GCC_CFLAGS)
drm_backend_la_SOURCES = compositor-drm.c tty.c evdev.c evdev.h
endif
if ENABLE_WAYLAND_COMPOSITOR
wayland_backend = wayland-backend.la
wayland_backend_la_LDFLAGS = -module -avoid-version
wayland_backend_la_LIBADD = $(COMPOSITOR_LIBS) $(WAYLAND_COMPOSITOR_LIBS)
wayland_backend_la_CFLAGS = $(WAYLAND_COMPOSITOR_CFLAGS) $(GCC_CFLAGS)
wayland_backend_la_SOURCES = compositor-wayland.c
endif
if ENABLE_OPENWFD_COMPOSITOR
openwfd_backend = openwfd-backend.la
openwfd_backend_la_LDFLAGS = -module -avoid-version
openwfd_backend_la_LIBADD = $(COMPOSITOR_LIBS) $(OPENWFD_COMPOSITOR_LIBS)
openwfd_backend_la_CFLAGS = $(OPENWFD_COMPOSITOR_CFLAGS) $(GCC_CFLAGS)
openwfd_backend_la_SOURCES = compositor-openwfd.c tty.c evdev.c evdev.h
endif
if ENABLE_DESKTOP_SHELL
desktop_shell = desktop-shell.la
desktop_shell_la_LDFLAGS = -module -avoid-version
desktop_shell_la_LIBADD = $(COMPOSITOR_LIBS) \
../shared/libconfig-parser.la
desktop_shell_la_CFLAGS = $(GCC_CFLAGS)
desktop_shell_la_SOURCES = \
shell.c \
switcher.c \
desktop-shell-protocol.c \
desktop-shell-server-protocol.h
endif
if ENABLE_TABLET_SHELL
tablet_shell = tablet-shell.la
tablet_shell_la_LDFLAGS = -module -avoid-version
tablet_shell_la_LIBADD = $(COMPOSITOR_LIBS)
tablet_shell_la_CFLAGS = $(GCC_CFLAGS)
tablet_shell_la_SOURCES = \
tablet-shell.c \
tablet-shell.h \
tablet-shell-protocol.c \
tablet-shell-server-protocol.h
endif
BUILT_SOURCES = \
screenshooter-server-protocol.h \
screenshooter-protocol.c \
tablet-shell-protocol.c \
tablet-shell-server-protocol.h \
xserver-protocol.c \
xserver-server-protocol.h \
desktop-shell-protocol.c \
desktop-shell-server-protocol.h
CLEANFILES = $(BUILT_SOURCES)
@wayland_scanner_rules@
-956
View File
@@ -1,956 +0,0 @@
/*
* Copyright © 2008-2011 Kristian Høgsberg
* Copyright © 2011 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.
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
#include <gbm.h>
#include "compositor.h"
#include "evdev.h"
struct drm_compositor {
struct wlsc_compositor base;
struct udev *udev;
struct wl_event_source *drm_source;
struct udev_monitor *udev_monitor;
struct wl_event_source *udev_drm_source;
struct {
int fd;
} drm;
struct gbm_device *gbm;
uint32_t crtc_allocator;
uint32_t connector_allocator;
struct tty *tty;
uint32_t prev_state;
};
struct drm_mode {
struct wlsc_mode base;
drmModeModeInfo mode_info;
};
struct drm_output {
struct wlsc_output base;
uint32_t crtc_id;
uint32_t connector_id;
drmModeCrtcPtr original_crtc;
GLuint rbo[2];
uint32_t fb_id[2];
EGLImageKHR image[2];
struct gbm_bo *bo[2];
uint32_t current;
uint32_t fs_surf_fb_id;
uint32_t pending_fs_surf_fb_id;
};
static int
drm_output_prepare_render(struct wlsc_output *output_base)
{
struct drm_output *output = (struct drm_output *) output_base;
glFramebufferRenderbuffer(GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_RENDERBUFFER,
output->rbo[output->current]);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
return -1;
return 0;
}
static int
drm_output_present(struct wlsc_output *output_base)
{
struct drm_output *output = (struct drm_output *) output_base;
struct drm_compositor *c =
(struct drm_compositor *) output->base.compositor;
uint32_t fb_id = 0;
glFlush();
output->current ^= 1;
if (output->pending_fs_surf_fb_id != 0) {
fb_id = output->pending_fs_surf_fb_id;
} else {
fb_id = output->fb_id[output->current ^ 1];
}
drmModePageFlip(c->drm.fd, output->crtc_id,
fb_id,
DRM_MODE_PAGE_FLIP_EVENT, output);
return 0;
}
static void
page_flip_handler(int fd, unsigned int frame,
unsigned int sec, unsigned int usec, void *data)
{
struct drm_output *output = (struct drm_output *) data;
struct drm_compositor *c =
(struct drm_compositor *) output->base.compositor;
uint32_t msecs;
if (output->fs_surf_fb_id) {
drmModeRmFB(c->drm.fd, output->fs_surf_fb_id);
output->fs_surf_fb_id = 0;
}
if (output->pending_fs_surf_fb_id) {
output->fs_surf_fb_id = output->pending_fs_surf_fb_id;
output->pending_fs_surf_fb_id = 0;
}
msecs = sec * 1000 + usec / 1000;
wlsc_output_finish_frame(&output->base, msecs);
}
static int
drm_output_prepare_scanout_surface(struct wlsc_output *output_base,
struct wlsc_surface *es)
{
struct drm_output *output = (struct drm_output *) output_base;
struct drm_compositor *c =
(struct drm_compositor *) output->base.compositor;
EGLint handle, stride;
int ret;
uint32_t fb_id = 0;
struct gbm_bo *bo;
if (es->x != output->base.x ||
es->y != output->base.y ||
es->width != output->base.current->width ||
es->height != output->base.current->height ||
es->image == EGL_NO_IMAGE_KHR)
return -1;
bo = gbm_bo_create_from_egl_image(c->gbm,
c->base.display, es->image,
es->width, es->height,
GBM_BO_USE_SCANOUT);
handle = gbm_bo_get_handle(bo).s32;
stride = gbm_bo_get_pitch(bo);
gbm_bo_destroy(bo);
if (handle == 0)
return -1;
ret = drmModeAddFB(c->drm.fd,
output->base.current->width,
output->base.current->height,
24, 32, stride, handle, &fb_id);
if (ret)
return -1;
output->pending_fs_surf_fb_id = fb_id;
return 0;
}
static int
drm_output_set_cursor(struct wlsc_output *output_base,
struct wlsc_input_device *eid)
{
struct drm_output *output = (struct drm_output *) output_base;
struct drm_compositor *c =
(struct drm_compositor *) output->base.compositor;
EGLint handle, stride;
int ret = -1;
pixman_region32_t cursor_region;
struct gbm_bo *bo;
if (eid == NULL) {
drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
return 0;
}
pixman_region32_init_rect(&cursor_region,
eid->sprite->x, eid->sprite->y,
eid->sprite->width, eid->sprite->height);
pixman_region32_intersect_rect(&cursor_region, &cursor_region,
output->base.x, output->base.y,
output->base.current->width,
output->base.current->height);
if (!pixman_region32_not_empty(&cursor_region))
goto out;
if (eid->sprite->image == EGL_NO_IMAGE_KHR)
goto out;
if (eid->sprite->width > 64 || eid->sprite->height > 64)
goto out;
bo = gbm_bo_create_from_egl_image(c->gbm,
c->base.display,
eid->sprite->image, 64, 64,
GBM_BO_USE_CURSOR_64X64);
handle = gbm_bo_get_handle(bo).s32;
stride = gbm_bo_get_pitch(bo);
gbm_bo_destroy(bo);
if (stride != 64 * 4) {
fprintf(stderr, "info: cursor stride is != 64\n");
goto out;
}
ret = drmModeSetCursor(c->drm.fd, output->crtc_id, handle, 64, 64);
if (ret) {
fprintf(stderr, "failed to set cursor: %s\n", strerror(-ret));
goto out;
}
ret = drmModeMoveCursor(c->drm.fd, output->crtc_id,
eid->sprite->x - output->base.x,
eid->sprite->y - output->base.y);
if (ret) {
fprintf(stderr, "failed to move cursor: %s\n", strerror(-ret));
goto out;
}
out:
pixman_region32_fini(&cursor_region);
if (ret)
drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
return ret;
}
static void
drm_output_destroy(struct wlsc_output *output_base)
{
struct drm_output *output = (struct drm_output *) output_base;
struct drm_compositor *c =
(struct drm_compositor *) output->base.compositor;
drmModeCrtcPtr origcrtc = output->original_crtc;
int i;
/* Turn off hardware cursor */
drm_output_set_cursor(&output->base, NULL);
/* Restore original CRTC state */
drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
origcrtc->x, origcrtc->y,
&output->connector_id, 1, &origcrtc->mode);
drmModeFreeCrtc(origcrtc);
glFramebufferRenderbuffer(GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_RENDERBUFFER,
0);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
glDeleteRenderbuffers(2, output->rbo);
/* Destroy output buffers */
for (i = 0; i < 2; i++) {
drmModeRmFB(c->drm.fd, output->fb_id[i]);
c->base.destroy_image(c->base.display, output->image[i]);
gbm_bo_destroy(output->bo[i]);
}
c->crtc_allocator &= ~(1 << output->crtc_id);
c->connector_allocator &= ~(1 << output->connector_id);
wlsc_output_destroy(&output->base);
wl_list_remove(&output->base.link);
free(output);
}
static int
on_drm_input(int fd, uint32_t mask, void *data)
{
drmEventContext evctx;
memset(&evctx, 0, sizeof evctx);
evctx.version = DRM_EVENT_CONTEXT_VERSION;
evctx.page_flip_handler = page_flip_handler;
drmHandleEvent(fd, &evctx);
return 1;
}
static int
init_egl(struct drm_compositor *ec, struct udev_device *device)
{
EGLint major, minor;
const char *extensions, *filename;
int fd;
static const EGLint context_attribs[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
filename = udev_device_get_devnode(device);
fd = open(filename, O_RDWR | O_CLOEXEC);
if (fd < 0) {
/* Probably permissions error */
fprintf(stderr, "couldn't open %s, skipping\n",
udev_device_get_devnode(device));
return -1;
}
ec->drm.fd = fd;
ec->gbm = gbm_create_device(ec->drm.fd);
ec->base.display = eglGetDisplay(ec->gbm);
if (ec->base.display == NULL) {
fprintf(stderr, "failed to create display\n");
return -1;
}
if (!eglInitialize(ec->base.display, &major, &minor)) {
fprintf(stderr, "failed to initialize display\n");
return -1;
}
extensions = eglQueryString(ec->base.display, EGL_EXTENSIONS);
if (!strstr(extensions, "EGL_KHR_surfaceless_gles2")) {
fprintf(stderr, "EGL_KHR_surfaceless_gles2 not available\n");
return -1;
}
if (!eglBindAPI(EGL_OPENGL_ES_API)) {
fprintf(stderr, "failed to bind api EGL_OPENGL_ES_API\n");
return -1;
}
ec->base.context = eglCreateContext(ec->base.display, NULL,
EGL_NO_CONTEXT, context_attribs);
if (ec->base.context == NULL) {
fprintf(stderr, "failed to create context\n");
return -1;
}
if (!eglMakeCurrent(ec->base.display, EGL_NO_SURFACE,
EGL_NO_SURFACE, ec->base.context)) {
fprintf(stderr, "failed to make context current\n");
return -1;
}
return 0;
}
static drmModeModeInfo builtin_1024x768 = {
63500, /* clock */
1024, 1072, 1176, 1328, 0,
768, 771, 775, 798, 0,
59920,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC,
0,
"1024x768"
};
static int
drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
{
struct drm_mode *mode;
mode = malloc(sizeof *mode);
if (mode == NULL)
return -1;
mode->base.flags = 0;
mode->base.width = info->hdisplay;
mode->base.height = info->vdisplay;
mode->base.refresh = info->vrefresh;
mode->mode_info = *info;
wl_list_insert(output->base.mode_list.prev, &mode->base.link);
return 0;
}
static int
drm_subpixel_to_wayland(int drm_value)
{
switch (drm_value) {
default:
case DRM_MODE_SUBPIXEL_UNKNOWN:
return WL_OUTPUT_SUBPIXEL_UNKNOWN;
case DRM_MODE_SUBPIXEL_NONE:
return WL_OUTPUT_SUBPIXEL_NONE;
case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
}
}
static int
create_output_for_connector(struct drm_compositor *ec,
drmModeRes *resources,
drmModeConnector *connector,
int x, int y)
{
struct drm_output *output;
struct drm_mode *drm_mode, *next;
drmModeEncoder *encoder;
int i, ret;
unsigned handle, stride;
encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[0]);
if (encoder == NULL) {
fprintf(stderr, "No encoder for connector.\n");
return -1;
}
for (i = 0; i < resources->count_crtcs; i++) {
if (encoder->possible_crtcs & (1 << i) &&
!(ec->crtc_allocator & (1 << resources->crtcs[i])))
break;
}
if (i == resources->count_crtcs) {
fprintf(stderr, "No usable crtc for encoder.\n");
drmModeFreeEncoder(encoder);
return -1;
}
output = malloc(sizeof *output);
if (output == NULL) {
drmModeFreeEncoder(encoder);
return -1;
}
output->fb_id[0] = -1;
output->fb_id[1] = -1;
memset(output, 0, sizeof *output);
output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
output->base.make = "unknown";
output->base.model = "unknown";
wl_list_init(&output->base.mode_list);
output->crtc_id = resources->crtcs[i];
ec->crtc_allocator |= (1 << output->crtc_id);
output->connector_id = connector->connector_id;
ec->connector_allocator |= (1 << output->connector_id);
output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
drmModeFreeEncoder(encoder);
for (i = 0; i < connector->count_modes; i++) {
ret = drm_output_add_mode(output, &connector->modes[i]);
if (ret)
goto err_free;
}
if (connector->count_modes == 0) {
ret = drm_output_add_mode(output, &builtin_1024x768);
if (ret)
goto err_free;
}
drm_mode = container_of(output->base.mode_list.next,
struct drm_mode, base.link);
output->base.current = &drm_mode->base;
drm_mode->base.flags =
WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
glGenRenderbuffers(2, output->rbo);
for (i = 0; i < 2; i++) {
glBindRenderbuffer(GL_RENDERBUFFER, output->rbo[i]);
output->bo[i] =
gbm_bo_create(ec->gbm,
output->base.current->width,
output->base.current->height,
GBM_BO_FORMAT_XRGB8888,
GBM_BO_USE_SCANOUT |
GBM_BO_USE_RENDERING);
if (!output->bo[i])
goto err_bufs;
output->image[i] = ec->base.create_image(ec->base.display,
NULL,
EGL_NATIVE_PIXMAP_KHR,
output->bo[i], NULL);
if (!output->image[i])
goto err_bufs;
ec->base.image_target_renderbuffer_storage(GL_RENDERBUFFER,
output->image[i]);
stride = gbm_bo_get_pitch(output->bo[i]);
handle = gbm_bo_get_handle(output->bo[i]).u32;
ret = drmModeAddFB(ec->drm.fd,
output->base.current->width,
output->base.current->height,
24, 32, stride, handle, &output->fb_id[i]);
if (ret) {
fprintf(stderr, "failed to add fb %d: %m\n", i);
goto err_bufs;
}
}
output->current = 0;
glFramebufferRenderbuffer(GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_RENDERBUFFER,
output->rbo[output->current]);
ret = drmModeSetCrtc(ec->drm.fd, output->crtc_id,
output->fb_id[output->current ^ 1], 0, 0,
&output->connector_id, 1,
&drm_mode->mode_info);
if (ret) {
fprintf(stderr, "failed to set mode: %m\n");
goto err_fb;
}
wlsc_output_init(&output->base, &ec->base, x, y,
connector->mmWidth, connector->mmHeight, 0);
wl_list_insert(ec->base.output_list.prev, &output->base.link);
output->pending_fs_surf_fb_id = 0;
output->base.prepare_render = drm_output_prepare_render;
output->base.present = drm_output_present;
output->base.prepare_scanout_surface =
drm_output_prepare_scanout_surface;
output->base.set_hardware_cursor = drm_output_set_cursor;
output->base.destroy = drm_output_destroy;
return 0;
err_fb:
glFramebufferRenderbuffer(GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_RENDERBUFFER,
0);
err_bufs:
for (i = 0; i < 2; i++) {
if (output->fb_id[i] != -1)
drmModeRmFB(ec->drm.fd, output->fb_id[i]);
if (output->image[i])
ec->base.destroy_image(ec->base.display,
output->image[i]);
if (output->bo[i])
gbm_bo_destroy(output->bo[i]);
}
glBindRenderbuffer(GL_RENDERBUFFER, 0);
glDeleteRenderbuffers(2, output->rbo);
err_free:
wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
base.link) {
wl_list_remove(&drm_mode->base.link);
free(drm_mode);
}
drmModeFreeCrtc(output->original_crtc);
ec->crtc_allocator &= ~(1 << output->crtc_id);
ec->connector_allocator &= ~(1 << output->connector_id);
free(output);
return -1;
}
static int
create_outputs(struct drm_compositor *ec, int option_connector)
{
drmModeConnector *connector;
drmModeRes *resources;
int i;
int x = 0, y = 0;
resources = drmModeGetResources(ec->drm.fd);
if (!resources) {
fprintf(stderr, "drmModeGetResources failed\n");
return -1;
}
for (i = 0; i < resources->count_connectors; i++) {
connector = drmModeGetConnector(ec->drm.fd,
resources->connectors[i]);
if (connector == NULL)
continue;
if (connector->connection == DRM_MODE_CONNECTED &&
(option_connector == 0 ||
connector->connector_id == option_connector)) {
if (create_output_for_connector(ec, resources,
connector, x, y) < 0) {
drmModeFreeConnector(connector);
continue;
}
x += container_of(ec->base.output_list.prev,
struct wlsc_output,
link)->current->width;
}
drmModeFreeConnector(connector);
}
if (wl_list_empty(&ec->base.output_list)) {
fprintf(stderr, "No currently active connector found.\n");
return -1;
}
drmModeFreeResources(resources);
return 0;
}
static void
update_outputs(struct drm_compositor *ec)
{
drmModeConnector *connector;
drmModeRes *resources;
struct drm_output *output, *next;
int x = 0, y = 0;
int x_offset = 0, y_offset = 0;
uint32_t connected = 0, disconnects = 0;
int i;
resources = drmModeGetResources(ec->drm.fd);
if (!resources) {
fprintf(stderr, "drmModeGetResources failed\n");
return;
}
/* collect new connects */
for (i = 0; i < resources->count_connectors; i++) {
int connector_id = resources->connectors[i];
connector = drmModeGetConnector(ec->drm.fd, connector_id);
if (connector == NULL)
continue;
if (connector->connection != DRM_MODE_CONNECTED) {
drmModeFreeConnector(connector);
continue;
}
connected |= (1 << connector_id);
if (!(ec->connector_allocator & (1 << connector_id))) {
struct wlsc_output *last =
container_of(ec->base.output_list.prev,
struct wlsc_output, link);
/* XXX: not yet needed, we die with 0 outputs */
if (!wl_list_empty(&ec->base.output_list))
x = last->x + last->current->width;
else
x = 0;
y = 0;
create_output_for_connector(ec, resources,
connector, x, y);
printf("connector %d connected\n", connector_id);
}
drmModeFreeConnector(connector);
}
drmModeFreeResources(resources);
disconnects = ec->connector_allocator & ~connected;
if (disconnects) {
wl_list_for_each_safe(output, next, &ec->base.output_list,
base.link) {
if (x_offset != 0 || y_offset != 0) {
wlsc_output_move(&output->base,
output->base.x - x_offset,
output->base.y - y_offset);
}
if (disconnects & (1 << output->connector_id)) {
disconnects &= ~(1 << output->connector_id);
printf("connector %d disconnected\n",
output->connector_id);
x_offset += output->base.current->width;
drm_output_destroy(&output->base);
}
}
}
/* FIXME: handle zero outputs, without terminating */
if (ec->connector_allocator == 0)
wl_display_terminate(ec->base.wl_display);
}
static int
udev_event_is_hotplug(struct udev_device *device)
{
struct udev_list_entry *list, *hotplug_entry;
list = udev_device_get_properties_list_entry(device);
hotplug_entry = udev_list_entry_get_by_name(list, "HOTPLUG");
if (hotplug_entry == NULL)
return 0;
return strcmp(udev_list_entry_get_value(hotplug_entry), "1") == 0;
}
static int
udev_drm_event(int fd, uint32_t mask, void *data)
{
struct drm_compositor *ec = data;
struct udev_device *event;
event = udev_monitor_receive_device(ec->udev_monitor);
if (udev_event_is_hotplug(event))
update_outputs(ec);
udev_device_unref(event);
return 1;
}
static EGLImageKHR
drm_compositor_create_cursor_image(struct wlsc_compositor *ec,
int32_t *width, int32_t *height)
{
struct drm_compositor *c = (struct drm_compositor *) ec;
struct gbm_bo *bo;
EGLImageKHR image;
if (*width > 64 || *height > 64)
return EGL_NO_IMAGE_KHR;
bo = gbm_bo_create(c->gbm,
/* width, height, */ 64, 64,
GBM_BO_FORMAT_ARGB8888,
GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_RENDERING);
image = ec->create_image(c->base.display, NULL,
EGL_NATIVE_PIXMAP_KHR, bo, NULL);
gbm_bo_destroy(bo);
*width = 64;
*height = 64;
return image;
}
static void
drm_destroy(struct wlsc_compositor *ec)
{
struct drm_compositor *d = (struct drm_compositor *) ec;
struct wlsc_input_device *input, *next;
wlsc_compositor_shutdown(ec);
gbm_device_destroy(d->gbm);
tty_destroy(d->tty);
wl_list_for_each_safe(input, next, &ec->input_device_list, link)
evdev_input_destroy(input);
free(d);
}
static void
vt_func(struct wlsc_compositor *compositor, int event)
{
struct drm_compositor *ec = (struct drm_compositor *) compositor;
struct wlsc_output *output;
struct wlsc_input_device *input;
switch (event) {
case TTY_ENTER_VT:
compositor->focus = 1;
drmSetMaster(ec->drm.fd);
compositor->state = ec->prev_state;
wlsc_compositor_damage_all(compositor);
wl_list_for_each(input, &compositor->input_device_list, link)
evdev_add_devices(ec->udev, input);
break;
case TTY_LEAVE_VT:
compositor->focus = 0;
ec->prev_state = compositor->state;
compositor->state = WLSC_COMPOSITOR_SLEEPING;
wl_list_for_each(input, &compositor->input_device_list, link)
evdev_remove_devices(input);
wl_list_for_each(output, &ec->base.output_list, link)
drm_output_set_cursor(output, NULL);
drmDropMaster(ec->drm.fd);
break;
};
}
static const char default_seat[] = "seat0";
static struct wlsc_compositor *
drm_compositor_create(struct wl_display *display,
int connector, const char *seat, int tty)
{
struct drm_compositor *ec;
struct udev_enumerate *e;
struct udev_list_entry *entry;
struct udev_device *device, *drm_device;
const char *path, *device_seat;
struct wl_event_loop *loop;
ec = malloc(sizeof *ec);
if (ec == NULL)
return NULL;
memset(ec, 0, sizeof *ec);
ec->udev = udev_new();
if (ec->udev == NULL) {
fprintf(stderr, "failed to initialize udev context\n");
return NULL;
}
e = udev_enumerate_new(ec->udev);
udev_enumerate_add_match_subsystem(e, "drm");
udev_enumerate_add_match_sysname(e, "card[0-9]*");
udev_enumerate_scan_devices(e);
drm_device = NULL;
udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
path = udev_list_entry_get_name(entry);
device = udev_device_new_from_syspath(ec->udev, path);
device_seat =
udev_device_get_property_value(device, "ID_SEAT");
if (!device_seat)
device_seat = default_seat;
if (strcmp(device_seat, seat) == 0) {
drm_device = device;
break;
}
udev_device_unref(device);
}
if (drm_device == NULL) {
fprintf(stderr, "no drm device found\n");
return NULL;
}
ec->base.wl_display = display;
if (init_egl(ec, drm_device) < 0) {
fprintf(stderr, "failed to initialize egl\n");
return NULL;
}
udev_device_unref(drm_device);
ec->base.destroy = drm_destroy;
ec->base.create_cursor_image = drm_compositor_create_cursor_image;
ec->base.focus = 1;
ec->prev_state = WLSC_COMPOSITOR_ACTIVE;
glGenFramebuffers(1, &ec->base.fbo);
glBindFramebuffer(GL_FRAMEBUFFER, ec->base.fbo);
/* Can't init base class until we have a current egl context */
if (wlsc_compositor_init(&ec->base, display) < 0)
return NULL;
if (create_outputs(ec, connector) < 0) {
fprintf(stderr, "failed to create output for %s\n", path);
return NULL;
}
udev_enumerate_unref(e);
path = NULL;
evdev_input_create(&ec->base, ec->udev, seat);
loop = wl_display_get_event_loop(ec->base.wl_display);
ec->drm_source =
wl_event_loop_add_fd(loop, ec->drm.fd,
WL_EVENT_READABLE, on_drm_input, ec);
ec->tty = tty_create(&ec->base, vt_func, tty);
ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
if (ec->udev_monitor == NULL) {
fprintf(stderr, "failed to intialize udev monitor\n");
return NULL;
}
udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
"drm", NULL);
ec->udev_drm_source =
wl_event_loop_add_fd(loop,
udev_monitor_get_fd(ec->udev_monitor),
WL_EVENT_READABLE, udev_drm_event, ec);
if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
fprintf(stderr, "failed to enable udev-monitor receiving\n");
return NULL;
}
return &ec->base;
}
struct wlsc_compositor *
backend_init(struct wl_display *display, char *options);
WL_EXPORT struct wlsc_compositor *
backend_init(struct wl_display *display, char *options)
{
int connector = 0, i;
const char *seat;
char *p, *value;
int tty = 1;
static char * const tokens[] = { "connector", "seat", "tty", NULL };
p = options;
seat = default_seat;
while (i = getsubopt(&p, tokens, &value), i != -1) {
switch (i) {
case 0:
connector = strtol(value, NULL, 0);
break;
case 1:
seat = value;
break;
case 2:
tty = strtol(value, NULL, 0);
break;
}
}
return drm_compositor_create(display, connector, seat, tty);
}
-699
View File
@@ -1,699 +0,0 @@
/*
* Copyright © 2011 Benjamin Franzke
* Copyright © 2011 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.
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <WF/wfd.h>
#include <WF/wfdext.h>
#include <gbm.h>
#include "compositor.h"
#include "evdev.h"
struct wfd_compositor {
struct wlsc_compositor base;
struct udev *udev;
struct gbm_device *gbm;
WFDDevice dev;
WFDEvent event;
int wfd_fd;
struct wl_event_source *wfd_source;
struct tty *tty;
uint32_t start_time;
uint32_t used_pipelines;
};
struct wfd_mode {
struct wlsc_mode base;
WFDPortMode mode;
};
struct wfd_output {
struct wlsc_output base;
WFDPort port;
WFDPipeline pipeline;
WFDint pipeline_id;
WFDPortMode mode;
WFDSource source[2];
struct gbm_bo *bo[2];
EGLImageKHR image[2];
GLuint rbo[2];
uint32_t current;
};
union wfd_geometry {
struct {
WFDint x, y;
WFDint width, height;
} g;
WFDint array[4];
};
static int
wfd_output_prepare_render(struct wlsc_output *output_base)
{
struct wfd_output *output = (struct wfd_output *) output_base;
glFramebufferRenderbuffer(GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_RENDERBUFFER,
output->rbo[output->current]);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
return -1;
return 0;
}
static int
wfd_output_present(struct wlsc_output *output_base)
{
struct wfd_output *output = (struct wfd_output *) output_base;
struct wfd_compositor *c =
(struct wfd_compositor *) output->base.compositor;
if (wfd_output_prepare_render(&output->base))
return -1;
glFlush();
output->current ^= 1;
wfdBindSourceToPipeline(c->dev, output->pipeline,
output->source[output->current ^ 1],
WFD_TRANSITION_AT_VSYNC, NULL);
wfdDeviceCommit(c->dev, WFD_COMMIT_PIPELINE, output->pipeline);
return 0;
}
static int
init_egl(struct wfd_compositor *ec)
{
EGLint major, minor;
const char *extensions;
int fd;
static const EGLint context_attribs[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
fd = wfdGetDeviceAttribi(ec->dev, WFD_DEVICE_ID);
if (fd < 0)
return -1;
ec->wfd_fd = fd;
ec->gbm = gbm_create_device(ec->wfd_fd);
ec->base.display = eglGetDisplay(ec->gbm);
if (ec->base.display == NULL) {
fprintf(stderr, "failed to create display\n");
return -1;
}
if (!eglInitialize(ec->base.display, &major, &minor)) {
fprintf(stderr, "failed to initialize display\n");
return -1;
}
extensions = eglQueryString(ec->base.display, EGL_EXTENSIONS);
if (!strstr(extensions, "EGL_KHR_surfaceless_gles2")) {
fprintf(stderr, "EGL_KHR_surfaceless_gles2 not available\n");
return -1;
}
if (!eglBindAPI(EGL_OPENGL_ES_API)) {
fprintf(stderr, "failed to bind api EGL_OPENGL_ES_API\n");
return -1;
}
ec->base.context = eglCreateContext(ec->base.display, NULL,
EGL_NO_CONTEXT, context_attribs);
if (ec->base.context == NULL) {
fprintf(stderr, "failed to create context\n");
return -1;
}
if (!eglMakeCurrent(ec->base.display, EGL_NO_SURFACE,
EGL_NO_SURFACE, ec->base.context)) {
fprintf(stderr, "failed to make context current\n");
return -1;
}
return 0;
}
static int
wfd_output_prepare_scanout_surface(struct wlsc_output *output_base,
struct wlsc_surface *es)
{
return -1;
}
static int
wfd_output_set_cursor(struct wlsc_output *output_base,
struct wlsc_input_device *input)
{
return -1;
}
static void
wfd_output_destroy(struct wlsc_output *output_base)
{
struct wfd_output *output = (struct wfd_output *) output_base;
struct wfd_compositor *ec =
(struct wfd_compositor *) output->base.compositor;
int i;
glFramebufferRenderbuffer(GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_RENDERBUFFER,
0);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
glDeleteRenderbuffers(2, output->rbo);
for (i = 0; i < 2; i++) {
ec->base.destroy_image(ec->base.display, output->image[i]);
gbm_bo_destroy(output->bo[i]);
wfdDestroySource(ec->dev, output->source[i]);
}
ec->used_pipelines &= ~(1 << output->pipeline_id);
wfdDestroyPipeline(ec->dev, output->pipeline);
wfdDestroyPort(ec->dev, output->port);
wlsc_output_destroy(&output->base);
wl_list_remove(&output->base.link);
free(output);
}
static int
wfd_output_add_mode(struct wfd_output *output, WFDPortMode mode)
{
struct wfd_compositor *ec =
(struct wfd_compositor *) output->base.compositor;
struct wfd_mode *wmode;
wmode = malloc(sizeof *wmode);
if (wmode == NULL)
return -1;
wmode->base.flags = 0;
wmode->base.width = wfdGetPortModeAttribi(ec->dev, output->port, mode,
WFD_PORT_MODE_WIDTH);
wmode->base.height = wfdGetPortModeAttribi(ec->dev, output->port, mode,
WFD_PORT_MODE_HEIGHT);
wmode->base.refresh = wfdGetPortModeAttribi(ec->dev, output->port, mode,
WFD_PORT_MODE_REFRESH_RATE);
wmode->mode = mode;
wl_list_insert(output->base.mode_list.prev, &wmode->base.link);
return 0;
}
static int
create_output_for_port(struct wfd_compositor *ec,
WFDHandle port,
int x, int y)
{
struct wfd_output *output;
int i;
WFDint num_pipelines, *pipelines;
WFDint num_modes;
union wfd_geometry geometry;
struct wfd_mode *mode;
WFDPortMode *modes;
WFDfloat physical_size[2];
output = malloc(sizeof *output);
if (output == NULL)
return -1;
memset(output, 0, sizeof *output);
memset(&geometry, 0, sizeof geometry);
output->port = port;
wl_list_init(&output->base.mode_list);
wfdSetPortAttribi(ec->dev, output->port,
WFD_PORT_POWER_MODE, WFD_POWER_MODE_ON);
num_modes = wfdGetPortModes(ec->dev, output->port, NULL, 0);
if (num_modes < 1) {
fprintf(stderr, "failed to get port mode\n");
goto cleanup_port;
}
modes = malloc(sizeof(WFDPortMode) * num_modes);
if (modes == NULL)
goto cleanup_port;
output->base.compositor = &ec->base;
num_modes = wfdGetPortModes(ec->dev, output->port, modes, num_modes);
for (i = 0; i < num_modes; ++i)
wfd_output_add_mode(output, modes[i]);
free(modes);
wfdGetPortAttribiv(ec->dev, output->port,
WFD_PORT_NATIVE_RESOLUTION,
2, &geometry.array[2]);
output->base.current = NULL;
wl_list_for_each(mode, &output->base.mode_list, base.link) {
if (mode->base.width == geometry.g.width &&
mode->base.height == geometry.g.height) {
output->base.current = &mode->base;
break;
}
}
if (output->base.current == NULL) {
fprintf(stderr, "failed to find a native mode\n");
goto cleanup_port;
}
mode = (struct wfd_mode *) output->base.current;
mode->base.flags = WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
wfdSetPortMode(ec->dev, output->port, mode->mode);
wfdEnumeratePipelines(ec->dev, NULL, 0, NULL);
num_pipelines = wfdGetPortAttribi(ec->dev, output->port,
WFD_PORT_PIPELINE_ID_COUNT);
if (num_pipelines < 1) {
fprintf(stderr, "failed to get a bindable pipeline\n");
goto cleanup_port;
}
pipelines = calloc(num_pipelines, sizeof *pipelines);
if (pipelines == NULL)
goto cleanup_port;
wfdGetPortAttribiv(ec->dev, output->port,
WFD_PORT_BINDABLE_PIPELINE_IDS,
num_pipelines, pipelines);
output->pipeline_id = WFD_INVALID_PIPELINE_ID;
for (i = 0; i < num_pipelines; ++i) {
if (!(ec->used_pipelines & (1 << pipelines[i]))) {
output->pipeline_id = pipelines[i];
break;
}
}
if (output->pipeline_id == WFD_INVALID_PIPELINE_ID) {
fprintf(stderr, "no pipeline found for port: %d\n", port);
goto cleanup_pipelines;
}
ec->used_pipelines |= (1 << output->pipeline_id);
wfdGetPortAttribfv(ec->dev, output->port,
WFD_PORT_PHYSICAL_SIZE,
2, physical_size);
wlsc_output_init(&output->base, &ec->base, x, y,
physical_size[0], physical_size[1], 0);
output->pipeline = wfdCreatePipeline(ec->dev, output->pipeline_id, NULL);
if (output->pipeline == WFD_INVALID_HANDLE) {
fprintf(stderr, "failed to create a pipeline\n");
goto cleanup_wlsc_output;
}
glGenRenderbuffers(2, output->rbo);
for (i = 0; i < 2; i++) {
glBindRenderbuffer(GL_RENDERBUFFER, output->rbo[i]);
output->bo[i] =
gbm_bo_create(ec->gbm,
output->base.current->width,
output->base.current->height,
GBM_BO_FORMAT_XRGB8888,
GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
output->image[i] = ec->base.create_image(ec->base.display,
NULL,
EGL_NATIVE_PIXMAP_KHR,
output->bo[i], NULL);
printf("output->image[i]: %p\n", output->image[i]);
ec->base.image_target_renderbuffer_storage(GL_RENDERBUFFER,
output->image[i]);
output->source[i] =
wfdCreateSourceFromImage(ec->dev, output->pipeline,
output->image[i], NULL);
if (output->source[i] == WFD_INVALID_HANDLE) {
fprintf(stderr, "failed to create source\n");
goto cleanup_pipeline;
}
}
output->current = 0;
glFramebufferRenderbuffer(GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_RENDERBUFFER,
output->rbo[output->current]);
wfdSetPipelineAttribiv(ec->dev, output->pipeline,
WFD_PIPELINE_SOURCE_RECTANGLE,
4, geometry.array);
wfdSetPipelineAttribiv(ec->dev, output->pipeline,
WFD_PIPELINE_DESTINATION_RECTANGLE,
4, geometry.array);
wfdBindSourceToPipeline(ec->dev, output->pipeline,
output->source[output->current ^ 1],
WFD_TRANSITION_AT_VSYNC, NULL);
wfdBindPipelineToPort(ec->dev, output->port, output->pipeline);
wfdDeviceCommit(ec->dev, WFD_COMMIT_ENTIRE_DEVICE, WFD_INVALID_HANDLE);
output->base.prepare_render = wfd_output_prepare_render;
output->base.present = wfd_output_present;
output->base.prepare_scanout_surface =
wfd_output_prepare_scanout_surface;
output->base.set_hardware_cursor = wfd_output_set_cursor;
output->base.destroy = wfd_output_destroy;
wl_list_insert(ec->base.output_list.prev, &output->base.link);
return 0;
cleanup_pipeline:
wfdDestroyPipeline(ec->dev, output->pipeline);
cleanup_wlsc_output:
wlsc_output_destroy(&output->base);
cleanup_pipelines:
free(pipelines);
cleanup_port:
wfdDestroyPort(ec->dev, output->port);
free(output);
return -1;
}
static int
create_outputs(struct wfd_compositor *ec, int option_connector)
{
int x = 0, y = 0;
WFDint i, num, *ports;
WFDPort port = WFD_INVALID_HANDLE;
num = wfdEnumeratePorts(ec->dev, NULL, 0, NULL);
ports = calloc(num, sizeof *ports);
if (ports == NULL)
return -1;
num = wfdEnumeratePorts(ec->dev, ports, num, NULL);
if (num < 1)
return -1;
for (i = 0; i < num; ++i) {
port = wfdCreatePort(ec->dev, ports[i], NULL);
if (port == WFD_INVALID_HANDLE)
continue;
if (wfdGetPortAttribi(ec->dev, port, WFD_PORT_ATTACHED) &&
(option_connector == 0 || ports[i] == option_connector)) {
create_output_for_port(ec, port, x, y);
x += container_of(ec->base.output_list.prev,
struct wlsc_output,
link)->current->width;
} else {
wfdDestroyPort(ec->dev, port);
}
}
free(ports);
return 0;
}
static int
handle_port_state_change(struct wfd_compositor *ec)
{
struct wfd_output *output, *next;
WFDint output_port_id;
int x = 0, y = 0;
int x_offset = 0, y_offset = 0;
WFDPort port;
WFDint port_id;
WFDboolean state;
port_id = wfdGetEventAttribi(ec->dev, ec->event,
WFD_EVENT_PORT_ATTACH_PORT_ID);
state = wfdGetEventAttribi(ec->dev, ec->event,
WFD_EVENT_PORT_ATTACH_STATE);
if (state) {
struct wlsc_output *last_output =
container_of(ec->base.output_list.prev,
struct wlsc_output, link);
/* XXX: not yet needed, we die with 0 outputs */
if (!wl_list_empty(&ec->base.output_list))
x = last_output->x +
last_output->current->width;
else
x = 0;
y = 0;
port = wfdCreatePort(ec->dev, port_id, NULL);
if (port == WFD_INVALID_HANDLE)
return -1;
create_output_for_port(ec, port, x, y);
return 0;
}
wl_list_for_each_safe(output, next, &ec->base.output_list, base.link) {
output_port_id =
wfdGetPortAttribi(ec->dev, output->port, WFD_PORT_ID);
if (!state && output_port_id == port_id) {
x_offset += output->base.current->width;
wfd_output_destroy(&output->base);
continue;
}
if (x_offset != 0 || y_offset != 0) {
wlsc_output_move(&output->base,
output->base.x - x_offset,
output->base.y - y_offset);
}
}
if (ec->used_pipelines == 0)
wl_display_terminate(ec->base.wl_display);
return 0;
}
static int
on_wfd_event(int fd, uint32_t mask, void *data)
{
struct wfd_compositor *c = data;
struct wfd_output *output = NULL, *output_iter;
WFDEventType type;
const WFDtime timeout = 0;
WFDint pipeline_id;
WFDint bind_time;
type = wfdDeviceEventWait(c->dev, c->event, timeout);
switch (type) {
case WFD_EVENT_PIPELINE_BIND_SOURCE_COMPLETE:
pipeline_id =
wfdGetEventAttribi(c->dev, c->event,
WFD_EVENT_PIPELINE_BIND_PIPELINE_ID);
bind_time =
wfdGetEventAttribi(c->dev, c->event,
WFD_EVENT_PIPELINE_BIND_TIME_EXT);
wl_list_for_each(output_iter, &c->base.output_list, base.link) {
if (output_iter->pipeline_id == pipeline_id)
output = output_iter;
}
if (output == NULL)
return 1;
wlsc_output_finish_frame(&output->base,
c->start_time + bind_time);
break;
case WFD_EVENT_PORT_ATTACH_DETACH:
handle_port_state_change(c);
break;
default:
return 1;
}
return 1;
}
static void
wfd_destroy(struct wlsc_compositor *ec)
{
struct wfd_compositor *d = (struct wfd_compositor *) ec;
wlsc_compositor_shutdown(ec);
udev_unref(d->udev);
wfdDestroyDevice(d->dev);
tty_destroy(d->tty);
free(d);
}
/* FIXME: Just add a stub here for now
* handle drm{Set,Drop}Master in owfdrm somehow */
static void
vt_func(struct wlsc_compositor *compositor, int event)
{
return;
}
static const char default_seat[] = "seat0";
static struct wlsc_compositor *
wfd_compositor_create(struct wl_display *display,
int connector, const char *seat, int tty)
{
struct wfd_compositor *ec;
struct wl_event_loop *loop;
struct timeval tv;
ec = malloc(sizeof *ec);
if (ec == NULL)
return NULL;
memset(ec, 0, sizeof *ec);
gettimeofday(&tv, NULL);
ec->start_time = tv.tv_sec * 1000 + tv.tv_usec / 1000;
ec->udev = udev_new();
if (ec->udev == NULL) {
fprintf(stderr, "failed to initialize udev context\n");
return NULL;
}
ec->dev = wfdCreateDevice(WFD_DEFAULT_DEVICE_ID, NULL);
if (ec->dev == WFD_INVALID_HANDLE) {
fprintf(stderr, "failed to create wfd device\n");
return NULL;
}
ec->event = wfdCreateEvent(ec->dev, NULL);
if (ec->event == WFD_INVALID_HANDLE) {
fprintf(stderr, "failed to create wfd event\n");
return NULL;
}
ec->base.wl_display = display;
if (init_egl(ec) < 0) {
fprintf(stderr, "failed to initialize egl\n");
return NULL;
}
ec->base.destroy = wfd_destroy;
ec->base.focus = 1;
glGenFramebuffers(1, &ec->base.fbo);
glBindFramebuffer(GL_FRAMEBUFFER, ec->base.fbo);
/* Can't init base class until we have a current egl context */
if (wlsc_compositor_init(&ec->base, display) < 0)
return NULL;
if (create_outputs(ec, connector) < 0) {
fprintf(stderr, "failed to create outputs\n");
return NULL;
}
evdev_input_create(&ec->base, ec->udev, seat);
loop = wl_display_get_event_loop(ec->base.wl_display);
ec->wfd_source =
wl_event_loop_add_fd(loop,
wfdDeviceEventGetFD(ec->dev, ec->event),
WL_EVENT_READABLE, on_wfd_event, ec);
ec->tty = tty_create(&ec->base, vt_func, tty);
return &ec->base;
}
struct wlsc_compositor *
backend_init(struct wl_display *display, char *options);
WL_EXPORT struct wlsc_compositor *
backend_init(struct wl_display *display, char *options)
{
int connector = 0, i;
const char *seat;
char *p, *value;
int tty = 1;
static char * const tokens[] = { "connector", "seat", "tty", NULL };
p = options;
seat = default_seat;
while (i = getsubopt(&p, tokens, &value), i != -1) {
switch (i) {
case 0:
connector = strtol(value, NULL, 0);
break;
case 1:
seat = value;
break;
case 2:
tty = strtol(value, NULL, 0);
break;
}
}
return wfd_compositor_create(display, connector, seat, tty);
}
-587
View File
@@ -1,587 +0,0 @@
/*
* Copyright © 2010-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.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stddef.h>
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <wayland-client.h>
#include <wayland-egl.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include "compositor.h"
struct wayland_compositor {
struct wlsc_compositor base;
struct {
struct wl_display *display;
struct wl_compositor *compositor;
struct wl_shell *shell;
struct wl_output *output;
struct {
int32_t x, y, width, height;
} screen_allocation;
struct wl_event_source *wl_source;
uint32_t event_mask;
} parent;
struct wl_list input_list;
};
struct wayland_output {
struct wlsc_output base;
struct {
struct wl_surface *surface;
struct wl_shell_surface *shell_surface;
struct wl_egl_window *egl_window;
} parent;
EGLSurface egl_surface;
struct wlsc_mode mode;
};
struct wayland_input {
struct wayland_compositor *compositor;
struct wl_input_device *input_device;
struct wl_list link;
};
static int
wayland_input_create(struct wayland_compositor *c)
{
struct wlsc_input_device *input;
input = malloc(sizeof *input);
if (input == NULL)
return -1;
memset(input, 0, sizeof *input);
wlsc_input_device_init(input, &c->base);
c->base.input_device = &input->input_device;
return 0;
}
static int
wayland_compositor_init_egl(struct wayland_compositor *c)
{
EGLint major, minor;
EGLint n;
const char *extensions;
EGLint config_attribs[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RED_SIZE, 1,
EGL_GREEN_SIZE, 1,
EGL_BLUE_SIZE, 1,
EGL_ALPHA_SIZE, 0,
EGL_DEPTH_SIZE, 1,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_NONE
};
static const EGLint context_attribs[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
c->base.display = eglGetDisplay(c->parent.display);
if (c->base.display == NULL) {
fprintf(stderr, "failed to create display\n");
return -1;
}
if (!eglInitialize(c->base.display, &major, &minor)) {
fprintf(stderr, "failed to initialize display\n");
return -1;
}
extensions = eglQueryString(c->base.display, EGL_EXTENSIONS);
if (!strstr(extensions, "EGL_KHR_surfaceless_gles2")) {
fprintf(stderr, "EGL_KHR_surfaceless_gles2 not available\n");
return -1;
}
if (!eglBindAPI(EGL_OPENGL_ES_API)) {
fprintf(stderr, "failed to bind EGL_OPENGL_ES_API\n");
return -1;
}
if (!eglChooseConfig(c->base.display, config_attribs,
&c->base.config, 1, &n) || n == 0) {
fprintf(stderr, "failed to choose config: %d\n", n);
return -1;
}
c->base.context = eglCreateContext(c->base.display, c->base.config,
EGL_NO_CONTEXT, context_attribs);
if (c->base.context == NULL) {
fprintf(stderr, "failed to create context\n");
return -1;
}
if (!eglMakeCurrent(c->base.display, EGL_NO_SURFACE,
EGL_NO_SURFACE, c->base.context)) {
fprintf(stderr, "failed to make context current\n");
return -1;
}
return 0;
}
static int
wayland_output_prepare_render(struct wlsc_output *output_base)
{
struct wayland_output *output = (struct wayland_output *) output_base;
struct wlsc_compositor *ec = output->base.compositor;
if (!eglMakeCurrent(ec->display, output->egl_surface,
output->egl_surface, ec->context)) {
fprintf(stderr, "failed to make current\n");
return -1;
}
return 0;
}
static void
frame_done(void *data, struct wl_callback *wl_callback, uint32_t time)
{
struct wlsc_output *output = data;
wlsc_output_finish_frame(output, time);
}
static const struct wl_callback_listener frame_listener = {
frame_done
};
static int
wayland_output_present(struct wlsc_output *output_base)
{
struct wayland_output *output = (struct wayland_output *) output_base;
struct wayland_compositor *c =
(struct wayland_compositor *) output->base.compositor;
struct wl_callback *callback;
if (wayland_output_prepare_render(&output->base))
return -1;
eglSwapBuffers(c->base.display, output->egl_surface);
callback = wl_surface_frame(output->parent.surface);
wl_callback_add_listener(callback, &frame_listener, output);
return 0;
}
static int
wayland_output_prepare_scanout_surface(struct wlsc_output *output_base,
struct wlsc_surface *es)
{
return -1;
}
static int
wayland_output_set_cursor(struct wlsc_output *output_base,
struct wlsc_input_device *input)
{
return -1;
}
static void
wayland_output_destroy(struct wlsc_output *output_base)
{
struct wayland_output *output = (struct wayland_output *) output_base;
struct wlsc_compositor *ec = output->base.compositor;
eglDestroySurface(ec->display, output->egl_surface);
wl_egl_window_destroy(output->parent.egl_window);
free(output);
return;
}
static int
wayland_compositor_create_output(struct wayland_compositor *c,
int width, int height)
{
struct wayland_output *output;
output = malloc(sizeof *output);
if (output == NULL)
return -1;
memset(output, 0, sizeof *output);
output->mode.flags =
WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
output->mode.width = width;
output->mode.height = height;
output->mode.refresh = 60;
wl_list_init(&output->base.mode_list);
wl_list_insert(&output->base.mode_list, &output->mode.link);
output->base.current = &output->mode;
wlsc_output_init(&output->base, &c->base, 0, 0, width, height,
WL_OUTPUT_FLIPPED);
output->parent.surface =
wl_compositor_create_surface(c->parent.compositor);
wl_surface_set_user_data(output->parent.surface, output);
output->parent.egl_window =
wl_egl_window_create(output->parent.surface, width, height);
if (!output->parent.egl_window) {
fprintf(stderr, "failure to create wl_egl_window\n");
goto cleanup_output;
}
output->egl_surface =
eglCreateWindowSurface(c->base.display, c->base.config,
output->parent.egl_window, NULL);
if (!output->egl_surface) {
fprintf(stderr, "failed to create window surface\n");
goto cleanup_window;
}
if (!eglMakeCurrent(c->base.display, output->egl_surface,
output->egl_surface, c->base.context)) {
fprintf(stderr, "failed to make surface current\n");
goto cleanup_surface;
return -1;
}
output->parent.shell_surface =
wl_shell_get_shell_surface(c->parent.shell,
output->parent.surface);
/* FIXME: add shell_surface listener for resizing */
wl_shell_surface_set_toplevel(output->parent.shell_surface);
glClearColor(0, 0, 0, 0.5);
output->base.prepare_render = wayland_output_prepare_render;
output->base.present = wayland_output_present;
output->base.prepare_scanout_surface =
wayland_output_prepare_scanout_surface;
output->base.set_hardware_cursor = wayland_output_set_cursor;
output->base.destroy = wayland_output_destroy;
wl_list_insert(c->base.output_list.prev, &output->base.link);
return 0;
cleanup_surface:
eglDestroySurface(c->base.display, output->egl_surface);
cleanup_window:
wl_egl_window_destroy(output->parent.egl_window);
cleanup_output:
/* FIXME: cleanup wlsc_output */
free(output);
return -1;
}
/* Events received from the wayland-server this compositor is client of: */
/* parent output interface */
static void
display_handle_geometry(void *data,
struct wl_output *wl_output,
int x,
int y,
int physical_width,
int physical_height,
int subpixel,
const char *make,
const char *model)
{
struct wayland_compositor *c = data;
c->parent.screen_allocation.x = x;
c->parent.screen_allocation.y = y;
}
static void
display_handle_mode(void *data,
struct wl_output *wl_output,
uint32_t flags,
int width,
int height,
int refresh)
{
struct wayland_compositor *c = data;
c->parent.screen_allocation.width = width;
c->parent.screen_allocation.height = height;
}
static const struct wl_output_listener output_listener = {
display_handle_geometry,
display_handle_mode
};
/* parent input interface */
static void
input_handle_motion(void *data, struct wl_input_device *input_device,
uint32_t time,
int32_t x, int32_t y, int32_t sx, int32_t sy)
{
struct wayland_input *input = data;
struct wayland_compositor *c = input->compositor;
notify_motion(c->base.input_device, time, sx, sy);
}
static void
input_handle_button(void *data,
struct wl_input_device *input_device,
uint32_t time, uint32_t button, uint32_t state)
{
struct wayland_input *input = data;
struct wayland_compositor *c = input->compositor;
notify_button(c->base.input_device, time, button, state);
}
static void
input_handle_key(void *data, struct wl_input_device *input_device,
uint32_t time, uint32_t key, uint32_t state)
{
struct wayland_input *input = data;
struct wayland_compositor *c = input->compositor;
notify_key(c->base.input_device, time, key, state);
}
static void
input_handle_pointer_focus(void *data,
struct wl_input_device *input_device,
uint32_t time, struct wl_surface *surface,
int32_t x, int32_t y, int32_t sx, int32_t sy)
{
struct wayland_input *input = data;
struct wayland_output *output;
struct wayland_compositor *c = input->compositor;
if (surface) {
output = wl_surface_get_user_data(surface);
notify_pointer_focus(c->base.input_device,
time, &output->base, sx, sy);
} else {
notify_pointer_focus(c->base.input_device, time, NULL, 0, 0);
}
}
static void
input_handle_keyboard_focus(void *data,
struct wl_input_device *input_device,
uint32_t time,
struct wl_surface *surface,
struct wl_array *keys)
{
struct wayland_input *input = data;
struct wayland_compositor *c = input->compositor;
struct wayland_output *output;
if (surface) {
output = wl_surface_get_user_data(surface);
notify_keyboard_focus(c->base.input_device,
time, &output->base, keys);
} else {
notify_keyboard_focus(c->base.input_device, time, NULL, NULL);
}
}
static const struct wl_input_device_listener input_device_listener = {
input_handle_motion,
input_handle_button,
input_handle_key,
input_handle_pointer_focus,
input_handle_keyboard_focus,
};
static void
display_add_input(struct wayland_compositor *c, uint32_t id)
{
struct wayland_input *input;
input = malloc(sizeof *input);
if (input == NULL)
return;
memset(input, 0, sizeof *input);
input->compositor = c;
input->input_device = wl_display_bind(c->parent.display,
id, &wl_input_device_interface);
wl_list_insert(c->input_list.prev, &input->link);
wl_input_device_add_listener(input->input_device,
&input_device_listener, input);
wl_input_device_set_user_data(input->input_device, input);
}
static void
display_handle_global(struct wl_display *display, uint32_t id,
const char *interface, uint32_t version, void *data)
{
struct wayland_compositor *c = data;
if (strcmp(interface, "wl_compositor") == 0) {
c->parent.compositor =
wl_display_bind(display, id, &wl_compositor_interface);
} else if (strcmp(interface, "wl_output") == 0) {
c->parent.output =
wl_display_bind(display, id, &wl_output_interface);
wl_output_add_listener(c->parent.output, &output_listener, c);
} else if (strcmp(interface, "wl_input_device") == 0) {
display_add_input(c, id);
} else if (strcmp(interface, "wl_shell") == 0) {
c->parent.shell =
wl_display_bind(display, id, &wl_shell_interface);
}
}
static int
update_event_mask(uint32_t mask, void *data)
{
struct wayland_compositor *c = data;
c->parent.event_mask = mask;
if (c->parent.wl_source)
wl_event_source_fd_update(c->parent.wl_source, mask);
return 0;
}
static int
wayland_compositor_handle_event(int fd, uint32_t mask, void *data)
{
struct wayland_compositor *c = data;
if (mask & WL_EVENT_READABLE)
wl_display_iterate(c->parent.display, WL_DISPLAY_READABLE);
if (mask & WL_EVENT_WRITABLE)
wl_display_iterate(c->parent.display, WL_DISPLAY_WRITABLE);
return 1;
}
static void
wayland_destroy(struct wlsc_compositor *ec)
{
wlsc_compositor_shutdown(ec);
free(ec);
}
static struct wlsc_compositor *
wayland_compositor_create(struct wl_display *display, int width, int height)
{
struct wayland_compositor *c;
struct wl_event_loop *loop;
int fd;
c = malloc(sizeof *c);
if (c == NULL)
return NULL;
memset(c, 0, sizeof *c);
c->parent.display = wl_display_connect(NULL);
if (c->parent.display == NULL) {
fprintf(stderr, "failed to create display: %m\n");
return NULL;
}
wl_list_init(&c->input_list);
wl_display_add_global_listener(c->parent.display,
display_handle_global, c);
wl_display_iterate(c->parent.display, WL_DISPLAY_READABLE);
c->base.wl_display = display;
if (wayland_compositor_init_egl(c) < 0)
return NULL;
c->base.destroy = wayland_destroy;
/* Can't init base class until we have a current egl context */
if (wlsc_compositor_init(&c->base, display) < 0)
return NULL;
if (wayland_compositor_create_output(c, width, height) < 0)
return NULL;
if (wayland_input_create(c) < 0)
return NULL;
loop = wl_display_get_event_loop(c->base.wl_display);
fd = wl_display_get_fd(c->parent.display, update_event_mask, c);
c->parent.wl_source =
wl_event_loop_add_fd(loop, fd, c->parent.event_mask,
wayland_compositor_handle_event, c);
if (c->parent.wl_source == NULL)
return NULL;
return &c->base;
}
struct wlsc_compositor *
backend_init(struct wl_display *display, char *options);
WL_EXPORT struct wlsc_compositor *
backend_init(struct wl_display *display, char *options)
{
int width = 1024, height = 640, i;
char *p, *value;
static char * const tokens[] = { "width", "height", NULL };
p = options;
while (i = getsubopt(&p, tokens, &value), i != -1) {
switch (i) {
case 0:
width = strtol(value, NULL, 0);
break;
case 1:
height = strtol(value, NULL, 0);
break;
}
}
return wayland_compositor_create(display, width, height);
}
-835
View File
@@ -1,835 +0,0 @@
/*
* Copyright © 2008-2011 Kristian Høgsberg
* Copyright © 2010-2011 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.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/time.h>
#include <linux/input.h>
#include <xcb/xcb.h>
#include <X11/Xlib.h>
#include <X11/Xlib-xcb.h>
#include <GLES2/gl2.h>
#include <EGL/egl.h>
#include "compositor.h"
struct x11_compositor {
struct wlsc_compositor base;
Display *dpy;
xcb_connection_t *conn;
xcb_screen_t *screen;
xcb_cursor_t null_cursor;
struct wl_array keys;
struct wl_event_source *xcb_source;
struct {
xcb_atom_t wm_protocols;
xcb_atom_t wm_normal_hints;
xcb_atom_t wm_size_hints;
xcb_atom_t wm_delete_window;
xcb_atom_t wm_class;
xcb_atom_t net_wm_name;
xcb_atom_t net_wm_icon;
xcb_atom_t net_wm_state;
xcb_atom_t net_wm_state_fullscreen;
xcb_atom_t string;
xcb_atom_t utf8_string;
xcb_atom_t cardinal;
} atom;
};
struct x11_output {
struct wlsc_output base;
xcb_window_t window;
EGLSurface egl_surface;
struct wlsc_mode mode;
struct wl_event_source *finish_frame_timer;
};
struct x11_input {
struct wlsc_input_device base;
};
static int
x11_input_create(struct x11_compositor *c)
{
struct x11_input *input;
input = malloc(sizeof *input);
if (input == NULL)
return -1;
memset(input, 0, sizeof *input);
wlsc_input_device_init(&input->base, &c->base);
c->base.input_device = &input->base.input_device;
return 0;
}
static int
x11_compositor_init_egl(struct x11_compositor *c)
{
EGLint major, minor;
EGLint n;
const char *extensions;
EGLint config_attribs[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RED_SIZE, 1,
EGL_GREEN_SIZE, 1,
EGL_BLUE_SIZE, 1,
EGL_DEPTH_SIZE, 1,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_NONE
};
static const EGLint context_attribs[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
c->base.display = eglGetDisplay(c->dpy);
if (c->base.display == NULL) {
fprintf(stderr, "failed to create display\n");
return -1;
}
if (!eglInitialize(c->base.display, &major, &minor)) {
fprintf(stderr, "failed to initialize display\n");
return -1;
}
extensions = eglQueryString(c->base.display, EGL_EXTENSIONS);
if (!strstr(extensions, "EGL_KHR_surfaceless_gles2")) {
fprintf(stderr, "EGL_KHR_surfaceless_gles2 not available\n");
return -1;
}
if (!eglBindAPI(EGL_OPENGL_ES_API)) {
fprintf(stderr, "failed to bind EGL_OPENGL_ES_API\n");
return -1;
}
if (!eglChooseConfig(c->base.display, config_attribs,
&c->base.config, 1, &n) || n == 0) {
fprintf(stderr, "failed to choose config: %d\n", n);
return -1;
}
c->base.context = eglCreateContext(c->base.display, c->base.config,
EGL_NO_CONTEXT, context_attribs);
if (c->base.context == NULL) {
fprintf(stderr, "failed to create context\n");
return -1;
}
if (!eglMakeCurrent(c->base.display, EGL_NO_SURFACE,
EGL_NO_SURFACE, c->base.context)) {
fprintf(stderr, "failed to make context current\n");
return -1;
}
return 0;
}
static int
x11_output_prepare_render(struct wlsc_output *output_base)
{
struct x11_output *output = (struct x11_output *) output_base;
struct wlsc_compositor *ec = output->base.compositor;
if (!eglMakeCurrent(ec->display, output->egl_surface,
output->egl_surface, ec->context)) {
fprintf(stderr, "failed to make current\n");
return -1;
}
return 0;
}
static int
finish_frame_handler(void *data)
{
struct x11_output *output = data;
uint32_t msec;
struct timeval tv;
gettimeofday(&tv, NULL);
msec = tv.tv_sec * 1000 + tv.tv_usec / 1000;
wlsc_output_finish_frame(&output->base, msec);
return 1;
}
static int
x11_output_present(struct wlsc_output *output_base)
{
struct x11_output *output = (struct x11_output *) output_base;
struct wlsc_compositor *ec = output->base.compositor;
if (x11_output_prepare_render(&output->base))
return -1;
eglSwapBuffers(ec->display, output->egl_surface);
wl_event_source_timer_update(output->finish_frame_timer, 10);
return 0;
}
static int
x11_output_prepare_scanout_surface(struct wlsc_output *output_base,
struct wlsc_surface *es)
{
return -1;
}
static int
x11_output_set_cursor(struct wlsc_output *output_base,
struct wlsc_input_device *input)
{
return -1;
}
static void
x11_output_destroy(struct wlsc_output *output_base)
{
return;
}
static void
x11_output_set_wm_protocols(struct x11_output *output)
{
xcb_atom_t list[1];
struct x11_compositor *c =
(struct x11_compositor *) output->base.compositor;
list[0] = c->atom.wm_delete_window;
xcb_change_property (c->conn,
XCB_PROP_MODE_REPLACE,
output->window,
c->atom.wm_protocols,
XCB_ATOM_ATOM,
32,
ARRAY_LENGTH(list),
list);
}
static void
x11_output_change_state(struct x11_output *output, int add, xcb_atom_t state)
{
xcb_client_message_event_t event;
struct x11_compositor *c =
(struct x11_compositor *) output->base.compositor;
xcb_screen_iterator_t iter;
#define _NET_WM_STATE_REMOVE 0 /* remove/unset property */
#define _NET_WM_STATE_ADD 1 /* add/set property */
#define _NET_WM_STATE_TOGGLE 2 /* toggle property */
memset(&event, 0, sizeof event);
event.response_type = XCB_CLIENT_MESSAGE;
event.format = 32;
event.window = output->window;
event.type = c->atom.net_wm_state;
event.data.data32[0] = add ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
event.data.data32[1] = state;
event.data.data32[2] = 0;
event.data.data32[3] = 0;
event.data.data32[4] = 0;
iter = xcb_setup_roots_iterator(xcb_get_setup(c->conn));
xcb_send_event(c->conn, 0, iter.data->root,
XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT,
(void *) &event);
}
struct wm_normal_hints {
uint32_t flags;
uint32_t pad[4];
int32_t min_width, min_height;
int32_t max_width, max_height;
int32_t width_inc, height_inc;
int32_t min_aspect_x, min_aspect_y;
int32_t max_aspect_x, max_aspect_y;
int32_t base_width, base_height;
int32_t win_gravity;
};
#define WM_NORMAL_HINTS_MIN_SIZE 16
#define WM_NORMAL_HINTS_MAX_SIZE 32
static void
x11_output_set_icon(struct x11_compositor *c,
struct x11_output *output, const char *filename)
{
uint32_t *icon, *pixels, stride;
int32_t width, height;
pixels = wlsc_load_image(filename, &width, &height, &stride);
if (!pixels)
return;
icon = malloc(width * height * 4 + 8);
if (!icon) {
free(pixels);
return;
}
icon[0] = width;
icon[1] = height;
memcpy(icon + 2, pixels, width * height * 4);
xcb_change_property(c->conn, XCB_PROP_MODE_REPLACE, output->window,
c->atom.net_wm_icon, c->atom.cardinal, 32,
width * height + 2, icon);
free(icon);
free(pixels);
}
static int
x11_compositor_create_output(struct x11_compositor *c, int x, int y,
int width, int height, int fullscreen)
{
static const char name[] = "Wayland Compositor";
static const char class[] = "wayland-1\0Wayland Compositor";
struct x11_output *output;
xcb_screen_iterator_t iter;
struct wm_normal_hints normal_hints;
struct wl_event_loop *loop;
uint32_t mask = XCB_CW_EVENT_MASK | XCB_CW_CURSOR;
uint32_t values[2] = {
XCB_EVENT_MASK_KEY_PRESS |
XCB_EVENT_MASK_KEY_RELEASE |
XCB_EVENT_MASK_BUTTON_PRESS |
XCB_EVENT_MASK_BUTTON_RELEASE |
XCB_EVENT_MASK_POINTER_MOTION |
XCB_EVENT_MASK_EXPOSURE |
XCB_EVENT_MASK_STRUCTURE_NOTIFY |
XCB_EVENT_MASK_ENTER_WINDOW |
XCB_EVENT_MASK_LEAVE_WINDOW |
XCB_EVENT_MASK_KEYMAP_STATE |
XCB_EVENT_MASK_FOCUS_CHANGE,
0
};
output = malloc(sizeof *output);
if (output == NULL)
return -1;
memset(output, 0, sizeof *output);
output->mode.flags =
WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
output->mode.width = width;
output->mode.height = height;
output->mode.refresh = 60;
wl_list_init(&output->base.mode_list);
wl_list_insert(&output->base.mode_list, &output->mode.link);
output->base.current = &output->mode;
wlsc_output_init(&output->base, &c->base, x, y, width, height,
WL_OUTPUT_FLIPPED);
values[1] = c->null_cursor;
output->window = xcb_generate_id(c->conn);
iter = xcb_setup_roots_iterator(xcb_get_setup(c->conn));
xcb_create_window(c->conn,
XCB_COPY_FROM_PARENT,
output->window,
iter.data->root,
0, 0,
width, height,
0,
XCB_WINDOW_CLASS_INPUT_OUTPUT,
iter.data->root_visual,
mask, values);
/* Don't resize me. */
memset(&normal_hints, 0, sizeof normal_hints);
normal_hints.flags =
WM_NORMAL_HINTS_MAX_SIZE | WM_NORMAL_HINTS_MIN_SIZE;
normal_hints.min_width = width;
normal_hints.min_height = height;
normal_hints.max_width = width;
normal_hints.max_height = height;
xcb_change_property (c->conn, XCB_PROP_MODE_REPLACE, output->window,
c->atom.wm_normal_hints,
c->atom.wm_size_hints, 32,
sizeof normal_hints / 4,
(uint8_t *) &normal_hints);
/* Set window name. Don't bother with non-EWMH WMs. */
xcb_change_property(c->conn, XCB_PROP_MODE_REPLACE, output->window,
c->atom.net_wm_name, c->atom.utf8_string, 8,
strlen(name), name);
xcb_change_property(c->conn, XCB_PROP_MODE_REPLACE, output->window,
c->atom.wm_class, c->atom.string, 8,
sizeof class, class);
x11_output_set_icon(c, output, DATADIR "/wayland/wayland.png");
xcb_map_window(c->conn, output->window);
x11_output_set_wm_protocols(output);
if (fullscreen)
x11_output_change_state(output, 1,
c->atom.net_wm_state_fullscreen);
output->egl_surface =
eglCreateWindowSurface(c->base.display, c->base.config,
output->window, NULL);
if (!output->egl_surface) {
fprintf(stderr, "failed to create window surface\n");
return -1;
}
if (!eglMakeCurrent(c->base.display, output->egl_surface,
output->egl_surface, c->base.context)) {
fprintf(stderr, "failed to make surface current\n");
return -1;
}
loop = wl_display_get_event_loop(c->base.wl_display);
output->finish_frame_timer =
wl_event_loop_add_timer(loop, finish_frame_handler, output);
output->base.prepare_render = x11_output_prepare_render;
output->base.present = x11_output_present;
output->base.prepare_scanout_surface =
x11_output_prepare_scanout_surface;
output->base.set_hardware_cursor = x11_output_set_cursor;
output->base.destroy = x11_output_destroy;
wl_list_insert(c->base.output_list.prev, &output->base.link);
return 0;
}
static struct x11_output *
x11_compositor_find_output(struct x11_compositor *c, xcb_window_t window)
{
struct x11_output *output;
wl_list_for_each(output, &c->base.output_list, base.link) {
if (output->window == window)
return output;
}
return NULL;
}
static void
x11_compositor_deliver_button_event(struct x11_compositor *c,
xcb_generic_event_t *event, int state)
{
xcb_button_press_event_t *button_event =
(xcb_button_press_event_t *) event;
int button;
switch (button_event->detail) {
default:
button = button_event->detail + BTN_LEFT - 1;
break;
case 2:
button = BTN_MIDDLE;
break;
case 3:
button = BTN_RIGHT;
break;
case 4:
case 5:
case 6:
case 7:
/* X11 sends wheel events as buttons events. But
* linux input treats as REL_WHEEL, therefore not
* button type at all. When we update the input
* protocol and get the 'axis' event, we'll send
* scroll events as axis events. */
return;
}
notify_button(c->base.input_device,
wlsc_compositor_get_time(), button, state);
}
static int
x11_compositor_next_event(struct x11_compositor *c,
xcb_generic_event_t **event, uint32_t mask)
{
if (mask & WL_EVENT_READABLE) {
*event = xcb_poll_for_event(c->conn);
} else {
#ifdef HAVE_XCB_POLL_FOR_QUEUED_EVENT
*event = xcb_poll_for_queued_event(c->conn);
#else
*event = xcb_poll_for_event(c->conn);
#endif
}
return *event != NULL;
}
static int
x11_compositor_handle_event(int fd, uint32_t mask, void *data)
{
struct x11_compositor *c = data;
struct x11_output *output;
xcb_generic_event_t *event, *prev;
xcb_client_message_event_t *client_message;
xcb_motion_notify_event_t *motion_notify;
xcb_enter_notify_event_t *enter_notify;
xcb_key_press_event_t *key_press, *key_release;
xcb_keymap_notify_event_t *keymap_notify;
xcb_focus_in_event_t *focus_in;
xcb_atom_t atom;
uint32_t *k;
int i, set;
prev = NULL;
while (x11_compositor_next_event(c, &event, mask)) {
switch (prev ? prev->response_type & ~0x80 : 0x80) {
case XCB_KEY_RELEASE:
key_release = (xcb_key_press_event_t *) prev;
key_press = (xcb_key_press_event_t *) event;
if ((event->response_type & ~0x80) == XCB_KEY_PRESS &&
key_release->time == key_press->time &&
key_release->detail == key_press->detail) {
/* Don't deliver the held key release
* event or the new key press event. */
free(event);
free(prev);
prev = NULL;
continue;
} else {
/* Deliver the held key release now
* and fall through and handle the new
* event below. */
notify_key(c->base.input_device,
wlsc_compositor_get_time(),
key_release->detail - 8, 0);
free(prev);
prev = NULL;
break;
}
case XCB_FOCUS_IN:
/* assert event is keymap_notify */
focus_in = (xcb_focus_in_event_t *) prev;
keymap_notify = (xcb_keymap_notify_event_t *) event;
c->keys.size = 0;
for (i = 0; i < ARRAY_LENGTH(keymap_notify->keys) * 8; i++) {
set = keymap_notify->keys[i >> 3] &
(1 << (i & 7));
if (set) {
k = wl_array_add(&c->keys, sizeof *k);
*k = i;
}
}
output = x11_compositor_find_output(c, focus_in->event);
notify_keyboard_focus(c->base.input_device,
wlsc_compositor_get_time(),
&output->base, &c->keys);
free(prev);
prev = NULL;
break;
default:
/* No previous event held */
break;
}
switch (event->response_type & ~0x80) {
case XCB_KEY_PRESS:
key_press = (xcb_key_press_event_t *) event;
notify_key(c->base.input_device,
wlsc_compositor_get_time(),
key_press->detail - 8, 1);
break;
case XCB_KEY_RELEASE:
prev = event;
break;
case XCB_BUTTON_PRESS:
x11_compositor_deliver_button_event(c, event, 1);
break;
case XCB_BUTTON_RELEASE:
x11_compositor_deliver_button_event(c, event, 0);
break;
case XCB_MOTION_NOTIFY:
motion_notify = (xcb_motion_notify_event_t *) event;
output = x11_compositor_find_output(c, motion_notify->event);
notify_motion(c->base.input_device,
wlsc_compositor_get_time(),
output->base.x + motion_notify->event_x,
output->base.y + motion_notify->event_y);
break;
case XCB_EXPOSE:
/* FIXME: schedule output repaint */
/* output = x11_compositor_find_output(c, expose->window); */
wlsc_compositor_schedule_repaint(&c->base);
break;
case XCB_ENTER_NOTIFY:
enter_notify = (xcb_enter_notify_event_t *) event;
if (enter_notify->state >= Button1Mask)
break;
output = x11_compositor_find_output(c, enter_notify->event);
notify_pointer_focus(c->base.input_device,
wlsc_compositor_get_time(),
&output->base,
output->base.x + enter_notify->event_x,
output->base.y + enter_notify->event_y);
break;
case XCB_LEAVE_NOTIFY:
enter_notify = (xcb_enter_notify_event_t *) event;
if (enter_notify->state >= Button1Mask)
break;
output = x11_compositor_find_output(c, enter_notify->event);
notify_pointer_focus(c->base.input_device,
wlsc_compositor_get_time(),
NULL,
output->base.x + enter_notify->event_x,
output->base.y + enter_notify->event_y);
break;
case XCB_CLIENT_MESSAGE:
client_message = (xcb_client_message_event_t *) event;
atom = client_message->data.data32[0];
if (atom == c->atom.wm_delete_window)
wl_display_terminate(c->base.wl_display);
break;
case XCB_FOCUS_IN:
focus_in = (xcb_focus_in_event_t *) event;
if (focus_in->mode == XCB_NOTIFY_MODE_WHILE_GRABBED)
break;
prev = event;
break;
case XCB_FOCUS_OUT:
focus_in = (xcb_focus_in_event_t *) event;
if (focus_in->mode == XCB_NOTIFY_MODE_WHILE_GRABBED ||
focus_in->mode == XCB_NOTIFY_MODE_UNGRAB)
break;
notify_keyboard_focus(c->base.input_device,
wlsc_compositor_get_time(),
NULL, NULL);
break;
default:
break;
}
if (prev != event)
free (event);
}
switch (prev ? prev->response_type & ~0x80 : 0x80) {
case XCB_KEY_RELEASE:
key_release = (xcb_key_press_event_t *) prev;
notify_key(c->base.input_device,
wlsc_compositor_get_time(),
key_release->detail - 8, 0);
free(prev);
prev = NULL;
break;
default:
break;
}
return event != NULL;
}
#define F(field) offsetof(struct x11_compositor, field)
static void
x11_compositor_get_resources(struct x11_compositor *c)
{
static const struct { const char *name; int offset; } atoms[] = {
{ "WM_PROTOCOLS", F(atom.wm_protocols) },
{ "WM_NORMAL_HINTS", F(atom.wm_normal_hints) },
{ "WM_SIZE_HINTS", F(atom.wm_size_hints) },
{ "WM_DELETE_WINDOW", F(atom.wm_delete_window) },
{ "WM_CLASS", F(atom.wm_class) },
{ "_NET_WM_NAME", F(atom.net_wm_name) },
{ "_NET_WM_ICON", F(atom.net_wm_icon) },
{ "_NET_WM_STATE", F(atom.net_wm_state) },
{ "_NET_WM_STATE_FULLSCREEN", F(atom.net_wm_state_fullscreen) },
{ "STRING", F(atom.string) },
{ "UTF8_STRING", F(atom.utf8_string) },
{ "CARDINAL", F(atom.cardinal) },
};
xcb_intern_atom_cookie_t cookies[ARRAY_LENGTH(atoms)];
xcb_intern_atom_reply_t *reply;
xcb_pixmap_t pixmap;
xcb_gc_t gc;
int i;
uint8_t data[] = { 0, 0, 0, 0 };
for (i = 0; i < ARRAY_LENGTH(atoms); i++)
cookies[i] = xcb_intern_atom (c->conn, 0,
strlen(atoms[i].name),
atoms[i].name);
for (i = 0; i < ARRAY_LENGTH(atoms); i++) {
reply = xcb_intern_atom_reply (c->conn, cookies[i], NULL);
*(xcb_atom_t *) ((char *) c + atoms[i].offset) = reply->atom;
free(reply);
}
pixmap = xcb_generate_id(c->conn);
gc = xcb_generate_id(c->conn);
xcb_create_pixmap(c->conn, 1, pixmap, c->screen->root, 1, 1);
xcb_create_gc(c->conn, gc, pixmap, 0, NULL);
xcb_put_image(c->conn, XCB_IMAGE_FORMAT_XY_PIXMAP,
pixmap, gc, 1, 1, 0, 0, 0, 32, sizeof data, data);
c->null_cursor = xcb_generate_id(c->conn);
xcb_create_cursor (c->conn, c->null_cursor,
pixmap, pixmap, 0, 0, 0, 0, 0, 0, 1, 1);
xcb_free_gc(c->conn, gc);
xcb_free_pixmap(c->conn, pixmap);
}
static void
x11_destroy(struct wlsc_compositor *ec)
{
wlsc_compositor_shutdown(ec);
free(ec);
}
static struct wlsc_compositor *
x11_compositor_create(struct wl_display *display,
int width, int height, int count, int fullscreen)
{
struct x11_compositor *c;
struct wl_event_loop *loop;
xcb_screen_iterator_t s;
int i, x;
c = malloc(sizeof *c);
if (c == NULL)
return NULL;
memset(c, 0, sizeof *c);
c->dpy = XOpenDisplay(NULL);
if (c->dpy == NULL)
return NULL;
c->conn = XGetXCBConnection(c->dpy);
XSetEventQueueOwner(c->dpy, XCBOwnsEventQueue);
if (xcb_connection_has_error(c->conn))
return NULL;
s = xcb_setup_roots_iterator(xcb_get_setup(c->conn));
c->screen = s.data;
wl_array_init(&c->keys);
x11_compositor_get_resources(c);
c->base.wl_display = display;
if (x11_compositor_init_egl(c) < 0)
return NULL;
c->base.destroy = x11_destroy;
/* Can't init base class until we have a current egl context */
if (wlsc_compositor_init(&c->base, display) < 0)
return NULL;
for (i = 0, x = 0; i < count; i++) {
if (x11_compositor_create_output(c, x, 0, width, height,
fullscreen) < 0)
return NULL;
x += width;
}
if (x11_input_create(c) < 0)
return NULL;
loop = wl_display_get_event_loop(c->base.wl_display);
c->xcb_source =
wl_event_loop_add_fd(loop, xcb_get_file_descriptor(c->conn),
WL_EVENT_READABLE,
x11_compositor_handle_event, c);
wl_event_source_check(c->xcb_source);
return &c->base;
}
struct wlsc_compositor *
backend_init(struct wl_display *display, char *options);
WL_EXPORT struct wlsc_compositor *
backend_init(struct wl_display *display, char *options)
{
int width = 1024, height = 640, fullscreen = 0, count = 1, i;
char *p, *value;
static char * const tokens[] = {
"width", "height", "fullscreen", "output-count", NULL
};
p = options;
while (i = getsubopt(&p, tokens, &value), i != -1) {
switch (i) {
case 0:
width = strtol(value, NULL, 0);
break;
case 1:
height = strtol(value, NULL, 0);
break;
case 2:
fullscreen = 1;
break;
case 3:
count = strtol(value, NULL, 0);
break;
}
}
return x11_compositor_create(display,
width, height, count, fullscreen);
}
File diff suppressed because it is too large Load Diff
-470
View File
@@ -1,470 +0,0 @@
/*
* Copyright © 2008-2011 Kristian Høgsberg
*
* 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.
*/
#ifndef _WAYLAND_SYSTEM_COMPOSITOR_H_
#define _WAYLAND_SYSTEM_COMPOSITOR_H_
#include <libudev.h>
#include <pixman.h>
#include <wayland-server.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
struct wlsc_matrix {
GLfloat d[16];
};
struct wlsc_vector {
GLfloat f[4];
};
void
wlsc_matrix_init(struct wlsc_matrix *matrix);
void
wlsc_matrix_scale(struct wlsc_matrix *matrix, GLfloat x, GLfloat y, GLfloat z);
void
wlsc_matrix_translate(struct wlsc_matrix *matrix,
GLfloat x, GLfloat y, GLfloat z);
void
wlsc_matrix_transform(struct wlsc_matrix *matrix, struct wlsc_vector *v);
struct wlsc_transform {
struct wlsc_matrix matrix;
struct wlsc_matrix inverse;
};
struct wlsc_surface;
struct wlsc_input_device;
struct wlsc_mode {
uint32_t flags;
int32_t width, height;
uint32_t refresh;
struct wl_list link;
};
struct wlsc_output {
struct wl_list link;
struct wlsc_compositor *compositor;
struct wlsc_matrix matrix;
struct wl_list frame_callback_list;
int32_t x, y, mm_width, mm_height;
pixman_region32_t region;
pixman_region32_t previous_damage;
uint32_t flags;
int repaint_needed;
int repaint_scheduled;
char *make, *model;
uint32_t subpixel;
struct wlsc_mode *current;
struct wl_list mode_list;
struct wl_buffer *scanout_buffer;
struct wl_listener scanout_buffer_destroy_listener;
struct wl_buffer *pending_scanout_buffer;
struct wl_listener pending_scanout_buffer_destroy_listener;
int (*prepare_render)(struct wlsc_output *output);
int (*present)(struct wlsc_output *output);
int (*prepare_scanout_surface)(struct wlsc_output *output,
struct wlsc_surface *es);
int (*set_hardware_cursor)(struct wlsc_output *output,
struct wlsc_input_device *input);
void (*destroy)(struct wlsc_output *output);
};
struct wlsc_input_device {
struct wl_input_device input_device;
struct wlsc_compositor *compositor;
struct wlsc_surface *sprite;
int32_t hotspot_x, hotspot_y;
struct wl_list link;
uint32_t modifier_state;
struct wl_selection *selection;
struct wl_list drag_resource_list;
struct wlsc_data_source *drag_data_source;
struct wl_surface *drag_focus;
struct wl_resource *drag_focus_resource;
struct wl_listener drag_focus_listener;
struct wlsc_data_source *selection_data_source;
struct wl_listener selection_data_source_listener;
struct wl_grab grab;
uint32_t num_tp;
struct wl_surface *touch_focus;
struct wl_listener touch_focus_listener;
struct wl_resource *touch_focus_resource;
struct wl_listener touch_focus_resource_listener;
};
enum wlsc_visual {
WLSC_NONE_VISUAL,
WLSC_ARGB_VISUAL,
WLSC_PREMUL_ARGB_VISUAL,
WLSC_RGB_VISUAL
};
struct wlsc_shader {
GLuint program;
GLuint vertex_shader, fragment_shader;
GLuint proj_uniform;
GLuint tex_uniform;
GLuint alpha_uniform;
GLuint color_uniform;
};
struct wlsc_animation {
void (*frame)(struct wlsc_animation *animation,
struct wlsc_output *output, uint32_t msecs);
struct wl_list link;
};
struct wlsc_spring {
double k;
double friction;
double current;
double target;
double previous;
uint32_t timestamp;
};
struct wlsc_shell {
void (*lock)(struct wlsc_shell *shell);
void (*unlock)(struct wlsc_shell *shell);
void (*map)(struct wlsc_shell *shell, struct wlsc_surface *surface,
int32_t width, int32_t height);
void (*configure)(struct wlsc_shell *shell,
struct wlsc_surface *surface,
int32_t x, int32_t y, int32_t width, int32_t height);
};
enum {
WLSC_COMPOSITOR_ACTIVE,
WLSC_COMPOSITOR_IDLE, /* shell->unlock called on activity */
WLSC_COMPOSITOR_SLEEPING /* no rendering, no frame events */
};
struct wlsc_compositor {
struct wl_shm *shm;
struct wlsc_xserver *wxs;
EGLDisplay display;
EGLContext context;
EGLConfig config;
GLuint fbo;
GLuint proj_uniform, tex_uniform, alpha_uniform;
uint32_t current_alpha;
struct wlsc_shader texture_shader;
struct wlsc_shader solid_shader;
struct wl_display *wl_display;
struct wlsc_shell *shell;
/* There can be more than one, but not right now... */
struct wl_input_device *input_device;
struct wl_list output_list;
struct wl_list input_device_list;
struct wl_list surface_list;
struct wl_list binding_list;
struct wl_list animation_list;
struct {
struct wlsc_spring spring;
struct wlsc_animation animation;
} fade;
uint32_t state;
struct wl_event_source *idle_source;
uint32_t idle_inhibit;
int option_idle_time; /* default timeout, s */
int idle_time; /* effective timeout, s */
/* Repaint state. */
struct timespec previous_swap;
struct wl_array vertices, indices;
struct wlsc_surface *overlay;
struct wlsc_switcher *switcher;
uint32_t focus;
PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC
image_target_renderbuffer_storage;
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC image_target_texture_2d;
PFNEGLCREATEIMAGEKHRPROC create_image;
PFNEGLDESTROYIMAGEKHRPROC destroy_image;
PFNEGLBINDWAYLANDDISPLAYWL bind_display;
PFNEGLUNBINDWAYLANDDISPLAYWL unbind_display;
int has_bind_display;
void (*destroy)(struct wlsc_compositor *ec);
int (*authenticate)(struct wlsc_compositor *c, uint32_t id);
EGLImageKHR (*create_cursor_image)(struct wlsc_compositor *c,
int32_t *width, int32_t *height);
};
#define MODIFIER_CTRL (1 << 8)
#define MODIFIER_ALT (1 << 9)
#define MODIFIER_SUPER (1 << 10)
enum wlsc_output_flags {
WL_OUTPUT_FLIPPED = 0x01
};
struct wlsc_surface {
struct wl_surface surface;
struct wlsc_compositor *compositor;
GLuint texture, saved_texture;
pixman_region32_t damage;
pixman_region32_t opaque;
int32_t x, y, width, height;
int32_t pitch;
struct wl_list link;
struct wl_list buffer_link;
struct wlsc_transform *transform;
uint32_t alpha;
uint32_t visual;
/*
* Which output to vsync this surface to.
* Used to determine, whether to send or queue frame events.
* Must be NULL, if 'link' is not in wlsc_compositor::surface_list.
*/
struct wlsc_output *output;
struct wlsc_output *fullscreen_output;
struct wl_list frame_callback_list;
EGLImageKHR image;
struct wl_buffer *buffer;
struct wl_listener buffer_destroy_listener;
};
struct wlsc_data_source {
struct wl_resource resource;
struct wl_array mime_types;
int refcount;
void *data;
struct wl_resource *(*create_offer)(struct wlsc_data_source *source,
struct wl_resource *target);
void (*cancel)(struct wlsc_data_source *source);
};
void
wlsc_data_source_unref(struct wlsc_data_source *source);
void
wlsc_input_device_set_selection(struct wlsc_input_device *device,
struct wlsc_data_source *source,
uint32_t time);
void
wlsc_spring_init(struct wlsc_spring *spring,
double k, double current, double target);
void
wlsc_spring_update(struct wlsc_spring *spring, uint32_t msec);
int
wlsc_spring_done(struct wlsc_spring *spring);
void
wlsc_surface_activate(struct wlsc_surface *surface,
struct wlsc_input_device *device, uint32_t time);
void
notify_motion(struct wl_input_device *device,
uint32_t time, int x, int y);
void
notify_button(struct wl_input_device *device,
uint32_t time, int32_t button, int32_t state);
void
notify_key(struct wl_input_device *device,
uint32_t time, uint32_t key, uint32_t state);
void
notify_pointer_focus(struct wl_input_device *device,
uint32_t time,
struct wlsc_output *output,
int32_t x, int32_t y);
void
notify_keyboard_focus(struct wl_input_device *device,
uint32_t time, struct wlsc_output *output,
struct wl_array *keys);
void
notify_touch(struct wl_input_device *device, uint32_t time, int touch_id,
int x, int y, int touch_type);
void
wlsc_output_finish_frame(struct wlsc_output *output, int msecs);
void
wlsc_output_damage(struct wlsc_output *output);
void
wlsc_compositor_repick(struct wlsc_compositor *compositor);
void
wlsc_compositor_schedule_repaint(struct wlsc_compositor *compositor);
void
wlsc_compositor_fade(struct wlsc_compositor *compositor, float tint);
void
wlsc_compositor_damage_all(struct wlsc_compositor *compositor);
void
wlsc_compositor_unlock(struct wlsc_compositor *compositor);
void
wlsc_compositor_wake(struct wlsc_compositor *compositor);
void
wlsc_compositor_activity(struct wlsc_compositor *compositor);
struct wlsc_binding;
typedef void (*wlsc_binding_handler_t)(struct wl_input_device *device,
uint32_t time, uint32_t key,
uint32_t button,
uint32_t state, void *data);
struct wlsc_binding *
wlsc_compositor_add_binding(struct wlsc_compositor *compositor,
uint32_t key, uint32_t button, uint32_t modifier,
wlsc_binding_handler_t binding, void *data);
void
wlsc_binding_destroy(struct wlsc_binding *binding);
void
wlsc_compositor_run_binding(struct wlsc_compositor *compositor,
struct wlsc_input_device *device,
uint32_t time,
uint32_t key, uint32_t button, int32_t state);
struct wlsc_surface *
wlsc_surface_create(struct wlsc_compositor *compositor,
int32_t x, int32_t y, int32_t width, int32_t height);
void
wlsc_surface_configure(struct wlsc_surface *surface,
int x, int y, int width, int height);
void
wlsc_surface_assign_output(struct wlsc_surface *surface);
void
wlsc_surface_damage(struct wlsc_surface *surface);
void
wlsc_surface_damage_below(struct wlsc_surface *surface);
void
wlsc_surface_damage_rectangle(struct wlsc_surface *surface,
int32_t x, int32_t y,
int32_t width, int32_t height);
struct wlsc_surface *
pick_surface(struct wl_input_device *device, int32_t *sx, int32_t *sy);
uint32_t
wlsc_compositor_get_time(void);
int
wlsc_compositor_init(struct wlsc_compositor *ec, struct wl_display *display);
void
wlsc_compositor_shutdown(struct wlsc_compositor *ec);
void
wlsc_output_move(struct wlsc_output *output, int x, int y);
void
wlsc_output_init(struct wlsc_output *output, struct wlsc_compositor *c,
int x, int y, int width, int height, uint32_t flags);
void
wlsc_output_destroy(struct wlsc_output *output);
void
wlsc_input_device_init(struct wlsc_input_device *device,
struct wlsc_compositor *ec);
void
wlsc_switcher_init(struct wlsc_compositor *compositor);
enum {
TTY_ENTER_VT,
TTY_LEAVE_VT
};
typedef void (*tty_vt_func_t)(struct wlsc_compositor *compositor, int event);
struct tty *
tty_create(struct wlsc_compositor *compositor, tty_vt_func_t vt_func,
int tty_nr);
void
tty_destroy(struct tty *tty);
void
screenshooter_create(struct wlsc_compositor *ec);
uint32_t *
wlsc_load_image(const char *filename,
int32_t *width_arg, int32_t *height_arg, uint32_t *stride_arg);
struct wlsc_process;
typedef void (*wlsc_process_cleanup_func_t)(struct wlsc_process *process,
int status);
struct wlsc_process {
pid_t pid;
wlsc_process_cleanup_func_t cleanup;
struct wl_list link;
};
struct wl_client *
wlsc_client_launch(struct wlsc_compositor *compositor,
struct wlsc_process *proc,
const char *path,
wlsc_process_cleanup_func_t cleanup);
int
wlsc_data_device_manager_init(struct wlsc_compositor *compositor);
void
wlsc_data_device_set_keyboard_focus(struct wlsc_input_device *device);
void
wlsc_watch_process(struct wlsc_process *process);
int
wlsc_xserver_init(struct wlsc_compositor *compositor);
void
wlsc_xserver_destroy(struct wlsc_compositor *compositor);
void
wlsc_xserver_surface_activate(struct wlsc_surface *surface);
void
wlsc_xserver_set_selection(struct wlsc_input_device *device);
struct wlsc_zoom;
typedef void (*wlsc_zoom_done_func_t)(struct wlsc_zoom *zoom, void *data);
struct wlsc_zoom *
wlsc_zoom_run(struct wlsc_surface *surface, GLfloat start, GLfloat stop,
wlsc_zoom_done_func_t done, void *data);
#endif
-478
View File
@@ -1,478 +0,0 @@
/*
* Copyright © 2011 Kristian Høgsberg
*
* 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 <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include "compositor.h"
void
wlsc_data_source_unref(struct wlsc_data_source *source)
{
source->refcount--;
if (source->refcount == 0)
free(source);
}
static void
data_offer_accept(struct wl_client *client, struct wl_resource *resource,
uint32_t time, const char *mime_type)
{
struct wlsc_data_source *source = resource->data;
/* FIXME: Check that client is currently focused by the input
* device that is currently dragging this data source. Should
* this be a wl_data_device request? */
wl_resource_post_event(&source->resource,
WL_DATA_SOURCE_TARGET, mime_type);
}
static void
data_offer_receive(struct wl_client *client, struct wl_resource *resource,
const char *mime_type, int32_t fd)
{
struct wlsc_data_source *source = resource->data;
wl_resource_post_event(&source->resource,
WL_DATA_SOURCE_SEND, mime_type, fd);
close(fd);
}
static void
data_offer_destroy(struct wl_client *client, struct wl_resource *resource)
{
wl_resource_destroy(resource, wlsc_compositor_get_time());
}
static void
destroy_data_offer(struct wl_resource *resource)
{
struct wlsc_data_source *source = resource->data;
wlsc_data_source_unref(source);
free(resource);
}
static const struct wl_data_offer_interface data_offer_interface = {
data_offer_accept,
data_offer_receive,
data_offer_destroy,
};
static struct wl_resource *
data_source_create_offer(struct wlsc_data_source *source,
struct wl_resource *target)
{
struct wl_resource *resource;
resource = wl_client_new_object(target->client,
&wl_data_offer_interface,
&data_offer_interface, source);
resource->destroy = destroy_data_offer;
return resource;
}
static void
data_source_cancel(struct wlsc_data_source *source)
{
wl_resource_post_event(&source->resource, WL_DATA_SOURCE_CANCELLED);
}
static struct wl_resource *
wlsc_data_source_send_offer(struct wlsc_data_source *source,
struct wl_resource *target)
{
struct wl_resource *resource;
char **p, **end;
resource = source->create_offer(source, target);
source->refcount++;
wl_resource_post_event(target, WL_DATA_DEVICE_DATA_OFFER, resource);
end = source->mime_types.data + source->mime_types.size;
for (p = source->mime_types.data; p < end; p++)
wl_resource_post_event(resource, WL_DATA_OFFER_OFFER, *p);
return resource;
}
static void
data_source_offer(struct wl_client *client,
struct wl_resource *resource,
const char *type)
{
struct wlsc_data_source *source = resource->data;
char **p;
p = wl_array_add(&source->mime_types, sizeof *p);
if (p)
*p = strdup(type);
if (!p || !*p)
wl_resource_post_no_memory(resource);
}
static void
data_source_destroy(struct wl_client *client, struct wl_resource *resource)
{
wl_resource_destroy(resource, wlsc_compositor_get_time());
}
static struct wl_data_source_interface data_source_interface = {
data_source_offer,
data_source_destroy
};
static struct wl_resource *
find_resource(struct wl_list *list, struct wl_client *client)
{
struct wl_resource *r;
wl_list_for_each(r, list, link) {
if (r->client == client)
return r;
}
return NULL;
}
static void
destroy_drag_focus(struct wl_listener *listener,
struct wl_resource *resource, uint32_t time)
{
struct wlsc_input_device *device =
container_of(listener, struct wlsc_input_device,
drag_focus_listener);
device->drag_focus_resource = NULL;
}
static void
drag_set_focus(struct wlsc_input_device *device,
struct wl_surface *surface, uint32_t time,
int32_t x, int32_t y)
{
struct wl_resource *resource, *offer;
if (device->drag_focus == surface)
return;
if (device->drag_focus_resource) {
wl_resource_post_event(device->drag_focus_resource,
WL_DATA_DEVICE_LEAVE);
wl_list_remove(&device->drag_focus_listener.link);
device->drag_focus_resource = NULL;
device->drag_focus = NULL;
}
if (surface)
resource = find_resource(&device->drag_resource_list,
surface->resource.client);
if (surface && resource) {
offer = wlsc_data_source_send_offer(device->drag_data_source,
resource);
wl_resource_post_event(resource,
WL_DATA_DEVICE_ENTER,
time, surface, x, y, offer);
device->drag_focus = surface;
device->drag_focus_listener.func = destroy_drag_focus;
wl_list_insert(resource->destroy_listener_list.prev,
&device->drag_focus_listener.link);
device->drag_focus_resource = resource;
}
}
static void
drag_grab_motion(struct wl_grab *grab,
uint32_t time, int32_t x, int32_t y)
{
struct wlsc_input_device *device =
container_of(grab, struct wlsc_input_device, grab);
struct wlsc_surface *es;
es = pick_surface(&device->input_device, &x, &y);
drag_set_focus(device, &es->surface, time, x, y);
if (es && device->drag_focus_resource)
wl_resource_post_event(device->drag_focus_resource,
WL_DATA_DEVICE_MOTION, time, x, y);
}
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 wlsc_input_device *device =
container_of(grab, struct wlsc_input_device, grab);
if (device->drag_focus_resource)
wl_resource_post_event(device->drag_focus_resource,
WL_DATA_DEVICE_DROP);
drag_set_focus(device, NULL, time, 0, 0);
wlsc_data_source_unref(device->drag_data_source);
device->drag_data_source = NULL;
}
static const struct wl_grab_interface drag_grab_interface = {
drag_grab_motion,
drag_grab_button,
drag_grab_end
};
static void
data_device_start_drag(struct wl_client *client, struct wl_resource *resource,
struct wl_resource *source_resource,
struct wl_resource *surface_resource, uint32_t time)
{
struct wlsc_input_device *device = resource->data;
struct wlsc_surface *surface = surface_resource->data;
struct wlsc_surface *target;
int32_t sx, sy;
/* FIXME: Check that client has implicit grab on the surface
* that matches the given time. */
/* FIXME: Check that the data source type array isn't empty. */
if (wl_input_device_update_grab(&device->input_device, &device->grab,
&surface->surface, time) < 0)
return;
device->grab.interface = &drag_grab_interface;
device->drag_data_source = source_resource->data;
device->drag_data_source->refcount++;
target = pick_surface(&device->input_device, &sx, &sy);
wl_input_device_set_pointer_focus(&device->input_device,
NULL, time, 0, 0, 0, 0);
drag_set_focus(device, &target->surface, time, sx, sy);
}
static void
data_device_attach(struct wl_client *client, struct wl_resource *resource,
uint32_t time,
struct wl_resource *buffer, int32_t x, int32_t y)
{
}
static void
destroy_selection_data_source(struct wl_listener *listener,
struct wl_resource *resource, uint32_t time)
{
struct wlsc_input_device *device =
container_of(listener, struct wlsc_input_device,
selection_data_source_listener);
struct wl_resource *data_device, *focus;
device->selection_data_source = NULL;
focus = device->input_device.keyboard_focus_resource;
if (focus) {
data_device = find_resource(&device->drag_resource_list,
focus->client);
wl_resource_post_event(data_device,
WL_DATA_DEVICE_SELECTION, NULL);
}
}
void
wlsc_input_device_set_selection(struct wlsc_input_device *device,
struct wlsc_data_source *source, uint32_t time)
{
struct wl_resource *data_device, *focus, *offer;
if (device->selection_data_source) {
device->selection_data_source->cancel(device->selection_data_source);
/* FIXME: All non-active clients will probably hold a
* reference to the selection data source, and thus it
* won't get destroyed until every client has been
* activated and seen the new selection event. */
wl_list_remove(&device->selection_data_source_listener.link);
wlsc_data_source_unref(device->selection_data_source);
device->selection_data_source = NULL;
}
device->selection_data_source = source;
source->refcount++;
focus = device->input_device.keyboard_focus_resource;
if (focus) {
data_device = find_resource(&device->drag_resource_list,
focus->client);
if (data_device) {
offer = wlsc_data_source_send_offer(device->selection_data_source,
data_device);
wl_resource_post_event(data_device,
WL_DATA_DEVICE_SELECTION,
offer);
}
}
wlsc_xserver_set_selection(device);
device->selection_data_source_listener.func =
destroy_selection_data_source;
wl_list_insert(source->resource.destroy_listener_list.prev,
&device->selection_data_source_listener.link);
}
static void
data_device_set_selection(struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *source_resource, uint32_t time)
{
if (!source_resource)
return;
wlsc_input_device_set_selection(resource->data,
source_resource->data, time);
}
static const struct wl_data_device_interface data_device_interface = {
data_device_start_drag,
data_device_attach,
data_device_set_selection,
};
static void
destroy_data_source(struct wl_resource *resource)
{
struct wlsc_data_source *source =
container_of(resource, struct wlsc_data_source, resource);
char **p, **end;
end = source->mime_types.data + source->mime_types.size;
for (p = source->mime_types.data; p < end; p++)
free(*p);
wl_array_release(&source->mime_types);
source->resource.object.id = 0;
wlsc_data_source_unref(source);
}
static void
create_data_source(struct wl_client *client,
struct wl_resource *resource, uint32_t id)
{
struct wlsc_data_source *source;
source = malloc(sizeof *source);
if (source == NULL) {
wl_resource_post_no_memory(resource);
return;
}
source->resource.destroy = destroy_data_source;
source->resource.object.id = id;
source->resource.object.interface = &wl_data_source_interface;
source->resource.object.implementation =
(void (**)(void)) &data_source_interface;
source->resource.data = source;
source->create_offer = data_source_create_offer;
source->cancel = data_source_cancel;
source->refcount = 1;
wl_array_init(&source->mime_types);
wl_client_add_resource(client, &source->resource);
}
static void unbind_data_device(struct wl_resource *resource)
{
wl_list_remove(&resource->link);
free(resource);
}
static void
get_data_device(struct wl_client *client,
struct wl_resource *manager_resource,
uint32_t id, struct wl_resource *input_device)
{
struct wlsc_input_device *device = input_device->data;
struct wl_resource *resource;
resource =
wl_client_add_object(client, &wl_data_device_interface,
&data_device_interface, id, device);
wl_list_insert(&device->drag_resource_list, &resource->link);
resource->destroy = unbind_data_device;
}
static const struct wl_data_device_manager_interface manager_interface = {
create_data_source,
get_data_device
};
static void
bind_manager(struct wl_client *client,
void *data, uint32_t version, uint32_t id)
{
wl_client_add_object(client, &wl_data_device_manager_interface,
&manager_interface, id, NULL);
}
WL_EXPORT void
wlsc_data_device_set_keyboard_focus(struct wlsc_input_device *device)
{
struct wl_resource *data_device, *focus, *offer;
struct wlsc_data_source *source;
focus = device->input_device.keyboard_focus_resource;
if (!focus)
return;
data_device = find_resource(&device->drag_resource_list,
focus->client);
if (!data_device)
return;
source = device->selection_data_source;
if (source) {
offer = wlsc_data_source_send_offer(source, data_device);
wl_resource_post_event(data_device,
WL_DATA_DEVICE_SELECTION, offer);
}
}
WL_EXPORT int
wlsc_data_device_manager_init(struct wlsc_compositor *compositor)
{
if (wl_display_add_global(compositor->wl_display,
&wl_data_device_manager_interface,
NULL, bind_manager) == NULL)
return -1;
return 0;
}
-653
View File
@@ -1,653 +0,0 @@
/*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <linux/input.h>
#include <unistd.h>
#include <fcntl.h>
#include "compositor.h"
#include "evdev.h"
struct evdev_input {
struct wlsc_input_device base;
struct wl_list devices_list;
struct udev_monitor *udev_monitor;
char *seat_id;
};
#define MAX_SLOTS 16
struct evdev_input_device {
struct evdev_input *master;
struct wl_list link;
struct wl_event_source *source;
struct wlsc_output *output;
char *devnode;
int fd;
struct {
int min_x, max_x, min_y, max_y;
int old_x, old_y, reset_x, reset_y;
int32_t x, y;
} abs;
struct {
int slot;
int32_t x[MAX_SLOTS];
int32_t y[MAX_SLOTS];
} mt;
struct {
int dx, dy;
} rel;
int type; /* event type flags */
int is_touchpad, is_mt;
};
/* event type flags */
#define EVDEV_ABSOLUTE_MOTION (1 << 0)
#define EVDEV_ABSOLUTE_MT_DOWN (1 << 1)
#define EVDEV_ABSOLUTE_MT_MOTION (1 << 2)
#define EVDEV_ABSOLUTE_MT_UP (1 << 3)
#define EVDEV_RELATIVE_MOTION (1 << 4)
static inline void
evdev_process_key(struct evdev_input_device *device,
struct input_event *e, int time)
{
if (e->value == 2)
return;
switch (e->code) {
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->is_touchpad)
{
device->abs.reset_x = 1;
device->abs.reset_y = 1;
}
break;
case BTN_TOUCH:
/* Multitouch touchscreen devices might not send individually
* button events each time a new finger is down. So we don't
* send notification for such devices and we solve the button
* case emulating on compositor side. */
if (device->is_mt)
break;
/* Treat BTN_TOUCH from devices that only have BTN_TOUCH as
* BTN_LEFT */
e->code = BTN_LEFT;
/* Intentional fallthrough! */
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, e->value);
break;
default:
notify_key(&device->master->base.input_device,
time, e->code, e->value);
break;
}
}
static void
evdev_process_touch(struct evdev_input_device *device,
struct input_event *e)
{
const int screen_width = device->output->current->width;
const int screen_height = device->output->current->height;
switch (e->code) {
case ABS_MT_SLOT:
device->mt.slot = e->value;
break;
case ABS_MT_TRACKING_ID:
if (e->value >= 0)
device->type |= EVDEV_ABSOLUTE_MT_DOWN;
else
device->type |= EVDEV_ABSOLUTE_MT_UP;
break;
case ABS_MT_POSITION_X:
device->mt.x[device->mt.slot] =
(e->value - device->abs.min_x) * screen_width /
(device->abs.max_x - device->abs.min_x) +
device->output->x;
device->type |= EVDEV_ABSOLUTE_MT_MOTION;
break;
case ABS_MT_POSITION_Y:
device->mt.y[device->mt.slot] =
(e->value - device->abs.min_y) * screen_height /
(device->abs.max_y - device->abs.min_y) +
device->output->y;
device->type |= EVDEV_ABSOLUTE_MT_MOTION;
break;
}
}
static inline void
evdev_process_absolute_motion(struct evdev_input_device *device,
struct input_event *e)
{
const int screen_width = device->output->current->width;
const int screen_height = device->output->current->height;
switch (e->code) {
case ABS_X:
device->abs.x =
(e->value - device->abs.min_x) * screen_width /
(device->abs.max_x - device->abs.min_x) +
device->output->x;
device->type |= EVDEV_ABSOLUTE_MOTION;
break;
case ABS_Y:
device->abs.y =
(e->value - device->abs.min_y) * screen_height /
(device->abs.max_y - device->abs.min_y) +
device->output->y;
device->type |= EVDEV_ABSOLUTE_MOTION;
break;
}
}
static inline void
evdev_process_absolute_motion_touchpad(struct evdev_input_device *device,
struct input_event *e)
{
/* FIXME: Make this configurable somehow. */
const int touchpad_speed = 700;
switch (e->code) {
case ABS_X:
e->value -= device->abs.min_x;
if (device->abs.reset_x)
device->abs.reset_x = 0;
else {
device->rel.dx =
(e->value - device->abs.old_x) *
touchpad_speed /
(device->abs.max_x - device->abs.min_x);
}
device->abs.old_x = e->value;
device->type |= EVDEV_RELATIVE_MOTION;
break;
case ABS_Y:
e->value -= device->abs.min_y;
if (device->abs.reset_y)
device->abs.reset_y = 0;
else {
device->rel.dy =
(e->value - device->abs.old_y) *
touchpad_speed /
/* maybe use x size here to have the same scale? */
(device->abs.max_y - device->abs.min_y);
}
device->abs.old_y = e->value;
device->type |= EVDEV_RELATIVE_MOTION;
break;
}
}
static inline void
evdev_process_relative_motion(struct evdev_input_device *device,
struct input_event *e)
{
switch (e->code) {
case REL_X:
device->rel.dx += e->value;
device->type |= EVDEV_RELATIVE_MOTION;
break;
case REL_Y:
device->rel.dy += e->value;
device->type |= EVDEV_RELATIVE_MOTION;
break;
}
}
static inline void
evdev_process_absolute(struct evdev_input_device *device,
struct input_event *e)
{
if (device->is_touchpad) {
evdev_process_absolute_motion_touchpad(device, e);
} else if (device->is_mt) {
evdev_process_touch(device, e);
} else {
evdev_process_absolute_motion(device, e);
}
}
static int
is_motion_event(struct input_event *e)
{
switch (e->type) {
case EV_REL:
switch (e->code) {
case REL_X:
case REL_Y:
return 1;
}
case EV_ABS:
switch (e->code) {
case ABS_X:
case ABS_Y:
case ABS_MT_POSITION_X:
case ABS_MT_POSITION_Y:
return 1;
}
}
return 0;
}
static void
evdev_flush_motion(struct evdev_input_device *device, uint32_t time)
{
struct wl_input_device *master = &device->master->base.input_device;
if (!device->type)
return;
if (device->type & EVDEV_RELATIVE_MOTION) {
notify_motion(master, time,
master->x + device->rel.dx,
master->y + device->rel.dy);
device->type &= ~EVDEV_RELATIVE_MOTION;
device->rel.dx = 0;
device->rel.dy = 0;
}
if (device->type & EVDEV_ABSOLUTE_MT_DOWN) {
notify_touch(master, time,
device->mt.slot,
device->mt.x[device->mt.slot],
device->mt.y[device->mt.slot],
WL_INPUT_DEVICE_TOUCH_DOWN);
device->type &= ~EVDEV_ABSOLUTE_MT_DOWN;
device->type &= ~EVDEV_ABSOLUTE_MT_MOTION;
}
if (device->type & EVDEV_ABSOLUTE_MT_MOTION) {
notify_touch(master, time,
device->mt.slot,
device->mt.x[device->mt.slot],
device->mt.y[device->mt.slot],
WL_INPUT_DEVICE_TOUCH_MOTION);
device->type &= ~EVDEV_ABSOLUTE_MT_DOWN;
device->type &= ~EVDEV_ABSOLUTE_MT_MOTION;
}
if (device->type & EVDEV_ABSOLUTE_MT_UP) {
notify_touch(master, time, device->mt.slot, 0, 0,
WL_INPUT_DEVICE_TOUCH_UP);
device->type &= ~EVDEV_ABSOLUTE_MT_UP;
}
if (device->type & EVDEV_ABSOLUTE_MOTION) {
notify_motion(master, time, device->abs.x, device->abs.y);
device->type &= ~EVDEV_ABSOLUTE_MOTION;
}
}
static int
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;
uint32_t time = 0;
ec = device->master->base.compositor;
if (!ec->focus)
return 1;
len = read(fd, &ev, sizeof ev);
if (len < 0 || len % sizeof e[0] != 0) {
/* FIXME: call device_removed when errno is ENODEV. */;
return 1;
}
e = ev;
end = (void *) ev + len;
for (e = ev; e < end; e++) {
time = e->time.tv_sec * 1000 + e->time.tv_usec / 1000;
/* we try to minimize the amount of notifications to be
* forwarded to the compositor, so we accumulate motion
* events and send as a bunch */
if (!is_motion_event(e))
evdev_flush_motion(device, time);
switch (e->type) {
case EV_REL:
evdev_process_relative_motion(device, e);
break;
case EV_ABS:
evdev_process_absolute(device, e);
break;
case EV_KEY:
evdev_process_key(device, e, time);
break;
}
}
evdev_flush_motion(device, time);
return 1;
}
/* copied from udev/extras/input_id/input_id.c */
/* we must use this kernel-compatible implementation */
#define BITS_PER_LONG (sizeof(unsigned long) * 8)
#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
#define OFF(x) ((x)%BITS_PER_LONG)
#define BIT(x) (1UL<<OFF(x))
#define LONG(x) ((x)/BITS_PER_LONG)
#define TEST_BIT(array, bit) ((array[LONG(bit)] >> OFF(bit)) & 1)
/* end copied */
static int
evdev_configure_device(struct evdev_input_device *device)
{
struct input_absinfo absinfo;
unsigned long ev_bits[NBITS(EV_MAX)];
unsigned long abs_bits[NBITS(ABS_MAX)];
unsigned long key_bits[NBITS(KEY_MAX)];
int has_key, has_abs;
has_key = 0;
has_abs = 0;
ioctl(device->fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits);
if (TEST_BIT(ev_bits, EV_ABS)) {
has_abs = 1;
ioctl(device->fd, EVIOCGBIT(EV_ABS, sizeof(abs_bits)),
abs_bits);
if (TEST_BIT(abs_bits, ABS_X)) {
ioctl(device->fd, EVIOCGABS(ABS_X), &absinfo);
device->abs.min_x = absinfo.minimum;
device->abs.max_x = absinfo.maximum;
}
if (TEST_BIT(abs_bits, ABS_Y)) {
ioctl(device->fd, EVIOCGABS(ABS_Y), &absinfo);
device->abs.min_y = absinfo.minimum;
device->abs.max_y = absinfo.maximum;
}
if (TEST_BIT(abs_bits, ABS_MT_SLOT)) {
device->is_mt = 1;
device->mt.slot = 0;
}
}
if (TEST_BIT(ev_bits, EV_KEY)) {
has_key = 1;
ioctl(device->fd, EVIOCGBIT(EV_KEY, sizeof(key_bits)),
key_bits);
if (TEST_BIT(key_bits, BTN_TOOL_FINGER) &&
!TEST_BIT(key_bits, BTN_TOOL_PEN))
device->is_touchpad = 1;
}
/* This rule tries to catch accelerometer devices and opt out. We may
* want to adjust the protocol later adding a proper event for dealing
* with accelerometers and implement here accordingly */
if (has_abs && !has_key)
return -1;
return 0;
}
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 wlsc_compositor *ec;
device = malloc(sizeof *device);
if (device == NULL)
return NULL;
ec = master->base.compositor;
device->output =
container_of(ec->output_list.next, struct wlsc_output, link);
device->master = master;
device->is_touchpad = 0;
device->is_mt = 0;
device->devnode = strdup(path);
device->mt.slot = -1;
device->rel.dx = 0;
device->rel.dy = 0;
device->fd = open(path, O_RDONLY);
if (device->fd < 0)
goto err0;
if (evdev_configure_device(device) == -1)
goto err1;
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)
goto err1;
wl_list_insert(master->devices_list.prev, &device->link);
return device;
err1:
close(device->fd);
err0:
free(device->devnode);
free(device);
return NULL;
}
static const char default_seat[] = "seat0";
static void
device_added(struct udev_device *udev_device, struct evdev_input *master)
{
struct wlsc_compositor *c;
const char *devnode;
const char *device_seat;
device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
if (!device_seat)
device_seat = default_seat;
if (strcmp(device_seat, master->seat_id))
return;
c = master->base.compositor;
devnode = udev_device_get_devnode(udev_device);
if (evdev_input_device_create(master, c->wl_display, devnode))
fprintf(stderr, "evdev input device: added: %s\n", devnode);
}
static void
device_removed(struct udev_device *udev_device, struct evdev_input *master)
{
const char *devnode = udev_device_get_devnode(udev_device);
struct evdev_input_device *device, *next;
wl_list_for_each_safe(device, next, &master->devices_list, link) {
if (!strcmp(device->devnode, devnode)) {
wl_event_source_remove(device->source);
wl_list_remove(&device->link);
close(device->fd);
free(device->devnode);
free(device);
break;
}
}
fprintf(stderr, "evdev input device: removed: %s\n", devnode);
}
void
evdev_add_devices(struct udev *udev, struct wlsc_input_device *input_base)
{
struct evdev_input *input = (struct evdev_input *) input_base;
struct udev_enumerate *e;
struct udev_list_entry *entry;
struct udev_device *device;
const char *path;
e = udev_enumerate_new(udev);
udev_enumerate_add_match_subsystem(e, "input");
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);
if (strncmp("event", udev_device_get_sysname(device), 5) != 0)
continue;
device_added(device, input);
udev_device_unref(device);
}
udev_enumerate_unref(e);
}
static int
evdev_udev_handler(int fd, uint32_t mask, void *data)
{
struct evdev_input *master = data;
struct udev_device *udev_device;
const char *action;
udev_device = udev_monitor_receive_device(master->udev_monitor);
if (!udev_device)
return 1;
action = udev_device_get_action(udev_device);
if (action) {
if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
return 0;
if (!strcmp(action, "add")) {
device_added(udev_device, master);
}
else if (!strcmp(action, "remove"))
device_removed(udev_device, master);
}
udev_device_unref(udev_device);
return 0;
}
static int
evdev_config_udev_monitor(struct udev *udev, struct evdev_input *master)
{
struct wl_event_loop *loop;
struct wlsc_compositor *c = master->base.compositor;
master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
if (!master->udev_monitor)
return 0;
udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
"input", NULL);
if (udev_monitor_enable_receiving(master->udev_monitor)) {
fprintf(stderr, "udev: failed to bind the udev monitor\n");
return 0;
}
loop = wl_display_get_event_loop(c->wl_display);
wl_event_loop_add_fd(loop, udev_monitor_get_fd(master->udev_monitor),
WL_EVENT_READABLE, evdev_udev_handler, master);
return 1;
}
void
evdev_input_create(struct wlsc_compositor *c, struct udev *udev,
const char *seat)
{
struct evdev_input *input;
input = malloc(sizeof *input);
if (input == NULL)
return;
memset(input, 0, sizeof *input);
wlsc_input_device_init(&input->base, c);
wl_list_init(&input->devices_list);
input->seat_id = strdup(seat);
if (!evdev_config_udev_monitor(udev, input)) {
free(input->seat_id);
free(input);
return;
}
evdev_add_devices(udev, &input->base);
c->input_device = &input->base.input_device;
}
void
evdev_remove_devices(struct wlsc_input_device *input_base)
{
struct evdev_input *input = (struct evdev_input *) input_base;
struct evdev_input_device *device, *next;
wl_list_for_each_safe(device, next, &input->devices_list, link) {
fprintf(stderr, "evdev input device: removed: %s\n", device->devnode);
wl_event_source_remove(device->source);
wl_list_remove(&device->link);
close(device->fd);
free(device->devnode);
free(device);
}
}
void
evdev_input_destroy(struct wlsc_input_device *input_base)
{
struct evdev_input *input = (struct evdev_input *) input_base;
evdev_remove_devices(input_base);
wl_list_remove(&input->base.link);
free(input->seat_id);
free(input);
}
-35
View File
@@ -1,35 +0,0 @@
/*
* Copyright © 2011 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.
*/
void
evdev_add_devices(struct udev *udev, struct wlsc_input_device
*input_base);
void
evdev_remove_devices(struct wlsc_input_device *input_base);
void
evdev_input_create(struct wlsc_compositor *c, struct udev *udev,
const char *seat);
void
evdev_input_destroy(struct wlsc_input_device *input_base);
-307
View File
@@ -1,307 +0,0 @@
/*
* Copyright © 2009 Intel Corporation
* Copyright © 1988-2004 Keith Packard and Bart Massey.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* Except as contained in this notice, the names of the authors
* or their institutions shall not be used in advertising or
* otherwise to promote the sale, use or other dealings in this
* Software without prior written authorization from the
* authors.
*
* Authors:
* Eric Anholt <eric@anholt.net>
* Keith Packard <keithp@keithp.com>
*/
#include <stdlib.h>
#include <stdint.h>
#include "hash.h"
struct hash_entry {
uint32_t hash;
void *data;
};
struct hash_table {
struct hash_entry *table;
uint32_t size;
uint32_t rehash;
uint32_t max_entries;
uint32_t size_index;
uint32_t entries;
uint32_t deleted_entries;
};
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
/*
* From Knuth -- a good choice for hash/rehash values is p, p-2 where
* p and p-2 are both prime. These tables are sized to have an extra 10%
* free to avoid exponential performance degradation as the hash table fills
*/
static const uint32_t deleted_data;
static const struct {
uint32_t max_entries, size, rehash;
} hash_sizes[] = {
{ 2, 5, 3 },
{ 4, 7, 5 },
{ 8, 13, 11 },
{ 16, 19, 17 },
{ 32, 43, 41 },
{ 64, 73, 71 },
{ 128, 151, 149 },
{ 256, 283, 281 },
{ 512, 571, 569 },
{ 1024, 1153, 1151 },
{ 2048, 2269, 2267 },
{ 4096, 4519, 4517 },
{ 8192, 9013, 9011 },
{ 16384, 18043, 18041 },
{ 32768, 36109, 36107 },
{ 65536, 72091, 72089 },
{ 131072, 144409, 144407 },
{ 262144, 288361, 288359 },
{ 524288, 576883, 576881 },
{ 1048576, 1153459, 1153457 },
{ 2097152, 2307163, 2307161 },
{ 4194304, 4613893, 4613891 },
{ 8388608, 9227641, 9227639 },
{ 16777216, 18455029, 18455027 },
{ 33554432, 36911011, 36911009 },
{ 67108864, 73819861, 73819859 },
{ 134217728, 147639589, 147639587 },
{ 268435456, 295279081, 295279079 },
{ 536870912, 590559793, 590559791 },
{ 1073741824, 1181116273, 1181116271},
{ 2147483648ul, 2362232233ul, 2362232231ul}
};
static int
entry_is_free(struct hash_entry *entry)
{
return entry->data == NULL;
}
static int
entry_is_deleted(struct hash_entry *entry)
{
return entry->data == &deleted_data;
}
static int
entry_is_present(struct hash_entry *entry)
{
return entry->data != NULL && entry->data != &deleted_data;
}
struct hash_table *
hash_table_create(void)
{
struct hash_table *ht;
ht = malloc(sizeof(*ht));
if (ht == NULL)
return NULL;
ht->size_index = 0;
ht->size = hash_sizes[ht->size_index].size;
ht->rehash = hash_sizes[ht->size_index].rehash;
ht->max_entries = hash_sizes[ht->size_index].max_entries;
ht->table = calloc(ht->size, sizeof(*ht->table));
ht->entries = 0;
ht->deleted_entries = 0;
if (ht->table == NULL) {
free(ht);
return NULL;
}
return ht;
}
/**
* Frees the given hash table.
*/
void
hash_table_destroy(struct hash_table *ht)
{
if (!ht)
return;
free(ht->table);
free(ht);
}
/**
* Finds a hash table entry with the given key and hash of that key.
*
* Returns NULL if no entry is found. Note that the data pointer may be
* modified by the user.
*/
static void *
hash_table_search(struct hash_table *ht, uint32_t hash)
{
uint32_t hash_address;
hash_address = hash % ht->size;
do {
uint32_t double_hash;
struct hash_entry *entry = ht->table + hash_address;
if (entry_is_free(entry)) {
return NULL;
} else if (entry_is_present(entry) && entry->hash == hash) {
return entry;
}
double_hash = 1 + hash % ht->rehash;
hash_address = (hash_address + double_hash) % ht->size;
} while (hash_address != hash % ht->size);
return NULL;
}
void
hash_table_for_each(struct hash_table *ht,
hash_table_iterator_func_t func, void *data)
{
struct hash_entry *entry;
uint32_t i;
for (i = 0; i < ht->size; i++) {
entry = ht->table + i;
if (entry_is_present(entry))
func(entry->data, data);
}
}
void *
hash_table_lookup(struct hash_table *ht, uint32_t hash)
{
struct hash_entry *entry;
entry = hash_table_search(ht, hash);
if (entry != NULL)
return entry->data;
return NULL;
}
static void
hash_table_rehash(struct hash_table *ht, int new_size_index)
{
struct hash_table old_ht;
struct hash_entry *table, *entry;
if (new_size_index >= ARRAY_SIZE(hash_sizes))
return;
table = calloc(hash_sizes[new_size_index].size, sizeof(*ht->table));
if (table == NULL)
return;
old_ht = *ht;
ht->table = table;
ht->size_index = new_size_index;
ht->size = hash_sizes[ht->size_index].size;
ht->rehash = hash_sizes[ht->size_index].rehash;
ht->max_entries = hash_sizes[ht->size_index].max_entries;
ht->entries = 0;
ht->deleted_entries = 0;
for (entry = old_ht.table;
entry != old_ht.table + old_ht.size;
entry++) {
if (entry_is_present(entry)) {
hash_table_insert(ht, entry->hash, entry->data);
}
}
free(old_ht.table);
}
/**
* Inserts the data with the given hash into the table.
*
* Note that insertion may rearrange the table on a resize or rehash,
* so previously found hash_entries are no longer valid after this function.
*/
int
hash_table_insert(struct hash_table *ht, uint32_t hash, void *data)
{
uint32_t hash_address;
if (ht->entries >= ht->max_entries) {
hash_table_rehash(ht, ht->size_index + 1);
} else if (ht->deleted_entries + ht->entries >= ht->max_entries) {
hash_table_rehash(ht, ht->size_index);
}
hash_address = hash % ht->size;
do {
struct hash_entry *entry = ht->table + hash_address;
uint32_t double_hash;
if (!entry_is_present(entry)) {
if (entry_is_deleted(entry))
ht->deleted_entries--;
entry->hash = hash;
entry->data = data;
ht->entries++;
return 0;
}
double_hash = 1 + hash % ht->rehash;
hash_address = (hash_address + double_hash) % ht->size;
} while (hash_address != hash % ht->size);
/* We could hit here if a required resize failed. An unchecked-malloc
* application could ignore this result.
*/
return -1;
}
/**
* This function deletes the given hash table entry.
*
* Note that deletion doesn't otherwise modify the table, so an iteration over
* the table deleting entries is safe.
*/
void
hash_table_remove(struct hash_table *ht, uint32_t hash)
{
struct hash_entry *entry;
entry = hash_table_search(ht, hash);
if (entry != NULL) {
entry->data = (void *) &deleted_data;
ht->entries--;
ht->deleted_entries++;
}
}
-49
View File
@@ -1,49 +0,0 @@
/*
* Copyright © 2009 Intel Corporation
* Copyright © 1988-2004 Keith Packard and Bart Massey.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* Except as contained in this notice, the names of the authors
* or their institutions shall not be used in advertising or
* otherwise to promote the sale, use or other dealings in this
* Software without prior written authorization from the
* authors.
*
* Authors:
* Eric Anholt <eric@anholt.net>
* Keith Packard <keithp@keithp.com>
*/
#ifndef HASH_H
#define HASH_H
struct hash_table;
struct hash_table *hash_table_create(void);
typedef void (*hash_table_iterator_func_t)(void *element, void *data);
void hash_table_destroy(struct hash_table *ht);
void *hash_table_lookup(struct hash_table *ht, uint32_t hash);
int hash_table_insert(struct hash_table *ht, uint32_t hash, void *data);
void hash_table_remove(struct hash_table *ht, uint32_t hash);
void hash_table_for_each(struct hash_table *ht,
hash_table_iterator_func_t func, void *data);
#endif
-176
View File
@@ -1,176 +0,0 @@
/*
* Copyright © 2011 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 <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <errno.h>
#include <png.h>
#include "compositor.h"
static inline int
multiply_alpha(int alpha, int color)
{
int temp = (alpha * color) + 0x80;
return ((temp + (temp >> 8)) >> 8);
}
static void
premultiply_data(png_structp png,
png_row_infop row_info,
png_bytep data)
{
unsigned int i;
png_bytep p;
for (i = 0, p = data; i < row_info->rowbytes; i += 4, p += 4) {
png_byte alpha = p[3];
uint32_t w;
if (alpha == 0) {
w = 0;
} else {
png_byte red = p[0];
png_byte green = p[1];
png_byte blue = p[2];
if (alpha != 0xff) {
red = multiply_alpha(alpha, red);
green = multiply_alpha(alpha, green);
blue = multiply_alpha(alpha, blue);
}
w = (alpha << 24) | (red << 16) | (green << 8) | (blue << 0);
}
* (uint32_t *) p = w;
}
}
static void
read_func(png_structp png, png_bytep data, png_size_t size)
{
FILE *fp = png_get_io_ptr(png);
if (fread(data, 1, size, fp) < 0)
png_error(png, NULL);
}
WL_EXPORT uint32_t *
wlsc_load_image(const char *filename,
int32_t *width_arg, int32_t *height_arg, uint32_t *stride_arg)
{
png_struct *png;
png_info *info;
png_byte *data;
png_byte **row_pointers = NULL;
png_uint_32 width, height;
int depth, color_type, interlace, stride;
unsigned int i;
FILE *fp;
fp = fopen(filename, "rb");
if (fp == NULL)
return NULL;
png = png_create_read_struct(PNG_LIBPNG_VER_STRING,
NULL, NULL, NULL);
if (!png) {
fclose(fp);
return NULL;
}
info = png_create_info_struct(png);
if (!info) {
png_destroy_read_struct(&png, &info, NULL);
fclose(fp);
return NULL;
}
png_set_read_fn(png, fp, read_func);
png_read_info(png, info);
png_get_IHDR(png, info,
&width, &height, &depth,
&color_type, &interlace, NULL, NULL);
if (color_type == PNG_COLOR_TYPE_PALETTE)
png_set_palette_to_rgb(png);
if (color_type == PNG_COLOR_TYPE_GRAY)
png_set_expand_gray_1_2_4_to_8(png);
if (png_get_valid(png, info, PNG_INFO_tRNS))
png_set_tRNS_to_alpha(png);
if (depth == 16)
png_set_strip_16(png);
if (depth < 8)
png_set_packing(png);
if (color_type == PNG_COLOR_TYPE_GRAY ||
color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
png_set_gray_to_rgb(png);
if (interlace != PNG_INTERLACE_NONE)
png_set_interlace_handling(png);
png_set_filler(png, 0xff, PNG_FILLER_AFTER);
png_set_read_user_transform_fn(png, premultiply_data);
png_read_update_info(png, info);
png_get_IHDR(png, info,
&width, &height, &depth,
&color_type, &interlace, NULL, NULL);
stride = width * 4;
data = malloc(stride * height);
if (!data) {
png_destroy_read_struct(&png, &info, NULL);
fclose(fp);
return NULL;
}
row_pointers = malloc(height * sizeof row_pointers[0]);
if (row_pointers == NULL) {
free(data);
png_destroy_read_struct(&png, &info, NULL);
fclose(fp);
return NULL;
}
for (i = 0; i < height; i++)
row_pointers[i] = &data[i * stride];
png_read_image(png, row_pointers);
png_read_end(png, info);
free(row_pointers);
png_destroy_read_struct(&png, &info, NULL);
fclose(fp);
*width_arg = width;
*height_arg = height;
*stride_arg = stride;
return (uint32_t *) data;
}
-83
View File
@@ -1,83 +0,0 @@
/*
* Copyright © 2008-2011 Kristian Høgsberg
*
* 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 <stdlib.h>
#include "compositor.h"
#include "screenshooter-server-protocol.h"
struct screenshooter {
struct wl_object base;
struct wlsc_compositor *ec;
};
static void
screenshooter_shoot(struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *output_resource,
struct wl_resource *buffer_resource)
{
struct wlsc_output *output = output_resource->data;
struct wl_buffer *buffer = buffer_resource->data;
if (!wl_buffer_is_shm(buffer))
return;
if (buffer->width < output->current->width ||
buffer->height < output->current->height)
return;
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(0, 0, output->current->width, output->current->height,
GL_RGBA, GL_UNSIGNED_BYTE,
wl_shm_buffer_get_data(buffer));
}
struct screenshooter_interface screenshooter_implementation = {
screenshooter_shoot
};
static void
bind_shooter(struct wl_client *client,
void *data, uint32_t version, uint32_t id)
{
wl_client_add_object(client, &screenshooter_interface,
&screenshooter_implementation, id, data);
}
void
screenshooter_create(struct wlsc_compositor *ec)
{
struct screenshooter *shooter;
shooter = malloc(sizeof *shooter);
if (shooter == NULL)
return;
shooter->base.interface = &screenshooter_interface;
shooter->base.implementation =
(void(**)(void)) &screenshooter_implementation;
shooter->ec = ec;
wl_display_add_global(ec->wl_display,
&screenshooter_interface, shooter, bind_shooter);
};
-1296
View File
File diff suppressed because it is too large Load Diff
-131
View File
@@ -1,131 +0,0 @@
/*
* Copyright © 2011 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 <stdlib.h>
#include <stdio.h>
#include <linux/input.h>
#include "compositor.h"
struct wlsc_switcher {
struct wlsc_compositor *compositor;
struct wlsc_surface *current;
struct wl_listener listener;
};
static void
wlsc_switcher_next(struct wlsc_switcher *switcher)
{
struct wl_list *l;
struct wl_surface *current;
wlsc_surface_damage(switcher->current);
l = switcher->current->link.next;
if (l == &switcher->compositor->surface_list)
l = switcher->compositor->surface_list.next;
switcher->current = container_of(l, struct wlsc_surface, link);
wl_list_remove(&switcher->listener.link);
current = &switcher->current->surface;
wl_list_insert(current->resource.destroy_listener_list.prev,
&switcher->listener.link);
switcher->compositor->overlay = switcher->current;
wlsc_surface_damage(switcher->current);
}
static void
switcher_handle_surface_destroy(struct wl_listener *listener,
struct wl_resource *resource, uint32_t time)
{
struct wlsc_switcher *switcher =
container_of(listener, struct wlsc_switcher, listener);
wlsc_switcher_next(switcher);
}
static struct wlsc_switcher *
wlsc_switcher_create(struct wlsc_compositor *compositor)
{
struct wlsc_switcher *switcher;
switcher = malloc(sizeof *switcher);
switcher->compositor = compositor;
switcher->current = container_of(compositor->surface_list.next,
struct wlsc_surface, link);
switcher->listener.func = switcher_handle_surface_destroy;
wl_list_init(&switcher->listener.link);
return switcher;
}
static void
wlsc_switcher_destroy(struct wlsc_switcher *switcher)
{
wl_list_remove(&switcher->listener.link);
free(switcher);
}
static void
switcher_next_binding(struct wl_input_device *device, uint32_t time,
uint32_t key, uint32_t button,
uint32_t state, void *data)
{
struct wlsc_compositor *compositor = data;
if (!state)
return;
if (wl_list_empty(&compositor->surface_list))
return;
if (compositor->switcher == NULL)
compositor->switcher = wlsc_switcher_create(compositor);
wlsc_switcher_next(compositor->switcher);
}
static void
switcher_terminate_binding(struct wl_input_device *device,
uint32_t time, uint32_t key, uint32_t button,
uint32_t state, void *data)
{
struct wlsc_compositor *compositor = data;
struct wlsc_input_device *wd = (struct wlsc_input_device *) device;
if (compositor->switcher && !state) {
wlsc_surface_activate(compositor->switcher->current, wd, time);
wlsc_switcher_destroy(compositor->switcher);
compositor->switcher = NULL;
compositor->overlay = NULL;
}
}
void
wlsc_switcher_init(struct wlsc_compositor *compositor)
{
wlsc_compositor_add_binding(compositor,
KEY_TAB, 0, MODIFIER_SUPER,
switcher_next_binding, compositor);
wlsc_compositor_add_binding(compositor,
KEY_LEFTMETA, 0, MODIFIER_SUPER,
switcher_terminate_binding, compositor);
wlsc_compositor_add_binding(compositor,
KEY_RIGHTMETA, 0, MODIFIER_SUPER,
switcher_terminate_binding, compositor);
}
-559
View File
@@ -1,559 +0,0 @@
/*
* Copyright © 2011 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 <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <linux/input.h>
#include "compositor.h"
#include "tablet-shell-server-protocol.h"
/*
* TODO: Don't fade back from black until we've received a lockscreen
* attachment.
*/
enum {
STATE_STARTING,
STATE_LOCKED,
STATE_HOME,
STATE_SWITCHER,
STATE_TASK
};
struct tablet_shell {
struct wl_resource resource;
struct wlsc_shell shell;
struct wlsc_compositor *compositor;
struct wlsc_process process;
struct wlsc_input_device *device;
struct wl_client *client;
struct wlsc_surface *surface;
struct wlsc_surface *lockscreen_surface;
struct wl_listener lockscreen_listener;
struct wlsc_surface *home_surface;
struct wlsc_surface *switcher_surface;
struct wl_listener switcher_listener;
struct tablet_client *current_client;
int state, previous_state;
int long_press_active;
struct wl_event_source *long_press_source;
};
struct tablet_client {
struct wl_resource resource;
struct tablet_shell *shell;
struct wl_client *client;
struct wlsc_surface *surface;
char *name;
};
static void
tablet_shell_sigchld(struct wlsc_process *process, int status)
{
struct tablet_shell *shell =
container_of(process, struct tablet_shell, process);
shell->process.pid = 0;
fprintf(stderr,
"wayland-tablet-daemon crashed, exit code %d\n", status);
}
static void
tablet_shell_set_state(struct tablet_shell *shell, int state)
{
static const char *states[] = {
"STARTING", "LOCKED", "HOME", "SWITCHER", "TASK"
};
fprintf(stderr, "switching to state %s (from %s)\n",
states[state], states[shell->state]);
shell->previous_state = shell->state;
shell->state = state;
}
static void
tablet_shell_map(struct wlsc_shell *base, struct wlsc_surface *surface,
int32_t width, int32_t height)
{
struct tablet_shell *shell =
container_of(base, struct tablet_shell, shell);
surface->x = 0;
surface->y = 0;
if (surface == shell->lockscreen_surface) {
/* */
} else if (surface == shell->switcher_surface) {
/* */
} else if (surface == shell->home_surface) {
if (shell->state == STATE_STARTING) {
tablet_shell_set_state(shell, STATE_LOCKED);
shell->previous_state = STATE_HOME;
wl_resource_post_event(&shell->resource,
TABLET_SHELL_SHOW_LOCKSCREEN);
}
} else if (shell->current_client &&
shell->current_client->surface != surface &&
shell->current_client->client == surface->surface.resource.client) {
tablet_shell_set_state(shell, STATE_TASK);
shell->current_client->surface = surface;
wlsc_zoom_run(surface, 0.3, 1.0, NULL, NULL);
}
wl_list_insert(&shell->compositor->surface_list, &surface->link);
wlsc_surface_configure(surface, surface->x, surface->y, width, height);
}
static void
tablet_shell_configure(struct wlsc_shell *base,
struct wlsc_surface *surface,
int32_t x, int32_t y,
int32_t width, int32_t height)
{
wlsc_surface_configure(surface, x, y, width, height);
}
static void
handle_lockscreen_surface_destroy(struct wl_listener *listener,
struct wl_resource *resource, uint32_t time)
{
struct tablet_shell *shell =
container_of(listener,
struct tablet_shell, lockscreen_listener);
shell->lockscreen_surface = NULL;
tablet_shell_set_state(shell, shell->previous_state);
}
static void
tablet_shell_set_lockscreen(struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *surface_resource)
{
struct tablet_shell *shell = resource->data;
struct wlsc_surface *es = surface_resource->data;
es->x = 0;
es->y = 0;
shell->lockscreen_surface = es;
shell->lockscreen_listener.func = handle_lockscreen_surface_destroy;
wl_list_insert(es->surface.resource.destroy_listener_list.prev,
&shell->lockscreen_listener.link);
}
static void
handle_switcher_surface_destroy(struct wl_listener *listener,
struct wl_resource *resource, uint32_t time)
{
struct tablet_shell *shell =
container_of(listener,
struct tablet_shell, switcher_listener);
shell->switcher_surface = NULL;
if (shell->state != STATE_LOCKED)
tablet_shell_set_state(shell, shell->previous_state);
}
static void
tablet_shell_set_switcher(struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *surface_resource)
{
struct tablet_shell *shell = resource->data;
struct wlsc_surface *es = surface_resource->data;
/* FIXME: Switcher should be centered and the compositor
* should do the tinting of the background. With the cache
* layer idea, we should be able to hit the framerate on the
* fade/zoom in. */
shell->switcher_surface = es;
shell->switcher_surface->x = 0;
shell->switcher_surface->y = 0;
shell->switcher_listener.func = handle_switcher_surface_destroy;
wl_list_insert(es->surface.resource.destroy_listener_list.prev,
&shell->switcher_listener.link);
}
static void
tablet_shell_set_homescreen(struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *surface_resource)
{
struct tablet_shell *shell = resource->data;
shell->home_surface = surface_resource->data;
shell->home_surface->x = 0;
shell->home_surface->y = 0;
}
static void
minimize_zoom_done(struct wlsc_zoom *zoom, void *data)
{
struct tablet_shell *shell = data;
struct wlsc_compositor *compositor = shell->compositor;
struct wlsc_input_device *device =
(struct wlsc_input_device *) compositor->input_device;
wlsc_surface_activate(shell->home_surface,
device, wlsc_compositor_get_time());
}
static void
tablet_shell_switch_to(struct tablet_shell *shell,
struct wlsc_surface *surface)
{
struct wlsc_compositor *compositor = shell->compositor;
struct wlsc_input_device *device =
(struct wlsc_input_device *) compositor->input_device;
struct wlsc_surface *current;
if (shell->state == STATE_SWITCHER) {
wl_list_remove(&shell->switcher_listener.link);
shell->switcher_surface = NULL;
};
if (surface == shell->home_surface) {
tablet_shell_set_state(shell, STATE_HOME);
if (shell->current_client && shell->current_client->surface) {
current = shell->current_client->surface;
wlsc_zoom_run(current, 1.0, 0.3,
minimize_zoom_done, shell);
}
} else {
fprintf(stderr, "switch to %p\n", surface);
wlsc_surface_activate(surface, device,
wlsc_compositor_get_time());
tablet_shell_set_state(shell, STATE_TASK);
wlsc_zoom_run(surface, 0.3, 1.0, NULL, NULL);
}
}
static void
tablet_shell_show_grid(struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *surface_resource)
{
struct tablet_shell *shell = resource->data;
struct wlsc_surface *es = surface_resource->data;
tablet_shell_switch_to(shell, es);
}
static void
tablet_shell_show_panels(struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *surface_resource)
{
struct tablet_shell *shell = resource->data;
struct wlsc_surface *es = surface_resource->data;
tablet_shell_switch_to(shell, es);
}
static void
destroy_tablet_client(struct wl_resource *resource)
{
struct tablet_client *tablet_client =
container_of(resource, struct tablet_client, resource);
free(tablet_client->name);
free(tablet_client);
}
static void
tablet_client_destroy(struct wl_client *client,
struct wl_resource *resource)
{
wl_resource_destroy(resource, wlsc_compositor_get_time());
}
static void
tablet_client_activate(struct wl_client *client, struct wl_resource *resource)
{
struct tablet_client *tablet_client = resource->data;
struct tablet_shell *shell = tablet_client->shell;
shell->current_client = tablet_client;
if (!tablet_client->surface)
return;
tablet_shell_switch_to(shell, tablet_client->surface);
}
static const struct tablet_client_interface tablet_client_implementation = {
tablet_client_destroy,
tablet_client_activate
};
static void
tablet_shell_create_client(struct wl_client *client,
struct wl_resource *resource,
uint32_t id, const char *name, int fd)
{
struct tablet_shell *shell = resource->data;
struct wlsc_compositor *compositor = shell->compositor;
struct tablet_client *tablet_client;
tablet_client = malloc(sizeof *tablet_client);
if (tablet_client == NULL) {
wl_resource_post_no_memory(resource);
return;
}
tablet_client->client = wl_client_create(compositor->wl_display, fd);
tablet_client->shell = shell;
tablet_client->name = strdup(name);
tablet_client->resource.destroy = destroy_tablet_client;
tablet_client->resource.object.id = id;
tablet_client->resource.object.interface =
&tablet_client_interface;
tablet_client->resource.object.implementation =
(void (**)(void)) &tablet_client_implementation;
wl_client_add_resource(client, &tablet_client->resource);
tablet_client->surface = NULL;
shell->current_client = tablet_client;
fprintf(stderr, "created client %p, id %d, name %s, fd %d\n",
tablet_client->client, id, name, fd);
}
static const struct tablet_shell_interface tablet_shell_implementation = {
tablet_shell_set_lockscreen,
tablet_shell_set_switcher,
tablet_shell_set_homescreen,
tablet_shell_show_grid,
tablet_shell_show_panels,
tablet_shell_create_client
};
static void
launch_ux_daemon(struct tablet_shell *shell)
{
const char *shell_exe = LIBEXECDIR "/wayland-tablet-shell";
shell->client = wlsc_client_launch(shell->compositor,
&shell->process,
shell_exe, tablet_shell_sigchld);
}
static void
toggle_switcher(struct tablet_shell *shell)
{
switch (shell->state) {
case STATE_SWITCHER:
wl_resource_post_event(&shell->resource,
TABLET_SHELL_HIDE_SWITCHER);
break;
default:
wl_resource_post_event(&shell->resource,
TABLET_SHELL_SHOW_SWITCHER);
tablet_shell_set_state(shell, STATE_SWITCHER);
break;
}
}
static void
tablet_shell_lock(struct wlsc_shell *base)
{
struct tablet_shell *shell =
container_of(base, struct tablet_shell, shell);
if (shell->state == STATE_LOCKED)
return;
if (shell->state == STATE_SWITCHER)
wl_resource_post_event(&shell->resource,
TABLET_SHELL_HIDE_SWITCHER);
wl_resource_post_event(&shell->resource,
TABLET_SHELL_SHOW_LOCKSCREEN);
tablet_shell_set_state(shell, STATE_LOCKED);
}
static void
tablet_shell_unlock(struct wlsc_shell *base)
{
struct tablet_shell *shell =
container_of(base, struct tablet_shell, shell);
wlsc_compositor_wake(shell->compositor);
}
static void
go_home(struct tablet_shell *shell)
{
struct wlsc_input_device *device =
(struct wlsc_input_device *) shell->compositor->input_device;
if (shell->state == STATE_SWITCHER)
wl_resource_post_event(&shell->resource,
TABLET_SHELL_HIDE_SWITCHER);
wlsc_surface_activate(shell->home_surface, device,
wlsc_compositor_get_time());
tablet_shell_set_state(shell, STATE_HOME);
}
static int
long_press_handler(void *data)
{
struct tablet_shell *shell = data;
shell->long_press_active = 0;
toggle_switcher(shell);
return 1;
}
static void
menu_key_binding(struct wl_input_device *device, uint32_t time,
uint32_t key, uint32_t button, uint32_t state, void *data)
{
struct tablet_shell *shell = data;
if (shell->state == STATE_LOCKED)
return;
if (state)
toggle_switcher(shell);
}
static void
home_key_binding(struct wl_input_device *device, uint32_t time,
uint32_t key, uint32_t button, uint32_t state, void *data)
{
struct tablet_shell *shell = data;
if (shell->state == STATE_LOCKED)
return;
shell->device = (struct wlsc_input_device *) device;
if (state) {
wl_event_source_timer_update(shell->long_press_source, 500);
shell->long_press_active = 1;
} else if (shell->long_press_active) {
wl_event_source_timer_update(shell->long_press_source, 0);
shell->long_press_active = 0;
switch (shell->state) {
case STATE_HOME:
case STATE_SWITCHER:
toggle_switcher(shell);
break;
default:
go_home(shell);
break;
}
}
}
static void
destroy_tablet_shell(struct wl_resource *resource)
{
}
static void
bind_shell(struct wl_client *client, void *data, uint32_t version, uint32_t id)
{
struct tablet_shell *shell = data;
if (shell->client != client)
/* Throw an error or just let the client fail when it
* tries to access the object?. */
return;
shell->resource.object.id = id;
shell->resource.object.interface = &tablet_shell_interface;
shell->resource.object.implementation =
(void (**)(void)) &tablet_shell_implementation;
shell->resource.client = client;
shell->resource.data = shell;
shell->resource.destroy = destroy_tablet_shell;
wl_client_add_resource(client, &shell->resource);
}
void
shell_init(struct wlsc_compositor *compositor);
WL_EXPORT void
shell_init(struct wlsc_compositor *compositor)
{
struct tablet_shell *shell;
struct wl_event_loop *loop;
shell = malloc(sizeof *shell);
if (shell == NULL)
return;
memset(shell, 0, sizeof *shell);
shell->compositor = compositor;
/* FIXME: This will make the object available to all clients. */
wl_display_add_global(compositor->wl_display,
&tablet_shell_interface, shell, bind_shell);
loop = wl_display_get_event_loop(compositor->wl_display);
shell->long_press_source =
wl_event_loop_add_timer(loop, long_press_handler, shell);
wlsc_compositor_add_binding(compositor, KEY_LEFTMETA, 0, 0,
home_key_binding, shell);
wlsc_compositor_add_binding(compositor, KEY_RIGHTMETA, 0, 0,
home_key_binding, shell);
wlsc_compositor_add_binding(compositor, KEY_LEFTMETA, 0,
MODIFIER_SUPER, home_key_binding, shell);
wlsc_compositor_add_binding(compositor, KEY_RIGHTMETA, 0,
MODIFIER_SUPER, home_key_binding, shell);
wlsc_compositor_add_binding(compositor, KEY_COMPOSE, 0, 0,
menu_key_binding, shell);
compositor->shell = &shell->shell;
shell->shell.lock = tablet_shell_lock;
shell->shell.unlock = tablet_shell_unlock;
shell->shell.map = tablet_shell_map;
shell->shell.configure = tablet_shell_configure;
launch_ux_daemon(shell);
tablet_shell_set_state(shell, STATE_STARTING);
}
-176
View File
@@ -1,176 +0,0 @@
/*
* 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 <termios.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <linux/kd.h>
#include <linux/vt.h>
#include <sys/ioctl.h>
#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;
tty_vt_func_t vt_func;
};
static int on_enter_vt(int signal_number, void *data)
{
struct tty *tty = data;
int ret;
tty->vt_func(tty->compositor, TTY_ENTER_VT);
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");
return 1;
}
static int
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->vt_func(tty->compositor, TTY_LEAVE_VT);
return 1;
}
static int
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);
return 1;
}
struct tty *
tty_create(struct wlsc_compositor *compositor, tty_vt_func_t vt_func,
int tty_nr)
{
struct termios raw_attributes;
struct vt_mode mode = { 0 };
int ret;
struct tty *tty;
struct wl_event_loop *loop;
char filename[16];
tty = malloc(sizeof *tty);
if (tty == NULL)
return NULL;
snprintf(filename, sizeof filename, "/dev/tty%d", tty_nr);
fprintf(stderr, "compositor: using %s\n", filename);
memset(tty, 0, sizeof *tty);
tty->compositor = compositor;
tty->vt_func = vt_func;
tty->fd = open(filename, 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)
{
if(!tty)
return;
if (ioctl(tty->fd, KDSETMODE, KD_TEXT))
fprintf(stderr,
"failed to set KD_TEXT 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);
}
-301
View File
@@ -1,301 +0,0 @@
/*
* Copyright © 2011 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 <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include "compositor.h"
WL_EXPORT void
wlsc_matrix_init(struct wlsc_matrix *matrix)
{
static const struct wlsc_matrix identity = {
{ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 }
};
memcpy(matrix, &identity, sizeof identity);
}
static void
wlsc_matrix_multiply(struct wlsc_matrix *m, const struct wlsc_matrix *n)
{
struct wlsc_matrix tmp;
const GLfloat *row, *column;
div_t d;
int i, j;
for (i = 0; i < 16; i++) {
tmp.d[i] = 0;
d = div(i, 4);
row = m->d + d.quot * 4;
column = n->d + d.rem;
for (j = 0; j < 4; j++)
tmp.d[i] += row[j] * column[j * 4];
}
memcpy(m, &tmp, sizeof tmp);
}
WL_EXPORT void
wlsc_matrix_translate(struct wlsc_matrix *matrix, GLfloat x, GLfloat y, GLfloat z)
{
struct wlsc_matrix translate = {
{ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, x, y, z, 1 }
};
wlsc_matrix_multiply(matrix, &translate);
}
WL_EXPORT void
wlsc_matrix_scale(struct wlsc_matrix *matrix, GLfloat x, GLfloat y, GLfloat z)
{
struct wlsc_matrix scale = {
{ x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, 0, 0, 0, 1 }
};
wlsc_matrix_multiply(matrix, &scale);
}
WL_EXPORT void
wlsc_matrix_transform(struct wlsc_matrix *matrix, struct wlsc_vector *v)
{
int i, j;
struct wlsc_vector t;
for (i = 0; i < 4; i++) {
t.f[i] = 0;
for (j = 0; j < 4; j++)
t.f[i] += v->f[j] * matrix->d[i + j * 4];
}
*v = t;
}
WL_EXPORT void
wlsc_spring_init(struct wlsc_spring *spring,
double k, double current, double target)
{
spring->k = k;
spring->friction = 400.0;
spring->current = current;
spring->previous = current;
spring->target = target;
}
WL_EXPORT void
wlsc_spring_update(struct wlsc_spring *spring, uint32_t msec)
{
double force, v, current, step;
step = 0.01;
while (4 < msec - spring->timestamp) {
current = spring->current;
v = current - spring->previous;
force = spring->k * (spring->target - current) / 10.0 +
(spring->previous - current) - v * spring->friction;
spring->current =
current + (current - spring->previous) +
force * step * step;
spring->previous = current;
#if 0
if (spring->current >= 1.0) {
#ifdef TWEENER_BOUNCE
spring->current = 2.0 - spring->current;
spring->previous = 2.0 - spring->previous;
#else
spring->current = 1.0;
spring->previous = 1.0;
#endif
}
if (spring->current <= 0.0) {
spring->current = 0.0;
spring->previous = 0.0;
}
#endif
spring->timestamp += 4;
}
}
WL_EXPORT int
wlsc_spring_done(struct wlsc_spring *spring)
{
return fabs(spring->previous - spring->target) < 0.0002 &&
fabs(spring->current - spring->target) < 0.0002;
}
struct wlsc_zoom {
struct wlsc_surface *surface;
struct wlsc_animation animation;
struct wlsc_spring spring;
struct wlsc_transform transform;
struct wl_listener listener;
GLfloat start, stop;
void (*done)(struct wlsc_zoom *zoom, void *data);
void *data;
};
static void
wlsc_zoom_destroy(struct wlsc_zoom *zoom)
{
wl_list_remove(&zoom->animation.link);
wl_list_remove(&zoom->listener.link);
zoom->surface->transform = NULL;
if (zoom->done)
zoom->done(zoom, zoom->data);
free(zoom);
}
static void
handle_zoom_surface_destroy(struct wl_listener *listener,
struct wl_resource *resource, uint32_t time)
{
struct wlsc_zoom *zoom =
container_of(listener, struct wlsc_zoom, listener);
wlsc_zoom_destroy(zoom);
}
static void
wlsc_zoom_frame(struct wlsc_animation *animation,
struct wlsc_output *output, uint32_t msecs)
{
struct wlsc_zoom *zoom =
container_of(animation, struct wlsc_zoom, animation);
struct wlsc_surface *es = zoom->surface;
GLfloat scale;
wlsc_spring_update(&zoom->spring, msecs);
if (wlsc_spring_done(&zoom->spring))
wlsc_zoom_destroy(zoom);
scale = zoom->start +
(zoom->stop - zoom->start) * zoom->spring.current;
wlsc_matrix_init(&zoom->transform.matrix);
wlsc_matrix_translate(&zoom->transform.matrix,
-(es->x + es->width / 2.0),
-(es->y + es->height / 2.0), 0);
wlsc_matrix_scale(&zoom->transform.matrix, scale, scale, scale);
wlsc_matrix_translate(&zoom->transform.matrix,
es->x + es->width / 2.0,
es->y + es->height / 2.0, 0);
es->alpha = zoom->spring.current * 255;
if (es->alpha > 255)
es->alpha = 255;
scale = 1.0 / zoom->spring.current;
wlsc_matrix_init(&zoom->transform.inverse);
wlsc_matrix_scale(&zoom->transform.inverse, scale, scale, scale);
wlsc_compositor_damage_all(es->compositor);
}
WL_EXPORT struct wlsc_zoom *
wlsc_zoom_run(struct wlsc_surface *surface, GLfloat start, GLfloat stop,
wlsc_zoom_done_func_t done, void *data)
{
struct wlsc_zoom *zoom;
zoom = malloc(sizeof *zoom);
if (!zoom)
return NULL;
zoom->surface = surface;
zoom->done = done;
zoom->data = data;
zoom->start = start;
zoom->stop = stop;
surface->transform = &zoom->transform;
wlsc_spring_init(&zoom->spring, 200.0, 0.0, 1.0);
zoom->spring.friction = 700;
zoom->spring.timestamp = wlsc_compositor_get_time();
zoom->animation.frame = wlsc_zoom_frame;
wlsc_zoom_frame(&zoom->animation, NULL, zoom->spring.timestamp);
zoom->listener.func = handle_zoom_surface_destroy;
wl_list_insert(surface->surface.resource.destroy_listener_list.prev,
&zoom->listener.link);
wl_list_insert(surface->compositor->animation_list.prev,
&zoom->animation.link);
return zoom;
}
struct wlsc_binding {
uint32_t key;
uint32_t button;
uint32_t modifier;
wlsc_binding_handler_t handler;
void *data;
struct wl_list link;
};
WL_EXPORT struct wlsc_binding *
wlsc_compositor_add_binding(struct wlsc_compositor *compositor,
uint32_t key, uint32_t button, uint32_t modifier,
wlsc_binding_handler_t handler, void *data)
{
struct wlsc_binding *binding;
binding = malloc(sizeof *binding);
if (binding == NULL)
return NULL;
binding->key = key;
binding->button = button;
binding->modifier = modifier;
binding->handler = handler;
binding->data = data;
wl_list_insert(compositor->binding_list.prev, &binding->link);
return binding;
}
WL_EXPORT void
wlsc_binding_destroy(struct wlsc_binding *binding)
{
wl_list_remove(&binding->link);
free(binding);
}
WL_EXPORT void
wlsc_compositor_run_binding(struct wlsc_compositor *compositor,
struct wlsc_input_device *device,
uint32_t time,
uint32_t key, uint32_t button, int32_t state)
{
struct wlsc_binding *b;
wl_list_for_each(b, &compositor->binding_list, link) {
if (b->key == key && b->button == button &&
b->modifier == device->modifier_state && state) {
b->handler(&device->input_device,
time, key, button, state, b->data);
break;
}
}
}
File diff suppressed because it is too large Load Diff