This manual describes the GTK+ 1.2 language binding for Alice.
GTK+ is a widget set that allows to build graphical user interfaces. The language binding described herein enables Alice programmers to build graphical user interfaces using this widget set. The binding provides access to GTK+ functionality by lifting its C interface one-to-one to Alice. It hence is a low-level interface without additional abstractions, but provides almost the full GTK+ functionality.
This manual summarizes the basics of GTK+ and describes how it is mapped to Alice. The goal is to enable Alice programmers to make use of the original reference documentation to write GTK+ applications in Alice.
GTK+ is organized into visual units called widgets. Some widget classes are defined by refinement of some parent widget class using inheritance. GTK+ has an object-oriented organization but is implemented in C. Thus, it can be easily mapped to Alice ML.
The general steps to create a GTK+ widget are:
A widget object is created by instantiating a widget class. The constructors are the functions ending with new; some widget classes have multiple constructors. In those cases the constructor name usually contains a hint on what is different to the default constuctor. For example,
val window = Gtk.buttonNewWithLabel "Hello, World!"creates a new object for a button labelled "Hello, World!", whereas Gtk.buttonNew would have created a button object with an empty label.
Object creation yields a freshly created widget object whose attributes are set to reasonable default values. It will not appear on the screen until it has been packed into a container which then is made visible.
GTK+ is event-driven, which means that when an event occurs, control is passed to the appropriate function.
Signals. Events in GTK+ are implemented through signals. (Note that these signals are unrelated to Unix system signals.) When an event occurs, such as pressing a mouse button, the appropriate signal will be emitted by the corresponding widget. Some signals are common to all widget classes, such as "delete-event", while others are widget-specific, such as "toggled" for a toggle button. Signals are denoted by strings.
Connecting Handlers. The Gtk.signalConnect function allows to catch signals and cause invocation of actions. For instance,
val id = Gtk.signalConnect (widget, signal, callback)
causes callback to be invoked each time signal is emitted on widget. The result id is a unique identifier which can be used to manually emit the signal or to remove the handler.
Callbacks. Callbacks are defined as functions:
fun myCallBack args = ...
where args is a list of the arguments associated with the signal.
Low-level Events. In addition to the high-level signals described above, there is a set of events that reflect the X Window System event mechanism (simulated on non-X platforms such as Windows). These can be caught using the special signal "event". For more details, see the reference.
GTK+ widgets organize their data using attributes. Some attributes are read-only, others are mutable. The latter allow for the widget to be reconfigured after creation.
Attributes are named by strings and have an associated (typed) value. Many widgets define accessors for commonly used attributes, but in general they can be read using the Gtk.widgetGet function and written to using the Gtk.widgetSet function. Trying to access a non-existing attribute yields an error.
Widgets are laid out on the screen using so-called containers. Container widgets themselves usually do not provide any visible information, but display their child widgets according to a built-in strategy. For example, an hBox container will align its children horizontally on the screen. A container can contain other container widgets.
GTK+ provides a variety of different container types covering the "daily" needs, which all are descendants of the container class.
Bins. window is a subclass of bin, which is the superclass of all containers accepting at most one child. Bins do not do any layouting. If our window had contained more than one child, we would have needed to create another container to lay out the children, which would then have been the window's single child.
The last step to start working with widgets on the screen is to make them visible. This can be done manually by a bottom-up traversal of the container tree and calling each container's show function. This is what the topmost container's showAll method does automatically.
With few exceptions, signals emitted by a widget are only caught as long as it remains visible.
GTK+ widgets do a lot of error-checking internally, but errors are just reported to the screen instead of being raised as an Alice exception. Errors discovered in the language binding's code are reported as exceptions.
This chapter describes the details of how the C API is mapped to Alice. This knowledge is required when you want to make use of the original reference documentation. (For the GTK Canvas, the documentation is at http://developer.gnome.org/doc/API/libgnomeui/; only look at the GnomeCanvas, GnomeCanvasItem and GnomeCanvasGroup widgets.)
The Alice GTK+ library is organized into the following components:
Each module represents a namespace. The corresponding API constants and functions are mapped to constants and functions in these namespaces.
We will illustrate how C structure fields and C functions are mapped to methods by example. Consider the C API for GtkButton, which is derived from GtkBin:
struct _GtkButton { GtkBin bin; GtkWidget *child; guint in_button : 1; guint button_down : 1; guint relief : 2; }; /* constructors */ GtkWidget *gtk_button_new(); GtkWidget *gtk_button_new_with_label(const gchar *label); /* signal emitters */ void gtk_button_pressed(GtkButton *button); void gtk_button_released(GtkButton *button); void gtk_button_clicked(GtkButton *button); void gtk_button_enter(GtkButton *button); void gtk_button_leave(GtkButton *button); /* attribute accessors */ void gtk_button_set_relief(GtkButton *button, GtkReliefStyle newstyle); GtkReliefStyle gtk_button_get_relief(GtkButton *button);You will find these functions as part of the Gtk structure:
(* accessors *) val buttonGetFieldBin : object -> object val buttonGetFieldChild : object -> object val buttonGetFieldInButton : object -> int val buttonGetFieldButtonDown : object -> int val buttonGetFieldRelief : object -> int (* constructors *) val buttonNew : unit -> object val buttonNewWithLabel : string -> object (* signal emitters *) val buttonPressed : object -> unit val buttonReleased : object -> unit val buttonClicked : object -> unit val buttonEnter : object -> unit val buttonLeave : object -> unit (* attribute accessors *) val buttonSetRelief : object * int -> unit val buttonGetRelief : object -> int
General Scheme. The general scheme is that all underscored identifiers are translated to use camel-casing. Since functions belong to a module, the module name prefixes are cut off to increase readability. The first letter of each function is downcased.
Field Accessors. Field accessors are also camel-cased, but in contrast to the standard methods, they use the {className}GetField{FieldName} pattern. For example, the button_down field above is read using the buttonGetFieldButtonDown accessor function. Fields cannot be written directly.
Constants. The members of enumerations and flags are translated to constants exported with all upper case names containing underscores, with the module prefix cut off.
C Type | Alice Type |
---|---|
gint, guint, glong, gulong | int |
gboolean | bool |
gchar, guchar | int |
gfloat, gdouble | real |
enumerations, flags | int |
gchar*, guchar* | string |
gchar*[], guchar*[] | string list |
GdkEvent* | Gdk.event |
GList* | Gtk.object list |
double[4] | real list |
all other pointers (i.e., GtkWidget*) | Gtk.object |
The above table shows the mapping of the C types onto Alice types. Values are converted back and forth transparently, preserving identity whenever possible.
Flags. Flags are translated to integer constants. In general, several constants can be combined using addition (op+).
Inout Arguments. The int* and double* types are considered to be inout arguments. They are mapped to a XIn and XOut pair where XIn is given as a function argument and and XOut is returned by the function after invokation.
Gdk Events. The records carried by constructors of the Gdk.event type represent the structs contained in the GdkEvent union.
A small demo application using GTK is available:
Compile with:
alicec scramble.aml
Run with:
alicerun scramble