Run and compile lablgtk2 code
Run the examples
From the examples directory, type:
In case you haven’t installed lablgtk2 yet, add the -localdir switch:
../src/lablgtk2 -localdir ???.ml
How to compile and link
The lablgtk2 script loads an extra module GtkInit, whose only contents is:
let locale = GtkMain.Main.init ()
To compile the examples, you must either add this line, or add this module to your link, before calling any Gtk function.
If you’re using ocamlfind, you can use the convenience package
ocamlfind ocamlc -package lablgtk2.auto-init -linkpkg -w s ???.ml -o ???
Otherwise, use something similar to:
ocamlc -I +lablgtk2 -w s lablgtk.cma gtkInit.cmo ???.ml -o ???
Lablgtk binds most of the GTK+ API and some functions in other libraries like Glib.
Some functions are not handled to avoid commiting unused and un-tested code. Don’t hesitate to ask for the ones you may need since they’re most-usually very simple to add.
Some widgets are only supported in newer versions of GTK+.
If you use them in older versions, you will get a runtime error:
Failure "Gobject.unsafe_create : type GtkActionGroup is not yet defined"
For unsupported methods, the error message is a bit clearer:
Failure "gdk_pixbuf_get_file_info unsupported in Gtk 2.x < 2.4"
Structure of the modules
(raw) Gtk* modules
These modules are composed of one submodule for each class.
Signals specific to a widget are in a Signals inner module.
A setter function is defined to give access to set_param functions.
These modules provide classes to wrap the raw function calls. Here are the widget classes contained in each module:
GPango: Pango font handling
GDraw: Gdk pixmaps, etc…
GObj: gtkobj, widget, style
GData: data, adjustment, tooltips
GContainer: container, item_container
GWindow: window, dialog, color_selection_dialog, file_selection, plug
GPack: box, button_box, table, fixed, layout, packer, paned, notebook
GBin: scrolled_window, event_box, handle_box, frame, aspect_frame, viewport, socket
GButton: button, toggle_button, check_button, radio_button, toolbar
GMenu: menu_item, tearoff_item, check_menu_item, radio_menu_item, menu_shell, menu, option_menu, menu_bar, factory
GMisc: separator, statusbar, calendar, drawing_area, misc, arrow, image, pixmap, label, tips_query, color_selection, font_selection
GTree: tree_item, tree, view (also tree/list_store, model)
GList: list_item, liste, clist
GEdit: editable, entry, spin_button, combo
GRange: progress, progress_bar, range, scale, scrollbar
GText: view (also buffer, iter, mark, tag, tagtable)
While subtyping follows the Gtk widget hierarchy, you cannot always use width subtyping (i.e. #super is not unifiable with all the subclasses of super). Still, it works for some classes, like #widget and #container, and allows subtyping without coercion towards these classes (cf. #container in examples/pousse.ml for instance).
Practically, each widget class is composed of:
a coerce method, returning the object coerced to the type widget.
an as_widget method, returning the raw Gtk widget used for packing, etc…
a destroy method, sending the destroy signal to the object.
a get_oid method, the equivalent of Oo.id for Gtk objects.
a connect sub-object, allowing one to widget specific signals (this is what prevents width subtyping in subclasses.)
a misc sub-object, giving access to miscellaneous functionality of the basic gtkwidget class, and a misc#connect sub-object.
an event sub-object, for Xevent related functions (only if the widget has an Xwindow), and an event#connect sub-object.
a drag sub-object, containing drag and drop functions, and a drag#connect sub-object.
widget specific methods.
Here is a diagram of the structure (- for methods, + for sub-objects)
- coerce : widget - as_widget : Gtk.widget obj - destroy : unit -> unit - get_oid : int - ... + connect : mywidget_signals | - after | - signal_name : callback:(... -> ...) -> GtkSignal.id + misc : misc_ops | - show, hide, disconnect, ... | + connect : misc_signals + drag : drag_ops | - ... | + connect : drag_signals + event : event_ops | - add, ... | + connect : event_signals
You create a widget with
<Module>.<widget name> options ... ().
Many optional arguments are admitted. The last two of them, packing: and show:, allow you respectively to call a function on your newly created widget, and to decide whether to show it immediately or not.
By default all widgets except toplevel windows (GWindow module) are shown immediately.
For many constructor or method arguments, default values are provided. Generally speaking, this default value is defined by GTK, and you must refer to GTK’s documentation.
For ML-defined defaults, default values are usually either false, 0, None or `NONE, according to the expected type.
Important exceptions are
~show, which defaults to true in all widgets
except those in GWindow, and
~fill, which defaults to true or `BOTH.
Note about unit as method argument
O’Caml introduces no distinction between methods having side-effects and methods simply returning a value. In practice, this is confusing, and awkward when used for callbacks. For this reason all methods having noticeable side-effects should take arguments, and unit if they have no argument.
How to use threads
% lablgtk2 -thread Objective Caml version 3.09 # let w = GWindow.window ~show:true ();; # let b = GButton.button ~packing:w#add ~label:"Hello!" ();;
You should see a window with a button appear at once.
The GTK main loop is running in a separate thread. Any command is immediately reflected.
For Windows and OSX/Quartz, there are restrictions on which commands can be used in which thread. See the windows port section below for how to use them.
When using threads in a stand-alone application, you must link with gtkThread.cmo and call GtkThread.main in place of GMain.main.
Since 2.16.0, busy waiting is no longer necessary with systems threads. (I.e., CPU usage is 0% if nothing occurs.)
With VM threads, you have to enable busy waiting by hand, otherwise other
threads won’t be executed; see
gtkThread.mli for details.
Beware that with VM threads, you cannot switch threads within a callback. The only thread-related command you may use in a callback is Thread.create. Calling blocking operations may cause deadlocks. On the other hand, all newly created threads will be run outside of the callback, so they can use all thread operations.
Gtk-2 uses unicode (utf8) for all strings. If you use non-ascii strings, you must imperatively convert them to unicode.
This can be done with the
Glib.Convert.locale_to_utf8 function. If
your input is already in utf8, it is still a good idea to validate it
with Glib.Utf8.validate, as malformed utf8 strings may cause
Note that setlocale is now always called (except if you set GTK_SETLOCALE to 0 in the environment), but LC_NUMERIC is reverted to "C" to avoid problems with floating point conversion in Caml.
Important efforts have been dedicated to cooperate with Gtk’s reference-counting mechanism. You should generally be able to use Gdk/Gtk data structures without caring about memory management. They will be freed when nobody points to them any more.
This also means that you do not need to pay too much attention to whether a data structure is still alive or not. If it is not, you should get an error rather than a core dump.
The case of Gtk objects deserves special care. Since they are interactive, we cannot just destroy them when they are no longer referenced. They have to be explicitly destroyed. If a widget was added to a container widget, it will automatically be destroyed when its last container is destroyed. For this reason you need only destroy toplevel widgets.
|Some Gtk data structures are allocated in the Caml heap, and their use in signals (Gtk functions internally calling callbacks) relies on their address being stable during a function call. For this reason automatic compaction is disabled in GtkMain. If you need it, you may use compaction through Gc.compact where it is safe (timeouts, other threads…), but do not enable automatic compaction.|
The GUtil module provides two kinds of utilities: a memo table, to be able to dynamically cast widgets to their original class, and more interesting ML-side signals.
With ML-side signals, you can combine LablGTK widgets into your own components, and add signals to them. Later you can connect to these signals, just like GTK signals. This proved very efficient to develop complex applications, abstracting the plumbing between various components. Explanations are provided in GUtil.mli.
Files in the source distribution
gdk.ml: low-level interface to the General Drawing Kit
gtk.ml: low-level interface to the GIMP Tool Kit
gtkThread.ml: main loop for threaded version
g[A-Z]*.ml: object-oriented interface to GTK
gdkObj.ml: object-oriented interface to GDK
examples/*.ml: various examples
applications/browser: an ongoing port of ocamlbrowser
applications/camlirc: an IRC client (by Nobuaki Yoshida)
The GToolbox module contains contributed components to help you build your applications.
See README.win32 for detailed information on installation.
If you want to use threads, you must be aware of windows specific restrictions; see for instance: http://article.gmane.org/gmane.comp.video.gimp.windows.devel/314
I.e. all GTK related calls must occur in the same thread, the one that runs the main loop. If you want to call them from other threads you need to do some forwarding. Fortunately, with a functional language this is easy. Two functions, are available in the GtkThread module to help you:
val async : ('a -> unit) -> 'a -> unit val sync : ('a -> 'b) -> 'a -> 'b
They will forward your call to the main thread (between handling two GUI events). This can be either asynchronous or synchronous.
In the synchronous case, beware of deadlocks (the trivial case, when you are calling from the same thread, is properly avoided).
Note also that since callbacks are always called from the main loop thread, you can freely use GTK in them. Also, non-graphical operations are thread-safe.
Here is an example using the lablgtk toplevel with threads:
% lablgtk2.bat -thread Objective Caml version 3.09 # open GtkThread;; # let w = sync (GWindow.window ~show:true) ();; # let b = sync (GButton.button ~packing:w#add ~label:"Hello!") ();; # b#connect#clicked (fun () -> prerr_endline "Hello");;
Since Darwin is Unix, this port compiles as usual.
Note however that Quartz imposes even stronger restrictions than Windows on threads: only the main thread of the application can do GUI work. Just apply the same techniques as described above, being careful to ensure that your first call to GtkThread.main occurs in the main thread. This is done automatically in the threaded toplvel.
Support for additional libraries
There is support for Glade-generated XML UI description files, using libglade. You can read in a file, access widgets, and define callbacks.
A tool for extracting widget definitions from glade description is provided. It generates a wrapper class, and you can then generate an object corresponding to the intended layout, and access individual widgets through its methods. Example:
% lablgladecc2 project1.glade > project1.ml % lablgtk2 -thread # #use "project1.ml" ;; class window1 : ... # let w1 = new window1 () ;; # w1#bind ~name:"on_paste1_activate" ~callback:(fun () -> w1#text1#insert "some text\n");;
See lablgladecc2 -help for other features (tracing and source embedding).
The executable must be linked with lablglade.cma.
You can use lablgtk in combination with LablGL:
get and install lablGL 1.04 from http://wwwfun.kurims.kyoto-u.ac.jp/soft/olabl/lablgl.html
get and install gtkglarea-1.99.0.tar.gz from ftp://ftp.gnome.org/pub/gnome/sources/gtkglarea/1.99/ or any other gnome mirror site
You can then use the widget GlGtk.gl_area as an OpenGL window.
Some examples are in examples/GL, but basically any LablGL example can be easily ported.
The executable must be linked with both lablgl.cma and lablgtkgl.cma.
This binding was contributed by Olivier Andrieu.
It requires librsvg-2.x (preferably 2.2.x).
See an example in examples/rsvg.
The executable must be linked with lablrsvg.cma.
This binding was contributed by Olivier Andrieu.
It requires libgnomecanvas-2.x.
See examples in examples/canvas.
The executable must be linked with lablgnomecanvas.cma.
This binding was contributed by Maxence Guesdon and Stefano Zacchiroli.
It requires libgtksourceview-1.x.
See examples in examples/sourceview.
The executable must be linked with lablgtksourceview.cma.
This binding was contributed by Benjamin Monate; it is based on the GtksourceView 1 support mentionned below.
It requires libgtksourceview-2.x.
See examples in examples/sourceview/*2.ml
The executable must be linked with lablgtksourceview2.cma.