X-Git-Url: https://git.stderr.nl/gitweb?a=blobdiff_plain;ds=sidebyside;f=libchimara%2Fdispatch.c;h=51c89f3afa5654b2c75183c5d54040c1c596fd5e;hb=40c961bdf2523ebdcb6717f2537f97156fd19ab4;hp=b1f84dacd6d40c6937460961e6e394df30a69b5e;hpb=d0d1517f5447d0bd95c6b9769a92054f4c7fcaae;p=rodin%2Fchimara.git
diff --git a/libchimara/dispatch.c b/libchimara/dispatch.c
index b1f84da..51c89f3 100644
--- a/libchimara/dispatch.c
+++ b/libchimara/dispatch.c
@@ -6,6 +6,66 @@
extern GPrivate *glk_data_key;
+/**
+ * gidispatch_set_object_registry:
+ * @regi: Function to call whenever an opaque object is created.
+ * @unregi: Function to call whenever an opaque object is destroyed.
+ *
+ * The Glk API refers to opaque objects by pointer; but a VM probably cannot
+ * store pointers to native memory. Therefore, a VM program will want to keep a
+ * VM-accessible collection of opaque objects.
+ *
+ *
+ * For example, it might keep a hash table for each opaque object class,
+ * mapping integer identifiers to object pointers.
+ *
+ *
+ * To make this possible, a Glk library must implement
+ * gidispatch_set_object_registry().
+ *
+ * Your program calls gidispatch_set_object_registry() early (before it begins
+ * actually executing VM code.) You pass in two function pointers, matching the
+ * following prototypes:
+ * |[
+ * #gidispatch_rock_t my_vm_reg_object(void *obj, #glui32 objclass);
+ * void my_vm_unreg_object(void *obj, #glui32 objclass, #gidispatch_rock_t objrock);
+ * ]|
+ *
+ * Whenever the Glk library creates an object, it will call my_vm_reg_object().
+ * It will pass the object pointer and the class number (from 0 to
+ * N - 1N -
+ * 1, where N is the value returned by
+ * gidispatch_count_classes().)
+ *
+ * You can return any value in the #gidispatch_rock_t object; the library will
+ * stash this away inside the object.
+ *
+ *
+ * Note that this is entirely separate from the regular Glk rock, which is
+ * always a #glui32 and can be set independently.
+ *
+ *
+ * Whenever the Glk library destroys an object, it will call
+ * my_vm_unreg_object(). It passes you the object pointer, class number, and the
+ * object rock.
+ *
+ * One significant detail: It is possible that some Glk objects will already
+ * exist when your glk_main() function is called.
+ *
+ *
+ * For example, MacGlk can open a stream when the user double-clicks a file;
+ * this occurs before glk_main().
+ *
+ *
+ * So when you call gidispatch_set_object_registry(), it may immediately call
+ * your my_vm_reg_object() callback, notifying you of the existing objects. You
+ * must be prepared for this possibility.
+ *
+ *
+ * If you are keeping hash tables, for example, create them before you call
+ * gidispatch_set_object_registry().
+ *
+ */
void
gidispatch_set_object_registry(gidispatch_rock_t (*regi)(void *obj, glui32 objclass), void (*unregi)(void *obj, glui32 objclass, gidispatch_rock_t objrock))
{
@@ -29,9 +89,26 @@ gidispatch_set_object_registry(gidispatch_rock_t (*regi)(void *obj, glui32 objcl
}
}
+/**
+ * gidispatch_get_objrock:
+ * @obj: An opaque object.
+ * @objclass: One of #gidisp_Class_Window, #gidisp_Class_Stream,
+ * #gidisp_Class_Fileref, or #gidisp_Class_Schannel.
+ *
+ * You can, at any time, get the object rock of an object. The library
+ * implements this function.
+ *
+ * With this and your two callbacks, you can maintain (say) a hash table for
+ * each object class, and easily convert back and forth between hash table keys
+ * and Glk object pointers. A more sophisticated run-time system (such as Java)
+ * could create a typed VM object for every Glk object, thus allowing VM code to
+ * manipulate Glk objects intelligently.
+ */
gidispatch_rock_t
gidispatch_get_objrock(void *obj, glui32 objclass)
{
+ g_return_val_if_fail(obj, (gidispatch_rock_t)NULL);
+
switch(objclass)
{
case gidisp_Class_Window:
@@ -49,6 +126,61 @@ gidispatch_get_objrock(void *obj, glui32 objclass)
}
}
+/**
+ * gidispatch_set_retained_registry:
+ * @regi: Function to call whenever the Glk library assumes ownership of an
+ * array.
+ * @unregi: Function to call whenever the Glk library releases ownership of an
+ * array.
+ *
+ * A few Glk functions take an array and hold onto it. The memory is
+ * owned
by the library until some future Glk call releases it.
+ * While the library retains the array, your program should not read, write,
+ * move, or deallocate it. When the library releases it, the contents are in
+ * their final form, and you can copy them out (if appropriate) and dispose of
+ * the memory as you wish.
+ *
+ * To allow this, the library implements gidispatch_set_retained_registry().
+ *
+ * Again, you pass in two function pointers:
+ * |[
+ * #gidispatch_rock_t my_vm_reg_array(void *array, #glui32 len, char *typecode);
+ * void my_vm_unreg_array(void *array, #glui32 len, char *typecode, #gidispatch_rock_t objrock);
+ * ]|
+ *
+ * Whenever a Glk function retains an array, it will call my_vm_reg_array().
+ * This occurs only if you pass an array to an argument with the
+ * "#!"
prefix.
+ *
+ *
+ * But not in every such case. Wait for the my_vm_reg_array() call to confirm
+ * it.
+ *
+ *
+ * The library passes the array and its length, exactly as you put them in the
+ * #gluniversal_t array. It also passes the string which describes the argument.
+ *
+ *
+ * Currently, the only calls that retain arrays are glk_request_line_event(),
+ * glk_stream_open_memory(), glk_request_line_event_uni(), and
+ * glk_stream_open_memory_uni(). The first two of these use arrays of
+ * characters, so the string is "&+#!Cn"
. The latter two use
+ * arrays of #glui32, so the string is "&+#!Iu"
.
+ *
+ *
+ * You can return any value in the #gidispatch_rock_t object; the library will
+ * stash this away with the array.
+ *
+ * When a Glk function releases a retained array, it will call
+ * my_vm_unreg_array(). It passes back the same @array, @len, and @typecode
+ * parameters, as well as the #gidispatch_rock_t you returned from
+ * my_vm_reg_array().
+ *
+ * With these callbacks, you can maintain a collection of retained arrays. You
+ * can use this to copy data from C arrays to your own data structures, or keep
+ * relocatable memory locked, or prevent a garbage-collection system from
+ * deallocating an array while Glk is writing to it.
+ */
void
gidispatch_set_retained_registry(gidispatch_rock_t (*regi)(void *array, glui32 len, char *typecode), void (*unregi)(void *array, glui32 len, char *typecode, gidispatch_rock_t objrock))
{