• home

  • blogs

    æ
  • art

  • games

  • projects

● dec2bin

Author(s): Renato Sanchez

Published on Thu Jan 01 2026

Summary: simple GTK base number converter, written in C.

URL: https://github.com/renatosanz/dec2bin

#algorithms

#linux

#GTK


A fast, native, keyboard-friendly number base converter for the GNOME desktop.

dec2bin preview

  • Version: 0.1
  • License: GPL-3.0-or-later
  • Language: C (GNU11)
  • UI Toolkit: GTK4 + Libadwaita

What is it?

dec2bin is a pure-C, GTK4 desktop application that converts numbers between the four most common numerical bases — binary (2), octal (8), decimal (10), and hexadecimal (16) — in real time, in both directions, with no web dependency and no bloat. It is not un encrusted webview wrapped around a JavaScript snippet: the entire conversion engine, input validation, and UI are hand-written, compiled, and native.

Why?

When I started at programming C was my first programming language, but I used in just scholar-like project, nothing more complex. Just after C I jumped on web, but more recently I got tired of all the ionic and PWA’s out there. So I decided to treat myself with a small project to break the ice and work on some real tools for people like me (just at the beginning) and then build more complex apps. Open source is a must. I got a lot of fun working on this project; Is it very useful? Maybe not, but this helped me to he fear on working with UI in C (thank god for GTK4 and libadwaita).

Some key points

1. Reusable Conversion Core -> src/dec2bin.c

The heart of the app — a modular engine with a clean separation of concerns:

  • from_<base>(input) converts any supported base → decimal using the classic positional-weighting algorithm (digit × base^position, summed right-to-left).
  • to_<base>(input) converts decimal → any base using repeated division with a custom string buffer, complemented by an in-place reverse() routine (src/dec2bin.c:15).
  • convert() (src/dec2bin.c:153) orchestrates everything: optional regex validation, base-to-decimal, then decimal-to-target in a single function. The intermediate decimal value keeps the 4×4 matrix of base-pair conversions down to only 8 total functions.

2. Signal-Loop-Proof Real-Time UI -> src/main.c

The app converts on every keystroke. The tricky part: updating the output field fires its own "changed" signal, which would trigger a reverse conversion and an infinite feedback loop.

The solution uses signal blocking:

g_signal_handlers_block_matched(G_OBJECT(editable_to), ...); // freeze echo
gtk_editable_set_text(GTK_EDITABLE(editable_to), converted_value);
g_signal_handlers_unblock_matched(G_OBJECT(editable_to), ...); // unfreeze

(src/main.c:59) — both bidirectional callbacks (left→right, right→left) are wired symmetrically, so either field is always the authoritative input.

3. Declarative UI via Blueprint -> data/ui/dec2bin.blp

The interface is authored in Blueprint (human-friendly XML-alternative) and compiled to .ui at build time through blueprint-compiler, then embedded in the binary as a GResource via Meson’s gnome.compile_resources() → zero runtime file dependencies.

4. Keyboard Shortcut Layer -> src/keybindings.c

A reusable add_keyboard_shortcut() helper wraps GtkShortcutController + GtkKeyvalTrigger + GtkCallbackAction, enabling:

  • Ctrl+Q — quit
  • Ctrl+X — swap input/output bases
  • Ctrl+Backspace — clear both fields

Architecture Map

┌─────────────────────────────────────────────────────────────┐
│                        main.c                               │
│   window wiring · signal plumbing · widget lookup           │
│   (builder loads embedded .ui from GResource)               │
├──────────────────────────┬──────────────────────────────────┤
│       dec2bin.c          │         keybindings.c            │
│   conversion core        │   GtkShortcutController layer    │
│   regex validation       │   Ctrl+Q / Ctrl+X / Ctrl+BC      │
├──────────────────────────┴──────────────────────────────────┤
│                       types.h / dec2bin.h                   │
│        shared state: InputData (entry, dropdown,            │
│        last_state, compiled regex)                          │
└─────────────────────────────────────────────────────────────┘

Build pipeline: Blueprint (.blp) → Greenfield XML → GResource → single native binary orchestrated by Meson + Ninja.

back to the top