Skip to content

Repository files navigation

7aaa527d-7867-418a-be61-5612fda46339

Axiom Platform Abstraction Toolkit

Build

A lightweight, cross-platform C library providing a unified API for window management, input/event handling, and system utilities. Designed for applications that need direct control over windowing and input without heavy framework dependencies.

Features

  • Cross-platform: Native support for Windows (Win32/WGL via MinGW), Linux (Wayland or X11), macOS (AppKit/Cocoa), QNX, and WebGL (browser)
  • Window Management: Create and manage windows with OpenGL/EGL context support
  • Event System: Unified event handling for mouse, keyboard, and window events
  • Input Processing: Comprehensive keyboard and mouse input with modifier support
  • Networking: Portable TCP/UDP sockets, DNS resolution, TLS (Schannel/Secure Transport/OpenSSL), and non-blocking I/O
  • File Dialogs: Native file open/save dialogs
  • System Integration: Theme detection, directory paths, timing utilities
  • Minimal Dependencies: Simple C API with no bloat

Quickstart

Here's a minimal example showing how to create a window and process input events:

#include"platform.h"#include<stdio.h>intmain(void) {
// Initialize the platform libraryaxInit();
// Create a window (800x600 pixels)if (!axCreateWindow("My Application", 800, 600, 0)) {
fprintf(stderr, "Failed to create window\n");
return1;
}
// Main event loopstructAXmessagemsg;
intrunning=1;
while (running&&axGetMessage(&msg)) {
switch (msg.message) {
casekEventWindowClosed:
running=0;
break;
casekEventKeyDown:
printf("Key pressed: %d (modifiers: 0x%x)\n",
msg.keyCode, msg.modflags);
// Exit on ESC keyif (msg.keyCode==AX_KEY_ESCAPE) {
running=0;
}
break;
casekEventLeftButtonDown:
printf("Mouse clicked at: %d, %d\n", msg.x, msg.y);
break;
casekEventMouseMoved:
// Mouse position in msg.x, msg.ybreak;
casekEventWindowResized:
printf("Window resized\n");
break;
}
// Render your frame hereaxBeginPaint();
// ... OpenGL rendering calls ...axEndPaint();
}
// CleanupaxShutdown();
return0;
}

For non-blocking event loops with axPeekMessage, see docs/event-loop.md.

Compiling the Example

On Windows (MinGW/MSYS2):

gcc -o myapp main.c -L. -lplatform -lopengl32 -lgdi32 -luser32

On Linux (X11):

gcc -o myapp main.c -L. -lplatform -lX11 -lEGL -lGL

On Linux (Wayland):

gcc -o myapp main.c -L. -lplatform -lwayland-client -lwayland-egl -lEGL -lGL

On macOS:

clang -o myapp main.c -L. -lplatform -framework AppKit -framework OpenGL

On WebGL (browser via Emscripten):

emcc -o myapp.js main.c -L. -lplatform -sUSE_WEBGL2=1 -sEXPORTED_RUNTIME_METHODS=ccall,cwrap

Make sure libplatform.so (Linux) or libplatform.dylib (macOS) is in your library path or current directory.

API Overview

Initialization and Cleanup

voidaxInit(void); // Initialize the platform libraryvoidaxShutdown(void); // Clean up and shutdown

Window Management

bool_taxCreateWindow(constchar*title, uint32_twidth, uint32_theight, uint32_tflags);
bool_taxCreateSurface(uint32_twidth, uint32_theight);
bool_taxSetSize(uint32_twidth, uint32_theight, bool_tcentered);
uint32_taxGetSize(structAXsize*size);
floataxGetScaling(void); // Get display scaling factor

Event Processing

intaxPeekMessage(structAXmessage*msg); // Poll for next event (non-blocking)intaxGetMessage(structAXmessage*msg); // Get next event (blocking where supported)intaxWaitMessage(longTime_ttimeout_ms); // Wait for events with timeoutvoidaxPostMessageW(void*hobj, uint32_tevent, uint32_twparam, void*lparam);

Event Types

The library supports comprehensive event handling through the AX_Message structure:

  • Mouse Events: kEventLeftButtonDown, kEventLeftButtonUp, kEventMouseMoved, kEventScrollWheel
  • Keyboard Events: kEventKeyDown, kEventKeyUp, kEventChar
  • Window Events: kEventWindowClosed, kEventWindowResized, kEventWindowPaint
  • Drag & Drop: kEventDragDrop, kEventDragEnter

Rendering

voidaxMakeCurrentContext(void); // Make OpenGL context currentvoidaxBeginPaint(void); // Begin rendering framevoidaxEndPaint(void); // End rendering and swap buffersvoidaxBindFramebuffer(void); // Bind default framebuffer

File Dialogs

bool_taxGetOpenFileName(AXopenfilenameconst*params);
bool_taxGetSaveFileName(AXopenfilenameconst*params);
bool_taxGetFolderName(AXopenfilenameconst*params);

Networking

bool_taxNetInit(void); // Initialise networking subsystemvoidaxNetShutdown(void); // Release networking resourcesintaxNetSocket(intaf, inttype); // Create a TCP or UDP socketvoidaxNetClose(intsock); // Close a socketbool_taxNetConnect(intsock, constchar*host, uint16_tport); // Resolve host and connectintaxNetSend(intsock, constvoid*buf, intlen); // Send dataintaxNetRecv(intsock, void*buf, intlen); // Receive databool_taxNetWouldBlock(void); // Test for EAGAIN/EWOULDBLOCKbool_taxNetResolve(constchar*host, char*out, intoutlen); // DNS lookup to IP stringintaxNetPoll(intsock, intevents, inttimeout_ms); // Wait for I/O readinessbool_taxNetBind(intsock, constchar*host, uint16_tport); // Bind to a local addressbool_taxNetListen(intsock, intbacklog); // Mark socket as passiveintaxNetAccept(intsock); // Accept an incoming connection// TLS (Schannel on Windows, Secure Transport on macOS, OpenSSL on Linux)AXtlsctx*axTlsConnect(intsock, constchar*hostname); // TLS handshakevoidaxTlsClose(AXtlsctx*ctx); // Send close_notify and freeintaxTlsSend(AXtlsctx*ctx, constvoid*buf, intlen); // Send through TLSintaxTlsRecv(AXtlsctx*ctx, void*buf, intlen); // Receive through TLS

See docs/networking.md for full examples.

Remote Control

Standalone applications using GEM_STANDALONE_MAIN can be started with -rc to expose a localhost TCP control socket on port 17777:

build/bin/helloworld -rc
printf'click 120 80\n'| nc 127.0.0.1 17777
printf'screenshot /tmp/helloworld.jpg\n'| nc 127.0.0.1 17777

Use -rc PORT to select another port. Commands are newline-delimited and receive ok or err replies. The supported commands are click x y, rclick x y, move x y, scroll x y dx dy, key code, keydown code, keyup code, screenshot path, stop, and quit. Coordinates and key codes use the same logical coordinate and platform key-code conventions as native events. The server binds to IPv4 localhost traffic only through the platform socket API and runs its accept loop on a background platform thread.

System Utilities

longTime_taxGetMilliseconds(void); // Get current time in millisecondsvoidaxSleep(longTime_tmsec); // Sleep for specified millisecondsbool_taxIsDarkTheme(void); // Check if dark theme is activeconstchar*axGetPlatform(void); // Get platform nameconstchar*axSettingsDirectory(void); // Get settings directory pathconstchar*axShareDirectory(void); // Get share directory pathconstchar*axLibDirectory(void); // Get library directory path

Logging

bool_taxSetLogFile(constchar*path); // Open or close the process log fileconstchar*axGetLogFile(void); // Query current log file pathvoidaxLog(constchar*fmt, ...); // Append one formatted log linevoidaxLogFlush(void); // Flush buffered log output

Example:

charlog_path[1024];
snprintf(log_path, sizeof(log_path), "%s/myapp.log", axSettingsDirectory());
if (axSetLogFile(log_path)) {
axLog("app started on %s", axGetPlatform());
}

On WebGL builds, file logging is unavailable and axSetLogFile("...") returns FALSE.

Key Codes

The library defines comprehensive key codes including:

  • Standard ASCII characters
  • Function keys (AX_KEY_F1 - AX_KEY_F12)
  • Arrow keys (AX_KEY_UPARROW, AX_KEY_DOWNARROW, etc.)
  • Special keys (AX_KEY_ENTER, AX_KEY_ESCAPE, AX_KEY_SPACE, etc.)
  • Mouse buttons (AX_KEY_MOUSE1, AX_KEY_MOUSE2, AX_KEY_MOUSE3)
  • Modifier flags (AX_MOD_SHIFT, AX_MOD_CTRL, AX_MOD_ALT, AX_MOD_CMD)

See platform.h for the complete list of key codes and event definitions.

Integrating as a Submodule

The recommended way to use platform in your own project is to add it as a git submodule and build it as part of your Makefile — in a single compiler pass, with no intermediate .o files. This keeps rebuilds fast and the integration simple.

1. Add the submodule

git submodule add https://github.com/corepunch/platform libs/platform
git submodule update --init --recursive

2. Add to your Makefile

PLATFORM_DIR = libs/platform
PLATFORM_OUTDIR = build/lib
# Build platform into your output lib directoryplatform:
$(MAKE) -C $(PLATFORM_DIR) OUTDIR=$(abspath$(PLATFORM_OUTDIR))# Link your app against itmyapp: platform
$(CC)$(CFLAGS) -I$(PLATFORM_DIR) main.c \
-L$(PLATFORM_OUTDIR) -lplatform \
-Wl,-rpath,$(abspath$(PLATFORM_OUTDIR))\
-o myapp

Internally, platform's Makefile compiles all sources in a single pass — no .o files are generated. All source files are collected with find, converted to #include directives, and piped directly to the compiler:

$(FIND_SOURCES) | sed 's|.*|#include "&"|' | $(CC) $(CFLAGS) -x $(LANG) - $(LDFLAGS) -o $@

This means the entire library recompiles in one shot, which is extremely fast and requires no dependency tracking.

3. Clean up

clean:
$(MAKE) -C $(PLATFORM_DIR) clean
rm -f myapp

For a real-world example using this pattern, see corepunch/orca.


Building

Simple Makefile that auto-detects your platform and builds the appropriate dynamic library using wildcards for source files.

Prerequisites

Windows (MinGW/MSYS2):

  • MinGW-w64 toolchain (GCC for Windows):
    # Install via MSYS2 (https://www.msys2.org/)
    pacman -S mingw-w64-x86_64-gcc make
  • No extra libraries required — uses Win32, WGL, and Winsock2 (all included with Windows)

WebGL (Emscripten):

  • Emscripten SDK (emcc compiler):
    # Install via emsdk (https://emscripten.org/docs/getting_started/downloads.html)
    git clone https://github.com/emscripten-core/emsdk.git
    cd emsdk && ./emsdk install latest && ./emsdk activate latest
    source ./emsdk_env.sh

Linux:

  • GCC compiler
  • Wayland development libraries (preferred, for Wayland support):
    sudo apt-get install libwayland-dev libwayland-egl1-mesa libxkbcommon-dev libegl-dev libgl-dev
  • Or X11 development libraries (fallback, if Wayland is unavailable):
    sudo apt-get install libx11-dev libegl-dev libgl-dev
  • Build order: Wayland (preferred) → X11 (fallback) → unix-only (networking only)

macOS:

  • Clang compiler (included with Xcode Command Line Tools)
  • AppKit framework (included with macOS)

Build Commands

make # Build the dynamic library
emmake make # Build for WebGL (requires Emscripten environment sourced)
make clean # Clean build artifacts
make install # Install to /usr/local/lib (requires sudo; Linux/macOS only)

Output

  • Windows: libplatform.dll (+ libplatform.dll.a import library)
  • Linux: libplatform.so
  • macOS: libplatform.dylib
  • WebGL: libplatform.wasm (Emscripten side module)

The library exports platform-specific functions for window management, event handling, networking, and system utilities.

Platform Support

  • Windows: Full support via Win32 API and WGL — window creation, OpenGL rendering, native file dialogs, dark-theme detection, Winsock2 networking; built with MinGW
  • Linux (Wayland): Full support with Wayland, EGL, and OpenGL (preferred when available)
  • Linux (X11): Full support with Xlib, EGL, and OpenGL (fallback when Wayland is unavailable)
  • macOS: Full support with AppKit and Cocoa frameworks
  • QNX: Source files available (qnx/)
  • WebGL (browser): Full support via Emscripten — mouse, keyboard, scroll, and resize events; WebGL 1/2 rendering context

The Linux backend is selected automatically at build time:

  1. If Wayland libraries are detected via pkg-config, the Wayland backend is used
  2. If Wayland is unavailable but X11 libraries are detected, the X11 backend is used
  3. If neither is available, a unix-only build is produced (networking only, no windowing)

Header

Include platform.h in your project to access platform types and APIs.

About

A clean C API for windowing, input, and OpenGL context management across Windows, macOS, Linux, and web. No bloat, just what you need.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
GitHub - corepunch/platform: A clean C API for windowing, input, and OpenGL context management across Windows, macOS, Linux, and web. No bloat, just what you need. · GitHub
Skip to content

