/*
 * platform.h - the backend interface.
 *
 * The core talks only to this interface and never includes an OS header.
 * Exactly one backend is linked into the binary, so there is a single
 * platform_init() symbol and main.c needs no #ifdef.
 *
 * All coordinates are global, logical pixels: the union of every screen laid
 * out in the display server's coordinate space.
 */
#ifndef MOUSEBOARD_PLATFORM_H
#define MOUSEBOARD_PLATFORM_H

#include <stdint.h>

#define MB_MAX_SCREENS 16

/* One monitor, positioned in the global coordinate space. */
struct mb_screen {
	int x, y, w, h;
};

/* A drawable overlay surface for one screen, ARGB8888, native byte order
 * (0xAARRGGBB). w,h are LOGICAL pixels - the core draws in these and stays
 * scale-agnostic. The backing store is w*scale by h*scale device pixels;
 * stride is device pixels per row. The renderer multiplies by scale. */
struct mb_buffer {
	uint32_t *px;
	int w, h;	/* logical size */
	int stride;	/* device pixels per row */
	int scale;	/* integer output scale (1 = non-HiDPI) */
};

enum mb_button { MB_LEFT = 0, MB_MIDDLE = 1, MB_RIGHT = 2 };

/* Keys handed to the core. Printable input arrives as its ASCII code
 * (0x20..0x7e); nothing else reaches the core except these. */
enum {
	MB_KEY_NONE = 0,	  /* overlay closed / connection lost */
	MB_KEY_ESC = 0x01000000,
	MB_KEY_BACKSPACE,
	MB_KEY_ENTER,
};

struct platform {
	int n_screens;
	struct mb_screen screens[MB_MAX_SCREENS];

	/* Return screen i's overlay buffer, cleared to fully transparent. */
	struct mb_buffer *(*frame_begin)(struct platform *, int screen);
	/* Present every buffer drawn since the last commit. */
	int (*frame_commit)(struct platform *);
	/* Block until the next key; returns an ASCII code or MB_KEY_*. */
	uint32_t (*next_key)(struct platform *);
	/* Warp the pointer to a global position. */
	int (*pointer_move)(struct platform *, int x, int y);
	/* Press (press=1) or release (press=0) a button. */
	int (*pointer_button)(struct platform *, enum mb_button, int press);
	/* Tear down the overlay and disconnect. */
	void (*teardown)(struct platform *);

	void *priv;
};

/* Run once at process start, before any argument parsing or output: the
 * Windows backend attaches to a parent console there so --help and --dry-run
 * still print from a terminal. A no-op elsewhere. */
void platform_early_init(void);

/* Bring up the backend: connect to the display server, create the fullscreen
 * overlay surfaces, and grab the keyboard. Returns NULL on failure (prints why
 * to stderr). */
struct platform *platform_init(void);

/* Sleep for ms milliseconds; used only to space out synthesized button
 * presses. Provided by the backend so the core needs no OS header. */
void platform_sleep_ms(int ms);

#endif /* MOUSEBOARD_PLATFORM_H */
