aboutsummaryrefslogtreecommitdiff
path: root/platform/x11
diff options
context:
space:
mode:
authoriamcheeseman <[email protected]>2026-05-24 17:00:30 -0400
committeriamcheeseman <[email protected]>2026-05-24 17:00:30 -0400
commit09d34f7b62f0bbf49b8c946b23c29cc51e7d67f9 (patch)
tree7e59d734447e923a6c4b0661c489d2aea65480d9 /platform/x11
parent39a02a3bf2fe923d595e4f8df693a524c47291d5 (diff)
move `teensy/platform` -> `platform/`
Diffstat (limited to 'platform/x11')
-rw-r--r--platform/x11/x11.c191
1 files changed, 191 insertions, 0 deletions
diff --git a/platform/x11/x11.c b/platform/x11/x11.c
new file mode 100644
index 0000000..ad85677
--- /dev/null
+++ b/platform/x11/x11.c
@@ -0,0 +1,191 @@
+// WARNING: CURRENTLY UNMAINTAINED IN FAVOR OF THE GL PLATFORM
+//
+// This platform is very restrictive and has issues with shearing. It is more
+// pure than OpenGL, but it has some undesired artifacts such as shearing.
+
+#include <unistd.h>
+#include <time.h>
+#include <sys/time.h>
+#include <string.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#include "teensy.h"
+#include "teensy_common.h"
+#include "teensy_platform.h"
+
+#define SEC2NANO ((uint64_t)1000000000)
+
+typedef struct {
+ Display *dis;
+ Window root;
+ Window win;
+ GC gc;
+ int scr;
+
+ Atom wm_delete_window;
+
+ bool should_close;
+ uint64_t initial_time;
+} X11_Platform;
+
+X11_Platform p;
+
+static
+int err_handler(Display *dis, XErrorEvent *ev)
+{
+ char msg[1024];
+ XGetErrorText(dis, ev->error_code, msg, 1024);
+ ty_log_fatal(
+ TY_PLATFORM_ERR,
+ "X Error (0x%x): %s",
+ ev->error_code,
+ msg
+ );
+ return 0;
+}
+
+void ty_platform_init(ty_Ctx *ctx)
+{
+ XSetErrorHandler(err_handler);
+
+ struct timespec ts;
+ clock_gettime(CLOCK_REALTIME, &ts);
+ p.initial_time = (uint64_t)ts.tv_sec * SEC2NANO + (uint64_t)ts.tv_nsec;
+
+ p.dis = XOpenDisplay(0);
+ p.root = XDefaultRootWindow(p.dis);
+ p.scr = DefaultScreen(p.dis);
+
+ XSetWindowAttributes attributes = {};
+ attributes.background_pixel = 0x00000000;
+ attributes.event_mask =
+ StructureNotifyMask |
+ KeyPressMask |
+ KeyReleaseMask;
+
+
+ p.win = XCreateWindow(
+ p.dis,
+ p.root,
+ 0, 0,
+ ctx->hints.scr_width, ctx->hints.scr_height,
+ 0,
+ DefaultDepth(p.dis, p.scr),
+ CopyFromParent,
+ DefaultVisual(p.dis, p.scr),
+ CWBackPixel | CWEventMask,
+ &attributes
+ );
+
+ p.gc = XCreateGC(p.dis, p.win, 0, NULL);
+
+ XMapWindow(p.dis, p.win);
+
+ p.wm_delete_window = XInternAtom(
+ p.dis,
+ "WM_DELETE_WINDOW",
+ false
+ );
+
+ p.should_close = false;
+}
+
+void ty_platform_deinit(void)
+{
+ XUnmapWindow(p.dis, p.win);
+ XFreeGC(p.dis, p.gc);
+ XDestroyWindow(p.dis, p.win);
+ XCloseDisplay(p.dis);
+}
+
+static
+void display_image(ty_Image img)
+{
+ size_t size = img.width * img.height;
+ // Don't use ty_alloc cause it will be owned and freed by Xlib
+ uint32_t *xdata = malloc(sizeof(uint32_t) * size);
+ for (int i = 0; i < size; i++) {
+ uint8_t r = img.data[i].r;
+ uint8_t g = img.data[i].g;
+ uint8_t b = img.data[i].b;
+ xdata[i] = ((uint32_t)r << 16) | ((uint32_t)g << 8) | (uint32_t)b;
+ }
+
+ XImage *image = XCreateImage(
+ p.dis,
+ DefaultVisual(p.dis, p.scr),
+ DefaultDepth(p.dis, p.scr),
+ ZPixmap,
+ 0,
+ (char*)xdata,
+ img.width,
+ img.height,
+ 32,
+ 0
+ );
+
+ XPutImage(
+ p.dis,
+ p.win,
+ p.gc,
+ image,
+ 0, 0, 0, 0,
+ img.width,
+ img.height
+ );
+
+ XFlush(p.dis);
+
+ XDestroyImage(image);
+}
+
+static
+void handle_keypress(XEvent ev)
+{
+ XKeyPressedEvent *kp_ev = (XKeyPressedEvent*)&ev;
+ if (kp_ev->keycode == XKeysymToKeycode(p.dis, XK_Escape)) {
+ p.should_close = true;
+ }
+}
+
+static
+void handle_client_msg(XEvent ev)
+{
+ if ((Atom)ev.xclient.data.l[0] == p.wm_delete_window)
+ p.should_close = true;
+}
+
+void ty_platform_frame(ty_Image img)
+{
+ XPending(p.dis);
+
+ while (QLength(p.dis)) {
+ XEvent ev;
+ XNextEvent(p.dis, &ev);
+
+ switch (ev.type) {
+ case KeyPress:
+ case KeyRelease: handle_keypress(ev); break;
+ case ClientMessage: handle_client_msg(ev); break;
+ }
+ }
+
+ display_image(img);
+}
+
+bool ty_platform_os_wants_quit(void)
+{
+ return p.should_close;
+}
+
+// Thanks GLFW, ily
+// https://github.com/glfw/glfw/blob/master/src/posix_time.c#L52
+double ty_platform_get_time(void)
+{
+ struct timespec ts;
+ clock_gettime(CLOCK_REALTIME, &ts);
+ uint64_t timensec = (uint64_t)ts.tv_sec * SEC2NANO + (uint64_t)ts.tv_nsec;
+ return (double)(timensec - p.initial_time) / SEC2NANO;
+}