Repository files navigation

7aaa527d-7867-418a-be61-5612fda46339

Axiom Platform Abstraction Toolkit

Build

A lightweight, cross-platform C library providing a unified API for window management, input/event handling, and system utilities. Designed for applications that need direct control over windowing and input without heavy framework dependencies.

Features

  • Cross-platform: Native support for Windows (Win32/WGL via MinGW), Linux (Wayland or X11), macOS (AppKit/Cocoa), QNX, and WebGL (browser)
  • Window Management: Create and manage windows with OpenGL/EGL context support
  • Event System: Unified event handling for mouse, keyboard, and window events
  • Input Processing: Comprehensive keyboard and mouse input with modifier support
  • Networking: Portable TCP/UDP sockets, DNS resolution, TLS (Schannel/Secure Transport/OpenSSL), and non-blocking I/O
  • File Dialogs: Native file open/save dialogs
  • System Integration: Theme detection, directory paths, timing utilities
  • Minimal Dependencies: Simple C API with no bloat

Quickstart

Here's a minimal example showing how to create a window and process input events:

#include"platform.h"#include<stdio.h>intmain(void) {
// Initialize the platform libraryaxInit();
// Create a window (800x600 pixels)if (!axCreateWindow("My Application", 800, 600, 0)) {
fprintf(stderr, "Failed to create window\n");
return1;
}
// Main event loopstructAXmessagemsg;
intrunning=1;
while (running&&axGetMessage(&msg)) {
switch (msg.message) {
casekEventWindowClosed:
running=0;
break;
casekEventKeyDown:
printf("Key pressed: %d (modifiers: 0x%x)\n",
msg.keyCode, msg.modflags);
// Exit on ESC keyif (msg.keyCode==AX_KEY_ESCAPE) {
running=0;
}
break;
casekEventLeftButtonDown:
printf("Mouse clicked at: %d, %d\n", msg.x, msg.y);
break;
casekEventMouseMoved:
// Mouse position in msg.x, msg.ybreak;
casekEventWindowResized:
printf("Window resized\n");
break;
}
// Render your frame hereaxBeginPaint();
// ... OpenGL rendering calls ...axEndPaint();
}
// CleanupaxShutdown();
return0;
}

For non-blocking event loops with axPeekMessage, see docs/event-loop.md.

Compiling the Example

On Windows (MinGW/MSYS2):

gcc -o myapp main.c -L. -lplatform -lopengl32 -lgdi32 -luser32

On Linux (X11):

gcc -o myapp main.c -L. -lplatform -lX11 -lEGL -lGL

On Linux (Wayland):

gcc -o myapp main.c -L. -lplatform -lwayland-client -lwayland-egl -lEGL -lGL

On macOS:

clang -o myapp main.c -L. -lplatform -framework AppKit -framework OpenGL

On WebGL (browser via Emscripten):

emcc -o myapp.js main.c -L. -lplatform -sUSE_WEBGL2=1 -sEXPORTED_RUNTIME_METHODS=ccall,cwrap

Make sure libplatform.so (Linux) or libplatform.dylib (macOS) is in your library path or current directory.

API Overview

Initialization and Cleanup

voidaxInit(void); // Initialize the platform libraryvoidaxShutdown(void); // Clean up and shutdown

Window Management

bool_taxCreateWindow(constchar*title, uint32_twidth, uint32_theight, uint32_tflags);
bool_taxCreateSurface(uint32_twidth, uint32_theight);
bool_taxSetSize(uint32_twidth, uint32_theight, bool_tcentered);
uint32_taxGetSize(structAXsize*size);
floataxGetScaling(void); // Get display scaling factor

Event Processing

intaxPeekMessage(structAXmessage*msg); // Poll for next event (non-blocking)intaxGetMessage(structAXmessage*msg); // Get next event (blocking where supported)intaxWaitMessage(longTime_ttimeout_ms); // Wait for events with timeoutvoidaxPostMessageW(void*hobj, uint32_tevent, uint32_twparam, void*lparam);

Event Types

The library supports comprehensive event handling through the AX_Message structure:

  • Mouse Events: kEventLeftButtonDown, kEventLeftButtonUp, kEventMouseMoved, kEventScrollWheel
  • Keyboard Events: kEventKeyDown, kEventKeyUp, kEventChar
  • Window Events: kEventWindowClosed, kEventWindowResized, kEventWindowPaint
  • Drag & Drop: kEventDragDrop, kEventDragEnter

Rendering

voidaxMakeCurrentContext(void); // Make OpenGL context currentvoidaxBeginPaint(void); // Begin rendering framevoidaxEndPaint(void); // End rendering and swap buffersvoidaxBindFramebuffer(void); // Bind default framebuffer

File Dialogs

bool_taxGetOpenFileName(AXopenfilenameconst*params);
bool_taxGetSaveFileName(AXopenfilenameconst*params);
bool_taxGetFolderName(AXopenfilenameconst*params);

Networking

bool_taxNetInit(void); // Initialise networking subsystemvoidaxNetShutdown(void); // Release networking resourcesintaxNetSocket(intaf, inttype); // Create a TCP or UDP socketvoidaxNetClose(intsock); // Close a socketbool_taxNetConnect(intsock, constchar*host, uint16_tport); // Resolve host and connectintaxNetSend(intsock, constvoid*buf, intlen); // Send dataintaxNetRecv(intsock, void*buf, intlen); // Receive databool_taxNetWouldBlock(void); // Test for EAGAIN/EWOULDBLOCKbool_taxNetResolve(constchar*host, char*out, intoutlen); // DNS lookup to IP stringintaxNetPoll(intsock, intevents, inttimeout_ms); // Wait for I/O readinessbool_taxNetBind(intsock, constchar*host, uint16_tport); // Bind to a local addressbool_taxNetListen(intsock, intbacklog); // Mark socket as passiveintaxNetAccept(intsock); // Accept an incoming connection// TLS (Schannel on Windows, Secure Transport on macOS, OpenSSL on Linux)AXtlsctx*axTlsConnect(intsock, constchar*hostname); // TLS handshakevoidaxTlsClose(AXtlsctx*ctx); // Send close_notify and freeintaxTlsSend(AXtlsctx*ctx, constvoid*buf, intlen); // Send through TLSintaxTlsRecv(AXtlsctx*ctx, void*buf, intlen); // Receive through TLS

See docs/networking.md for full examples.

Remote Control

Standalone applications using GEM_STANDALONE_MAIN can be started with -rc to expose a localhost TCP control socket on port 17777:

build/bin/helloworld -rc
printf'click 120 80\n'| nc 127.0.0.1 17777
printf'screenshot /tmp/helloworld.jpg\n'| nc 127.0.0.1 17777

Use -rc PORT to select another port. Commands are newline-delimited and receive ok or err replies. The supported commands are click x y, rclick x y, move x y, scroll x y dx dy, key code, keydown code, keyup code, screenshot path, stop, and quit. Coordinates and key codes use the same logical coordinate and platform key-code conventions as native events. The server binds to IPv4 localhost traffic only through the platform socket API and runs its accept loop on a background platform thread.

System Utilities

longTime_taxGetMilliseconds(void); // Get current time in millisecondsvoidaxSleep(longTime_tmsec); // Sleep for specified millisecondsbool_taxIsDarkTheme(void); // Check if dark theme is activeconstchar*axGetPlatform(void); // Get platform nameconstchar*axSettingsDirectory(void); // Get settings directory pathconstchar*axShareDirectory(void); // Get share directory pathconstchar*axLibDirectory(void); // Get library directory path

Logging

bool_taxSetLogFile(constchar*path); // Open or close the process log fileconstchar*axGetLogFile(void); // Query current log file pathvoidaxLog(constchar*fmt, ...); // Append one formatted log linevoidaxLogFlush(void); // Flush buffered log output

Example:

charlog_path[1024];
snprintf(log_path, sizeof(log_path), "%s/myapp.log", axSettingsDirectory());
if (axSetLogFile(log_path)) {
axLog("app started on %s", axGetPlatform());
}

On WebGL builds, file logging is unavailable and axSetLogFile("...") returns FALSE.

Key Codes

The library defines comprehensive key codes including:

  • Standard ASCII characters
  • Function keys (AX_KEY_F1 - AX_KEY_F12)
  • Arrow keys (AX_KEY_UPARROW, AX_KEY_DOWNARROW, etc.)
  • Special keys (AX_KEY_ENTER, AX_KEY_ESCAPE, AX_KEY_SPACE, etc.)
  • Mouse buttons (AX_KEY_MOUSE1, AX_KEY_MOUSE2, AX_KEY_MOUSE3)
  • Modifier flags (AX_MOD_SHIFT, AX_MOD_CTRL, AX_MOD_ALT, AX_MOD_CMD)

See platform.h for the complete list of key codes and event definitions.

Integrating as a Submodule

The recommended way to use platform in your own project is to add it as a git submodule and build it as part of your Makefile — in a single compiler pass, with no intermediate .o files. This keeps rebuilds fast and the integration simple.

1. Add the submodule

git submodule add https://github.com/corepunch/platform libs/platform
git submodule update --init --recursive

2. Add to your Makefile

PLATFORM_DIR = libs/platform
PLATFORM_OUTDIR = build/lib
# Build platform into your output lib directoryplatform:
$(MAKE) -C $(PLATFORM_DIR) OUTDIR=$(abspath$(PLATFORM_OUTDIR))# Link your app against itmyapp: platform
$(CC)$(CFLAGS) -I$(PLATFORM_DIR) main.c \
-L$(PLATFORM_OUTDIR) -lplatform \
-Wl,-rpath,$(abspath$(PLATFORM_OUTDIR))\
-o myapp

Internally, platform's Makefile compiles all sources in a single pass — no .o files are generated. All source files are collected with find, converted to #include directives, and piped directly to the compiler:

$(FIND_SOURCES) | sed 's|.*|#include "&"|' | $(CC) $(CFLAGS) -x $(LANG) - $(LDFLAGS) -o $@

This means the entire library recompiles in one shot, which is extremely fast and requires no dependency tracking.

3. Clean up

clean:
$(MAKE) -C $(PLATFORM_DIR) clean
rm -f myapp

For a real-world example using this pattern, see corepunch/orca.


Building

Simple Makefile that auto-detects your platform and builds the appropriate dynamic library using wildcards for source files.

Prerequisites

Windows (MinGW/MSYS2):

  • MinGW-w64 toolchain (GCC for Windows):
    # Install via MSYS2 (https://www.msys2.org/)
    pacman -S mingw-w64-x86_64-gcc make
  • No extra libraries required — uses Win32, WGL, and Winsock2 (all included with Windows)

WebGL (Emscripten):

  • Emscripten SDK (emcc compiler):
    # Install via emsdk (https://emscripten.org/docs/getting_started/downloads.html)
    git clone https://github.com/emscripten-core/emsdk.git
    cd emsdk && ./emsdk install latest && ./emsdk activate latest
    source ./emsdk_env.sh

Linux:

  • GCC compiler
  • Wayland development libraries (preferred, for Wayland support):
    sudo apt-get install libwayland-dev libwayland-egl1-mesa libxkbcommon-dev libegl-dev libgl-dev
  • Or X11 development libraries (fallback, if Wayland is unavailable):
    sudo apt-get install libx11-dev libegl-dev libgl-dev
  • Build order: Wayland (preferred) → X11 (fallback) → unix-only (networking only)

macOS:

  • Clang compiler (included with Xcode Command Line Tools)
  • AppKit framework (included with macOS)

Build Commands

make # Build the dynamic library
emmake make # Build for WebGL (requires Emscripten environment sourced)
make clean # Clean build artifacts
make install # Install to /usr/local/lib (requires sudo; Linux/macOS only)

Output

  • Windows: libplatform.dll (+ libplatform.dll.a import library)
  • Linux: libplatform.so
  • macOS: libplatform.dylib
  • WebGL: libplatform.wasm (Emscripten side module)

The library exports platform-specific functions for window management, event handling, networking, and system utilities.

Platform Support

  • Windows: Full support via Win32 API and WGL — window creation, OpenGL rendering, native file dialogs, dark-theme detection, Winsock2 networking; built with MinGW
  • Linux (Wayland): Full support with Wayland, EGL, and OpenGL (preferred when available)
  • Linux (X11): Full support with Xlib, EGL, and OpenGL (fallback when Wayland is unavailable)
  • macOS: Full support with AppKit and Cocoa frameworks
  • QNX: Source files available (qnx/)
  • WebGL (browser): Full support via Emscripten — mouse, keyboard, scroll, and resize events; WebGL 1/2 rendering context

The Linux backend is selected automatically at build time:

  1. If Wayland libraries are detected via pkg-config, the Wayland backend is used
  2. If Wayland is unavailable but X11 libraries are detected, the X11 backend is used
  3. If neither is available, a unix-only build is produced (networking only, no windowing)

Header

Include platform.h in your project to access platform types and APIs.

About

A clean C API for windowing, input, and OpenGL context management across Windows, macOS, Linux, and web. No bloat, just what you need.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - corepunch/platform: A clean C API for windowing, input, and OpenGL context management across Windows, macOS, Linux, and web. No bloat, just what you need. · GitHub
Skip to content

