Commit Diff


commit - /dev/null
commit + 61d67952bb7d89f33f258407967f721c83a3bdb6
blob - /dev/null
blob + 3fe7ac0b03427301f6a7db54eee5351014c539d2 (mode 644)
--- /dev/null
+++ README
@@ -0,0 +1,11 @@
+This directory contains the source code for the ria 
+graphics system that can be built and run on OpenBSD 
+when drm is turned off.
+
+prot.h		Protocol used by libria
+ria/		The server
+libria/		Interface to comunicate with ria
+
+The goal of this system is to have a simple graphics
+system that can be easily understood with very little
+code.
blob - /dev/null
blob + 865ecbcdaae71fb7e4353f4dca931f34451adcca (mode 644)
--- /dev/null
+++ TODO
@@ -0,0 +1,7 @@
+- Emulate Plan9 by making the window system both a
+  a shell and an image. Look at openpty(3) and 
+  pty(4). This will allow nested instances.
+
+- Define a proper and well documented protocol :^).
+
+- Make a couple of demo programs using the protocol.
blob - /dev/null
blob + 20d4bcef726a4cbf96ffbb605738e9ba4a899377 (mode 644)
--- /dev/null
+++ libria/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 + 4588c35f26e9400c256ab1d9c2e6c8ddc5724074 (mode 644)
--- /dev/null
+++ libria/Makefile
@@ -0,0 +1,31 @@
+CC=cc
+LIB=libria
+SRCS=\
+		draw.c
+OBJS=${SRCS:.c=.o}
+PREFIX=/usr/local
+CFLAGS=-O0 -Wall -Werror -I ../
+HDRS=\
+		draw.h\
+		event.h\
+		../prot.h
+
+${LIB}: ${OBJS} ${HDRS}
+	ar rc ${LIB}.a ${OBJS}
+
+install: ${LIB}
+	install -d ${PREFIX} ${PREFIX}/include/ria
+	install -m 644 ${HDRS} ${PREFIX}/include/ria
+	install -m 644 ${LIB}.a ${PREFIX}/lib
+
+uninstall:
+	rm -rf ${PREFIX}/include/ria
+	rm -rf ${PREFIX}/lib/${LIB}.a
+
+.c.o:
+	${CC} -c $< -o $@ ${CFLAGS}
+
+clean:
+	rm -rf ${OBJS} ${LIB}.a 
+
+.PHONY: clean
blob - /dev/null
blob + 09011e6ee5930249e0cd4db1af20daad61e3695e (mode 644)
--- /dev/null
+++ libria/draw.c
@@ -0,0 +1,68 @@
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/un.h>
+#include <sys/socket.h>
+
+#include "prot.h"
+#include "draw.h"
+
+static int _connect(void);
+
+struct ria_display *ria_display;
+
+int
+ria_init()
+{
+	if (_connect() == -1)
+		return -1;
+
+	return 0;
+}
+
+int
+ria_draw()
+{
+	struct msg dmsg;
+
+	dmsg.type = MSG_TYPE_DRAW;
+	dmsg.len = sizeof(dmsg);
+
+	if (send(ria_display->fd, &dmsg, dmsg.len, 0) == -1)
+		return -1;
+
+	return 0;
+}
+
+static int
+_connect()
+{
+	struct sockaddr_un addr;
+
+	if (ria_display != NULL) {
+		errno = EPERM;
+		return -1;
+	}
+
+	if ((ria_display = calloc(1, sizeof(*ria_display))) == NULL)
+		return -1;
+
+	if ((ria_display->fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
+		return -1;
+	}
+
+	addr.sun_family = AF_UNIX;
+	memset(addr.sun_path, 0, sizeof(addr.sun_path));
+	strncpy(addr.sun_path, RIA_SOCK_PATH, sizeof(addr.sun_path));
+
+	if (connect(ria_display->fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+		close(ria_display->fd);
+		free(ria_display);
+		return -1;
+	}
+
+	return 0;
+}
blob - /dev/null
blob + 5d22f9421f0836d35b1a637f27a0a0fe548798b6 (mode 644)
--- /dev/null
+++ libria/draw.h
@@ -0,0 +1,17 @@
+#ifndef _RIA_DRAW_H_
+#define _RIA_DRAW_H_
+
+struct ria_display {
+	int fd;
+};
+
+int ria_init(void);
+int ria_draw(void);
+
+
+/*
+ * Global variables
+ */
+extern struct ria_display *ria_display;
+
+#endif
blob - /dev/null
blob + 4237e2d1848d82bf9e16ede9fffe9efa49dfd5d5 (mode 644)
--- /dev/null
+++ libria/event.h
@@ -0,0 +1,4 @@
+#ifndef _RIA_EVENT_H_
+#define _RIA_EVENT_H_
+
+#endif
blob - /dev/null
blob + 19b99122f4a2cc2cc6a0bf3110a20d08e92dfb6c (mode 644)
--- /dev/null
+++ prot.h
@@ -0,0 +1,10 @@
+#define RIA_SOCK_PATH	"/tmp/ria.sock"
+
+enum msg_type {
+	MSG_TYPE_DRAW,
+};
+
+struct msg {
+	enum msg_type type;
+	uint32_t len;
+};
blob - /dev/null
blob + 20d4bcef726a4cbf96ffbb605738e9ba4a899377 (mode 644)
--- /dev/null
+++ ria/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 + 0c3d3f212aa575bf622fffd69b5eb30525e9bf0a (mode 644)
--- /dev/null
+++ ria/Makefile
@@ -0,0 +1,27 @@
+CC=cc
+BIN=ria
+SRCS=\
+		ria.c\
+		cursor.c\
+		event.c\
+		kmap.c\
+		wsctl.c\
+		fb.c
+
+OBJS=${SRCS:.c=.o}
+CFLAGS=-O0 -Wall -Werror -I ../
+HDRS=\
+		fb.h\
+		wsctl.h\
+		event.h
+
+${BIN}: ${OBJS} ${HDRS}
+	${CC} ${OBJS} -o ${BIN}
+
+.c.o:
+	${CC} -fPIE -c $< -o $@ ${CFLAGS}
+
+clean:
+	rm -rf ${BIN} ${BIN}.core ${OBJS}
+
+.PHONY: clean
blob - /dev/null
blob + 34f28370755e3f1e3a70108a7d6750d82667d3e8 (mode 644)
--- /dev/null
+++ ria/README
@@ -0,0 +1,31 @@
+This is intended to run on OpenBSD.
+
+Features:
+
+- No drm
+
+- No web browser
+
+- Plenty of screen tearing
+
+- No ttf/otf
+
+- US encoding only
+
+- usb keyboard device only supported
+
+- and more
+
+- No keybinding because i18n sucks
+
+- also, its kinda cool?
+
+Tutorial:
+
+- disable inteldrm/radeondrm
+
+- make
+
+- ria
+
+- ascend
blob - /dev/null
blob + 2c22d89edd26ebfa94da6439d811b57b062e1d00 (mode 644)
--- /dev/null
+++ ria/cursor.c
@@ -0,0 +1,13 @@
+#include "fb.h"
+
+void
+button_press(int button)
+{
+	cursor.held[button] = 1;
+}
+
+void
+button_release(int button)
+{
+	cursor.held[button] = 0;
+}
blob - /dev/null
blob + e21f2827e4fdc2ef70f01790ef3584b4b9d14971 (mode 644)
--- /dev/null
+++ ria/event.c
@@ -0,0 +1,32 @@
+#include <stdio.h>
+
+#include "event.h"
+
+#define EVENT_QUEUE_SIZE	255
+
+static struct event queue[EVENT_QUEUE_SIZE];
+static size_t head;
+static size_t tail;
+
+void
+event_push(struct event *ev)
+{
+	size_t n = (head + 1) % EVENT_QUEUE_SIZE;
+
+	if (n == tail)
+		return;
+
+	queue[head] = *ev;
+	head = n;
+}
+
+int
+event_pop(struct event *ev)
+{
+	if (head == tail)
+		return -1;
+
+	*ev = queue[tail];
+	tail = (tail + 1) % EVENT_QUEUE_SIZE;
+	return 0;
+}
blob - /dev/null
blob + 20f5100703baaeb641ad8e2a8e91efac2807c34d (mode 644)
--- /dev/null
+++ ria/event.h
@@ -0,0 +1,35 @@
+enum event_type {
+	EVENT_TYPE_MOUSE,
+	EVENT_TYPE_KEYBOARD
+};
+
+enum event_list {
+	EVENT_KEY_DOWN,
+	EVENT_KEY_UP,
+	EVENT_MOUSE_MOTION,
+	EVENT_MOUSE_PRESS,
+	EVENT_MOUSE_RELEASE,
+};
+
+struct mouse_event {
+	int type;
+	int x, y;
+	int button;
+};
+
+struct kbd_event {
+	int type;
+	int key;
+};
+
+struct event {
+	enum event_type type;
+
+	union {
+		struct mouse_event mouse;
+		struct kbd_event kbd;
+	};
+};
+
+void event_push(struct event*);
+int event_pop(struct event*);
blob - /dev/null
blob + 8849d4de6d84a880961be9319d2b5ab1f9c50bbf (mode 644)
--- /dev/null
+++ ria/fb.c
@@ -0,0 +1,81 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "fb.h"
+
+struct fbinfo *fb;
+struct cursor cursor;
+
+int
+intersects(struct rectangle *, struct rectangle *);
+
+/*
+ * Expects 32 bits
+ */
+void
+fill(unsigned int value)
+{
+	uint32_t *data = (uint32_t *)fb->bdat;
+
+	/*
+	 * 4 channels ARGB
+	 */
+	for (size_t i = 0; i < fb->bytes/4; i++)
+		data[i] = value;
+
+	damage(&(struct rectangle) { 0, 0, fb->width, fb->height });
+}
+
+void
+draw_cursor()
+{
+	int x1 = cursor.x;
+	int y1 = cursor.y;
+
+	int x2 = cursor.x + CURSOR_WIDTH;
+	int y2 = cursor.y + CURSOR_HEIGHT;
+
+	uint32_t *dat = (uint32_t *)fb->dat;
+
+	/* Clamp */
+	if (x2 > fb->width) x2 = fb->width;
+	if (y2 > fb->height) y2 = fb->height;
+
+	for (int j = y1; j < y2; j++) {
+		int idx = j * fb->width + x1;
+		memcpy(dat + idx, cursor.bits, (x2 - x1) * 4);
+	}
+}
+
+void
+damage(struct rectangle *rect)
+{
+	int x1 = rect->x1 < rect->x2 ? rect->x1 : rect->x2;
+	int y1 = rect->y1 < rect->y2 ? rect->y1 : rect->y2;
+	int x2 = rect->x1 < rect->x2 ? rect->x2 : rect->x1;
+	int y2 = rect->y1 < rect->y2 ? rect->y2 : rect->y1;
+
+	/* CLAMP */
+	if (x1 > fb->width) x1 = fb->width;
+	if (x2 > fb->width) x2 = fb->width;
+	if (y1 > fb->height) y1 = fb->height;
+	if (y2 > fb->height) y2 = fb->height;
+
+	if (x1 < 0) { x2 = (x2 - x1); x1 = 0; }
+	if (y1 < 0) { y2 = (y2 - y1); y1 = 0; }
+
+	uint32_t *bdat = (uint32_t *)fb->bdat;
+	uint32_t *dat = (uint32_t *)fb->dat;
+
+	for (int j = y1; j < y2; j++) {
+		int idx = j * fb->width + x1;
+		memcpy(dat + idx, bdat + idx, (x2 - x1) * 4); /* 4 channels */
+	}
+}
+
+
+int intersects(struct rectangle *a, struct rectangle *b)
+{
+	return (a->x1 <= b->x2 && a->x2 >= b->x2) && (a->y1 <= b->y2 && a->y2 >= b->y1);
+}
blob - /dev/null
blob + b1b7b1f224308bbf60c20abd12306a19a4a191d4 (mode 644)
--- /dev/null
+++ ria/fb.h
@@ -0,0 +1,41 @@
+#include <stdlib.h>
+
+#define CURSOR_WIDTH	16
+#define CURSOR_HEIGHT	16
+
+#define BUTTON_1 	0
+#define BUTTON_2	1
+#define BUTTON_3	2
+
+struct cursor {
+	unsigned char bits[CURSOR_WIDTH * CURSOR_HEIGHT * 4];
+	unsigned char held[3];
+	int16_t x;
+	int16_t y;
+};
+
+struct rectangle {
+	int x1;
+	int y1;
+	int x2;
+	int y2;
+};
+
+struct fbinfo {
+	unsigned int width;
+	unsigned int height;
+	unsigned int depth;
+	void *dat;
+	void *bdat;	/* back-buffer */
+	size_t bytes;
+};
+
+void fill(unsigned int);
+void draw_cursor();
+void damage(struct rectangle *);
+
+void button_press(int);
+void button_release(int);
+
+extern struct fbinfo *fb;
+extern struct cursor cursor;
blob - /dev/null
blob + 5e6dfb744c4e93a1e07353ce7fc4a5d72043639d (mode 644)
--- /dev/null
+++ ria/kbd.h
@@ -0,0 +1,5 @@
+struct kbd_map {
+	int keysym;
+};
+
+int get_kbd_map(struct kbd_map **, unsigned int, int);
blob - /dev/null
blob + 98b14321611425116ca425cff8db37ac7581f2b0 (mode 644)
--- /dev/null
+++ ria/kmap.c
@@ -0,0 +1,158 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <dev/wscons/wsksymdef.h>
+#include "kbd.h"
+
+/*
+ * Source: /usr/include/dev/usb/ukbmap.c
+ *
+ * This is shit
+ */
+static struct kbd_map usb_us[] = {
+/* 	keysym */
+	[0x04] = { KS_a },
+	[0x05] = { KS_b },
+	[0x06] = { KS_c },
+	[0x07] = { KS_d },
+	[0x08] = { KS_e },
+	[0x09] = { KS_f },
+	[0x0A] = { KS_g },
+	[0x0B] = { KS_h },
+	[0x0C] = { KS_i },
+ 	[0x0D] = { KS_j },
+	[0x0E] = { KS_k },
+	[0x0F] = { KS_l },
+	[0x10] = { KS_m },
+	[0x11] = { KS_n },
+	[0x12] = { KS_o },
+	[0x13] = { KS_p },
+	[0x14] = { KS_q },
+	[0x15] = { KS_r },
+	[0x16] = { KS_s },
+	[0x17] = { KS_t },
+	[0x18] = { KS_u },
+	[0x19] = { KS_v },
+	[0x1A] = { KS_w },
+	[0x1B] = { KS_x },
+	[0x1C] = { KS_y },
+	[0x1D] = { KS_z },
+	[0x1E] = { KS_1 },
+	[0x1F] = { KS_2 },
+	[0x20] = { KS_3 },
+	[0x21] = { KS_4 },
+	[0x22] = { KS_5 },
+	[0x23] = { KS_6 },
+	[0x24] = { KS_7 },
+	[0x25] = { KS_8 },
+	[0x26] = { KS_9 },
+	[0x27] = { KS_0 },
+	[0x28] = { KS_Return },
+	[0x29] = { KS_Escape },
+	[0x2A] = { KS_Delete },
+	[0x2B] = { KS_Tab },
+	[0x2C] = { KS_space },
+	[0x2D] = { KS_minus },
+	[0x2E] = { KS_equal },
+	[0x2F] = { KS_bracketleft },
+	[0x30] = { KS_bracketright },
+	[0x31] = { KS_backslash },
+	[0x32] = { KS_backslash },
+	[0x33] = { KS_semicolon },
+	[0x34] = { KS_apostrophe },
+	[0x35] = { KS_grave },
+	[0x36] = { KS_comma },
+	[0x37] = { KS_period },
+	[0x38] = { KS_slash },
+	[0x39] = { KS_Caps_Lock },
+	[0x3A] = { KS_f1 },
+	[0x3B] = { KS_f2 },
+	[0x3C] = { KS_f3 },
+	[0x3D] = { KS_f4 },
+	[0x3E] = { KS_f5 },
+	[0x3F] = { KS_f6 },
+	[0x40] = { KS_f7 },
+	[0x41] = { KS_f8 },
+	[0x42] = { KS_f9 },
+	[0x43] = { KS_f10 },
+	[0x44] = { KS_f11 },
+	[0x45] = { KS_f12 },
+	[0x46] = { KS_Print_Screen },
+	[0x47] = { KS_Hold_Screen },
+	[0x48] = { KS_Pause },
+	[0x49] = { KS_Insert },
+	[0x4A] = { KS_Home },
+	[0x4B] = { KS_Prior },
+	[0x4C] = { KS_KP_Delete },
+	[0x4D] = { KS_End },
+	[0x4E] = { KS_Next },
+	[0x4F] = { KS_Right },
+	[0x50] = { KS_Left },
+	[0x51] = { KS_Down },
+	[0x52] = { KS_Up },
+	[0x53] = { KS_Num_Lock },
+	[0x54] = { KS_KP_Divide },
+	[0x55] = { KS_KP_Multiply },
+	[0x56] = { KS_KP_Subtract },
+	[0x57] = { KS_KP_Add },
+	[0x58] = { KS_KP_Enter },
+	[0x59] = { KS_KP_1 },
+	[0x5A] = { KS_KP_2 },
+	[0x5B] = { KS_KP_3 },
+	[0x5C] = { KS_KP_4 },
+	[0x5D] = { KS_KP_5 },
+	[0x5E] = { KS_KP_6 },
+	[0x5F] = { KS_KP_7 },
+	[0x60] = { KS_KP_8 },
+	[0x61] = { KS_KP_9 },
+	[0x62] = { KS_KP_0 },
+	[0x63] = { KS_KP_Delete }, /* 100 don't exists */
+	[0x64] = { KS_Menu },
+	[0x66] = { KS_Cmd_Sleep }, /* 103 either */
+	[0x68] = { KS_f13 },
+	[0x69] = { KS_f14 },
+	[0x6A] = { KS_f15 },
+	[0x6B] = { KS_f16 },
+	[0x6C] = { KS_f17 },
+	[0x6D] = { KS_f18 },
+	[0x6E] = { KS_f19 },
+	[0x6F] = { KS_f20 },
+	[0x70] = { KS_f21 },
+	[0x71] = { KS_f22 },
+	[0x72] = { KS_f23 },
+	[0x73] = { KS_f24 },
+	[0x74] = { KS_Open },
+	[0x75] = { KS_Help },
+	[0x76] = { KS_Props },
+	[0x77] = { KS_Front },
+	[0x78] = { KS_Cmd },
+	[0x79] = { KS_Again },
+	[0x7A] = { KS_Undo },
+	[0x7B] = { KS_Cut },
+	[0x7C] = { KS_Copy },
+	[0x7D] = { KS_Paste },
+	[0x7E] = { KS_Find },
+	[0x7F] = { KS_AudioMute },
+	[0x80] = { KS_AudioRaise },
+	[0x81] = { KS_AudioLower }, /* Keys [130, 223] are empty */
+	[0xE0] = { KS_Control_L },
+	[0xE1] = { KS_Shift_L },
+	[0xE2] = { KS_Alt_L },
+	[0xE3] = { KS_Meta_L },
+	[0xE4] = { KS_Control_R },
+	[0xE5] = { KS_Shift_R },
+	[0xE6] = { KS_Alt_R },
+	[0xE7] = { KS_Meta_R },
+	[0xE8] = { KS_Cmd_BrightnessUp },
+	[0xE9] = { KS_Cmd_BrightnessDown },
+	[0xEA] = { KS_Cmd_KbdBacklightToggle },
+	[0xEB] = { KS_Cmd_KbdBacklightUp },
+	[0xEC] = { KS_Cmd_KbdBacklightDown },
+};
+
+int
+get_kbd_map(struct kbd_map **kmap, unsigned int type, int encoding)
+{
+	size_t size = sizeof(usb_us) / sizeof(*usb_us);
+	*kmap = usb_us;
+	return size;
+}
blob - /dev/null
blob + 26df1a54c2f1d50fa99ea19e36ebb01633ff6594 (mode 644)
--- /dev/null
+++ ria/ria.1
@@ -0,0 +1,36 @@
+.Dd $Mdocdate: August 09 2026$
+.Dt RIA 1
+.Os
+.Sh NAME
+.Nm ria
+.Nd rio is amazing
+.Sh SYNOPSIS
+.Nm
+.Sh DESCRIPTION
+.Nm
+was created to emulate some of the functionalities of
+.Xr rio 1
+and window managers like
+.Xr cwm 1
+in order to create a coherent and simple system on 
+OpenBSD.
+
+Just as in
+.Xr rio 1
+most operations are handled by the mouse. Keybinding
+is not supported for shortcut and is not planned in the
+future. This is partly to avoid i18n issues and keep the
+system simple.
+.Sh CAVEATS
+For now it only supports 32-bit depth displays and keyboard
+driver support is limited to
+.Xr ukbd 4
+with us encoding.
+
+.Xr pckbd 4
+support will be added later.
+.Sh SEE ALSO
+.Xr cwm 1 ,
+.Xr rio 1
+.Sh AUTHORS
+.An Onana Onana Xavier Manuel Aq Mt xavier@onana.net
blob - /dev/null
blob + f3eee918ea7d3b2b6bf59106d11e3d56588550d0 (mode 644)
--- /dev/null
+++ ria/ria.c
@@ -0,0 +1,123 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+
+#include <dev/wscons/wsksymdef.h>
+
+#include "wsctl.h"
+#include "event.h"
+#include "fb.h"
+
+static volatile sig_atomic_t running = 1;
+
+void read_kbd(struct kbd_event *);
+void read_mouse(struct mouse_event *);
+
+void int_handler(int);
+
+/*
+ * TODO:
+ * Check ttyname to see if it starts with ttyC[0-N]
+ * to prevent remote execution of ria(1).
+ */
+
+int
+main()
+{
+	struct event ev;
+	int ret;
+
+	signal(SIGTERM, int_handler);
+	signal(SIGINT, int_handler);
+
+	if ((fb = wsctl_init()) == NULL) {
+		return -1;
+	}
+
+	fill(0xFF7F7F7F);
+	draw_cursor();
+
+	while (running) {
+		if ((ret = wsctl_run()) == -1)
+			break;
+
+		while (event_pop(&ev) != -1) {
+			switch (ev.type) {
+			case EVENT_TYPE_KEYBOARD:
+				read_kbd(&ev.kbd);
+				break;
+			case EVENT_TYPE_MOUSE:
+				read_mouse(&ev.mouse);
+				break;
+			}
+		}
+	}
+
+	fill(0);
+	wsctl_exit();
+}
+
+
+void
+read_kbd(struct kbd_event *kev)
+{
+	switch (kev->type) {
+	case EVENT_KEY_DOWN:
+		if (kev->key == KS_q)
+			running = 0;
+		break;
+	default:
+		break;
+	}
+}
+
+void
+read_mouse(struct mouse_event *mev)
+{
+	switch (mev->type) {
+	case EVENT_MOUSE_MOTION: {
+		struct rectangle old;
+
+		old.x1 = cursor.x;
+		old.y1 = cursor.y;
+		old.x2 = old.x1 + CURSOR_WIDTH;
+		old.y2 = old.y1 + CURSOR_HEIGHT;
+
+		cursor.x += mev->x;
+		cursor.y += mev->y;
+
+		if (cursor.x < 0)
+			cursor.x = 0;
+
+		if (cursor.y < 0)
+			cursor.y = 0;
+
+		if (cursor.x >= fb->width)
+			cursor.x = fb->width - 1;
+
+		if (cursor.y >= fb->height)
+			cursor.y = fb->height - 1;
+
+		damage(&old);
+		draw_cursor();
+		break;
+	}
+	case EVENT_MOUSE_PRESS:
+		if (mev->button >= 0 && mev->button < 3)
+			button_press(mev->button);
+		break;
+	case EVENT_MOUSE_RELEASE:
+		if (mev->button >= 0 && mev->button < 3)
+			button_release(mev->button);
+		break;
+	default:
+		break;
+	}
+}
+
+void
+int_handler(int sig)
+{
+	running = 0;
+}
blob - /dev/null
blob + 9e8340f2a0f48187013f4f16af117daa104484e4 (mode 644)
--- /dev/null
+++ ria/wsctl.c
@@ -0,0 +1,429 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <time.h>
+#include <errno.h>
+#include <string.h>
+#include <poll.h>
+
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+
+#include <sys/un.h>
+#include <sys/socket.h>
+
+#include <dev/wscons/wsconsio.h>
+#include <dev/wscons/wsksymdef.h>
+
+#include "prot.h"
+#include "fb.h"
+#include "kbd.h"
+#include "event.h"
+#include "wsctl.h"
+
+static int init_kbd(void);
+static int init_mouse(void);
+static int read_kbd(void);
+static int read_mouse(void);
+static int read_cmd(void);
+static int sock_init(void);
+static void sock_exit(void);
+
+static struct {
+	int fd;
+	struct {
+		int fd;
+	} mouse;
+	struct {
+		int fd;
+		int maplen;
+		struct kbd_map *map;
+	} kbd;
+
+	struct {
+		int fd;
+		socklen_t len;
+		struct sockaddr_un addr;
+	} sock;
+
+	struct fbinfo *fb;
+} wsctl;
+
+struct fbinfo*
+wsctl_init()
+{
+	int mode = WSDISPLAYIO_MODE_DUMBFB;
+	struct wsdisplay_fbinfo fbinfo;
+	struct fbinfo *fbi;
+
+	if ((fbi = malloc(sizeof(*fbi))) == 0) {
+		fprintf(stderr, "failed to allocate fbinfo\n");
+		return NULL;
+	}
+
+	/*
+	 * TODO:
+	 * Open the active tty instead of /dev/ttyC0
+	 */
+
+	if((wsctl.fd = open("/dev/ttyC4", O_RDWR | O_EXCL)) == -1) {
+		perror("failed to open tty file descriptor");
+		free(fbi);
+		return NULL;
+	}
+
+	if (init_mouse() == -1) {
+		close(wsctl.fd);
+		free(fbi);
+		return NULL;
+	}
+
+	if (init_kbd() == -1) {
+		close(wsctl.mouse.fd);
+		close(wsctl.fd);
+		free(fbi);
+		return NULL;
+	}
+
+	if (sock_init() == -1) {
+		close(wsctl.mouse.fd);
+		close(wsctl.kbd.fd);
+		close(wsctl.fd);
+		free(fbi);
+	}
+
+	if (ioctl(wsctl.fd, WSDISPLAYIO_GINFO, &fbinfo) == -1) {
+		perror("failed to fetch display information");
+		close(wsctl.mouse.fd);
+		close(wsctl.kbd.fd);
+		close(wsctl.fd);
+		free(fbi);
+		return NULL;
+	}
+
+	fbi->height = fbinfo.height;
+	fbi->width = fbinfo.width;
+	fbi->depth = fbinfo.depth;
+
+	/*
+	 * For now we only support ARGB
+	 */
+	if (fbi->depth != 32) {
+		close(wsctl.mouse.fd);
+		close(wsctl.kbd.fd);
+		close(wsctl.fd);
+		free(fbi);
+		errno=ENOTSUP;
+		return NULL;
+	}
+
+	if ((fbi->bdat = calloc(1, fbi->width * fbi->height * fbi->depth / 8)) == NULL) {
+		close(wsctl.mouse.fd);
+		close(wsctl.kbd.fd);
+		close(wsctl.fd);
+		free(fbi);
+		return NULL;
+	}
+
+	if (ioctl(wsctl.fd, WSDISPLAYIO_SMODE, &mode) == -1) {
+		perror("could not initialize the framebuffer");
+		close(wsctl.mouse.fd);
+		close(wsctl.kbd.fd);
+		close(wsctl.fd);
+		free(fbi);
+		return NULL;
+	}
+
+	fbi->bytes = fbi->width * fbi->height * fbi->depth / 8;
+
+	fbi->dat = mmap(NULL, fbi->bytes, PROT_WRITE | PROT_READ, MAP_SHARED, wsctl.fd, 0);
+
+	if (fbi->dat == MAP_FAILED) {
+		perror("could not map frame buffer");
+		mode = WSDISPLAYIO_MODE_EMUL;
+		ioctl(wsctl.fd, WSDISPLAYIO_SMODE, &mode);
+		close(wsctl.mouse.fd);
+		close(wsctl.kbd.fd);
+		close(wsctl.fd);
+		free(fbi);
+		return NULL;
+	}
+
+
+	cursor.x = fbi->width / 2;
+	cursor.y = fbi->height / 2;
+	wsctl.fb = fbi;
+
+	return fbi;
+}
+
+void
+wsctl_exit()
+{
+	int mode;
+	
+	if (ioctl(wsctl.fd, WSDISPLAYIO_GMODE, &mode) == -1)
+		perror("failed to get video mode");
+	else {
+		if (mode != WSDISPLAYIO_MODE_EMUL) {
+			mode = WSDISPLAYIO_MODE_EMUL;
+			munmap(wsctl.fb->dat, wsctl.fb->bytes);
+
+			if (ioctl(wsctl.fd, WSDISPLAYIO_SMODE, &mode) == -1)
+				perror("failed to smode to emul");
+		}
+	}
+
+	close(wsctl.mouse.fd);
+	free(wsctl.fb->bdat);
+	close(wsctl.kbd.fd);
+	close(wsctl.fd);
+	free(wsctl.fb);
+	sock_exit();
+}
+
+int
+wsctl_run()
+{
+	struct pollfd pfds[3];
+	int ret;
+
+	pfds[0].fd = wsctl.mouse.fd;
+	pfds[1].fd = wsctl.kbd.fd;
+	pfds[2].fd = wsctl.sock.fd;
+
+	pfds[0].events = POLLIN;
+	pfds[1].events = POLLIN;
+	pfds[2].events = POLLIN;
+
+	ret = poll(pfds, 3, -1);
+
+	if (ret == -1) {
+		if (errno == EINTR)
+			return 0;
+
+		perror("poll");
+		return -1;
+	}
+
+	if (pfds[0].revents & POLLIN)
+		read_mouse();
+
+	if (pfds[1].revents & POLLIN)
+		read_kbd();
+
+	if (pfds[2].revents & POLLIN)
+		read_cmd();
+
+	return 0;
+}
+
+static int
+init_mouse()
+{
+	if ((wsctl.mouse.fd = open("/dev/wsmouse", O_RDONLY | O_NONBLOCK)) == -1) {
+		perror("failed to open mouse");
+		return -1;
+	}
+	return 0;
+}
+
+/*
+ * There is probably a better way to do this but unfortunately I did
+ * not found 1. The method is getting the encoding, getting the type
+ * usb/pckb etc, and then mapping the ev.value to a lookup table to
+ * get a keysym.
+ *
+ * This makes it so we have to create a lookup table for every single
+ * device and every encoding. For now only usbkb and us encoding will
+ * be supported.
+ */
+static int
+init_kbd()
+{
+	kbd_t encoding;
+	u_int type;
+
+	if ((wsctl.kbd.fd = open("/dev/wskbd", O_RDONLY | O_NONBLOCK)) == -1) {
+		perror("failed to open keyboard");
+		return -1;
+	}
+
+	if (ioctl(wsctl.kbd.fd, WSKBDIO_GETENCODING, &encoding) == -1) {
+		close(wsctl.kbd.fd);
+		return -1;
+	}
+
+	if (ioctl(wsctl.kbd.fd, WSKBDIO_GTYPE, &type) == -1) {
+		close(wsctl.kbd.fd);
+		return -1;
+	}
+
+	switch (type) {
+	case WSKBD_TYPE_USB:
+		break;
+	default:
+		close(wsctl.kbd.fd);
+		errno = ENOTSUP;
+		return -1;
+	}
+
+	switch (encoding) {
+	case KB_US:
+		break;
+	default:
+		close(wsctl.kbd.fd);
+		errno = ENOTSUP;
+		return -1;
+	}
+
+	wsctl.kbd.maplen = get_kbd_map(&wsctl.kbd.map, encoding, type);
+
+	return 0;
+}
+
+
+static int
+read_mouse()
+{
+	unsigned char flags[WSCONS_EVENT_SYNC + 1] = { 0 };
+	struct event mev = { 0 };
+	struct wscons_event ev;
+	int n;
+
+	while ((n = read(wsctl.mouse.fd, &ev, sizeof(ev))) > 0) {
+		switch (ev.type) {
+		case WSCONS_EVENT_MOUSE_DELTA_X:
+			mev.mouse.x = ev.value;
+			break;
+		case WSCONS_EVENT_MOUSE_DELTA_Y:
+			mev.mouse.y = -ev.value;
+			break;
+		/* Event ready */
+		case WSCONS_EVENT_SYNC:
+			break;
+		/* Unsupported events */
+		case WSCONS_EVENT_MOUSE_UP:
+			mev.mouse.button = ev.value;
+			break;
+		case WSCONS_EVENT_MOUSE_DOWN:
+			mev.mouse.button = ev.value;
+			break;
+		case WSCONS_EVENT_MOUSE_DELTA_Z:
+		case WSCONS_EVENT_MOUSE_DELTA_W:
+		case WSCONS_EVENT_MOUSE_ABSOLUTE_W:
+		case WSCONS_EVENT_MOUSE_ABSOLUTE_Z:
+		case WSCONS_EVENT_MOUSE_ABSOLUTE_X:
+		case WSCONS_EVENT_MOUSE_ABSOLUTE_Y:
+			continue;
+		}
+
+		flags[ev.type] = 1;
+
+		if (flags[WSCONS_EVENT_SYNC] == 1) {
+			if (flags[WSCONS_EVENT_MOUSE_DELTA_X] || flags[WSCONS_EVENT_MOUSE_DELTA_Y]) {
+				mev.mouse.type = EVENT_MOUSE_MOTION;
+				mev.type = EVENT_TYPE_MOUSE;
+
+				flags[WSCONS_EVENT_MOUSE_DELTA_X] = 0;
+				flags[WSCONS_EVENT_MOUSE_DELTA_Y] = 0;
+			}
+
+			if (flags[WSCONS_EVENT_MOUSE_DOWN]) {
+				mev.mouse.type = EVENT_MOUSE_PRESS;
+				mev.type = EVENT_TYPE_MOUSE;
+
+				flags[WSCONS_EVENT_MOUSE_DOWN] = 0;
+			}
+
+			if (flags[WSCONS_EVENT_MOUSE_UP]) {
+				mev.mouse.type = EVENT_MOUSE_RELEASE;
+				mev.type = EVENT_TYPE_MOUSE;
+
+				flags[WSCONS_EVENT_MOUSE_UP] = 0;
+			}
+
+			event_push(&mev);
+			flags[WSCONS_EVENT_SYNC] = 0;
+		}
+	}
+	return 0;
+}
+
+static int
+read_kbd()
+{
+	struct wscons_event ev;
+	int keysym;
+	int n;
+
+	while ((n = read(wsctl.kbd.fd, &ev, sizeof(ev))) > 0) {
+		struct event push = { 0 };
+		push.type = EVENT_TYPE_KEYBOARD;
+
+		switch (ev.type) {
+		case WSCONS_EVENT_KEY_DOWN:
+			if (ev.value < 0 || ev.value >= wsctl.kbd.maplen)
+				continue;
+
+			keysym = wsctl.kbd.map[ev.value].keysym;
+			push.kbd.type = EVENT_KEY_DOWN;
+			push.kbd.key = keysym;
+			break;
+		case WSCONS_EVENT_KEY_UP:
+			if (ev.value < 0 || ev.value >= wsctl.kbd.maplen)
+				continue;
+
+			keysym = wsctl.kbd.map[ev.value].keysym;
+			push.kbd.type = EVENT_KEY_UP;
+			push.kbd.key = keysym;
+			break;
+		/* Not supported */
+		default:
+			continue;
+		}
+
+		event_push(&push);
+	}
+	return 0;
+}
+
+int
+read_cmd()
+{
+	return 0;
+}
+
+
+static int
+sock_init()
+{
+	if ((wsctl.sock.fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0)) == -1)
+		return -1;
+
+	wsctl.sock.addr.sun_family = AF_UNIX;
+	memset(wsctl.sock.addr.sun_path, 0, sizeof(wsctl.sock.addr.sun_path));
+	strncpy(wsctl.sock.addr.sun_path, RIA_SOCK_PATH, sizeof(wsctl.sock.addr.sun_path));
+
+	wsctl.sock.len = sizeof(wsctl.sock.addr);
+
+	if (bind(wsctl.sock.fd, (struct sockaddr *)&wsctl.sock.addr, wsctl.sock.len) == -1) {
+		close(wsctl.sock.fd);
+		return -1;
+	}
+
+	if (listen(wsctl.sock.fd, SOMAXCONN)) {
+		perror("failed to listen");
+		close(wsctl.sock.fd);
+		return -1;
+	}
+
+	return 0;
+}
+
+static void
+sock_exit()
+{
+	unlink(RIA_SOCK_PATH);
+}
blob - /dev/null
blob + 53028ef6deb1cf043d22636af2f10570970397b5 (mode 644)
--- /dev/null
+++ ria/wsctl.h
@@ -0,0 +1,3 @@
+struct fbinfo *wsctl_init(void);
+void wsctl_exit(void);
+int wsctl_run(void);