<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Josep Bigorra (Joe)</title>
    <description>The latest articles on DEV Community by Josep Bigorra (Joe) (@jjba23).</description>
    <link>https://dev.to/jjba23</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4098845%2F72eeca6e-ec04-4573-befe-28b5703d476a.png</url>
      <title>DEV Community: Josep Bigorra (Joe)</title>
      <link>https://dev.to/jjba23</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jjba23"/>
    <language>en</language>
    <item>
      <title>Quest for eternal dock on Wayland - lambdock (C + GTK4 + Lisp GNU Guile Scheme)</title>
      <dc:creator>Josep Bigorra (Joe)</dc:creator>
      <pubDate>Fri, 28 Aug 2026 11:28:08 +0000</pubDate>
      <link>https://dev.to/jjba23/quest-for-eternal-dock-on-wayland-lambdock-c-gtk4-lisp-gnu-guile-scheme-1mm9</link>
      <guid>https://dev.to/jjba23/quest-for-eternal-dock-on-wayland-lambdock-c-gtk4-lisp-gnu-guile-scheme-1mm9</guid>
      <description>&lt;p&gt;This is the story of &lt;code&gt;lambdock&lt;/code&gt;: &lt;a href="https://codeberg.org/jjba23/lambdock" rel="noopener noreferrer"&gt;https://codeberg.org/jjba23/lambdock&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;lambdock&lt;/code&gt; is a modern, hyper-hackable, Wayland-native desktop dock&lt;br&gt;
application (C and Guile Scheme + GTK4) w/ REPL.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;As a heavy computer user, spending most of my day enjoying digital&lt;br&gt;
life, and as an eye-candy enjoyer and workflow optimization&lt;br&gt;
afficionado, I have long dreamt of the ultimate desktop dock.&lt;/p&gt;

&lt;p&gt;Here's the story behind &lt;code&gt;lambdock&lt;/code&gt; , the Wayland-native beast with&lt;br&gt;
infinite hackability, fluid physics animcations, instant&lt;br&gt;
responsiveness, and free as in freedom .&lt;/p&gt;

&lt;p&gt;But to get here, I will first take you through the mindset, the&lt;br&gt;
graveyard of failed prototypes, the uphill battles and the ultimate&lt;br&gt;
conquest of GTK4 C runtime, and embedding of a living, breathing,&lt;br&gt;
interactive Lisp heart.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;
  
  
  Quest for the eternal Dock
&lt;/h1&gt;

&lt;p&gt;For years, desktop GNU/Linux users moving to Wayland faced a recurring&lt;br&gt;
tragedy: the loss of iconic, deeply hackable docks like Cairo-Dock and&lt;br&gt;
Plank. That being said, anno 2026, those (and other) projects have made&lt;br&gt;
great efforts to become Wayland-compatible, so that's great. While bar&lt;br&gt;
engines like Waybar and EWW excel at status displays, a true application&lt;br&gt;
dock that can rival those heavyweights (and macOS too) requires a unique&lt;br&gt;
blend of layout positioning, dynamic window tracking, auto-hiding, and&lt;br&gt;
fluid hover physics for animations.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;lambdock&lt;/code&gt;'s is a story of resilience in many ways, as I cannot even&lt;br&gt;
remember how many attempts I made at building a dock (in different&lt;br&gt;
ways). Little did I know how many paradigms, ideas and PoCs would&lt;br&gt;
collapse before my vision became tangible reality.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjointhefreeworld.org%2Fstatic-assets%2Flambdock%2Fgif_2026-08-07_22-32-33.gif" class="article-body-image-wrapper"&gt;&lt;img alt="lambdock showcase" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjointhefreeworld.org%2Fstatic-assets%2Flambdock%2Fgif_2026-08-07_22-32-33.gif" width="599" height="203"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the 30th of July 2026, I had a revelation and set out to build&lt;br&gt;
&lt;strong&gt;lambdock&lt;/strong&gt;: a Wayland-native desktop dock that wouldn't just&lt;br&gt;
replicate the macOS or Cairo-Dock experience, but would transcend it&lt;br&gt;
with full runtime inspectability, hackability, and Lisp enlightenment.&lt;/p&gt;