Repository files navigation

7aaa527d-7867-418a-be61-5612fda46339

Axiom Platform Abstraction Toolkit

Build

A lightweight, cross-platform C library providing a unified API for window management, input/event handling, and system utilities. Designed for applications that need direct control over windowing and input without heavy framework dependencies.

Features

  • Cross-platform: Native support for Windows (Win32/WGL via MinGW), Linux (Wayland or X11), macOS (AppKit/Cocoa), QNX, and WebGL (browser)
  • Window Management: Create and manage windows with OpenGL/EGL context support
  • Event System: Unified event handling for mouse, keyboard, and window events
  • Input Processing: Comprehensive keyboard and mouse input with modifier support
  • Networking: Portable TCP/UDP sockets, DNS resolution, TLS (Schannel/Secure Transport/OpenSSL), and non-blocking I/O
  • File Dialogs: Native file open/save dialogs
  • System Integration: Theme detection, directory paths, timing utilities
  • Minimal Dependencies: Simple C API with no bloat

Quickstart

Here's a minimal example showing how to create a window and process input events:

#include"platform.h"#include<stdio.h>intmain(void) {
// Initialize the platform libraryaxInit();
// Create a window (800x600 pixels)if (!axCreateWindow("My Application", 800, 600, 0)) {
fprintf(stderr, "Failed to create window\n");
return1;
}
// Main event loopstructAXmessagemsg;
intrunning=1;
while (running&&axGetMessage(&msg)) {
switch (msg.message) {
casekEventWindowClosed:
running=0;
break;
casekEventKeyDown:
printf("Key pressed: %d (modifiers: 0x%x)\n",
msg.keyCode, msg.modflags);
// Exit on ESC keyif (msg.keyCode==AX_KEY_ESCAPE) {
running=0;
}
break;
casekEventLeftButtonDown:
printf("Mouse clicked at: %d, %d\n", msg.x, msg.y);
break;
casekEventMouseMoved:
// Mouse position in msg.x, msg.ybreak;
casekEventWindowResized:
printf("Window resized\n");
break;
}
// Render your frame hereaxBeginPaint();
// ... OpenGL rendering calls ...axEndPaint();
}
// CleanupaxShutdown();
return0;
}

For non-blocking event loops with axPeekMessage, see docs/event-loop.md.

Compiling the Example

On Windows (MinGW/MSYS2):

gcc -o myapp main.c -L. -lplatform -lopengl32 -lgdi32 -luser32

On Linux (X11):

gcc -o myapp main.c -L. -lplatform -lX11 -lEGL -lGL

On Linux (Wayland):

gcc -o myapp main.c -L. -lplatform -lwayland-client -lwayland-egl -lEGL -lGL

On macOS:

clang -o myapp main.c -L. -lplatform -framework AppKit -framework OpenGL

On WebGL (browser via Emscripten):

emcc -o myapp.js main.c -L. -lplatform -sUSE_WEBGL2=1 -sEXPORTED_RUNTIME_METHODS=ccall,cwrap

Make sure libplatform.so (Linux) or libplatform.dylib (macOS) is in your library path or current directory.

API Overview

Initialization and Cleanup

voidaxInit(void); // Initialize the platform libraryvoidaxShutdown(void); // Clean up and shutdown

Window Management

bool_taxCreateWindow(constchar*title, uint32_twidth, uint32_theight, uint32_tflags);
bool_taxCreateSurface(uint32_twidth, uint32_theight);
bool_taxSetSize(uint32_twidth, uint32_theight, bool_tcentered);
uint32_taxGetSize(structAXsize*size);
floataxGetScaling(void); // Get display scaling factor

Event Processing

intaxPeekMessage(structAXmessage*msg); // Poll for next event (non-blocking)intaxGetMessage(structAXmessage*msg); // Get next event (blocking where supported)intaxWaitMessage(longTime_ttimeout_ms); // Wait for events with timeoutvoidaxPostMessageW(void*hobj, uint32_tevent, uint32_twparam, void*lparam);

Event Types

The library supports comprehensive event handling through the AX_Message structure:

  • Mouse Events: kEventLeftButtonDown, kEventLeftButtonUp, kEventMouseMoved, kEventScrollWheel
  • Keyboard Events: kEventKeyDown, kEventKeyUp, kEventChar
  • Window Events: kEventWindowClosed, kEventWindowResized, kEventWindowPaint
  • Drag & Drop: kEventDragDrop, kEventDragEnter

Rendering

voidaxMakeCurrentContext(void); // Make OpenGL context currentvoidaxBeginPaint(void); // Begin rendering framevoidaxEndPaint(void); // End rendering and swap buffersvoidaxBindFramebuffer(void); // Bind default framebuffer

File Dialogs

bool_taxGetOpenFileName(AXopenfilenameconst*params);
bool_taxGetSaveFileName(AXopenfilenameconst*params);
bool_taxGetFolderName(AXopenfilenameconst*params);

Networking

bool_taxNetInit(void); // Initialise networking subsystemvoidaxNetShutdown(void); // Release networking resourcesintaxNetSocket(intaf, inttype); // Create a TCP or UDP socketvoidaxNetClose(intsock); // Close a socketbool_taxNetConnect(intsock, constchar*host, uint16_tport); // Resolve host and connectintaxNetSend(intsock, constvoid*buf, intlen); // Send dataintaxNetRecv(intsock, void*buf, intlen); // Receive databool_taxNetWouldBlock(void); // Test for EAGAIN/EWOULDBLOCKbool_taxNetResolve(constchar*host, char*out, intoutlen); // DNS lookup to IP stringintaxNetPoll(intsock, intevents, inttimeout_ms); // Wait for I/O readinessbool_taxNetBind(intsock, constchar*host, uint16_tport); // Bind to a local addressbool_taxNetListen(intsock, intbacklog); // Mark socket as passiveintaxNetAccept(intsock); // Accept an incoming connection// TLS (Schannel on Windows, Secure Transport on macOS, OpenSSL on Linux)AXtlsctx*axTlsConnect(intsock, constchar*hostname); // TLS handshakevoidaxTlsClose(AXtlsctx*ctx); // Send close_notify and freeintaxTlsSend(AXtlsctx*ctx, constvoid*buf, intlen); // Send through TLSintaxTlsRecv(AXtlsctx*ctx, void*buf, intlen); // Receive through TLS

See docs/networking.md for full examples.

Remote Control

Standalone applications using GEM_STANDALONE_MAIN can be started with -rc to expose a localhost TCP control socket on port 17777:

build/bin/helloworld -rc
printf'click 120 80\n'| nc 127.0.0.1 17777
printf'screenshot /tmp/helloworld.jpg\n'| nc 127.0.0.1 17777

Use -rc PORT to select another port. Commands are newline-delimited and receive ok or err replies. The supported commands are click x y, rclick x y, move x y, scroll x y dx dy, key code, keydown code, keyup code, screenshot path, stop, and quit. Coordinates and key codes use the same logical coordinate and platform key-code conventions as native events. The server binds to IPv4 localhost traffic only through the platform socket API and runs its accept loop on a background platform thread.

System Utilities

longTime_taxGetMilliseconds(void); // Get current time in millisecondsvoidaxSleep(longTime_tmsec); // Sleep for specified millisecondsbool_taxIsDarkTheme(void); // Check if dark theme is activeconstchar*axGetPlatform(void); // Get platform nameconstchar*axSettingsDirectory(void); // Get settings directory pathconstchar*axShareDirectory(void); // Get share directory pathconstchar*axLibDirectory(void); // Get library directory path

Logging

bool_taxSetLogFile(constchar*path); // Open or close the process log fileconstchar*axGetLogFile(void); // Query current log file pathvoidaxLog(constchar*fmt, ...); // Append one formatted log linevoidaxLogFlush(void); // Flush buffered log output

Example:

charlog_path[1024];
snprintf(log_path, sizeof(log_path), "%s/myapp.log", axSettingsDirectory());
if (axSetLogFile(log_path)) {
axLog("app started on %s", axGetPlatform());
}

On WebGL builds, file logging is unavailable and axSetLogFile("...") returns FALSE.

Key Codes

The library defines comprehensive key codes including:

  • Standard ASCII characters
  • Function keys (AX_KEY_F1 - AX_KEY_F12)
  • Arrow keys (AX_KEY_UPARROW, AX_KEY_DOWNARROW, etc.)
  • Special keys (AX_KEY_ENTER, AX_KEY_ESCAPE, AX_KEY_SPACE, etc.)
  • Mouse buttons (AX_KEY_MOUSE1, AX_KEY_MOUSE2, AX_KEY_MOUSE3)
  • Modifier flags (AX_MOD_SHIFT, AX_MOD_CTRL, AX_MOD_ALT, AX_MOD_CMD)

See platform.h for the complete list of key codes and event definitions.

Integrating as a Submodule

The recommended way to use platform in your own project is to add it as a git submodule and build it as part of your Makefile — in a single compiler pass, with no intermediate .o files. This keeps rebuilds fast and the integration simple.

1. Add the submodule

git submodule add https://github.com/corepunch/platform libs/platform
git submodule update --init --recursive

2. Add to your Makefile

PLATFORM_DIR = libs/platform
PLATFORM_OUTDIR = build/lib
# Build platform into your output lib directoryplatform:
$(MAKE) -C $(PLATFORM_DIR) OUTDIR=$(abspath$(PLATFORM_OUTDIR))# Link your app against itmyapp: platform
$(CC)$(CFLAGS) -I$(PLATFORM_DIR) main.c \
-L$(PLATFORM_OUTDIR) -lplatform \
-Wl,-rpath,$(abspath$(PLATFORM_OUTDIR))\
-o myapp

Internally, platform's Makefile compiles all sources in a single pass — no .o files are generated. All source files are collected with find, converted to #include directives, and piped directly to the compiler:

$(FIND_SOURCES) | sed 's|.*|#include "&"|' | $(CC) $(CFLAGS) -x $(LANG) - $(LDFLAGS) -o $@

This means the entire library recompiles in one shot, which is extremely fast and requires no dependency tracking.

3. Clean up

clean:
$(MAKE) -C $(PLATFORM_DIR) clean
rm -f myapp

For a real-world example using this pattern, see corepunch/orca.


Building

Simple Makefile that auto-detects your platform and builds the appropriate dynamic library using wildcards for source files.

Prerequisites

Windows (MinGW/MSYS2):

  • MinGW-w64 toolchain (GCC for Windows):
    # Install via MSYS2 (https://www.msys2.org/)
    pacman -S mingw-w64-x86_64-gcc make
  • No extra libraries required — uses Win32, WGL, and Winsock2 (all included with Windows)

WebGL (Emscripten):

  • Emscripten SDK (emcc compiler):
    # Install via emsdk (https://emscripten.org/docs/getting_started/downloads.html)
    git clone https://github.com/emscripten-core/emsdk.git
    cd emsdk && ./emsdk install latest && ./emsdk activate latest
    source ./emsdk_env.sh

Linux:

  • GCC compiler
  • Wayland development libraries (preferred, for Wayland support):
    sudo apt-get install libwayland-dev libwayland-egl1-mesa libxkbcommon-dev libegl-dev libgl-dev
  • Or X11 development libraries (fallback, if Wayland is unavailable):
    sudo apt-get install libx11-dev libegl-dev libgl-dev
  • Build order: Wayland (preferred) → X11 (fallback) → unix-only (networking only)

macOS:

  • Clang compiler (included with Xcode Command Line Tools)
  • AppKit framework (included with macOS)

Build Commands

make # Build the dynamic library
emmake make # Build for WebGL (requires Emscripten environment sourced)
make clean # Clean build artifacts
make install # Install to /usr/local/lib (requires sudo; Linux/macOS only)

Output

  • Windows: libplatform.dll (+ libplatform.dll.a import library)
  • Linux: libplatform.so
  • macOS: libplatform.dylib
  • WebGL: libplatform.wasm (Emscripten side module)

The library exports platform-specific functions for window management, event handling, networking, and system utilities.

Platform Support

  • Windows: Full support via Win32 API and WGL — window creation, OpenGL rendering, native file dialogs, dark-theme detection, Winsock2 networking; built with MinGW
  • Linux (Wayland): Full support with Wayland, EGL, and OpenGL (preferred when available)
  • Linux (X11): Full support with Xlib, EGL, and OpenGL (fallback when Wayland is unavailable)
  • macOS: Full support with AppKit and Cocoa frameworks
  • QNX: Source files available (qnx/)
  • WebGL (browser): Full support via Emscripten — mouse, keyboard, scroll, and resize events; WebGL 1/2 rendering context

The Linux backend is selected automatically at build time:

  1. If Wayland libraries are detected via pkg-config, the Wayland backend is used
  2. If Wayland is unavailable but X11 libraries are detected, the X11 backend is used
  3. If neither is available, a unix-only build is produced (networking only, no windowing)

Header

Include platform.h in your project to access platform types and APIs.

About

A clean C API for windowing, input, and OpenGL context management across Windows, macOS, Linux, and web. No bloat, just what you need.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - corepunch/platform: A clean C API for windowing, input, and OpenGL context management across Windows, macOS, Linux, and web. No bloat, just what you need. · GitHub
Skip to content

