Auto-generated GTK4 bindings for Mojo, enabling you to build native GUI applications with modern Mojo syntax.
- Overview
- Features
- Installation
- Quick Start
- Scripts
- Demo Applications
- Usage Guide
- Contributing
- License
Mojo-GTK provides comprehensive bindings for GTK4, allowing Mojo developers to create cross-platform desktop applications with native look and feel. The bindings are automatically generated from GTK's introspection data, ensuring accuracy and completeness.
-
Install GTK4 on your system:
macOS:
brew install gtk4
Ubuntu/Debian:
sudo apt-get install libgtk-4-dev
Fedora:
sudo dnf install gtk4-devel
-
Install Mojo from modular.com
Clone the repository:
git clone https://github.com/Hammad-hab/Mojo-GTK.git
cd Mojo-GTKOr download gtk.mojo which contains all the definations
-
Configure library paths in
pixi.toml:[activation.env] MODULAR_MOJO_MAX_SYSTEM_LIBS = "path/to/gtk/libs"
You can find the required paths using:
pkg-config --libs gtk4
-
Build the bindings (if needed):
python descriptgen.py python bindgen.py # OR ./gen.sh
Here's a simple "Hello World" application:
from gtk import * # make sure you have gtk.mojo
@register_passable("trivial")
struct App:
@staticmethod
fn activate(app: GTKInterface, gptr: GTKInterface):
var win = gtk_application_window_new(app)
gtk_window_set_title(win, "Hello Mojo-GTK!")
gtk_window_set_default_size(win, 400, 300)
var label = gtk_label_new("Hello from Mojo! π₯")
gtk_window_set_child(win, label)
gtk_widget_show(win)
fn main() raises:
var app = gtk_application_new("com.example.hello", 0)
_ = g_signal_connect_data(
app,
"activate",
rebind[GTKInterface](App.activate),
GTKInterface(),
None,
0
)
_ = g_application_run(app, 0, GTKInterface())Build and run:
mojo build hello.mojo
./helloGenerates a JSON file containing all GTK functions, structs, and enums by parsing GTK's introspection data.
Usage:
python descriptgen.pyOutput: Creates fn.json with complete API definitions.
Uses the JSON file generated by descriptgen.py to create gtk.mojo, which contains all the appropriate struct and function declarations.
Usage:
python bindgen.pyOutput: Generates gtk.mojo with Mojo-compatible bindings.
Builds and runs all demo applications to verify the bindings work correctly,.
Usage:
python test-demos.pyOutput: A table summarising all the demos that compiled and executed successfully
Build Summary
--------------------------------------------------------------------------------
File Errors Warnings Status Retcode
--------------------------------------------------------------------------------
main.mojo 0 1 OK -15
widgetzoo2.mojo 0 4 OK -15
widgetzoo.mojo 0 1 OK -15
old_gtk3_sample.mojo 0 5 OK -15
drawingboard.mojo 0 18 OK -15
animations.mojo 0 1 OK -15
new_dialogs.mojo 0 1 OK -15
listview.mojo 0 6 OK -15
image.mojo 0 12 OK -15
dialogs.mojo 0 1 OK -15
editor.mojo 0 1 OK -15
opengl.mojo 0 17 OK -15
layout.mojo 0 6 OK -15
forms.mojo 0 1 OK -15
--------------------------------------------------------------------------------
TOTAL 0 75
The /gtk-demos directory contains 13+ example applications demonstrating various GTK features:
| Demo | Description |
|---|---|
animations.mojo |
Smooth CSS-based animations and transitions |
dialogs.mojo |
Legacy dialog system for gtk4 |
new_dialogs.mojo |
Modern gtk dialog implementations |
image.mojo |
Image loading and display |
listview.mojo |
List and grid views with custom models |
forms.mojo |
Form inputs and validation |
layout.mojo |
Different layout managers (Box, Grid, etc.) |
opengl.mojo |
OpenGL rendering in GTK |
widgetzoo.mojo |
Showcase of all available widgets |
widgetzoo2.mojo |
Additional widget demonstrations |
old_gtk3_sample.mojo |
Legacy GTK3 compatibility example |
drawingboard.mojo |
Custom drawing with Cairo |
editor.mojo |
Simple text editor implementation |
main.mojo |
Comprehensive application example |
Run any demo:
mojo build gtk-demos/animations.mojo
./animationsAll functions and types bear a similar or exactly the same name as their C GTK counterparts, with one important exception:
- Functions: Same as C (e.g.,
gtk_window_new,gtk_button_set_label) - Enums: Slightly differ from their C versions, (e.g
GTK_ORIENTATION->GTKOrientation) - Structs: Prefixed with "GTK" (e.g.,
GdkRGBAβGTKRGBA)
Examples:
# C GTK
GdkRGBA color;
gtk_color_chooser_get_rgba(chooser, &color);
# Mojo-GTK
var rgba_ptr = LegacyUnsafePointer[GTKRGBA].alloc(1)
gtk_color_chooser_get_rgba(dialog, rgba_ptr) Most opaque GTK pointers are represented using the GTKInterface type:
var window: GTKInterface = gtk_application_window_new(app)
var button: GTKInterface = gtk_button_new_with_label("Click Me")
gtk_window_set_child(window, button)Due to Mojo's current limitations with C-compatible function pointers, callbacks require a specific pattern:
- Create a
@register_passable("trivial")struct - Define a static method for your callback
- Pass the static method using
rebind[GTKInterface]()
Example:
@register_passable("trivial")
struct ButtonHandler:
@staticmethod
fn on_clicked(button: GTKInterface, user_data: GTKInterface):
print("Button clicked!")
# Connect the callback
_ = g_signal_connect_data(
button,
"clicked",
rebind[GTKInterface](ButtonHandler.on_clicked),
GTKInterface(), # user_data
None,
0
)Pattern for custom data:
@register_passable("trivial")
struct AppState:
var counter: Int
fn __init__(out self):
self.counter = 0
@register_passable("trivial")
struct Handler:
@staticmethod
fn on_click(btn: GTKInterface, user_data: GTKInterface):
var state_ptr = rebind[LegacyUnsafePointer[AppState]](user_data)
state_ptr[].