add doc
authorDmitry Kalyanov <Kalyanov.Dmitry@gmail.com>
Tue, 21 Apr 2009 18:55:53 +0000 (22:55 +0400)
committerDmitry Kalyanov <Kalyanov.Dmitry@gmail.com>
Tue, 21 Apr 2009 18:55:53 +0000 (22:55 +0400)
doc/Makefile [new file with mode: 0644]
doc/doc.xml [new file with mode: 0644]
doc/hello.lisp [new file with mode: 0644]
doc/hello_world.png [new file with mode: 0644]
doc/tutorial.xml [new file with mode: 0644]

diff --git a/doc/Makefile b/doc/Makefile
new file mode 100644 (file)
index 0000000..4209300
--- /dev/null
@@ -0,0 +1,10 @@
+all: doc.html index.html tutorial.html
+
+doc.html: doc.xml
+       xsltproc -o $@ /usr/share/sgml/docbook/xsl-stylesheets/html/docbook.xsl $<
+
+tutorial.html: tutorial.xml
+       xsltproc -o $@ /usr/share/sgml/docbook/xsl-stylesheets/html/docbook.xsl $<
+
+index.html: doc.xml
+       xsltproc /usr/share/sgml/docbook/xsl-stylesheets/html/chunk.xsl $<
\ No newline at end of file
diff --git a/doc/doc.xml b/doc/doc.xml
new file mode 100644 (file)
index 0000000..b21645a
--- /dev/null
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+<book>
+  <bookinfo>
+    <title>CL-GTK2 - a Gtk+ binding for Common Lisp</title>
+    <author>
+      <personname>
+        <firstname>Dmitry</firstname>
+        <surname>Kalyanov</surname>
+      </personname>
+    </author>
+  </bookinfo>
+  <chapter>
+    <title>TODO</title>
+    <para>Installation and requirements</para>
+    <para>*Introduction</para>
+    <para>Goals</para>
+    <para>Development History</para>
+    <para>Features</para>
+    <para>*Examples</para>
+    <para>*GObject binding: using objects, handling memory</para>
+    <para>*Using Gtk+ in Lisp: Gtk+, Widgets, main loop, threading</para>
+    <para>*Advanced GObject: defining objects, creating custom gobject classes, overriding and implementing methods and properties</para>
+    <para>*Internals: how gobject binding is implemented</para>
+  </chapter>
+  <chapter>
+    <title>Introduction</title>
+    <para>CL-GTK2 package is a Common Lisp binding for Gtk+ and related libraries. This package enables Lisp developers to develop Gtk+-based GUI applications.</para>
+  </chapter>
+  <chapter>
+    <title>Goals</title>
+    <para>The goal of CL-GTK2 is to provide portable (modulo threading, metaobject protocol, FFI), extensible and feature-complete binding for Gtk+ and set of related libraries (GLib, GObject, Gdk, Pango, Cairo, GdkPixbuf, GtkSourceView, etc.)</para>
+    <para>Gtk+ is writtent in C and uses object-oriented style of programming with support of GObject library. GObject provides classes, objects, memory management via reference counters, classes introspection, signals, properties. Goal includes "lispy" interface to GObject-based libraries. This means that GObject classes should map into CLOS classes, GObject instance into CLOS instances, properties should match to slots, it should be possible to attach closures as signal handlers. It should be possible to define GObject classes, implement properties, methods, signals, interfaces from lisp.</para>
+    <para>All memory management (object instances, closures, signal handlers, etc.) should be automatic. When applicable, optional support for manual management (using refcounts) should be provided for perfomance reasons.</para>
+    <para>All Gtk+ classes should be mapped, and the rest of the API should be mapped in lispy way. Support for NIH features should not be provided (e.g., do not expose GSList, GList, GHashtable, GUri but rather transparently convert to/from them).</para>
+    <para>Error handling should be provided; GObject/Gtk warnings and errors should be exposed as conditions. It should not be possible to bring Gtk+ into incostistent state when error in lisp code called from Gtk occurs (e.g., error in signal handler should not cause fatal errors but rather should be handleable).</para>
+    <para>CL-GTK2 should be threadsafe: it should be possible to make actions under the Gdk lock, and make actions from withing the GUI thread.</para>
+    <para>Ease of extending and updating to reflect progress of Gtk+ is also important.</para>
+    <para>CL-GTK2 should run main-loop threadedly; it should be possible to interactively modify the code while the GUI program is running.</para>
+  </chapter>
+  <chapter>
+    <title>Development history</title>
+    <para>This project was started by Kalyanov Dmitry in 2008. It was a hobby project to address the (perceived or real) lack of good portable GUI libraries for Common Lisp and to be able to use it for writing diploma (or is it called "graduate"?) project during final course of the university.</para>
+    <para>Initial intent was to use SWIG<footnote><para><ulink url="http://www.swig.org/">Simplified Wrapper and Interface Generator</ulink>; a program that automatically parses C and C++ header files and generates the binding code for many languages, including Common Lisp (targetting CFFI).</para></footnote> in order to be able to generate all of the code. After some experimenting, it was found out that use of SWIG would not help to achieve the goals. First of all, in order to create "lispy" bindings, a lot of integration should be done: object systems, memory management, passing closure and values, type mapping (G(S)List to list, GCallback/GCLosure to functions, etc.). SWIG is not of much help here.</para>
+    <para>So, it was decided to use CFFI and manually map all of the API. First, base infrastructure was created (definition of basic types, maps for basic types, integration with GObject object system and memory management, introspection of GObject types). Then large chunks of API were mapped with automatic generation of classes definitions. Then missing properties were added and functions were mapped.</para>
+    <para>In order to map GtkTreeModel, preliminary support for subclassing and implementing GObjects was introduced. With its help, lispy ArrayListStore (analog for GtkListStore) was implemented.</para>
+    <para>At the moment, next version of GObject binding using the CLOS MOP is being developed. It pretty much obsoletes class generation macroses and is neede in order to be able to make lispy maps of GObject methods into CLOS generic functions and to subclass GObject classes.</para>
+    <para>For future development, using GObjectIntrospection seems the definite way.</para>
+  </chapter>
+  <chapter>
+    <title>Features</title>
+    <para>Short summary of features provided by CL-GTK2:</para>
+    <itemizedlist>
+      <listitem><para>Mapping from GObject to CLOS with (partial) support for creating subclasses, overriding methods</para></listitem>
+      <listitem><para>Automatic memory management (with optional support for manual reference counting)</para></listitem>
+      <listitem><para>Lispy interface to related libraries (currently only to GLib, GObject, Gdk, Gtk)</para></listitem>
+      <listitem><para>Lispy mapping of Gtk+ API</para></listitem>
+      <listitem><para>Custom ListStore (TreeStore to be done) for GtkTreeModel</para></listitem>
+      <listitem><para>Partial error management (closures are invoked with restarts making it possible to cancel signal handling without crashing Gtk+)</para></listitem>
+      <listitem><para>Some high-level features based on Gtk+ API: with-progress-bar, with-message-error-handler</para></listitem>
+    </itemizedlist>
+  </chapter>
+  <chapter>
+    <title>GObject binding</title>
+    <para>At the base of Gtk+ is the GObject library. This library provides basic object-oriented system and various services. </para>
+  </chapter>
+</book>
diff --git a/doc/hello.lisp b/doc/hello.lisp
new file mode 100644 (file)
index 0000000..3b1e16d
--- /dev/null
@@ -0,0 +1,27 @@
+(defpackage :gtk-hello
+  (:use :cl :gtk :gobject :glib)
+  (:export :run))
+
+(in-package :gtk-hello)
+
+(defun run ()
+  (let ((output *standard-output*))
+    (with-main-loop
+        (let ((window (make-instance 'gtk-window
+                                     :type :toplevel
+                                     :window-position :center
+                                     :title "Hello world!"
+                                     :default-width 300
+                                     :default-height 100))
+              (button (make-instance 'button :label "Hello, world!"))
+              (counter 0))
+          (g-signal-connect button "clicked"
+                            (lambda (b)
+                              (declare (ignore b))
+                              (format output "Hello, world!~%")
+                              (setf (button-label button)
+                                    (format nil
+                                            "Hello, world! (clicked ~D times)"
+                                            (incf counter)))))
+          (container-add window button)
+          (widget-show window :all t)))))
\ No newline at end of file
diff --git a/doc/hello_world.png b/doc/hello_world.png
new file mode 100644 (file)
index 0000000..6d8c849
Binary files /dev/null and b/doc/hello_world.png differ
diff --git a/doc/tutorial.xml b/doc/tutorial.xml
new file mode 100644 (file)
index 0000000..61b8f39
--- /dev/null
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8"?>
+<article>
+  <articleinfo>
+    <title>CL-GTK2 Tutorial</title>
+    <author>
+      <personname>
+        <firstname>Dmitry</firstname>
+        <surname>Kalyanov</surname>
+      </personname>
+    </author>
+  </articleinfo>
+  <section>
+    <title>TODO</title>
+    <para>Introduction</para>
+    <para>More involved example: simple text editor</para>
+    <para>More involved example walk-through: widgets, properties, packing, child properties</para>
+    <para>TreeView example</para>
+  </section>
+  <section>
+    <title>Installation</title>
+    <para>Unpack the CL-GTK2 sources, and add them to <varname>asdf:*central-registry*</varname>:</para>
+    <programlisting>
+      (push "/path/to/cl-gtk2/glib/" asdf:*central-registry*)
+      (push "/path/to/cl-gtk2/gdk/" asdf:*central-registry*)
+      (push "/path/to/cl-gtk2/gtk/" asdf:*central-registry*)
+    </programlisting>
+  </section>
+  <section>
+    <title>"Hello world" example</title>
+    <para>Let's start from a simple example.</para>
+    <graphic fileref="hello_world.png"/>
+    <para>Load the GTK system: <programlisting>(asdf:oos 'asdf:load-op :gtk)</programlisting></para>
+    <para>Having loaded the GTK system, compile the following code:</para>
+    <programlisting linenumbering="numbered">
+(defpackage :gtk-hello
+  (:use :cl :gtk :gobject :glib)
+  (:export :run))
+
+(in-package :gtk-hello)
+
+(defun run ()
+  (let ((output *standard-output*))
+    (with-main-loop
+        (let ((window (make-instance 'gtk-window
+                                     :type :toplevel
+                                     :window-position :center
+                                     :title "Hello world!"
+                                     :default-width 300
+                                     :default-height 100))
+              (button (make-instance 'button :label "Hello, world!"))
+              (counter 0))
+          (g-signal-connect button "clicked"
+                            (lambda (b)
+                              (declare (ignore b))
+                              (format output "Hello, world!~%")
+                              (setf (button-label button)
+                                    (format nil
+                                            "Hello, world! (clicked ~D times)"
+                                            (incf counter)))))
+          (container-add window button)
+          (widget-show window :all t)))))
+    </programlisting>
+    <para>And now, run it:<programlisting>(gtk-hello:run)</programlisting></para>
+    <para>This code should create a form with a button. When the button is clicked, this program prints a message to standard output and changes the text of the button.</para>
+    <para>If you have a window, then congratulations! Otherwise, contact the author for support.</para>
+  </section>
+  <section>
+    <title>Example walk-through</title>
+    <para>Let's analyze the example step by step.</para>
+    <para>CL-GTK2 runs the Gtk main loop in background thread. This is done so you could have your application running and interacting with the Lisp system through the REPL.</para>
+    <para>To execute some code and ensure that Gtk+ main loop is started, WITH-MAIN-LOOP macro is used. It runs the body of code within the Gtk+ main loop. Because all calls to Gtk+ functions require locking, it is neccessary to run this code from th main loop. Because we are running the code in another thread, its dynamic bindings (including *standard-output*) will be lost. To be able to print at REPL, we save reference to the standard output stream in the closure.</para>
+    <para>Gtk+ objects are created with make-instance and are properly garbage-collected. Some properties (slots) of objects are constructor-only properties and can only be set at object construction time. For example, "type" property of GtkWindow can only be set during its creation.</para>
+    <para>Call to container-add puts button as a child widget into window, and widget-show shows all widgets of window.</para>
+    <para>In Gtk+, objects have "signals", to which handlers can be attached. When something happens that results in "emitting" the signal (e.g., button being clicked emits "clicked" signal), all handlers of this signal are called. Handler of GtkButton's "clicked" signal has only one argument - the button that was clicked. CL-GTK2 allows attaching any function (including closures) as signal handlers and ensures that closure is freed properly.</para>
+  </section>
+</article>