&lt;p&gt;I find GTK to be the very best UI toolkit for GNU/Linux and other&lt;br&gt;
platforms, anno 2026. So for me that choice was pretty clear, even if I&lt;br&gt;
also toyed with Qt and others, but GTK always came on top. After the&lt;br&gt;
wreckage of many PoCs and while reading some HackerNews in bed, a&lt;br&gt;
thought crossed my mind, and suddenly, &lt;strong&gt;absolute clarity&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;Why not use idiomatic modern GTK4, in the language that it's written&lt;br&gt;
in. Oh wait, that language, C, has &lt;code&gt;libguile.h&lt;/code&gt;, a great library&lt;br&gt;
inter-operability with Lisp (GNU Guile Scheme), allowing bi-directional&lt;br&gt;
bindings and communication. Why not go down this rabbit hole, which&lt;br&gt;
might at the same time teach me more about my favourite language (GNU&lt;br&gt;
Guile) and allow me a frictionless setup with GTK and native super&lt;br&gt;
performance.&lt;/p&gt;

&lt;p&gt;I therefore designed lambdock in my mind, in bed, much inspired by&lt;br&gt;
Emacs. A powerful, small C core that powers the program, rendering,&lt;br&gt;
graphics and low level details, and an embedded GNU Guile Scheme engine&lt;br&gt;
that at runtime is the heart and brain of the whole thing. This&lt;br&gt;
architecture uniquely delivers interactive socket REPL control, Lisp&lt;br&gt;
metaprogramming macros, dynamic multi-dock spawning, native Wayland&lt;br&gt;
foreign-toplevel window tracking, and frame-clock-driven hover&lt;br&gt;
animations.&lt;/p&gt;
&lt;h1&gt;
  
  
  Graveyard of Prototypes
&lt;/h1&gt;

&lt;p&gt;The journey to &lt;code&gt;lambdock&lt;/code&gt; was paved with ambitious Proofs of&lt;br&gt;
Concept (PoCs) that ultimately died. I cycled through several languages,&lt;br&gt;
approaches, frameworks, and architecture experiments, chasing the dream&lt;br&gt;
of rapid development without sacrificing low-level display server&lt;br&gt;
control.&lt;/p&gt;

&lt;p&gt;The quest initially aimed for a pure, 100% Lisp architecture using Guile&lt;br&gt;
GI and other existing Guile GTK bindings. However, this vision collapsed&lt;br&gt;
under sparse documentation and inscrutable binding layers. Bridging&lt;br&gt;
GTK's imperative, object-oriented state with functional Scheme patterns&lt;br&gt;
created constant architectural friction, and a small community meant&lt;br&gt;
every binding edge-case became a dead end and a long dive in the rabbit&lt;br&gt;
hole.&lt;/p&gt;

&lt;p&gt;Trying Python + GTK3/4 offered rapid prototyping and a massive library&lt;br&gt;
ecosystem, but crashed into severe real-time performance limits.&lt;br&gt;
Single-threaded bottlenecks and Global Interpreter Lock (GIL) stutters&lt;br&gt;
ruined fluid slide-out animations unless backed by custom C code. That&lt;br&gt;
also triggered me to think, might as well just write this whole thing in&lt;br&gt;
C. Coupled with a heavy memory footprint and fragile IPC mechanisms, the&lt;br&gt;
runtime proved too heavy and unpredictable for a low-latency desktop&lt;br&gt;
dock.&lt;/p&gt;

&lt;p&gt;Attempts with Rust, GTK bindings, and custom compositor IPC promised&lt;br&gt;
memory safety and fearless concurrency, yet introduced severe verbosity&lt;br&gt;
and binding friction. Mismatches between Rust's async event loops and&lt;br&gt;
GTK4's main thread created structural problems, the borrow checker was&lt;br&gt;
a real PITA when working with GTK and the dynamic features I wanted to&lt;br&gt;
support, while the lack of reflection completely shut the door on&lt;br&gt;
(easily) embedding a live, interactive Lisp REPL.&lt;/p&gt;

