LablGTK 1.2.6 : an interface to the GIMP Tool Kit Needed: ocaml-3.06 or ocaml-3.07 gtk-1.2.x GNU make (there is no standard for conditionals) Info/upgrades: http://wwwfun.kurims.kyoto-u.ac.jp/soft/olabl/lablgtk.html How to compile: You should normally not need to modify Makefiles. First type "make configure ". Options are USE_DOTOPT=1 to use ocaml.opt and ocamlopt.opt USE_CC=1 to use $(CC) rather than gcc USE_GL=1 to compile with OpenGL support (see lower) USE_GNOME=1 to compile GdkPixbuf and GtkXmHTML support USE_GLADE=1 to compile libglade support The following variables will also be remembered if passed as options BINDIR INSTALLDIR DLLDIR DEBUG CC CAMLC CAMLOPT CAMLMKTOP CAMLMKLIB CAMLP40 or you may directly edit config.make. Note that if you change DLLDIR, you should add the new directory either to OCAMLLIB/ld.conf or to CAML_LD_LIBRARY_PATH before running programs. If gtk-config has a different name, you can set the GTK_CONFIG variable to it (e.g. FreeBSD). Then just type "make" to build the library and toplevels. If you are using the windows precompiled version, you must first obtain gtk-1.3-dlls-win32.zip from the above location, and then copy bin\lablgtk.bat, lib\stublibs\dlllablgtk.dll and lib\lablgtk to their respective locations in the OCaml distribution. Contents: 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 lablgtk toplevel lablgladecc glade compiler examples/*.ml various examples applications/* applications using the library camlirc an IRC (chat) client (by Nobuaki Yoshida) radtest a very experimental RAD for lablgtk (by Hubert Fauque) browser the begin of a port of OCamlBrowser (by Jacques Garrigue) unison a frontend for the Unison file synchronizer see the README for details. How to run the examples: In the examples directory just type: lablgtk ???.ml Before installing lablgtk you have to be more explicit: setenv CAML_LD_LIBRARY_PATH ../src (or export CAML..PATH=../src) ../src/lablgtktop -w s -I ../src ???.ml How to link them: lablgtktop contains an extra module GtkInit, whose only contents is: let locale = GtkMain.Main.init () You must either add this line, or add this module to your link, before calling any Gtk function. ocamlc -I CAMLLIB/lablgtk -w s lablgtk.cma gtkInit.cmo ???.ml -o ??? How to use the threaded toplevel: % lablgtk -thread (or ./lablgtktop_t before installing) Objective Caml version 3.06 # let w = GWindow.window ~show:true ();; # let b = GButton.button ~packing:w#add ~label:"Hello!" ();; You should at once see a window appear, and then a button. The GTK main loop is running in a separate thread. Any command is immediately reflected by the system. Beware that with bytecode 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. There is no such problem for posix and win32 threads, but win32 threads have problems of their own. See the windows port section lower. When using threads in a stand-alone application, you must link with gtkThread.cmo and call GtkThread.main in place of GMain.main. Locale or not locale ? Until version 1.2.0, lablgtk called setlocale automatically on intitialization. Unfortunately, this appears to have side effects in some cases, paritcularly when the locale defines a numeric format different from the standard one. Since locale must be set before initialization, you may do it in two ways: * set the GTK_SETLOCALE environment variable to a non-0 value * use the ~setlocale parameter to GMain.Main.init (if you do not link gtkInit.cmo) Note that GTK_SETLOCALE, when set, overrides ~setlocale. On some systems you may also need to link libxpg4.so for the locale to work. Upgrading from lablgtk-1.00: There are a few incompatibilities between 1.00 and 1.2.x releases. We do not describe them all, since usually a type error message will inform you. * all signals are no longer under #connect. #connect#event changed to #event#connect, and some signals are under #misc#connect or #grab#connect. See lower for a description of the new widget structure. * some defaults changed. In particular GPack.box#pack have now all its parameters defaulting to false rather than true. See lower for the new default policy. Beware that this does not cause type errors, just changes in the aspect. * coerce functions disappeared from Gtk*.ml. You can now coerce with (w :> Gtk.mywidget Gtk.obj), thanks to variance annotations. Structure of the (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. Structure of the G[A-Z]* modules: These modules provide classes to wrap the raw function calls. Here are the widget classes contained in each module: 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 GList list_item, liste, clist GEdit editable, entry, spin_button, combo, text GRange progress, progress_bar, range, scale, scrollbar 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 connect sub-object, allowing one to widget specific signals (this is what prevents width subtyping in subclasses.) * a misc sub-object, giving access to miscellanous 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 grab sub-object, containing drag and drop functions, and a grab#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 - ... + connect : mywidget_signals | - after | - signal_name : callback:(... -> ...) -> GtkSignal.id + misc : misc_ops | - show, hide, disconnect, ... | + connect : misc_signals + event : event_ops | - add, ... | + connect : event_signals + grab : grab_ops | - ... | + connect : grab_signals You create a widget by [. 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 wether to show it immediately or not. By default all widgets except toplevel windows (GWindow module) are shown immediately. Default arguments: For many constructor or method arguments, default values are provided. Generally, this default value is defined by GTK, and you must refer to GTK's documentation. For ML defined defaults, usually default values are either false, 0, None or `NONE, according to the expected type. Important exceptions are ~show, which default 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 as callbacks. For this reason all methods having noticeable side-effects should take arguments, and unit if they have no argument. ML-side signals: 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. Contributed components: The GToolbox module contains contributed components to help you build your applications. Memory management: Important efforts have been dedicated to cooperate with Gtk's reference counting mechanism. As a result 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 explicitely 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. LibGlade support: There is support for Glade generated XML UI description files, using libglade. You can read in a file, access to 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: % lablgladecc project1.glade > project1.ml % lablgtk -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 lablgladecc -help for other features (tracing and source embedding). The xecutable must be linked with lablglade.cma. External prototyping tools: Two other tools are available for GUI prototyping MLglade compiles a glade description file to lablgtk source code, rather than the dynamic interpretation of lablglade. http://www.lri.fr/~monate/mlglade Zoggy is GUI builder writte in OCaml, which also generates lablgtk source code. It is much more advanced than radtest, which is only left as code sample. http://pauillac.inria.fr/~guesdon/Tools/zoggy/zoggy.html GL extension: You can use lablgtk in combination with LablGL * get and install lablGL 0.98 from http://wwwfun.kurims.kyoto-u.ac.jp/soft/olabl/lablgl.html * get and install gtkglarea-1.2.x.tar.gz from http://www.student.oulu.fi/~jlof/gtkglarea/index.html * reconfigure: "make configure USE_GL=1" You can also set the GLLIBS variable to the libraries you must link with. The default is "-lGLU -lGL". Due to a bug in ld.so, this should be empty on some systems, including Solaris 8. 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. Gnome support There is no real gnome support, but there is support for the gdk-pixbuf and GtkXmHtml libraries. See the GdkPixpuf and GHtml modules for details. you will need to link with lablgnome.cma. Windows port A Win32 port is provided. A binary version for use with the precompiled version of Objective Caml on Windows is avilable on the LablGTK web site. If you want to compile it yourself, you will need to get and unpack libiconv-*.zip, libintl-*.zip, glib-*.zip and gtk+-1.3.0-*.zip from http://www.gimp.org/~tml/gimp/win32/ Do not forget to get all the -dev- packages. The file include/gdk/win32/gdkwin32-private.h seems to be missing from the above distribution, so I included it in this package. Please copy it to its right location. Edit config.make.nt, then, using Visual C++ with cygwin tools, cd src make -f Makefile.nt make -f Makefile.nt opt (if you have an MS Assembler) Then install with make -f Makefile.nt install Since the link is dynamic you will also need to have in your path: libintl-1.dll (extralibs), iconv.dll (iconv), libglib-2.0-0.dll and libgmodule-2.0-0.dll (glib), libgdk-0.dll and libgtk-0.dll (gtk+). I checked with the 2002-07-03 version of these libraries. Everything seems OK. In particular, you can run all examples, and build applications/unison as usual. However, if you want to use threads, you must be aware of windows specific restrictions; see for instance: http://groups.yahoo.com/group/gimpwin-dev/message/1828 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, val async : ('a -> unit) -> 'a -> unit val sync : ('a -> 'b) -> 'a -> 'b are available in the GtkThread module to help you. 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: % lablgtk -thread Objective Caml version 3.03 # 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");; Authors: Jacques Garrigue Hubert Fauque Jun Furuse Koji Kagawa Bug reports: Jacques Garrigue $Id: lablgtk.txt,v 1.5 2005/02/17 07:41:27 garrigue Exp $