1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
|
This file documents coding conventions used in mlgtk.
Hopefully it will help make it easier to understand
the stubs already written, and to add more.
Quantitatively, a lot of what remains to be done is
very simple : stubs to access more gtk functions.
Gtk manipulates all widgets thru a pointer. For instance
the function:
guint gtk_text_get_point (GtkText *text);
takes a pointer to a GtkText. This is good, because
this is also how values are represented in Ocaml.
Still, it is best to always use the following macros:
Gtk<widget name>_ml(object) : to convert an ml value into a
pointer to a gtk widget.
ml_GtkObject(object) : to convert a gtk widget to an ml value
check_GtkObject_ml(object, func_id) : This macro should be
used on all Gtk objects (and only on Gtk objects)
before using them.
in debugging mode, this will insert a sanity check.
------------------
Before writing mlgtk code, you should have read, *and understood*,
the chapter "Interfacing C with Objective Caml" in the Ocaml manual.
Here are a few guidelines :
The GC is authorized to move blocks around. Therefore, the gc should
be aware of all pointers to heap-allocated blocks, so that it can
update these pointers if it moves the pointed blocks.
Garbage collections can take place at any allocation of memory.
So, if you only need to allocate one block in the heap there
is no particular precaution to take, and if you need n blocks,
you should make sure that the variables that hold the address of
blocks 0 to (i-1) are registered roots before allocating block
number i.
Registered roots will be traversed by the GC, so they must
point to well-formed blocks. See the Ocaml manual for the
definition of "well-formed". Never register as a root an
uninitialized variable!!! The variable that will hold the
block you are currently allocating doesn't need to be registered.
------------------
les macros CAMLparam* representent la nouvelle maniere d'interfacer
du C avec Caml. Les macros que nous utilisons pour l'instant
(register_*_root) sont l'ancienne maniere. Le gc lui-meme n'a
pas change, et l'ancienne methode continue de fonctionner tout
aussi bien. On peut d'ailleurs utiliser les deux methodes dans
un meme fichier (mais pour une meme fonction, il faut rester coherent
et n'utiliser qu'une seule des deux methodes).
Pourquoi ne pas utiliser les macros CAMLparam* ? parce qu'elles sont
completement overkill. Sous pretexte d'homogeneiser, on est oblige
de declarer toutes les variable locales d'une fonction comme
racines. Alors que dans 90% des cas on n'a rien besoin de declarer,
parce que l'on ne fait pas d'allocation a l'interieur de la fonction C
(donc le gc ne prend pas le controle). C'est inefficace, ca reduit
la lisibilite en augmentant le nombre de lignes n'apportant pas de
"vraie" information, bref, ce nouveau systeme a tous les defauts et
il ne faut pas s'en servir.
Le probleme est que dans le cas precis qui se presente, utiliser
CAMLparam* (ou l'equivalent en "ancienne methode", dans lequel
il n'y a besoin d'appeler aucune macro, ce qui prouve bien la superiorite
de l'ancienne methode) ne marchent ni l'un ni l'autre.
Je viens de discuter du probleme avec Damien Doligez, et ce
qu'il faut faire, c'est allouer un bloc avec malloc, le declarer
comme racine, passer l'adresse du bloc allouer avec malloc
a gtk_clist_set_row_data (comme ca on lui passe quelque chose qui ne
peut pas bouger), et ecrire l'adresse du bloc ML dans le bloc
alloue par malloc.
Ca veut dire aussi qu'il faut faire en sorte que quand la clist
est liberee, tous les blocs malloces associes soient liberes aussi.
Ca, ca releve de gtk, et pas de caml.
Pascal
|