diff options
Diffstat (limited to 'teensy/platform/x11')
| -rw-r--r-- | teensy/platform/x11/x11.c | 191 |
1 files changed, 191 insertions, 0 deletions
diff --git a/teensy/platform/x11/x11.c b/teensy/platform/x11/x11.c new file mode 100644 index 0000000..ad85677 --- /dev/null +++ b/teensy/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; +} |
