For convenience of specifying widgets hierarchy in Lisp code, the let-ui macro is introduced.
(let-ui ui-description &body body)
ui-description ::= widget
widget ::= (class properties child*)
properties ::= {:prop-name prop-value}*
child ::= widget properties
child ::= (:expr expr) properties
:var for specifying the variable name to which the object will be bound
:prop-name is :var
This macro creates widgets and evaluates the body. Widgets that have :var specified are bound to lexical variables with specified names.
ui-description specifies the hierarchy of widgets in a window. It can specify either the entire top-level window or other kind of widgets. ui-description is a mini-language for specifying widgets. let-ui creates specified widgets, lexically binds specified variables to widgets and evaluates the body. The body my refer to these widgets.
widget is the specification of a single widget. It may specify some properties (slots of objects) and their values (the expressions to be evaluated), a variable name that will be bound to the widget (the :var property whose prop-value must be a symbol) and widget's children.
class specifies the class of the widget (e.g., label, button, gtk-window). :prop-name may be any slot of the class. If :var property is specified, then corresponding variable is accessible in body and its value is the widget on which it is specified as :var.
Container widgets may specify their children along with their child properties. Child properties specify how children are used in widget. They are specific to the type of the container:
:expand, :fill. See box-pack-start for information.
:resize, :shrink. See paned-pack-1 for information.
:left, :right, :top, :bottom, :x-options, :y-options, x-padding, y-padding. Of these, :left, :right, :top and :bottom are mandatory. See table-attach for information.
An example:
(let-ui (gtk-window :title "Hello" :position :center :var w
(v-box
(label :label "Hello, world!")
(button :label "gtk-ok" :use-stock t) :expand nil))
(widget-show w))
produces this output:

More complex example from demo of cl-gtk2-gtk-glext:
(let-ui (v-paned :var v
(:expr (opengl-window-drawing-area window))
:resize t :shrink nil
(v-box
(h-paned
(scrolled-window
:hscrollbar-policy :automatic
:vscrollbar-policy :automatic
(:expr (opengl-window-expose-fn-text-view window)))
:resize t :shrink nil
(scrolled-window
:hscrollbar-policy :automatic
:vscrollbar-policy :automatic
(:expr (opengl-window-resize-fn-text-view window)))
:resize t :shrink nil)
(h-box
(button :label "Update functions" :var update-fns-button) :expand nil
(button :label "Redraw" :var redraw-button) :expand nil)
:expand nil)
:resize t :shrink nil)
(container-add window v)
(connect-signal update-fns-button "clicked"
(lambda (b)
(declare (ignore b))
(update-fns window)))
(connect-signal redraw-button "clicked"
(lambda (b)
(declare (ignore b))
(widget-queue-draw (opengl-window-drawing-area window))))
(let ((area (opengl-window-drawing-area window)))
(setf (gl-drawing-area-on-expose area)
(lambda (w e)
(declare (ignore w e))
(opengl-interactive-on-expose window))
(gl-drawing-area-on-resize area)
(lambda (widget w h)
(declare (ignore widget))
(opengl-interactive-on-resize window w h)))))
produces this output:

In this example, not top-level window, but a widget is created and then added to already existing window. This UI also uses some already created widgets: (:expr (opengl-window-resize-fn-text-view window)).