# While making a mojo GUI UI , lessons learned

**URL:** <https://forum.modular.com/t/while-making-a-mojo-gui-ui-lessons-learned/1539>\
**Category:** Mojo\
**Created:** [May 29, 2025, 12:54pm UTC](https://forum.modular.com/t/while-making-a-mojo-gui-ui-lessons-learned/1539 "2025-05-29T12:54:27Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![alexone](https://avatars.discourse-cdn.com/v4/letter/a/977dab/32.png) [@alexone](https://forum.modular.com/u/alexone)\
**Post date:** [May 29, 2025, 12:54pm UTC](https://forum.modular.com/t/while-making-a-mojo-gui-ui-lessons-learned/1539/1 "2025-05-29T12:54:27Z")

</div>

i

 ![image](https://us1.discourse-cdn.com/flex001/uploads/modular/original/1X/da0cec7b095a33366b0dcac080bb2b96d79454e3.png)  
OpenGL !!!

* * *

had claude code draft documents on how a pure mojo( c bindings also) GUI UI was made. I used some stuff I remembered back in my coding days before I retired. # 🚀 MOJO GUI BREAKTHROUGH - First Working GUI Framework in Mojo

## Executive Summary

We have successfully created the **FIRST WORKING GUI FRAMEWORK** in Mojo by solving critical FFI (Foreign Function Interface) challenges that were preventing GUI development. This enables native GUI applications in Mojo with professional menus, widgets, and event handling.

## The Problem We Solved

### 1. The FFI String Array Crash

**Problem** : Mojo would crash with segmentation faults when accessing C string arrays:

```c
// THIS CRASHES - Don't do this!
char strings[256][1024]; // C side
int DrawText(int string_id, float font_size) {
    XDrawString(..., state.strings[string_id], ...); // SEGFAULT!
}

```

**Solution** : Direct string passing without arrays:

```c
// THIS WORKS - Direct string passing
int DrawTextDirect(const char* text, float font_size) {
    XDrawString(..., text, strlen(text));
    return 0;
}

```

### 2. The DLHandle Pattern Discovery

the correct pattern for loading C libraries in Mojo:

```mojo
# The Working Pattern
struct X11GuiBindings:
    var handle: DLHandle
    
    fn __init__ (inout self) raises:
        self.handle = DLHandle("./libmojox11.so")
        print("Loaded GUI library")
    
    fn DrawRect(self, width: Float32, height: Float32) raises -> Int32:
        var f = self.handle.get_function[fn(Float32, Float32) -> Int32]("DrawRect")
        return f(width, height)

```

## Key Design Principles

### 1. Simple C Functions Only

**RULE** : Every C function must have simple parameter types only:

- ✅ `int`, `float`, `double`
- ✅ Individual parameters
- ❌ Arrays, pointers to arrays
- ❌ Complex structs
- ❌ String parameters (except with special handling)

### 2. Build Complex Data Piece by Piece

Instead of passing arrays or complex data, build them incrementally:

```c
// String building - character by character
int StrRegister(int ch, int position, int string_id) {
    if (string_id < 0 || string_id >= 256) return -1;
    state.strings[string_id][position] = (char)ch;
    return 0;
}

int StrClear(int string_id) {
    memset(state.strings[string_id], 0, 1024);
    return 0;
}

```

Mojo side:

```mojo
fn register_string(gui: X11GuiBindings, text: String, string_id: Int32) raises:
    _ = gui.StrClear(string_id)
    for i in range(len(text)):
        _ = gui.StrRegister(ord(text[i]), i, string_id)

```

### 3. State Management in C

Keep all complex state on the C side:

```c
static struct {
    Display *display;
    Window window;
    GC gc;
    char strings[256][1024]; // Internal only - never exposed in API
    float draw_color[4];
    float draw_pos[2];
} state = {0};

```

## Working Implementation Details

### Window Creation

```mojo
var gui = X11GuiBindings()
_ = gui.WinInit()
_ = gui.WinSetSize(800, 600)
register_string(gui, "My Mojo GUI App", 0)
_ = gui.WinSetTitle(0) // Use string ID, not string
_ = gui.WinCreate()

```

### Event Loop

```mojo
while True:
    var event_type = gui.EventPoll()
    if event_type == EVENT_CLOSE:
        break
    
    var mouse_x = gui.EventGetMouseX()
    var mouse_y = gui.EventGetMouseY()
    
    if event_type == EVENT_KEY_PRESS:
        var key = gui.EventGetKey()
        var char = gui.EventGetChar()

```

### Drawing Operations

```mojo
_ = gui.FrameBegin()

# Draw background
_ = gui.DrawSetColor(0.1, 0.1, 0.15, 1.0)
_ = gui.DrawSetPos(0.0, 0.0)
_ = gui.DrawRect(800.0, 600.0)

# Draw text using registered string
_ = gui.DrawSetColor(1.0, 1.0, 1.0, 1.0)
_ = gui.DrawSetPos(100.0, 100.0)
_ = gui.DrawText(string_id, 14.0)

_ = gui.FrameEnd()

```

## What Works vs What Doesn’t

### ✅ WORKS: Simple Function Signatures

```c
int DrawSetColor(float r, float g, float b, float a);
int DrawSetPos(float x, float y);
int EventGetKey();
float EventGetMouseX();

```

### ❌ DOESN’T WORK: Complex Parameters

```c
// Arrays cause crashes
void SetColors(float colors[4]); // CRASH
void LoadMatrix(float matrix[16]); // CRASH

// String parameters are problematic
void DrawString(const char* text); // RISKY

// Structs don't translate well
void SetRect(struct Rect r); // DOESN'T WORK

```

## Lessons Learned

### 1. **Incremental Data Building**

Instead of passing complex data, build it piece by piece:

```mojo
# Matrix example
for row in range(4):
    for col in range(4):
        _ = gui.MatrixSetValue(matrix_id, row, col, value)
_ = gui.MatrixApply(matrix_id)

```

### 2. **ID-Based Resource Management**

Use integer IDs for all resources:

- String IDs (0-255)
- Window IDs
- Shader IDs
- Matrix IDs

### 3. **Avoid Mojo Collection Types in C Interface**

Mojo’s List, Dict, etc. don’t map to C. Keep collections on one side only.

### 4. **Direct String Solution**

For cases where you must pass strings directly:

```mojo
# Using the working pattern from X11
fn DrawTextDirect(self, text: String, font_size: Float32) raises -> Int32:
    var f = self.handle.get_function[fn(UnsafePointer[Int8], Float32) -> Int32]("DrawTextDirect")
    return f(text.unsafe_ptr(), font_size)

```

## Complete Working Example

```mojo
from x11_gui_bindings import X11GuiBindings, register_string, EVENT_CLOSE

fn main() raises:
    var gui = X11GuiBindings()
    
    # Initialize
    _ = gui.WinInit()
    _ = gui.WinSetSize(800, 600)
    register_string(gui, "First Mojo GUI!", 0)
    _ = gui.WinSetTitle(0)
    _ = gui.WinCreate()
    
    # Main loop
    while True:
        var event = gui.EventPoll()
        if event == EVENT_CLOSE:
            break
        
        _ = gui.FrameBegin()
        
        # Draw
        _ = gui.DrawSetColor(0.2, 0.3, 0.4, 1.0)
        _ = gui.DrawSetPos(0.0, 0.0)
        _ = gui.DrawRect(800.0, 600.0)
        
        _ = gui.FrameEnd()
    
    _ = gui.WinDestroy(0)

```

## Impact

This enables:

- ✅ Native GUI applications in Mojo
- ✅ Professional menu systems
- ✅ Interactive widgets (buttons, text boxes, sliders)
- ✅ Real-time event handling
- ✅ Smooth animations
- ✅ Cross-platform potential (X11 → Wayland, Windows, macOS)

# Mojo X11 GUI Widget System

## Overview

We’ve successfully built a complete GUI widget system for Mojo using X11, featuring:

### Core Components

1. **Extended C Wrapper** (`mojo_x11_wrapper_extended.c`)

2. **Mojo FFI Bindings** (`x11_gui_bindings.mojo`)

3. **GUI Types** (`gui_types.mojo`)

4. **Widget System** (`gui_widgets_fixed.mojo`)

## Implemented Widgets

### TextBox

- Text input with cursor positioning
- Keyboard navigation (arrows, home, end)
- Character insertion and deletion
- Placeholder text
- Focus highlighting
- Cursor blinking

### Checkbox

- Toggle state on click
- Hover highlighting
- Label rendering
- Customizable colors

### Slider

- Horizontal and vertical orientations
- Drag-to-adjust value
- Range constraints
- Visual feedback on hover/drag

## Build and Run

```bash
# Build everything
make clean
make all

# Run the GUI demo
make run-gui

# Or directly:
LD_LIBRARY_PATH=. ./gui_demo

```

## Key Solutions

1. **FFI Pattern** : Used DLHandle with explicit library loading instead of external\_call
2. **Color Handling** : Created Color struct to avoid tuple copying issues
3. **String Conversion** : Implemented custom int\_to\_string function
4. **Event System** : Proper event routing to widgets with focus management

## Next Steps

To complete the GUI framework, you could add:

1. **RadioButton** - Exclusive selection groups
2. **ScrollBar** - For scrollable content
3. **DropDown/ComboBox** - Using subwindows
4. **TabView** - Multi-tab interface
5. **Layout System** - Automatic widget positioning
6. **Theme System** - Customizable widget styles
7. **Text Selection** - In TextBox widget
8. **Multi-line TextBox** - For text areas
9. **Menu System** - Context and dropdown menus
10. **Dialog Windows** - Modal dialogs

## Example Usage

```mojo
# Create a textbox
var textbox = TextBox(50.0, 50.0, 300.0, 30.0, "Enter text...", 10)

# Handle events in main loop
textbox.handle_event(gui, event, mouse_x, mouse_y)

# Update widget state
textbox.update(delta_time)

# Draw widget
textbox.draw(gui)

```

The system is fully functional and provides a solid foundation for building GUI applications in Mojo!  
we already built everything.. just this morning – on OpenGl.. TEXT renderiing does not work on OpenGL, right now, on x11 it does, I am trying different things to make the darn text work on OpenGL.

---

<div class="post-metadata">

**Author:** ![rd4com](https://avatars.discourse-cdn.com/v4/letter/r/cdc98d/32.png) [@rd4com](https://forum.modular.com/u/rd4com)\
**Post date:** [May 29, 2025, 7:53pm UTC](https://forum.modular.com/t/while-making-a-mojo-gui-ui-lessons-learned/1539/2 "2025-05-29T19:53:05Z")

</div>

Nice 👍,  
check out `.unsafe_cstr_ptr()` as an alternative to `.unsafe_ptr()`  
(depending on the mojo version of the mojoproject)

---

<div class="post-metadata">

**Author:** ![alexone](https://avatars.discourse-cdn.com/v4/letter/a/977dab/32.png) [@alexone](https://forum.modular.com/u/alexone)\
**Post date:** [May 29, 2025, 8:05pm UTC](https://forum.modular.com/t/while-making-a-mojo-gui-ui-lessons-learned/1539/3 "2025-05-29T20:05:39Z")

</div>

![image](https://us1.discourse-cdn.com/flex001/uploads/modular/original/1X/2cbc31d80eb83f22d96e4fd4924187c574c99dba.png)  
thank you. i got the functionality working on opengl, it is ugly af..gotta work on its beauty  
now. i will give your suggestion testing..

---

<div class="post-metadata">

**Author:** ![rd4com](https://avatars.discourse-cdn.com/v4/letter/r/cdc98d/32.png) [@rd4com](https://forum.modular.com/u/rd4com)\
**Post date:** [May 29, 2025, 8:08pm UTC](https://forum.modular.com/t/while-making-a-mojo-gui-ui-lessons-learned/1539/4 "2025-05-29T20:08:28Z")

</div>

🥳 It seem to work and have layouts, great job

---

<div class="post-metadata">

**Author:** ![alexone](https://avatars.discourse-cdn.com/v4/letter/a/977dab/32.png) [@alexone](https://forum.modular.com/u/alexone)\
**Post date:** [May 29, 2025, 8:10pm UTC](https://forum.modular.com/t/while-making-a-mojo-gui-ui-lessons-learned/1539/5 "2025-05-29T20:10:55Z")

</div>

thank you. the ffi is a joke on mojo, so i had to break down complex parameters to single value passing to C where it combined them to call openGL, dhandle was used exclusively and arrays was a big no no, everything simple calls. don’t get me wrong, i love mojo – already got a json lib ready along with a http server in pure mojo.. just need to test the hell out of them

---

<div class="post-metadata">

**Author:** ![Ryulord](https://avatars.discourse-cdn.com/v4/letter/r/77aa72/32.png) [@Ryulord](https://forum.modular.com/u/Ryulord)\
**Post date:** [May 29, 2025, 8:29pm UTC](https://forum.modular.com/t/while-making-a-mojo-gui-ui-lessons-learned/1539/6 "2025-05-29T20:29:36Z")

</div>

This is cool! You might want to share with the Mojo gamedev discord. There should be a post about it here on the forums. Do you have a link for the repo?

---

<div class="post-metadata">

**Author:** ![alexone](https://avatars.discourse-cdn.com/v4/letter/a/977dab/32.png) [@alexone](https://forum.modular.com/u/alexone)\
**Post date:** [May 29, 2025, 8:33pm UTC](https://forum.modular.com/t/while-making-a-mojo-gui-ui-lessons-learned/1539/7 "2025-05-29T20:33:21Z")

</div>

i don’t have it right now, i need to beautify it. i gotta work today i am off next two days and will put it up.

---

<div class="post-metadata">

**Author:** ![alexone](https://avatars.discourse-cdn.com/v4/letter/a/977dab/32.png) [@alexone](https://forum.modular.com/u/alexone)\
**Post date:** [May 29, 2025, 9:20pm UTC](https://forum.modular.com/t/while-making-a-mojo-gui-ui-lessons-learned/1539/8 "2025-05-29T21:20:28Z")

</div>

i put a video up on the x11 version interface in the Modular discord in mojo section for a display of it working. Opengl will be next

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/flex001/uploads/modular/original/1X/2751e0fbdc595a99718b216730957e9db4448cfd.jpeg) [@system](https://forum.modular.com/u/system)\
**Post date:** [November 25, 2025, 9:21pm UTC](https://forum.modular.com/t/while-making-a-mojo-gui-ui-lessons-learned/1539/9 "2025-11-25T21:21:08Z")

</div>

Closed on November 25, 2025, 9:21pm UTC

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.