Repository files navigation

7aaa527d-7867-418a-be61-5612fda46339

Axiom Platform Abstraction Toolkit

Build

A lightweight, cross-platform C library providing a unified API for window management, input/event handling, and system utilities. Designed for applications that need direct control over windowing and input without heavy framework dependencies.

Features

  • Cross-platform: Native support for Windows (Win32/WGL via MinGW), Linux (Wayland or X11), macOS (AppKit/Cocoa), QNX, and WebGL (browser)
  • Window Management: Create and manage windows with OpenGL/EGL context support
  • Event System: Unified event handling for mouse, keyboard, and window events
  • Input Processing: Comprehensive keyboard and mouse input with modifier support
  • Networking: Portable TCP/UDP sockets, DNS resolution, TLS (Schannel/Secure Transport/OpenSSL), and non-blocking I/O
  • File Dialogs: Native file open/save dialogs
  • System Integration: Theme detection, directory paths, timing utilities
  • Minimal Dependencies: Simple C API with no bloat

Quickstart

Here's a minimal example showing how to create a window and process input events:

#include"platform.h"#include<stdio.h>intmain(void) {
// Initialize the platform libraryaxInit();
// Create a window (800x600 pixels)if (!axCreateWindow("My Application", 800, 600, 0)) {
fprintf(stderr, "Failed to create window\n");
return1;
}
// Main event loopstructAXmessagemsg;
intrunning=1;
while (running&&axGetMessage(&msg)) {
switch (msg.message) {
casekEventWindowClosed:
running=0;
break;
casekEventKeyDown:
printf("Key pressed: %d (modifiers: 0x%x)\n",
msg.keyCode, msg.modflags);
// Exit on ESC keyif (msg.keyCode==AX_KEY_ESCAPE) {
running=0;
}
break;
casekEventLeftButtonDown:
printf("Mouse clicked at: %d, %d\n", msg.x, msg.y);
break;
casekEventMouseMoved:
// Mouse position in msg.x, msg.ybreak;
casekEventWindowResized:
printf("Window resized\n");
break;
}
// Render your frame hereaxBeginPaint();
// ... OpenGL rendering calls ...axEndPaint();
}
// CleanupaxShutdown();
return0;
}

For non-blocking event loops with axPeekMessage, see docs/event-loop.md.

Compiling the Example

On Windows (MinGW/MSYS2):

gcc -o myapp main.c -L. -lplatform -lopengl32 -lgdi32 -luser32

On Linux (X11):

gcc -o myapp main.c -L. -lplatform -lX11 -lEGL -lGL

On Linux (Wayland):

gcc -o myapp main.c -L. -lplatform -lwayland-client -lwayland-egl -lEGL -lGL

On macOS:

clang -o myapp main.c -L. -lplatform -framework AppKit -framework OpenGL

On WebGL (browser via Emscripten):

emcc -o myapp.js main.c -L. -lplatform -sUSE_WEBGL2=1 -sEXPORTED_RUNTIME_METHODS=ccall,cwrap

Make sure libplatform.so (Linux) or libplatform.dylib (macOS) is in your library path or current directory.

API Overview

Initialization and Cleanup

voidaxInit(void); // Initialize the platform libraryvoidaxShutdown(void); // Clean up and shutdown

Window Management

bool_taxCreateWindow(constchar*title, uint32_twidth, uint32_theight, uint32_tflags);
bool_taxCreateSurface(uint32_twidth, uint32_theight);
bool_taxSetSize(uint32_twidth, uint32_theight, bool_tcentered);
uint32_taxGetSize(structAXsize*size);
floataxGetScaling(void); // Get display scaling factor

Event Processing

intaxPeekMessage(structAXmessage*msg); // Poll for next event (non-blocking)intaxGetMessage(structAXmessage*msg); // Get next event (blocking where supported)intaxWaitMessage(longTime_ttimeout_ms); // Wait for events with timeoutvoidaxPostMessageW(void*hobj, uint32_tevent, uint32_twparam, void*lparam);

Event Types

The library supports comprehensive event handling through the AX_Message structure:

  • Mouse Events: kEventLeftButtonDown, kEventLeftButtonUp, kEventMouseMoved, kEventScrollWheel
  • Keyboard Events: kEventKeyDown, kEventKeyUp, kEventChar
  • Window Events: kEventWindowClosed, kEventWindowResized, kEventWindowPaint
  • Drag & Drop: kEventDragDrop, kEventDragEnter

Rendering

voidaxMakeCurrentContext(void); // Make OpenGL context currentvoidaxBeginPaint(void); // Begin rendering framevoidaxEndPaint(void); // End rendering and swap buffersvoidaxBindFramebuffer(void); // Bind default framebuffer

File Dialogs

bool_taxGetOpenFileName(AXopenfilenameconst*params);
bool_taxGetSaveFileName(AXopenfilenameconst*params);
bool_taxGetFolderName(AXopenfilenameconst*params);

Networking

bool_taxNetInit(void); // Initialise networking subsystemvoidaxNetShutdown(void); // Release networking resourcesintaxNetSocket(intaf, inttype); // Create a TCP or UDP socketvoidaxNetClose(intsock); // Close a socketbool_taxNetConnect(intsock, constchar*host, uint16_tport); // Resolve host and connectintaxNetSend(intsock, constvoid*buf, intlen); // Send dataintaxNetRecv(intsock, void*buf, intlen); // Receive databool_taxNetWouldBlock(void); // Test for EAGAIN/EWOULDBLOCKbool_taxNetResolve(constchar*host, char*out, intoutlen); // DNS lookup to IP stringintaxNetPoll(intsock, intevents, inttimeout_ms); // Wait for I/O readinessbool_taxNetBind(intsock, constchar*host, uint16_tport); // Bind to a local addressbool_taxNetListen(intsock, intbacklog); // Mark socket as passiveintaxNetAccept(intsock); // Accept an incoming connection// TLS (Schannel on Windows, Secure Transport on macOS, OpenSSL on Linux)AXtlsctx*axTlsConnect(intsock, constchar*hostname); // TLS handshakevoidaxTlsClose(AXtlsctx*ctx); // Send close_notify and freeintaxTlsSend(AXtlsctx*ctx, constvoid*buf, intlen); // Send through TLSintaxTlsRecv(AXtlsctx*ctx, void*buf, intlen); // Receive through TLS

See docs/networking.md for full examples.

Remote Control

Standalone applications using GEM_STANDALONE_MAIN can be started with -rc to expose a localhost TCP control socket on port 17777:

build/bin/helloworld -rc
printf'click 120 80\n'| nc 127.0.0.1 17777
printf'screenshot /tmp/helloworld.jpg\n'| nc 127.0.0.1 17777

Use -rc PORT to select another port. Commands are newline-delimited and receive ok or err replies. The supported commands are click x y, rclick x y, move x y, scroll x y dx dy, key code, keydown code, keyup code, screenshot path, stop, and quit. Coordinates and key codes use the same logical coordinate and platform key-code conventions as native events. The server binds to IPv4 localhost traffic only through the platform socket API and runs its accept loop on a background platform thread.

System Utilities

longTime_taxGetMilliseconds(void); // Get current time in millisecondsvoidaxSleep(longTime_tmsec); // Sleep for specified millisecondsbool_taxIsDarkTheme(void); // Check if dark theme is activeconstchar*axGetPlatform(void); // Get platform nameconstchar*axSettingsDirectory(void); // Get settings directory pathconstchar*axShareDirectory(void); // Get share directory pathconstchar*axLibDirectory(void); // Get library directory path

Logging

bool_taxSetLogFile(constchar*path); // Open or close the process log fileconstchar*axGetLogFile(void); // Query current log file pathvoidaxLog(constchar*fmt, ...); // Append one formatted log linevoidaxLogFlush(void); // Flush buffered log output

Example:

charlog_path[1024];
snprintf(log_path, sizeof(log_path), "%s/myapp.log", axSettingsDirectory());
if (axSetLogFile(log_path)) {
axLog("app started on %s", axGetPlatform());
}

On WebGL builds, file logging is unavailable and axSetLogFile("...") returns FALSE.

Key Codes

The library defines comprehensive key codes including:

  • Standard ASCII characters
  • Function keys (AX_KEY_F1 - AX_KEY_F12)
  • Arrow keys (AX_KEY_UPARROW, AX_KEY_DOWNARROW, etc.)
  • Special keys (AX_KEY_ENTER, AX_KEY_ESCAPE, AX_KEY_SPACE, etc.)
  • Mouse buttons (AX_KEY_MOUSE1, AX_KEY_MOUSE2, AX_KEY_MOUSE3)
  • Modifier flags (AX_MOD_SHIFT, AX_MOD_CTRL, AX_MOD_ALT, AX_MOD_CMD)

See platform.h for the complete list of key codes and event definitions.

Integrating as a Submodule

The recommended way to use platform in your own project is to add it as a git submodule and build it as part of your Makefile — in a single compiler pass, with no intermediate .o files. This keeps rebuilds fast and the integration simple.

1. Add the submodule

git submodule add https://github.com/corepunch/platform libs/platform
git submodule update --init --recursive

2. Add to your Makefile

PLATFORM_DIR = libs/platform
PLATFORM_OUTDIR = build/lib
# Build platform into your output lib directoryplatform:
$(MAKE) -C $(PLATFORM_DIR) OUTDIR=$(abspath$(PLATFORM_OUTDIR))# Link your app against itmyapp: platform
$(CC)$(CFLAGS) -I$(PLATFORM_DIR) main.c \
-L$(PLATFORM_OUTDIR) -lplatform \
-Wl,-rpath,$(abspath$(PLATFORM_OUTDIR))\
-o myapp

Internally, platform's Makefile compiles all sources in a single pass — no .o files are generated. All source files are collected with find, converted to #include directives, and piped directly to the compiler:

$(FIND_SOURCES) | sed 's|.*|#include "&"|' | $(CC) $(CFLAGS) -x $(LANG) - $(LDFLAGS) -o $@

This means the entire library recompiles in one shot, which is extremely fast and requires no dependency tracking.

3. Clean up

clean:
$(MAKE) -C $(PLATFORM_DIR) clean
rm -f myapp

For a real-world example using this pattern, see corepunch/orca.


Building

Simple Makefile that auto-detects your platform and builds the appropriate dynamic library using wildcards for source files.

Prerequisites

Windows (MinGW/MSYS2):

  • MinGW-w64 toolchain (GCC for Windows):
    # Install via MSYS2 (https://www.msys2.org/)
    pacman -S mingw-w64-x86_64-gcc make
  • No extra libraries required — uses Win32, WGL, and Winsock2 (all included with Windows)

WebGL (Emscripten):

  • Emscripten SDK (emcc compiler):
    # Install via emsdk (https://emscripten.org/docs/getting_started/downloads.html)
    git clone https://github.com/emscripten-core/emsdk.git
    cd emsdk && ./emsdk install latest && ./emsdk activate latest
    source ./emsdk_env.sh

Linux:

  • GCC compiler
  • Wayland development libraries (preferred, for Wayland support):
    sudo apt-get install libwayland-dev libwayland-egl1-mesa libxkbcommon-dev libegl-dev libgl-dev
  • Or X11 development libraries (fallback, if Wayland is unavailable):
    sudo apt-get install libx11-dev libegl-dev libgl-dev
  • Build order: Wayland (preferred) → X11 (fallback) → unix-only (networking only)

macOS:

  • Clang compiler (included with Xcode Command Line Tools)
  • AppKit framework (included with macOS)

Build Commands

make # Build the dynamic library
emmake make # Build for WebGL (requires Emscripten environment sourced)
make clean # Clean build artifacts
make install # Install to /usr/local/lib (requires sudo; Linux/macOS only)

Output

  • Windows: libplatform.dll (+ libplatform.dll.a import library)
  • Linux: libplatform.so
  • macOS: libplatform.dylib
  • WebGL: libplatform.wasm (Emscripten side module)

The library exports platform-specific functions for window management, event handling, networking, and system utilities.

Platform Support

  • Windows: Full support via Win32 API and WGL — window creation, OpenGL rendering, native file dialogs, dark-theme detection, Winsock2 networking; built with MinGW
  • Linux (Wayland): Full support with Wayland, EGL, and OpenGL (preferred when available)
  • Linux (X11): Full support with Xlib, EGL, and OpenGL (fallback when Wayland is unavailable)
  • macOS: Full support with AppKit and Cocoa frameworks
  • QNX: Source files available (qnx/)
  • WebGL (browser): Full support via Emscripten — mouse, keyboard, scroll, and resize events; WebGL 1/2 rendering context

The Linux backend is selected automatically at build time:

  1. If Wayland libraries are detected via pkg-config, the Wayland backend is used
  2. If Wayland is unavailable but X11 libraries are detected, the X11 backend is used
  3. If neither is available, a unix-only build is produced (networking only, no windowing)

Header

Include platform.h in your project to access platform types and APIs.

About

A clean C API for windowing, input, and OpenGL context management across Windows, macOS, Linux, and web. No bloat, just what you need.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' GitHub - corepunch/platform: A clean C API for windowing, input, and OpenGL context management across Windows, macOS, Linux, and web. No bloat, just what you need. · GitHub
Skip to content