&lt;p&gt;I made a final attempt by using JavaScript/Node and Layer Shell targeted&lt;br&gt;
familiar web-style styling and asynchronous I/O. However, this suffered&lt;br&gt;
from bloated resource consumption, poor integration with low-level&lt;br&gt;
Wayland protocols, and no clear pathway for Lisp extensibility, and thus&lt;br&gt;
it quickly gained its place in the graveyard of abandoned prototypes.&lt;/p&gt;
&lt;h1&gt;
  
  
  Iron Skeleton, Lisp Soul
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;C + GTK4 + gtk4-layer-shell&lt;/strong&gt; is the undisputed champion of native
Wayland surface control. C provides raw speed, zero-cost GLib
integration, memory layout efficiency, flawless Wayland scanner
protocol generation and the best GTK documentation you can get.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GNU Guile Scheme (&lt;code&gt;libguile&lt;/code&gt;)&lt;/strong&gt; is the ultimate runtime
mind. Instead of configuring the dock with static, dead JSON or TOML
files, embedding Lisp (Guile Scheme) via &lt;code&gt;libguile.h&lt;/code&gt; gives
the dock a living Lisp heart and turns it into an infinitely
extensible program.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cm"&gt;/* The moment C boots the Lisp engine in main.c */&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="cp"&gt;#ifdef DEFAULT_GSK_RENDERER
&lt;/span&gt;  &lt;span class="n"&gt;g_setenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GSK_RENDERER"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DEFAULT_GSK_RENDERER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FALSE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="cp"&gt;#endif
&lt;/span&gt;  &lt;span class="cm"&gt;/* Boot the GNU Guile Scheme engine and surrender control to inner_main */&lt;/span&gt;
  &lt;span class="n"&gt;scm_boot_guile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;inner_main&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;By hosting &lt;code&gt;libguile&lt;/code&gt; directly inside C's GTK4 main loop,&lt;br&gt;
&lt;code&gt;lambdock&lt;/code&gt; achieves what I consider the holy grail, much like&lt;br&gt;
GNU Emacs does: &lt;strong&gt;infinite extensibility, uncompromising native&lt;br&gt;
performance for rendering and animation, and metaprogramming superpowers&lt;br&gt;
of Lisp for user configuration and live REPL inspection.&lt;/strong&gt;&lt;/p&gt;


&lt;h1&gt;
  
  
  Etymology
&lt;/h1&gt;

&lt;p&gt;The name &lt;em&gt;lambdock&lt;/em&gt; is a play on words combining:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ship Docks&lt;/strong&gt; ⚓ where containers and applications dock safely.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;lambda λ&lt;/code&gt; expressions from functional programming &amp;amp; Lisp
enlightenment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lambs&lt;/strong&gt; 🐑 (gentle, fluffy, lightweight, and clean).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docks&lt;/strong&gt; as desktop UI components (e.g., Plank, Cairo-Dock, macOS
Dock).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;lambdock&lt;/code&gt; adopts as its project logo the &lt;a href="https://en.wikipedia.org/wiki/Agnus_Dei" rel="noopener noreferrer"&gt;Agnus&lt;br&gt;
Dei&lt;/a&gt;: The Lamb of God carrying&lt;br&gt;
a cross and a red flag&lt;/p&gt;

&lt;p&gt;You could say using this dock &lt;em&gt;es casi una experiencia religiosa como la&lt;br&gt;
de &lt;a href="https://www.youtube.com/watch?v=3DV57Y4tEAM&amp;amp;t=3s" rel="noopener noreferrer"&gt;Enrique Iglesias&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;


&lt;h1&gt;
  
  
  Multi-Config &amp;amp; Multi-Dock Instance
&lt;/h1&gt;

