termbox-glib: a GLib wrapper around termbox2

2 minute read Published: 2026-05-03

I published the first public version of termbox-glib, a small C wrapper around termbox2 for GLib/GObject programs and languages using GObject Introspection.

The goal is simple: make termbox2 feel natural in a GLib application. The library exposes a TbgTerminal object that owns the terminal lifetime, reports errors with GError, integrates input events with GMainContext, and ships introspection metadata for bindings such as GJS and Vala.

The current API is alpha quality. It is usable enough to write small terminal applications, and the C wrapper should already cover the useful termbox2 API surface. Source and ABI stability are not promised yet.

What is already there:

Arch Linux users can install the development package from the AUR:

paru -S termbox-glib-git

Getting started

Applications compile against the installed pkg-config package:

cc hello.c `pkg-config --cflags --libs termbox-glib-0.1` -o hello

Use the umbrella header:

#include <termbox-glib.h>

The simplest program creates a TbgTerminal, draws text into the back buffer, and presents the buffer:

#include <glib.h>
#include <termbox-glib.h>

int
main (void)
{
  g_autoptr (TbgTerminal) terminal = tbg_terminal_new (NULL);

  if (terminal == NULL)
    return 1;

  TbgAttr fg = tbg_attr_color (TBG_COLOR_GREEN, TBG_ATTR_FLAGS_BOLD);
  TbgAttr bg = tbg_attr_default ();

  tbg_terminal_print (terminal, 0, 0, fg, bg, "hello from termbox-glib", NULL);
  tbg_terminal_present (terminal, NULL);

  g_usleep (G_USEC_PER_SEC * 3);

  return 0;
}

Recording of the hello terminal example

To receive input without blocking GLib, attach the terminal event source to a GMainContext and listen to typed terminal signals:

#include <glib.h>
#include <termbox-glib.h>

static void
on_key (TbgTerminal *terminal, TbgKeyEvent *event, gpointer user_data)
{
  GMainLoop *loop = user_data;

  if (tbg_key_event_get_char (event) == 'q')
    g_main_loop_quit (loop);
}

int
main (void)
{
  g_autoptr (TbgTerminal) terminal = tbg_terminal_new (NULL);
  g_autoptr (GSource) source = NULL;
  g_autoptr (GMainLoop) loop = NULL;

  if (terminal == NULL)
    return 1;

  loop = g_main_loop_new (NULL, FALSE);
  g_signal_connect (terminal, "key", G_CALLBACK (on_key), loop);

  TbgAttr fg = tbg_attr_color (TBG_COLOR_GREEN, TBG_ATTR_FLAGS_BOLD);
  TbgAttr bg = tbg_attr_default ();
  tbg_terminal_print (terminal, 0, 0, fg, bg, "press q to quit", NULL);
  tbg_terminal_present (terminal, NULL);

  source = tbg_terminal_create_event_source (terminal, NULL);
  if (source == NULL)
    return 1;

  g_source_attach (source, NULL);
  g_main_loop_run (loop);
  g_source_destroy (source);

  return 0;
}

Recording of the event source example

Links:

A lot of the wrapper and documentation was generated with AI assistance from the termbox2 source code, then reviewed and adapted to GLib/GObject and GObject Introspection conventions.