summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith Packard <keithp@keithp.com>2004-09-15 20:43:17 +0000
committerKeith Packard <keithp@keithp.com>2004-09-15 20:43:17 +0000
commit266f94cdcc59dee4a6b15dc7ca75a591096651f6 (patch)
tree6b56278bc464e5309d487dbd99191f83d3a52c7a
Initial revision
-rw-r--r--AUTHORS0
-rw-r--r--COPYING19
-rw-r--r--ChangeLog0
-rw-r--r--INSTALL229
-rw-r--r--Makefile.am27
-rw-r--r--NEWS0
-rw-r--r--README0
-rw-r--r--architecture54
-rwxr-xr-xautogen.sh3
-rw-r--r--configure.ac56
-rw-r--r--twin.h244
-rw-r--r--twin.pc.in10
-rw-r--r--twin_draw.c408
-rw-r--r--twin_pixmap.c118
-rw-r--r--twin_primitive.c230
-rw-r--r--twin_screen.c148
-rw-r--r--twin_x11.c116
-rw-r--r--twinint.h213
-rw-r--r--xtwin.c79
19 files changed, 1954 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/AUTHORS
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..57e71ff
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,19 @@
+Copyright © 2004 Keith Packard
+
+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 Keith Packard not be used in
+advertising or publicity pertaining to distribution of the software without
+specific, written prior permission. Keith Packard makes no
+representations about the suitability of this software for any purpose. It
+is provided "as is" without express or implied warranty.
+
+KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+EVENT SHALL KEITH PACKARD 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.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ChangeLog
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..54caf7c
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,229 @@
+Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software
+Foundation, Inc.
+
+ This file is free documentation; the Free Software Foundation gives
+unlimited permission to copy, distribute and modify it.
+
+Basic Installation
+==================
+
+ These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+ It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring. (Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.)
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+ The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'. You only need
+`configure.ac' if you want to change it or regenerate `configure' using
+a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes awhile. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. Run `./configure --help'
+for details on some of the pertinent environment variables.
+
+ You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment. Here
+is an example:
+
+ ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
+
+ *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not support the `VPATH'
+variable, you have to compile the package for one architecture at a
+time in the source code directory. After you have installed the
+package for one architecture, use `make distclean' before reconfiguring
+for another architecture.
+
+Installation Names
+==================
+
+ By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc. You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=PATH' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' cannot figure out
+automatically, but needs to determine by the type of machine the package
+will run on. Usually, assuming the package is built to be run on the
+_same_ architectures, `configure' can figure that out, but if it prints
+a message saying it cannot guess the machine type, give it the
+`--build=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+ CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+ OS KERNEL-OS
+
+ See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+ If you are _building_ compiler tools for cross-compiling, you should
+use the `--target=TYPE' option to select the type of system they will
+produce code for.
+
+ If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+ Variables not defined in a site shell script can be set in the
+environment passed to `configure'. However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost. In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'. For example:
+
+ ./configure CC=/usr/local2/bin/gcc
+
+will cause the specified gcc to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+`configure' Invocation
+======================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--help'
+`-h'
+ Print a summary of the options to `configure', and exit.
+
+`--version'
+`-V'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`--cache-file=FILE'
+ Enable the cache: use and save the results of the tests in FILE,
+ traditionally `config.cache'. FILE defaults to `/dev/null' to
+ disable caching.
+
+`--config-cache'
+`-C'
+ Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to `/dev/null' (any error
+ messages will still be shown).
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`configure' also accepts some other, not widely useful, options. Run
+`configure --help' for more details.
+
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..a673b9e
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,27 @@
+CFLAGS=-g
+INCLUDES= @X_CFLAGS@ @WARN_CFLAGS@
+
+#libtwin_la_SOURCES = \
+# twin.h \
+# twin_draw.c \
+# twin_pixmap.c \
+# twin_primitive.c \
+# twin_screen.c \
+# twin_x11.c \
+# twinint.h
+#
+#lib_LTLIBRARIES = libtwin.la
+
+bin_PROGRAMS = xtwin
+
+xtwin_SOURCES = \
+ twin.h \
+ twin_draw.c \
+ twin_pixmap.c \
+ twin_primitive.c \
+ twin_screen.c \
+ twin_x11.c \
+ twinint.h \
+ xtwin.c
+
+xtwin_LDADD = @X_LIBS@
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/NEWS
diff --git a/README b/README
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/README
diff --git a/architecture b/architecture
new file mode 100644
index 0000000..dd095fd
--- /dev/null
+++ b/architecture
@@ -0,0 +1,54 @@
+ TWIN: a tiny window system
+ 2004/8/23
+ Keith Packard
+ HP Cambridge Research Laboratory
+
+1. Introduction
+
+twin is a window system designed for devices with constrained memory, CPU
+and display space.
+
+2. Pixel formats
+
+twin supports a limited set of pixel formats; additional formats introduce
+significant cost into the system.
+
+ Name Bits Content
+ A8 8 8-bit A
+ RGB16 16 5-6-5 RGB
+ ARGB32 32 8-8-8-8 ARGB
+
+3. Objects
+
+twin unifies onscreen and offscreen data in a single 'pixmap' object. The
+screen is constructed from a list of pixmaps composited together to form the
+final image. Pixmaps contain position, width height and stride
+information and stacking information. A pixmap is "on screen" if it is
+included in the list of on-screen pixmaps.
+
+4. Operators
+
+twin is architected with an abstract single operator that performs all of
+the basic pixel manipulation. That operator is:
+
+ dest = source IN mask OP dest
+
+IN is the Porter/Duff operator of the same name, OP is either OVER or
+SOURCE. If necessary, OP may be extended in the future to cover additional
+Porter/Duff operators.
+
+In the above operator, Source and mask may be replaced with constant values,
+mask may be elided (in which case it is implicitly replaced with a constant
+opaque pixel).
+
+5. Screen Generation
+
+The screen image is generated by compositing the list of displayed pixmaps.
+Displayed pixmaps may be in any format which contains RGB data. Underneath
+all of the windows the screen is white.
+
+6. Geometric figures
+
+Geometry can be displayed by computing an appropriate A8 pixmap and
+compositing the result to a pixmap.
+
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..b1376df
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,3 @@
+#! /bin/sh
+autoreconf -v --install || exit 1
+./configure --enable-maintainer-mode "$@"
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..21268c7
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,56 @@
+dnl
+dnl $Id$
+dnl
+dnl Copyright © 2003 Keith Packard, Noah Levitt
+dnl
+dnl Permission to use, copy, modify, distribute, and sell this software and its
+dnl documentation for any purpose is hereby granted without fee, provided that
+dnl the above copyright notice appear in all copies and that both that
+dnl copyright notice and this permission notice appear in supporting
+dnl documentation, and that the name of Keith Packard not be used in
+dnl advertising or publicity pertaining to distribution of the software without
+dnl specific, written prior permission. Keith Packard makes no
+dnl representations about the suitability of this software for any purpose. It
+dnl is provided "as is" without express or implied warranty.
+dnl
+dnl KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+dnl INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+dnl EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+dnl CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+dnl DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+dnl TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+dnl PERFORMANCE OF THIS SOFTWARE.
+dnl
+dnl Process this file with autoconf to create configure.
+
+AC_PREREQ([2.57])
+
+AC_INIT(libtwin, 0.0.0, [keithp@keithp.com], libtwin)
+AM_INIT_AUTOMAKE()
+AM_MAINTAINER_MODE
+
+AM_CONFIG_HEADER(config.h)
+AC_CONFIG_AUX_DIR(.)
+
+# Check for progs
+AC_PROG_CC
+AC_PROG_LIBTOOL
+
+WARN_CFLAGS=""
+
+if test "x$GCC" = "xyes"; then
+ WARN_CFLAGS="-Wall -Wpointer-arith -Wstrict-prototypes \
+ -Wmissing-prototypes -Wmissing-declarations \
+ -Wnested-externs -fno-strict-aliasing"
+fi
+AC_SUBST(WARN_CFLAGS)
+
+# Check for X
+PKG_CHECK_MODULES(X, x11,
+ [x_found_with_pkgconfig=yes],
+ [x_found_with_pkgconfig=no])
+AC_SUBST(X_CFLAGS)
+AC_SUBST(X_LIBS)
+
+AC_OUTPUT([Makefile
+ twin.pc])
diff --git a/twin.h b/twin.h
new file mode 100644
index 0000000..1154790
--- /dev/null
+++ b/twin.h
@@ -0,0 +1,244 @@
+/*
+ * $Id$
+ *
+ * Copyright © 2004 Keith Packard
+ *
+ * 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 Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD 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 _TWIN_H_
+#define _TWIN_H_
+
+#include <stdlib.h>
+#include <stdint.h>
+
+typedef uint8_t twin_a8_t;
+typedef uint16_t twin_rgb16_t;
+typedef uint32_t twin_argb32_t;
+typedef int twin_bool;
+
+#define TWIN_FALSE 0
+#define TWIN_TRUE 1
+
+typedef enum { TWIN_A8, TWIN_RGB16, TWIN_ARGB32 } twin_format_t;
+
+#define twin_bytes_per_pixel(format) (1 << (int) (format))
+
+/*
+ * A rectangle
+ */
+typedef struct _twin_rect {
+ int left, right, top, bottom;
+} twin_rect_t;
+
+typedef union _twin_pointer {
+ void *v;
+ uint8_t *b;
+ twin_a8_t *a8;
+ twin_rgb16_t *rgb16;
+ twin_argb32_t *argb32;
+} twin_pointer_t;
+
+/*
+ * A rectangular array of pixels
+ */
+typedef struct _twin_pixmap {
+ /*
+ * Screen showing these pixels
+ */
+ struct _twin_screen *screen;
+ /*
+ * List of displayed pixmaps
+ */
+ struct _twin_pixmap *higher;
+ /*
+ * Screen position
+ */
+ int x, y;
+ /*
+ * Pixmap layout
+ */
+ twin_format_t format;
+ int width; /* pixels */
+ int height; /* pixels */
+ int stride; /* bytes */
+ /*
+ * Pixels
+ */
+ twin_pointer_t p;
+} twin_pixmap_t;
+
+/*
+ * A function that paints pixels to the screen
+ */
+typedef void (*twin_put_span_t) (int x,
+ int y,
+ int width,
+ twin_argb32_t *pixels,
+ void *closure);
+
+/*
+ * A screen
+ */
+typedef struct _twin_screen {
+ /*
+ * List of displayed pixmaps
+ */
+ twin_pixmap_t *bottom;
+ /*
+ * Output size
+ */
+ int width, height;
+ /*
+ * Damage
+ */
+ twin_rect_t damage;
+ /*
+ * Repaint function
+ */
+ twin_put_span_t put_span;
+ void *closure;
+} twin_screen_t;
+
+/*
+ * A source operand
+ */
+
+typedef enum { TWIN_SOLID, TWIN_PIXMAP } twin_source_t;
+
+typedef struct _twin_operand {
+ twin_source_t source_kind;
+ union {
+ twin_pixmap_t *pixmap;
+ twin_argb32_t argb;
+ } u;
+} twin_operand_t;
+
+typedef enum { TWIN_OVER, TWIN_SOURCE } twin_operator_t;
+
+/*
+ * twin_draw.c
+ */
+
+void
+twin_composite (twin_pixmap_t *dst,
+ int dst_x,
+ int dst_y,
+ twin_operand_t *src,
+ int src_x,
+ int src_y,
+ twin_operand_t *msk,
+ int msk_x,
+ int msk_y,
+ twin_operator_t operator,
+ int width,
+ int height);
+
+void
+twin_fill (twin_pixmap_t *dst,
+ twin_argb32_t pixel,
+ twin_operator_t operator,
+ int x,
+ int y,
+ int width,
+ int height);
+
+/*
+ * twin_pixmap.c
+ */
+
+twin_pixmap_t *
+twin_pixmap_create (twin_format_t format, int width, int height);
+
+void
+twin_pixmap_destroy (twin_pixmap_t *pixmap);
+
+void
+twin_pixmap_show (twin_pixmap_t *pixmap,
+ twin_screen_t *screen,
+ twin_pixmap_t *higher);
+
+void
+twin_pixmap_hide (twin_pixmap_t *pixmap);
+
+void
+twin_pixmap_damage (twin_pixmap_t *pixmap,
+ int x1, int y1, int x2, int y2);
+
+void
+twin_pixmap_move (twin_pixmap_t *pixmap, int x, int y);
+
+twin_pointer_t
+twin_pixmap_pointer (twin_pixmap_t *pixmap, int x, int y);
+
+/*
+ * twin_screen.c
+ */
+
+twin_screen_t *
+twin_screen_create (int width,
+ int height,
+ twin_put_span_t put_span,
+ void *closure);
+
+void
+twin_screen_destroy (twin_screen_t *screen);
+
+void
+twin_screen_damage (twin_screen_t *screen,
+ int x1, int y1, int x2, int y2);
+
+void
+twin_screen_resize (twin_screen_t *screen, int width, int height);
+
+twin_bool
+twin_screen_damaged (twin_screen_t *screen);
+
+void
+twin_screen_update (twin_screen_t *screen);
+
+/* twin_x11.c */
+
+#include <X11/Xlib.h>
+
+typedef struct _twin_x11 {
+ twin_screen_t *screen;
+ Display *dpy;
+ Window win;
+ GC gc;
+ Visual *visual;
+ int depth;
+} twin_x11_t;
+
+twin_x11_t *
+twin_x11_create (Display *dpy, int width, int height);
+
+void
+twin_x11_destroy (twin_x11_t *tx);
+
+void
+twin_x11_damage (twin_x11_t *tx, XExposeEvent *ev);
+
+void
+twin_x11_configure (twin_x11_t *tx, XConfigureEvent *ev);
+
+void
+twin_x11_update (twin_x11_t *tx);
+
+#endif /* _TWIN_H_ */
diff --git a/twin.pc.in b/twin.pc.in
new file mode 100644
index 0000000..93678ff
--- /dev/null
+++ b/twin.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: twin
+Description: Twin window system library
+Version: @PACKAGE_VERSION@
+Cflags: -I${includedir} @X_CFLAGS@
+Libs: -L${libdir} -ltwin @X_LIBS@
diff --git a/twin_draw.c b/twin_draw.c
new file mode 100644
index 0000000..b7c7a1f
--- /dev/null
+++ b/twin_draw.c
@@ -0,0 +1,408 @@
+/*
+ * $Id$
+ *
+ * Copyright © 2004 Keith Packard
+ *
+ * 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 Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD 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 "twinint.h"
+
+/* op, src, dst */
+static twin_src_op comp2[2][4][3] = {
+ { /* OVER */
+ { /* A8 */
+ _twin_a8_over_a8,
+ _twin_a8_over_rgb16,
+ _twin_a8_over_argb32,
+ },
+ { /* RGB16 */
+ _twin_rgb16_over_a8,
+ _twin_rgb16_over_rgb16,
+ _twin_rgb16_over_argb32,
+ },
+ { /* ARGB32 */
+ _twin_argb32_over_a8,
+ _twin_argb32_over_rgb16,
+ _twin_argb32_over_argb32,
+ },
+ { /* C */
+ _twin_c_over_a8,
+ _twin_c_over_rgb16,
+ _twin_c_over_argb32,
+ }
+ },
+ { /* SOURCE */
+ { /* A8 */
+ _twin_a8_source_a8,
+ _twin_a8_source_rgb16,
+ _twin_a8_source_argb32,
+ },
+ { /* RGB16 */
+ _twin_rgb16_source_a8,
+ _twin_rgb16_source_rgb16,
+ _twin_rgb16_source_argb32,
+ },
+ { /* ARGB32 */
+ _twin_argb32_source_a8,
+ _twin_argb32_source_rgb16,
+ _twin_argb32_source_argb32,
+ },
+ { /* C */
+ _twin_c_source_a8,
+ _twin_c_source_rgb16,
+ _twin_c_source_argb32,
+ }
+ }
+};
+
+/* op, src, msk, dst */
+static twin_src_msk_op comp3[2][4][4][3] = {
+ { /* OVER */
+ { /* A8 */
+ { /* A8 */
+ _twin_a8_in_a8_over_a8,
+ _twin_a8_in_a8_over_rgb16,
+ _twin_a8_in_a8_over_argb32,
+ },
+ { /* RGB16 */
+ _twin_a8_in_rgb16_over_a8,
+ _twin_a8_in_rgb16_over_rgb16,
+ _twin_a8_in_rgb16_over_argb32,
+ },
+ { /* ARGB32 */
+ _twin_a8_in_argb32_over_a8,
+ _twin_a8_in_argb32_over_rgb16,
+ _twin_a8_in_argb32_over_argb32,
+ },
+ { /* C */
+ _twin_a8_in_c_over_a8,
+ _twin_a8_in_c_over_rgb16,
+ _twin_a8_in_c_over_argb32,
+ },
+ },
+ { /* RGB16 */
+ { /* A8 */
+ _twin_rgb16_in_a8_over_a8,
+ _twin_rgb16_in_a8_over_rgb16,
+ _twin_rgb16_in_a8_over_argb32,
+ },
+ { /* RGB16 */
+ _twin_rgb16_in_rgb16_over_a8,
+ _twin_rgb16_in_rgb16_over_rgb16,
+ _twin_rgb16_in_rgb16_over_argb32,
+ },
+ { /* ARGB32 */
+ _twin_rgb16_in_argb32_over_a8,
+ _twin_rgb16_in_argb32_over_rgb16,
+ _twin_rgb16_in_argb32_over_argb32,
+ },
+ { /* C */
+ _twin_rgb16_in_c_over_a8,
+ _twin_rgb16_in_c_over_rgb16,
+ _twin_rgb16_in_c_over_argb32,
+ },
+ },
+ { /* ARGB32 */
+ { /* A8 */
+ _twin_argb32_in_a8_over_a8,
+ _twin_argb32_in_a8_over_rgb16,
+ _twin_argb32_in_a8_over_argb32,
+ },
+ { /* RGB16 */
+ _twin_argb32_in_rgb16_over_a8,
+ _twin_argb32_in_rgb16_over_rgb16,
+ _twin_argb32_in_rgb16_over_argb32,
+ },
+ { /* ARGB32 */
+ _twin_argb32_in_argb32_over_a8,
+ _twin_argb32_in_argb32_over_rgb16,
+ _twin_argb32_in_argb32_over_argb32,
+ },
+ { /* C */
+ _twin_argb32_in_c_over_a8,
+ _twin_argb32_in_c_over_rgb16,
+ _twin_argb32_in_c_over_argb32,
+ },
+ },
+ { /* C */
+ { /* A8 */
+ _twin_c_in_a8_over_a8,
+ _twin_c_in_a8_over_rgb16,
+ _twin_c_in_a8_over_argb32,
+ },
+ { /* RGB16 */
+ _twin_c_in_rgb16_over_a8,
+ _twin_c_in_rgb16_over_rgb16,
+ _twin_c_in_rgb16_over_argb32,
+ },
+ { /* ARGB32 */
+ _twin_c_in_argb32_over_a8,
+ _twin_c_in_argb32_over_rgb16,
+ _twin_c_in_argb32_over_argb32,
+ },
+ { /* C */
+ _twin_c_in_c_over_a8,
+ _twin_c_in_c_over_rgb16,
+ _twin_c_in_c_over_argb32,
+ },
+ },
+ },
+ { /* SOURCE */
+ { /* A8 */
+ { /* A8 */
+ _twin_a8_in_a8_source_a8,
+ _twin_a8_in_a8_source_rgb16,
+ _twin_a8_in_a8_source_argb32,
+ },
+ { /* RGB16 */
+ _twin_a8_in_rgb16_source_a8,
+ _twin_a8_in_rgb16_source_rgb16,
+ _twin_a8_in_rgb16_source_argb32,
+ },
+ { /* ARGB32 */
+ _twin_a8_in_argb32_source_a8,
+ _twin_a8_in_argb32_source_rgb16,
+ _twin_a8_in_argb32_source_argb32,
+ },
+ { /* C */
+ _twin_a8_in_c_source_a8,
+ _twin_a8_in_c_source_rgb16,
+ _twin_a8_in_c_source_argb32,
+ },
+ },
+ { /* RGB16 */
+ { /* A8 */
+ _twin_rgb16_in_a8_source_a8,
+ _twin_rgb16_in_a8_source_rgb16,
+ _twin_rgb16_in_a8_source_argb32,
+ },
+ { /* RGB16 */
+ _twin_rgb16_in_rgb16_source_a8,
+ _twin_rgb16_in_rgb16_source_rgb16,
+ _twin_rgb16_in_rgb16_source_argb32,
+ },
+ { /* ARGB32 */
+ _twin_rgb16_in_argb32_source_a8,
+ _twin_rgb16_in_argb32_source_rgb16,
+ _twin_rgb16_in_argb32_source_argb32,
+ },
+ { /* C */
+ _twin_rgb16_in_c_source_a8,
+ _twin_rgb16_in_c_source_rgb16,
+ _twin_rgb16_in_c_source_argb32,
+ },
+ },
+ { /* ARGB32 */
+ { /* A8 */
+ _twin_argb32_in_a8_source_a8,
+ _twin_argb32_in_a8_source_rgb16,
+ _twin_argb32_in_a8_source_argb32,
+ },
+ { /* RGB16 */
+ _twin_argb32_in_rgb16_source_a8,
+ _twin_argb32_in_rgb16_source_rgb16,
+ _twin_argb32_in_rgb16_source_argb32,
+ },
+ { /* ARGB32 */
+ _twin_argb32_in_argb32_source_a8,
+ _twin_argb32_in_argb32_source_rgb16,
+ _twin_argb32_in_argb32_source_argb32,
+ },
+ { /* C */
+ _twin_argb32_in_c_source_a8,
+ _twin_argb32_in_c_source_rgb16,
+ _twin_argb32_in_c_source_argb32,
+ },
+ },
+ { /* C */
+ { /* A8 */
+ _twin_c_in_a8_source_a8,
+ _twin_c_in_a8_source_rgb16,
+ _twin_c_in_a8_source_argb32,
+ },
+ { /* RGB16 */
+ _twin_c_in_rgb16_source_a8,
+ _twin_c_in_rgb16_source_rgb16,
+ _twin_c_in_rgb16_source_argb32,
+ },
+ { /* ARGB32 */
+ _twin_c_in_argb32_source_a8,
+ _twin_c_in_argb32_source_rgb16,
+ _twin_c_in_argb32_source_argb32,
+ },
+ { /* C */
+ _twin_c_in_c_source_a8,
+ _twin_c_in_c_source_rgb16,
+ _twin_c_in_c_source_argb32,
+ },
+ },
+ }
+};
+
+#define operand_index(o) ((o)->source_kind == TWIN_SOLID ? 3 : o->u.pixmap->format)
+
+void
+twin_composite (twin_pixmap_t *dst,
+ int dst_x,
+ int dst_y,
+ twin_operand_t *src,
+ int src_x,
+ int src_y,
+ twin_operand_t *msk,
+ int msk_x,
+ int msk_y,
+ twin_operator_t operator,
+ int width,
+ int height)
+{
+ int iy;
+ int left, right, top, bottom;
+
+ if (msk)
+ {
+ twin_src_msk_op op;
+ twin_source_u s, m;
+ int sdx, sdy, mdx, mdy;
+ twin_argb32_t *src_tmp;
+ twin_argb32_t *msk_tmp;
+ twin_argb32_t *dst_tmp;
+
+ sdx = src_x - dst_x;
+ sdy = src_y - dst_y;
+ mdx = msk_x - dst_x;
+ mdy = msk_y - dst_y;
+
+ left = dst_x;
+ right = dst_x + width;
+ top = dst_y;
+ bottom = dst_y + height;
+ if (left < 0)
+ left = 0;
+ if (right > dst->width)
+ right = dst->width;
+ if (top < 0)
+ top = 0;
+ if (top > dst->height)
+ top = dst->height;
+
+ op = comp3[operator][operand_index(src)][operand_index(msk)][dst->format];
+ if (op)
+ {
+ if (src->source_kind == TWIN_SOLID)
+ s.c = src->u.argb;
+ if (msk->source_kind == TWIN_SOLID)
+ s.c = msk->u.argb;
+ for (iy = top; iy < bottom; iy++)
+ {
+ if (src->source_kind == TWIN_PIXMAP)
+ s.p = twin_pixmap_pointer (src->u.pixmap, left+sdx, iy+sdy);
+ if (msk->source_kind == TWIN_PIXMAP)
+ m.p = twin_pixmap_pointer (msk->u.pixmap, left+mdx, iy+mdy);
+ (*op) (twin_pixmap_pointer (dst, left, iy),
+ s, m, right - left);
+ }
+ }
+ else
+ {
+ }
+ }
+ else
+ {
+ twin_src_op op;
+ twin_source_u s;
+ int sdx, sdy;
+
+ sdx = src_x - dst_x;
+ sdy = src_y - dst_y;
+
+ left = dst_x;
+ right = dst_x + width;
+ top = dst_y;
+ bottom = dst_y + height;
+ if (left < 0)
+ left = 0;
+ if (right > dst->width)
+ right = dst->width;
+ if (top < 0)
+ top = 0;
+ if (top > dst->height)
+ top = dst->height;
+
+ op = comp2[operator][operand_index(src)][dst->format];
+ if (src->source_kind == TWIN_SOLID)
+ s.c = src->u.argb;
+ for (iy = top; iy < bottom; iy++)
+ {
+ if (src->source_kind == TWIN_PIXMAP)
+ s.p = twin_pixmap_pointer (src->u.pixmap, left+sdx, iy+sdy);
+ (*op) (twin_pixmap_pointer (dst, left, iy),
+ s, right - left);
+ }
+ }
+}
+
+/*
+ * array primary index is OVER SOURCE
+ * array secondary index is ARGB32 RGB16 A8
+ */
+static twin_src_op fill[2][3] = {
+ { /* OVER */
+ _twin_c_over_a8,
+ _twin_c_over_rgb16,
+ _twin_c_over_argb32,
+ },
+ { /* SOURCE */
+ _twin_c_source_a8,
+ _twin_c_source_rgb16,
+ _twin_c_source_argb32,
+ }
+};
+
+void
+twin_fill (twin_pixmap_t *dst,
+ twin_argb32_t pixel,
+ twin_operator_t operator,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ twin_src_op op;
+ twin_source_u src;
+ int iy;
+ int left, right, top, bottom;
+
+ src.c = pixel;
+ left = x;
+ right = x + width;
+ top = y;
+ bottom = y + height;
+ if (left < 0)
+ left = 0;
+ if (right > dst->width)
+ right = dst->width;
+ if (top < 0)
+ top = 0;
+ if (top > dst->height)
+ top = dst->height;
+ op = fill[operator][dst->format];
+ for (iy = top; iy < bottom; iy++)
+ (*op) (twin_pixmap_pointer (dst, left, iy), src, right - left);
+}
diff --git a/twin_pixmap.c b/twin_pixmap.c
new file mode 100644
index 0000000..3610e01
--- /dev/null
+++ b/twin_pixmap.c
@@ -0,0 +1,118 @@
+/*
+ * $Id$
+ *
+ * Copyright © 2004 Keith Packard
+ *
+ * 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 Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD 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 "twinint.h"
+
+twin_pixmap_t *
+twin_pixmap_create (twin_format_t format, int width, int height)
+{
+ int stride = twin_bytes_per_pixel (format) * width;
+ int size = sizeof (twin_pixmap_t) + stride * height;
+ twin_pixmap_t *pixmap = malloc (size);
+ if (!pixmap)
+ return 0;
+ pixmap->screen = 0;
+ pixmap->higher = 0;
+ pixmap->x = pixmap->y = 0;
+ pixmap->format = format;
+ pixmap->width = width;
+ pixmap->height = height;
+ pixmap->stride = stride;
+ pixmap->p.v = pixmap + 1;
+ return pixmap;
+}
+
+void
+twin_pixmap_destroy (twin_pixmap_t *pixmap)
+{
+ if (pixmap->screen)
+ twin_pixmap_hide (pixmap);
+ free (pixmap);
+}
+
+void
+twin_pixmap_show (twin_pixmap_t *pixmap,
+ twin_screen_t *screen,
+ twin_pixmap_t *lower)
+{
+ twin_pixmap_t **higherp;
+ if (pixmap->screen)
+ twin_pixmap_hide (pixmap);
+ pixmap->screen = screen;
+ if (lower)
+ higherp = &lower->higher;
+ else
+ higherp = &screen->bottom;
+ pixmap->higher = *higherp;
+ *higherp = pixmap;
+ twin_pixmap_damage (pixmap, 0, 0, pixmap->width, pixmap->height);
+}
+
+void
+twin_pixmap_hide (twin_pixmap_t *pixmap)
+{
+ twin_screen_t *screen = pixmap->screen;
+ twin_pixmap_t **higherp;
+
+ if (!screen)
+ return;
+ twin_pixmap_damage (pixmap, 0, 0, pixmap->width, pixmap->height);
+ for (higherp = &screen->bottom; *higherp != pixmap; higherp = &(*higherp)->higher)
+ ;
+ *higherp = pixmap->higher;
+ pixmap->screen = 0;
+ pixmap->higher = 0;
+}
+
+twin_pointer_t
+twin_pixmap_pointer (twin_pixmap_t *pixmap, int x, int y)
+{
+ twin_pointer_t p;
+
+ p.b = (pixmap->p.b +
+ y * pixmap->stride +
+ x * twin_bytes_per_pixel(pixmap->format));
+ return p;
+}
+
+void
+twin_pixmap_damage (twin_pixmap_t *pixmap,
+ int x1, int y1, int x2, int y2)
+{
+ if (pixmap->screen)
+ twin_screen_damage (pixmap->screen,
+ x1 + pixmap->x,
+ y1 + pixmap->y,
+ x2 + pixmap->x,
+ y2 + pixmap->y);
+}
+
+void
+twin_pixmap_move (twin_pixmap_t *pixmap, int x, int y)
+{
+ twin_pixmap_damage (pixmap, 0, 0, pixmap->width, pixmap->height);
+ pixmap->x = x;
+ pixmap->y = y;
+ twin_pixmap_damage (pixmap, 0, 0, pixmap->width, pixmap->height);
+}
diff --git a/twin_primitive.c b/twin_primitive.c
new file mode 100644
index 0000000..2f69938
--- /dev/null
+++ b/twin_primitive.c
@@ -0,0 +1,230 @@
+/*
+ * $Id$
+ *
+ * Copyright © 2004 Keith Packard
+ *
+ * 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 Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD 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 "twinint.h"
+
+static twin_argb32_t __inline
+in_over (twin_argb32_t dst,
+ twin_argb32_t src,
+ twin_a8_t msk)
+{
+ uint16_t t1, t2, t3, t4;
+ twin_a8_t a;
+
+ src = (twin_in(src,0,msk,t1) |
+ twin_in(src,8,msk,t2) |
+ twin_in(src,16,msk,t3) |
+ twin_in(src,24,msk,t4));
+ a = ~(src >> 24);
+ return (twin_over (src, dst, 0, a, t1) |
+ twin_over (src, dst, 8, a, t2) |
+ twin_over (src, dst, 16, a, t3) |
+ twin_over (src, dst, 24, a, t4));
+}
+
+static twin_argb32_t __inline
+in (twin_argb32_t src,
+ twin_a8_t msk)
+{
+ uint16_t t1, t2, t3, t4;
+
+ return (twin_in(src,0,msk,t1) |
+ twin_in(src,8,msk,t2) |
+ twin_in(src,16,msk,t3) |
+ twin_in(src,24,msk,t4));
+}
+
+static twin_argb32_t __inline
+over (twin_argb32_t dst,
+ twin_argb32_t src)
+{
+ uint16_t t1, t2, t3, t4;
+ twin_a8_t a;
+
+ a = ~(src >> 24);
+ return (twin_over (src, dst, 0, a, t1) |
+ twin_over (src, dst, 8, a, t2) |
+ twin_over (src, dst, 16, a, t3) |
+ twin_over (src, dst, 24, a, t4));
+}
+
+static twin_argb32_t __inline
+rgb16_to_argb32 (twin_rgb16_t v)
+{
+ return twin_rgb16_to_argb32(v);
+}
+
+static twin_argb32_t __inline
+a8_to_argb32 (twin_a8_t v)
+{
+ return v << 24;
+}
+
+static twin_rgb16_t __inline
+argb32_to_rgb16 (twin_argb32_t v)
+{
+ return twin_argb32_to_rgb16 (v);
+}
+
+static twin_a8_t __inline
+argb32_to_a8 (twin_argb32_t v)
+{
+ return v >> 24;
+}
+
+/*
+ * Naming convention
+ *
+ * _twin_<src>_in_<msk>_op_<dst>
+ *
+ * Use 'c' for constant
+ */
+
+#define dst_argb32_get (*dst.argb32)
+#define dst_argb32_set (*dst.argb32++) =
+#define dst_rgb16_get (rgb16_to_argb32(*dst.rgb16))
+#define dst_rgb16_set (*dst.rgb16++) = argb32_to_rgb16
+#define dst_a8_get (a8_to_argb32(*dst.a8))
+#define dst_a8_set (*dst.a8++) = argb32_to_a8
+
+#define src_c (src.c)
+#define src_argb32 (*src.p.argb32++)
+#define src_rgb16 (rgb16_to_argb32(*src.p.rgb16++))
+#define src_a8 (a8_to_argb32(*src.p.a8++))
+
+#define msk_c (argb32_to_a8 (msk.c))
+#define msk_argb32 (argb32_to_a8 (*msk.p.argb32++))
+#define msk_rgb16 (0xff)
+#define msk_a8 (*msk.p.a8++)
+
+#define cat2(a,b) a##b
+#define cat3(a,b,c) a##b##c
+#define cat4(a,b,c,d) a##b##c##d
+#define cat6(a,b,c,d,e,f) a##b##c##d##e##f
+
+#define _twin_in_op_name(src,op,msk,dst) cat6(_twin_,src,_in_,msk,op,dst)
+
+#define _twin_op_name(src,op,dst) cat4(_twin_,src,op,dst)
+
+#define make_twin_in_over(__dst,__src,__msk) \
+void \
+_twin_in_op_name(__src,_over_,__msk,__dst)(twin_pointer_t dst, \
+ twin_source_u src, \
+ twin_source_u msk, \
+ int width) \
+{ \
+ twin_argb32_t dst32; \
+ twin_argb32_t src32; \
+ twin_a8_t msk8; \
+ while (width--) { \
+ dst32 = cat3(dst_,__dst,_get); \
+ src32 = cat2(src_,__src); \
+ msk8 = cat2(msk_,__msk); \
+ dst32 = in_over (dst32, src32, msk8); \
+ cat3(dst_,__dst,_set) (dst32); \
+ } \
+}
+
+#define make_twin_in_source(__dst,__src,__msk) \
+void \
+_twin_in_op_name(__src,_source_,__msk,__dst)(twin_pointer_t dst, \
+ twin_source_u src, \
+ twin_source_u msk, \
+ int width) \
+{ \
+ twin_argb32_t dst32; \
+ twin_argb32_t src32; \
+ twin_a8_t msk8; \
+ while (width--) { \
+ src32 = cat2(src_,__src); \
+ msk8 = cat2(msk_,__msk); \
+ dst32 = in (src32, msk8); \
+ cat3(dst_,__dst,_set) (dst32); \
+ } \
+}
+
+#define make_twin_in_op_msks(op,dst,src) \
+cat2(make_twin_in_,op)(dst,src,argb32) \
+cat2(make_twin_in_,op)(dst,src,rgb16) \
+cat2(make_twin_in_,op)(dst,src,a8) \
+cat2(make_twin_in_,op)(dst,src,c)
+
+#define make_twin_in_op_srcs_msks(op,dst) \
+make_twin_in_op_msks(op,dst,argb32) \
+make_twin_in_op_msks(op,dst,rgb16) \
+make_twin_in_op_msks(op,dst,a8) \
+make_twin_in_op_msks(op,dst,c)
+
+#define make_twin_in_op_dsts_srcs_msks(op) \
+make_twin_in_op_srcs_msks(op,argb32) \
+make_twin_in_op_srcs_msks(op,rgb16) \
+make_twin_in_op_srcs_msks(op,a8)
+
+make_twin_in_op_dsts_srcs_msks(over)
+make_twin_in_op_dsts_srcs_msks(source)
+
+#define make_twin_over(__dst,__src) \
+void \
+_twin_op_name(__src,_over_,__dst) (twin_pointer_t dst, \
+ twin_source_u src, \
+ int width) \
+{ \
+ twin_argb32_t dst32; \
+ twin_argb32_t src32; \
+ while (width--) { \
+ dst32 = cat3(dst_,__dst,_get); \
+ src32 = cat2(src_,__src); \
+ dst32 = over (dst32, src32); \
+ cat3(dst_,__dst,_set) (dst32); \
+ } \
+}
+
+#define make_twin_source(__dst,__src) \
+void \
+_twin_op_name(__src,_source_,__dst) (twin_pointer_t dst, \
+ twin_source_u src, \
+ int width) \
+{ \
+ twin_argb32_t dst32; \
+ twin_argb32_t src32; \
+ while (width--) { \
+ src32 = cat2(src_,__src); \
+ dst32 = src32; \
+ cat3(dst_,__dst,_set) (dst32); \
+ } \
+}
+
+#define make_twin_op_srcs(op,dst) \
+cat2(make_twin_,op)(dst,argb32) \
+cat2(make_twin_,op)(dst,rgb16) \
+cat2(make_twin_,op)(dst,a8) \
+cat2(make_twin_,op)(dst,c)
+
+#define make_twin_op_dsts_srcs(op) \
+make_twin_op_srcs(op,argb32) \
+make_twin_op_srcs(op,rgb16) \
+make_twin_op_srcs(op,a8)
+
+make_twin_op_dsts_srcs(over)
+make_twin_op_dsts_srcs(source)
diff --git a/twin_screen.c b/twin_screen.c
new file mode 100644
index 0000000..c8936f7
--- /dev/null
+++ b/twin_screen.c
@@ -0,0 +1,148 @@
+/*
+ * $Id$
+ *
+ * Copyright © 2004 Keith Packard
+ *
+ * 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 Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD 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 "twinint.h"
+
+twin_screen_t *
+twin_screen_create (int width,
+ int height,
+ twin_put_span_t put_span,
+ void *closure)
+{
+ twin_screen_t *screen = malloc (sizeof (twin_screen_t));
+ if (!screen)
+ return 0;
+ screen->bottom = 0;
+ screen->width = width;
+ screen->height = height;
+ screen->damage.left = screen->damage.right = 0;
+ screen->damage.top = screen->damage.bottom = 0;
+ screen->put_span = put_span;
+ screen->closure = closure;
+ return screen;
+}
+
+void
+twin_screen_destroy (twin_screen_t *screen)
+{
+ while (screen->bottom)
+ twin_pixmap_hide (screen->bottom);
+ free (screen);
+}
+
+void
+twin_screen_damage (twin_screen_t *screen,
+ int left, int top, int right, int bottom)
+{
+ if (screen->damage.left == screen->damage.right)
+ {
+ screen->damage.left = left;
+ screen->damage.right = right;
+ screen->damage.top = top;
+ screen->damage.bottom = bottom;
+ }
+ else
+ {
+ if (left < screen->damage.left)
+ screen->damage.left = left;
+ if (top < screen->damage.top)
+ screen->damage.top = top;
+ if (screen->damage.right < right)
+ screen->damage.right = right;
+ if (screen->damage.bottom < bottom)
+ screen->damage.bottom = bottom;
+ }
+}
+
+void
+twin_screen_resize (twin_screen_t *screen, int width, int height)
+{
+ screen->width = width;
+ screen->height = height;
+ twin_screen_damage (screen, 0, 0, screen->width, screen->height);
+}
+
+twin_bool
+twin_screen_damaged (twin_screen_t *screen)
+{
+ return (screen->damage.left < screen->damage.right &&
+ screen->damage.top < screen->damage.bottom);
+}
+
+void
+twin_screen_update (twin_screen_t *screen)
+{
+ if (screen->damage.left < screen->damage.right &&
+ screen->damage.top < screen->damage.bottom)
+ {
+ int x = screen->damage.left;
+ int y = screen->damage.top;
+ int width = screen->damage.right - screen->damage.left;
+ int height = screen->damage.bottom - screen->damage.top;
+ twin_argb32_t *span;
+ twin_pixmap_t *p;
+
+ /* XXX what is the maximum number of lines? */
+ span = malloc (width * sizeof (twin_argb32_t));
+ if (!span)
+ return;
+
+ while (height--)
+ {
+ memset (span, 0xff, width * sizeof (twin_argb32_t));
+ for (p = screen->bottom; p; p = p->higher)
+ {
+ twin_pointer_t dst;
+ twin_source_u src;
+
+ int left, right;
+ /* bounds check in y */
+ if (y < p->y)
+ continue;
+ if (p->y + p->height <= y)
+ continue;
+ /* bounds check in x*/
+ left = x;
+ if (left < p->x)
+ left = p->x;
+ right = x + width;
+ if (right > p->x + p->width)
+ right = p->x + p->width;
+ if (left >= right)
+ continue;
+ dst.argb32 = span + (left - x);
+ src.p = twin_pixmap_pointer (p, left - p->x, y - p->y);
+ if (p->format == TWIN_RGB16)
+ _twin_rgb16_source_argb32 (dst, src, right - left);
+ else
+ _twin_argb32_over_argb32 (dst, src, right - left);
+ }
+ (*screen->put_span) (x, y, width, span, screen->closure);
+ y++;
+ }
+ free (span);
+ screen->damage.left = screen->damage.right = 0;
+ screen->damage.top = screen->damage.bottom = 0;
+ }
+}
diff --git a/twin_x11.c b/twin_x11.c
new file mode 100644
index 0000000..31797bc
--- /dev/null
+++ b/twin_x11.c
@@ -0,0 +1,116 @@
+/*
+ * $Id$
+ *
+ * Copyright © 2004 Keith Packard
+ *
+ * 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 Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD 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 "twinint.h"
+#include <X11/Xutil.h>
+
+static void
+_twin_x11_put_span (int x,
+ int y,
+ int width,
+ twin_argb32_t *pixels,
+ void *closure)
+{
+ twin_x11_t *tx = closure;
+ XImage *image;
+ int ix = 0;
+ int iw = width;
+
+ image = XCreateImage (tx->dpy, tx->visual, tx->depth, ZPixmap,
+ 0, 0, width, 1, 32, 0);
+
+ image->data = malloc (4 * width);
+
+ while (iw--)
+ {
+ twin_argb32_t pixel = *pixels++;
+
+ if (tx->depth == 16)
+ pixel = twin_argb32_to_rgb16 (pixel);
+ XPutPixel (image, ix, 0, pixel);
+ ix++;
+ }
+ XPutImage (tx->dpy, tx->win, tx->gc, image, 0, 0, x, y, width, 1);
+ XDestroyImage (image);
+}
+
+twin_x11_t *
+twin_x11_create (Display *dpy, int width, int height)
+{
+ twin_x11_t *tx;
+ int scr = DefaultScreen (dpy);
+ XSetWindowAttributes wa;
+
+ tx = malloc (sizeof (twin_x11_t));
+ if (!tx)
+ return 0;
+ tx->dpy = dpy;
+ tx->visual = DefaultVisual (dpy, scr);
+ tx->depth = DefaultDepth (dpy, scr);
+
+ wa.background_pixmap = None;
+ wa.event_mask = (KeyPressMask|
+ KeyReleaseMask|
+ ButtonPressMask|
+ ButtonReleaseMask|
+ PointerMotionMask|
+ ExposureMask|
+ StructureNotifyMask);
+
+ tx->win = XCreateWindow (dpy, RootWindow (dpy, scr),
+ 0, 0, width, height, 0,
+ tx->depth, InputOutput,
+ tx->visual, CWBackPixmap|CWEventMask, &wa);
+ tx->gc = XCreateGC (dpy, tx->win, 0, 0);
+ tx->screen = twin_screen_create (width, height,
+ _twin_x11_put_span, tx);
+ XMapWindow (dpy, tx->win);
+ return tx;
+}
+
+void
+twin_x11_destroy (twin_x11_t *tx)
+{
+ twin_screen_destroy (tx->screen);
+ XDestroyWindow (tx->dpy, tx->win);
+}
+
+void
+twin_x11_damage (twin_x11_t *tx, XExposeEvent *ev)
+{
+ twin_screen_damage (tx->screen,
+ ev->x, ev->y, ev->x + ev->width, ev->y + ev->height);
+}
+
+void
+twin_x11_configure (twin_x11_t *tx, XConfigureEvent *ev)
+{
+ twin_screen_resize (tx->screen, ev->width, ev->height);
+}
+
+void
+twin_x11_update (twin_x11_t *tx)
+{
+ twin_screen_update (tx->screen);
+}
diff --git a/twinint.h b/twinint.h
new file mode 100644
index 0000000..3c2dc6d
--- /dev/null
+++ b/twinint.h
@@ -0,0 +1,213 @@
+/*
+ * $Id$
+ *
+ * Copyright © 2004 Keith Packard
+ *
+ * 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 Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD 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 _TWININT_H_
+#define _TWININT_H_
+
+#include "twin.h"
+#include <string.h>
+
+#define twin_int_mult(a,b,t) ((t) = (a) * (b) + 0x80, \
+ ((((t)>>8 ) + (t))>>8 ))
+#define twin_int_div(a,b) (((uint16_t) (a) * 255) / (b))
+#define twin_get_8(v,i) ((uint16_t) (uint8_t) ((v) >> (i)))
+#define twin_sat(t) ((uint8_t) ((t) | (0 - ((t) >> 8))))
+
+#define twin_in(s,i,m,t) \
+ ((twin_argb32_t) twin_int_mult (twin_get_8(s,i),(m),(t)) << (i))
+
+#define twin_over(s,d,i,m,t) \
+ ((t) = twin_int_mult(twin_get_8(d,i),(m),(t)) + twin_get_8(s,i),\
+ (twin_argb32_t) twin_sat (t) << (i))
+
+#define twin_over(s,d,i,m,t) \
+ ((t) = twin_int_mult(twin_get_8(d,i),(m),(t)) + twin_get_8(s,i),\
+ (twin_argb32_t) twin_sat (t) << (i))
+
+#define twin_argb32_to_rgb16(s) ((((s) >> 3) & 0x001f) | \
+ (((s) >> 5) & 0x07e0) | \
+ (((s) >> 8) & 0xf800))
+#define twin_rgb16_to_argb32(s) \
+ (((((s) << 3) & 0xf8) | (((s) >> 2) & 0x7)) | \
+ ((((s) << 5) & 0xfc00) | (((s) >> 1) & 0x300)) | \
+ ((((s) << 8) & 0xf80000) | (((s) << 3) & 0x70000)) | \
+ 0xff000000)
+
+typedef union {
+ twin_pointer_t p;
+ twin_argb32_t c;
+} twin_source_u;
+
+typedef void (*twin_src_msk_op) (twin_pointer_t dst,
+ twin_source_u src,
+ twin_source_u msk,
+ int width);
+
+typedef void (*twin_src_op) (twin_pointer_t dst,
+ twin_source_u src,
+ int width);
+
+/* twin_primitive.c */
+
+typedef void twin_in_op_func (twin_pointer_t dst,
+ twin_source_u src,
+ twin_source_u msk,
+ int width);
+
+typedef void twin_op_func (twin_pointer_t dst,
+ twin_source_u src,
+ int width);
+
+twin_in_op_func _twin_argb32_in_argb32_over_argb32;
+twin_in_op_func _twin_argb32_in_rgb16_over_argb32;
+twin_in_op_func _twin_argb32_in_a8_over_argb32;
+twin_in_op_func _twin_argb32_in_c_over_argb32;
+twin_in_op_func _twin_rgb16_in_argb32_over_argb32;
+twin_in_op_func _twin_rgb16_in_rgb16_over_argb32;
+twin_in_op_func _twin_rgb16_in_a8_over_argb32;
+twin_in_op_func _twin_rgb16_in_c_over_argb32;
+twin_in_op_func _twin_a8_in_argb32_over_argb32;
+twin_in_op_func _twin_a8_in_rgb16_over_argb32;
+twin_in_op_func _twin_a8_in_a8_over_argb32;
+twin_in_op_func _twin_a8_in_c_over_argb32;
+twin_in_op_func _twin_c_in_argb32_over_argb32;
+twin_in_op_func _twin_c_in_rgb16_over_argb32;
+twin_in_op_func _twin_c_in_a8_over_argb32;
+twin_in_op_func _twin_c_in_c_over_argb32;
+twin_in_op_func _twin_argb32_in_argb32_over_rgb16;
+twin_in_op_func _twin_argb32_in_rgb16_over_rgb16;
+twin_in_op_func _twin_argb32_in_a8_over_rgb16;
+twin_in_op_func _twin_argb32_in_c_over_rgb16;
+twin_in_op_func _twin_rgb16_in_argb32_over_rgb16;
+twin_in_op_func _twin_rgb16_in_rgb16_over_rgb16;
+twin_in_op_func _twin_rgb16_in_a8_over_rgb16;
+twin_in_op_func _twin_rgb16_in_c_over_rgb16;
+twin_in_op_func _twin_a8_in_argb32_over_rgb16;
+twin_in_op_func _twin_a8_in_rgb16_over_rgb16;
+twin_in_op_func _twin_a8_in_a8_over_rgb16;
+twin_in_op_func _twin_a8_in_c_over_rgb16;
+twin_in_op_func _twin_c_in_argb32_over_rgb16;
+twin_in_op_func _twin_c_in_rgb16_over_rgb16;
+twin_in_op_func _twin_c_in_a8_over_rgb16;
+twin_in_op_func _twin_c_in_c_over_rgb16;
+twin_in_op_func _twin_argb32_in_argb32_over_a8;
+twin_in_op_func _twin_argb32_in_rgb16_over_a8;
+twin_in_op_func _twin_argb32_in_a8_over_a8;
+twin_in_op_func _twin_argb32_in_c_over_a8;
+twin_in_op_func _twin_rgb16_in_argb32_over_a8;
+twin_in_op_func _twin_rgb16_in_rgb16_over_a8;
+twin_in_op_func _twin_rgb16_in_a8_over_a8;
+twin_in_op_func _twin_rgb16_in_c_over_a8;
+twin_in_op_func _twin_a8_in_argb32_over_a8;
+twin_in_op_func _twin_a8_in_rgb16_over_a8;
+twin_in_op_func _twin_a8_in_a8_over_a8;
+twin_in_op_func _twin_a8_in_c_over_a8;
+twin_in_op_func _twin_c_in_argb32_over_a8;
+twin_in_op_func _twin_c_in_rgb16_over_a8;
+twin_in_op_func _twin_c_in_a8_over_a8;
+twin_in_op_func _twin_c_in_c_over_a8;
+twin_in_op_func _twin_argb32_in_argb32_over_c;
+
+twin_in_op_func _twin_argb32_in_argb32_source_argb32;
+twin_in_op_func _twin_argb32_in_rgb16_source_argb32;
+twin_in_op_func _twin_argb32_in_a8_source_argb32;
+twin_in_op_func _twin_argb32_in_c_source_argb32;
+twin_in_op_func _twin_rgb16_in_argb32_source_argb32;
+twin_in_op_func _twin_rgb16_in_rgb16_source_argb32;
+twin_in_op_func _twin_rgb16_in_a8_source_argb32;
+twin_in_op_func _twin_rgb16_in_c_source_argb32;
+twin_in_op_func _twin_a8_in_argb32_source_argb32;
+twin_in_op_func _twin_a8_in_rgb16_source_argb32;
+twin_in_op_func _twin_a8_in_a8_source_argb32;
+twin_in_op_func _twin_a8_in_c_source_argb32;
+twin_in_op_func _twin_c_in_argb32_source_argb32;
+twin_in_op_func _twin_c_in_rgb16_source_argb32;
+twin_in_op_func _twin_c_in_a8_source_argb32;
+twin_in_op_func _twin_c_in_c_source_argb32;
+twin_in_op_func _twin_argb32_in_argb32_source_rgb16;
+twin_in_op_func _twin_argb32_in_rgb16_source_rgb16;
+twin_in_op_func _twin_argb32_in_a8_source_rgb16;
+twin_in_op_func _twin_argb32_in_c_source_rgb16;
+twin_in_op_func _twin_rgb16_in_argb32_source_rgb16;
+twin_in_op_func _twin_rgb16_in_rgb16_source_rgb16;
+twin_in_op_func _twin_rgb16_in_a8_source_rgb16;
+twin_in_op_func _twin_rgb16_in_c_source_rgb16;
+twin_in_op_func _twin_a8_in_argb32_source_rgb16;
+twin_in_op_func _twin_a8_in_rgb16_source_rgb16;
+twin_in_op_func _twin_a8_in_a8_source_rgb16;
+twin_in_op_func _twin_a8_in_c_source_rgb16;
+twin_in_op_func _twin_c_in_argb32_source_rgb16;
+twin_in_op_func _twin_c_in_rgb16_source_rgb16;
+twin_in_op_func _twin_c_in_a8_source_rgb16;
+twin_in_op_func _twin_c_in_c_source_rgb16;
+twin_in_op_func _twin_argb32_in_argb32_source_a8;
+twin_in_op_func _twin_argb32_in_rgb16_source_a8;
+twin_in_op_func _twin_argb32_in_a8_source_a8;
+twin_in_op_func _twin_argb32_in_c_source_a8;
+twin_in_op_func _twin_rgb16_in_argb32_source_a8;
+twin_in_op_func _twin_rgb16_in_rgb16_source_a8;
+twin_in_op_func _twin_rgb16_in_a8_source_a8;
+twin_in_op_func _twin_rgb16_in_c_source_a8;
+twin_in_op_func _twin_a8_in_argb32_source_a8;
+twin_in_op_func _twin_a8_in_rgb16_source_a8;
+twin_in_op_func _twin_a8_in_a8_source_a8;
+twin_in_op_func _twin_a8_in_c_source_a8;
+twin_in_op_func _twin_c_in_argb32_source_a8;
+twin_in_op_func _twin_c_in_rgb16_source_a8;
+twin_in_op_func _twin_c_in_a8_source_a8;
+twin_in_op_func _twin_c_in_c_source_a8;
+twin_in_op_func _twin_argb32_in_argb32_source_c;
+
+twin_op_func _twin_argb32_over_argb32;
+twin_op_func _twin_rgb16_over_argb32;
+twin_op_func _twin_a8_over_argb32;
+twin_op_func _twin_c_over_argb32;
+twin_op_func _twin_argb32_over_rgb16;
+twin_op_func _twin_rgb16_over_rgb16;
+twin_op_func _twin_a8_over_rgb16;
+twin_op_func _twin_c_over_rgb16;
+twin_op_func _twin_argb32_over_a8;
+twin_op_func _twin_rgb16_over_a8;
+twin_op_func _twin_a8_over_a8;
+twin_op_func _twin_c_over_a8;
+twin_op_func _twin_argb32_source_argb32;
+twin_op_func _twin_rgb16_source_argb32;
+twin_op_func _twin_a8_source_argb32;
+twin_op_func _twin_c_source_argb32;
+twin_op_func _twin_argb32_source_rgb16;
+twin_op_func _twin_rgb16_source_rgb16;
+twin_op_func _twin_a8_source_rgb16;
+twin_op_func _twin_c_source_rgb16;
+twin_op_func _twin_argb32_source_a8;
+twin_op_func _twin_rgb16_source_a8;
+twin_op_func _twin_a8_source_a8;
+twin_op_func _twin_c_source_a8;
+
+twin_argb32_t *
+_twin_fetch_rgb16 (twin_pixmap_t *pixmap, int x, int y, int w, twin_argb32_t *span);
+
+twin_argb32_t *
+_twin_fetch_argb32 (twin_pixmap_t *pixmap, int x, int y, int w, twin_argb32_t *span);
+
+#endif /* _TWININT_H_ */
diff --git a/xtwin.c b/xtwin.c
new file mode 100644
index 0000000..c91de18
--- /dev/null
+++ b/xtwin.c
@@ -0,0 +1,79 @@
+/*
+ * $Id$
+ *
+ * Copyright © 2004 Keith Packard
+ *
+ * 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 Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD 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 <X11/Xlib.h>
+#include "twin.h"
+#include <string.h>
+#include <stdio.h>
+
+int
+main (int argc, char **argv)
+{
+ Display *dpy = XOpenDisplay (0);
+ twin_x11_t *x11 = twin_x11_create (dpy, 256, 256);
+ twin_pixmap_t *red = twin_pixmap_create (TWIN_ARGB32, 100, 100);
+ twin_pixmap_t *blue = twin_pixmap_create (TWIN_ARGB32, 100, 100);
+ XEvent ev;
+ int x, y;
+
+ twin_fill (red, 0x80800000, TWIN_SOURCE, 0, 0, 100, 100);
+ twin_fill (red, 0xffffff00, TWIN_SOURCE, 25, 25, 50, 50);
+ twin_fill (blue, 0x80000080, TWIN_SOURCE, 0, 0, 100, 100);
+ twin_fill (blue, 0xff00c000, TWIN_SOURCE, 25, 25, 50, 50);
+ twin_pixmap_move (red, 20, 20);
+ twin_pixmap_move (blue, 80, 80);
+ twin_pixmap_show (red, x11->screen, 0);
+ twin_pixmap_show (blue, x11->screen, 0);
+ for (;;)
+ {
+ if (twin_screen_damaged (x11->screen))
+ twin_x11_update (x11);
+ do {
+ XNextEvent (dpy, &ev);
+ switch (ev.type) {
+ case Expose:
+ twin_x11_damage (x11, &ev.xexpose);
+ break;
+ case ButtonPress:
+ if (ev.xbutton.button == 2)
+ {
+ if (red->higher == 0)
+ twin_pixmap_show (red, x11->screen, 0);
+ else
+ twin_pixmap_show (blue, x11->screen, 0);
+ }
+ break;
+ case MotionNotify:
+ x = ev.xmotion.x - 50;
+ y = ev.xmotion.y - 50;
+ if (ev.xmotion.state & Button1Mask)
+ twin_pixmap_move (red, x, y);
+ if (ev.xmotion.state & Button3Mask)
+ twin_pixmap_move (blue, x, y);
+ break;
+ }
+ } while (QLength (dpy));
+ }
+}
+