Repository files navigation

7aaa527d-7867-418a-be61-5612fda46339

Axiom Platform Abstraction Toolkit

Build

A lightweight, cross-platform C library providing a unified API for window management, input/event handling, and system utilities. Designed for applications that need direct control over windowing and input without heavy framework dependencies.

Features

  • Cross-platform: Native support for Windows (Win32/WGL via MinGW), Linux (Wayland or X11), macOS (AppKit/Cocoa), QNX, and WebGL (browser)
  • Window Management: Create and manage windows with OpenGL/EGL context support
  • Event System: Unified event handling for mouse, keyboard, and window events
  • Input Processing: Comprehensive keyboard and mouse input with modifier support
  • Networking: Portable TCP/UDP sockets, DNS resolution, TLS (Schannel/Secure Transport/OpenSSL), and non-blocking I/O
  • File Dialogs: Native file open/save dialogs
  • System Integration: Theme detection, directory paths, timing utilities
  • Minimal Dependencies: Simple C API with no bloat

Quickstart

Here's a minimal example showing how to create a window and process input events:

#include"platform.h"#include<stdio.h>intmain(void) {
// Initialize the platform libraryaxInit();
// Create a window (800x600 pixels)if (!axCreateWindow("My Application", 800, 600, 0)) {
fprintf(stderr, "Failed to create window\n");
return1;
}
// Main event loopstructAXmessagemsg;
intrunning=1;
while (running&&axGetMessage(&msg)) {
switch (msg.message) {
casekEventWindowClosed:
running=0;
break;
casekEventKeyDown:
printf("Key pressed: %d (modifiers: 0x%x)\n",
msg.keyCode, msg.modflags);
// Exit on ESC keyif (msg.keyCode==AX_KEY_ESCAPE) {
running=0;
}
break;
casekEventLeftButtonDown:
printf("Mouse clicked at: %d, %d\n", msg.x, msg.y);
break;
casekEventMouseMoved:
// Mouse position in msg.x, msg.ybreak;
casekEventWindowResized:
printf("Window resized\n");
break;
}
// Render your frame hereaxBeginPaint();
// ... OpenGL rendering calls ...axEndPaint();
}
// CleanupaxShutdown();
return0;
}

For non-blocking event loops with axPeekMessage, see docs/event-loop.md.

Compiling the Example

On Windows (MinGW/MSYS2):

gcc -o myapp main.c -L. -lplatform -lopengl32 -lgdi32 -luser32

On Linux (X11):

gcc -o myapp main.c -L. -lplatform -lX11 -lEGL -lGL

On Linux (Wayland):

gcc -o myapp main.c -L. -lplatform -lwayland-client -lwayland-egl -lEGL -lGL

On macOS:

clang -o myapp main.c -L. -lplatform -framework AppKit -framework OpenGL

On WebGL (browser via Emscripten):

emcc -o myapp.js main.c -L. -lplatform -sUSE_WEBGL2=1 -sEXPORTED_RUNTIME_METHODS=ccall,cwrap

Make sure libplatform.so (Linux) or libplatform.dylib (macOS) is in your library path or current directory.

API Overview

Initialization and Cleanup

voidaxInit(void); // Initialize the platform libraryvoidaxShutdown(void); // Clean up and shutdown

Window Management

bool_taxCreateWindow(constchar*title, uint32_twidth, uint32_theight, uint32_tflags);
bool_taxCreateSurface(uint32_twidth, uint32_theight);
bool_taxSetSize(uint32_twidth, uint32_theight, bool_tcentered);
uint32_taxGetSize(structAXsize*size);
floataxGetScaling(void); // Get display scaling factor

Event Processing

intaxPeekMessage(structAXmessage*msg); // Poll for next event (non-blocking)intaxGetMessage(structAXmessage*msg); // Get next event (blocking where supported)intaxWaitMessage(longTime_ttimeout_ms); // Wait for events with timeoutvoidaxPostMessageW(void*hobj, uint32_tevent, uint32_twparam, void*lparam);

Event Types

The library supports comprehensive event handling through the AX_Message structure:

  • Mouse Events: kEventLeftButtonDown, kEventLeftButtonUp, kEventMouseMoved, kEventScrollWheel
  • Keyboard Events: kEventKeyDown, kEventKeyUp, kEventChar
  • Window Events: kEventWindowClosed, kEventWindowResized, kEventWindowPaint
  • Drag & Drop: kEventDragDrop, kEventDragEnter

Rendering

voidaxMakeCurrentContext(void); // Make OpenGL context currentvoidaxBeginPaint(void); // Begin rendering framevoidaxEndPaint(void); // End rendering and swap buffersvoidaxBindFramebuffer(void); // Bind default framebuffer

File Dialogs

bool_taxGetOpenFileName(AXopenfilenameconst*params);
bool_taxGetSaveFileName(AXopenfilenameconst*params);
bool_taxGetFolderName(AXopenfilenameconst*params);

Networking

bool_taxNetInit(void); // Initialise networking subsystemvoidaxNetShutdown(void); // Release networking resourcesintaxNetSocket(intaf, inttype); // Create a TCP or UDP socketvoidaxNetClose(intsock); // Close a socketbool_taxNetConnect(intsock, constchar*host, uint16_tport); // Resolve host and connectintaxNetSend(intsock, constvoid*buf, intlen); // Send dataintaxNetRecv(intsock, void*buf, intlen); // Receive databool_taxNetWouldBlock(void); // Test for EAGAIN/EWOULDBLOCKbool_taxNetResolve(constchar*host, char*out, intoutlen); // DNS lookup to IP stringintaxNetPoll(intsock, intevents, inttimeout_ms); // Wait for I/O readinessbool_taxNetBind(intsock, constchar*host, uint16_tport); // Bind to a local addressbool_taxNetListen(intsock, intbacklog); // Mark socket as passiveintaxNetAccept(intsock); // Accept an incoming connection// TLS (Schannel on Windows, Secure Transport on macOS, OpenSSL on Linux)AXtlsctx*axTlsConnect(intsock, constchar*hostname); // TLS handshakevoidaxTlsClose(AXtlsctx*ctx); // Send close_notify and freeintaxTlsSend(AXtlsctx*ctx, constvoid*buf, intlen); // Send through TLSintaxTlsRecv(AXtlsctx*ctx, void*buf, intlen); // Receive through TLS

See docs/networking.md for full examples.

Remote Control

Standalone applications using GEM_STANDALONE_MAIN can be started with -rc to expose a localhost TCP control socket on port 17777:

build/bin/helloworld -rc
printf'click 120 80\n'| nc 127.0.0.1 17777
printf'screenshot /tmp/helloworld.jpg\n'| nc 127.0.0.1 17777

Use -rc PORT to select another port. Commands are newline-delimited and receive ok or err replies. The supported commands are click x y, rclick x y, move x y, scroll x y dx dy, key code, keydown code, keyup code, screenshot path, stop, and quit. Coordinates and key codes use the same logical coordinate and platform key-code conventions as native events. The server binds to IPv4 localhost traffic only through the platform socket API and runs its accept loop on a background platform thread.

System Utilities

longTime_taxGetMilliseconds(void); // Get current time in millisecondsvoidaxSleep(longTime_tmsec); // Sleep for specified millisecondsbool_taxIsDarkTheme(void); // Check if dark theme is activeconstchar*axGetPlatform(void); // Get platform nameconstchar*axSettingsDirectory(void); // Get settings directory pathconstchar*axShareDirectory(void); // Get share directory pathconstchar*axLibDirectory(void); // Get library directory path

Logging

bool_taxSetLogFile(constchar*path); // Open or close the process log fileconstchar*axGetLogFile(void); // Query current log file pathvoidaxLog(constchar*fmt, ...); // Append one formatted log linevoidaxLogFlush(void); // Flush buffered log output

Example:

charlog_path[1024];
snprintf(log_path, sizeof(log_path), "%s/myapp.log", axSettingsDirectory());
if (axSetLogFile(log_path)) {
axLog("app started on %s", axGetPlatform());
}

On WebGL builds, file logging is unavailable and axSetLogFile("...") returns FALSE.

Key Codes

The library defines comprehensive key codes including:

  • Standard ASCII characters
  • Function keys (AX_KEY_F1 - AX_KEY_F12)
  • Arrow keys (AX_KEY_UPARROW, AX_KEY_DOWNARROW, etc.)
  • Special keys (AX_KEY_ENTER, AX_KEY_ESCAPE, AX_KEY_SPACE, etc.)
  • Mouse buttons (AX_KEY_MOUSE1, AX_KEY_MOUSE2, AX_KEY_MOUSE3)
  • Modifier flags (AX_MOD_SHIFT, AX_MOD_CTRL, AX_MOD_ALT, AX_MOD_CMD)

See platform.h for the complete list of key codes and event definitions.

Integrating as a Submodule

The recommended way to use platform in your own project is to add it as a git submodule and build it as part of your Makefile — in a single compiler pass, with no intermediate .o files. This keeps rebuilds fast and the integration simple.

1. Add the submodule

git submodule add https://github.com/corepunch/platform libs/platform
git submodule update --init --recursive

2. Add to your Makefile

PLATFORM_DIR = libs/platform
PLATFORM_OUTDIR = build/lib
# Build platform into your output lib directoryplatform:
$(MAKE) -C $(PLATFORM_DIR) OUTDIR=$(abspath$(PLATFORM_OUTDIR))# Link your app against itmyapp: platform
$(CC)$(CFLAGS) -I$(PLATFORM_DIR) main.c \
-L$(PLATFORM_OUTDIR) -lplatform \
-Wl,-rpath,$(abspath$(PLATFORM_OUTDIR))\
-o myapp

Internally, platform's Makefile compiles all sources in a single pass — no .o files are generated. All source files are collected with find, converted to #include directives, and piped directly to the compiler:

$(FIND_SOURCES) | sed 's|.*|#include "&"|' | $(CC) $(CFLAGS) -x $(LANG) - $(LDFLAGS) -o $@

This means the entire library recompiles in one shot, which is extremely fast and requires no dependency tracking.

3. Clean up

clean:
$(MAKE) -C $(PLATFORM_DIR) clean
rm -f myapp

For a real-world example using this pattern, see corepunch/orca.


Building

Simple Makefile that auto-detects your platform and builds the appropriate dynamic library using wildcards for source files.

Prerequisites

Windows (MinGW/MSYS2):

  • MinGW-w64 toolchain (GCC for Windows):
    # Install via MSYS2 (https://www.msys2.org/)
    pacman -S mingw-w64-x86_64-gcc make
  • No extra libraries required — uses Win32, WGL, and Winsock2 (all included with Windows)

WebGL (Emscripten):

  • Emscripten SDK (emcc compiler):
    # Install via emsdk (https://emscripten.org/docs/getting_started/downloads.html)
    git clone https://github.com/emscripten-core/emsdk.git
    cd emsdk && ./emsdk install latest && ./emsdk activate latest
    source ./emsdk_env.sh

Linux:

  • GCC compiler
  • Wayland development libraries (preferred, for Wayland support):
    sudo apt-get install libwayland-dev libwayland-egl1-mesa libxkbcommon-dev libegl-dev libgl-dev
  • Or X11 development libraries (fallback, if Wayland is unavailable):
    sudo apt-get install libx11-dev libegl-dev libgl-dev
  • Build order: Wayland (preferred) → X11 (fallback) → unix-only (networking only)

macOS:

  • Clang compiler (included with Xcode Command Line Tools)
  • AppKit framework (included with macOS)

Build Commands

make # Build the dynamic library
emmake make # Build for WebGL (requires Emscripten environment sourced)
make clean # Clean build artifacts
make install # Install to /usr/local/lib (requires sudo; Linux/macOS only)

Output

  • Windows: libplatform.dll (+ libplatform.dll.a import library)
  • Linux: libplatform.so
  • macOS: libplatform.dylib
  • WebGL: libplatform.wasm (Emscripten side module)

The library exports platform-specific functions for window management, event handling, networking, and system utilities.

Platform Support

  • Windows: Full support via Win32 API and WGL — window creation, OpenGL rendering, native file dialogs, dark-theme detection, Winsock2 networking; built with MinGW
  • Linux (Wayland): Full support with Wayland, EGL, and OpenGL (preferred when available)
  • Linux (X11): Full support with Xlib, EGL, and OpenGL (fallback when Wayland is unavailable)
  • macOS: Full support with AppKit and Cocoa frameworks
  • QNX: Source files available (qnx/)
  • WebGL (browser): Full support via Emscripten — mouse, keyboard, scroll, and resize events; WebGL 1/2 rendering context

The Linux backend is selected automatically at build time:

  1. If Wayland libraries are detected via pkg-config, the Wayland backend is used
  2. If Wayland is unavailable but X11 libraries are detected, the X11 backend is used
  3. If neither is available, a unix-only build is produced (networking only, no windowing)

Header

Include platform.h in your project to access platform types and APIs.

About

A clean C API for windowing, input, and OpenGL context management across Windows, macOS, Linux, and web. No bloat, just what you need.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - corepunch/platform: A clean C API for windowing, input, and OpenGL context management across Windows, macOS, Linux, and web. No bloat, just what you need. · GitHub
Skip to content

