Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/dRessedAlarm184/LWXGL/llms.txt

Use this file to discover all available pages before exploring further.

Every LWXGL application follows the same three-phase lifecycle: create a window and allocate its X11 resources, loop to process events and render frames, then terminate to free all resources. Understanding this flow is essential before using any other part of the API.
GCreateWindow()  →  loop (GSimpleWindowLoop or manual)  →  GTerminateWindow()
GCreateWindow must be called before any other G* function. All LWXGL state — the X11 display connection, graphics context, back-buffer, font, and color palette — is initialised inside GCreateWindow.

Creating a Window

int GCreateWindow(int w, int h, const char* name, int bgcol);
ParameterTypeDescription
wintWindow width in pixels
hintWindow height in pixels
nameconst char*Title bar string
bgcolintBackground color — a palette index (0–15)
GCreateWindow opens a connection to the X11 display, loads the 9x15 bitmap font, allocates all 16 palette colors from the default colormap, creates the X11 window, and sets up the Pixmap back-buffer used for double buffering. Return codes:
CodeMeaning
0Success
1Could not open X11 display (XOpenDisplay returned NULL)
2Font 9x15 not found on the server
3A window is already open (call GTerminateWindow first)
Fixed-size windows: LWXGL sets both the minimum and maximum WM size hints to w × h, so the window cannot be resized by the user.

The Rendering Loop

After creating a window you need a loop that pumps X11 events and issues draw calls every frame. LWXGL provides a managed loop helper and also supports a fully manual pattern.

Managed loop — GSimpleWindowLoop

void GSimpleWindowLoop(int target_fps, void (*on_every)(int tick));
GSimpleWindowLoop runs until GWindowShouldClose() returns non-zero. On each frame it:
  1. Calls GHandleWindowEvents() to process queued X11 events (input, expose, close)
  2. Calls GRenderWindow() to draw all elements to the back-buffer and blit to the screen
  3. Calls your on_every callback (if non-NULL), passing the current tick counter (a monotonically increasing int starting at 0)
The loop caps throughput to target_fps frames per second using a high-resolution std::chrono timer. Between frames it either sleeps or yields depending on how much headroom remains. GSimpleWindowLoop also enables the debug overlay — press F12 at runtime to toggle it on and off (see Debug overlay below).
#include "libLWXGL.h"

void on_frame(int tick) {
    // called once per frame; tick counts up from 0
    if (tick % 60 == 0) {
        GCreateText(0, 10, 10, 15, "Hello, LWXGL!");
    }
}

int main(void) {
    if (GCreateWindow(640, 480, "My App", 0) != 0) return 1;

    // create elements here ...

    GSimpleWindowLoop(60, on_frame); // run at up to 60 FPS

    GTerminateWindow();
    return 0;
}

Manual loop

For cases that need custom timing, integration with an external event loop, or full control over when events and rendering happen, you can drive the loop yourself:
#include "libLWXGL.h"

int main(void) {
    if (GCreateWindow(800, 600, "Manual Loop", 0) != 0) return 1;

    while (!GWindowShouldClose()) {
        GHandleWindowEvents(); // process X11 input & window events
        GRenderWindow();       // draw frame to back-buffer, then blit
    }

    GTerminateWindow();
    return 0;
}
GHandleWindowEvents and GRenderWindow must be called together each iteration; calling one without the other will result in stale input state or a frozen display.

Closing the Window

void GDeleteWindow(void);
GDeleteWindow sets the internal closing flag to 1, which causes GWindowShouldClose() to return non-zero and breaks the loop on the next iteration. The X11 close button (the window manager’s ✕) is intercepted via the WM_DELETE_WINDOW atom and internally calls GDeleteWindow, so both code-initiated and user-initiated closes follow the same path. Custom close logic: attach a handler with GEventAttachDelete before entering the loop:
int my_on_close(void) {
    // return 1 to confirm close, 0 to cancel
    return 1;
}

GEventAttachDelete(my_on_close);
When a delete handler is registered, GDeleteWindow calls it and sets closing to whatever value the handler returns. Returning 0 cancels the close.

Cleanup

void GTerminateWindow(void);
GTerminateWindow must be called after the loop exits. It performs a full teardown in order:
  1. Calls GDeleteElement for every non-NULL slot in the element vector
  2. Frees the X11 font, graphics context, back-buffer Pixmap, and stipple Pixmap
  3. Releases all 16 allocated palette colors from the colormap
  4. Destroys the X11 window and closes the display connection
Failing to call GTerminateWindow will leak X11 resources.

Double Buffering

LWXGL renders every frame entirely into an off-screen Pixmap (the back-buffer, bb) before copying it to the visible window in one XCopyArea call. This eliminates screen tearing — the display is only updated once the complete frame is ready. GRenderWindow follows this sequence each frame:
  1. Fill the back-buffer with the background color
  2. Iterate the element vector and render each visible element onto the back-buffer
  3. Draw any active modal dialog on top
  4. Draw the debug overlay if enabled
  5. XCopyArea — blit the back-buffer to the window
  6. XSync — flush the display connection

Debug Overlay

When using GSimpleWindowLoop, the debug overlay is armed automatically. Press F12 at any time to toggle it. The overlay renders a small panel in the top-left corner of the window showing:
  • FPS — the current measured frame rate
  • FT — the rolling average frame time in microseconds (averaged over the last 60 frames)
The overlay is drawn directly onto the back-buffer each frame, so it is always up to date and never interferes with your own element layout.

Build docs developers (and LLMs) love