summaryrefslogtreecommitdiff
path: root/shared
diff options
context:
space:
mode:
Diffstat (limited to 'shared')
-rw-r--r--shared/Makefile.am32
-rw-r--r--shared/cairo-util.c511
-rw-r--r--shared/cairo-util.h89
-rw-r--r--shared/config-parser.c434
-rw-r--r--shared/config-parser.h114
-rw-r--r--shared/image-loader.c405
-rw-r--r--shared/image-loader.h31
-rw-r--r--shared/matrix.c273
-rw-r--r--shared/matrix.h82
-rw-r--r--shared/option-parser.c85
-rw-r--r--shared/os-compatibility.c180
-rw-r--r--shared/os-compatibility.h54
-rw-r--r--shared/zalloc.h42
13 files changed, 2332 insertions, 0 deletions
diff --git a/shared/Makefile.am b/shared/Makefile.am
new file mode 100644
index 00000000..2fcff7bb
--- /dev/null
+++ b/shared/Makefile.am
@@ -0,0 +1,32 @@
+noinst_LTLIBRARIES = libshared.la libshared-cairo.la
+
+libshared_la_CFLAGS = $(GCC_CFLAGS) $(COMPOSITOR_CFLAGS)
+
+libshared_la_SOURCES = \
+ config-parser.c \
+ option-parser.c \
+ config-parser.h \
+ os-compatibility.c \
+ os-compatibility.h
+
+libshared_cairo_la_CFLAGS = \
+ $(GCC_CFLAGS) \
+ $(COMPOSITOR_CFLAGS) \
+ $(PIXMAN_CFLAGS) \
+ $(CAIRO_CFLAGS) \
+ $(PNG_CFLAGS) \
+ $(WEBP_CFLAGS)
+
+libshared_cairo_la_LIBADD = \
+ $(PIXMAN_LIBS) \
+ $(CAIRO_LIBS) \
+ $(PNG_LIBS) \
+ $(WEBP_LIBS) \
+ $(JPEG_LIBS)
+
+libshared_cairo_la_SOURCES = \
+ $(libshared_la_SOURCES) \
+ image-loader.c \
+ image-loader.h \
+ cairo-util.c \
+ cairo-util.h
diff --git a/shared/cairo-util.c b/shared/cairo-util.c
new file mode 100644
index 00000000..4305ba69
--- /dev/null
+++ b/shared/cairo-util.c
@@ -0,0 +1,511 @@
+/*
+ * Copyright © 2008 Kristian Høgsberg
+ * Copyright © 2012 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 "config.h"
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+#include <cairo.h>
+#include "cairo-util.h"
+
+#include "image-loader.h"
+#include "config-parser.h"
+
+#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
+
+void
+surface_flush_device(cairo_surface_t *surface)
+{
+ cairo_device_t *device;
+
+ device = cairo_surface_get_device(surface);
+ if (device)
+ cairo_device_flush(device);
+}
+
+static int
+blur_surface(cairo_surface_t *surface, int margin)
+{
+ int32_t width, height, stride, x, y, z, w;
+ uint8_t *src, *dst;
+ uint32_t *s, *d, a, p;
+ int i, j, k, size, half;
+ uint32_t kernel[71];
+ double f;
+
+ size = ARRAY_LENGTH(kernel);
+ width = cairo_image_surface_get_width(surface);
+ height = cairo_image_surface_get_height(surface);
+ stride = cairo_image_surface_get_stride(surface);
+ src = cairo_image_surface_get_data(surface);
+
+ dst = malloc(height * stride);
+ if (dst == NULL)
+ return -1;
+
+ half = size / 2;
+ a = 0;
+ for (i = 0; i < size; i++) {
+ f = (i - half);
+ kernel[i] = exp(- f * f / ARRAY_LENGTH(kernel)) * 10000;
+ a += kernel[i];
+ }
+
+ for (i = 0; i < height; i++) {
+ s = (uint32_t *) (src + i * stride);
+ d = (uint32_t *) (dst + i * stride);
+ for (j = 0; j < width; j++) {
+ if (margin < j && j < width - margin) {
+ d[j] = s[j];
+ continue;
+ }
+
+ x = 0;
+ y = 0;
+ z = 0;
+ w = 0;
+ for (k = 0; k < size; k++) {
+ if (j - half + k < 0 || j - half + k >= width)
+ continue;
+ p = s[j - half + k];
+
+ x += (p >> 24) * kernel[k];
+ y += ((p >> 16) & 0xff) * kernel[k];
+ z += ((p >> 8) & 0xff) * kernel[k];
+ w += (p & 0xff) * kernel[k];
+ }
+ d[j] = (x / a << 24) | (y / a << 16) | (z / a << 8) | w / a;
+ }
+ }
+
+ for (i = 0; i < height; i++) {
+ s = (uint32_t *) (dst + i * stride);
+ d = (uint32_t *) (src + i * stride);
+ for (j = 0; j < width; j++) {
+ if (margin <= i && i < height - margin) {
+ d[j] = s[j];
+ continue;
+ }
+
+ x = 0;
+ y = 0;
+ z = 0;
+ w = 0;
+ for (k = 0; k < size; k++) {
+ if (i - half + k < 0 || i - half + k >= height)
+ continue;
+ s = (uint32_t *) (dst + (i - half + k) * stride);
+ p = s[j];
+
+ x += (p >> 24) * kernel[k];
+ y += ((p >> 16) & 0xff) * kernel[k];
+ z += ((p >> 8) & 0xff) * kernel[k];
+ w += (p & 0xff) * kernel[k];
+ }
+ d[j] = (x / a << 24) | (y / a << 16) | (z / a << 8) | w / a;
+ }
+ }
+
+ free(dst);
+ cairo_surface_mark_dirty(surface);
+
+ return 0;
+}
+
+void
+tile_mask(cairo_t *cr, cairo_surface_t *surface,
+ int x, int y, int width, int height, int margin, int top_margin)
+{
+ cairo_pattern_t *pattern;
+ cairo_matrix_t matrix;
+ int i, fx, fy, vmargin;
+
+ cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
+ pattern = cairo_pattern_create_for_surface (surface);
+ cairo_pattern_set_filter(pattern, CAIRO_FILTER_NEAREST);
+
+ for (i = 0; i < 4; i++) {
+ fx = i & 1;
+ fy = i >> 1;
+
+ cairo_matrix_init_translate(&matrix,
+ -x + fx * (128 - width),
+ -y + fy * (128 - height));
+ cairo_pattern_set_matrix(pattern, &matrix);
+
+ if (fy)
+ vmargin = margin;
+ else
+ vmargin = top_margin;
+
+ cairo_reset_clip(cr);
+ cairo_rectangle(cr,
+ x + fx * (width - margin),
+ y + fy * (height - vmargin),
+ margin, vmargin);
+ cairo_clip (cr);
+ cairo_mask(cr, pattern);
+ }
+
+ /* Top stretch */
+ cairo_matrix_init_translate(&matrix, 60, 0);
+ cairo_matrix_scale(&matrix, 8.0 / width, 1);
+ cairo_matrix_translate(&matrix, -x - width / 2, -y);
+ cairo_pattern_set_matrix(pattern, &matrix);
+ cairo_rectangle(cr, x + margin, y, width - 2 * margin, margin);
+
+ cairo_reset_clip(cr);
+ cairo_rectangle(cr,
+ x + margin,
+ y,
+ width - 2 * margin, margin);
+ cairo_clip (cr);
+ cairo_mask(cr, pattern);
+
+ /* Bottom stretch */
+ cairo_matrix_translate(&matrix, 0, -height + 128);
+ cairo_pattern_set_matrix(pattern, &matrix);
+
+ cairo_reset_clip(cr);
+ cairo_rectangle(cr, x + margin, y + height - margin,
+ width - 2 * margin, margin);
+ cairo_clip (cr);
+ cairo_mask(cr, pattern);
+
+ /* Left stretch */
+ cairo_matrix_init_translate(&matrix, 0, 60);
+ cairo_matrix_scale(&matrix, 1, 8.0 / height);
+ cairo_matrix_translate(&matrix, -x, -y - height / 2);
+ cairo_pattern_set_matrix(pattern, &matrix);
+ cairo_reset_clip(cr);
+ cairo_rectangle(cr, x, y + margin, margin, height - 2 * margin);
+ cairo_clip (cr);
+ cairo_mask(cr, pattern);
+
+ /* Right stretch */
+ cairo_matrix_translate(&matrix, -width + 128, 0);
+ cairo_pattern_set_matrix(pattern, &matrix);
+ cairo_rectangle(cr, x + width - margin, y + margin,
+ margin, height - 2 * margin);
+ cairo_reset_clip(cr);
+ cairo_clip (cr);
+ cairo_mask(cr, pattern);
+
+ cairo_pattern_destroy(pattern);
+ cairo_reset_clip(cr);
+}
+
+void
+tile_source(cairo_t *cr, cairo_surface_t *surface,
+ int x, int y, int width, int height, int margin, int top_margin)
+{
+ cairo_pattern_t *pattern;
+ cairo_matrix_t matrix;
+ int i, fx, fy, vmargin;
+
+ cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
+ pattern = cairo_pattern_create_for_surface (surface);
+ cairo_pattern_set_filter(pattern, CAIRO_FILTER_NEAREST);
+ cairo_set_source(cr, pattern);
+ cairo_pattern_destroy(pattern);
+
+ for (i = 0; i < 4; i++) {
+ fx = i & 1;
+ fy = i >> 1;
+
+ cairo_matrix_init_translate(&matrix,
+ -x + fx * (128 - width),
+ -y + fy * (128 - height));
+ cairo_pattern_set_matrix(pattern, &matrix);
+
+ if (fy)
+ vmargin = margin;
+ else
+ vmargin = top_margin;
+
+ cairo_rectangle(cr,
+ x + fx * (width - margin),
+ y + fy * (height - vmargin),
+ margin, vmargin);
+ cairo_fill(cr);
+ }
+
+ /* Top stretch */
+ cairo_matrix_init_translate(&matrix, 60, 0);
+ cairo_matrix_scale(&matrix, 8.0 / (width - 2 * margin), 1);
+ cairo_matrix_translate(&matrix, -x - width / 2, -y);
+ cairo_pattern_set_matrix(pattern, &matrix);
+ cairo_rectangle(cr, x + margin, y, width - 2 * margin, top_margin);
+ cairo_fill(cr);
+
+ /* Bottom stretch */
+ cairo_matrix_translate(&matrix, 0, -height + 128);
+ cairo_pattern_set_matrix(pattern, &matrix);
+ cairo_rectangle(cr, x + margin, y + height - margin,
+ width - 2 * margin, margin);
+ cairo_fill(cr);
+
+ /* Left stretch */
+ cairo_matrix_init_translate(&matrix, 0, 60);
+ cairo_matrix_scale(&matrix, 1, 8.0 / (height - margin - top_margin));
+ cairo_matrix_translate(&matrix, -x, -y - height / 2);
+ cairo_pattern_set_matrix(pattern, &matrix);
+ cairo_rectangle(cr, x, y + top_margin,
+ margin, height - margin - top_margin);
+ cairo_fill(cr);
+
+ /* Right stretch */
+ cairo_matrix_translate(&matrix, -width + 128, 0);
+ cairo_pattern_set_matrix(pattern, &matrix);
+ cairo_rectangle(cr, x + width - margin, y + top_margin,
+ margin, height - margin - top_margin);
+ cairo_fill(cr);
+}
+
+void
+rounded_rect(cairo_t *cr, int x0, int y0, int x1, int y1, int radius)
+{
+ cairo_move_to(cr, x0, y0 + radius);
+ cairo_arc(cr, x0 + radius, y0 + radius, radius, M_PI, 3 * M_PI / 2);
+ cairo_line_to(cr, x1 - radius, y0);
+ cairo_arc(cr, x1 - radius, y0 + radius, radius, 3 * M_PI / 2, 2 * M_PI);
+ cairo_line_to(cr, x1, y1 - radius);
+ cairo_arc(cr, x1 - radius, y1 - radius, radius, 0, M_PI / 2);
+ cairo_line_to(cr, x0 + radius, y1);
+ cairo_arc(cr, x0 + radius, y1 - radius, radius, M_PI / 2, M_PI);
+ cairo_close_path(cr);
+}
+
+cairo_surface_t *
+load_cairo_surface(const char *filename)
+{
+ pixman_image_t *image;
+ int width, height, stride;
+ void *data;
+
+ image = load_image(filename);
+ if (image == NULL) {
+ return NULL;
+ }
+
+ data = pixman_image_get_data(image);
+ width = pixman_image_get_width(image);
+ height = pixman_image_get_height(image);
+ stride = pixman_image_get_stride(image);
+
+ return cairo_image_surface_create_for_data(data, CAIRO_FORMAT_ARGB32,
+ width, height, stride);
+}
+
+struct theme *
+theme_create(void)
+{
+ struct theme *t;
+ cairo_t *cr;
+ cairo_pattern_t *pattern;
+
+ t = malloc(sizeof *t);
+ if (t == NULL)
+ return NULL;
+
+ t->margin = 32;
+ t->width = 6;
+ t->titlebar_height = 27;
+ t->frame_radius = 3;
+ t->shadow = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 128, 128);
+ cr = cairo_create(t->shadow);
+ cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
+ cairo_set_source_rgba(cr, 0, 0, 0, 1);
+ rounded_rect(cr, 32, 32, 96, 96, t->frame_radius);
+ cairo_fill(cr);
+ if (cairo_status (cr) != CAIRO_STATUS_SUCCESS)
+ goto err_shadow;
+ cairo_destroy(cr);
+ if (blur_surface(t->shadow, 64) == -1)
+ goto err_shadow;
+
+ t->active_frame =
+ cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 128, 128);
+ cr = cairo_create(t->active_frame);
+ cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
+
+ pattern = cairo_pattern_create_linear(16, 16, 16, 112);
+ cairo_pattern_add_color_stop_rgb(pattern, 0.0, 1.0, 1.0, 1.0);
+ cairo_pattern_add_color_stop_rgb(pattern, 0.2, 0.8, 0.8, 0.8);
+ cairo_set_source(cr, pattern);
+ cairo_pattern_destroy(pattern);
+
+ rounded_rect(cr, 0, 0, 128, 128, t->frame_radius);
+ cairo_fill(cr);
+
+ if (cairo_status(cr) != CAIRO_STATUS_SUCCESS)
+ goto err_active_frame;
+
+ cairo_destroy(cr);
+
+ t->inactive_frame =
+ cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 128, 128);
+ cr = cairo_create(t->inactive_frame);
+ cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
+ cairo_set_source_rgba(cr, 0.75, 0.75, 0.75, 1);
+ rounded_rect(cr, 0, 0, 128, 128, t->frame_radius);
+ cairo_fill(cr);
+
+ if (cairo_status (cr) != CAIRO_STATUS_SUCCESS)
+ goto err_inactive_frame;
+
+ cairo_destroy(cr);
+
+ return t;
+
+ err_inactive_frame:
+ cairo_surface_destroy(t->inactive_frame);
+ err_active_frame:
+ cairo_surface_destroy(t->active_frame);
+ err_shadow:
+ cairo_surface_destroy(t->shadow);
+ free(t);
+ return NULL;
+}
+
+void
+theme_destroy(struct theme *t)
+{
+ cairo_surface_destroy(t->active_frame);
+ cairo_surface_destroy(t->inactive_frame);
+ cairo_surface_destroy(t->shadow);
+ free(t);
+}
+
+void
+theme_render_frame(struct theme *t,
+ cairo_t *cr, int width, int height,
+ const char *title, uint32_t flags)
+{
+ cairo_text_extents_t extents;
+ cairo_font_extents_t font_extents;
+ cairo_surface_t *source;
+ int x, y, margin;
+
+ cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+ cairo_set_source_rgba(cr, 0, 0, 0, 0);
+ cairo_paint(cr);
+
+ if (flags & THEME_FRAME_MAXIMIZED)
+ margin = 0;
+ else {
+ cairo_set_source_rgba(cr, 0, 0, 0, 0.45);
+ tile_mask(cr, t->shadow,
+ 2, 2, width + 8, height + 8,
+ 64, 64);
+ margin = t->margin;
+ }
+
+ if (flags & THEME_FRAME_ACTIVE)
+ source = t->active_frame;
+ else
+ source = t->inactive_frame;
+
+ tile_source(cr, source,
+ margin, margin,
+ width - margin * 2, height - margin * 2,
+ t->width, t->titlebar_height);
+
+ cairo_rectangle (cr, margin + t->width, margin,
+ width - (margin + t->width) * 2,
+ t->titlebar_height - t->width);
+ cairo_clip(cr);
+
+ cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
+ cairo_select_font_face(cr, "sans",
+ CAIRO_FONT_SLANT_NORMAL,
+ CAIRO_FONT_WEIGHT_BOLD);
+ cairo_set_font_size(cr, 14);
+ cairo_text_extents(cr, title, &extents);
+ cairo_font_extents (cr, &font_extents);
+ x = (width - extents.width) / 2;
+ y = margin +
+ (t->titlebar_height -
+ font_extents.ascent - font_extents.descent) / 2 +
+ font_extents.ascent;
+
+ if (flags & THEME_FRAME_ACTIVE) {
+ cairo_move_to(cr, x + 1, y + 1);
+ cairo_set_source_rgb(cr, 1, 1, 1);
+ cairo_show_text(cr, title);
+ cairo_move_to(cr, x, y);
+ cairo_set_source_rgb(cr, 0, 0, 0);
+ cairo_show_text(cr, title);
+ } else {
+ cairo_move_to(cr, x, y);
+ cairo_set_source_rgb(cr, 0.4, 0.4, 0.4);
+ cairo_show_text(cr, title);
+ }
+}
+
+enum theme_location
+theme_get_location(struct theme *t, int x, int y,
+ int width, int height, int flags)
+{
+ int vlocation, hlocation, location;
+ const int grip_size = 8;
+ int margin;
+
+ margin = (flags & THEME_FRAME_MAXIMIZED) ? 0 : t->margin;
+
+ if (x < margin)
+ hlocation = THEME_LOCATION_EXTERIOR;
+ else if (margin <= x && x < margin + grip_size)
+ hlocation = THEME_LOCATION_RESIZING_LEFT;
+ else if (x < width - margin - grip_size)
+ hlocation = THEME_LOCATION_INTERIOR;
+ else if (x < width - margin)
+ hlocation = THEME_LOCATION_RESIZING_RIGHT;
+ else
+ hlocation = THEME_LOCATION_EXTERIOR;
+
+ if (y < margin)
+ vlocation = THEME_LOCATION_EXTERIOR;
+ else if (margin <= y && y < margin + grip_size)
+ vlocation = THEME_LOCATION_RESIZING_TOP;
+ else if (y < height - margin - grip_size)
+ vlocation = THEME_LOCATION_INTERIOR;
+ else if (y < height - margin)
+ vlocation = THEME_LOCATION_RESIZING_BOTTOM;
+ else
+ vlocation = THEME_LOCATION_EXTERIOR;
+
+ location = vlocation | hlocation;
+ if (location & THEME_LOCATION_EXTERIOR)
+ location = THEME_LOCATION_EXTERIOR;
+ if (location == THEME_LOCATION_INTERIOR &&
+ y < margin + t->titlebar_height)
+ location = THEME_LOCATION_TITLEBAR;
+ else if (location == THEME_LOCATION_INTERIOR)
+ location = THEME_LOCATION_CLIENT_AREA;
+
+ return location;
+}
diff --git a/shared/cairo-util.h b/shared/cairo-util.h
new file mode 100644
index 00000000..7b403944
--- /dev/null
+++ b/shared/cairo-util.h
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+
+#ifndef _CAIRO_UTIL_H
+#define _CAIRO_UTIL_H
+
+#include <cairo.h>
+
+void
+surface_flush_device(cairo_surface_t *surface);
+
+void
+tile_mask(cairo_t *cr, cairo_surface_t *surface,
+ int x, int y, int width, int height, int margin, int top_margin);
+
+void
+tile_source(cairo_t *cr, cairo_surface_t *surface,
+ int x, int y, int width, int height, int margin, int top_margin);
+
+void
+rounded_rect(cairo_t *cr, int x0, int y0, int x1, int y1, int radius);
+
+cairo_surface_t *
+load_cairo_surface(const char *filename);
+
+struct theme {
+ cairo_surface_t *active_frame;
+ cairo_surface_t *inactive_frame;
+ cairo_surface_t *shadow;
+ int frame_radius;
+ int margin;
+ int width;
+ int titlebar_height;
+};
+
+struct theme *
+theme_create(void);
+void
+theme_destroy(struct theme *t);
+
+enum {
+ THEME_FRAME_ACTIVE = 1,
+ THEME_FRAME_MAXIMIZED,
+};
+
+void
+theme_render_frame(struct theme *t,
+ cairo_t *cr, int width, int height,
+ const char *title, uint32_t flags);
+
+enum theme_location {
+ THEME_LOCATION_INTERIOR = 0,
+ THEME_LOCATION_RESIZING_TOP = 1,
+ THEME_LOCATION_RESIZING_BOTTOM = 2,
+ THEME_LOCATION_RESIZING_LEFT = 4,
+ THEME_LOCATION_RESIZING_TOP_LEFT = 5,
+ THEME_LOCATION_RESIZING_BOTTOM_LEFT = 6,
+ THEME_LOCATION_RESIZING_RIGHT = 8,
+ THEME_LOCATION_RESIZING_TOP_RIGHT = 9,
+ THEME_LOCATION_RESIZING_BOTTOM_RIGHT = 10,
+ THEME_LOCATION_RESIZING_MASK = 15,
+ THEME_LOCATION_EXTERIOR = 16,
+ THEME_LOCATION_TITLEBAR = 17,
+ THEME_LOCATION_CLIENT_AREA = 18,
+};
+
+enum theme_location
+theme_get_location(struct theme *t, int x, int y, int width, int height, int flags);
+
+#endif
diff --git a/shared/config-parser.c b/shared/config-parser.c
new file mode 100644
index 00000000..8defbbb4
--- /dev/null
+++ b/shared/config-parser.c
@@ -0,0 +1,434 @@
+/*
+ * 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 "config.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <ctype.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <wayland-util.h>
+#include "config-parser.h"
+
+#define container_of(ptr, type, member) ({ \
+ const __typeof__( ((type *)0)->member ) *__mptr = (ptr); \
+ (type *)( (char *)__mptr - offsetof(type,member) );})
+
+struct weston_config_entry {
+ char *key;
+ char *value;
+ struct wl_list link;
+};
+
+struct weston_config_section {
+ char *name;
+ struct wl_list entry_list;
+ struct wl_list link;
+};
+
+struct weston_config {
+ struct wl_list section_list;
+ char path[PATH_MAX];
+};
+
+static int
+open_config_file(struct weston_config *c, const char *name)
+{
+ const char *config_dir = getenv("XDG_CONFIG_HOME");
+ const char *home_dir = getenv("HOME");
+ const char *config_dirs = getenv("XDG_CONFIG_DIRS");
+ const char *p, *next;
+ int fd;
+
+ if (name[0] == '/') {
+ snprintf(c->path, sizeof c->path, "%s", name);
+ return open(name, O_RDONLY | O_CLOEXEC);
+ }
+
+ /* Precedence is given to config files in the home directory,
+ * and then to directories listed in XDG_CONFIG_DIRS and
+ * finally to the current working directory. */
+
+ /* $XDG_CONFIG_HOME */
+ if (config_dir) {
+ snprintf(c->path, sizeof c->path, "%s/%s", config_dir, name);
+ fd = open(c->path, O_RDONLY | O_CLOEXEC);
+ if (fd >= 0)
+ return fd;
+ }
+
+ /* $HOME/.config */
+ if (home_dir) {
+ snprintf(c->path, sizeof c->path,
+ "%s/.config/%s", home_dir, name);
+ fd = open(c->path, O_RDONLY | O_CLOEXEC);
+ if (fd >= 0)
+ return fd;
+ }
+
+ /* For each $XDG_CONFIG_DIRS: weston/<config_file> */
+ if (!config_dirs)
+ config_dirs = "/etc/xdg"; /* See XDG base dir spec. */
+
+ for (p = config_dirs; *p != '\0'; p = next) {
+ next = strchrnul(p, ':');
+ snprintf(c->path, sizeof c->path,
+ "%.*s/weston/%s", (int)(next - p), p, name);
+ fd = open(c->path, O_RDONLY | O_CLOEXEC);
+ if (fd >= 0)
+ return fd;
+
+ if (*next == ':')
+ next++;
+ }
+
+ /* Current working directory. */
+ snprintf(c->path, sizeof c->path, "./%s", name);
+
+ return open(c->path, O_RDONLY | O_CLOEXEC);
+}
+
+static struct weston_config_entry *
+config_section_get_entry(struct weston_config_section *section,
+ const char *key)
+{
+ struct weston_config_entry *e;
+
+ if (section == NULL)
+ return NULL;
+ wl_list_for_each(e, &section->entry_list, link)
+ if (strcmp(e->key, key) == 0)
+ return e;
+
+ return NULL;
+}
+
+WL_EXPORT
+struct weston_config_section *
+weston_config_get_section(struct weston_config *config, const char *section,
+ const char *key, const char *value)
+{
+ struct weston_config_section *s;
+ struct weston_config_entry *e;
+
+ if (config == NULL)
+ return NULL;
+ wl_list_for_each(s, &config->section_list, link) {
+ if (strcmp(s->name, section) != 0)
+ continue;
+ if (key == NULL)
+ return s;
+ e = config_section_get_entry(s, key);
+ if (e && strcmp(e->value, value) == 0)
+ return s;
+ }
+
+ return NULL;
+}
+
+WL_EXPORT
+int
+weston_config_section_get_int(struct weston_config_section *section,
+ const char *key,
+ int32_t *value, int32_t default_value)
+{
+ struct weston_config_entry *entry;
+ char *end;
+
+ entry = config_section_get_entry(section, key);
+ if (entry == NULL) {
+ *value = default_value;
+ errno = ENOENT;
+ return -1;
+ }
+
+ *value = strtol(entry->value, &end, 0);
+ if (*end != '\0') {
+ *value = default_value;
+ errno = EINVAL;
+ return -1;
+ }
+
+ return 0;
+}
+
+WL_EXPORT
+int
+weston_config_section_get_uint(struct weston_config_section *section,
+ const char *key,
+ uint32_t *value, uint32_t default_value)
+{
+ struct weston_config_entry *entry;
+ char *end;
+
+ entry = config_section_get_entry(section, key);
+ if (entry == NULL) {
+ *value = default_value;
+ errno = ENOENT;
+ return -1;
+ }
+
+ *value = strtoul(entry->value, &end, 0);
+ if (*end != '\0') {
+ *value = default_value;
+ errno = EINVAL;
+ return -1;
+ }
+
+ return 0;
+}
+
+WL_EXPORT
+int
+weston_config_section_get_double(struct weston_config_section *section,
+ const char *key,
+ double *value, double default_value)
+{
+ struct weston_config_entry *entry;
+ char *end;
+
+ entry = config_section_get_entry(section, key);
+ if (entry == NULL) {
+ *value = default_value;
+ errno = ENOENT;
+ return -1;
+ }
+
+ *value = strtod(entry->value, &end);
+ if (*end != '\0') {
+ *value = default_value;
+ errno = EINVAL;
+ return -1;
+ }
+
+ return 0;
+}
+
+WL_EXPORT
+int
+weston_config_section_get_string(struct weston_config_section *section,
+ const char *key,
+ char **value, const char *default_value)
+{
+ struct weston_config_entry *entry;
+
+ entry = config_section_get_entry(section, key);
+ if (entry == NULL) {
+ if (default_value)
+ *value = strdup(default_value);
+ else
+ *value = NULL;
+ errno = ENOENT;
+ return -1;
+ }
+
+ *value = strdup(entry->value);
+
+ return 0;
+}
+
+WL_EXPORT
+int
+weston_config_section_get_bool(struct weston_config_section *section,
+ const char *key,
+ int *value, int default_value)
+{
+ struct weston_config_entry *entry;
+
+ entry = config_section_get_entry(section, key);
+ if (entry == NULL) {
+ *value = default_value;
+ errno = ENOENT;
+ return -1;
+ }
+
+ if (strcmp(entry->value, "false") == 0)
+ *value = 0;
+ else if (strcmp(entry->value, "true") == 0)
+ *value = 1;
+ else {
+ *value = default_value;
+ errno = EINVAL;
+ return -1;
+ }
+
+ return 0;
+}
+
+static struct weston_config_section *
+config_add_section(struct weston_config *config, const char *name)
+{
+ struct weston_config_section *section;
+
+ section = malloc(sizeof *section);
+ section->name = strdup(name);
+ wl_list_init(&section->entry_list);
+ wl_list_insert(config->section_list.prev, &section->link);
+
+ return section;
+}
+
+static struct weston_config_entry *
+section_add_entry(struct weston_config_section *section,
+ const char *key, const char *value)
+{
+ struct weston_config_entry *entry;
+
+ entry = malloc(sizeof *entry);
+ entry->key = strdup(key);
+ entry->value = strdup(value);
+ wl_list_insert(section->entry_list.prev, &entry->link);
+
+ return entry;
+}
+
+struct weston_config *
+weston_config_parse(const char *name)
+{
+ FILE *fp;
+ char line[512], *p;
+ struct weston_config *config;
+ struct weston_config_section *section = NULL;
+ int i, fd;
+
+ config = malloc(sizeof *config);
+ if (config == NULL)
+ return NULL;
+
+ wl_list_init(&config->section_list);
+
+ fd = open_config_file(config, name);
+ if (fd == -1) {
+ free(config);
+ return NULL;
+ }
+
+ fp = fdopen(fd, "r");
+ if (fp == NULL) {
+ free(config);
+ return NULL;
+ }
+
+ while (fgets(line, sizeof line, fp)) {
+ switch (line[0]) {
+ case '#':
+ case '\n':
+ continue;
+ case '[':
+ p = strchr(&line[1], ']');
+ if (!p || p[1] != '\n') {
+ fprintf(stderr, "malformed "
+ "section header: %s\n", line);
+ fclose(fp);
+ weston_config_destroy(config);
+ return NULL;
+ }
+ p[0] = '\0';
+ section = config_add_section(config, &line[1]);
+ continue;
+ default:
+ p = strchr(line, '=');
+ if (!p || p == line || !section) {
+ fprintf(stderr, "malformed "
+ "config line: %s\n", line);
+ fclose(fp);
+ weston_config_destroy(config);
+ return NULL;
+ }
+
+ p[0] = '\0';
+ p++;
+ while (isspace(*p))
+ p++;
+ i = strlen(p);
+ while (i > 0 && isspace(p[i - 1])) {
+ p[i - 1] = '\0';
+ i--;
+ }
+ section_add_entry(section, line, p);
+ continue;
+ }
+ }
+
+ fclose(fp);
+
+ return config;
+}
+
+const char *
+weston_config_get_full_path(struct weston_config *config)
+{
+ return config == NULL ? NULL : config->path;
+}
+
+int
+weston_config_next_section(struct weston_config *config,
+ struct weston_config_section **section,
+ const char **name)
+{
+ if (config == NULL)
+ return 0;
+
+ if (*section == NULL)
+ *section = container_of(config->section_list.next,
+ struct weston_config_section, link);
+ else
+ *section = container_of((*section)->link.next,
+ struct weston_config_section, link);
+
+ if (&(*section)->link == &config->section_list)
+ return 0;
+
+ *name = (*section)->name;
+
+ return 1;
+}
+
+void
+weston_config_destroy(struct weston_config *config)
+{
+ struct weston_config_section *s, *next_s;
+ struct weston_config_entry *e, *next_e;
+
+ if (config == NULL)
+ return;
+
+ wl_list_for_each_safe(s, next_s, &config->section_list, link) {
+ wl_list_for_each_safe(e, next_e, &s->entry_list, link) {
+ free(e->key);
+ free(e->value);
+ free(e);
+ }
+ free(s->name);
+ free(s);
+ }
+
+ free(config);
+}
diff --git a/shared/config-parser.h b/shared/config-parser.h
new file mode 100644
index 00000000..745562bc
--- /dev/null
+++ b/shared/config-parser.h
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ */
+
+#ifndef CONFIGPARSER_H
+#define CONFIGPARSER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum config_key_type {
+ CONFIG_KEY_INTEGER, /* typeof data = int */
+ CONFIG_KEY_UNSIGNED_INTEGER, /* typeof data = unsigned int */
+ CONFIG_KEY_STRING, /* typeof data = char* */
+ CONFIG_KEY_BOOLEAN /* typeof data = int */
+};
+
+struct config_key {
+ const char *name;
+ enum config_key_type type;
+ void *data;
+};
+
+struct config_section {
+ const char *name;
+ const struct config_key *keys;
+ int num_keys;
+ void (*done)(void *data);
+};
+
+enum weston_option_type {
+ WESTON_OPTION_INTEGER,
+ WESTON_OPTION_UNSIGNED_INTEGER,
+ WESTON_OPTION_STRING,
+ WESTON_OPTION_BOOLEAN
+};
+
+struct weston_option {
+ enum weston_option_type type;
+ const char *name;
+ int short_name;
+ void *data;
+};
+
+int
+parse_options(const struct weston_option *options,
+ int count, int *argc, char *argv[]);
+
+struct weston_config_section;
+struct weston_config;
+
+struct weston_config_section *
+weston_config_get_section(struct weston_config *config, const char *section,
+ const char *key, const char *value);
+int
+weston_config_section_get_int(struct weston_config_section *section,
+ const char *key,
+ int32_t *value, int32_t default_value);
+int
+weston_config_section_get_uint(struct weston_config_section *section,
+ const char *key,
+ uint32_t *value, uint32_t default_value);
+int
+weston_config_section_get_double(struct weston_config_section *section,
+ const char *key,
+ double *value, double default_value);
+int
+weston_config_section_get_string(struct weston_config_section *section,
+ const char *key,
+ char **value,
+ const char *default_value);
+int
+weston_config_section_get_bool(struct weston_config_section *section,
+ const char *key,
+ int *value, int default_value);
+struct weston_config *
+weston_config_parse(const char *name);
+
+const char *
+weston_config_get_full_path(struct weston_config *config);
+
+void
+weston_config_destroy(struct weston_config *config);
+
+int weston_config_next_section(struct weston_config *config,
+ struct weston_config_section **section,
+ const char **name);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CONFIGPARSER_H */
+
diff --git a/shared/image-loader.c b/shared/image-loader.c
new file mode 100644
index 00000000..35dadd3d
--- /dev/null
+++ b/shared/image-loader.c
@@ -0,0 +1,405 @@
+/*
+ * Copyright © 2008-2012 Kristian Høgsberg
+ * Copyright © 2012 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 "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <jpeglib.h>
+#include <png.h>
+#include <pixman.h>
+
+#include "image-loader.h"
+
+#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
+
+#ifdef HAVE_WEBP
+#include <webp/decode.h>
+#endif
+
+static int
+stride_for_width(int width)
+{
+ return width * 4;
+}
+
+static void
+swizzle_row(JSAMPLE *row, JDIMENSION width)
+{
+ JSAMPLE *s;
+ uint32_t *d;
+
+ s = row + (width - 1) * 3;
+ d = (uint32_t *) (row + (width - 1) * 4);
+ while (s >= row) {
+ *d = 0xff000000 | (s[0] << 16) | (s[1] << 8) | (s[2] << 0);
+ s -= 3;
+ d--;
+ }
+}
+
+static void
+error_exit(j_common_ptr cinfo)
+{
+ longjmp(cinfo->client_data, 1);
+}
+
+static void
+pixman_image_destroy_func(pixman_image_t *image, void *data)
+{
+ free(data);
+}
+
+static pixman_image_t *
+load_jpeg(FILE *fp)
+{
+ struct jpeg_decompress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+ pixman_image_t *pixman_image = NULL;
+ unsigned int i;
+ int stride, first;
+ JSAMPLE *data, *rows[4];
+ jmp_buf env;
+
+ cinfo.err = jpeg_std_error(&jerr);
+ jerr.error_exit = error_exit;
+ cinfo.client_data = env;
+ if (setjmp(env))
+ return NULL;
+
+ jpeg_create_decompress(&cinfo);
+
+ jpeg_stdio_src(&cinfo, fp);
+
+ jpeg_read_header(&cinfo, TRUE);
+
+ cinfo.out_color_space = JCS_RGB;
+ jpeg_start_decompress(&cinfo);
+
+ stride = cinfo.output_width * 4;
+ data = malloc(stride * cinfo.output_height);
+ if (data == NULL) {
+ fprintf(stderr, "couldn't allocate image data\n");
+ return NULL;
+ }
+
+ while (cinfo.output_scanline < cinfo.output_height) {
+ first = cinfo.output_scanline;
+ for (i = 0; i < ARRAY_LENGTH(rows); i++)
+ rows[i] = data + (first + i) * stride;
+
+ jpeg_read_scanlines(&cinfo, rows, ARRAY_LENGTH(rows));
+ for (i = 0; first + i < cinfo.output_scanline; i++)
+ swizzle_row(rows[i], cinfo.output_width);
+ }
+
+ jpeg_finish_decompress(&cinfo);
+
+ jpeg_destroy_decompress(&cinfo);
+
+ pixman_image = pixman_image_create_bits(PIXMAN_a8r8g8b8,
+ cinfo.output_width,
+ cinfo.output_height,
+ (uint32_t *) data, stride);
+
+ pixman_image_set_destroy_function(pixman_image,
+ pixman_image_destroy_func, data);
+
+ return pixman_image;
+}
+
+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) != size)
+ png_error(png, NULL);
+}
+
+static void
+png_error_callback(png_structp png, png_const_charp error_msg)
+{
+ longjmp (png_jmpbuf (png), 1);
+}
+
+static pixman_image_t *
+load_png(FILE *fp)
+{
+ png_struct *png;
+ png_info *info;
+ png_byte *data = NULL;
+ png_byte **row_pointers = NULL;
+ png_uint_32 width, height;
+ int depth, color_type, interlace, stride;
+ unsigned int i;
+ pixman_image_t *pixman_image = NULL;
+
+ png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,
+ png_error_callback, NULL);
+ if (!png)
+ return NULL;
+
+ info = png_create_info_struct(png);
+ if (!info) {
+ png_destroy_read_struct(&png, &info, NULL);
+ return NULL;
+ }
+
+ if (setjmp(png_jmpbuf(png))) {
+ if (data)
+ free(data);
+ if (row_pointers)
+ free(row_pointers);
+ png_destroy_read_struct(&png, &info, NULL);
+ 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 = stride_for_width(width);
+ data = malloc(stride * height);
+ if (!data) {
+ png_destroy_read_struct(&png, &info, NULL);
+ return NULL;
+ }
+
+ row_pointers = malloc(height * sizeof row_pointers[0]);
+ if (row_pointers == NULL) {
+ free(data);
+ png_destroy_read_struct(&png, &info, NULL);
+ 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);
+
+ pixman_image = pixman_image_create_bits(PIXMAN_a8r8g8b8,
+ width, height, (uint32_t *) data, stride);
+
+ pixman_image_set_destroy_function(pixman_image,
+ pixman_image_destroy_func, data);
+
+ return pixman_image;
+}
+
+#ifdef HAVE_WEBP
+
+static pixman_image_t *
+load_webp(FILE *fp)
+{
+ WebPDecoderConfig config;
+ uint8_t buffer[16 * 1024];
+ int len;
+ VP8StatusCode status;
+ WebPIDecoder *idec;
+
+ if (!WebPInitDecoderConfig(&config)) {
+ fprintf(stderr, "Library version mismatch!\n");
+ return NULL;
+ }
+
+ /* webp decoding api doesn't seem to specify a min size that's
+ usable for GetFeatures, but 256 works... */
+ len = fread(buffer, 1, 256, fp);
+ status = WebPGetFeatures(buffer, len, &config.input);
+ if (status != VP8_STATUS_OK) {
+ fprintf(stderr, "failed to parse webp header\n");
+ WebPFreeDecBuffer(&config.output);
+ return NULL;
+ }
+
+ config.output.colorspace = MODE_BGRA;
+ config.output.u.RGBA.stride = stride_for_width(config.input.width);
+ config.output.u.RGBA.size =
+ config.output.u.RGBA.stride * config.input.height;
+ config.output.u.RGBA.rgba =
+ malloc(config.output.u.RGBA.stride * config.input.height);
+ config.output.is_external_memory = 1;
+ if (!config.output.u.RGBA.rgba) {
+ WebPFreeDecBuffer(&config.output);
+ return NULL;
+ }
+
+ rewind(fp);
+ idec = WebPINewDecoder(&config.output);
+ if (!idec) {
+ WebPFreeDecBuffer(&config.output);
+ return NULL;
+ }
+
+ while (!feof(fp)) {
+ len = fread(buffer, 1, sizeof buffer, fp);
+ status = WebPIAppend(idec, buffer, len);
+ if (status != VP8_STATUS_OK) {
+ fprintf(stderr, "webp decode status %d\n", status);
+ WebPIDelete(idec);
+ WebPFreeDecBuffer(&config.output);
+ return NULL;
+ }
+ }
+
+ WebPIDelete(idec);
+ WebPFreeDecBuffer(&config.output);
+
+ return pixman_image_create_bits(PIXMAN_a8r8g8b8,
+ config.input.width,
+ config.input.height,
+ (uint32_t *) config.output.u.RGBA.rgba,
+ config.output.u.RGBA.stride);
+}
+
+#endif
+
+
+struct image_loader {
+ unsigned char header[4];
+ int header_size;
+ pixman_image_t *(*load)(FILE *fp);
+};
+
+static const struct image_loader loaders[] = {
+ { { 0x89, 'P', 'N', 'G' }, 4, load_png },
+ { { 0xff, 0xd8 }, 2, load_jpeg },
+#ifdef HAVE_WEBP
+ { { 'R', 'I', 'F', 'F' }, 4, load_webp }
+#endif
+};
+
+pixman_image_t *
+load_image(const char *filename)
+{
+ pixman_image_t *image;
+ unsigned char header[4];
+ FILE *fp;
+ unsigned int i;
+
+ fp = fopen(filename, "rb");
+ if (fp == NULL)
+ return NULL;
+
+ if (fread(header, sizeof header, 1, fp) != 1) {
+ fclose(fp);
+ return NULL;
+ }
+
+ rewind(fp);
+ for (i = 0; i < ARRAY_LENGTH(loaders); i++) {
+ if (memcmp(header, loaders[i].header,
+ loaders[i].header_size) == 0) {
+ image = loaders[i].load(fp);
+ break;
+ }
+ }
+
+ fclose(fp);
+
+ if (i == ARRAY_LENGTH(loaders)) {
+ fprintf(stderr, "unrecognized file header for %s: "
+ "0x%02x 0x%02x 0x%02x 0x%02x\n",
+ filename, header[0], header[1], header[2], header[3]);
+ image = NULL;
+ }
+
+ return image;
+}
diff --git a/shared/image-loader.h b/shared/image-loader.h
new file mode 100644
index 00000000..445e651e
--- /dev/null
+++ b/shared/image-loader.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright © 2013 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.
+ */
+
+#ifndef _IMAGE_LOADER_H
+#define _IMAGE_LOADER_H
+
+#include <pixman.h>
+
+pixman_image_t *
+load_image(const char *filename);
+
+#endif
diff --git a/shared/matrix.c b/shared/matrix.c
new file mode 100644
index 00000000..4f0b6b79
--- /dev/null
+++ b/shared/matrix.c
@@ -0,0 +1,273 @@
+/*
+ * Copyright © 2011 Intel Corporation
+ * Copyright © 2012 Collabora, Ltd.
+ *
+ * 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 "config.h"
+
+#include <float.h>
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+
+#ifdef IN_WESTON
+#include <wayland-server.h>
+#else
+#define WL_EXPORT
+#endif
+
+#include "matrix.h"
+
+
+/*
+ * Matrices are stored in column-major order, that is the array indices are:
+ * 0 4 8 12
+ * 1 5 9 13
+ * 2 6 10 14
+ * 3 7 11 15
+ */
+
+WL_EXPORT void
+weston_matrix_init(struct weston_matrix *matrix)
+{
+ static const struct weston_matrix identity = {
+ .d = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 },
+ .type = 0,
+ };
+
+ memcpy(matrix, &identity, sizeof identity);
+}
+
+/* m <- n * m, that is, m is multiplied on the LEFT. */
+WL_EXPORT void
+weston_matrix_multiply(struct weston_matrix *m, const struct weston_matrix *n)
+{
+ struct weston_matrix tmp;
+ const float *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];
+ }
+ tmp.type = m->type | n->type;
+ memcpy(m, &tmp, sizeof tmp);
+}
+
+WL_EXPORT void
+weston_matrix_translate(struct weston_matrix *matrix, float x, float y, float z)
+{
+ struct weston_matrix translate = {
+ .d = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, x, y, z, 1 },
+ .type = WESTON_MATRIX_TRANSFORM_TRANSLATE,
+ };
+
+ weston_matrix_multiply(matrix, &translate);
+}
+
+WL_EXPORT void
+weston_matrix_scale(struct weston_matrix *matrix, float x, float y,float z)
+{
+ struct weston_matrix scale = {
+ .d = { x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, 0, 0, 0, 1 },
+ .type = WESTON_MATRIX_TRANSFORM_SCALE,
+ };
+
+ weston_matrix_multiply(matrix, &scale);
+}
+
+WL_EXPORT void
+weston_matrix_rotate_xy(struct weston_matrix *matrix, float cos, float sin)
+{
+ struct weston_matrix translate = {
+ .d = { cos, sin, 0, 0, -sin, cos, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 },
+ .type = WESTON_MATRIX_TRANSFORM_ROTATE,
+ };
+
+ weston_matrix_multiply(matrix, &translate);
+}
+
+/* v <- m * v */
+WL_EXPORT void
+weston_matrix_transform(struct weston_matrix *matrix, struct weston_vector *v)
+{
+ int i, j;
+ struct weston_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;
+}
+
+static inline void
+swap_rows(double *a, double *b)
+{
+ unsigned k;
+ double tmp;
+
+ for (k = 0; k < 13; k += 4) {
+ tmp = a[k];
+ a[k] = b[k];
+ b[k] = tmp;
+ }
+}
+
+static inline void
+swap_unsigned(unsigned *a, unsigned *b)
+{
+ unsigned tmp;
+
+ tmp = *a;
+ *a = *b;
+ *b = tmp;
+}
+
+static inline unsigned
+find_pivot(double *column, unsigned k)
+{
+ unsigned p = k;
+ for (++k; k < 4; ++k)
+ if (fabs(column[p]) < fabs(column[k]))
+ p = k;
+
+ return p;
+}
+
+/*
+ * reference: Gene H. Golub and Charles F. van Loan. Matrix computations.
+ * 3rd ed. The Johns Hopkins University Press. 1996.
+ * LU decomposition, forward and back substitution: Chapter 3.
+ */
+
+MATRIX_TEST_EXPORT inline int
+matrix_invert(double *A, unsigned *p, const struct weston_matrix *matrix)
+{
+ unsigned i, j, k;
+ unsigned pivot;
+ double pv;
+
+ for (i = 0; i < 4; ++i)
+ p[i] = i;
+ for (i = 16; i--; )
+ A[i] = matrix->d[i];
+
+ /* LU decomposition with partial pivoting */
+ for (k = 0; k < 4; ++k) {
+ pivot = find_pivot(&A[k * 4], k);
+ if (pivot != k) {
+ swap_unsigned(&p[k], &p[pivot]);
+ swap_rows(&A[k], &A[pivot]);
+ }
+
+ pv = A[k * 4 + k];
+ if (fabs(pv) < 1e-9)
+ return -1; /* zero pivot, not invertible */
+
+ for (i = k + 1; i < 4; ++i) {
+ A[i + k * 4] /= pv;
+
+ for (j = k + 1; j < 4; ++j)
+ A[i + j * 4] -= A[i + k * 4] * A[k + j * 4];
+ }
+ }
+
+ return 0;
+}
+
+MATRIX_TEST_EXPORT inline void
+inverse_transform(const double *LU, const unsigned *p, float *v)
+{
+ /* Solve A * x = v, when we have P * A = L * U.
+ * P * A * x = P * v => L * U * x = P * v
+ * Let U * x = b, then L * b = P * v.
+ */
+ double b[4];
+ unsigned j;
+
+ /* Forward substitution, column version, solves L * b = P * v */
+ /* The diagonal of L is all ones, and not explicitly stored. */
+ b[0] = v[p[0]];
+ b[1] = (double)v[p[1]] - b[0] * LU[1 + 0 * 4];
+ b[2] = (double)v[p[2]] - b[0] * LU[2 + 0 * 4];
+ b[3] = (double)v[p[3]] - b[0] * LU[3 + 0 * 4];
+ b[2] -= b[1] * LU[2 + 1 * 4];
+ b[3] -= b[1] * LU[3 + 1 * 4];
+ b[3] -= b[2] * LU[3 + 2 * 4];
+
+ /* backward substitution, column version, solves U * y = b */
+#if 1
+ /* hand-unrolled, 25% faster for whole function */
+ b[3] /= LU[3 + 3 * 4];
+ b[0] -= b[3] * LU[0 + 3 * 4];
+ b[1] -= b[3] * LU[1 + 3 * 4];
+ b[2] -= b[3] * LU[2 + 3 * 4];
+
+ b[2] /= LU[2 + 2 * 4];
+ b[0] -= b[2] * LU[0 + 2 * 4];
+ b[1] -= b[2] * LU[1 + 2 * 4];
+
+ b[1] /= LU[1 + 1 * 4];
+ b[0] -= b[1] * LU[0 + 1 * 4];
+
+ b[0] /= LU[0 + 0 * 4];
+#else
+ for (j = 3; j > 0; --j) {
+ unsigned k;
+ b[j] /= LU[j + j * 4];
+ for (k = 0; k < j; ++k)
+ b[k] -= b[j] * LU[k + j * 4];
+ }
+
+ b[0] /= LU[0 + 0 * 4];
+#endif
+
+ /* the result */
+ for (j = 0; j < 4; ++j)
+ v[j] = b[j];
+}
+
+WL_EXPORT int
+weston_matrix_invert(struct weston_matrix *inverse,
+ const struct weston_matrix *matrix)
+{
+ double LU[16]; /* column-major */
+ unsigned perm[4]; /* permutation */
+ unsigned c;
+
+ if (matrix_invert(LU, perm, matrix) < 0)
+ return -1;
+
+ weston_matrix_init(inverse);
+ for (c = 0; c < 4; ++c)
+ inverse_transform(LU, perm, &inverse->d[c * 4]);
+ inverse->type = matrix->type;
+
+ return 0;
+}
diff --git a/shared/matrix.h b/shared/matrix.h
new file mode 100644
index 00000000..e5cf636b
--- /dev/null
+++ b/shared/matrix.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright © 2008-2011 Kristian Høgsberg
+ * Copyright © 2012 Collabora, Ltd.
+ *
+ * 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 WESTON_MATRIX_H
+#define WESTON_MATRIX_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum weston_matrix_transform_type {
+ WESTON_MATRIX_TRANSFORM_TRANSLATE = (1 << 0),
+ WESTON_MATRIX_TRANSFORM_SCALE = (1 << 1),
+ WESTON_MATRIX_TRANSFORM_ROTATE = (1 << 2),
+ WESTON_MATRIX_TRANSFORM_OTHER = (1 << 3),
+};
+
+struct weston_matrix {
+ float d[16];
+ unsigned int type;
+};
+
+struct weston_vector {
+ float f[4];
+};
+
+void
+weston_matrix_init(struct weston_matrix *matrix);
+void
+weston_matrix_multiply(struct weston_matrix *m, const struct weston_matrix *n);
+void
+weston_matrix_scale(struct weston_matrix *matrix, float x, float y, float z);
+void
+weston_matrix_translate(struct weston_matrix *matrix,
+ float x, float y, float z);
+void
+weston_matrix_rotate_xy(struct weston_matrix *matrix, float cos, float sin);
+void
+weston_matrix_transform(struct weston_matrix *matrix, struct weston_vector *v);
+
+int
+weston_matrix_invert(struct weston_matrix *inverse,
+ const struct weston_matrix *matrix);
+
+#ifdef UNIT_TEST
+# define MATRIX_TEST_EXPORT WL_EXPORT
+
+int
+matrix_invert(double *A, unsigned *p, const struct weston_matrix *matrix);
+
+void
+inverse_transform(const double *LU, const unsigned *p, float *v);
+
+#else
+# define MATRIX_TEST_EXPORT static
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* WESTON_MATRIX_H */
diff --git a/shared/option-parser.c b/shared/option-parser.c
new file mode 100644
index 00000000..c00349a8
--- /dev/null
+++ b/shared/option-parser.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright © 2012 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 "config.h"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "config-parser.h"
+
+static void
+handle_option(const struct weston_option *option, char *value)
+{
+ switch (option->type) {
+ case WESTON_OPTION_INTEGER:
+ * (int32_t *) option->data = strtol(value, NULL, 0);
+ return;
+ case WESTON_OPTION_UNSIGNED_INTEGER:
+ * (uint32_t *) option->data = strtoul(value, NULL, 0);
+ return;
+ case WESTON_OPTION_STRING:
+ * (char **) option->data = strdup(value);
+ return;
+ case WESTON_OPTION_BOOLEAN:
+ * (int32_t *) option->data = 1;
+ return;
+ default:
+ assert(0);
+ }
+}
+
+int
+parse_options(const struct weston_option *options,
+ int count, int *argc, char *argv[])
+{
+ int i, j, k, len = 0;
+
+ for (i = 1, j = 1; i < *argc; i++) {
+ for (k = 0; k < count; k++) {
+ if (options[k].name)
+ len = strlen(options[k].name);
+ if (options[k].name &&
+ argv[i][0] == '-' &&
+ argv[i][1] == '-' &&
+ strncmp(options[k].name, &argv[i][2], len) == 0 &&
+ (argv[i][len + 2] == '=' || argv[i][len + 2] == '\0')) {
+ handle_option(&options[k], &argv[i][len + 3]);
+ break;
+ } else if (options[k].short_name &&
+ argv[i][0] == '-' &&
+ options[k].short_name == argv[i][1]) {
+ handle_option(&options[k], &argv[i][2]);
+ break;
+ }
+ }
+ if (k == count)
+ argv[j++] = argv[i];
+ }
+ argv[j] = NULL;
+ *argc = j;
+
+ return j;
+}
diff --git a/shared/os-compatibility.c b/shared/os-compatibility.c
new file mode 100644
index 00000000..4f96dd4c
--- /dev/null
+++ b/shared/os-compatibility.c
@@ -0,0 +1,180 @@
+/*
+ * Copyright © 2012 Collabora, Ltd.
+ *
+ * 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 "config.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/epoll.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "os-compatibility.h"
+
+static int
+set_cloexec_or_close(int fd)
+{
+ long flags;
+
+ if (fd == -1)
+ return -1;
+
+ flags = fcntl(fd, F_GETFD);
+ if (flags == -1)
+ goto err;
+
+ if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
+ goto err;
+
+ return fd;
+
+err:
+ close(fd);
+ return -1;
+}
+
+int
+os_socketpair_cloexec(int domain, int type, int protocol, int *sv)
+{
+ int ret;
+
+#ifdef SOCK_CLOEXEC
+ ret = socketpair(domain, type | SOCK_CLOEXEC, protocol, sv);
+ if (ret == 0 || errno != EINVAL)
+ return ret;
+#endif
+
+ ret = socketpair(domain, type, protocol, sv);
+ if (ret < 0)
+ return ret;
+
+ sv[0] = set_cloexec_or_close(sv[0]);
+ sv[1] = set_cloexec_or_close(sv[1]);
+
+ if (sv[0] != -1 && sv[1] != -1)
+ return 0;
+
+ close(sv[0]);
+ close(sv[1]);
+ return -1;
+}
+
+int
+os_epoll_create_cloexec(void)
+{
+ int fd;
+
+#ifdef EPOLL_CLOEXEC
+ fd = epoll_create1(EPOLL_CLOEXEC);
+ if (fd >= 0)
+ return fd;
+ if (errno != EINVAL)
+ return -1;
+#endif
+
+ fd = epoll_create(1);
+ return set_cloexec_or_close(fd);
+}
+
+static int
+create_tmpfile_cloexec(char *tmpname)
+{
+ int fd;
+
+#ifdef HAVE_MKOSTEMP
+ fd = mkostemp(tmpname, O_CLOEXEC);
+ if (fd >= 0)
+ unlink(tmpname);
+#else
+ fd = mkstemp(tmpname);
+ if (fd >= 0) {
+ fd = set_cloexec_or_close(fd);
+ unlink(tmpname);
+ }
+#endif
+
+ return fd;
+}
+
+/*
+ * Create a new, unique, anonymous file of the given size, and
+ * return the file descriptor for it. The file descriptor is set
+ * CLOEXEC. The file is immediately suitable for mmap()'ing
+ * the given size at offset zero.
+ *
+ * The file should not have a permanent backing store like a disk,
+ * but may have if XDG_RUNTIME_DIR is not properly implemented in OS.
+ *
+ * The file name is deleted from the file system.
+ *
+ * The file is suitable for buffer sharing between processes by
+ * transmitting the file descriptor over Unix sockets using the
+ * SCM_RIGHTS methods.
+ */
+int
+os_create_anonymous_file(off_t size)
+{
+ static const char template[] = "/weston-shared-XXXXXX";
+ const char *path;
+ char *name;
+ int fd;
+
+ path = getenv("XDG_RUNTIME_DIR");
+ if (!path) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ name = malloc(strlen(path) + sizeof(template));
+ if (!name)
+ return -1;
+
+ strcpy(name, path);
+ strcat(name, template);
+
+ fd = create_tmpfile_cloexec(name);
+
+ free(name);
+
+ if (fd < 0)
+ return -1;
+
+ if (ftruncate(fd, size) < 0) {
+ close(fd);
+ return -1;
+ }
+
+ return fd;
+}
+
+#ifndef HAVE_STRCHRNUL
+char *
+strchrnul(const char *s, int c)
+{
+ while (*s && *s != c)
+ s++;
+ return (char *)s;
+}
+#endif
diff --git a/shared/os-compatibility.h b/shared/os-compatibility.h
new file mode 100644
index 00000000..c1edcfbd
--- /dev/null
+++ b/shared/os-compatibility.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright © 2012 Collabora, Ltd.
+ *
+ * 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 OS_COMPATIBILITY_H
+#define OS_COMPATIBILITY_H
+
+#include <sys/types.h>
+
+#include "../config.h"
+
+#ifdef HAVE_EXECINFO_H
+#include <execinfo.h>
+#else
+static inline int
+backtrace(void **buffer, int size)
+{
+ return 0;
+}
+#endif
+
+int
+os_socketpair_cloexec(int domain, int type, int protocol, int *sv);
+
+int
+os_epoll_create_cloexec(void);
+
+int
+os_create_anonymous_file(off_t size);
+
+#ifndef HAVE_STRCHRNUL
+char *
+strchrnul(const char *s, int c);
+#endif
+
+#endif /* OS_COMPATIBILITY_H */
diff --git a/shared/zalloc.h b/shared/zalloc.h
new file mode 100644
index 00000000..29da1190
--- /dev/null
+++ b/shared/zalloc.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright © 2013 Red Hat, Inc.
+ *
+ * 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 WESTON_ZALLOC_H
+#define WESTON_ZALLOC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdlib.h>
+
+static inline void *
+zalloc(size_t size)
+{
+ return calloc(1, size);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* WESTON_ZALLOC_H */