Commit Diff


commit - /dev/null
commit + ad1030b41065a5fd42324100b9689f43a9a84b15
blob - /dev/null
blob + 20d4bcef726a4cbf96ffbb605738e9ba4a899377 (mode 644)
--- /dev/null
+++ LICENSE
@@ -0,0 +1,13 @@
+Copyright (c) 2026 Onana Onana Xavier Manuel <xavier@onana.net>
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED AS IS AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, 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.
blob - /dev/null
blob + 526401143b87409307e1d991f80cabac3e6b3de6 (mode 644)
--- /dev/null
+++ Makefile
@@ -0,0 +1,38 @@
+CC=			cc
+LIB=		libaui
+PREFIX=		/usr/local
+
+SRCS=		button.c \
+			canvas.c \
+			driver.c \
+			frame.c \
+			font.c \
+			label.c \
+			layout.c \
+			ui.c \
+			xcb.c \
+			widget.c \
+			window.c
+CFLAGS=		-fPIC -O0 -std=c99 -Werror
+OBJS=		${SRCS:.c=.o}
+INCS=		-I /usr/X11R6/include -I /usr/X11R6/include/freetype2
+HDR=		aui.h
+LDADD=		-L /usr/X11R6/lib -lxcb -lxcb-render -lfontconfig -lfreetype
+
+
+all: ${LIB}
+
+
+${LIB}: ${OBJS}
+	${INSTALL} -m 755 ${HDR} ${PREFIX}/include
+	${CC} ${OBJS} -shared -o ${PREFIX}/lib/${LIB}.so ${LDADD}
+	ar rc ${PREFIX}/lib/${LIB}.a ${OBJS}
+
+.c.o:
+	${CC} -c -fPIC $< -o $@ ${INCS} ${CFLAGS}
+
+clean:
+	rm -rf ${PREFIX}/lib/${LIB}.so ${PREFIX}/include/${HDR} ${PREFIX}/lib/${LIB}.a ${OBJS}
+	make -C examples clean
+
+.PHONY: examples
blob - /dev/null
blob + 0106a7c1cc9ef90a3965a6743bf1fa20259b7b28 (mode 644)
--- /dev/null
+++ README
@@ -0,0 +1,6 @@
+libaui - A User Interface Library
+
+Minimal, portable and simple. This library is inspired by Tk.
+The goal of this library is not to be competing with popular
+UI toolkits but rather offer a simple codebase that can be
+used for studying.
blob - /dev/null
blob + 23726f477429dbcce18c8e990451b9de4f169f21 (mode 644)
--- /dev/null
+++ aui.h
@@ -0,0 +1,165 @@
+#ifndef __AUI_H__
+#define __AUI_H__
+
+#define AUI_WIDGET(widget) ((struct aui_widget *) widget)
+
+struct aui_color {
+	unsigned char red;
+	unsigned char green;
+	unsigned char blue;
+	unsigned char alpha;
+};
+
+struct aui_placepar {
+	int x, y;
+	float relx;
+	float rely;
+	unsigned int width;
+	unsigned int height;
+	float relwidth;
+	float relheight;
+#define AUI_ANCHOR_NW	   	0
+#define AUI_ANCHOR_N		1
+#define AUI_ANCHOR_E		2
+#define AUI_ANCHOR_SE	   	3
+#define AUI_ANCHOR_S		4
+#define AUI_ANCHOR_SW	   	5
+#define AUI_ANCHOR_W		6
+#define AUI_ANCHOR_NE	   	7
+#define AUI_ANCHOR_CENTER   8
+	unsigned char anchor;
+};
+
+struct aui_packpar {
+	unsigned char anchor;
+#define AUI_FILL_NONE   0
+#define AUI_FILL_X	  	1
+#define AUI_FILL_Y	  	2
+#define AUI_FILL_BOTH   3
+	unsigned char fill;
+#define AUI_SIDE_TOP		0
+#define AUI_SIDE_RIGHT	  	1
+#define AUI_SIDE_LEFT	   	2
+#define AUI_SIDE_BOTTOM	 	3
+	unsigned char side;
+	unsigned char expand;
+};
+
+struct aui_gridpar {
+	unsigned int column;
+	unsigned int row;
+	unsigned int columnspan;
+	unsigned int rowspan;
+	unsigned int ipadx; /* Internal padding X */
+	unsigned int ipady; /* Internal padding Y */
+	unsigned int padx;
+	unsigned int pady;
+};
+
+struct aui_rowpar {
+	unsigned int minsize;
+	unsigned char weight; /*  Minimum is 1 */
+	unsigned char uniform;
+	unsigned int pad;
+};
+
+struct aui_columnpar {
+	unsigned int minsize;
+	unsigned char weight; /*  Minimum is 1 */
+	unsigned char uniform;
+	unsigned int pad;
+};
+
+struct aui_widget;
+struct aui_window;
+struct aui_frame;
+struct aui_canvas;	  /* rendering free of rules */
+struct aui_button;
+struct aui_label;
+
+struct aui_window_config {
+	unsigned int width;
+	unsigned int height;
+	const char *title; /* Not allocated by libaui */
+};
+
+struct aui_button_config {
+	struct aui_color foreground;
+	const char *text; /* Not allocated by libaui */
+	void (*command) (struct aui_button *, void *args);
+	void *args;
+};
+
+struct aui_frame_config {
+	struct aui_color background;
+};
+
+struct aui_canvas_config {
+	struct aui_color background;
+};
+
+struct aui_label_config {
+	char *text;
+	struct aui_color foreground;
+	struct aui_color bg;
+};
+
+void aui_run(void);
+void aui_destroy(struct aui_widget *);
+struct aui_window *aui_window_new(struct aui_window_config *);
+struct aui_button *aui_button_new(struct aui_widget *, struct aui_button_config *);
+int aui_button_config(struct aui_widget *, struct aui_button_config *);
+struct aui_frame *aui_frame_new(struct aui_widget *, struct aui_frame_config *);
+int aui_frame_config(struct aui_widget *, struct aui_frame_config *);
+struct aui_canvas *aui_canvas_new(struct aui_widget *, struct aui_canvas_config *);
+int aui_canvas_config(struct aui_widget *, struct aui_canvas_config *);
+struct aui_label *aui_label_new(struct aui_widget *, struct aui_label_config *);
+int aui_label_config(struct aui_widget *, struct aui_label_config *);
+int aui_place(struct aui_widget *, struct aui_placepar *);
+int aui_pack(struct aui_widget *, struct aui_packpar *);
+int aui_grid(struct aui_widget *, struct aui_gridpar *);
+int aui_getplacepar(struct aui_widget *, struct aui_placepar *);
+int aui_getgridpar(struct aui_widget *, struct aui_gridpar *);
+int aui_getpackpar(struct aui_widget *, struct aui_packpar *);
+
+/*
+ * Grid container operations
+ */
+int aui_rowconfigure(struct aui_widget *, struct aui_rowpar *);
+int aui_columnconfigure(struct aui_widget *, struct aui_columnpar *);
+
+#define AUI_CANVAS_RECTANGLE		0
+#define AUI_CANVAS_ARC				1
+#define AUI_CANVAS_IMAGE			2
+#define AUI_CANVAS_BITMAP			3
+#define AUI_CANVAS_OVAL				4
+#define AUI_CANVAS_POLYGON			5
+#define AUI_CANVAS_LINE				6
+#define AUI_CANVAS_TEXT				7
+#define AUI_CANVAS_WINDOW			8
+
+struct aui_canvas_item;
+
+struct aui_canvas_line {
+	int x1, y1;
+	int x2, y2;
+};
+
+struct aui_canvas_rectangle {
+	int x, y;
+	struct aui_color color;
+	unsigned int width, height;
+};
+
+struct aui_canvas_item_config {
+	union {
+		struct aui_canvas_line line;
+		struct aui_canvas_rectangle rectangle;
+	};
+};
+
+struct aui_canvas_item *aui_canvas_create(struct aui_canvas *, unsigned char,
+	struct aui_canvas_item_config *);
+void aui_canvas_delete(struct aui_canvas *, struct aui_canvas_item *);
+
+#endif
blob - /dev/null
blob + 27247026aac62a520238719eea0fa73522bf1522 (mode 644)
--- /dev/null
+++ aui_run.3
@@ -0,0 +1,109 @@
+.Dd $Mdocdate: July 14 2026$
+.Dt AUI_RUN 3
+.Os
+.Sh NAME
+.Nm aui_run ,
+.Nm aui_destroy ,
+.Nm aui_window_new ,
+.Nm aui_button_new ,
+.Nm aui_button_config ,
+.Nm aui_frame_new ,
+.Nm aui_frame_config ,
+.Nm aui_label_new ,
+.Nm aui_label_config ,
+.Nm aui_canvas_new ,
+.Nm aui_canvas_config ,
+.Nm aui_place ,
+.Nm aui_pack ,
+.Nm aui_grid ,
+.Nm aui_getplacepar ,
+.Nm aui_getgridpar ,
+.Nm aui_getpackpar
+.Sh SYNOPSIS
+.In aui.h
+.Ft void
+.Fn aui_run "void"
+.Ft void
+.Fn aui_destroy "struct aui_widget *"
+.Ft struct aui_window*
+.Fn aui_window_new "struct aui_window_config * config"
+.Ft struct aui_button*
+.Fn aui_button_new "struct aui_widget * parent" "struct aui_button_config * config"
+.Ft int
+.Fn aui_button_config "struct aui_widget * widget" "struct aui_button_config * config"
+.Ft struct aui_label*
+.Fn aui_label_new "struct aui_widget * parent" "struct aui_label_config * config"
+.Ft int
+.Fn aui_label_config "struct aui_widget * widget" "struct aui_label_config * config"
+.Ft struct aui_frame*
+.Fn aui_frame_new "struct aui_widget * parent" "struct aui_frame_config * config"
+.Ft int
+.Fn aui_frame_config "struct aui_widget * widget" "struct aui_frame_config * config"
+.Ft struct aui_canvas*
+.Fn aui_canvas_new "struct aui_widget * widget" "struct aui_canvas_config * config"
+.Ft int
+.Fn aui_canvas_config "struct aui_widget * parent" "struct aui_canvas_config * config"
+.Ft int
+.Fn aui_place "struct aui_widget * widget" "struct aui_placepar * par"
+.Ft int
+.Fn aui_grid "struct aui_widget * widget" "struct aui_gridpar * par"
+.Ft int
+.Fn aui_pack "struct aui_widget * widget" "struct aui_packpar * par"
+.Ft int
+.Fn aui_getplacepar "struct aui_widget * widget"
+.Ft int
+.Fn aui_getgridpar "struct aui_widget * widget"
+.Ft int
+.Fn aui_getpackpar "struct aui_widget * widget"
+.Sh DESCRIPTION
+Assides for windows, every widget must take a container in order to be
+created. The containers can be a window or a frame. Once a widget is
+created it can be mapped using place, grid or pack.
+.Pp
+Canvases are also containers although they cannot take widgets as childrens.
+.Sh EXAMPLES
+Creating a basic window is done with the following.
+.Bd -literal -offset indent
+struct aui_window *aw = aui_window_new(NULL);
+.Ed
+.Pp
+Afterwards the mainloop can be started using:
+.Bd -literal -offset indent
+aui_run();
+.Ed
+.Pp
+As for buttons they can be created using the following:
+.Bd -literal -offset indent
+struct aui_button *btn = aui_button_new(AUI_WIDGET(aw));
+.Ed
+.Pp
+The AUI_WIDGET macro must be used in order to pass widgets so the
+.Nm aui
+library can understand. In the example above aw can be switched for a
+container like frame. Here is an example.
+.Pp
+.Bd -literal -offset indent
+struct aui_frame *frame = aui_frame_new(AUI_WIDGET(aw), NULL);
+struct aui_button *btn = aui_button_new(AUI_WIDGET(frame), NULL);
+.Ed
+.Pp
+Adding widgets to containers does not make them directly visible. You must
+first pack, place or grid them for them to be mapped.
+.Pp
+.Bd -literal -offset indent
+aui_pack(AUI_WIDGET(btn), NULL);
+.Ed
+.Pp
+It is important to keep in mind that operations for 
+.Nm aui 
+must be done before
+.Nm aui_run 
+in a single threaded program.
+.Sh RETURN VALUES
+For all these function, if the output is -1 or NULL it means an error. Otherwise,
+the function was successful.
+.Sh AUTHORS
+The
+.Nm aui
+library was written by
+.An Onana Onana Xavier Manuel .
blob - /dev/null
blob + 36661b64d6d1cac811398d1ce8ebc2207b00cdc3 (mode 644)
--- /dev/null
+++ button.c
@@ -0,0 +1,148 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "driver.h"
+#include "widget.h"
+
+static void button_mouse_hover(struct aui_widget *, uint16_t, uint16_t);
+static void button_mouse_unhover(struct aui_widget *);
+static void button_mouse_press(struct aui_widget *, uint16_t, uint16_t, uint8_t);
+static void button_mouse_release(struct aui_widget *, uint16_t, uint16_t, uint8_t);
+static void button_set_geometry(struct aui_widget *, struct aui_geometry *);
+static void button_free(struct aui_widget *);
+static struct aui_geometry button_get_min_size(struct aui_widget *);
+
+static struct widget_ops button_ops = {
+	button_mouse_hover,
+	button_mouse_unhover,
+	button_mouse_press,
+	button_mouse_release,
+	button_set_geometry, /* set geometry */
+	button_free,
+	button_get_min_size,
+};
+
+struct aui_color color[] = {
+	{ 0xff, 0, 0, 0xff },	   /* Borders */
+	{ 0, 0, 0, 0xff },		  /* Normal */
+	{ 0x1b, 0x1b, 0x1b, 0xff }, /* Hover */
+	{ 0x3b, 0x3b, 0x3b, 0xff }, /* Press */
+};
+
+static struct aui_button_config default_config = {
+	.text = NULL,
+	.foreground = { 0xff, 0, 0, 0xff }
+};
+
+struct aui_button*
+aui_button_new(struct aui_widget *parent, struct aui_button_config *config)
+{
+	struct aui_button *button = calloc(1, sizeof(struct aui_button));
+	struct aui_widget *widget = &button->widget;
+	widget_init(&button->widget, WIDGET_TYPE_BUTTON, &button_ops);
+
+	/*
+	 * Creating the rectangle primitive
+	 */
+	widget_add(parent, widget);
+	button->config = (config == NULL) ? default_config : *config;
+
+	widget->primitives.count = 3;
+	widget->primitives.list = calloc(widget->primitives.count, sizeof(struct primitive*));
+	widget->primitives.list[0] = driver->ops->create_rectangle();
+	widget->primitives.list[1] = driver->ops->create_rectangle();
+	widget->primitives.list[2] = driver->ops->create_text();
+
+	driver->ops->set_rectangle_color(widget->window, widget->primitives.list[0], 
+		&button->config.foreground);
+	driver->ops->set_rectangle_color(widget->window, widget->primitives.list[1], &color[1]);
+	driver->ops->set_text(widget->primitives.list[2], button->config.text, 0, 0);
+	driver->ops->set_text_color(widget->primitives.list[2], &button->config.foreground);
+
+	return button;
+}
+
+void
+button_free(struct aui_widget *widget)
+{
+	struct aui_button *button = (struct aui_button *)widget;
+	widget_remove(widget->parent, widget);
+
+	driver->ops->delete_rectangle(widget->primitives.list[0]);
+	driver->ops->delete_rectangle(widget->primitives.list[1]);
+
+	widget->window->draw_flag = 1;
+
+	free(button);
+}
+
+static void
+button_mouse_hover(struct aui_widget *widget, uint16_t x, uint16_t y)
+{
+	struct aui_button *btn = (struct aui_button *)widget;
+	if (btn->pressed == 0) {
+		driver->ops->set_rectangle_color(widget->window, widget->primitives.list[1], &color[2]);
+	} else {
+		driver->ops->set_rectangle_color(widget->window, widget->primitives.list[1], &color[3]);
+	}
+}
+
+static void
+button_mouse_unhover(struct aui_widget *widget)
+{
+	driver->ops->set_rectangle_color(widget->window, widget->primitives.list[1], &color[1]);
+}
+
+static void 
+button_mouse_press(struct aui_widget *widget, uint16_t x, uint16_t y, uint8_t button)
+{
+	struct aui_button *btn = (struct aui_button *)widget;
+
+	btn->pressed = 1;
+	driver->ops->set_rectangle_color(widget->window, widget->primitives.list[1], &color[3]);
+}
+
+static void 
+button_mouse_release(struct aui_widget *widget, uint16_t x, uint16_t y, uint8_t button)
+{
+	struct aui_button *btn = (struct aui_button *)widget;
+	btn->pressed = 0;
+
+	driver->ops->set_rectangle_color(widget->window, widget->primitives.list[1], &color[1]);
+
+	if (btn->config.command && widget_collides_with_point(widget, x, y))
+		 btn->config.command(btn, btn->config.args);
+}
+
+static void
+button_set_geometry(struct aui_widget *widget, struct aui_geometry *geom)
+{
+	struct aui_button *button = (struct aui_button *)widget;
+	struct aui_geometry foregroundeom = { 0 };
+	struct aui_geometry tgeom = driver->ops->get_text_geometry(widget->primitives.list[2]);
+	int tx = geom->x + geom->width / 2 - tgeom.width / 2;
+	int ty = geom->y + geom->height / 2 + tgeom.height / 2;
+
+	foregroundeom.x = geom->x + 1;
+	foregroundeom.y = geom->y + 1;
+	foregroundeom.width = geom->width - 2;
+	foregroundeom.height = geom->height - 2;
+
+	memcpy(&widget->geom, geom, sizeof(struct aui_geometry));
+	driver->ops->set_rectangle_geometry(widget->window, widget->primitives.list[0], geom);
+	driver->ops->set_rectangle_geometry(widget->window, widget->primitives.list[1], &foregroundeom);
+	driver->ops->set_text(widget->primitives.list[2], button->config.text, tx, ty);
+}
+
+static struct aui_geometry 
+button_get_min_size(struct aui_widget *widget)
+{
+	struct aui_geometry geom = driver->ops->get_text_geometry(widget->primitives.list[2]);
+	struct aui_button *button = (struct aui_button *)widget;
+
+	geom.width = (geom.width < 30) ? geom.width = 30 : geom.width + 30;
+	geom.height = (button->config.text == NULL) ? 12 + 20 : geom.height + 20;
+
+	return geom;
+}
blob - /dev/null
blob + d3bbeda2bba3d8e751a603f30dc66edd518f168a (mode 644)
--- /dev/null
+++ canvas.c
@@ -0,0 +1,159 @@
+/*
+ * Canvases do not store pixels but rather the operations taking
+ * place within them. This makes resizing easier.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "driver.h"
+#include "widget.h"
+
+static void canvas_mouse_hover(struct aui_widget *, uint16_t, uint16_t);
+static void canvas_mouse_unhover(struct aui_widget *);
+static void canvas_mouse_press(struct aui_widget *, uint16_t, uint16_t, uint8_t);
+static void canvas_mouse_release(struct aui_widget *, uint16_t, uint16_t, uint8_t);
+static void canvas_set_geometry(struct aui_widget *, struct aui_geometry *);
+static void canvas_free(struct aui_widget *);
+static struct aui_geometry canvas_get_min_size(struct aui_widget *);
+
+#define DEFAULT_W 300
+#define DEFAULT_H 200
+
+static struct widget_ops canvas_ops = {
+	canvas_mouse_hover,
+	canvas_mouse_unhover,
+	canvas_mouse_press,
+	canvas_mouse_release,
+	canvas_set_geometry, /* set geometry */
+	canvas_free,
+	canvas_get_min_size,
+};
+
+static struct aui_color colors[] = {
+	{ 0xff, 0xff, 0xff, 0xff },
+};
+
+struct aui_canvas*
+aui_canvas_new(struct aui_widget *parent, struct aui_canvas_config *config)
+{
+	struct aui_canvas *canvas = calloc(1, sizeof(struct aui_canvas));
+	struct aui_widget *widget = (struct aui_widget *)canvas;
+
+	widget_init(widget, WIDGET_TYPE_CANVAS, &canvas_ops);
+
+	widget_add(parent, widget);
+	widget->primitives.count = 1;
+	widget->primitives.list = calloc(widget->primitives.count, sizeof(struct primitive *));
+	widget->primitives.list[0] = driver->ops->create_rectangle();
+
+	driver->ops->set_rectangle_color(widget->window, widget->primitives.list[0], &colors[0]);
+
+	TAILQ_INIT(&canvas->queue);
+
+	return canvas;
+}
+
+struct aui_canvas_item*
+aui_canvas_create(struct aui_canvas *canvas, unsigned char type, struct aui_canvas_item_config *cfg)
+{
+	struct aui_canvas_item *i = calloc(1, sizeof(struct aui_canvas_item));
+	struct aui_widget *widget = (struct aui_widget *)canvas;
+
+	if (i == NULL)
+		return NULL;
+
+	i->config = *cfg;
+
+	switch (type) {
+	case AUI_CANVAS_RECTANGLE:
+		i->primitives.count = 1;
+		i->primitives.list = calloc(widget->primitives.count, sizeof(struct primitives *));
+		i->primitives.list[0] = driver->ops->create_rectangle();
+
+		driver->ops->set_rectangle_color(widget->window, i->primitives.list[0],
+			&i->config.rectangle.color);
+		break;
+	default:
+		fprintf(stderr, "libaui: uknwon canvas item type\n");
+		free(i);
+		return NULL;
+	}
+
+	TAILQ_INSERT_TAIL(&canvas->queue, i, entries);
+
+	return i;
+}
+
+static void
+canvas_mouse_hover(struct aui_widget *widget, uint16_t dx, uint16_t dy)
+{
+
+}
+
+static void
+canvas_mouse_unhover(struct aui_widget *widget)
+{
+
+}
+
+static void
+canvas_mouse_press(struct aui_widget *widget, uint16_t x, uint16_t y, uint8_t button)
+{
+
+}
+
+static void
+canvas_mouse_release(struct aui_widget *widget, uint16_t x, uint16_t y, uint8_t button)
+{
+
+}
+
+static void
+canvas_set_geometry(struct aui_widget *widget, struct aui_geometry *geom)
+{
+	struct aui_canvas *canvas = (struct aui_canvas *)widget;
+	struct aui_canvas_item *item;
+
+	memcpy(&widget->geom, geom, sizeof(struct aui_geometry));
+	driver->ops->set_rectangle_geometry(widget->window, widget->primitives.list[0], geom);
+
+	TAILQ_FOREACH(item, &canvas->queue, entries) {
+		struct primitive *prim;
+
+		switch (item->type) {
+		case AUI_CANVAS_RECTANGLE: {
+			struct aui_geometry g = {
+				geom->x + item->config.rectangle.x,
+				geom->y + item->config.rectangle.y,
+				item->config.rectangle.width,
+				item->config.rectangle.height
+			};
+
+			prim = item->primitives.list[0];
+			driver->ops->set_rectangle_geometry(
+				widget->window,
+				prim,
+				&g
+			);
+			break;
+		}
+		default:
+			break;
+		}
+	}
+}
+
+static void
+canvas_free(struct aui_widget *widget)
+{
+
+}
+
+static struct aui_geometry
+canvas_get_min_size(struct aui_widget *widget)
+{
+	struct aui_geometry geom = { .x= 0, .y = 0, .width = DEFAULT_W, .height = DEFAULT_H };
+	return geom;
+}
blob - /dev/null
blob + 541800459ec99ef1b349cc301b1093997f0e234b (mode 644)
--- /dev/null
+++ driver.c
@@ -0,0 +1,18 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "driver.h"
+
+int
+driver_open(enum driver_type type)
+{
+	switch (type) {
+	case DRIVER_TYPE_X11:
+		xcb_driver_open();
+		break;
+	default:
+		fprintf(stderr, "libaui: attempt to open unknown driver\n");
+		return -1;
+	}
+	return 0;
+}
blob - /dev/null
blob + 0ee22df660d00d2889e0e6f995024c9d0a56132c (mode 644)
--- /dev/null
+++ driver.h
@@ -0,0 +1,43 @@
+#ifndef __DRIVER_H__
+#define __DRIVER_H__
+
+#include "aui.h"
+#include "widget.h"
+
+enum driver_type {
+	DRIVER_TYPE_X11
+};
+
+struct aui_dri {
+	struct dri_ops *ops;
+};
+
+struct dri_ops {
+	struct aui_window *(*create_window)(struct aui_window_config*);
+	void (*delete_window)(struct aui_window *);
+	void (*handle_events)(void);
+	void (*resize_window)(struct aui_window *);
+	void (*render_background)(struct aui_window *);
+	void (*render_foreground)(struct aui_window *);
+
+	struct primitive *(*create_rectangle)(void);
+	void (*delete_rectangle) (struct primitive *);
+	void (*render_rectangle) (struct aui_window *, struct primitive *);
+	void (*set_rectangle_color) (struct aui_window *, struct primitive *, struct aui_color *);
+	void (*set_rectangle_geometry) (struct aui_window *, struct primitive *, struct aui_geometry *);
+
+	struct primitive *(*create_text) (void);
+	void (*set_text) (struct primitive *, const char *, int16_t, int16_t);
+	void (*set_text_color) (struct primitive *, struct aui_color *);
+	void (*render_text) (struct aui_window *, struct primitive *);
+	struct aui_geometry (*get_text_geometry) (struct primitive *);
+
+	struct aui_canvas *(*create_canvas)();
+};
+
+extern struct aui_dri *driver; /* Associated with xcb backend */
+
+int driver_open(enum driver_type);
+int xcb_driver_open(void);
+
+#endif
blob - /dev/null
blob + e2600bc25354e3a91a8706bb61f91a67849dd1cd (mode 644)
--- /dev/null
+++ event.h
@@ -0,0 +1,66 @@
+#ifndef __AUI_EVENT_H__
+#define __AUI_EVENT_H__
+
+#include "openbsd-queue.h"
+
+/*
+ * These aren't accessible in aui.h because there is no
+ * need for events. While using the library, you should
+ * handle interactions through callback functions
+ *
+ * These are used internaly.
+ */
+
+enum aui_event_type {
+	AUI_EVENT_QUIT,
+	AUI_EVENT_RESIZE,
+	AUI_EVENT_KEY_PRESS,
+	AUI_EVENT_MOUSE_PRESS,
+	AUI_EVENT_MOUSE_RELEASE,
+	AUI_EVENT_MOUSE_MOTION,
+};
+
+TAILQ_HEAD(aui_event_queue, aui_event);
+struct aui_event {
+	int type;
+	struct aui_window *aw;
+	TAILQ_ENTRY(aui_event) entries;
+};
+
+struct aui_event_quit {
+	struct aui_event event;
+};
+
+struct aui_event_key_press {
+	struct aui_event event;
+	unsigned int key;
+};
+
+struct aui_event_resize {
+	struct aui_event event;
+	uint16_t old_w, old_h;
+	uint16_t new_w, new_h;
+};
+
+struct aui_event_mouse_motion {
+	struct aui_event event;
+	uint16_t x, y;
+};
+
+struct aui_event_mouse_press {
+	struct aui_event event;
+	uint16_t x, y;
+	uint8_t button;
+};
+
+struct aui_event_mouse_release {
+	struct aui_event event;
+	uint16_t x, y;
+	uint8_t button;
+};
+
+extern struct aui_event_queue ev_queue;
+
+void aui_add_event(struct aui_event *);
+
+#endif
blob - /dev/null
blob + 1afaa1f144e8a23216d36f361fcfe57234537502 (mode 644)
--- /dev/null
+++ examples/Makefile
@@ -0,0 +1,16 @@
+ACALC_BIN=		acalc/acalc
+ACALC_SRC=		acalc/acalc.c
+
+INCS=			-I /usr/local/include
+LIBS=			-L /usr/local/lib -laui
+CFLAGS=			-O0
+
+all: acalc
+
+acalc:
+	${CC} ${ACALC_SRC} -o ${ACALC_BIN} ${CFLAGS} ${LIBS} ${INCS}
+
+clean:
+	rm -rf ${ACALC_BIN} ${ACALC_BIN}.core
+
+.PHONY: acalc
blob - /dev/null
blob + 14979f10387d8311e504cbbba898861cd690550d (mode 644)
--- /dev/null
+++ examples/acalc/acalc.c
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 2026 Onana Onana Xavier Manuel <xavier@onana.net>
+ * 
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ * 
+ * THE SOFTWARE IS PROVIDED AS IS AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <aui.h>
+
+#define	DGT_MAX		9
+
+struct equation {
+	struct aui_label_config config;
+	struct aui_label *label;
+	char *display;
+	int queue[2];
+	int qindex;
+	struct binfo *op;
+};
+
+struct acalc {
+	struct equation equation;
+	struct aui_window *aw;
+};
+
+enum button_class {
+	CLASS_DGT,
+	CLASS_DIV,
+	CLASS_ADD,
+	CLASS_SUB,
+	CLASS_MUL,
+	CLASS_EQU,
+	CLASS_CLR,
+};
+
+struct binfo {
+	enum button_class class;
+	struct aui_button_config config;
+	struct aui_gridpar par;
+};
+
+static struct acalc app;
+
+static const struct aui_color theme[] = {
+	{ 255, 255, 255, 255 },
+};
+
+static struct binfo binfo[] = {
+	{ CLASS_CLR, { .text = "C", .foreground = theme[0] }, { .row = 0, .columnspan = 3 } },
+	{ CLASS_DIV, { .text = "/", .foreground = theme[0] }, { .row = 0, .column = 3 } },
+
+	{ CLASS_DGT, { .text = "7", .foreground = theme[0] }, { .row = 1, .column = 0 } },
+	{ CLASS_DGT, { .text = "8", .foreground = theme[0] }, { .row = 1, .column = 1 } },
+	{ CLASS_DGT, { .text = "9", .foreground = theme[0] }, { .row = 1, .column = 2 } },
+	{ CLASS_MUL, { .text = "*", .foreground = theme[0] }, { .row = 1, .column = 3 } },
+
+	{ CLASS_DGT, { .text = "4", .foreground = theme[0] }, { .row = 2, .column = 0 } },
+	{ CLASS_DGT, { .text = "5", .foreground = theme[0] }, { .row = 2, .column = 1 } },
+	{ CLASS_DGT, { .text = "6", .foreground = theme[0] }, { .row = 2, .column = 2 } },
+	{ CLASS_SUB, { .text = "-", .foreground = theme[0] }, { .row = 2, .column = 3 } },
+
+	{ CLASS_DGT, { .text = "1", .foreground = theme[0] }, { .row = 3, .column = 0 } },
+	{ CLASS_DGT, { .text = "2", .foreground = theme[0] }, { .row = 3, .column = 1 } },
+	{ CLASS_DGT, { .text = "3", .foreground = theme[0] }, { .row = 3, .column = 2 } },
+	{ CLASS_ADD, { .text = "+", .foreground = theme[0] }, { .row = 3, .column = 3 } },
+
+	{ CLASS_DGT, { .text = "0", .foreground = theme[0] }, { .row = 4, .columnspan = 3 } },
+	{ CLASS_EQU, { .text = "=", .foreground = theme[0] }, { .row = 4, .column = 3 } },
+};
+
+void
+display_init(struct aui_frame *frame)
+{
+	app.equation.display = malloc(DGT_MAX + 1);
+	memset(app.equation.display, 0, DGT_MAX);
+
+	app.equation.config = (struct aui_label_config) {
+		.text = "What's up?",
+		.foreground = { 0, 0, 0, 255 },
+	};
+
+	app.equation.label = aui_label_new(AUI_WIDGET(frame), &app.equation.config);
+	aui_pack(AUI_WIDGET(app.equation.label), NULL);
+	app.equation.op = NULL;
+}
+
+void
+display_refresh()
+{
+	app.equation.config.text = app.equation.display;
+	aui_label_config(AUI_WIDGET(app.equation.label), &app.equation.config);
+}
+
+void
+display_empty()
+{
+	memset(app.equation.display, 0, DGT_MAX);
+}
+
+void
+display_warn(const char *msg)
+{
+	display_empty();
+	strncpy(app.equation.display, msg, strlen(msg));
+	display_refresh();
+	display_empty();
+}
+
+void
+display_result(int res)
+{
+	display_empty();
+	snprintf(app.equation.display, DGT_MAX, "%d", res);
+	display_refresh();
+	display_empty();
+}
+
+void
+equation_add()
+{
+	const char *errstr;
+	long long res;
+
+	if (strlen(app.equation.display) == 0)
+		return;
+
+	res = strtonum(app.equation.display, 0, INT_MAX, &errstr);
+	if (errstr != NULL) {
+		fprintf(stderr, "acalc: invalid equation number added!\n");
+		exit(1);
+	}
+
+	app.equation.queue[app.equation.qindex++] = (int)res;
+}
+
+void
+equation_solve()
+{
+	long long res;
+
+	if (app.equation.qindex < 2 || app.equation.op == NULL)
+		return;
+
+	switch (app.equation.op->class) {
+	case CLASS_ADD:
+		res = app.equation.queue[0] + app.equation.queue[1];
+		if (res > 999999999 || res < 0) {
+			display_warn("TOO BIG!");
+			goto clear;
+		}
+		display_result(res);
+		break;
+	case CLASS_SUB:
+		res = app.equation.queue[0] - app.equation.queue[1];
+		if (res < 0 || res > 999999999) {
+			display_warn("TOO SMALL!");
+			goto clear;
+		}
+		display_result(res);
+		break;
+	case CLASS_MUL:
+		res = app.equation.queue[0] * app.equation.queue[1];
+		if (res > 999999999 || res < 0) {
+			display_warn("TOO BIG!");
+			goto clear;
+		}
+		display_result(res);
+		break;
+	case CLASS_DIV:
+		if (app.equation.queue[1] == 0) {
+			display_warn("NaN!");
+			goto clear;
+		}
+		res = app.equation.queue[0] / app.equation.queue[1];
+		if (res < 0 || res > 999999999) {
+			display_warn("TOO SMALL!");
+			goto clear;
+		}
+		display_result(res);
+		break;
+	default:
+		break;
+	}
+	app.equation.queue[0] = res;
+	app.equation.qindex = 1;
+	return;
+
+clear:
+	app.equation.qindex = 0;
+	display_empty();
+}
+
+void
+write_dgt(const char *dgt)
+{
+	const char *errstr;
+	long long num;
+	int index;
+
+	num = strtonum(dgt, 0, 9, &errstr);
+	if (errstr != NULL) {
+		fprintf(stderr, "acalc: out of bounds\n");
+		exit(1);
+	}
+
+	index = strlen(app.equation.display);
+	if (index == DGT_MAX)
+		return;
+
+	app.equation.display[index++] = dgt[0];
+	app.equation.display[index] = '\0';
+	display_refresh();
+}
+
+static void
+button_cmd(struct aui_button *b, void *args)
+{
+	struct binfo *info = (struct binfo *)args;
+
+	switch (info->class) {
+	case CLASS_DGT:
+		write_dgt(info->config.text);
+		break;
+	case CLASS_ADD:
+	case CLASS_SUB:
+	case CLASS_MUL:
+	case CLASS_DIV:
+		equation_add();
+		equation_solve();
+		app.equation.op = info;
+		display_empty();
+		break;
+	case CLASS_CLR:
+		display_empty();
+		display_refresh();
+		break;
+	case CLASS_EQU:
+		if (app.equation.op) {
+			equation_add();
+			equation_solve();
+			app.equation.qindex = 0;
+		}
+		break;
+	}
+}
+
+int
+main()
+{
+	struct aui_frame *display_frame;
+	struct aui_frame *buttons_frame;
+	size_t bcount = sizeof(binfo) / sizeof(*binfo);
+
+	{
+		struct aui_window_config config = { .title = "acalc", .width = 120, .height = 188 };
+		app.aw = aui_window_new(&config);
+	}
+
+	{
+		struct aui_frame_config config = { .background = { 255, 255, 255, 255 } };
+		display_frame = aui_frame_new(AUI_WIDGET(app.aw), &config);
+	}
+
+	{
+		struct aui_frame_config config = { .background = { 0, 0, 0, 255 } };
+		buttons_frame = aui_frame_new(AUI_WIDGET(app.aw), &config);
+	}
+
+	struct aui_placepar place[] = {
+		{ .relwidth = 1.0, .relheight = 0.2 },
+		{ .rely = 0.2, .relwidth = 1.0, .relheight = 0.8 }
+	};
+
+	aui_place(AUI_WIDGET(display_frame), &place[0]);
+	aui_place(AUI_WIDGET(buttons_frame), &place[1]);
+	display_init(display_frame);
+
+	for (int i = 0; i < bcount; i++) {
+		struct binfo info = binfo[i];
+
+		info.config.command = &button_cmd;
+		info.config.args = &binfo[i];
+
+		struct aui_button *btn = aui_button_new(AUI_WIDGET(buttons_frame), &info.config);
+		aui_grid(AUI_WIDGET(btn), &binfo[i].par);
+	}
+
+	aui_run();
+	return 0;
+}
blob - /dev/null
blob + 1f102d48dd4007452f43c9b190d4d1735611fc12 (mode 644)
--- /dev/null
+++ font.c
@@ -0,0 +1,111 @@
+#include <fontconfig/fontconfig.h>
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+#include "font.h"
+
+struct _font {
+	FcConfig	   *fc_config;
+	FT_Library	  ft_library;
+	char		   *base;
+	unsigned int	size;
+};
+
+static struct _font font;
+
+static char *find_font_fc(const char *);
+
+int
+font_init()
+{
+	font.fc_config = FcInitLoadConfigAndFonts();
+	if (font.fc_config == NULL) {
+		fprintf(stderr, "libaui: failed to load fontconfig\n");
+		return -1;
+	}
+
+	font.size = 12;
+	font.base = find_font_fc("sans-serif");
+
+	if (FT_Init_FreeType(&font.ft_library) != 0) {
+		fprintf(stderr, "libaui: FT_Init_FreeType failed!\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+int
+font_load_glyphs(struct glyph *gptr, unsigned int dt)
+{
+	FT_Face face;
+
+	if (FT_New_Face(font.ft_library, font.base, 0, &face) != 0 ) {
+		fprintf(stderr, "libaui: failed to load new face\n");
+		return -1;
+	}
+
+	if (FT_Select_Charmap(face, FT_ENCODING_UNICODE) != 0) {
+		fprintf(stderr, "libaui: FT_SelectCharmap failed\n");
+		return -1;
+	}
+
+	FT_Set_Pixel_Sizes(face, 0, font.size);
+
+	for (int i = 0; i < dt; i++) {
+		struct glyph *g = &gptr[i];
+		if (FT_Load_Char(face, g->charcode, FT_LOAD_RENDER) != 0) {
+			fprintf(stderr, "libaui: FT_Load_Char failed\n");
+			return -1;
+		}
+
+		FT_Bitmap bmp = face->glyph->bitmap;
+
+		g->x = -face->glyph->bitmap_left;
+		g->y =  face->glyph->bitmap_top;
+		g->height = bmp.rows;
+		g->width = bmp.width;
+		g->x_offset = face->glyph->advance.x >> 6; /* 26.6 format to pixels */
+		g->y_offset = face->glyph->metrics.horiBearingY >> 6;
+		g->stride = (g->width + 3) &~3;
+		g->bitmap = calloc(g->stride * g->height, sizeof(*g->bitmap));
+
+		for (int y = 0; y < g->height; y++)
+			memcpy(g->bitmap + y * g->stride, bmp.buffer + y * g->width, g->width);
+	}
+
+	FT_Done_Face(face);
+	return 0;
+}
+
+static char*
+find_font_fc(const char *name)
+{
+	FcPattern *pattern;
+	FcPattern *match;
+	FcResult result;
+	FcChar8 *file;
+	char *path;
+
+	pattern  = FcNameParse((FcChar8 *)name);
+	if (pattern == NULL)
+		return NULL;
+
+	if (FcConfigSubstitute(font.fc_config, pattern, FcMatchPattern) == FcFalse) {
+		fprintf(stderr, "libaui: FcConfigSubstitute failed!\n");
+		return NULL;
+	}
+
+	FcConfigSetDefaultSubstitute(font.fc_config, pattern);
+	match = FcFontMatch(font.fc_config, pattern, &result);
+
+	if (FcPatternGetString(match, FC_FILE, 0, &file) == FcResultTypeMismatch) {
+		fprintf(stderr, "libaui: FcPatternGetString\n");
+		return NULL;
+	}
+
+	path = strdup((char *)file);
+	FcPatternDestroy(match);
+	FcPatternDestroy(pattern);
+	return path;
+}
blob - /dev/null
blob + 93f82183920b9cdbff84b43d81c664782946d2af (mode 644)
--- /dev/null
+++ font.h
@@ -0,0 +1,17 @@
+#ifndef FONT_H
+
+struct glyph {
+	unsigned int charcode;
+	int x, y;
+	unsigned int width;
+	unsigned int height;
+	int x_offset;
+	int y_offset;
+	unsigned int stride;
+	unsigned char *bitmap;
+};
+
+int font_init(void);
+int font_load_glyphs(struct glyph *, unsigned int);
+
+#endif
blob - /dev/null
blob + a68537cc8a39f45621290298693e63dcd7c0b066 (mode 644)
--- /dev/null
+++ frame.c
@@ -0,0 +1,144 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "driver.h"
+#include "widget.h"
+
+static void frame_mouse_hover(struct aui_widget *, uint16_t, uint16_t);
+static void frame_mouse_unhover(struct aui_widget *);
+static void frame_mouse_press(struct aui_widget *, uint16_t, uint16_t, uint8_t);
+static void frame_mouse_release(struct aui_widget *, uint16_t, uint16_t, uint8_t);
+static void frame_set_geometry(struct aui_widget *, struct aui_geometry *);
+static void frame_free(struct aui_widget *);
+static struct aui_geometry frame_get_min_size(struct aui_widget *);
+
+static struct widget_ops frame_ops = {
+	frame_mouse_hover,
+	frame_mouse_unhover,
+	frame_mouse_press,
+	frame_mouse_release,
+	frame_set_geometry,
+	frame_free,
+	frame_get_min_size,
+};
+
+static struct aui_frame_config default_config = {
+	.background = { 0x77, 0x77, 0x77, 0xff },
+};
+
+struct aui_frame*
+aui_frame_new(struct aui_widget *parent, struct aui_frame_config *config)
+{
+	struct aui_frame *frame = calloc(1, sizeof(struct aui_frame));
+	struct aui_widget *widget = (struct aui_widget *)frame;
+	struct aui_container *con = (struct aui_container *)frame;
+
+	widget_init(widget, WIDGET_TYPE_FRAME, &frame_ops);
+
+	widget_add(parent, widget);
+	con->map_count = 0;
+
+	widget->primitives.count = 1;
+	widget->primitives.list = calloc(widget->primitives.count, sizeof(struct primitive *));
+	widget->primitives.list[0] = driver->ops->create_rectangle();
+
+	aui_frame_config(widget, config);
+
+	return frame;
+}
+
+int
+aui_frame_config(struct aui_widget *widget, struct aui_frame_config *config)
+{
+	struct aui_frame *frame = (struct aui_frame *)widget;
+
+	frame->config = (config == NULL) ? default_config : *config;
+	driver->ops->set_rectangle_color(widget->window, widget->primitives.list[0], 
+		&frame->config.background);
+
+	return 0;
+}
+
+static void
+frame_mouse_hover(struct aui_widget *widget, uint16_t x, uint16_t y)
+{
+	struct aui_container *con = (struct aui_container *)widget;
+	struct aui_widget *tohover = NULL;
+	struct aui_widget *child;
+
+	TAILQ_FOREACH(child, &widget->queue, entries) {
+		if (child->mapped && widget_collides_with_point(child, x, y))
+			tohover = child;
+	}
+
+	if (tohover != con->focus.hover && con->focus.hover != NULL)
+		con->focus.hover->ops->mouse_unhover(con->focus.hover);
+
+	con->focus.hover = tohover;
+
+	if (tohover != NULL)
+		tohover->ops->mouse_hover(tohover, x, y);
+}
+
+static void
+frame_mouse_unhover(struct aui_widget *widget)
+{
+	struct aui_container *con = (struct aui_container *)widget;
+
+	if (con->focus.hover) {
+		con->focus.hover->ops->mouse_unhover(con->focus.hover);
+		con->focus.hover = NULL;
+	}
+}
+
+static void
+frame_mouse_press(struct aui_widget *widget, uint16_t x, uint16_t y, uint8_t button)
+{
+	struct aui_container *con = (struct aui_container *)widget;
+	struct aui_widget *topress = NULL;
+	struct aui_widget *child;
+
+	TAILQ_FOREACH(child, &widget->queue, entries) {
+		if (child->mapped && widget_collides_with_point(child, x, y))
+			topress = child;
+	}
+
+	if (topress != con->focus.press && con->focus.press != NULL)
+		con->focus.press->ops->mouse_release(con->focus.press, x, y, button);
+
+	con->focus.press = topress;
+
+	if (topress != NULL)
+		topress->ops->mouse_press(topress, x, y, button);
+}
+
+static void
+frame_mouse_release(struct aui_widget *widget, uint16_t x, uint16_t y, uint8_t button)
+{
+	struct aui_container *con = (struct aui_container *)widget;
+
+	if (con->focus.press != NULL) {
+		con->focus.press->ops->mouse_release(con->focus.press, x, y, button);
+		con->focus.press = NULL;
+	}
+}
+
+static void
+frame_set_geometry(struct aui_widget *widget, struct aui_geometry *geom)
+{
+	memcpy(&widget->geom, geom, sizeof(struct aui_geometry));
+	driver->ops->set_rectangle_geometry(widget->window, widget->primitives.list[0], geom);
+}
+
+static void
+frame_free(struct aui_widget *widget)
+{
+
+}
+
+static struct aui_geometry frame_get_min_size(struct aui_widget *widget)
+{
+	struct aui_geometry geom = { 0, 0, 120, 120 };
+	return geom;
+}
blob - /dev/null
blob + ebeb86585fd96a64565a5fc6881784a9a9726eb3 (mode 644)
--- /dev/null
+++ label.c
@@ -0,0 +1,124 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "driver.h"
+#include "widget.h"
+
+static void label_mouse_hover(struct aui_widget *, uint16_t, uint16_t);
+static void label_mouse_unhover(struct aui_widget *);
+static void label_mouse_press(struct aui_widget *, uint16_t, uint16_t, uint8_t);
+static void label_mouse_release(struct aui_widget *, uint16_t, uint16_t, uint8_t);
+static void label_set_geometry(struct aui_widget *, struct aui_geometry *);
+static void label_free(struct aui_widget *);
+static struct aui_geometry label_get_min_size(struct aui_widget *);
+
+static struct widget_ops label_ops = {
+	label_mouse_hover,
+	label_mouse_unhover,
+	label_mouse_press,
+	label_mouse_release,
+	label_set_geometry, /* set geometry */
+	label_free,
+	label_get_min_size,
+};
+
+struct aui_label_config default_config = {
+	.text = "Hello AUI",
+	.foreground = { 0, 0, 0, 255 },
+};
+
+struct aui_label*
+aui_label_new(struct aui_widget *parent, struct aui_label_config *config)
+{
+	struct aui_label *label = calloc(1, sizeof(struct aui_label));
+	struct aui_widget *widget = &label->widget;
+
+	widget_init(widget, WIDGET_TYPE_LABEL, &label_ops);
+	widget_add(parent, widget);
+
+	widget->primitives.count = 1;
+	widget->primitives.list = calloc(widget->primitives.count, sizeof(struct primitive*));
+
+	widget->primitives.list[0] = driver->ops->create_text();
+	aui_label_config(widget, config);
+
+	return label;
+}
+
+int
+aui_label_config(struct aui_widget *widget, struct aui_label_config *config)
+{
+	struct aui_label *label = (struct aui_label *)widget;
+	struct aui_geometry geom = widget->geom;
+
+	if (label->config.text) {
+		free(label->config.text);
+		label->config.text = NULL;
+	}
+
+	config = (config == NULL) ? &default_config : config;
+	label->config = *config;
+
+	if (config->text)
+		label->config.text = strdup(config->text);
+
+	driver->ops->set_text(widget->primitives.list[0], label->config.text, 0, 0);
+	driver->ops->set_text_color(widget->primitives.list[0], &label->config.foreground);
+	label_set_geometry(widget, &geom);
+
+	layout_organize(widget->parent);
+	return 0;
+}
+
+static void
+label_mouse_hover(struct aui_widget *widget, uint16_t dx, uint16_t dy)
+{
+
+}
+
+static void
+label_mouse_unhover(struct aui_widget *widget)
+{
+
+}
+
+static void
+label_mouse_press(struct aui_widget *widget, uint16_t x, uint16_t y, uint8_t button)
+{
+
+}
+
+static void
+label_mouse_release(struct aui_widget *widget, uint16_t x, uint16_t y, uint8_t button)
+{
+
+}
+
+static void
+label_set_geometry(struct aui_widget *widget, struct aui_geometry *geom)
+{
+	struct aui_geometry tgeom = driver->ops->get_text_geometry(widget->primitives.list[0]);
+	struct aui_label *label = (struct aui_label *)widget;
+
+	driver->ops->set_text(
+		widget->primitives.list[0], 
+		label->config.text, 
+		geom->x + geom->width / 2 - tgeom.width / 2 ,
+		geom->y + geom->height
+	);
+	widget->geom = *geom;
+}
+
+static void
+label_free(struct aui_widget *widget)
+{
+
+}
+
+static struct aui_geometry
+label_get_min_size(struct aui_widget *widget)
+{
+	struct aui_geometry geom = driver->ops->get_text_geometry(widget->primitives.list[0]);
+	return geom;
+}
blob - /dev/null
blob + b831bfede94fa9091f932ac551253007c170c259 (mode 644)
--- /dev/null
+++ layout.c
@@ -0,0 +1,728 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "aui.h"
+#include "widget.h"
+
+static struct aui_placepar default_place = {
+	.x = 0,
+	.y = 0,
+	.relx = 0,
+	.rely = 0,
+	.width = 0,
+	.height = 0,
+	.relwidth = 0,
+	.relheight = 0,
+	.anchor = AUI_ANCHOR_NW,
+};
+
+static struct aui_packpar default_pack = {
+	.anchor = AUI_ANCHOR_NW,
+	.fill = AUI_FILL_NONE,
+	.side = AUI_SIDE_TOP,
+	.expand = 0,
+};
+
+static struct aui_gridpar default_grid = {
+	.column = 0,
+	.row = 0,
+	.columnspan = 1,
+	.rowspan = 1,
+	.ipadx = 0,
+	.ipady = 0,
+	.padx = 0,
+	.pady = 0
+};
+
+static struct aui_rowpar default_rowconfigure = {
+	.minsize = 0,
+	.weight = 0,
+	.uniform = 0,
+	.pad = 0,
+};
+
+static struct aui_columnpar default_columnconfigure = {
+	.minsize = 0,
+	.weight = 0,
+	.uniform = 0,
+	.pad = 0,
+};
+
+static int
+can_add(struct aui_widget *widget, enum aui_layout_type type)
+{
+	struct aui_widget *parent = widget->parent;
+
+	if (parent->type != WIDGET_TYPE_WINDOW && parent->type != WIDGET_TYPE_CANVAS &&
+		parent->type != WIDGET_TYPE_FRAME) {
+		fprintf(stderr, "libaui: cannot map widget in non-container\n");
+		return -1;
+	}
+
+	struct aui_container *con = (struct aui_container *)parent;
+
+	if ((con->layout_type != type) && (con->layout_type != AUI_LAYOUT_NONE)) {
+		fprintf(stderr, "libaui: cannot map as mismatching type / non-empty container\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+void
+place(struct aui_widget *widget)
+{
+	struct aui_widget *child;
+
+	TAILQ_FOREACH(child, &widget->queue, entries) {
+		if (child->mapped == 0)
+			continue;
+
+		struct aui_placepar *par = &child->placepar;
+		int dx = 0, dy = 0;
+
+		struct aui_geometry geom = { 
+			.x = widget->geom.x + child->placepar.x + widget->geom.width * child->placepar.relx,
+			.y = widget->geom.y + child->placepar.y + widget->geom.height * child->placepar.rely,
+			.width = child->placepar.width + child->placepar.relwidth * widget->geom.width,
+			.height = child->placepar.height + child->placepar.relheight * widget->geom.height };
+
+		switch (par->anchor) {
+		case AUI_ANCHOR_NW:
+			dx = 0;
+			dy = 0;
+			break;
+		case AUI_ANCHOR_NE:
+			dx = -geom.width;
+			dy = 0;
+			break;
+		case AUI_ANCHOR_N:
+			dx = -geom.width / 2;
+			dy = 0;
+			break;
+		case AUI_ANCHOR_W:
+			dx = 0;
+			dy = -geom.height / 2;
+			break;
+		case AUI_ANCHOR_E:
+			dx = -geom.width;
+			dy = -geom.height /2;
+			break;
+		case AUI_ANCHOR_SE:
+			dx = -geom.width;
+			dy = -geom.height;
+			break;
+		case AUI_ANCHOR_SW:
+			dx = 0;
+			dy = -geom.height;
+			break;
+		case AUI_ANCHOR_S:
+			dx = -geom.width / 2;
+			dy = -geom.height;
+			break;
+		case AUI_ANCHOR_CENTER:
+			dx = -geom.width / 2;
+			dy = -geom.height / 2;
+			break;
+		default:
+			break;
+		}
+
+		geom.x += dx;
+		geom.y += dy;
+		child->ops->set_geometry(child, &geom); 
+
+		switch (child->type) {
+		case WIDGET_TYPE_FRAME:
+			layout_organize(child);
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+void
+grid(struct aui_widget *widget)
+{
+	struct aui_container *con = (struct aui_container *)widget;
+	uint8_t *rmap = con->row_maps;
+	uint8_t *cmap = con->col_maps;
+	struct aui_widget *child;
+
+	unsigned int *rsize = con->row_sizes;
+	unsigned int *csize = con->col_sizes;
+
+	memset(con->row_maps, 0, sizeof(*con->row_maps) * con->grid_size[1]);
+	memset(con->col_maps, 0, sizeof(*con->col_maps) * con->grid_size[0]);
+
+	memset(con->row_sizes, 0, sizeof(*con->row_sizes) * con->grid_size[1]);
+	memset(con->col_sizes, 0, sizeof(*con->col_sizes) * con->grid_size[0]);
+
+	TAILQ_FOREACH(child, &widget->queue, entries) {
+		if (child->mapped == 0)
+			continue;
+
+		struct aui_geometry min = child->ops->get_min_size(child);
+
+		rmap[child->gridpar.row] = 1;
+		cmap[child->gridpar.column] = 1;
+
+		rsize[child->gridpar.row] = (rsize[child->gridpar.row] < min.height) ?
+			min.height : rsize[child->gridpar.row];
+
+		csize[child->gridpar.column] = (csize[child->gridpar.column] < min.width) ?
+			min.width : csize[child->gridpar.column];
+	}
+
+	unsigned int *rpos = con->row_pos;
+	unsigned int *cpos = con->col_pos;
+
+	unsigned int rowdt = 0;
+	unsigned int coldt = 0;
+
+	for (int r = 0; r < con->grid_size[1]; r++) {
+		rpos[r] = rowdt;
+		rowdt = (rmap[r] == 1) ? rowdt + rsize[r] : rowdt;
+	}
+
+	for (int c = 0; c < con->grid_size[0]; c++) {
+		cpos[c] = coldt;
+		coldt = (cmap[c] == 1) ? coldt + csize[c] : coldt;
+	}
+
+	TAILQ_FOREACH(child, &widget->queue, entries) {
+		if (child->mapped == 0)
+			continue;
+
+		struct aui_geometry min = child->ops->get_min_size(child);
+		struct aui_geometry geom = { 0 };
+		struct aui_gridpar *gpar = &child->gridpar;
+
+		int cspan = (gpar->column + gpar->columnspan) <= con->grid_size[0] ?
+					gpar->columnspan - 1: con->grid_size[0] - gpar->column - 1;
+
+		int rspan = (gpar->row + gpar->rowspan) <= con->grid_size[1] ?
+					gpar->rowspan - 1: con->grid_size[1] - gpar->row - 1;
+
+
+		int dx = (csize[child->gridpar.column] - min.width);
+		int dy = (rsize[child->gridpar.row] - min.height);
+
+		int width = min.width;
+		int height = min.height;
+
+		for (int i = gpar->column; i < gpar->column + cspan; i++)
+			width += csize[i];
+
+		for (int i = gpar->row; i < gpar->row + rspan; i++)
+			height += rsize[i];
+
+		geom.x = widget->geom.x + cpos[child->gridpar.column] + dx / 2;
+		geom.y = widget->geom.y + rpos[child->gridpar.row] + dy / 2;
+		geom.width = width;
+		geom.height = height;
+
+		child->ops->set_geometry(child, &geom);
+	}
+
+	TAILQ_FOREACH(child, &widget->queue, entries) {
+		switch (child->type) {
+		case WIDGET_TYPE_FRAME:
+			layout_organize(child);
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+void
+pack(struct aui_widget *widget)
+{
+	struct aui_container *con = (struct aui_container *)widget;
+	struct aui_widget *child;
+	struct aui_geometry space = widget->geom;
+	unsigned int hexpand = 0;
+	unsigned int vexpand = 0;
+	unsigned int req_w = 0;
+	unsigned int req_h = 0;
+	int extra_w = 0;
+	int extra_h = 0;
+	int hextra = 0;
+	int vextra = 0;
+
+	/*
+	 * Compute requested and extra space. hextra and vextra are only set
+	 * if there is no top/bottom widgets succeeding it. This guarantees
+	 * a proper request size.
+	 */
+	TAILQ_FOREACH(child, &widget->queue, entries) {
+		if (child->mapped == 0)
+			continue;
+
+		struct aui_geometry cgeom = child->ops->get_min_size(child);
+		switch (child->packpar.side) {
+		case AUI_SIDE_TOP:
+		case AUI_SIDE_BOTTOM:
+			vexpand = (child->packpar.expand) ? vexpand + 1 : vexpand;
+			if (vextra) vextra = 0;
+			req_h += cgeom.height;
+			hextra = (cgeom.width > hextra) ? cgeom.width : hextra;
+			break;
+		case AUI_SIDE_LEFT:
+		case AUI_SIDE_RIGHT:
+			hexpand = (child->packpar.expand) ? hexpand + 1 : hexpand;
+			if (hextra) hextra = 0;
+			vextra = (cgeom.height > vextra) ? cgeom.height : vextra;
+			req_w += cgeom.width;
+			break;
+		default:
+			break;
+		}
+	}
+
+	req_w += hextra;
+	req_h += vextra;
+
+	if (req_w > space.width)
+		req_w = space.width;
+
+	if (req_h > space.height)
+		req_h = space.height;
+
+	extra_w = space.width - req_w;
+	extra_h = space.height - req_h;
+
+	/*
+	 * Making sure each widget consume space before expension
+	 * for their area.
+	 */
+	TAILQ_FOREACH(child, &widget->queue, entries) {
+		if (child->mapped == 0)
+			continue;
+
+		struct aui_geometry min = child->ops->get_min_size(child);
+
+		switch (child->packpar.side) {
+		case AUI_SIDE_TOP:
+			child->packarea = (struct aui_geometry) {
+				.x = space.x,
+				.y = space.y,
+				.width = space.width,
+				.height = min.height,
+			};
+
+			if (child->packarea.height > space.height) {
+				child->packarea.height = space.height;
+			}
+
+			space.y += child->packarea.height;
+			space.height -= child->packarea.height;
+			break;
+		case AUI_SIDE_BOTTOM:
+			child->packarea = (struct aui_geometry) {
+				.x = space.x,
+				.y = space.y,
+				.width = space.width,
+				.height = min.height
+			};
+
+			if (child->packarea.height > space.height) {
+				child->packarea.height = space.height;
+			}
+
+			child->packarea.y = space.y + space.height - child->packarea.height;
+
+			space.height -= child->packarea.height;
+			break;
+		case AUI_SIDE_LEFT:
+			child->packarea = (struct aui_geometry) {
+				.x = space.x,
+				.y = space.y,
+				.width = min.width,
+				.height = space.height
+			};
+
+			if (child->packarea.width > space.width) {
+				child->packarea.width = space.width;
+			}
+
+			space.x += child->packarea.width;
+			space.width -= child->packarea.width;
+			break;
+		case AUI_SIDE_RIGHT:
+			child->packarea = (struct aui_geometry) {
+				.x = space.x,
+				.y = space.y,
+				.width = min.width,
+				.height = space.height
+			};
+
+			if (child->packarea.width > space.width) {
+				child->packarea.width = space.width;
+			}
+
+			child->packarea.x = space.x + space.width - child->packarea.width;
+
+			space.width -= child->packarea.width;
+			break;
+		default:
+			break;
+		}
+	}
+
+	int top = 0;
+	int bottom = 0;
+	int right = 0;
+	int left = 0;
+
+	/*
+	 * Consuming the remaining space if expanded
+	 */
+	TAILQ_FOREACH(child, &widget->queue, entries) {
+		if (child->mapped == 0)
+			continue;
+
+		if (space.width == 0 && space.height == 0)
+			break;
+
+		struct aui_geometry *area = &child->packarea;
+
+		switch (child->packpar.side) {
+		case AUI_SIDE_TOP:
+			area->x += left;
+			area->y += top;
+			area->width -= left;
+
+			area->width -= right;
+
+			if (child->packpar.expand == 1) {
+				if (vexpand) {
+					top += extra_h / vexpand;
+					area->height += extra_h / vexpand;
+					extra_h -= extra_h / vexpand;
+					vexpand--;
+				}
+			}
+			break;
+
+		case AUI_SIDE_BOTTOM:
+			area->x += left;
+			area->width -= left;
+
+			area->width -= right;
+			if (child->packpar.expand == 1) {
+				if (vexpand) {
+					bottom += extra_h / vexpand;
+					area->height += extra_h / vexpand;
+					area->y -= extra_h / vexpand;
+					extra_h -= extra_h / vexpand;
+					vexpand--;
+				}
+			}
+			break;
+		case AUI_SIDE_LEFT:
+			area->y += top;
+			area->x += left;
+			area->height -= top;
+			area->height -= bottom;
+
+			if (child->packpar.expand == 1) {
+				if (hexpand) {
+					left += extra_w / hexpand;
+					area->width += extra_w / hexpand;
+					extra_w -= extra_w / hexpand;
+					hexpand--;
+				}
+			}
+			break;
+		case AUI_SIDE_RIGHT:
+			area->y += top;
+			area->height -= top;
+			area->height -= bottom;
+
+			if (child->packpar.expand == 1) {
+				if (hexpand) {
+					right += extra_w / hexpand;
+					area->x -= extra_w / hexpand;
+					area->width += extra_w / hexpand;
+					extra_w -= extra_w / hexpand;
+					hexpand--;
+				}
+			}
+			break;
+		default:
+			break;
+		}
+	}
+
+	/*
+	 * Setting geometry
+	 */
+	TAILQ_FOREACH(child, &widget->queue, entries) {
+		if (child->mapped == 0)
+			continue;
+
+		struct aui_geometry min = child->ops->get_min_size(child);
+		struct aui_geometry *area = &child->packarea;
+
+		switch (child->packpar.fill) {
+		case AUI_FILL_NONE:
+			child->geom.width = (min.width > area->width) ?  area->width : min.width;
+			child->geom.height = (min.height > area->height) ?  area->height : min.height;
+			break;
+		case AUI_FILL_X:
+			child->geom.width = area->width;
+			child->geom.height = (min.height > area->height) ?  area->height : min.height;
+			break;
+		case AUI_FILL_Y:
+			child->geom.width = (min.width > area->width) ?  area->width : min.width;
+			child->geom.height = area->height;
+			break;
+		case AUI_FILL_BOTH:
+			child->geom.width = area->width;
+			child->geom.height = area->height;
+			break;
+		default:
+			break;
+		}
+
+		switch (child->packpar.anchor) {
+		case AUI_ANCHOR_NW:
+			child->geom.x = area->x;
+			child->geom.y = area->y;
+			break;
+		case AUI_ANCHOR_N:
+			child->geom.x = area->x + area->width / 2 - child->geom.width / 2;
+			child->geom.y = area->y;
+			break;
+		case AUI_ANCHOR_NE:
+			child->geom.x = area->x + area->width - child->geom.width;
+			child->geom.y = area->y;
+			break;
+		case AUI_ANCHOR_CENTER:
+			child->geom.x = area->x + area->width / 2 - child->geom.width / 2;
+			child->geom.y = area->y + area->height / 2 - child->geom.height / 2;
+			break;
+		case AUI_ANCHOR_SE:
+			child->geom.x = area->x + area->width - child->geom.width;
+			child->geom.y = area->y + area->height - child->geom.height;
+			break;
+		case AUI_ANCHOR_S:
+			child->geom.x = area->x + area->width / 2 - child->geom.width / 2;
+			child->geom.y = area->y + area->height - child->geom.height;
+			break;
+		case AUI_ANCHOR_SW:
+			child->geom.x = area->x;
+			child->geom.y = area->y + area->height - child->geom.height;
+			break;	
+		case AUI_ANCHOR_W:
+			child->geom.x = area->x;
+			child->geom.y = area->y + area->height / 2 - child->geom.height / 2;
+			break;
+		case AUI_ANCHOR_E:
+			child->geom.x = area->x + area->width - child->geom.width;
+			child->geom.y = area->y + area->height / 2 - child->geom.height / 2;
+			break;
+		default:
+			break;
+		break;
+		}
+
+		child->ops->set_geometry(child, &child->geom);
+	}
+
+	TAILQ_FOREACH(child, &widget->queue, entries) {
+		switch (child->type) {
+		case WIDGET_TYPE_FRAME:
+			layout_organize(child);
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+void
+layout_organize(struct aui_widget *widget)
+{
+	struct aui_container *con = (struct aui_container *)widget;
+	struct aui_widget *child;
+
+	switch (con->layout_type) {
+	case AUI_LAYOUT_PLACE:
+		place(widget);
+		break;
+	case AUI_LAYOUT_GRID: 
+		grid(widget);
+		break;
+	/*
+	 * Lots of suffering into implementing this one :D
+	 */
+	case AUI_LAYOUT_PACK:
+		pack(widget);
+		break;
+	default:
+		break;
+	}
+}
+
+int 
+aui_place(struct aui_widget *widget, struct aui_placepar *par)
+{
+	int check = can_add(widget, AUI_LAYOUT_PLACE);
+	struct aui_widget *parent;
+	struct aui_container *con;
+
+	if (check == -1)
+		return -1;
+
+	if (par == NULL)
+		par = &default_place;
+
+	con = (struct aui_container *)widget->parent;
+	parent = (struct aui_widget *)widget->parent;
+	con->layout_type = AUI_LAYOUT_PLACE;
+	widget->placepar = *(par);
+	widget->mapped = 1;
+	con->map_count++;
+
+	layout_organize(parent);
+
+	return 0;
+}
+
+int
+aui_pack(struct aui_widget *widget, struct aui_packpar *par)
+{
+	int check = can_add(widget, AUI_LAYOUT_PACK);
+	struct aui_widget *parent;
+	struct aui_container *con;
+
+	if (check == -1)
+		return - 1;
+
+	if (par == NULL)
+		par = &default_pack;
+
+	con = (struct aui_container *)widget->parent;
+	parent = widget->parent;
+	con->layout_type = AUI_LAYOUT_PACK;
+	widget->packpar = *(par);
+	widget->mapped = 1;
+	con->map_count++;
+
+	/*
+	 * This is important for packing order
+	 */
+	widget_lead(widget->parent, widget);
+
+	layout_organize(parent);
+
+	return 0;
+}
+
+int
+aui_grid(struct aui_widget *widget, struct aui_gridpar *par)
+{
+	int check = can_add(widget, AUI_LAYOUT_GRID);
+	struct aui_widget *parent;
+	struct aui_container *con;
+	unsigned int *rsizes;
+	unsigned int *csizes;
+	unsigned int *rpos;
+	unsigned int *cpos;
+	uint8_t *rmaps;
+	uint8_t *cmaps;
+
+	if (check == -1)
+		return -1;
+
+	if (par == NULL)
+		par = &default_grid;
+
+	par->columnspan = (par->columnspan < 1) ? 1 : par->columnspan;
+	par->rowspan = (par->rowspan < 1) ? 1 : par->rowspan;
+	con = (struct aui_container *)widget->parent;
+	parent = widget->parent;
+	con->layout_type = AUI_LAYOUT_GRID;
+	widget->gridpar = *(par);
+	widget->mapped = 1;
+	con->map_count++;
+
+	con->grid_size[0] = (con->grid_size[0] > (par->column + par->columnspan)) ? 
+		con->grid_size[0] : (par->column + par->columnspan);
+
+	con->grid_size[1] = (con->grid_size[1] > (par->row + par->rowspan)) ? 
+		con->grid_size[1] : (par->row + par->rowspan);
+
+	rmaps = reallocarray(con->row_maps, con->grid_size[1], sizeof(*con->row_maps));
+	if (rmaps == NULL) {
+		fprintf(stderr, "libaui: failed to allocate row maps\n");
+		return -1;
+	}
+	con->row_maps = rmaps;
+
+	cmaps = reallocarray(con->col_maps, con->grid_size[0], sizeof(*con->col_maps));
+	if (cmaps == NULL) {
+		fprintf(stderr, "libaui: failed to allocate col maps\n");
+		return -1;
+	}
+	con->col_maps = cmaps;
+
+
+	rsizes = reallocarray(con->row_sizes, con->grid_size[1], sizeof(*con->row_sizes));
+	if (rsizes == NULL) {
+		fprintf(stderr, "libaui: failed to allocated row sizes\n");
+		return -1;
+	}
+	con->row_sizes = rsizes;
+
+	csizes = reallocarray(con->col_sizes, con->grid_size[0], sizeof(*con->col_sizes));
+	if (csizes == NULL) {
+		fprintf(stderr, "libaui: failed to allocated col sizes\n");
+		return -1;
+	}
+	con->col_sizes = csizes;
+
+	rpos = reallocarray(con->row_pos, con->grid_size[1], sizeof(*con->row_pos));
+	if (rpos == NULL) {
+		fprintf(stderr, "libaui: failed to allocate row positions\n");
+		return -1;
+	}
+	con->row_pos = rpos;
+
+	cpos = reallocarray(con->col_pos, con->grid_size[0], sizeof(*con->col_pos));
+	if (cpos == NULL) {
+		fprintf(stderr, "libaui: failed to allocate col positions\n");
+		return -1;
+	}
+	con->col_pos = cpos;
+
+	layout_organize(parent);
+
+	return 0;
+}
+
+int
+aui_getplacepar(struct aui_widget *widget, struct aui_placepar *par)
+{
+	*par = widget->placepar;
+	return 0;
+}
+
+int
+aui_getpackpar(struct aui_widget *widget, struct aui_packpar *par)
+{
+	*par = widget->packpar;
+	return 0;
+}
+
+int
+aui_getgridpar(struct aui_widget *widget, struct aui_gridpar *par)
+{
+	*par = widget->gridpar;
+	return 0;
+}
blob - /dev/null
blob + f85d43f0c4dc673b366f3193971ad988171b2d87 (mode 644)
--- /dev/null
+++ layout.h
@@ -0,0 +1,13 @@
+#ifndef LAYOUT_H
+#define LAYOUT_H
+
+enum aui_layout_type {
+	AUI_LAYOUT_NONE,
+	AUI_LAYOUT_PLACE,
+	AUI_LAYOUT_GRID,
+	AUI_LAYOUT_PACK
+};
+
+void layout_organize(struct aui_widget *widget);
+
+#endif
blob - /dev/null
blob + 127c9194d4549b7d775d7b50b3e4b39703f9fc2f (mode 644)
--- /dev/null
+++ openbsd-queue.h
@@ -0,0 +1,635 @@
+/*	$OpenBSD: queue.h,v 1.46 2020/12/30 13:33:12 millert Exp $	*/
+/*	$NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $	*/
+
+/*
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)queue.h	8.5 (Berkeley) 8/20/94
+ */
+
+#ifndef	_SYS_QUEUE_H_
+#define	_SYS_QUEUE_H_
+
+#ifdef __OpenBSD__
+#include <sys/_null.h>
+#endif
+
+/*
+ * This file defines five types of data structures: singly-linked lists,
+ * lists, simple queues, tail queues and XOR simple queues.
+ *
+ *
+ * A singly-linked list is headed by a single forward pointer. The elements
+ * are singly linked for minimum space and pointer manipulation overhead at
+ * the expense of O(n) removal for arbitrary elements. New elements can be
+ * added to the list after an existing element or at the head of the list.
+ * Elements being removed from the head of the list should use the explicit
+ * macro for this purpose for optimum efficiency. A singly-linked list may
+ * only be traversed in the forward direction.  Singly-linked lists are ideal
+ * for applications with large datasets and few or no removals or for
+ * implementing a LIFO queue.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may only be traversed in the forward direction.
+ *
+ * A simple queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are singly
+ * linked to save space, so elements can only be removed from the
+ * head of the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the
+ * list. A simple queue may only be traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * An XOR simple queue is used in the same way as a regular simple queue.
+ * The difference is that the head structure also includes a "cookie" that
+ * is XOR'd with the queue pointer (first, last or next) to generate the
+ * real pointer value.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ */
+
+#if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC))
+#define _Q_INVALID ((void *)-1)
+#define _Q_INVALIDATE(a) (a) = _Q_INVALID
+#else
+#define _Q_INVALIDATE(a)
+#endif
+
+/*
+ * Singly-linked List definitions.
+ */
+#define SLIST_HEAD(name, type)						\
+struct name {								\
+	struct type *slh_first;	/* first element */			\
+}
+
+#define	SLIST_HEAD_INITIALIZER(head)					\
+	{ NULL }
+
+#define SLIST_ENTRY(type)						\
+struct {								\
+	struct type *sle_next;	/* next element */			\
+}
+
+/*
+ * Singly-linked List access methods.
+ */
+#define	SLIST_FIRST(head)	((head)->slh_first)
+#define	SLIST_END(head)		NULL
+#define	SLIST_EMPTY(head)	(SLIST_FIRST(head) == SLIST_END(head))
+#define	SLIST_NEXT(elm, field)	((elm)->field.sle_next)
+
+#define	SLIST_FOREACH(var, head, field)					\
+	for((var) = SLIST_FIRST(head);					\
+	    (var) != SLIST_END(head);					\
+	    (var) = SLIST_NEXT(var, field))
+
+#define	SLIST_FOREACH_SAFE(var, head, field, tvar)			\
+	for ((var) = SLIST_FIRST(head);				\
+	    (var) && ((tvar) = SLIST_NEXT(var, field), 1);		\
+	    (var) = (tvar))
+
+/*
+ * Singly-linked List functions.
+ */
+#define	SLIST_INIT(head) {						\
+	SLIST_FIRST(head) = SLIST_END(head);				\
+}
+
+#define	SLIST_INSERT_AFTER(slistelm, elm, field) do {			\
+	(elm)->field.sle_next = (slistelm)->field.sle_next;		\
+	(slistelm)->field.sle_next = (elm);				\
+} while (0)
+
+#define	SLIST_INSERT_HEAD(head, elm, field) do {			\
+	(elm)->field.sle_next = (head)->slh_first;			\
+	(head)->slh_first = (elm);					\
+} while (0)
+
+#define	SLIST_REMOVE_AFTER(elm, field) do {				\
+	(elm)->field.sle_next = (elm)->field.sle_next->field.sle_next;	\
+} while (0)
+
+#define	SLIST_REMOVE_HEAD(head, field) do {				\
+	(head)->slh_first = (head)->slh_first->field.sle_next;		\
+} while (0)
+
+#define SLIST_REMOVE(head, elm, type, field) do {			\
+	if ((head)->slh_first == (elm)) {				\
+		SLIST_REMOVE_HEAD((head), field);			\
+	} else {							\
+		struct type *curelm = (head)->slh_first;		\
+									\
+		while (curelm->field.sle_next != (elm))			\
+			curelm = curelm->field.sle_next;		\
+		curelm->field.sle_next =				\
+		    curelm->field.sle_next->field.sle_next;		\
+	}								\
+	_Q_INVALIDATE((elm)->field.sle_next);				\
+} while (0)
+
+/*
+ * List definitions.
+ */
+#define LIST_HEAD(name, type)						\
+struct name {								\
+	struct type *lh_first;	/* first element */			\
+}
+
+#define LIST_HEAD_INITIALIZER(head)					\
+	{ NULL }
+
+#define LIST_ENTRY(type)						\
+struct {								\
+	struct type *le_next;	/* next element */			\
+	struct type **le_prev;	/* address of previous next element */	\
+}
+
+/*
+ * List access methods.
+ */
+#define	LIST_FIRST(head)		((head)->lh_first)
+#define	LIST_END(head)			NULL
+#define	LIST_EMPTY(head)		(LIST_FIRST(head) == LIST_END(head))
+#define	LIST_NEXT(elm, field)		((elm)->field.le_next)
+
+#define LIST_FOREACH(var, head, field)					\
+	for((var) = LIST_FIRST(head);					\
+	    (var)!= LIST_END(head);					\
+	    (var) = LIST_NEXT(var, field))
+
+#define	LIST_FOREACH_SAFE(var, head, field, tvar)			\
+	for ((var) = LIST_FIRST(head);				\
+	    (var) && ((tvar) = LIST_NEXT(var, field), 1);		\
+	    (var) = (tvar))
+
+/*
+ * List functions.
+ */
+#define	LIST_INIT(head) do {						\
+	LIST_FIRST(head) = LIST_END(head);				\
+} while (0)
+
+#define LIST_INSERT_AFTER(listelm, elm, field) do {			\
+	if (((elm)->field.le_next = (listelm)->field.le_next) != NULL)	\
+		(listelm)->field.le_next->field.le_prev =		\
+		    &(elm)->field.le_next;				\
+	(listelm)->field.le_next = (elm);				\
+	(elm)->field.le_prev = &(listelm)->field.le_next;		\
+} while (0)
+
+#define	LIST_INSERT_BEFORE(listelm, elm, field) do {			\
+	(elm)->field.le_prev = (listelm)->field.le_prev;		\
+	(elm)->field.le_next = (listelm);				\
+	*(listelm)->field.le_prev = (elm);				\
+	(listelm)->field.le_prev = &(elm)->field.le_next;		\
+} while (0)
+
+#define LIST_INSERT_HEAD(head, elm, field) do {				\
+	if (((elm)->field.le_next = (head)->lh_first) != NULL)		\
+		(head)->lh_first->field.le_prev = &(elm)->field.le_next;\
+	(head)->lh_first = (elm);					\
+	(elm)->field.le_prev = &(head)->lh_first;			\
+} while (0)
+
+#define LIST_REMOVE(elm, field) do {					\
+	if ((elm)->field.le_next != NULL)				\
+		(elm)->field.le_next->field.le_prev =			\
+		    (elm)->field.le_prev;				\
+	*(elm)->field.le_prev = (elm)->field.le_next;			\
+	_Q_INVALIDATE((elm)->field.le_prev);				\
+	_Q_INVALIDATE((elm)->field.le_next);				\
+} while (0)
+
+#define LIST_REPLACE(elm, elm2, field) do {				\
+	if (((elm2)->field.le_next = (elm)->field.le_next) != NULL)	\
+		(elm2)->field.le_next->field.le_prev =			\
+		    &(elm2)->field.le_next;				\
+	(elm2)->field.le_prev = (elm)->field.le_prev;			\
+	*(elm2)->field.le_prev = (elm2);				\
+	_Q_INVALIDATE((elm)->field.le_prev);				\
+	_Q_INVALIDATE((elm)->field.le_next);				\
+} while (0)
+
+/*
+ * Simple queue definitions.
+ */
+#define SIMPLEQ_HEAD(name, type)					\
+struct name {								\
+	struct type *sqh_first;	/* first element */			\
+	struct type **sqh_last;	/* addr of last next element */		\
+}
+
+#define SIMPLEQ_HEAD_INITIALIZER(head)					\
+	{ NULL, &(head).sqh_first }
+
+#define SIMPLEQ_ENTRY(type)						\
+struct {								\
+	struct type *sqe_next;	/* next element */			\
+}
+
+/*
+ * Simple queue access methods.
+ */
+#define	SIMPLEQ_FIRST(head)	    ((head)->sqh_first)
+#define	SIMPLEQ_END(head)	    NULL
+#define	SIMPLEQ_EMPTY(head)	    (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
+#define	SIMPLEQ_NEXT(elm, field)    ((elm)->field.sqe_next)
+
+#define SIMPLEQ_FOREACH(var, head, field)				\
+	for((var) = SIMPLEQ_FIRST(head);				\
+	    (var) != SIMPLEQ_END(head);					\
+	    (var) = SIMPLEQ_NEXT(var, field))
+
+#define	SIMPLEQ_FOREACH_SAFE(var, head, field, tvar)			\
+	for ((var) = SIMPLEQ_FIRST(head);				\
+	    (var) && ((tvar) = SIMPLEQ_NEXT(var, field), 1);		\
+	    (var) = (tvar))
+
+/*
+ * Simple queue functions.
+ */
+#define	SIMPLEQ_INIT(head) do {						\
+	(head)->sqh_first = NULL;					\
+	(head)->sqh_last = &(head)->sqh_first;				\
+} while (0)
+
+#define SIMPLEQ_INSERT_HEAD(head, elm, field) do {			\
+	if (((elm)->field.sqe_next = (head)->sqh_first) == NULL)	\
+		(head)->sqh_last = &(elm)->field.sqe_next;		\
+	(head)->sqh_first = (elm);					\
+} while (0)
+
+#define SIMPLEQ_INSERT_TAIL(head, elm, field) do {			\
+	(elm)->field.sqe_next = NULL;					\
+	*(head)->sqh_last = (elm);					\
+	(head)->sqh_last = &(elm)->field.sqe_next;			\
+} while (0)
+
+#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do {		\
+	if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
+		(head)->sqh_last = &(elm)->field.sqe_next;		\
+	(listelm)->field.sqe_next = (elm);				\
+} while (0)
+
+#define SIMPLEQ_REMOVE_HEAD(head, field) do {			\
+	if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
+		(head)->sqh_last = &(head)->sqh_first;			\
+} while (0)
+
+#define SIMPLEQ_REMOVE_AFTER(head, elm, field) do {			\
+	if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) \
+	    == NULL)							\
+		(head)->sqh_last = &(elm)->field.sqe_next;		\
+} while (0)
+
+#define SIMPLEQ_CONCAT(head1, head2) do {				\
+	if (!SIMPLEQ_EMPTY((head2))) {					\
+		*(head1)->sqh_last = (head2)->sqh_first;		\
+		(head1)->sqh_last = (head2)->sqh_last;			\
+		SIMPLEQ_INIT((head2));					\
+	}								\
+} while (0)
+
+/*
+ * XOR Simple queue definitions.
+ */
+#define XSIMPLEQ_HEAD(name, type)					\
+struct name {								\
+	struct type *sqx_first;	/* first element */			\
+	struct type **sqx_last;	/* addr of last next element */		\
+	unsigned long sqx_cookie;					\
+}
+
+#define XSIMPLEQ_ENTRY(type)						\
+struct {								\
+	struct type *sqx_next;	/* next element */			\
+}
+
+/*
+ * XOR Simple queue access methods.
+ */
+#define XSIMPLEQ_XOR(head, ptr)	    ((__typeof(ptr))((head)->sqx_cookie ^ \
+					(unsigned long)(ptr)))
+#define	XSIMPLEQ_FIRST(head)	    XSIMPLEQ_XOR(head, ((head)->sqx_first))
+#define	XSIMPLEQ_END(head)	    NULL
+#define	XSIMPLEQ_EMPTY(head)	    (XSIMPLEQ_FIRST(head) == XSIMPLEQ_END(head))
+#define	XSIMPLEQ_NEXT(head, elm, field)    XSIMPLEQ_XOR(head, ((elm)->field.sqx_next))
+
+
+#define XSIMPLEQ_FOREACH(var, head, field)				\
+	for ((var) = XSIMPLEQ_FIRST(head);				\
+	    (var) != XSIMPLEQ_END(head);				\
+	    (var) = XSIMPLEQ_NEXT(head, var, field))
+
+#define	XSIMPLEQ_FOREACH_SAFE(var, head, field, tvar)			\
+	for ((var) = XSIMPLEQ_FIRST(head);				\
+	    (var) && ((tvar) = XSIMPLEQ_NEXT(head, var, field), 1);	\
+	    (var) = (tvar))
+
+/*
+ * XOR Simple queue functions.
+ */
+#define	XSIMPLEQ_INIT(head) do {					\
+	arc4random_buf(&(head)->sqx_cookie, sizeof((head)->sqx_cookie)); \
+	(head)->sqx_first = XSIMPLEQ_XOR(head, NULL);			\
+	(head)->sqx_last = XSIMPLEQ_XOR(head, &(head)->sqx_first);	\
+} while (0)
+
+#define XSIMPLEQ_INSERT_HEAD(head, elm, field) do {			\
+	if (((elm)->field.sqx_next = (head)->sqx_first) ==		\
+	    XSIMPLEQ_XOR(head, NULL))					\
+		(head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
+	(head)->sqx_first = XSIMPLEQ_XOR(head, (elm));			\
+} while (0)
+
+#define XSIMPLEQ_INSERT_TAIL(head, elm, field) do {			\
+	(elm)->field.sqx_next = XSIMPLEQ_XOR(head, NULL);		\
+	*(XSIMPLEQ_XOR(head, (head)->sqx_last)) = XSIMPLEQ_XOR(head, (elm)); \
+	(head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next);	\
+} while (0)
+
+#define XSIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do {		\
+	if (((elm)->field.sqx_next = (listelm)->field.sqx_next) ==	\
+	    XSIMPLEQ_XOR(head, NULL))					\
+		(head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
+	(listelm)->field.sqx_next = XSIMPLEQ_XOR(head, (elm));		\
+} while (0)
+
+#define XSIMPLEQ_REMOVE_HEAD(head, field) do {				\
+	if (((head)->sqx_first = XSIMPLEQ_XOR(head,			\
+	    (head)->sqx_first)->field.sqx_next) == XSIMPLEQ_XOR(head, NULL)) \
+		(head)->sqx_last = XSIMPLEQ_XOR(head, &(head)->sqx_first); \
+} while (0)
+
+#define XSIMPLEQ_REMOVE_AFTER(head, elm, field) do {			\
+	if (((elm)->field.sqx_next = XSIMPLEQ_XOR(head,			\
+	    (elm)->field.sqx_next)->field.sqx_next)			\
+	    == XSIMPLEQ_XOR(head, NULL))				\
+		(head)->sqx_last = 					\
+		    XSIMPLEQ_XOR(head, &(elm)->field.sqx_next);		\
+} while (0)
+
+
+/*
+ * Tail queue definitions.
+ */
+#define TAILQ_HEAD(name, type)						\
+struct name {								\
+	struct type *tqh_first;	/* first element */			\
+	struct type **tqh_last;	/* addr of last next element */		\
+}
+
+#define TAILQ_HEAD_INITIALIZER(head)					\
+	{ NULL, &(head).tqh_first }
+
+#define TAILQ_ENTRY(type)						\
+struct {								\
+	struct type *tqe_next;	/* next element */			\
+	struct type **tqe_prev;	/* address of previous next element */	\
+}
+
+/*
+ * Tail queue access methods.
+ */
+#define	TAILQ_FIRST(head)		((head)->tqh_first)
+#define	TAILQ_END(head)			NULL
+#define	TAILQ_NEXT(elm, field)		((elm)->field.tqe_next)
+#define TAILQ_LAST(head, headname)					\
+	(*(((struct headname *)((head)->tqh_last))->tqh_last))
+/* XXX */
+#define TAILQ_PREV(elm, headname, field)				\
+	(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+#define	TAILQ_EMPTY(head)						\
+	(TAILQ_FIRST(head) == TAILQ_END(head))
+
+#define TAILQ_FOREACH(var, head, field)					\
+	for((var) = TAILQ_FIRST(head);					\
+	    (var) != TAILQ_END(head);					\
+	    (var) = TAILQ_NEXT(var, field))
+
+#define	TAILQ_FOREACH_SAFE(var, head, field, tvar)			\
+	for ((var) = TAILQ_FIRST(head);					\
+	    (var) != TAILQ_END(head) &&					\
+	    ((tvar) = TAILQ_NEXT(var, field), 1);			\
+	    (var) = (tvar))
+
+
+#define TAILQ_FOREACH_REVERSE(var, head, headname, field)		\
+	for((var) = TAILQ_LAST(head, headname);				\
+	    (var) != TAILQ_END(head);					\
+	    (var) = TAILQ_PREV(var, headname, field))
+
+#define	TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar)	\
+	for ((var) = TAILQ_LAST(head, headname);			\
+	    (var) != TAILQ_END(head) &&					\
+	    ((tvar) = TAILQ_PREV(var, headname, field), 1);		\
+	    (var) = (tvar))
+
+/*
+ * Tail queue functions.
+ */
+#define	TAILQ_INIT(head) do {						\
+	(head)->tqh_first = NULL;					\
+	(head)->tqh_last = &(head)->tqh_first;				\
+} while (0)
+
+#define TAILQ_INSERT_HEAD(head, elm, field) do {			\
+	if (((elm)->field.tqe_next = (head)->tqh_first) != NULL)	\
+		(head)->tqh_first->field.tqe_prev =			\
+		    &(elm)->field.tqe_next;				\
+	else								\
+		(head)->tqh_last = &(elm)->field.tqe_next;		\
+	(head)->tqh_first = (elm);					\
+	(elm)->field.tqe_prev = &(head)->tqh_first;			\
+} while (0)
+
+#define TAILQ_INSERT_TAIL(head, elm, field) do {			\
+	(elm)->field.tqe_next = NULL;					\
+	(elm)->field.tqe_prev = (head)->tqh_last;			\
+	*(head)->tqh_last = (elm);					\
+	(head)->tqh_last = &(elm)->field.tqe_next;			\
+} while (0)
+
+#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do {		\
+	if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
+		(elm)->field.tqe_next->field.tqe_prev =			\
+		    &(elm)->field.tqe_next;				\
+	else								\
+		(head)->tqh_last = &(elm)->field.tqe_next;		\
+	(listelm)->field.tqe_next = (elm);				\
+	(elm)->field.tqe_prev = &(listelm)->field.tqe_next;		\
+} while (0)
+
+#define	TAILQ_INSERT_BEFORE(listelm, elm, field) do {			\
+	(elm)->field.tqe_prev = (listelm)->field.tqe_prev;		\
+	(elm)->field.tqe_next = (listelm);				\
+	*(listelm)->field.tqe_prev = (elm);				\
+	(listelm)->field.tqe_prev = &(elm)->field.tqe_next;		\
+} while (0)
+
+#define TAILQ_REMOVE(head, elm, field) do {				\
+	if (((elm)->field.tqe_next) != NULL)				\
+		(elm)->field.tqe_next->field.tqe_prev =			\
+		    (elm)->field.tqe_prev;				\
+	else								\
+		(head)->tqh_last = (elm)->field.tqe_prev;		\
+	*(elm)->field.tqe_prev = (elm)->field.tqe_next;			\
+	_Q_INVALIDATE((elm)->field.tqe_prev);				\
+	_Q_INVALIDATE((elm)->field.tqe_next);				\
+} while (0)
+
+#define TAILQ_REPLACE(head, elm, elm2, field) do {			\
+	if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL)	\
+		(elm2)->field.tqe_next->field.tqe_prev =		\
+		    &(elm2)->field.tqe_next;				\
+	else								\
+		(head)->tqh_last = &(elm2)->field.tqe_next;		\
+	(elm2)->field.tqe_prev = (elm)->field.tqe_prev;			\
+	*(elm2)->field.tqe_prev = (elm2);				\
+	_Q_INVALIDATE((elm)->field.tqe_prev);				\
+	_Q_INVALIDATE((elm)->field.tqe_next);				\
+} while (0)
+
+#define TAILQ_CONCAT(head1, head2, field) do {				\
+	if (!TAILQ_EMPTY(head2)) {					\
+		*(head1)->tqh_last = (head2)->tqh_first;		\
+		(head2)->tqh_first->field.tqe_prev = (head1)->tqh_last;	\
+		(head1)->tqh_last = (head2)->tqh_last;			\
+		TAILQ_INIT((head2));					\
+	}								\
+} while (0)
+
+/*
+ * Singly-linked Tail queue declarations.
+ */
+#define	STAILQ_HEAD(name, type)						\
+struct name {								\
+	struct type *stqh_first;	/* first element */		\
+	struct type **stqh_last;	/* addr of last next element */	\
+}
+
+#define	STAILQ_HEAD_INITIALIZER(head)					\
+	{ NULL, &(head).stqh_first }
+
+#define	STAILQ_ENTRY(type)						\
+struct {								\
+	struct type *stqe_next;	/* next element */			\
+}
+
+/*
+ * Singly-linked Tail queue access methods.
+ */
+#define	STAILQ_FIRST(head)	((head)->stqh_first)
+#define	STAILQ_END(head)	NULL
+#define	STAILQ_EMPTY(head)	(STAILQ_FIRST(head) == STAILQ_END(head))
+#define	STAILQ_NEXT(elm, field)	((elm)->field.stqe_next)
+
+#define STAILQ_FOREACH(var, head, field)				\
+	for ((var) = STAILQ_FIRST(head);				\
+	    (var) != STAILQ_END(head);					\
+	    (var) = STAILQ_NEXT(var, field))
+
+#define	STAILQ_FOREACH_SAFE(var, head, field, tvar)			\
+	for ((var) = STAILQ_FIRST(head);				\
+	    (var) && ((tvar) = STAILQ_NEXT(var, field), 1);		\
+	    (var) = (tvar))
+
+/*
+ * Singly-linked Tail queue functions.
+ */
+#define	STAILQ_INIT(head) do {						\
+	STAILQ_FIRST((head)) = NULL;					\
+	(head)->stqh_last = &STAILQ_FIRST((head));			\
+} while (0)
+
+#define	STAILQ_INSERT_HEAD(head, elm, field) do {			\
+	if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL)	\
+		(head)->stqh_last = &STAILQ_NEXT((elm), field);		\
+	STAILQ_FIRST((head)) = (elm);					\
+} while (0)
+
+#define	STAILQ_INSERT_TAIL(head, elm, field) do {			\
+	STAILQ_NEXT((elm), field) = NULL;				\
+	*(head)->stqh_last = (elm);					\
+	(head)->stqh_last = &STAILQ_NEXT((elm), field);			\
+} while (0)
+
+#define	STAILQ_INSERT_AFTER(head, listelm, elm, field) do {		\
+	if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((elm), field)) == NULL)\
+		(head)->stqh_last = &STAILQ_NEXT((elm), field);		\
+	STAILQ_NEXT((elm), field) = (elm);				\
+} while (0)
+
+#define STAILQ_REMOVE_HEAD(head, field) do {                            \
+	if ((STAILQ_FIRST((head)) =					\
+	    STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL)		\
+		(head)->stqh_last = &STAILQ_FIRST((head));		\
+} while (0)
+
+#define STAILQ_REMOVE_AFTER(head, elm, field) do {                      \
+	if ((STAILQ_NEXT(elm, field) =					\
+	    STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL)	\
+		(head)->stqh_last = &STAILQ_NEXT((elm), field);		\
+} while (0)
+
+#define	STAILQ_REMOVE(head, elm, type, field) do {			\
+	if (STAILQ_FIRST((head)) == (elm)) {				\
+		STAILQ_REMOVE_HEAD((head), field);			\
+	} else {							\
+		struct type *curelm = (head)->stqh_first;		\
+		while (STAILQ_NEXT(curelm, field) != (elm))		\
+			curelm = STAILQ_NEXT(curelm, field);		\
+		STAILQ_REMOVE_AFTER(head, curelm, field);		\
+	}								\
+} while (0)
+
+#define	STAILQ_CONCAT(head1, head2) do {				\
+	if (!STAILQ_EMPTY((head2))) {					\
+		*(head1)->stqh_last = (head2)->stqh_first;		\
+		(head1)->stqh_last = (head2)->stqh_last;		\
+		STAILQ_INIT((head2));					\
+	}								\
+} while (0)
+
+#define	STAILQ_LAST(head, type, field)					\
+	(STAILQ_EMPTY((head)) ?	NULL :					\
+	        ((struct type *)(void *)				\
+		((char *)((head)->stqh_last) - offsetof(struct type, field))))
+
+#endif	/* !_SYS_QUEUE_H_ */
blob - /dev/null
blob + edd3117b9e9802fc1c80378cf86ad3ffb7b9016e (mode 644)
--- /dev/null
+++ primitive.h
@@ -0,0 +1,20 @@
+#ifndef PRIMITIVE_H
+#define PRIMITIVE_H
+
+enum primitive_type {
+	PRIMITIVE_TYPE_RECTANGLE,
+	PRIMITIVE_TYPE_TEXT,
+	PRIMITIVE_TYPE_ARC,
+	PRIMITIVE_TYPE_BITMAP,
+	PRIMITIVE_TYPE_IMAGE,
+	PRIMITIVE_TYPE_LINE,
+	PRIMITIVE_TYPE_OVAL,
+	PRIMITIVE_TYPE_POLYGON,
+	PRIMITIVE_TYPE_WINDOW,
+};
+
+struct primitive {
+	unsigned int type;
+};
+
+#endif
blob - /dev/null
blob + c000b893c06f2f505578722d812040afc3387238 (mode 644)
--- /dev/null
+++ ui.c
@@ -0,0 +1,158 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "event.h"
+#include "driver.h"
+#include "widget.h"
+#include "layout.h"
+
+struct aui_event_queue ev_queue;
+
+void
+aui_add_event(struct aui_event *event)
+{
+	struct aui_event *toadd;
+
+	switch (event->type) {
+	case AUI_EVENT_QUIT: {
+		struct aui_event_quit *qev = calloc(1, sizeof(struct aui_event_quit));
+		memcpy((void *)qev, event, sizeof(struct aui_event_quit));
+
+		toadd = &qev->event;
+		break;
+	}
+	case AUI_EVENT_RESIZE: {
+		struct aui_event_resize *erz = calloc(1, sizeof(struct aui_event_resize));
+		memcpy((void *)erz, event, sizeof(struct aui_event_resize));
+
+		/*
+		printf("libaui: resize %dx%d => %dx%d\n", erz->old_w, erz->old_h, erz->new_w, erz->new_h);
+		*/
+
+		toadd = &erz->event;
+		break;
+	}
+	case AUI_EVENT_MOUSE_MOTION: {
+		struct aui_event_mouse_motion *mev = calloc(1, sizeof(struct aui_event_mouse_motion));
+		memcpy((void *)mev, event, sizeof(struct aui_event_mouse_motion));
+
+		toadd = &mev->event;
+		break;
+	}
+	case AUI_EVENT_MOUSE_PRESS: {
+		struct aui_event_mouse_press *mpe = calloc(1, sizeof(struct aui_event_mouse_press));
+		memcpy((void *)mpe, event, sizeof(struct aui_event_mouse_press));
+
+		toadd = &mpe->event;
+		break;
+	}
+	case AUI_EVENT_MOUSE_RELEASE: {
+		struct aui_event_mouse_release *mre = calloc(1, sizeof(struct aui_event_mouse_release));
+		memcpy((void *)mre, event, sizeof(struct aui_event_mouse_release));
+
+		toadd = &mre->event;
+		break;
+	}
+	default:
+		fprintf(stderr, "libaui: failed to add event\n");
+		return;
+	}
+
+	TAILQ_INSERT_TAIL(&ev_queue, toadd, entries);
+}
+
+void
+aui_run(void)
+{
+	while (!LIST_EMPTY(&wlist)) {
+		driver->ops->handle_events();
+
+		/*
+		 * Event Management
+		 */
+		struct aui_event *ev;
+		while (!TAILQ_EMPTY(&ev_queue)) {
+			ev = TAILQ_FIRST(&ev_queue);
+			TAILQ_REMOVE(&ev_queue, ev, entries);
+
+			switch (ev->type) {
+			case AUI_EVENT_QUIT: {
+				struct aui_event_quit *qev = (struct aui_event_quit *)ev;
+				struct aui_window *aw = ev->aw;
+				struct aui_widget *ww = (struct aui_widget *)aw;
+
+				ww->ops->free(ww);
+
+				free((void *)qev);
+				break;
+			}
+			case AUI_EVENT_RESIZE: {
+				struct aui_event_resize *rze = (struct aui_event_resize *)ev;
+				struct aui_window *aw = ev->aw;
+
+				aw->config.width = rze->new_w;
+				aw->config.height = rze->new_h;
+
+				driver->ops->resize_window(aw);
+				free((void *)rze);
+
+				layout_organize((struct aui_widget *)aw);
+				break;
+			}
+			case AUI_EVENT_MOUSE_MOTION: {
+				struct aui_event_mouse_motion *mev = (struct aui_event_mouse_motion *)ev;
+				struct aui_window *aw = ev->aw;
+				struct aui_widget *ww = (struct aui_widget *)aw;
+				struct widget_ops *ops = ww->ops;
+
+				ops->mouse_hover(ww, mev->x, mev->y);
+				free((void *)mev);
+				break;
+			}
+			case AUI_EVENT_MOUSE_PRESS: {
+				struct aui_event_mouse_press *mpe = (struct aui_event_mouse_press *)ev;
+				struct aui_window *aw = ev->aw;
+				struct aui_widget *ww = (struct aui_widget *)aw;
+				struct widget_ops *ops = ww->ops;
+
+				ops->mouse_press(ww, mpe->x, mpe->y, mpe->button);
+				free((void *)mpe);
+				break;
+			}
+			case AUI_EVENT_MOUSE_RELEASE: {
+				struct aui_event_mouse_release *mre = (struct aui_event_mouse_release *)ev;
+				struct aui_window *aw = ev->aw;
+				struct aui_widget *ww = (struct aui_widget *)aw;
+				struct widget_ops *ops = ww->ops;
+
+				ops->mouse_release(ww, mre->x, mre->y, mre->button);
+				free((void *)mre);
+				break;
+			}
+			default:
+				break;
+			}
+		}
+
+		/*
+		 * Draw Calls
+		 */
+		struct aui_window *aw;
+		LIST_FOREACH(aw, &wlist, entries) {
+			if (aw->draw_flag) {
+				struct aui_widget *widget = (struct aui_widget *)aw;
+				driver->ops->render_background(aw);
+				widget_draw(widget);
+				driver->ops->render_foreground(aw);
+				aw->draw_flag = 0;
+			}
+		}
+	}
+}
+
+void
+aui_destroy(struct aui_widget *widget)
+{
+	widget->ops->free(widget);
+}
blob - /dev/null
blob + a75e978fa3653449f0abf805f3abdfdfd0a5cea3 (mode 644)
--- /dev/null
+++ widget.c
@@ -0,0 +1,102 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "driver.h"
+#include "widget.h"
+#include "primitive.h"
+
+void
+widget_init(struct aui_widget *widget, unsigned int type, struct widget_ops *ops)
+{
+	TAILQ_INIT(&(widget)->queue);
+	widget->geom = (struct aui_geometry) { 0 };
+	widget->mapped = 0;
+
+	memset(&widget->placepar, 0, sizeof(struct aui_placepar));
+	memset(&widget->gridpar, 0, sizeof(struct aui_gridpar));
+	memset(&widget->packpar, 0, sizeof(struct aui_packpar));
+
+	widget->type = type;
+	widget->ops = ops;
+}
+
+void
+widget_add(struct aui_widget *parent, struct aui_widget *child)
+{
+	child->parent = parent;
+	child->window = parent->window;
+	TAILQ_INSERT_TAIL(&parent->queue, child, entries);
+}
+
+void
+widget_lead(struct aui_widget *parent, struct aui_widget *child)
+{
+	TAILQ_REMOVE(&parent->queue, child, entries);
+	TAILQ_INSERT_TAIL(&parent->queue, child, entries);
+}
+
+void
+widget_remove(struct aui_widget *parent, struct aui_widget *child)
+{
+	TAILQ_REMOVE(&parent->queue, child, entries);
+}
+
+void
+widget_draw(struct aui_widget *widget)
+{
+	if (widget->mapped == 0)
+		return;
+
+	struct primitive *prim;
+
+	if (widget->geom.width == 0 || widget->geom.height == 0)
+		return;
+
+	for (int i = 0; i < widget->primitives.count; i++) {
+		prim = widget->primitives.list[i];
+
+		switch (prim->type) {
+		case PRIMITIVE_TYPE_RECTANGLE:
+			driver->ops->render_rectangle(widget->window, prim);
+			break;
+		case PRIMITIVE_TYPE_TEXT:
+			driver->ops->render_text(widget->window, prim);
+			break;
+		default:
+			break;
+		}
+	}
+
+	if (widget->type == WIDGET_TYPE_CANVAS) {
+		struct aui_canvas *canvas = (struct aui_canvas *)widget;
+		struct aui_canvas_item *item;
+
+		TAILQ_FOREACH(item, &canvas->queue, entries) {
+			struct primitive *prim;
+			for (int i = 0; i < item->primitives.count; i++) {
+				prim = item->primitives.list[i];
+
+				switch (prim->type) {
+				case PRIMITIVE_TYPE_RECTANGLE:
+					driver->ops->render_rectangle(widget->window, prim);
+					break;
+				default:
+					break;
+				}
+			}
+		}
+	}
+
+	struct aui_widget *child;
+	TAILQ_FOREACH(child, &widget->queue, entries) {
+		widget_draw(child);
+	}
+}
+
+int
+widget_collides_with_point(struct aui_widget *widget, uint16_t x, uint16_t y)
+{
+	return (x >= widget->geom.x && x < (widget->geom.x + widget->geom.width) &&
+			y >= widget->geom.y && y < (widget->geom.y + widget->geom.height));
+}
blob - /dev/null
blob + ff0077c16e3465ac05c6d6ec98065e4f0a6f14ba (mode 644)
--- /dev/null
+++ widget.h
@@ -0,0 +1,132 @@
+#ifndef __WIDGET_H__
+#define __WIDGET_H__
+
+#include "openbsd-queue.h"
+
+#include "layout.h"
+
+/*
+ * Gives screen position
+ */
+struct aui_geometry {
+	int x, y;
+	uint16_t width;
+	uint16_t height;
+};
+
+enum widget_type {
+	WIDGET_TYPE_WINDOW,
+	WIDGET_TYPE_FRAME,
+	WIDGET_TYPE_CANVAS,
+	WIDGET_TYPE_BUTTON,
+	WIDGET_TYPE_LABEL,
+};
+
+struct widget_primitives {
+	unsigned int count;
+	struct primitive **list;
+};
+
+TAILQ_HEAD(aui_widget_queue, aui_widget);
+struct aui_widget {
+	enum widget_type type;
+	struct aui_geometry geom;
+
+	struct aui_window *window;
+	struct widget_ops *ops;
+
+	struct aui_placepar placepar;
+	struct aui_gridpar gridpar;
+	struct aui_packpar packpar;
+	struct aui_geometry packarea;
+
+	unsigned int mapped;
+	struct widget_primitives primitives;
+
+	struct aui_widget *parent;
+	struct aui_widget_queue queue;
+	TAILQ_ENTRY(aui_widget) entries;
+};
+
+struct widget_ops {
+	void (*mouse_hover) (struct aui_widget *, uint16_t, uint16_t);
+	void (*mouse_unhover) (struct aui_widget *);
+	void (*mouse_press) (struct aui_widget *, uint16_t, uint16_t, uint8_t);
+	void (*mouse_release) (struct aui_widget *, uint16_t, uint16_t, uint8_t);
+	void (*set_geometry) (struct aui_widget *, struct aui_geometry *);
+	void (*free) (struct aui_widget *);
+	struct aui_geometry (*get_min_size) (struct aui_widget *);
+};
+
+struct aui_container {
+	struct aui_widget widget;
+	enum aui_layout_type layout_type;
+	unsigned int map_count;
+
+	/*
+	 * Grid members
+	 */
+	uint8_t *row_maps;
+	uint8_t *col_maps;
+	uint32_t grid_size[2];
+	unsigned int *row_sizes;
+	unsigned int *col_sizes;
+	unsigned int *row_pos;
+	unsigned int *col_pos;
+	struct aui_rowpar *rowconfigure;
+	struct aui_columnpar *columnconfigure;
+
+	struct container_focus {
+		struct aui_widget *press;
+		struct aui_widget *hover;
+	} focus;
+};
+
+LIST_HEAD(aui_window_list, aui_window);
+struct aui_window {
+	struct aui_container con;
+	const char *title;
+	int draw_flag;
+	struct aui_window_config config;
+
+	LIST_ENTRY(aui_window) entries;
+};
+
+struct aui_frame {
+	struct aui_container con;
+	struct aui_frame_config config;
+};
+
+struct aui_canvas_item {
+	unsigned int type;
+	struct widget_primitives primitives;
+	struct aui_canvas_item_config config;
+	TAILQ_ENTRY(aui_canvas_item) entries;
+};
+
+struct aui_canvas {
+	struct aui_container con;
+	TAILQ_HEAD(aui_canvas_item_queue, aui_canvas_item) queue;
+};
+
+struct aui_button {
+	struct aui_widget widget;
+	unsigned int pressed;
+	struct aui_button_config config;
+};
+
+struct aui_label {
+	struct aui_widget widget;
+	struct aui_label_config config;
+};
+
+extern struct aui_window_list wlist;
+
+void widget_init(struct aui_widget*, unsigned int, struct widget_ops*);
+void widget_draw(struct aui_widget *);
+void widget_add(struct aui_widget *, struct aui_widget *);
+void widget_remove(struct aui_widget *, struct aui_widget *);
+void widget_lead(struct aui_widget *, struct aui_widget *);
+int widget_collides_with_point(struct aui_widget*, uint16_t, uint16_t);
+
+#endif
blob - /dev/null
blob + 74f2f8e5ae9aa2bff600fc5eb5a2fe98da520864 (mode 644)
--- /dev/null
+++ window.c
@@ -0,0 +1,145 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "event.h"
+#include "driver.h"
+#include "widget.h"
+
+struct aui_window_list wlist;
+
+static void window_mouse_hover(struct aui_widget *, uint16_t, uint16_t);
+static void window_mouse_unhover(struct aui_widget *);
+static void window_mouse_press(struct aui_widget *, uint16_t, uint16_t, uint8_t);
+static void window_mouse_release(struct aui_widget *, uint16_t, uint16_t, uint8_t);
+static void window_free(struct aui_widget *);
+static struct aui_geometry window_get_min_size(struct aui_widget *);
+
+static struct widget_ops window_ops = {
+	window_mouse_hover,
+	window_mouse_unhover,
+	window_mouse_press,
+	window_mouse_release,
+	NULL, /* set geomtry */
+	window_free,
+	window_get_min_size,
+};
+
+static struct aui_window_config default_config = {
+	.width =	200,
+	.height =   200,
+	.title =   "aui",
+};
+
+struct aui_window*
+aui_window_new(struct aui_window_config *config)
+{
+	if (driver == NULL) {
+		if (driver_open(DRIVER_TYPE_X11) == -1) {
+			return NULL;
+		}
+		TAILQ_INIT(&ev_queue);
+		LIST_INIT(&wlist);
+	}
+
+	if (config == NULL) {
+		config = &default_config;
+	}
+
+	struct aui_window *aw = driver->ops->create_window(config);
+	struct aui_widget *widget = (struct aui_widget *)aw;
+	struct aui_container *con = (struct aui_container *)aw;
+	con->map_count = 0;
+
+	LIST_INSERT_HEAD(&wlist, aw, entries);
+	widget_init(widget, WIDGET_TYPE_WINDOW, &window_ops);
+
+	widget->mapped = 1;
+
+	widget->window = aw;
+	aw->draw_flag = 1;
+	return aw;
+}
+
+void
+window_free(struct aui_widget *widget)
+{
+	struct aui_window *aw = (struct aui_window *)widget;
+
+	LIST_REMOVE(aw, entries);
+	driver->ops->delete_window(aw);
+}
+
+static void
+window_mouse_hover(struct aui_widget *widget, uint16_t x, uint16_t y)
+{
+	struct aui_window *aw = (struct aui_window *)widget;
+	struct aui_container *con = (struct aui_container *)widget;
+	struct aui_widget *tohover = NULL;
+	struct aui_widget *child;
+
+	TAILQ_FOREACH(child, &widget->queue, entries) {
+		if (child->mapped && widget_collides_with_point(child, x, y))
+			tohover = child;
+	}
+
+	if (tohover != con->focus.hover && con->focus.hover != NULL)
+		con->focus.hover->ops->mouse_unhover(con->focus.hover);
+
+	con->focus.hover = tohover;
+
+	if (tohover != NULL)
+		tohover->ops->mouse_hover(tohover, x, y);
+}
+
+static void
+window_mouse_unhover(struct aui_widget *widget)
+{
+
+}
+
+static void 
+window_mouse_press(struct aui_widget *widget, uint16_t x, uint16_t y, uint8_t button)
+{
+	struct aui_container *con = (struct aui_container *)widget;
+	struct aui_window *aw = (struct aui_window *)widget;
+	struct aui_widget *topress = NULL;
+	struct aui_widget *child;
+
+	TAILQ_FOREACH(child, &widget->queue, entries) {
+		if (child->mapped && widget_collides_with_point(child, x, y))
+			topress = child;
+	}
+
+	if (topress != con->focus.press && con->focus.press != NULL)
+		con->focus.press->ops->mouse_release(con->focus.press, x, y, button);
+
+	con->focus.press = topress;
+
+	if (topress != NULL)
+		topress->ops->mouse_press(topress, x, y, button);
+}
+
+static void 
+window_mouse_release(struct aui_widget *widget, uint16_t x, uint16_t y, uint8_t button)
+{
+	struct aui_container *con = (struct aui_container *)widget;
+	struct aui_window *aw = (struct aui_window *)widget;
+
+	if (con->focus.press != NULL) {
+		con->focus.press->ops->mouse_release(con->focus.press, x, y, button);
+		con->focus.press = NULL;
+
+		window_mouse_hover(widget, x, y);
+	}
+}
+
+static struct aui_geometry
+window_get_min_size(struct aui_widget *widget)
+{
+	struct aui_window *aw = (struct aui_window *)widget;
+	struct aui_geometry geom = { 0 };
+	geom.width = aw->config.width;
+	geom.height = aw->config.height;
+	return geom;
+}
blob - /dev/null
blob + 0f60d614d1ab3cdf8e93ef5c6f4847f6b2e912e1 (mode 644)
--- /dev/null
+++ xcb.c
@@ -0,0 +1,751 @@
+#include <poll.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <xcb/xcb.h>
+#include <xcb/render.h>
+
+#include "font.h"
+#include "event.h"
+#include "driver.h"
+#include "widget.h"
+#include "primitive.h"
+
+struct aui_dri_xcb {
+	struct aui_dri adr;
+
+	struct pollfd pollfd; /* One reason, POSIX */
+
+	xcb_connection_t *conn;
+	xcb_screen_t *screen;
+	xcb_intern_atom_reply_t *wm_protocols;
+	xcb_intern_atom_reply_t *wm_delete_window;
+
+	xcb_render_glyphset_t glyphset;
+	struct glyph *glyphs;
+	int font_height;
+	xcb_render_pictformat_t fmt_normal;
+	xcb_render_pictformat_t fmt_alpha8;
+	xcb_render_pictformat_t fmt_argb32;
+};
+
+struct aui_window_xcb {
+	struct aui_window aw;
+
+	xcb_window_t xw;
+	xcb_pixmap_t pixmap;
+	xcb_render_picture_t dst_pict;
+	xcb_render_picture_t src_pict;
+};
+
+struct aui_dri *driver;
+
+static struct aui_window *aui_dri_create_window(struct aui_window_config *);
+static void aui_dri_delete_window(struct aui_window *);
+static void aui_dri_handle_events(void);
+static void aui_dri_resize_window(struct aui_window *);
+static void aui_dri_render_background(struct aui_window *);
+static void aui_dri_render_foreground(struct aui_window *);
+
+static struct primitive *aui_dri_create_rectangle(void);
+static void aui_dri_delete_rectangle(struct primitive *);
+static void aui_dri_render_rectangle(struct aui_window *, struct primitive *);
+static void aui_dri_set_rectangle_color(struct aui_window *, struct primitive *, struct aui_color *);
+static void aui_dri_set_rectangle_geometry(struct aui_window *, struct primitive *, 
+	struct aui_geometry *);
+
+static struct primitive *aui_dri_create_text(void);
+static void aui_dri_set_text(struct primitive *, const char *, int16_t, int16_t);
+static void aui_dri_set_text_color(struct primitive*, struct aui_color*);
+static void aui_dri_render_text(struct aui_window *, struct primitive *);
+static struct aui_geometry aui_dri_get_text_geometry(struct primitive *);
+
+struct aui_dri_canvas {
+	struct aui_canvas can;
+};
+
+static struct dri_ops aui_dri_ops = {
+	aui_dri_create_window,
+	aui_dri_delete_window,
+	aui_dri_handle_events,
+	aui_dri_resize_window,
+	aui_dri_render_background,
+	aui_dri_render_foreground,
+
+	aui_dri_create_rectangle,
+	aui_dri_delete_rectangle,
+	aui_dri_render_rectangle,
+	aui_dri_set_rectangle_color,
+	aui_dri_set_rectangle_geometry,
+
+	aui_dri_create_text,
+	aui_dri_set_text,
+	aui_dri_set_text_color,
+	aui_dri_render_text,
+	aui_dri_get_text_geometry
+};
+
+struct rectangle {
+	struct primitive base;
+	xcb_rectangle_t xrect;
+	xcb_render_color_t xcolor;
+};
+
+struct text {
+	struct primitive base;
+	const char *data; /* Not allocated, pointer to string literal */
+	xcb_render_color_t xcolor;
+	xcb_render_picture_t xpict;
+	int16_t x, y;
+};
+
+static int config_xcb(struct aui_dri_xcb*);
+static void set_pixmap_xcb(struct aui_window_xcb *);
+static struct aui_window_xcb *find_window_xcb(xcb_window_t);
+static void set_name_xcb(struct aui_window_xcb *, const char *);
+
+int
+xcb_driver_open(void)
+{
+	struct aui_dri_xcb *dri_xcb;
+
+	dri_xcb = malloc(sizeof(struct aui_dri_xcb));
+	if (dri_xcb == NULL)
+		return -1;
+
+	/* Setting up the driver */
+	dri_xcb->adr.ops = &aui_dri_ops;
+	driver = &dri_xcb->adr;
+
+	if (config_xcb(dri_xcb) == -1)
+		return -1;
+
+
+	dri_xcb->font_height = 0;
+	dri_xcb->glyphs = calloc(126, sizeof(struct glyph));
+	for (int i = 32; i < 127; i++) dri_xcb->glyphs[i].charcode = i;
+
+	font_init();
+	font_load_glyphs(dri_xcb->glyphs + 32, 127 - 32);
+
+	dri_xcb->glyphset = xcb_generate_id(dri_xcb->conn);
+	xcb_render_create_glyph_set(dri_xcb->conn, dri_xcb->glyphset, dri_xcb->fmt_alpha8);
+
+	for (int i = 0; i < (127 - 32); i++) {
+		uint32_t glyphid = 32 + i;
+		struct glyph *g = &dri_xcb->glyphs[i + 32];
+		xcb_render_glyphinfo_t ginfo = {
+			.width = g->width,
+			.height = g->height,
+			.x = g->x,
+			.y = g->y,
+			.x_off = g->x_offset,
+			.y_off = 0, /* We are only rendering horizontaly. This is unecessary */
+		};
+
+		xcb_render_add_glyphs(
+			dri_xcb->conn,
+			dri_xcb->glyphset,
+			1,
+			&glyphid,
+			&ginfo,
+			g->stride * g->height,
+			g->bitmap
+		);
+
+		if (dri_xcb->font_height < g->y_offset)
+			dri_xcb->font_height = g->y_offset;
+	}
+
+	return 0;
+}
+
+static struct aui_window
+*aui_dri_create_window(struct aui_window_config *config)
+{
+	struct aui_window_xcb *aw_xcb;
+	struct aui_dri_xcb *dri_xcb;
+	struct aui_window *aw;
+
+	aw_xcb = calloc(1, sizeof(struct aui_window_xcb));
+
+	if (aw_xcb == NULL)
+		return NULL;
+
+	dri_xcb = (struct aui_dri_xcb*)driver;
+	aw = &aw_xcb->aw;
+
+
+	int mask = XCB_CW_BACK_PIXMAP | XCB_CW_EVENT_MASK;
+	uint32_t values[2] = {XCB_NONE,
+		XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY |
+		XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE |
+		XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_BUTTON_PRESS|
+		XCB_EVENT_MASK_BUTTON_RELEASE};
+
+	aw_xcb->xw = xcb_generate_id(dri_xcb->conn);
+	xcb_create_window(dri_xcb->conn,
+					  XCB_COPY_FROM_PARENT,
+					  aw_xcb->xw,
+					  dri_xcb->screen->root,
+					  0, 0,
+					  config->width, config->height,
+					  0,
+					  XCB_WINDOW_CLASS_INPUT_OUTPUT,
+					  dri_xcb->screen->root_visual,
+					  mask, values);
+
+	xcb_atom_t data[] = { dri_xcb->wm_delete_window->atom };
+	xcb_change_property(dri_xcb->conn,
+						XCB_PROP_MODE_REPLACE,
+						aw_xcb->xw,
+						dri_xcb->wm_protocols->atom,
+						XCB_ATOM_ATOM, 
+						32, 
+						1,
+						(const void *)data);
+
+	struct aui_widget *ww = (struct aui_widget *)aw;
+	ww->geom.width = config->width;
+	ww->geom.height = config->height;
+	set_pixmap_xcb(aw_xcb);
+	set_name_xcb(aw_xcb, config->title);
+	xcb_map_window(dri_xcb->conn, aw_xcb->xw);
+	xcb_flush(dri_xcb->conn);
+	return aw;
+}
+
+static void
+aui_dri_delete_window(struct aui_window *aw)
+{
+	struct aui_window_xcb *aw_xcb;
+	struct aui_dri_xcb *dri_xcb;
+
+	dri_xcb = (struct aui_dri_xcb *)driver;
+	aw_xcb = (struct aui_window_xcb *)aw;
+
+	xcb_destroy_window(dri_xcb->conn, aw_xcb->xw);
+	free(aw_xcb);
+	xcb_flush(dri_xcb->conn);
+}
+
+/*
+ * Formats event sent by xcb into aui events
+ */
+static void
+aui_dri_handle_events()
+{
+	struct aui_dri_xcb *dri_xcb;
+	xcb_generic_event_t *event;
+	struct aui_window_xcb *aw_xcb;
+	struct aui_window *aw;
+	struct aui_widget *ww;
+	xcb_expose_event_t *exe;
+	xcb_motion_notify_event_t *mne;
+	xcb_client_message_event_t *cme;
+	xcb_configure_notify_event_t *cne;
+	xcb_button_press_event_t *bpe;
+	xcb_button_release_event_t *bre;
+
+	dri_xcb = (struct aui_dri_xcb *)driver;
+
+	int ret = poll(&dri_xcb->pollfd, 1, 10);
+
+	if (ret < 0)
+		return;
+
+	while ((event = xcb_poll_for_event(dri_xcb->conn)) != NULL) {
+		switch (event->response_type & ~0x80) {
+		case XCB_EXPOSE:
+			exe = (xcb_expose_event_t *)event;
+			aw_xcb = find_window_xcb(exe->window);
+			aw = (struct aui_window *)aw_xcb;
+			aw->draw_flag = 1;
+			break;
+		case XCB_CLIENT_MESSAGE:
+			cme = (xcb_client_message_event_t *)event;
+			aw_xcb = find_window_xcb(cme->window);
+			aw = (struct aui_window *)aw_xcb;
+
+			if (cme->data.data32[0] == dri_xcb->wm_delete_window->atom) {
+				struct aui_event_quit qev = {
+					.event = { .type = AUI_EVENT_QUIT, .aw = aw },
+				};
+				aui_add_event(&qev.event);
+			}
+			break;
+		case XCB_CONFIGURE_NOTIFY:
+			cne = (xcb_configure_notify_event_t *)event;
+			aw_xcb = find_window_xcb(cne->window);
+			aw = (struct aui_window *)aw_xcb;
+			ww = (struct aui_widget *)aw;
+
+			if (ww->geom.width != cne->width || ww->geom.height != cne->height) {
+				struct aui_event_resize rse = {
+					.event = { .type = AUI_EVENT_RESIZE, .aw = aw },
+					.old_w = ww->geom.width,
+					.old_h = ww->geom.height,
+					.new_w = cne->width,
+					.new_h = cne->height,
+				};
+				ww->geom.width = cne->width;
+				ww->geom.height = cne->height;
+				aui_add_event(&rse.event);
+				aw->draw_flag = 1;
+			}
+			break;
+		case XCB_MOTION_NOTIFY:
+			mne = (xcb_motion_notify_event_t *)event;
+			aw_xcb = find_window_xcb(mne->event);
+			aw = (struct aui_window *)aw_xcb;
+
+			struct aui_event_mouse_motion mev = {
+				.event = { .type = AUI_EVENT_MOUSE_MOTION, .aw = aw },
+				.x = mne->event_x, .y = mne->event_y
+			};
+			aui_add_event(&mev.event);
+			break;
+		case XCB_BUTTON_PRESS:
+			bpe = (xcb_button_press_event_t *)event;
+			aw_xcb = find_window_xcb(bpe->event);
+			aw = (struct aui_window *)aw_xcb;
+
+			struct aui_event_mouse_press mpe = {
+				.event = { .type = AUI_EVENT_MOUSE_PRESS, .aw = aw },
+				.x = bpe->event_x, .y = bpe->event_y, .button = bpe->detail
+			};
+			aui_add_event(&mpe.event);
+			break;
+		case XCB_BUTTON_RELEASE:
+			bre = (xcb_button_release_event_t *)event;
+			aw_xcb = find_window_xcb(bre->event);
+			aw = (struct aui_window *)aw_xcb;
+
+			struct aui_event_mouse_release mre = {
+				.event = { .type = AUI_EVENT_MOUSE_RELEASE, .aw = aw },
+				.x = bre->event_x, .y = bre->event_y, .button = bre->detail
+			};
+			aui_add_event(&mre.event);
+			break;
+		default:
+			break;
+		}
+		free(event);
+	}
+}
+
+static void 
+aui_dri_resize_window(struct aui_window *aw)
+{
+	set_pixmap_xcb((struct aui_window_xcb *)aw);
+	aw->draw_flag = 1;
+}
+
+static void 
+aui_dri_render_background(struct aui_window *aw)
+{
+	xcb_render_color_t color = { .red = 0xd9d9, .green = 0xd9d9, .blue = 0xd9d9, .alpha = 0xffff };
+	struct aui_widget *ww = (struct aui_widget *)aw;
+	xcb_rectangle_t rects[] = { { .x = 0, .y = 0, .width = ww->geom.width, 
+		.height = ww->geom.height } };
+	struct aui_dri_xcb *dri_xcb = (struct aui_dri_xcb *)driver;
+	struct aui_window_xcb *aw_xcb = (struct aui_window_xcb *)aw;
+
+	xcb_render_fill_rectangles(dri_xcb->conn,
+							   XCB_RENDER_PICT_OP_OVER,
+							   aw_xcb->src_pict,
+							   color,
+							   1,
+							   rects);
+}
+
+static void
+aui_dri_render_foreground(struct aui_window *aw)
+{
+	struct aui_window_xcb *aw_xcb = (struct aui_window_xcb *)aw;
+	struct aui_dri_xcb *dri_xcb = (struct aui_dri_xcb *)driver;
+	struct aui_widget *ww = (struct aui_widget *)aw;
+
+	xcb_render_composite(dri_xcb->conn,
+						 XCB_RENDER_PICT_OP_OVER,
+						 aw_xcb->src_pict,
+						 XCB_NONE,
+						 aw_xcb->dst_pict,
+						 0, 0, 0, 0, 0, 0,
+						 ww->geom.width, ww->geom.height);
+
+	xcb_flush(dri_xcb->conn);
+}
+
+static struct primitive*
+aui_dri_create_rectangle()
+{
+	struct rectangle *rect = calloc(1, sizeof(struct rectangle));
+
+	rect->base.type = PRIMITIVE_TYPE_RECTANGLE;
+	rect->xrect.x = 0;
+	rect->xrect.y = 0;
+	rect->xrect.width = 0;
+	rect->xrect.height = 0;
+
+	rect->xcolor.red = 0;
+	rect->xcolor.green = 0;
+	rect->xcolor.blue = 0;
+	rect->xcolor.alpha = 0;
+
+	return &(rect)->base;
+}
+
+static void 
+aui_dri_delete_rectangle(struct primitive *prim)
+{
+	struct rectangle *rect = (struct rectangle *)prim;
+	free(rect);
+}
+
+static void
+aui_dri_render_rectangle(struct aui_window *aw, struct primitive *prim)
+{
+	struct aui_window_xcb *aw_xcb = (struct aui_window_xcb *)aw;
+	struct aui_dri_xcb *dri_xcb = (struct aui_dri_xcb *)driver;
+	struct rectangle *rect = (struct rectangle *)prim;
+
+	if (prim->type != PRIMITIVE_TYPE_RECTANGLE) {
+		fprintf(stderr, "libaui: attempt to render rectangle with mismatching type.\n");
+		return;
+	}
+
+	xcb_render_fill_rectangles(dri_xcb->conn,
+							   XCB_RENDER_PICT_OP_OVER,
+							   aw_xcb->src_pict,
+							   rect->xcolor,
+							   1,
+							   &rect->xrect);
+}
+
+static void 
+aui_dri_set_rectangle_color(struct aui_window *aw, struct primitive *prim, struct aui_color *color)
+{
+	struct rectangle *rect = (struct rectangle *)prim;
+
+	if (prim->type != PRIMITIVE_TYPE_RECTANGLE) {
+		fprintf(stderr, "libaui: attempt to set_rectangle_color for mismatching type\n");
+		return;
+	}
+
+	rect->xcolor.red = (color->red * 0xFFFF) / 0xFF;
+	rect->xcolor.green = (color->green * 0xFFFF) / 0xFF;
+	rect->xcolor.blue = (color->blue * 0xFFFF) / 0xFF;
+	rect->xcolor.alpha = (color->alpha * 0xFFFF) / 0xFF;
+
+	aw->draw_flag = 1;
+}
+
+static 
+void aui_dri_set_rectangle_geometry(struct aui_window *aw, struct primitive *prim, 
+	struct aui_geometry *geom)
+{
+	struct rectangle *rect = (struct rectangle *)prim;
+
+	rect->xrect.x = geom->x;
+	rect->xrect.y = geom->y;
+	rect->xrect.width = geom->width;
+	rect->xrect.height = geom->height;
+}
+
+static struct primitive*
+aui_dri_create_text()
+{
+	struct aui_dri_xcb *dri_xcb = (struct aui_dri_xcb *)driver;
+	struct text *t = calloc(1, sizeof(struct text));
+
+	t->xpict = xcb_generate_id(dri_xcb->conn);
+	t->xcolor = (xcb_render_color_t) { 0xffff/2, 0xffff/2, 0, 0xffff };
+	xcb_render_create_solid_fill(dri_xcb->conn, t->xpict, t->xcolor);
+	return &(t)->base;
+}
+
+static void
+aui_dri_set_text(struct primitive *p, const char *data, int16_t x, int16_t y)
+{
+	struct text *t = (struct text *)p;
+	t->base.type = PRIMITIVE_TYPE_TEXT;
+	t->data = data;
+	t->x = x;
+	t->y = y;
+}
+
+static void
+aui_dri_set_text_color(struct primitive *p, struct aui_color *c)
+{
+	struct aui_dri_xcb *dri_xcb = (struct aui_dri_xcb *)driver;
+	struct text *t = (struct text *)p;
+
+	t->xcolor = (xcb_render_color_t) { 
+		c->red * 0xffff / 0xff,
+		c->green * 0xffff / 0xff,
+		c->blue * 0xffff / 0xff,
+		c->alpha * 0xffff / 0xff
+	};
+
+	xcb_render_free_picture(dri_xcb->conn, t->xpict);
+	t->xpict = xcb_generate_id(dri_xcb->conn);
+	xcb_render_create_solid_fill(dri_xcb->conn, t->xpict, t->xcolor);
+}
+
+/*
+ * This renders text without the use of xcb_render utils. It utilises the
+ * xcb_render_composite_glyphs_8 function which expects an 8 bytes header
+ * where. Can only be up to 255 characters:
+ *
+ * byte0=>	 len
+ * byte1-3=>   padding
+ * byte4-5=>   dx
+ * byte6-7=>   dy
+ */
+struct ghead {
+	uint8_t	   len;
+	uint8_t	   pad[3];
+	int16_t	   dx;
+	int16_t	   dy;
+};
+
+static void 
+aui_dri_render_text(struct aui_window *aw, struct primitive *p)
+{
+	struct aui_window_xcb *aw_xcb = (struct aui_window_xcb *)aw;
+	struct aui_dri_xcb *dri_xcb = (struct aui_dri_xcb *)driver;
+	struct text *t = (struct text *)p;
+
+	size_t len = (t->data == NULL) ? 0 : strlen(t->data);
+	struct ghead cmd = { .len = len, .dx = t->x, .dy = t->y };
+
+	size_t cmd_len = len + 8;
+	uint8_t *glyphcmds = malloc(cmd_len);
+
+	if (glyphcmds == NULL)
+		return;
+
+	glyphcmds[0] = cmd.len;
+	glyphcmds[1] = 0;
+	glyphcmds[2] = 0;
+	glyphcmds[3] = 0;
+
+	memcpy(&glyphcmds[4], &cmd.dx, 2);
+	memcpy(&glyphcmds[6], &cmd.dy, 2);
+
+	memcpy(glyphcmds + 8, t->data, len);
+
+	xcb_render_composite_glyphs_8(
+		dri_xcb->conn,
+		XCB_RENDER_PICT_OP_OVER,
+		t->xpict,
+		aw_xcb->src_pict,
+		0,
+		dri_xcb->glyphset,
+		0, 0,
+		cmd_len,
+		glyphcmds);
+
+	free(glyphcmds);
+}
+
+static struct aui_geometry
+aui_dri_get_text_geometry(struct primitive *p)
+{
+	struct aui_dri_xcb *dri_xcb = (struct aui_dri_xcb *)driver;
+	struct aui_geometry geom = { 0 };
+	struct text *t = (struct text *)p;
+	size_t len = (t->data == NULL) ? 0 : strlen(t->data);
+
+	for (int i = 0; i < len; i++) {
+		uint32_t glyphid = (uint32_t)t->data[i];
+		if (glyphid < 32 || glyphid > 126) {
+			/* fprintf(stderr, "libaui: unknown geometry for glyph id: %d\n", glyphid); */
+			continue;
+		}
+
+		struct glyph *g = &dri_xcb->glyphs[glyphid];
+		geom.width += g->x_offset;
+	}
+	geom.height = dri_xcb->font_height;
+
+	return geom;
+}
+
+/*
+ * XCB section
+ *
+ * Function ends with xcb to prevent clashing with xcb
+ * defined functions.
+ */
+static int
+config_xcb(struct aui_dri_xcb *axcb)
+{
+	xcb_intern_atom_cookie_t cookies[2];
+
+	axcb->conn = xcb_connect(NULL, NULL);
+
+	if (xcb_connection_has_error(axcb->conn))
+		return -1;
+
+	axcb->screen = xcb_setup_roots_iterator(xcb_get_setup(axcb->conn)).data;
+
+	if (axcb->screen == NULL)
+		return -1;
+
+	axcb->pollfd.fd = xcb_get_file_descriptor(axcb->conn);
+	axcb->pollfd.events = POLLIN;
+
+	/*
+	 * Prevents auto delete
+	 */
+	cookies[0] = xcb_intern_atom(axcb->conn, 1, strlen("WM_PROTOCOLS"), "WM_PROTOCOLS");
+	axcb->wm_protocols = xcb_intern_atom_reply(axcb->conn, cookies[0], NULL);
+
+	cookies[1] = xcb_intern_atom(axcb->conn, 1, strlen("WM_DELETE_WINDOW"), "WM_DELETE_WINDOW");
+	axcb->wm_delete_window = xcb_intern_atom_reply(axcb->conn, cookies[1], NULL);
+
+	/*
+	 * XCB Render
+	 */
+	xcb_render_query_pict_formats_cookie_t rcookie = xcb_render_query_pict_formats(axcb->conn);
+	xcb_render_query_pict_formats_reply_t *rreply;
+	xcb_render_pictscreen_iterator_t rpiter;
+
+	rreply = xcb_render_query_pict_formats_reply(axcb->conn, rcookie, NULL);
+	rpiter = xcb_render_query_pict_formats_screens_iterator(rreply);
+
+	/*
+	 * This is `NORMAL` format
+	 */
+	while (rpiter.rem != 0) {
+		xcb_render_pictdepth_iterator_t rditer;
+		rditer = xcb_render_pictscreen_depths_iterator(rpiter.data);
+
+		while (rditer.rem != 0) {
+			xcb_render_pictvisual_iterator_t rviter;
+			rviter = xcb_render_pictdepth_visuals_iterator(rditer.data);
+
+			while (rviter.rem != 0) {
+				if (rviter.data->visual == axcb->screen->root_visual)
+					axcb->fmt_normal = rviter.data->format;
+				xcb_render_pictvisual_next(&rviter);
+			}
+			xcb_render_pictdepth_next(&rditer);
+		}
+		xcb_render_pictscreen_next(&rpiter);
+	}
+
+	/*
+	 * Formats for `ARGB32` and `ALPHA8`
+	 */
+	xcb_render_pictforminfo_iterator_t rfiter;
+	rfiter = xcb_render_query_pict_formats_formats_iterator(rreply);
+
+	while (rfiter.rem != 0) {
+		xcb_render_pictforminfo_t *info = rfiter.data;
+
+		if (info->type == XCB_RENDER_PICT_TYPE_DIRECT &&
+			info->depth == 32 &&
+			info->direct.red_shift == 16 &&
+			info->direct.red_mask == 0xff &&
+			info->direct.green_shift == 8 &&
+			info->direct.green_mask == 0xff &&
+			info->direct.blue_shift == 0 &&
+			info->direct.blue_mask == 0xff &&
+			info->direct.alpha_shift == 24 &&
+			info->direct.alpha_mask == 0xff)
+			axcb->fmt_argb32 = rfiter.data->id;
+
+		if (info->type == XCB_RENDER_PICT_TYPE_DIRECT &&
+			info->depth == 8 &&
+			info->direct.red_shift == 0 &&
+			info->direct.red_mask == 0x00 &&
+			info->direct.green_shift == 0 &&
+			info->direct.green_mask == 0x00 &&
+			info->direct.blue_shift == 0 &&
+			info->direct.blue_mask == 0x00 &&
+			info->direct.alpha_shift == 0 &&
+			info->direct.alpha_mask == 0xff)
+			axcb->fmt_alpha8 = rfiter.data->id;
+		xcb_render_pictforminfo_next(&rfiter);
+	}
+
+	free(rreply);
+
+	return 0;
+}
+
+/*
+ * Sets pixmap. This is used when the window is being resized to fit with
+ * the new dimensions
+ */
+static void
+set_pixmap_xcb(struct aui_window_xcb *aw_xcb)
+{
+	struct aui_dri_xcb *dri_xcb = (struct aui_dri_xcb *)driver;
+	struct aui_window *aw = (struct aui_window *)aw_xcb;
+	struct aui_widget *ww = (struct aui_widget *)aw;
+
+	xcb_render_free_picture(dri_xcb->conn, aw_xcb->dst_pict);
+	xcb_render_free_picture(dri_xcb->conn, aw_xcb->src_pict);
+	xcb_free_pixmap(dri_xcb->conn, aw_xcb->pixmap);
+
+	aw_xcb->pixmap = xcb_generate_id(dri_xcb->conn);
+	xcb_create_pixmap(dri_xcb->conn,
+					  32,
+					  aw_xcb->pixmap,
+					  aw_xcb->xw,
+					  ww->geom.width,
+					  ww->geom.height);
+
+	aw_xcb->src_pict = xcb_generate_id(dri_xcb->conn);
+	xcb_render_create_picture(dri_xcb->conn,
+							  aw_xcb->src_pict,
+							  aw_xcb->pixmap,
+							  dri_xcb->fmt_argb32,
+							  0,
+							  NULL);
+
+	aw_xcb->dst_pict = xcb_generate_id(dri_xcb->conn);
+	xcb_render_create_picture(dri_xcb->conn,
+							  aw_xcb->dst_pict,
+							  aw_xcb->xw,
+							  dri_xcb->fmt_normal,
+							  0,
+							  NULL);
+}
+
+static struct aui_window_xcb*
+find_window_xcb(xcb_window_t xw)
+{
+	struct aui_window_xcb *aw_xcb;
+	struct aui_window *aw;
+
+	LIST_FOREACH(aw, &wlist, entries) {
+		aw_xcb = (struct aui_window_xcb *)aw;
+		if (aw_xcb->xw == xw)
+			return aw_xcb;
+	}
+
+	return NULL;
+}
+
+static void
+set_name_xcb(struct aui_window_xcb *aw_xcb, const char *title)
+{
+	if (title == NULL) return;
+
+	struct aui_dri_xcb *dri_xcb = (struct aui_dri_xcb *)driver;
+	xcb_change_property(dri_xcb->conn,
+						 XCB_PROP_MODE_REPLACE,
+						 aw_xcb->xw,
+						 XCB_ATOM_WM_NAME,
+						 XCB_ATOM_STRING,
+						 8,
+						 strlen(title),
+						 title
+	);
+}