X-Git-Url: https://git.stderr.nl/gitweb?a=blobdiff_plain;f=libchimara%2Fdispatch.c;h=8473b20899fe3772c88642bd5823230852c2c0a4;hb=1e0dc5378f314f555e3b923c6d95f5017abd528b;hp=b1f84dacd6d40c6937460961e6e394df30a69b5e;hpb=1d19cdbaca8b7cd239cd5d1e1f650bd48fa37bee;p=projects%2Fchimara%2Fchimara.git diff --git a/libchimara/dispatch.c b/libchimara/dispatch.c index b1f84da..8473b20 100644 --- a/libchimara/dispatch.c +++ b/libchimara/dispatch.c @@ -3,13 +3,74 @@ #include "window.h" #include "stream.h" #include "fileref.h" +#include "schannel.h" -extern GPrivate *glk_data_key; +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)) { - ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key); + ChimaraGlkPrivate *glk_data = g_private_get(&glk_data_key); winid_t win; strid_t str; frefid_t fref; @@ -29,9 +90,27 @@ 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: @@ -40,6 +119,8 @@ gidispatch_get_objrock(void *obj, glui32 objclass) return ((strid_t)obj)->disprock; case gidisp_Class_Fileref: return ((frefid_t)obj)->disprock; + case gidisp_Class_Schannel: + return ((schanid_t)obj)->disprock; default: { gidispatch_rock_t dummy; @@ -49,10 +130,65 @@ 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)) { - ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key); + ChimaraGlkPrivate *glk_data = g_private_get(&glk_data_key); glk_data->register_arr = regi; glk_data->unregister_arr = unregi; }