diff --git a/.gitignore b/.gitignore
index ed29992..f11de3e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,6 +10,7 @@ c3s/c3s
c3s/c3s_asan
c3s/c3s_cov
c3s/c3s_debug
+config.h
config.mk
*.core
*.css
@@ -22,7 +23,7 @@ ic3/ic3_asan
ic3/ic3_cov
ic3/ic3_debug
*.la
-libc3/config.h
+libc3/window/cairo/xcb/demo/c3_window_cairo_xcb_demo
.libs/
*.lo
*.o
diff --git a/README.md b/README.md
index 4742f3d..0124d39 100644
--- a/README.md
+++ b/README.md
@@ -241,28 +241,41 @@ All these list formats are supported in pattern matching.
- libc3
- c3
- [DONE] tag_type
+ - macros
+ - modules
+ - defmodule
+ - def
+ - gui
+ - cairo graphics
- facts
- negative facts : 4 + 2n = not 3 + 2n
- with ignore variables
- math
- fractions
- floating point numbers (decimals)
+ - maps (anonymous struct)
+ - access
+ - get
+ - put
+ - machine word alignment (from rtbuf)
- structs
- - unions
+ - as tagged maps
- enums
+ - unions
- errors (setjmp, longjmp)
- stacktrace
- ffi ?
- libdwarf
- control structures
+ - if / when / unless
+ - switch/case/cond
- while
- - modules
- - defmodule
+ - quote
+ - unquote
- functions
- return
- def
- & &1
- - macros
- livebook
- gaussian
- buf_sha256
diff --git a/libc3/window/cairo/c3_window_cairo_demo.c b/libc3/window/cairo/c3_window_cairo_demo.c
new file mode 100644
index 0000000..2badd55
--- /dev/null
+++ b/libc3/window/cairo/c3_window_cairo_demo.c
@@ -0,0 +1,23 @@
+/* c3
+ * Copyright 2022,2023 kmx.io <contact@kmx.io>
+ *
+ * Permission is hereby granted to use this software granted the above
+ * copyright notice and this permission paragraph are included in all
+ * copies and substantial portions of this software.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS-IS" WITHOUT ANY GUARANTEE OF
+ * PURPOSE AND PERFORMANCE. IN NO EVENT WHATSOEVER SHALL THE
+ * AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+#include <libc3/c3.h>
+#include <cairo/cairo.h>
+#include "c3_window_cairo_demo.h"
+
+bool c3_window_cairo_demo_render (cairo_t *cr)
+{
+ cairo_set_source_rgb(cr, 0, 0, 1);
+ cairo_rectangle(cr, 20, 20, 100, 100);
+ cairo_fill(cr);
+ return true;
+}
diff --git a/libc3/window/cairo/c3_window_cairo_demo.h b/libc3/window/cairo/c3_window_cairo_demo.h
new file mode 100644
index 0000000..86f64ee
--- /dev/null
+++ b/libc3/window/cairo/c3_window_cairo_demo.h
@@ -0,0 +1,20 @@
+/* c3
+ * Copyright 2022,2023 kmx.io <contact@kmx.io>
+ *
+ * Permission is hereby granted to use this software granted the above
+ * copyright notice and this permission paragraph are included in all
+ * copies and substantial portions of this software.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS-IS" WITHOUT ANY GUARANTEE OF
+ * PURPOSE AND PERFORMANCE. IN NO EVENT WHATSOEVER SHALL THE
+ * AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+#ifndef C3_CAIRO_DEMO_H
+#define C3_CAIRO_DEMO_H
+
+#include <libc3/types.h>
+
+bool c3_window_cairo_demo_render (cairo_t *cr);
+
+#endif /* C3_CAIRO_DEMO_H */
diff --git a/libc3/window/cairo/types.h b/libc3/window/cairo/types.h
new file mode 100644
index 0000000..9fb9aa7
--- /dev/null
+++ b/libc3/window/cairo/types.h
@@ -0,0 +1,46 @@
+/* c3
+ * Copyright 2022,2023 kmx.io <contact@kmx.io>
+ *
+ * Permission is hereby granted to use this software granted the above
+ * copyright notice and this permission paragraph are included in all
+ * copies and substantial portions of this software.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS-IS" WITHOUT ANY GUARANTEE OF
+ * PURPOSE AND PERFORMANCE. IN NO EVENT WHATSOEVER SHALL THE
+ * AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+/** @file types.h
+ * @brief Module C3.Window.Cairo
+ *
+ * Struct for all GUI window Cairo graphics operations.
+ */
+#ifndef LIBC3_WINDOW_CAIRO_TYPES_H
+#define LIBC3_WINDOW_CAIRO_TYPES_H
+
+#include <cairo/cairo.h>
+#include <libc3/types.h>
+#include "../types.h"
+
+typedef struct window_cairo s_window_cairo;
+
+/* return false to break event loop */
+typedef bool (*f_window_cairo_render) (s_cairo_window *window,
+ cairo_t *cr);
+
+/* return false to break event loop */
+typedef bool (*f_window_cairo_resize) (s_cairo_window *window,
+ uw w, uw h);
+
+struct window_cairo {
+ /* compatible with s_window */
+ sw x;
+ sw y;
+ uw w;
+ uw h;
+ f_cairo_window_render render;
+ f_cairo_window_resize resize;
+ cairo_t *cr;
+};
+
+#endif /* LIBC3_WINDOW_CAIRO_TYPES_H */
diff --git a/libc3/window/cairo/window_cairo.h b/libc3/window/cairo/window_cairo.h
new file mode 100644
index 0000000..884ac61
--- /dev/null
+++ b/libc3/window/cairo/window_cairo.h
@@ -0,0 +1,25 @@
+/* c3
+ * Copyright 2022,2023 kmx.io <contact@kmx.io>
+ *
+ * Permission is hereby granted to use this software granted the above
+ * copyright notice and this permission paragraph are included in all
+ * copies and substantial portions of this software.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS-IS" WITHOUT ANY GUARANTEE OF
+ * PURPOSE AND PERFORMANCE. IN NO EVENT WHATSOEVER SHALL THE
+ * AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+#ifndef WINDOW_CAIRO_H
+#define WINDOW_CAIRO_H
+
+#include <libc3/types.h>
+#include <cairo/cairo.h>
+
+typedef bool (*f_window_cairo_render) (cairo_t *cr);
+
+bool window_cairo (sw x, sw y, sw w, sw h,
+ const s8 *title,
+ f_window_cairo_render render);
+
+#endif /* WINDOW_CAIRO_H */
diff --git a/libc3/window/cairo/xcb/Makefile b/libc3/window/cairo/xcb/Makefile
new file mode 100644
index 0000000..1a7b513
--- /dev/null
+++ b/libc3/window/cairo/xcb/Makefile
@@ -0,0 +1,52 @@
+## c3
+## Copyright 2022,2023 kmx.io <contact@kmx.io>
+##
+## Permission is hereby granted to use this software granted the above
+## copyright notice and this permission paragraph are included in all
+## copies and substantial portions of this software.
+##
+## THIS SOFTWARE IS PROVIDED "AS-IS" WITHOUT ANY GUARANTEE OF
+## PURPOSE AND PERFORMANCE. IN NO EVENT WHATSOEVER SHALL THE
+## AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
+## THIS SOFTWARE.
+
+CLEANFILES = *.a *.gcno *.la .libs *.lo *.o
+
+CLEANFILES_COV = *.css *.gcda *.html .libs/*.gcda
+
+CLEANFILES += ${CLEANFILES_COV}
+
+DISTCLEANFILES = ${CLEANFILES} config.h config.mk
+
+build: libc3_window_cairo_xcb.la
+
+all:
+ ${MAKE} build
+ if ${HAVE_GCOV}; then ${MAKE} cov; fi
+ ${MAKE} debug
+ if ${HAVE_ASAN}; then ${MAKE} asan; fi
+
+asan: libc3_window_cairo_xcb_asan.la
+
+clean:
+ rm -rf ${CLEANFILES}
+
+clean_cov:
+ rm -rf ${CLEANFILES_COV}
+
+cov: libc3_window_cairo_xcb_cov.la
+
+debug: libc3_window_cairo_xcb_debug.la
+
+distclean:
+ rm -rf ${DISTCLEANFILES}
+
+test:
+
+update_sources:
+ ./update_sources
+
+.PHONY: all asan build clean cov debug distclean gen install test update_sources
+
+include config.mk
+include sources.mk
diff --git a/libc3/window/cairo/xcb/configure b/libc3/window/cairo/xcb/configure
new file mode 100755
index 0000000..999181b
--- /dev/null
+++ b/libc3/window/cairo/xcb/configure
@@ -0,0 +1,133 @@
+#!/bin/sh
+## c3
+## Copyright 2022,2023 kmx.io <contact@kmx.io>
+##
+## Permission is hereby granted to use this software granted the above
+## copyright notice and this permission paragraph are included in all
+## copies and substantial portions of this software.
+##
+## THIS SOFTWARE IS PROVIDED "AS-IS" WITHOUT ANY GUARANTEE OF
+## PURPOSE AND PERFORMANCE. IN NO EVENT WHATSOEVER SHALL THE
+## AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
+## THIS SOFTWARE.
+
+set -e
+
+export SRC_TOP="$(dirname "$PWD")"
+
+. ../../../config.subr
+
+LIB=libc3_window_cairo_xcb.la
+LIB_ASAN=libc3_window_cairo_xcb_asan.la
+LIB_COV=libc3_window_cairo_xcb_cov.la
+LIB_DEBUG=libc3_window_cairo_xcb_debug.la
+
+. ./sources.sh
+
+OBJECTS="$(c2ext .main.lo "$SOURCES")"
+echo "OBJECTS = $OBJECTS" >> ${CONFIG_MK}
+OBJECTS_ASAN="$(c2ext .asan.lo "$SOURCES")"
+OBJECTS_COV="$(c2ext .cov.lo "$SOURCES")"
+OBJECTS_DEBUG="$(c2ext .debug.lo "$SOURCES")"
+
+# Default config
+CPPFLAGS="${CPPFLAGS:=}"
+ENV_CFLAGS="${CFLAGS:=}"
+DEFAULT_CFLAGS="-O2 -pipe"
+LDFLAGS="--shared -no-undefined ${LDFLAGS}"
+LIBS="${LIBS} -rpath ${PREFIX}/lib"
+
+# Common config for all targets
+CFLAGS="$CFLAGS -W -Wall -Werror -std=c99 -pedantic -fPIC"
+CPPFLAGS="$CPPFLAGS -I../../../libffi/include -I../../.."
+config_asan
+config_gnu
+pkg_config xcb
+pkg_config cairo
+config_define PREFIX "\"${PREFIX}\""
+update_config_h
+LIBS="$LIBS"
+
+# Address Sanitizer config
+CFLAGS_ASAN="$CFLAGS -O1 -fsanitize=address -fno-omit-frame-pointer -g"
+LDFLAGS_ASAN="$LDFLAGS"
+LIBS_ASAN="../../../libc3/libc3_asan.la $LIBS"
+
+# Coverage config
+CFLAGS_COV="$CFLAGS -ftest-coverage -fprofile-arcs -fprofile-generate"
+LDFLAGS_COV="$LDFLAGS --coverage"
+LIBS_COV="../../../libc3/libc3_cov.la $LIBS"
+
+# Debug config
+CFLAGS_DEBUG="$CFLAGS -DDEBUG -O0 -g"
+LDFLAGS_DEBUG="$LDFLAGS"
+LIBS_DEBUG="../../../libc3/libc3_debug.la $LIBS"
+
+# Main config
+if [ "x$ENV_CFLAGS" = "x" ]; then
+ CFLAGS="$CFLAGS $DEFAULT_CFLAGS"
+fi
+CFLAGS="$CFLAGS -DNDEBUG"
+LIBS="../../../libc3/libc3.la $LIBS"
+
+echo "LIB = $LIB" >> ${CONFIG_MK}
+echo "HAVE_ASAN = $HAVE_ASAN" >> ${CONFIG_MK}
+echo "CPPFLAGS = $CPPFLAGS" >> ${CONFIG_MK}
+echo "CFLAGS = $CFLAGS" >> ${CONFIG_MK}
+echo "LDFLAGS = $LDFLAGS" >> ${CONFIG_MK}
+echo "LIBS = $LIBS" >> ${CONFIG_MK}
+echo >> ${CONFIG_MK}
+echo "LIB_ASAN = $LIB_ASAN" >> ${CONFIG_MK}
+echo "CFLAGS_ASAN = $CFLAGS_ASAN" >> ${CONFIG_MK}
+echo "LDFLAGS_ASAN = $LDFLAGS_ASAN" >> ${CONFIG_MK}
+echo "LIBS_ASAN = $LIBS_ASAN" >> ${CONFIG_MK}
+echo >> ${CONFIG_MK}
+echo "LIB_COV = $LIB_COV" >> ${CONFIG_MK}
+echo "CFLAGS_COV = $CFLAGS_COV" >> ${CONFIG_MK}
+echo "LDFLAGS_COV = $LDFLAGS_COV" >> ${CONFIG_MK}
+echo "LIBS_COV = $LIBS_COV" >> ${CONFIG_MK}
+echo >> ${CONFIG_MK}
+echo "LIB_DEBUG = $LIB_DEBUG" >> ${CONFIG_MK}
+echo "CFLAGS_DEBUG = $CFLAGS_DEBUG" >> ${CONFIG_MK}
+echo "LDFLAGS_DEBUG = $LDFLAGS_DEBUG" >> ${CONFIG_MK}
+echo "LIBS_DEBUG = $LIBS_DEBUG" >> ${CONFIG_MK}
+
+echo >> ${CONFIG_MK}
+echo "$LIB: $LIBTOMMATH $OBJECTS" >> ${CONFIG_MK}
+echo " ${LIBTOOL} --tag=CC --mode=link \${CC} -shared \${LDFLAGS} ${OBJECTS} \${LIBS} -rpath ${LIBDIR} -o ${LIB}" >> ${CONFIG_MK}
+
+echo >> ${CONFIG_MK}
+echo "$LIB_ASAN: $LIBTOMMATH_ASAN $OBJECTS_ASAN" >> ${CONFIG_MK}
+echo " ${LIBTOOL} --tag=CC --mode=link \${CC} -shared \${LDFLAGS_ASAN} ${OBJECTS_ASAN} \${LIBS_ASAN} -rpath ${LIBDIR} -o ${LIB_ASAN}" >> ${CONFIG_MK}
+
+echo >> ${CONFIG_MK}
+echo "$LIB_COV: $LIBTOMMATH_COV $OBJECTS_COV" >> ${CONFIG_MK}
+echo " ${LIBTOOL} --tag=CC --mode=link \${CC} -shared \${LDFLAGS_COV} ${OBJECTS_COV} \${LIBS_COV} -rpath ${LIBDIR} -o ${LIB_COV}" >> ${CONFIG_MK}
+
+echo >> ${CONFIG_MK}
+echo "$LIB_DEBUG: $LIBTOMMATH_DEBUG $OBJECTS_DEBUG" >> ${CONFIG_MK}
+echo " ${LIBTOOL} --tag=CC --mode=link \${CC} -shared \${LDFLAGS_DEBUG} ${OBJECTS_DEBUG} \${LIBS_DEBUG} -rpath ${LIBDIR} -o ${LIB_DEBUG}" >> ${CONFIG_MK}
+
+for SRC in $SOURCES; do
+ echo >> ${CONFIG_MK}
+ SRC_LO="$(c2ext .main.lo "$SRC")"
+ ext_rule .main.lo "$SRC" >> ${CONFIG_MK}
+ echo " ${LIBTOOL} --tag=CC --mode=compile \${CC} \${CPPFLAGS} \${CFLAGS} -c $SRC -o $SRC_LO" >> ${CONFIG_MK}
+
+ echo >> ${CONFIG_MK}
+ SRC_ASAN_LO="$(c2ext .asan.lo "$SRC")"
+ ext_rule .asan.lo "$SRC" >> ${CONFIG_MK}
+ echo " ${LIBTOOL} --tag=CC --mode=compile \${CC} \${CPPFLAGS} \${CFLAGS_ASAN} -c $SRC -o $SRC_ASAN_LO" >> ${CONFIG_MK}
+
+ echo >> ${CONFIG_MK}
+ SRC_COV_LO="$(c2ext .cov.lo "$SRC")"
+ ext_rule .cov.lo "$SRC" >> ${CONFIG_MK}
+ echo " ${LIBTOOL} --tag=CC --mode=compile \${CC} \${CPPFLAGS} \${CFLAGS_COV} -c $SRC -o $SRC_COV_LO" >> ${CONFIG_MK}
+
+ echo >> ${CONFIG_MK}
+ SRC_DEBUG_LO="$(c2ext .debug.lo "$SRC")"
+ ext_rule .debug.lo "$SRC" >> ${CONFIG_MK}
+ echo " ${LIBTOOL} --tag=CC --mode=compile \${CC} \${CPPFLAGS} \${CFLAGS_DEBUG} -c $SRC -o $SRC_DEBUG_LO" >> ${CONFIG_MK}
+done
+
+update_config_mk
diff --git a/libc3/window/cairo/xcb/demo/Makefile b/libc3/window/cairo/xcb/demo/Makefile
new file mode 100644
index 0000000..36a3aad
--- /dev/null
+++ b/libc3/window/cairo/xcb/demo/Makefile
@@ -0,0 +1,56 @@
+## c3
+## Copyright 2022,2023 kmx.io <contact@kmx.io>
+##
+## Permission is hereby granted to use this software granted the above
+## copyright notice and this permission paragraph are included in all
+## copies and substantial portions of this software.
+##
+## THIS SOFTWARE IS PROVIDED "AS-IS" WITHOUT ANY GUARANTEE OF
+## PURPOSE AND PERFORMANCE. IN NO EVENT WHATSOEVER SHALL THE
+## AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
+## THIS SOFTWARE.
+
+CLEANFILES = *.a c3_window_cairo_xcb_demo c3_window_cairo_xcb_demo_asan c3_window_cairo_xcb_demo_cov c3_window_cairo_xcb_demo_debug *.css *.gcno *.html *.o .libs *.lo
+
+CLEANFILES_COV = *.css *.gcda *.html .libs/*.gcda
+CLEANFILES += ${CLEANFILES_COV}
+
+DISTCLEANFILES = ${CLEANFILES} config.mk
+
+build: c3_window_cairo_xcb_demo
+
+all:
+ ${MAKE} build
+ if ${HAVE_GCOV}; then ${MAKE} cov; fi
+ ${MAKE} debug
+ if ${HAVE_ASAN}; then ${MAKE} asan; fi
+
+asan: c3_window_cairo_xcb_demo_asan
+
+clean:
+ rm -rf ${CLEANFILES}
+
+clean_cov:
+ rm -rf ${CLEANFILES_COV}
+
+cov: c3_window_cairo_xcb_demo_cov
+
+debug: c3_window_cairo_xcb_demo_debug
+
+distclean:
+ rm -rf ${DISTCLEANFILES}
+
+gcovr:
+ gcovr --gcov-executable ${GCOV} --html-details c3_window_cairo_xcb_demo.html
+
+gdb_c3_window_cairo_xcb_demo: debug
+ if [ -f c3_window_cairo_xcb_demo_debug.core ]; then gdb .libs/c3_window_cairo_xcb_demo_debug c3_window_cairo_xcb_demo_debug.core; else gdb .libs/c3_window_cairo_xcb_demo_debug; fi
+
+install:
+ mkdir -p ${prefix}/bin
+ install -m 755 c3_window_cairo_xcb_demo ${prefix}/bin/c3_window_cairo_xcb_demo
+
+.PHONY: all asan cov debug clean clean_cov distclean
+
+include config.mk
+include sources.mk
diff --git a/libc3/window/cairo/xcb/demo/c3_window_cairo_xcb_demo.c b/libc3/window/cairo/xcb/demo/c3_window_cairo_xcb_demo.c
new file mode 100644
index 0000000..fe9cf8f
--- /dev/null
+++ b/libc3/window/cairo/xcb/demo/c3_window_cairo_xcb_demo.c
@@ -0,0 +1,27 @@
+/* c3
+ * Copyright 2022,2023 kmx.io <contact@kmx.io>
+ *
+ * Permission is hereby granted to use this software granted the above
+ * copyright notice and this permission paragraph are included in all
+ * copies and substantial portions of this software.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS-IS" WITHOUT ANY GUARANTEE OF
+ * PURPOSE AND PERFORMANCE. IN NO EVENT WHATSOEVER SHALL THE
+ * AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <cairo/cairo.h>
+#include <libc3/c3.h>
+#include "../../c3_window_cairo_demo.h"
+#include "../window_cairo_xcb.h"
+
+int main ()
+{
+ if (! window_cairo_xcb(0, 0, 800, 600,
+ "C3.Window.Cairo.XCB demo",
+ c3_window_cairo_demo_render))
+ return 1;
+ return 0;
+}
diff --git a/libc3/window/cairo/xcb/demo/configure b/libc3/window/cairo/xcb/demo/configure
new file mode 100755
index 0000000..eadc0fd
--- /dev/null
+++ b/libc3/window/cairo/xcb/demo/configure
@@ -0,0 +1,143 @@
+#!/bin/sh
+## c3
+## Copyright 2022,2023 kmx.io <contact@kmx.io>
+##
+## Permission is hereby granted to use this software granted the above
+## copyright notice and this permission paragraph are included in all
+## copies and substantial portions of this software.
+##
+## THIS SOFTWARE IS PROVIDED "AS-IS" WITHOUT ANY GUARANTEE OF
+## PURPOSE AND PERFORMANCE. IN NO EVENT WHATSOEVER SHALL THE
+## AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
+## THIS SOFTWARE.
+
+set -e
+
+export SRC_TOP="$(dirname "$PWD")"
+
+. ../../../../config.subr
+
+PROG=c3_window_cairo_xcb_demo
+PROG_ASAN=c3_window_cairo_xcb_demo_asan
+PROG_COV=c3_window_cairo_xcb_demo_cov
+PROG_DEBUG=c3_window_cairo_xcb_demo_debug
+
+. ./sources.sh
+
+OBJECTS="$(c2lo "$SOURCES")"
+echo "OBJECTS = $OBJECTS" >> ${CONFIG_MK}
+
+OBJECTS_ASAN="$(c2ext .asan.lo "$SOURCES")"
+echo "OBJECTS_ASAN = $OBJECTS_ASAN" >> ${CONFIG_MK}
+
+if $HAVE_GCOV; then
+ OBJECTS_COV="$(c2ext .cov.lo "$SOURCES")"
+ echo "OBJECTS_COV = $OBJECTS_COV" >> ${CONFIG_MK}
+fi
+
+OBJECTS_DEBUG="$(c2ext .debug.lo "$SOURCES")"
+echo "OBJECTS_DEBUG = $OBJECTS_DEBUG" >> ${CONFIG_MK}
+
+# Default config
+CPPFLAGS="${CPPFLAGS:-}"
+ENV_CFLAGS="${CFLAGS:-}"
+DEFAULT_CFLAGS="-O2 -pipe -fPIC"
+LDFLAGS="${LDFLAGS:-}"
+LIBS="${LIBS:-}"
+
+# Common config for all targets
+CFLAGS="$CFLAGS -W -Wall -Werror -std=c99 -pedantic"
+CPPFLAGS="$CPPFLAGS -I../../../../libffi/include -I../../../.."
+config_asan
+config_gnu
+pkg_config xcb
+LIBS="$LIBS"
+
+# Asan config
+CFLAGS_ASAN="$CFLAGS -fsanitize=address -O1 -fno-omit-frame-pointer -g"
+LDFLAGS_ASAN="$LDFLAGS"
+LOCAL_LIBS_ASAN="../libc3_window_cairo_xcb_asan.la"
+LIBS_ASAN="$LOCAL_LIBS_ASAN $LIBS"
+
+# Coverage config
+CFLAGS_COV="$CFLAGS -ftest-coverage -fprofile-arcs -fprofile-generate"
+LDFLAGS_COV="$LDFLAGS --coverage"
+LOCAL_LIBS_COV="../libc3_window_cairo_xcb_cov.la"
+LIBS_COV="$LOCAL_LIBS_COV $LIBS"
+
+# Debug config
+CFLAGS_DEBUG="$CFLAGS -DDEBUG -O0 -g"
+LDFLAGS_DEBUG="$LDFLAGS"
+LOCAL_LIBS_DEBUG="../libc3_window_cairo_xcb_debug.la"
+LIBS_DEBUG="$LOCAL_LIBS_DEBUG $LIBS"
+
+# Main config
+if [ "x$ENV_CFLAGS" = "x" ]; then
+ CFLAGS="$CFLAGS $DEFAULT_CFLAGS"
+fi
+CFLAGS="$CFLAGS -DNDEBUG"
+LIBC3=../libc3/libc3.la
+LOCAL_LIBS="../libc3_window_cairo_xcb.la"
+LIBS="$LOCAL_LIBS $LIBS"
+
+echo "HAVE_ASAN = $HAVE_ASAN" >> ${CONFIG_MK}
+echo "CPPFLAGS = $CPPFLAGS" >> ${CONFIG_MK}
+echo "CFLAGS = $CFLAGS" >> ${CONFIG_MK}
+echo "LDFLAGS = $LDFLAGS" >> ${CONFIG_MK}
+echo "LIBS = $LIBS" >> ${CONFIG_MK}
+echo >> ${CONFIG_MK}
+echo "CFLAGS_ASAN = $CFLAGS_ASAN" >> ${CONFIG_MK}
+echo "LDFLAGS_ASAN = $LDFLAGS_ASAN" >> ${CONFIG_MK}
+echo "LIBS_ASAN = $LIBS_ASAN" >> ${CONFIG_MK}
+echo >> ${CONFIG_MK}
+echo "CFLAGS_COV = $CFLAGS_COV" >> ${CONFIG_MK}
+echo "LDFLAGS_COV = $LDFLAGS_COV" >> ${CONFIG_MK}
+echo "LIBS_COV = $LIBS_COV" >> ${CONFIG_MK}
+echo >> ${CONFIG_MK}
+echo "CFLAGS_DEBUG = $CFLAGS_DEBUG" >> ${CONFIG_MK}
+echo "LDFLAGS_DEBUG = $LDFLAGS_DEBUG" >> ${CONFIG_MK}
+echo "LIBS_DEBUG = $LIBS_DEBUG" >> ${CONFIG_MK}
+
+echo >> ${CONFIG_MK}
+echo "$PROG: $LOCAL_LIBS $OBJECTS" >> ${CONFIG_MK}
+echo " ${LIBTOOL} --tag=CC --mode=link \${CC} \${CFLAGS} \${LDFLAGS} ${OBJECTS} ${LIBS} -o $PROG" >> ${CONFIG_MK}
+
+echo >> ${CONFIG_MK}
+echo "$PROG_ASAN: $LOCAL_LIBS_ASAN $OBJECTS_ASAN" >> ${CONFIG_MK}
+echo " ${LIBTOOL} --tag=CC --mode=link \${CC} \${CFLAGS_ASAN} \${LDFLAGS_ASAN} ${OBJECTS_ASAN} ${LIBS_ASAN} -o $PROG_ASAN" >> ${CONFIG_MK}
+
+if $HAVE_GCOV; then
+ echo >> ${CONFIG_MK}
+ echo "$PROG_COV: $LOCAL_LIBS_COV $OBJECTS_COV" >> ${CONFIG_MK}
+ echo " ${LIBTOOL} --tag=CC --mode=link \${CC} \${CFLAGS_COV} \${LDFLAGS_COV} ${OBJECTS_COV} ${LIBS_COV} -o $PROG_COV" >> ${CONFIG_MK}
+fi
+
+echo >> ${CONFIG_MK}
+echo "$PROG_DEBUG: $LOCAL_LIBS_DEBUG $OBJECTS_DEBUG" >> ${CONFIG_MK}
+echo " ${LIBTOOL} --tag=CC --mode=link \${CC} \${CFLAGS_DEBUG} \${LDFLAGS_DEBUG} ${OBJECTS_DEBUG} ${LIBS_DEBUG} -o $PROG_DEBUG" >> ${CONFIG_MK}
+
+for SRC in $SOURCES; do
+ echo >> ${CONFIG_MK}
+ SRC_LO="$(c2lo "$SRC")"
+ lo_rule "$SRC" >> ${CONFIG_MK}
+ echo " ${LIBTOOL} --tag=CC --mode=compile \${CC} \${CPPFLAGS} \${CFLAGS} -c $SRC -o $SRC_LO" >> ${CONFIG_MK}
+
+ echo >> ${CONFIG_MK}
+ SRC_ASAN_LO="$(c2ext .asan.lo "$SRC")"
+ ext_rule .asan.lo "$SRC" >> ${CONFIG_MK}
+ echo " ${LIBTOOL} --tag=CC --mode=compile \${CC} \${CPPFLAGS} \${CFLAGS_ASAN} -c $SRC -o $SRC_ASAN_LO" >> ${CONFIG_MK}
+
+ if $HAVE_GCOV; then
+ echo >> ${CONFIG_MK}
+ SRC_COV_LO="$(c2ext .cov.lo "$SRC")"
+ ext_rule .cov.lo "$SRC" >> ${CONFIG_MK}
+ echo " ${LIBTOOL} --tag=CC --mode=compile \${CC} \${CPPFLAGS} \${CFLAGS_COV} -c $SRC -o $SRC_COV_LO" >> ${CONFIG_MK}
+ fi
+
+ echo >> ${CONFIG_MK}
+ SRC_DEBUG_LO="$(c2ext .debug.lo "$SRC")"
+ ext_rule .debug.lo "$SRC" >> ${CONFIG_MK}
+ echo " ${LIBTOOL} --tag=CC --mode=compile \${CC} \${CPPFLAGS} \${CFLAGS_DEBUG} -c $SRC -o $SRC_DEBUG_LO" >> ${CONFIG_MK}
+done
+
+update_config_mk
diff --git a/libc3/window/cairo/xcb/demo/sources.mk b/libc3/window/cairo/xcb/demo/sources.mk
new file mode 100644
index 0000000..6de0913
--- /dev/null
+++ b/libc3/window/cairo/xcb/demo/sources.mk
@@ -0,0 +1,7 @@
+# sources.mk generated by update_sources
+HEADERS = \
+ ../../c3_window_cairo_demo.h \
+
+SOURCES = \
+ c3_window_cairo_xcb_demo.c ../../c3_window_cairo_demo.c \
+
diff --git a/libc3/window/cairo/xcb/demo/sources.sh b/libc3/window/cairo/xcb/demo/sources.sh
new file mode 100644
index 0000000..63623c7
--- /dev/null
+++ b/libc3/window/cairo/xcb/demo/sources.sh
@@ -0,0 +1,3 @@
+# sources.sh generated by update_sources
+HEADERS=' ../../c3_window_cairo_demo.h '
+SOURCES='c3_window_cairo_xcb_demo.c ../../c3_window_cairo_demo.c '
diff --git a/libc3/window/cairo/xcb/demo/update_sources b/libc3/window/cairo/xcb/demo/update_sources
new file mode 100755
index 0000000..40521c4
--- /dev/null
+++ b/libc3/window/cairo/xcb/demo/update_sources
@@ -0,0 +1,26 @@
+#!/bin/sh
+## c3
+## Copyright 2022,2023 kmx.io <contact@kmx.io>
+##
+## Permission is hereby granted to use this software granted the above
+## copyright notice and this permission paragraph are included in all
+## copies and substantial portions of this software.
+##
+## THIS SOFTWARE IS PROVIDED "AS-IS" WITHOUT ANY GUARANTEE OF
+## PURPOSE AND PERFORMANCE. IN NO EVENT WHATSOEVER SHALL THE
+## AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
+## THIS SOFTWARE.
+
+. ../../../../config.subr
+
+echo "# sources.mk generated by update_sources" > ${SOURCES_MK}
+echo "# sources.sh generated by update_sources" > ${SOURCES_SH}
+
+HEADERS="$(ls *.h | sort) ../../c3_window_cairo_demo.h"
+sources HEADERS "$HEADERS"
+
+SOURCES="$(ls *.c | sort) ../../c3_window_cairo_demo.c"
+sources SOURCES "$SOURCES"
+
+update_sources_mk
+update_sources_sh
diff --git a/libc3/window/cairo/xcb/sources.mk b/libc3/window/cairo/xcb/sources.mk
new file mode 100644
index 0000000..5a5f114
--- /dev/null
+++ b/libc3/window/cairo/xcb/sources.mk
@@ -0,0 +1,8 @@
+# sources.mk generated by update_sources
+HEADERS = \
+ config.h \
+ window_cairo_xcb.h ../window_cairo.h \
+
+SOURCES = \
+ window_cairo_xcb.c \
+
diff --git a/libc3/window/cairo/xcb/sources.sh b/libc3/window/cairo/xcb/sources.sh
new file mode 100644
index 0000000..82c629f
--- /dev/null
+++ b/libc3/window/cairo/xcb/sources.sh
@@ -0,0 +1,3 @@
+# sources.sh generated by update_sources
+HEADERS='config.h window_cairo_xcb.h ../window_cairo.h '
+SOURCES='window_cairo_xcb.c '
diff --git a/libc3/window/cairo/xcb/update_sources b/libc3/window/cairo/xcb/update_sources
new file mode 100755
index 0000000..e2e45b4
--- /dev/null
+++ b/libc3/window/cairo/xcb/update_sources
@@ -0,0 +1,26 @@
+#!/bin/sh
+## c3
+## Copyright 2022,2023 kmx.io <contact@kmx.io>
+##
+## Permission is hereby granted to use this software granted the above
+## copyright notice and this permission paragraph are included in all
+## copies and substantial portions of this software.
+##
+## THIS SOFTWARE IS PROVIDED "AS-IS" WITHOUT ANY GUARANTEE OF
+## PURPOSE AND PERFORMANCE. IN NO EVENT WHATSOEVER SHALL THE
+## AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
+## THIS SOFTWARE.
+
+. ../../../config.subr
+
+echo "# sources.mk generated by update_sources" > ${SOURCES_MK}
+echo "# sources.sh generated by update_sources" > ${SOURCES_SH}
+
+HEADERS="$(ls *.h | sort) ../window_cairo.h"
+sources HEADERS "$HEADERS"
+
+SOURCES="$(ls *.c | sort)"
+sources SOURCES "$SOURCES"
+
+update_sources_mk
+update_sources_sh
diff --git a/libc3/window/cairo/xcb/window_cairo_xcb.c b/libc3/window/cairo/xcb/window_cairo_xcb.c
new file mode 100644
index 0000000..c395bf2
--- /dev/null
+++ b/libc3/window/cairo/xcb/window_cairo_xcb.c
@@ -0,0 +1,89 @@
+/* c3
+ * Copyright 2022,2023 kmx.io <contact@kmx.io>
+ *
+ * Permission is hereby granted to use this software granted the above
+ * copyright notice and this permission paragraph are included in all
+ * copies and substantial portions of this software.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS-IS" WITHOUT ANY GUARANTEE OF
+ * PURPOSE AND PERFORMANCE. IN NO EVENT WHATSOEVER SHALL THE
+ * AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <cairo/cairo-xcb.h>
+#include <libc3/c3.h>
+#include <xcb/xcb.h>
+#include "window_cairo_xcb.h"
+
+bool window_cairo (sw x, sw y, sw w, sw h,
+ const s8 *title,
+ f_window_cairo_render render
+ f_window_cairo_resize resize)
+{
+ return window_cairo_xcb(x, y, w, h, title, render, resize);
+}
+
+bool window_cairo_xcb (sw x, sw y, sw w, sw h,
+ const s8 *title,
+ f_window_cairo_render render,
+ f_window_cairo_resize resize)
+{
+ xcb_connection_t *conn;
+ cairo_t *cr;
+ xcb_screen_t *screen;
+ xcb_visualtype_t *screen_visual;
+ cairo_surface_t *surface;
+ xcb_window_t window;
+ xcb_generic_event_t *event;
+ conn = xcb_connect(NULL, NULL);
+ if (xcb_connection_has_error(conn)) {
+ fprintf(stderr, "Error opening display.\n");
+ exit(1);
+ }
+ screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data;
+ screen_visual = xcb_screen_visual_type(screen);
+ window = xcb_generate_id(conn);
+ xcb_create_window(conn, XCB_COPY_FROM_PARENT, window, screen->root, x, y, w, h, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual, 0, NULL);
+ xcb_change_property(conn, XCB_PROP_MODE_REPLACE, window, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8, 12, title);
+ xcb_map_window(conn, window);
+ xcb_flush(conn);
+ surface = cairo_xcb_surface_create(conn, window, screen_visual, 800, 600);
+ cr = cairo_create(surface);
+ if (render(cr)) {
+ cairo_surface_flush(surface);
+ xcb_flush(conn);
+ while ((event = xcb_wait_for_event(conn))) {
+ if ((event->response_type & ~0x80) == XCB_EXPOSE) {
+ if (! render(cr))
+ break;
+ cairo_surface_flush(surface);
+ xcb_flush(conn);
+ }
+ free(event);
+ }
+ }
+ cairo_destroy(cr);
+ cairo_surface_destroy(surface);
+ xcb_disconnect(conn);
+ return 0;
+}
+
+xcb_visualtype_t * xcb_screen_visual_type (xcb_screen_t *screen)
+{
+ xcb_depth_iterator_t depth_iter;
+ xcb_visualtype_iterator_t visual_iter;
+ depth_iter = xcb_screen_allowed_depths_iterator(screen);
+ while (depth_iter.rem) {
+ visual_iter = xcb_depth_visuals_iterator(depth_iter.data);
+ while (visual_iter.rem) {
+ if (screen->root_visual == visual_iter.data->visual_id) {
+ return visual_iter.data;
+ }
+ xcb_visualtype_next(&visual_iter);
+ }
+ xcb_depth_next(&depth_iter);
+ }
+ return NULL;
+}
diff --git a/libc3/window/cairo/xcb/window_cairo_xcb.h b/libc3/window/cairo/xcb/window_cairo_xcb.h
new file mode 100644
index 0000000..ce601dc
--- /dev/null
+++ b/libc3/window/cairo/xcb/window_cairo_xcb.h
@@ -0,0 +1,26 @@
+/* c3
+ * Copyright 2022,2023 kmx.io <contact@kmx.io>
+ *
+ * Permission is hereby granted to use this software granted the above
+ * copyright notice and this permission paragraph are included in all
+ * copies and substantial portions of this software.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS-IS" WITHOUT ANY GUARANTEE OF
+ * PURPOSE AND PERFORMANCE. IN NO EVENT WHATSOEVER SHALL THE
+ * AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+#ifndef WINDOW_CAIRO_XCB_H
+#define WINDOW_CAIRO_XCB_H
+
+#include <libc3/types.h>
+#include <xcb/xcb.h>
+#include "../window_cairo.h"
+
+bool window_cairo_xcb (sw x, sw y, sw w, sw h,
+ const s8 *title,
+ f_window_cairo_render render);
+
+xcb_visualtype_t * xcb_screen_visual_type (xcb_screen_t *screen);
+
+#endif /* ndef WINDOW_CAIRO_XCB_H */
diff --git a/libc3/window/types.h b/libc3/window/types.h
new file mode 100644
index 0000000..3644829
--- /dev/null
+++ b/libc3/window/types.h
@@ -0,0 +1,43 @@
+/* c3
+ * Copyright 2022,2023 kmx.io <contact@kmx.io>
+ *
+ * Permission is hereby granted to use this software granted the above
+ * copyright notice and this permission paragraph are included in all
+ * copies and substantial portions of this software.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS-IS" WITHOUT ANY GUARANTEE OF
+ * PURPOSE AND PERFORMANCE. IN NO EVENT WHATSOEVER SHALL THE
+ * AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+/** @file types.h
+ * @brief Module C3.Window
+ *
+ * Base struct for all GUI window operations.
+ */
+#ifndef LIBC3_WINDOW_TYPES_H
+#define LIBC3_WINDOW_TYPES_H
+
+#include <libc3/types.h>
+
+typedef struct window s_window;
+
+/* return false to break event loop */
+typedef bool (*f_window_render) (s_window *window,
+ void *render_context);
+
+/* return false to break event loop */
+typedef bool (*f_window_resize) (s_window *window,
+ uw w, uw h);
+
+struct window {
+ sw x;
+ sw y;
+ uw w;
+ uw h;
+ f_window_render render;
+ f_window_resize resize;
+ void *render_context;
+};
+
+#endif /* LIBC3_WINDOW_TYPES_H */