Repository files navigation

7aaa527d-7867-418a-be61-5612fda46339

Axiom Platform Abstraction Toolkit

Build

A lightweight, cross-platform C library providing a unified API for window management, input/event handling, and system utilities. Designed for applications that need direct control over windowing and input without heavy framework dependencies.

Features

  • Cross-platform: Native support for Windows (Win32/WGL via MinGW), Linux (Wayland or X11), macOS (AppKit/Cocoa), QNX, and WebGL (browser)
  • Window Management: Create and manage windows with OpenGL/EGL context support
  • Event System: Unified event handling for mouse, keyboard, and window events
  • Input Processing: Comprehensive keyboard and mouse input with modifier support
  • Networking: Portable TCP/UDP sockets, DNS resolution, TLS (Schannel/Secure Transport/OpenSSL), and non-blocking I/O
  • File Dialogs: Native file open/save dialogs
  • System Integration: Theme detection, directory paths, timing utilities
  • Minimal Dependencies: Simple C API with no bloat

Quickstart

Here's a minimal example showing how to create a window and process input events:

#include"platform.h"#include<stdio.h>intmain(void) {
// Initialize the platform libraryaxInit();
// Create a window (800x600 pixels)if (!axCreateWindow("My Application", 800, 600, 0)) {
fprintf(stderr, "Failed to create window\n");
return1;
}
// Main event loopstructAXmessagemsg;
intrunning=1;
while (running&&axGetMessage(&msg)) {
switch (msg.message) {
casekEventWindowClosed:
running=0;
break;
casekEventKeyDown:
printf("Key pressed: %d (modifiers: 0x%x)\n",
msg.keyCode, msg.modflags);
// Exit on ESC keyif (msg.keyCode==AX_KEY_ESCAPE) {
running=0;
}
break;
casekEventLeftButtonDown:
printf("Mouse clicked at: %d, %d\n", msg.x, msg.y);
break;
casekEventMouseMoved:
// Mouse position in msg.x, msg.ybreak;
casekEventWindowResized:
printf("Window resized\n");
break;
}
// Render your frame hereaxBeginPaint();
// ... OpenGL rendering calls ...axEndPaint();
}
// CleanupaxShutdown();
return0;
}

For non-blocking event loops with axPeekMessage, see docs/event-loop.md.

Compiling the Example

On Windows (MinGW/MSYS2):

gcc -o myapp main.c -L. -lplatform -lopengl32 -lgdi32 -luser32

On Linux (X11):

gcc -o myapp main.c -L. -lplatform -lX11 -lEGL -lGL

On Linux (Wayland):

gcc -o myapp main.c -L. -lplatform -lwayland-client -lwayland-egl -lEGL -lGL

On macOS:

clang -o myapp main.c -L. -lplatform -framework AppKit -framework OpenGL

On WebGL (browser via Emscripten):

emcc -o myapp.js main.c -L. -lplatform -sUSE_WEBGL2=1 -sEXPORTED_RUNTIME_METHODS=ccall,cwrap

Make sure libplatform.so (Linux) or libplatform.dylib (macOS) is in your library path or current directory.

API Overview

Initialization and Cleanup

voidaxInit(void); // Initialize the platform libraryvoidaxShutdown(void); // Clean up and shutdown

Window Management

bool_taxCreateWindow(constchar*title, uint32_twidth, uint32_theight, uint32_tflags);
bool_taxCreateSurface(uint32_twidth, uint32_theight);
bool_taxSetSize(uint32_twidth, uint32_theight, bool_tcentered);
uint32_taxGetSize(structAXsize*size);
floataxGetScaling(void); // Get display scaling factor

Event Processing

intaxPeekMessage(structAXmessage*msg); // Poll for next event (non-blocking)intaxGetMessage(structAXmessage*msg); // Get next event (blocking where supported)intaxWaitMessage(longTime_ttimeout_ms); // Wait for events with timeoutvoidaxPostMessageW(void*hobj, uint32_tevent, uint32_twparam, void*lparam);

Event Types

The library supports comprehensive event handling through the AX_Message structure:

  • Mouse Events: kEventLeftButtonDown, kEventLeftButtonUp, kEventMouseMoved, kEventScrollWheel
  • Keyboard Events: kEventKeyDown, kEventKeyUp, kEventChar
  • Window Events: kEventWindowClosed, kEventWindowResized, kEventWindowPaint
  • Drag & Drop: kEventDragDrop, kEventDragEnter

Rendering

voidaxMakeCurrentContext(void); // Make OpenGL context currentvoidaxBeginPaint(void); // Begin rendering framevoidaxEndPaint(void); // End rendering and swap buffersvoidaxBindFramebuffer(void); // Bind default framebuffer

File Dialogs

bool_taxGetOpenFileName(AXopenfilenameconst*params);
bool_taxGetSaveFileName(AXopenfilenameconst*params);
bool_taxGetFolderName(AXopenfilenameconst*params);

Networking

bool_taxNetInit(void); // Initialise networking subsystemvoidaxNetShutdown(void); // Release networking resourcesintaxNetSocket(intaf, inttype); // Create a TCP or UDP socketvoidaxNetClose(intsock); // Close a socketbool_taxNetConnect(intsock, constchar*host, uint16_tport); // Resolve host and connectintaxNetSend(intsock, constvoid*buf, intlen); // Send dataintaxNetRecv(intsock, void*buf, intlen); // Receive databool_taxNetWouldBlock(void); // Test for EAGAIN/EWOULDBLOCKbool_taxNetResolve(constchar*host, char*out, intoutlen); // DNS lookup to IP stringintaxNetPoll(intsock, intevents, inttimeout_ms); // Wait for I/O readinessbool_taxNetBind(intsock, constchar*host, uint16_tport); // Bind to a local addressbool_taxNetListen(intsock, intbacklog); // Mark socket as passiveintaxNetAccept(intsock); // Accept an incoming connection// TLS (Schannel on Windows, Secure Transport on macOS, OpenSSL on Linux)AXtlsctx*axTlsConnect(intsock, constchar*hostname); // TLS handshakevoidaxTlsClose(AXtlsctx*ctx); // Send close_notify and freeintaxTlsSend(AXtlsctx*ctx, constvoid*buf, intlen); // Send through TLSintaxTlsRecv(AXtlsctx*ctx, void*buf, intlen); // Receive through TLS

See docs/networking.md for full examples.

Remote Control

Standalone applications using GEM_STANDALONE_MAIN can be started with -rc to expose a localhost TCP control socket on port 17777:

build/bin/helloworld -rc
printf'click 120 80\n'| nc 127.0.0.1 17777
printf'screenshot /tmp/helloworld.jpg\n'| nc 127.0.0.1 17777

Use -rc PORT to select another port. Commands are newline-delimited and receive ok or err replies. The supported commands are click x y, rclick x y, move x y, scroll x y dx dy, key code, keydown code, keyup code, screenshot path, stop, and quit. Coordinates and key codes use the same logical coordinate and platform key-code conventions as native events. The server binds to IPv4 localhost traffic only through the platform socket API and runs its accept loop on a background platform thread.

System Utilities

longTime_taxGetMilliseconds(void); // Get current time in millisecondsvoidaxSleep(longTime_tmsec); // Sleep for specified millisecondsbool_taxIsDarkTheme(void); // Check if dark theme is activeconstchar*axGetPlatform(void); // Get platform nameconstchar*axSettingsDirectory(void); // Get settings directory pathconstchar*axShareDirectory(void); // Get share directory pathconstchar*axLibDirectory(void); // Get library directory path

Logging

bool_taxSetLogFile(constchar*path); // Open or close the process log fileconstchar*axGetLogFile(void); // Query current log file pathvoidaxLog(constchar*fmt, ...); // Append one formatted log linevoidaxLogFlush(void); // Flush buffered log output

Example:

charlog_path[1024];
snprintf(log_path, sizeof(log_path), "%s/myapp.log", axSettingsDirectory());
if (axSetLogFile(log_path)) {
axLog("app started on %s", axGetPlatform());
}

On WebGL builds, file logging is unavailable and axSetLogFile("...") returns FALSE.

Key Codes

The library defines comprehensive key codes including:

  • Standard ASCII characters
  • Function keys (AX_KEY_F1 - AX_KEY_F12)
  • Arrow keys (AX_KEY_UPARROW, AX_KEY_DOWNARROW, etc.)
  • Special keys (AX_KEY_ENTER, AX_KEY_ESCAPE, AX_KEY_SPACE, etc.)
  • Mouse buttons (AX_KEY_MOUSE1, AX_KEY_MOUSE2, AX_KEY_MOUSE3)
  • Modifier flags (AX_MOD_SHIFT, AX_MOD_CTRL, AX_MOD_ALT, AX_MOD_CMD)

See platform.h for the complete list of key codes and event definitions.

Integrating as a Submodule

The recommended way to use platform in your own project is to add it as a git submodule and build it as part of your Makefile — in a single compiler pass, with no intermediate .o files. This keeps rebuilds fast and the integration simple.

1. Add the submodule

git submodule add https://github.com/corepunch/platform libs/platform
git submodule update --init --recursive

2. Add to your Makefile

PLATFORM_DIR = libs/platform
PLATFORM_OUTDIR = build/lib
# Build platform into your output lib directoryplatform:
$(MAKE) -C $(PLATFORM_DIR) OUTDIR=$(abspath$(PLATFORM_OUTDIR))# Link your app against itmyapp: platform
$(CC)$(CFLAGS) -I$(PLATFORM_DIR) main.c \
-L$(PLATFORM_OUTDIR) -lplatform \
-Wl,-rpath,$(abspath$(PLATFORM_OUTDIR))\
-o myapp

Internally, platform's Makefile compiles all sources in a single pass — no .o files are generated. All source files are collected with find, converted to #include directives, and piped directly to the compiler:

$(FIND_SOURCES) | sed 's|.*|#include "&"|' | $(CC) $(CFLAGS) -x $(LANG) - $(LDFLAGS) -o $@

This means the entire library recompiles in one shot, which is extremely fast and requires no dependency tracking.

3. Clean up

clean:
$(MAKE) -C $(PLATFORM_DIR) clean
rm -f myapp

For a real-world example using this pattern, see corepunch/orca.


Building

Simple Makefile that auto-detects your platform and builds the appropriate dynamic library using wildcards for source files.

Prerequisites

Windows (MinGW/MSYS2):

  • MinGW-w64 toolchain (GCC for Windows):
    # Install via MSYS2 (https://www.msys2.org/)
    pacman -S mingw-w64-x86_64-gcc make
  • No extra libraries required — uses Win32, WGL, and Winsock2 (all included with Windows)

WebGL (Emscripten):

  • Emscripten SDK (emcc compiler):
    # Install via emsdk (https://emscripten.org/docs/getting_started/downloads.html)
    git clone https://github.com/emscripten-core/emsdk.git
    cd emsdk && ./emsdk install latest && ./emsdk activate latest
    source ./emsdk_env.sh

Linux:

  • GCC compiler
  • Wayland development libraries (preferred, for Wayland support):
    sudo apt-get install libwayland-dev libwayland-egl1-mesa libxkbcommon-dev libegl-dev libgl-dev
  • Or X11 development libraries (fallback, if Wayland is unavailable):
    sudo apt-get install libx11-dev libegl-dev libgl-dev
  • Build order: Wayland (preferred) → X11 (fallback) → unix-only (networking only)

macOS:

  • Clang compiler (included with Xcode Command Line Tools)
  • AppKit framework (included with macOS)

Build Commands

make # Build the dynamic library
emmake make # Build for WebGL (requires Emscripten environment sourced)
make clean # Clean build artifacts
make install # Install to /usr/local/lib (requires sudo; Linux/macOS only)

Output

  • Windows: libplatform.dll (+ libplatform.dll.a import library)
  • Linux: libplatform.so
  • macOS: libplatform.dylib
  • WebGL: libplatform.wasm (Emscripten side module)

The library exports platform-specific functions for window management, event handling, networking, and system utilities.

Platform Support

  • Windows: Full support via Win32 API and WGL — window creation, OpenGL rendering, native file dialogs, dark-theme detection, Winsock2 networking; built with MinGW
  • Linux (Wayland): Full support with Wayland, EGL, and OpenGL (preferred when available)
  • Linux (X11): Full support with Xlib, EGL, and OpenGL (fallback when Wayland is unavailable)
  • macOS: Full support with AppKit and Cocoa frameworks
  • QNX: Source files available (qnx/)
  • WebGL (browser): Full support via Emscripten — mouse, keyboard, scroll, and resize events; WebGL 1/2 rendering context

The Linux backend is selected automatically at build time:

  1. If Wayland libraries are detected via pkg-config, the Wayland backend is used
  2. If Wayland is unavailable but X11 libraries are detected, the X11 backend is used
  3. If neither is available, a unix-only build is produced (networking only, no windowing)

Header

Include platform.h in your project to access platform types and APIs.

About

A clean C API for windowing, input, and OpenGL context management across Windows, macOS, Linux, and web. No bloat, just what you need.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - corepunch/platform: A clean C API for windowing, input, and OpenGL context management across Windows, macOS, Linux, and web. No bloat, just what you need. · GitHub
Skip to content

