| git.druid.rocks | index | militantprogrammer | astral_canvas | src/ | platform/ | platform.h |
src/platform/platform.h
#ifndef PLATFORM_H
#define PLATFORM_H
#include "../input/event.h"
#include <stdbool.h>
#include <stdint.h>
/*
* Opaque window + framebuffer + input handle. Callers fill this via
* platform_open() and talk to it only through the fields and function
* pointers below; implementation is backend-private (X11 or Wayland).
*/
typedef struct Platform Platform;
typedef enum {
DISPLAY_NULL = 0,
DISPLAY_WAYLAND,
DISPLAY_X11
} DisplayKind;
typedef enum {
MODE_COMPLEX,
MODE_SIMPLE,
MODE_TEXT,
MODE_INVALID
} Mode;
typedef enum {
BACKEND_AUTO = 0,
BACKEND_X11,
BACKEND_WAYLAND,
BACKEND_INVALID
} Backend;
const char *convertBackendToString(Backend backend);
/*
* Public window state shared by both backends. After a successful
* platform_open(), fileDescriptor / flush / dispatch / pollEvents / present / destroy
* are non-NULL and implementation points at the backend struct.
*
* width/height are logical (compositor units). The CPU buffer is
* bufferWidth × bufferHeight XRGB8888 pixels with stride bytes per row; on Wayland
* bufferWidth = width * scale. pixels is invalid after resize or close —
* EVENT_RESIZE already points it at the new buffer.
*
* modifiers / buttons / mouseX/Y / pointerInside / focused are a live snapshot
* updated as events are dispatched, so the HUD (and later SGR mouse
* reporting) can read them without replaying the queue.
*/
struct Platform {
int width, height; /* logical surface size in compositor units */
int scale; /* integer buffer scale (Wayland HiDPI; X11 is 1) */
int bufferWidth, bufferHeight; /* pixel buffer size (width*scale × height*scale) */
int stride; /* bytes per row of pixels; always bufferWidth * 4 */
uint32_t *pixels; /* XRGB8888 0xFFRRGGBB, valid until the next resize/close */
bool running; /* false after EVENT_QUIT or a dead connection */
uint32_t modifiers; /* live MOD_* bits */
uint8_t buttons; /* live BUTTON_*_MASK chord */
double mouseX, mouseY; /* last known pointer, logical surface pixels */
bool pointerInside; /* true while the cursor is over the surface */
bool focused; /* true while the window has keyboard focus */
EventQueue events; /* backend-translated events, drained with platformPop() */
int (*fileDescriptor)(Platform *platform); /* display socket; poll this next to the PTY */
int (*flush)(Platform *platform); /* push pending requests to the server; 0 ok, -1 error */
int (*dispatch)(Platform *platform); /* drain already-read server messages into events */
int (*pollEvents)(Platform *platform, int timeoutMilliseconds); /* -1 block, 0 nonblock, >0 milliseconds */
int (*present)(Platform *platform); /* software upload of pixels; no-op while gpuPresent is set */
void (*destroy)(Platform *platform); /* tear down the backend; called by platformClose() */
void *implementation; /* X11* or Wayland*; NULL after destroy */
/*
* Vulkan WSI. The backend fills vulkanSurfaceExtension and
* createVulkanSurface during open. gpuPresent is set by vk_renderer_init
* once the GPU owns the window; backends then must not attach wl_shm /
* PutImage or change wl_surface buffer scale (the ICD presents).
*
* createVulkanSurface: vulkanInstance is a VkInstance handle, outSurface is
* a VkSurfaceKHR *. Returns 0 or -1.
*/
const char *vulkanSurfaceExtension; /* VK_KHR_xcb_surface or VK_KHR_wayland_surface */
int (*createVulkanSurface)(Platform *platform, void *vulkanInstance, void *outSurface);
bool gpuPresent; /* true while Vulkan is presenting to this window */
DisplayKind display;
Backend backend;
Mode mode;
};
/*
* backend: "x11", "wayland", "auto", or NULL.
* Auto prefers WAYLAND_DISPLAY, then DISPLAY, and falls back if open fails.
*/
int platformOpen(Platform *platform, const char *title, int width, int height);
void platformClose(Platform *platform);
bool platformPop(Platform *platform, Event *out);
int platformX11Open(Platform *platform, const char *title, int width, int height);
int platformWaylandOpen(Platform *platform, const char *title, int width, int height);
#endif