mpd-libui
Crystal MPD libui
A desktop MPD client written in Crystal using the UIng (libui-ng) GUI library.
Screenshots

Features
- Playback controls: play/pause, previous, next
- Shuffle and repeat toggle buttons
- Seek slider with elapsed / total time display
- Album cover art fetched from MPD (
readpicture/albumart) - Integrated playlist with Artist, Title, Duration columns
- Currently playing track highlighted and auto-scrolled into view
- Window title updates to reflect the current track
- Settings window for MPD host / port configuration
- About dialog with MPD server stats (version, artists, albums, songs, uptime)
Requirements
- Crystal >= 1.19.1
- libui-ng shared library installed
- GTK3 (required by libui-ng on Linux)
- A running MPD server
Installation
git clone https://github.com/mamantoha/mpd-libui
cd mpd-libui
shards install
crystal build src/mpd_ui.cr --release -o mpd-libui
./mpd-libui
Dependencies
| Shard | Purpose |
|---|---|
| kojix2/uing | libui-ng bindings — native desktop GUI |
| mamantoha/crystal_mpd | MPD protocol client |
| stumpycr/stumpy_png | Pure-Crystal PNG decoding for cover art |
| stumpycr/stumpy_jpeg | Pure-Crystal JPEG decoding for cover art |
Platform support
| Platform | Status |
|---|---|
| Linux (GTK3) | ✅ Tested |
| macOS | ❓ Untested |
| Windows | ❓ Untested |
Custom components
ToggleButton (src/mpd_ui/toggle_button.cr)
UIng does not provide a toggle button widget. ToggleButton is a custom widget built on top of UIng::Area (a libui-ng raw drawing surface).
- Renders a filled rectangle with a centered emoji/text label using the
UIng::Area::DrawAPI (paths, brushes, text layouts) - Active state shown as a blue highlight; hover tracked for a subtle gray tint
- Minimum size enforced via
uiControlHandle+gtk_widget_set_size_requestbecauseuiNewAreahas no natural GTK size hint - Font loaded once via
UIng::FontDescriptor(uiLoadControlFont) and cached as an instance variable to avoid per-frame allocation and Pango errors AttributedStringandTextLayoutcreated and freed deterministically each draw using theopen { }block API to prevent libui leak warnings at shutdown
PlaylistView (src/mpd_ui/playlist_view.cr)
A UIng::Table-backed playlist widget embedded directly in the main window.
- Custom
UIng::Table::Model::Handlerbacked by a mutableArray(Song)that is updated in-place (clear+concat) so the model handler closure always sees the live array — replacing the array reference caused auiTableModel_get_value: stampassertion crash - Per-row background color column (type
Color) highlights the active track with a blue tint - Auto-scrolls to the playing row using raw GTK calls:
uiControlHandle→gtk_bin_get_child(GtkScrolledWindow → GtkTreeView) →gtk_tree_view_scroll_to_cell - Proper cleanup on window close:
table.destroybeforemodel.free, matching libui-ng's required teardown order
Architecture notes
- Dual MPD clients: a regular
MPD::Clientfor commands and a second client withwith_callbacks: truerunning in a backgroundThreadfor push events (song change, state, elapsed, random, repeat, playlist) - UI thread safety: all UI mutations from the callback thread go through
UIng.queue_main { } - Cover art: fetched in a third
Threadusing a dedicated MPD connection; decoded in pure Crystal (no subprocess) viaStumpyJPEG/StumpyPNGto avoidProcess.rundeadlock inside threads (Crystal'swaitpidsignal handler is occupied byUIng.main) - Stale result guard:
@current_fileis compared before applying a fetched cover image to discard results that arrived after the track changed
License
MIT
Repository
mpd-libui
Owner
Statistic
- 0
- 0
- 0
- 0
- 4
- about 4 hours ago
- April 3, 2026
License
MIT License
Links
Synced at
Fri, 03 Apr 2026 18:05:55 GMT
Languages