&lt;p&gt;&lt;code&gt;lambdock&lt;/code&gt; features built-in multi-dock orchestration. Rather than being&lt;br&gt;
limited to a single dock bar, you can run multiple independent docks&lt;br&gt;
simultaneously across different screen edges or monitors.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Automatic Directory Monitoring&lt;/strong&gt;: &lt;code&gt;lambdock&lt;/code&gt; watches
&lt;code&gt;~/.config/lambdock/&lt;/code&gt; for files matching &lt;code&gt;settings.scm&lt;/code&gt; or
&lt;code&gt;settings-*.scm&lt;/code&gt; (e.g., &lt;code&gt;settings-left.scm&lt;/code&gt;, &lt;code&gt;settings-bottom.scm&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each configuration file defines its own isolated &lt;code&gt;LambdockState&lt;/code&gt;,&lt;br&gt;
position (&lt;code&gt;dock-position&lt;/code&gt;), theme (&lt;code&gt;dock-theme&lt;/code&gt;), monitor targets&lt;br&gt;
(&lt;code&gt;dock-monitor&lt;/code&gt;), and item launcher layout (&lt;code&gt;dock-items&lt;/code&gt;).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic Spawning&lt;/strong&gt;: Creating a new &lt;code&gt;settings-2.scm&lt;/code&gt; file instantly
spawns a new dock bar on screen.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic Hot-Reloading&lt;/strong&gt;: Editing any &lt;code&gt;settings-*.scm&lt;/code&gt; file
hot-reloads that specific dock instance without flickering or
restarting other running instances.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic Destruction&lt;/strong&gt;: Deleting a &lt;code&gt;settings-*.scm&lt;/code&gt; file safely tears
down and destroys its corresponding dock window, removing Wayland
handles and GTK widgets without crashing the application.&lt;/li&gt;
&lt;/ul&gt;


&lt;h1&gt;
  
  
  What systems does lambdock support?
&lt;/h1&gt;

&lt;p&gt;&lt;code&gt;lambdock&lt;/code&gt; is a GNU/Linux first utility.&lt;/p&gt;

&lt;p&gt;The tool uses &lt;code&gt;gtk4-layer-shell&lt;/code&gt; to render to the screen and positioning&lt;br&gt;
and for dock behavior.&lt;/p&gt;

&lt;p&gt;That means it works well in Wayland compositors that support the&lt;br&gt;
&lt;code&gt;wlr-layer-shell-unstable-v1&lt;/code&gt; protocol, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;KDE Plasma (Wayland session)&lt;/li&gt;
&lt;li&gt;Smithay-based compositors: Niri, COSMIC Desktop&lt;/li&gt;
&lt;li&gt;wlroots-based compositors: Sway, Hyprland, River, Wayfire&lt;/li&gt;
&lt;li&gt;Mir-based compositors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note: GNOME (Mutter) currently not supported due to not implementing the&lt;br&gt;
protocol&lt;/p&gt;


&lt;h1&gt;
  
  
  How the Bi-Directional Engine Works
&lt;/h1&gt;

&lt;p&gt;&lt;code&gt;lambdock&lt;/code&gt; is not merely configured by Scheme. It has an embedded,&lt;br&gt;
extensible Lisp engine and runtime environment which complements a&lt;br&gt;
high-performance C applciation core and graphics engine. Execution flows&lt;br&gt;
bi-directionally between C and Guile.&lt;/p&gt;

&lt;p&gt;The entry point of the binary (&lt;code&gt;main.c&lt;/code&gt;) boots the Guile interpreter&lt;br&gt;
using &lt;code&gt;scm_boot_guile&lt;/code&gt;. The C runtime acts as the host and invokes&lt;br&gt;
Scheme procedures to manage state and extract settings.&lt;/p&gt;

&lt;p&gt;Scheme is not restricted to passive data declarations, as it can trigger&lt;br&gt;
actions inside the running C engine.&lt;/p&gt;

&lt;p&gt;lambdock provides a beautiful Lisp DSL for defining your dock, based on&lt;br&gt;
items and presets&lt;/p&gt;

&lt;p&gt;&lt;code&gt;(app-item ...)&lt;/code&gt;                 Record        Custom application launcher definition                   &lt;code&gt;#:name&lt;/code&gt;, &lt;code&gt;#:exec&lt;/code&gt;, &lt;code&gt;#:icon&lt;/code&gt;&lt;br&gt;
  &lt;code&gt;(dynamic-item ...)&lt;/code&gt;             Record        Dynamic polling widget displaying dynamic textual data   &lt;code&gt;#:name&lt;/code&gt;, &lt;code&gt;#:icon&lt;/code&gt;, &lt;code&gt;#:exec&lt;/code&gt;, &lt;code&gt;#:poll-fn&lt;/code&gt;, &lt;code&gt;#:interval-ms&lt;/code&gt;, &lt;code&gt;#:hover-animate?&lt;/code&gt;&lt;br&gt;
  &lt;code&gt;(preset-launcher 'symbol)&lt;/code&gt;      Record        Standard launcher resolved from internal preset list     Symbol (e.g. &lt;code&gt;'emacs&lt;/code&gt;, &lt;code&gt;'alacritty&lt;/code&gt;)&lt;br&gt;
  &lt;code&gt;(preset-launchers-for 'a 'b)&lt;/code&gt;   List          Batch helper returning a list of preset launchers        Variadic list of symbols&lt;br&gt;
  &lt;code&gt;(separator-item)&lt;/code&gt;               Record        Layout divider line                                      None&lt;br&gt;
  &lt;code&gt;(preset-icon 'symbol)&lt;/code&gt;          String        Resolves default icon name string for a given preset     Symbol&lt;/p&gt;

&lt;p&gt;The magic of &lt;code&gt;lambdock&lt;/code&gt; lies in the seamless bi-directional&lt;br&gt;
bridge between the C graphics core and the GNU Guile Scheme engine. See&lt;br&gt;
an example config file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scheme"&gt;&lt;code&gt;&lt;span class="c1"&gt;;; Modern, declarative Lisp configuration in ~/.config/lambdock/settings.scm&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;define&lt;/span&gt; &lt;span class="nv"&gt;dock-auto-hide?&lt;/span&gt; &lt;span class="no"&gt;#t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;define&lt;/span&gt; &lt;span class="nv"&gt;dock-position&lt;/span&gt; &lt;span class="ss"&gt;'bottom&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;define&lt;/span&gt; &lt;span class="nv"&gt;dock-icon-size&lt;/span&gt; &lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;define&lt;/span&gt; &lt;span class="nv"&gt;dock-theme&lt;/span&gt; &lt;span class="ss"&gt;'vanilla&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;define&lt;/span&gt; &lt;span class="nv"&gt;dock-monitor&lt;/span&gt; &lt;span class="ss"&gt;'all&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;define&lt;/span&gt; &lt;span class="nv"&gt;dock-items&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;
   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;preset-launchers-for&lt;/span&gt; &lt;span class="ss"&gt;'alacritty&lt;/span&gt; &lt;span class="ss"&gt;'google-chrome&lt;/span&gt; &lt;span class="ss"&gt;'spotify-flatpak&lt;/span&gt; &lt;span class="ss"&gt;'nautilus&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;separator-item&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;preset-launchers-for&lt;/span&gt; &lt;span class="ss"&gt;'emacs&lt;/span&gt; &lt;span class="ss"&gt;'intellij&lt;/span&gt; &lt;span class="ss"&gt;'bruno-flatpak&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;separator-item&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;preset-launchers-for&lt;/span&gt; &lt;span class="ss"&gt;'ram&lt;/span&gt; &lt;span class="ss"&gt;'cpu&lt;/span&gt; &lt;span class="ss"&gt;'cpu-temp&lt;/span&gt; &lt;span class="ss"&gt;'battery&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

&lt;span class="c1"&gt;;; === you can evaluate any Lisp code here too ===&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;use-modules&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ice-9&lt;/span&gt; &lt;span class="nv"&gt;popen&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
             &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ice-9&lt;/span&gt; &lt;span class="nv"&gt;rdelim&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
             &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;srfi&lt;/span&gt; &lt;span class="nv"&gt;srfi-19&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
             &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;srfi&lt;/span&gt; &lt;span class="nv"&gt;srfi-1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="c1"&gt;;; Helper to run a shell command and return its output as a clean string&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;define&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sh-output&lt;/span&gt; &lt;span class="nv"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let*&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nf"&gt;port&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;open-input-pipe&lt;/span&gt; &lt;span class="nv"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
         &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;output&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;read-line&lt;/span&gt; &lt;span class="nv"&gt;port&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;close-pipe&lt;/span&gt; &lt;span class="nv"&gt;port&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;eof-object?&lt;/span&gt; &lt;span class="nv"&gt;output&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="nv"&gt;output&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

&lt;span class="c1"&gt;;; Enable auto-hide only on a specific hostname (e.g., laptop setup)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;define&lt;/span&gt; &lt;span class="nv"&gt;dock-auto-hide?&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;string=?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;string-trim-both&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sh-output&lt;/span&gt; &lt;span class="s"&gt;"hostname"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="s"&gt;"thinkpad"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa3nmb73pkvp3wt2aauho.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa3nmb73pkvp3wt2aauho.png" alt="Explaining the bidirectional working of C and Guile" width="800" height="517"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  Read Eval Print Loop (REPL)
&lt;/h1&gt;

&lt;p&gt;For purposes of development, experimentation and live hackability,&lt;br&gt;
&lt;code&gt;lambdock&lt;/code&gt; features an embedded GNU Guile Scheme runtime. You can enable&lt;br&gt;
a background Unix domain socket REPL to query or dynamically alter the&lt;br&gt;
running dock's state in real time.&lt;/p&gt;

&lt;p&gt;Through Guile's &lt;code&gt;(system repl server)&lt;/code&gt;,&lt;br&gt;
&lt;code&gt;lambdock&lt;/code&gt; can spawn Unix domain sockets (one per dock&lt;br&gt;
instance) for example at &lt;code&gt;/tmp/lambdock-repl.sock&lt;/code&gt;. You can&lt;br&gt;
plug directly into a running dock process via Emacs (Geiser),&lt;br&gt;
&lt;code&gt;socat&lt;/code&gt;, or &lt;code&gt;ncat&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Because GTK4 requires all UI modifications to happen on the main thread&lt;br&gt;
while the REPL listens on a background thread, &lt;code&gt;lambdock&lt;/code&gt;&lt;br&gt;
uses GLib's &lt;code&gt;g_idle_add&lt;/code&gt; to dispatch Scheme-triggered UI&lt;br&gt;
updates safely:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cm"&gt;/* Thread-safe C callback triggered from Guile REPL evaluation */&lt;/span&gt;
&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;gboolean&lt;/span&gt; &lt;span class="nf"&gt;on_manual_reload_idle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gpointer&lt;/span&gt; &lt;span class="n"&gt;user_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;user_data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;LOG_C_INFO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Main"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Redrawing UI from in-memory Guile state..."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;redraw_active_docks&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;G_SOURCE_REMOVE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;SCM&lt;/span&gt; &lt;span class="nf"&gt;scm_reload_dock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;g_idle_add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;on_manual_reload_idle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;SCM_UNSPECIFIED&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can edit a theme, change icon dimensions, or redefine launchers in&lt;br&gt;
Emacs, issue a &lt;code&gt;(reload-dock!)&lt;/code&gt;, and watch your dock&lt;br&gt;
transform live, without restarting or dropping a single frame!&lt;/p&gt;

&lt;p&gt;In your &lt;code&gt;~/.config/lambdock/settings.scm&lt;/code&gt; file, set&lt;br&gt;
&lt;code&gt;#:enable-repl?&lt;/code&gt; to &lt;code&gt;#t&lt;/code&gt;. You can optionally&lt;br&gt;
customize the socket path using &lt;code&gt;#:repl-socket-path&lt;/code&gt;&lt;br&gt;
(defaults to &lt;code&gt;/tmp/lambdock-repl.sock&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scheme"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;configure-dock!&lt;/span&gt;
 &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="nv"&gt;:position&lt;/span&gt; &lt;span class="ss"&gt;'bottom&lt;/span&gt;
 &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="nv"&gt;:items&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="c1"&gt;;; .... other settings&lt;/span&gt;
 &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="nv"&gt;:enable-repl?&lt;/span&gt; &lt;span class="no"&gt;#t&lt;/span&gt;
 &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="nv"&gt;:repl-socket-path&lt;/span&gt; &lt;span class="s"&gt;"/tmp/lambdock-repl.sock"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can then inspect or modify the dock state, and when desired also&lt;br&gt;
reload the dock (with &lt;code&gt;reload-dock!&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Once connected, you can evaluate Scheme expressions against the running&lt;br&gt;
&lt;code&gt;lambdock&lt;/code&gt; instance, possibilities are endless, e.g.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;scheme@(guile-user)&amp;gt; (use-modules (lambdock core))
scheme@(guile-user)&amp;gt; (get-dock-theme) ;; -&amp;gt; 'vanilla
scheme@(guile-user)&amp;gt; (set-dock-theme! 'nature)
scheme@(guile-user)&amp;gt; (reload-dock!)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;If you use Emacs with Geiser:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Run &lt;code&gt;M-x geiser-connect-local&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt; Select &lt;code&gt;guile&lt;/code&gt; as the Scheme implementation.&lt;/li&gt;
&lt;li&gt; Enter the socket path: &lt;code&gt;/tmp/lambdock-repl.sock&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;See here Emacs + Geiser GIF&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjointhefreeworld.org%2Fstatic-assets%2Flambdock%2Fgif_2026-08-06_13-13-17.gif" class="article-body-image-wrapper"&gt;&lt;img alt="lambdock showcase" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjointhefreeworld.org%2Fstatic-assets%2Flambdock%2Fgif_2026-08-06_13-13-17.gif" width="560" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can connect directly from your terminal using different tooling,&lt;br&gt;
like &lt;code&gt;nc&lt;/code&gt;, &lt;code&gt;ncat&lt;/code&gt;, &lt;code&gt;socat&lt;/code&gt; wrapped with &lt;code&gt;rlwrap&lt;/code&gt; , and others:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;socat - UNIX-CONNECT:/tmp/lambdock-repl.sock
ncat -U /tmp/lambdock-repl.sock
nc -U /tmp/lambdock-repl.sock
rlwrap socat - UNIX-CONNECT:/tmp/lambdock-repl.sock
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Victory: Upstream in Guix, Nix, OCI and Beyond!
&lt;/h1&gt;

&lt;p&gt;What began as a chaotic experiment in a local directory has officially&lt;br&gt;
arrived on the global stage.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;lambdock&lt;/code&gt; is upstreamed and natively packaged in GNU Guix.&lt;br&gt;
You can run or install it in a single hermetic command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;guix time-machine --channels=channels.scm -- shell -f guix.scm -- lambdock
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fully upstreamed into Nixpkgs (today) and available as a Flake too:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nix --extra-experimental-features 'nix-command flakes' run .#
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;lambdock&lt;/code&gt; binaries and native packages are marching across&lt;br&gt;
the GNU/Linux ecosystem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;openSUSE / RPM&lt;/strong&gt;: Packaged on OBS with native
&lt;code&gt;lambdock.spec&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Debian / Ubuntu&lt;/strong&gt;: Full &lt;code&gt;debian/&lt;/code&gt; rules and unsigned
&lt;code&gt;.deb&lt;/code&gt; build pipeline.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Arch Linux&lt;/strong&gt;: Ready-to-build &lt;code&gt;PKGBUILD&lt;/code&gt; in
&lt;code&gt;packaging/arch&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Containers&lt;/strong&gt;: Lightweight OCI images on DockerHub for Podman/Docker.&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  What does one learn after the Odyssey
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Don't fight the platform&lt;/strong&gt;: If you are building a Wayland utility
on GNU/Linux, consider embracing C and GTK4/Layer-Shell directly. The
clarity, speed, and reliability are unmatched. Even if you might have
to shoot yourself in the foot a couple times with memory management ☺️&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lisp remains THE supreme extension engine&lt;/strong&gt;: Embedding
&lt;code&gt;libguile&lt;/code&gt; transformed a simple UI bar into an extensible
and programmable canvas where users can run shell pipelines, system
queries, and dynamic macros right inside their config files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't surrender to \"good enough\"&lt;/strong&gt;: The failed PoCs were not
wasted time, they were but the crucible that forged the ultimate
architecture.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Long live Free Software, long live Lisp, and happy docking! 🐑⚓λ&lt;/p&gt;

</description>
      <category>lisp</category>
      <category>c</category>
      <category>gtk</category>
      <category>linux</category>
    </item>
  </channel>
</rss>
