/* * Copyright © 2008 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. * * Authors: * Kristian Høgsberg * Benjamin Franzke * */ #include #include #include #include #include #include "wayland-server.h" struct wl_shm { const struct wl_shm_callbacks *callbacks; }; struct wl_shm_buffer { struct wl_buffer buffer; struct wl_shm *shm; int32_t stride; uint32_t format; void *data; }; static void destroy_buffer(struct wl_resource *resource) { struct wl_shm_buffer *buffer = container_of(resource, struct wl_shm_buffer, buffer.resource); munmap(buffer->data, buffer->stride * buffer->buffer.height); buffer->shm->callbacks->buffer_destroyed(&buffer->buffer); free(buffer); } static void shm_buffer_damage(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) { struct wl_shm_buffer *buffer = resource->data; buffer->shm->callbacks->buffer_damaged(&buffer->buffer, x, y, width, height); } static void shm_buffer_destroy(struct wl_client *client, struct wl_resource *resource) { wl_resource_destroy(resource, 0); } const static struct wl_buffer_interface shm_buffer_interface = { shm_buffer_damage, shm_buffer_destroy }; static struct wl_shm_buffer * wl_shm_buffer_init(struct wl_shm *shm, struct wl_client *client, uint32_t id, int32_t width, int32_t height, int32_t stride, uint32_t format, void *data) { struct wl_shm_buffer *buffer; buffer = calloc(1, sizeof *buffer); if (buffer == NULL) return NULL; buffer->buffer.width = width; buffer->buffer.height = height; buffer->format = format; buffer->stride = stride; buffer->data = data; buffer->buffer.resource.object.id = id; buffer->buffer.resource.object.interface = &wl_buffer_interface; buffer->buffer.resource.object.implementation = (void (**)(void)) &shm_buffer_interface; buffer->buffer.resource.data = buffer; buffer->buffer.resource.client = client; buffer->buffer.resource.destroy = destroy_buffer; buffer->shm = shm; buffer->shm->callbacks->buffer_created(&buffer->buffer); return buffer; } static void shm_create_buffer(struct wl_client *client, struct wl_resource *resource, uint32_t id, int fd, int32_t width, int32_t height, uint32_t stride, uint32_t format) { struct wl_shm *shm = resource->data; struct wl_shm_buffer *buffer; void *data; switch (format) { case WL_SHM_FORMAT_ARGB8888: case WL_SHM_FORMAT_XRGB8888: break; default: wl_resource_post_error(resource, WL_SHM_ERROR_INVALID_FORMAT, "invalid format"); close(fd); return; } if (width < 0 || height < 0 || stride < width) { wl_resource_post_error(resource, WL_SHM_ERROR_INVALID_STRIDE, "invalid width, height or stride (%dx%d, %u)", width, height, stride); close(fd); return; } data = mmap(NULL, stride * height, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); close(fd); if (data == MAP_FAILED) { wl_resource_post_error(resource, WL_SHM_ERROR_INVALID_FD, "failed mmap fd %d", fd); return; } buffer = wl_shm_buffer_init(shm, client, id, width, height, stride, format, data); if (buffer == NULL) { munmap(data, stride * height); wl_resource_post_no_memory(resource); return; } wl_client_add_resource(client, &buffer->buffer.resource); } const static struct wl_shm_interface shm_interface = { shm_create_buffer }; static void bind_shm(struct wl_client *client, void *data, uint32_t version, uint32_t id) { struct wl_resource *resource; resource = wl_client_add_object(client, &wl_shm_interface, &shm_interface, id, data); wl_resource_post_event(resource, WL_SHM_FORMAT, WL_SHM_FORMAT_ARGB8888); wl_resource_post_event(resource, WL_SHM_FORMAT, WL_SHM_FORMAT_XRGB8888); } WL_EXPORT struct wl_shm * wl_shm_init(struct wl_display *display, const struct wl_shm_callbacks *callbacks) { struct wl_shm *shm; shm = malloc(sizeof *shm); if (!shm) return NULL; if (!wl_display_add_global(display, &wl_shm_interface, shm, bind_shm)) { free(shm); return NULL; } shm->callbacks = callbacks; return shm; } WL_EXPORT void wl_shm_finish(struct wl_shm *shm) { /* FIXME: add wl_display_del_{object,global} */ free(shm); } WL_EXPORT int wl_buffer_is_shm(struct wl_buffer *buffer) { return buffer->resource.object.implementation == (void (**)(void)) &shm_buffer_interface; } WL_EXPORT int32_t wl_shm_buffer_get_stride(struct wl_buffer *buffer_base) { struct wl_shm_buffer *buffer = (struct wl_shm_buffer *) buffer_base; if (!wl_buffer_is_shm(buffer_base)) return 0; return buffer->stride; } WL_EXPORT void * wl_shm_buffer_get_data(struct wl_buffer *buffer_base) { struct wl_shm_buffer *buffer = (struct wl_shm_buffer *) buffer_base; if (!wl_buffer_is_shm(buffer_base)) return NULL; return buffer->data; } WL_EXPORT uint32_t wl_shm_buffer_get_format(struct wl_buffer *buffer_base) { struct wl_shm_buffer *buffer = (struct wl_shm_buffer *) buffer_base; return buffer->format; }