Repository files navigation

7aaa527d-7867-418a-be61-5612fda46339

Axiom Platform Abstraction Toolkit

Build

A lightweight, cross-platform C library providing a unified API for window management, input/event handling, and system utilities. Designed for applications that need direct control over windowing and input without heavy framework dependencies.

Features

  • Cross-platform: Native support for Windows (Win32/WGL via MinGW), Linux (Wayland or X11), macOS (AppKit/Cocoa), QNX, and WebGL (browser)
  • Window Management: Create and manage windows with OpenGL/EGL context support
  • Event System: Unified event handling for mouse, keyboard, and window events
  • Input Processing: Comprehensive keyboard and mouse input with modifier support
  • Networking: Portable TCP/UDP sockets, DNS resolution, TLS (Schannel/Secure Transport/OpenSSL), and non-blocking I/O
  • File Dialogs: Native file open/save dialogs
  • System Integration: Theme detection, directory paths, timing utilities
  • Minimal Dependencies: Simple C API with no bloat

Quickstart

Here's a minimal example showing how to create a window and process input events:

#include"platform.h"#include<stdio.h>intmain(void) {
// Initialize the platform libraryaxInit();
// Create a window (800x600 pixels)if (!axCreateWindow("My Application", 800, 600, 0)) {
fprintf(stderr, "Failed to create window\n");
return1;
}
// Main event loopstructAXmessagemsg;
intrunning=1;
while (running&&axGetMessage(&msg)) {
switch (msg.message) {
casekEventWindowClosed:
running=0;
break;
casekEventKeyDown:
printf("Key pressed: %d (modifiers: 0x%x)\n",
msg.keyCode, msg.modflags);
// Exit on ESC keyif (msg.keyCode==AX_KEY_ESCAPE) {
running=0;
}
break;
casekEventLeftButtonDown:
printf("Mouse clicked at: %d, %d\n", msg.x, msg.y);
break;
casekEventMouseMoved:
// Mouse position in msg.x, msg.ybreak;
casekEventWindowResized:
printf("Window resized\n");
break;
}
// Render your frame hereaxBeginPaint();
// ... OpenGL rendering calls ...axEndPaint();
}
// CleanupaxShutdown();
return0;
}

For non-blocking event loops with axPeekMessage, see docs/event-loop.md.

Compiling the Example

On Windows (MinGW/MSYS2):

gcc -o myapp main.c -L. -lplatform -lopengl32 -lgdi32 -luser32

On Linux (X11):

gcc -o myapp main.c -L. -lplatform -lX11 -lEGL -lGL

On Linux (Wayland):

gcc -o myapp main.c -L. -lplatform -lwayland-client -lwayland-egl -lEGL -lGL

On macOS:

clang -o myapp main.c -L. -lplatform -framework AppKit -framework OpenGL

On WebGL (browser via Emscripten):

emcc -o myapp.js main.c -L. -lplatform -sUSE_WEBGL2=1 -sEXPORTED_RUNTIME_METHODS=ccall,cwrap

Make sure libplatform.so (Linux) or libplatform.dylib (macOS) is in your library path or current directory.

API Overview

Initialization and Cleanup

voidaxInit(void); // Initialize the platform libraryvoidaxShutdown(void); // Clean up and shutdown

Window Management

bool_taxCreateWindow(constchar*title, uint32_twidth, uint32_theight, uint32_tflags);
bool_taxCreateSurface(uint32_twidth, uint32_theight);
bool_taxSetSize(uint32_twidth, uint32_theight, bool_tcentered);
uint32_taxGetSize(structAXsize*size);
floataxGetScaling(void); // Get display scaling factor

Event Processing

intaxPeekMessage(structAXmessage*msg); // Poll for next event (non-blocking)intaxGetMessage(structAXmessage*msg); // Get next event (blocking where supported)intaxWaitMessage(longTime_ttimeout_ms); // Wait for events with timeoutvoidaxPostMessageW(void*hobj, uint32_tevent, uint32_twparam, void*lparam);

Event Types

The library supports comprehensive event handling through the AX_Message structure:

  • Mouse Events: kEventLeftButtonDown, kEventLeftButtonUp, kEventMouseMoved, kEventScrollWheel
  • Keyboard Events: kEventKeyDown, kEventKeyUp, kEventChar
  • Window Events: kEventWindowClosed, kEventWindowResized, kEventWindowPaint
  • Drag & Drop: kEventDragDrop, kEventDragEnter

Rendering

voidaxMakeCurrentContext(void); // Make OpenGL context currentvoidaxBeginPaint(void); // Begin rendering framevoidaxEndPaint(void); // End rendering and swap buffersvoidaxBindFramebuffer(void); // Bind default framebuffer

File Dialogs

bool_taxGetOpenFileName(AXopenfilenameconst*params);
bool_taxGetSaveFileName(AXopenfilenameconst*params);
bool_taxGetFolderName(AXopenfilenameconst*params);

Networking

bool_taxNetInit(void); // Initialise networking subsystemvoidaxNetShutdown(void); // Release networking resourcesintaxNetSocket(intaf, inttype); // Create a TCP or UDP socketvoidaxNetClose(intsock); // Close a socketbool_taxNetConnect(intsock, constchar*host, uint16_tport); // Resolve host and connectintaxNetSend(intsock, constvoid*buf, intlen); // Send dataintaxNetRecv(intsock, void*buf, intlen); // Receive databool_taxNetWouldBlock(void); // Test for EAGAIN/EWOULDBLOCKbool_taxNetResolve(constchar*host, char*out, intoutlen); // DNS lookup to IP stringintaxNetPoll(intsock, intevents, inttimeout_ms); // Wait for I/O readinessbool_taxNetBind(intsock, constchar*host, uint16_tport); // Bind to a local addressbool_taxNetListen(intsock, intbacklog); // Mark socket as passiveintaxNetAccept(intsock); // Accept an incoming connection// TLS (Schannel on Windows, Secure Transport on macOS, OpenSSL on Linux)AXtlsctx*axTlsConnect(intsock, constchar*hostname); // TLS handshakevoidaxTlsClose(AXtlsctx*ctx); // Send close_notify and freeintaxTlsSend(AXtlsctx*ctx, constvoid*buf, intlen); // Send through TLSintaxTlsRecv(AXtlsctx*ctx, void*buf, intlen); // Receive through TLS

See docs/networking.md for full examples.

Remote Control

Standalone applications using GEM_STANDALONE_MAIN can be started with -rc to expose a localhost TCP control socket on port 17777:

build/bin/helloworld -rc
printf'click 120 80\n'| nc 127.0.0.1 17777
printf'screenshot /tmp/helloworld.jpg\n'| nc 127.0.0.1 17777

Use -rc PORT to select another port. Commands are newline-delimited and receive ok or err replies. The supported commands are click x y, rclick x y, move x y, scroll x y dx dy, key code, keydown code, keyup code, screenshot path, stop, and quit. Coordinates and key codes use the same logical coordinate and platform key-code conventions as native events. The server binds to IPv4 localhost traffic only through the platform socket API and runs its accept loop on a background platform thread.

System Utilities

longTime_taxGetMilliseconds(void); // Get current time in millisecondsvoidaxSleep(longTime_tmsec); // Sleep for specified millisecondsbool_taxIsDarkTheme(void); // Check if dark theme is activeconstchar*axGetPlatform(void); // Get platform nameconstchar*axSettingsDirectory(void); // Get settings directory pathconstchar*axShareDirectory(void); // Get share directory pathconstchar*axLibDirectory(void); // Get library directory path

Logging

bool_taxSetLogFile(constchar*path); // Open or close the process log fileconstchar*axGetLogFile(void); // Query current log file pathvoidaxLog(constchar*fmt, ...); // Append one formatted log linevoidaxLogFlush(void); // Flush buffered log output

Example:

charlog_path[1024];
snprintf(log_path, sizeof(log_path), "%s/myapp.log", axSettingsDirectory());
if (axSetLogFile(log_path)) {
axLog("app started on %s", axGetPlatform());
}

On WebGL builds, file logging is unavailable and axSetLogFile("...") returns FALSE.

Key Codes

The library defines comprehensive key codes including:

  • Standard ASCII characters
  • Function keys (AX_KEY_F1 - AX_KEY_F12)
  • Arrow keys (AX_KEY_UPARROW, AX_KEY_DOWNARROW, etc.)
  • Special keys (AX_KEY_ENTER, AX_KEY_ESCAPE, AX_KEY_SPACE, etc.)
  • Mouse buttons (AX_KEY_MOUSE1, AX_KEY_MOUSE2, AX_KEY_MOUSE3)
  • Modifier flags (AX_MOD_SHIFT, AX_MOD_CTRL, AX_MOD_ALT, AX_MOD_CMD)

See platform.h for the complete list of key codes and event definitions.

Integrating as a Submodule

The recommended way to use platform in your own project is to add it as a git submodule and build it as part of your Makefile — in a single compiler pass, with no intermediate .o files. This keeps rebuilds fast and the integration simple.

1. Add the submodule

git submodule add https://github.com/corepunch/platform libs/platform
git submodule update --init --recursive

2. Add to your Makefile

PLATFORM_DIR = libs/platform
PLATFORM_OUTDIR = build/lib
# Build platform into your output lib directoryplatform:
$(MAKE) -C $(PLATFORM_DIR) OUTDIR=$(abspath$(PLATFORM_OUTDIR))# Link your app against itmyapp: platform
$(CC)$(CFLAGS) -I$(PLATFORM_DIR) main.c \
-L$(PLATFORM_OUTDIR) -lplatform \
-Wl,-rpath,$(abspath$(PLATFORM_OUTDIR))\
-o myapp

Internally, platform's Makefile compiles all sources in a single pass — no .o files are generated. All source files are collected with find, converted to #include directives, and piped directly to the compiler:

$(FIND_SOURCES) | sed 's|.*|#include "&"|' | $(CC) $(CFLAGS) -x $(LANG) - $(LDFLAGS) -o $@

This means the entire library recompiles in one shot, which is extremely fast and requires no dependency tracking.

3. Clean up

clean:
$(MAKE) -C $(PLATFORM_DIR) clean
rm -f myapp

For a real-world example using this pattern, see corepunch/orca.


Building

Simple Makefile that auto-detects your platform and builds the appropriate dynamic library using wildcards for source files.

Prerequisites

Windows (MinGW/MSYS2):

  • MinGW-w64 toolchain (GCC for Windows):
    # Install via MSYS2 (https://www.msys2.org/)
    pacman -S mingw-w64-x86_64-gcc make
  • No extra libraries required — uses Win32, WGL, and Winsock2 (all included with Windows)

WebGL (Emscripten):

  • Emscripten SDK (emcc compiler):
    # Install via emsdk (https://emscripten.org/docs/getting_started/downloads.html)
    git clone https://github.com/emscripten-core/emsdk.git
    cd emsdk && ./emsdk install latest && ./emsdk activate latest
    source ./emsdk_env.sh

Linux:

  • GCC compiler
  • Wayland development libraries (preferred, for Wayland support):
    sudo apt-get install libwayland-dev libwayland-egl1-mesa libxkbcommon-dev libegl-dev libgl-dev
  • Or X11 development libraries (fallback, if Wayland is unavailable):
    sudo apt-get install libx11-dev libegl-dev libgl-dev
  • Build order: Wayland (preferred) → X11 (fallback) → unix-only (networking only)

macOS:

  • Clang compiler (included with Xcode Command Line Tools)
  • AppKit framework (included with macOS)

Build Commands

make # Build the dynamic library
emmake make # Build for WebGL (requires Emscripten environment sourced)
make clean # Clean build artifacts
make install # Install to /usr/local/lib (requires sudo; Linux/macOS only)

Output

  • Windows: libplatform.dll (+ libplatform.dll.a import library)
  • Linux: libplatform.so
  • macOS: libplatform.dylib
  • WebGL: libplatform.wasm (Emscripten side module)

The library exports platform-specific functions for window management, event handling, networking, and system utilities.

Platform Support

  • Windows: Full support via Win32 API and WGL — window creation, OpenGL rendering, native file dialogs, dark-theme detection, Winsock2 networking; built with MinGW
  • Linux (Wayland): Full support with Wayland, EGL, and OpenGL (preferred when available)
  • Linux (X11): Full support with Xlib, EGL, and OpenGL (fallback when Wayland is unavailable)
  • macOS: Full support with AppKit and Cocoa frameworks
  • QNX: Source files available (qnx/)
  • WebGL (browser): Full support via Emscripten — mouse, keyboard, scroll, and resize events; WebGL 1/2 rendering context

The Linux backend is selected automatically at build time:

  1. If Wayland libraries are detected via pkg-config, the Wayland backend is used
  2. If Wayland is unavailable but X11 libraries are detected, the X11 backend is used
  3. If neither is available, a unix-only build is produced (networking only, no windowing)

Header

Include platform.h in your project to access platform types and APIs.

About

A clean C API for windowing, input, and OpenGL context management across Windows, macOS, Linux, and web. No bloat, just what you need.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); GitHub - corepunch/platform: A clean C API for windowing, input, and OpenGL context management across Windows, macOS, Linux, and web. No bloat, just what you need. · GitHub
Skip to content

Repository files navigation

7aaa527d-7867-418a-be61-5612fda46339

Axiom Platform Abstraction Toolkit

Build

A lightweight, cross-platform C library providing a unified API for window management, input/event handling, and system utilities. Designed for applications that need direct control over windowing and input without heavy framework dependencies.

Features

  • Cross-platform: Native support for Windows (Win32/WGL via MinGW), Linux (Wayland or X11), macOS (AppKit/Cocoa), QNX, and WebGL (browser)
  • Window Management: Create and manage windows with OpenGL/EGL context support
  • Event System: Unified event handling for mouse, keyboard, and window events
  • Input Processing: Comprehensive keyboard and mouse input with modifier support
  • Networking: Portable TCP/UDP sockets, DNS resolution, TLS (Schannel/Secure Transport/OpenSSL), and non-blocking I/O
  • File Dialogs: Native file open/save dialogs
  • System Integration: Theme detection, directory paths, timing utilities
  • Minimal Dependencies: Simple C API with no bloat

Quickstart

Here's a minimal example showing how to create a window and process input events:

#include"platform.h"#include<stdio.h>intmain(void) {
// Initialize the platform libraryaxInit();
// Create a window (800x600 pixels)if (!axCreateWindow("My Application", 800, 600, 0)) {
fprintf(stderr, "Failed to create window\n");
return1;
}
// Main event loopstructAXmessagemsg;
intrunning=1;
while (running&&axGetMessage(&msg)) {
switch (msg.message) {
casekEventWindowClosed:
running=0;
break;
casekEventKeyDown:
printf("Key pressed: %d (modifiers: 0x%x)\n",
msg.keyCode, msg.modflags);
// Exit on ESC keyif (msg.keyCode==AX_KEY_ESCAPE) {
running=0;
}
break;
casekEventLeftButtonDown:
printf("Mouse clicked at: %d, %d\n", msg.x, msg.y);
break;
casekEventMouseMoved:
// Mouse position in msg.x, msg.ybreak;
casekEventWindowResized:
printf("Window resized\n");
break;
}
// Render your frame hereaxBeginPaint();
// ... OpenGL rendering calls ...axEndPaint();
}
// CleanupaxShutdown();
return0;
}

For non-blocking event loops with axPeekMessage, see docs/event-loop.md.

Compiling the Example

On Windows (MinGW/MSYS2):

gcc -o myapp main.c -L. -lplatform -lopengl32 -lgdi32 -luser32

On Linux (X11):

gcc -o myapp main.c -L. -lplatform -lX11 -lEGL -lGL

On Linux (Wayland):

gcc -o myapp main.c -L. -lplatform -lwayland-client -lwayland-egl -lEGL -lGL

On macOS:

clang -o myapp main.c -L. -lplatform -framework AppKit -framework OpenGL

On WebGL (browser via Emscripten):

emcc -o myapp.js main.c -L. -lplatform -sUSE_WEBGL2=1 -sEXPORTED_RUNTIME_METHODS=ccall,cwrap

Make sure libplatform.so (Linux) or libplatform.dylib (macOS) is in your library path or current directory.

API Overview

Initialization and Cleanup

voidaxInit(void); // Initialize the platform libraryvoidaxShutdown(void); // Clean up and shutdown

Window Management

bool_taxCreateWindow(constchar*title, uint32_twidth, uint32_theight, uint32_tflags);
bool_taxCreateSurface(uint32_twidth, uint32_theight);
bool_taxSetSize(uint32_twidth, uint32_theight, bool_tcentered);
uint32_taxGetSize(structAXsize*size);
floataxGetScaling(void); // Get display scaling factor

Event Processing

intaxPeekMessage(structAXmessage*msg); // Poll for next event (non-blocking)intaxGetMessage(structAXmessage*msg); // Get next event (blocking where supported)intaxWaitMessage(longTime_ttimeout_ms); // Wait for events with timeoutvoidaxPostMessageW(void*hobj, uint32_tevent, uint32_twparam, void*lparam);

Event Types

The library supports comprehensive event handling through the AX_Message structure:

  • Mouse Events: kEventLeftButtonDown, kEventLeftButtonUp, kEventMouseMoved, kEventScrollWheel
  • Keyboard Events: kEventKeyDown, kEventKeyUp, kEventChar
  • Window Events: kEventWindowClosed, kEventWindowResized, kEventWindowPaint
  • Drag & Drop: kEventDragDrop, kEventDragEnter

Rendering

voidaxMakeCurrentContext(void); // Make OpenGL context currentvoidaxBeginPaint(void); // Begin rendering framevoidaxEndPaint(void); // End rendering and swap buffersvoidaxBindFramebuffer(void); // Bind default framebuffer

File Dialogs

bool_taxGetOpenFileName(AXopenfilenameconst*params);
bool_taxGetSaveFileName(AXopenfilenameconst*params);
bool_taxGetFolderName(AXopenfilenameconst*params);

Networking

bool_taxNetInit(void); // Initialise networking subsystemvoidaxNetShutdown(void); // Release networking resourcesintaxNetSocket(intaf, inttype); // Create a TCP or UDP socketvoidaxNetClose(intsock); // Close a socketbool_taxNetConnect(intsock, constchar*host, uint16_tport); // Resolve host and connectintaxNetSend(intsock, constvoid*buf, intlen); // Send dataintaxNetRecv(intsock, void*buf, intlen); // Receive databool_taxNetWouldBlock(void); // Test for EAGAIN/EWOULDBLOCKbool_taxNetResolve(constchar*host, char*out, intoutlen); // DNS lookup to IP stringintaxNetPoll(intsock, intevents, inttimeout_ms); // Wait for I/O readinessbool_taxNetBind(intsock, constchar*host, uint16_tport); // Bind to a local addressbool_taxNetListen(intsock, intbacklog); // Mark socket as passiveintaxNetAccept(intsock); // Accept an incoming connection// TLS (Schannel on Windows, Secure Transport on macOS, OpenSSL on Linux)AXtlsctx*axTlsConnect(intsock, constchar*hostname); // TLS handshakevoidaxTlsClose(AXtlsctx*ctx); // Send close_notify and freeintaxTlsSend(AXtlsctx*ctx, constvoid*buf, intlen); // Send through TLSintaxTlsRecv(AXtlsctx*ctx, void*buf, intlen); // Receive through TLS

See docs/networking.md for full examples.

Remote Control

Standalone applications using GEM_STANDALONE_MAIN can be started with -rc to expose a localhost TCP control socket on port 17777:

build/bin/helloworld -rc
printf'click 120 80\n'| nc 127.0.0.1 17777
printf'screenshot /tmp/helloworld.jpg\n'| nc 127.0.0.1 17777

Use -rc PORT to select another port. Commands are newline-delimited and receive ok or err replies. The supported commands are click x y, rclick x y, move x y, scroll x y dx dy, key code, keydown code, keyup code, screenshot path, stop, and quit. Coordinates and key codes use the same logical coordinate and platform key-code conventions as native events. The server binds to IPv4 localhost traffic only through the platform socket API and runs its accept loop on a background platform thread.

System Utilities

longTime_taxGetMilliseconds(void); // Get current time in millisecondsvoidaxSleep(longTime_tmsec); // Sleep for specified millisecondsbool_taxIsDarkTheme(void); // Check if dark theme is activeconstchar*axGetPlatform(void); // Get platform nameconstchar*axSettingsDirectory(void); // Get settings directory pathconstchar*axShareDirectory(void); // Get share directory pathconstchar*axLibDirectory(void); // Get library directory path

Logging

bool_taxSetLogFile(constchar*path); // Open or close the process log fileconstchar*axGetLogFile(void); // Query current log file pathvoidaxLog(constchar*fmt, ...); // Append one formatted log linevoidaxLogFlush(void); // Flush buffered log output

Example:

charlog_path[1024];
snprintf(log_path, sizeof(log_path), "%s/myapp.log", axSettingsDirectory());
if (axSetLogFile(log_path)) {
axLog("app started on %s", axGetPlatform());
}

On WebGL builds, file logging is unavailable and axSetLogFile("...") returns FALSE.

Key Codes

The library defines comprehensive key codes including:

  • Standard ASCII characters
  • Function keys (AX_KEY_F1 - AX_KEY_F12)
  • Arrow keys (AX_KEY_UPARROW, AX_KEY_DOWNARROW, etc.)
  • Special keys (AX_KEY_ENTER, AX_KEY_ESCAPE, AX_KEY_SPACE, etc.)
  • Mouse buttons (AX_KEY_MOUSE1, AX_KEY_MOUSE2, AX_KEY_MOUSE3)
  • Modifier flags (AX_MOD_SHIFT, AX_MOD_CTRL, AX_MOD_ALT, AX_MOD_CMD)

See platform.h for the complete list of key codes and event definitions.

Integrating as a Submodule

The recommended way to use platform in your own project is to add it as a git submodule and build it as part of your Makefile — in a single compiler pass, with no intermediate .o files. This keeps rebuilds fast and the integration simple.

1. Add the submodule

git submodule add https://github.com/corepunch/platform libs/platform
git submodule update --init --recursive

2. Add to your Makefile

PLATFORM_DIR = libs/platform
PLATFORM_OUTDIR = build/lib
# Build platform into your output lib directoryplatform:
$(MAKE) -C $(PLATFORM_DIR) OUTDIR=$(abspath$(PLATFORM_OUTDIR))# Link your app against itmyapp: platform
$(CC)$(CFLAGS) -I$(PLATFORM_DIR) main.c \
-L$(PLATFORM_OUTDIR) -lplatform \
-Wl,-rpath,$(abspath$(PLATFORM_OUTDIR))\
-o myapp

Internally, platform's Makefile compiles all sources in a single pass — no .o files are generated. All source files are collected with find, converted to #include directives, and piped directly to the compiler:

$(FIND_SOURCES) | sed 's|.*|#include "&"|' | $(CC) $(CFLAGS) -x $(LANG) - $(LDFLAGS) -o $@

This means the entire library recompiles in one shot, which is extremely fast and requires no dependency tracking.

3. Clean up

clean:
$(MAKE) -C $(PLATFORM_DIR) clean
rm -f myapp

For a real-world example using this pattern, see corepunch/orca.


Building

Simple Makefile that auto-detects your platform and builds the appropriate dynamic library using wildcards for source files.

Prerequisites

Windows (MinGW/MSYS2):

  • MinGW-w64 toolchain (GCC for Windows):
    # Install via MSYS2 (https://www.msys2.org/)
    pacman -S mingw-w64-x86_64-gcc make
  • No extra libraries required — uses Win32, WGL, and Winsock2 (all included with Windows)

WebGL (Emscripten):

  • Emscripten SDK (emcc compiler):
    # Install via emsdk (https://emscripten.org/docs/getting_started/downloads.html)
    git clone https://github.com/emscripten-core/emsdk.git
    cd emsdk && ./emsdk install latest && ./emsdk activate latest
    source ./emsdk_env.sh

Linux:

  • GCC compiler
  • Wayland development libraries (preferred, for Wayland support):
    sudo apt-get install libwayland-dev libwayland-egl1-mesa libxkbcommon-dev libegl-dev libgl-dev
  • Or X11 development libraries (fallback, if Wayland is unavailable):
    sudo apt-get install libx11-dev libegl-dev libgl-dev
  • Build order: Wayland (preferred) → X11 (fallback) → unix-only (networking only)

macOS:

  • Clang compiler (included with Xcode Command Line Tools)
  • AppKit framework (included with macOS)

Build Commands

make # Build the dynamic library
emmake make # Build for WebGL (requires Emscripten environment sourced)
make clean # Clean build artifacts
make install # Install to /usr/local/lib (requires sudo; Linux/macOS only)

Output

  • Windows: libplatform.dll (+ libplatform.dll.a import library)
  • Linux: libplatform.so
  • macOS: libplatform.dylib
  • WebGL: libplatform.wasm (Emscripten side module)

The library exports platform-specific functions for window management, event handling, networking, and system utilities.

Platform Support

  • Windows: Full support via Win32 API and WGL — window creation, OpenGL rendering, native file dialogs, dark-theme detection, Winsock2 networking; built with MinGW
  • Linux (Wayland): Full support with Wayland, EGL, and OpenGL (preferred when available)
  • Linux (X11): Full support with Xlib, EGL, and OpenGL (fallback when Wayland is unavailable)
  • macOS: Full support with AppKit and Cocoa frameworks
  • QNX: Source files available (qnx/)
  • WebGL (browser): Full support via Emscripten — mouse, keyboard, scroll, and resize events; WebGL 1/2 rendering context

The Linux backend is selected automatically at build time:

  1. If Wayland libraries are detected via pkg-config, the Wayland backend is used
  2. If Wayland is unavailable but X11 libraries are detected, the X11 backend is used
  3. If neither is available, a unix-only build is produced (networking only, no windowing)

Header

Include platform.h in your project to access platform types and APIs.

About

A clean C API for windowing, input, and OpenGL context management across Windows, macOS, Linux, and web. No bloat, just what you need.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages