1 #include <libchimara/glk.h>
2 #include "chimara-glk-private.h"
7 extern GPrivate *glk_data_key;
10 * gidispatch_set_object_registry:
11 * @regi: Function to call whenever an opaque object is created.
12 * @unregi: Function to call whenever an opaque object is destroyed.
14 * The Glk API refers to opaque objects by pointer; but a VM probably cannot
15 * store pointers to native memory. Therefore, a VM program will want to keep a
16 * VM-accessible collection of opaque objects.
19 * For example, it might keep a hash table for each opaque object class,
20 * mapping integer identifiers to object pointers.
23 * To make this possible, a Glk library must implement
24 * gidispatch_set_object_registry().
26 * Your program calls gidispatch_set_object_registry() early (before it begins
27 * actually executing VM code.) You pass in two function pointers, matching the
28 * following prototypes:
30 * #gidispatch_rock_t my_vm_reg_object(void *obj, #glui32 objclass);
31 * void my_vm_unreg_object(void *obj, #glui32 objclass, #gidispatch_rock_t objrock);
34 * Whenever the Glk library creates an object, it will call my_vm_reg_object().
35 * It will pass the object pointer and the class number (from 0 to
36 * <inlineequation><mathphrase>N - 1</mathphrase><alt>N -
37 * 1</alt></inlineequation>, where N is the value returned by
38 * gidispatch_count_classes().)
40 * You can return any value in the #gidispatch_rock_t object; the library will
41 * stash this away inside the object.
44 * Note that this is entirely separate from the regular Glk rock, which is
45 * always a #glui32 and can be set independently.
48 * Whenever the Glk library destroys an object, it will call
49 * my_vm_unreg_object(). It passes you the object pointer, class number, and the
52 * One significant detail: It is possible that some Glk objects will already
53 * exist when your glk_main() function is called.
56 * For example, MacGlk can open a stream when the user double-clicks a file;
57 * this occurs before glk_main().
60 * So when you call gidispatch_set_object_registry(), it may immediately call
61 * your my_vm_reg_object() callback, notifying you of the existing objects. You
62 * must be prepared for this possibility.
65 * If you are keeping hash tables, for example, create them before you call
66 * gidispatch_set_object_registry().
70 gidispatch_set_object_registry(gidispatch_rock_t (*regi)(void *obj, glui32 objclass), void (*unregi)(void *obj, glui32 objclass, gidispatch_rock_t objrock))
72 ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
77 glk_data->register_obj = regi;
78 glk_data->unregister_obj = unregi;
80 if(glk_data->register_obj)
82 /* It's now necessary to go through all existing objects, and register them. */
83 for(win = glk_window_iterate(NULL, NULL); win; win = glk_window_iterate(win, NULL))
84 win->disprock = (*glk_data->register_obj)(win, gidisp_Class_Window);
85 for(str = glk_stream_iterate(NULL, NULL); str; str = glk_stream_iterate(str, NULL))
86 str->disprock = (*glk_data->register_obj)(str, gidisp_Class_Stream);
87 for(fref = glk_fileref_iterate(NULL, NULL); fref; fref = glk_fileref_iterate(fref, NULL))
88 fref->disprock = (*glk_data->register_obj)(fref, gidisp_Class_Fileref);
93 * gidispatch_get_objrock:
94 * @obj: An opaque object.
95 * @objclass: One of #gidisp_Class_Window, #gidisp_Class_Stream,
96 * #gidisp_Class_Fileref, or #gidisp_Class_Schannel.
98 * You can, at any time, get the object rock of an object. The library
99 * implements this function.
101 * With this and your two callbacks, you can maintain (say) a hash table for
102 * each object class, and easily convert back and forth between hash table keys
103 * and Glk object pointers. A more sophisticated run-time system (such as Java)
104 * could create a typed VM object for every Glk object, thus allowing VM code to
105 * manipulate Glk objects intelligently.
108 gidispatch_get_objrock(void *obj, glui32 objclass)
110 g_return_val_if_fail(obj, (gidispatch_rock_t)NULL);
114 case gidisp_Class_Window:
115 return ((winid_t)obj)->disprock;
116 case gidisp_Class_Stream:
117 return ((strid_t)obj)->disprock;
118 case gidisp_Class_Fileref:
119 return ((frefid_t)obj)->disprock;
122 gidispatch_rock_t dummy;
130 * gidispatch_set_retained_registry:
131 * @regi: Function to call whenever the Glk library assumes ownership of an
133 * @unregi: Function to call whenever the Glk library releases ownership of an
136 * A few Glk functions take an array and hold onto it. The memory is
137 * <quote>owned</quote> by the library until some future Glk call releases it.
138 * While the library retains the array, your program should not read, write,
139 * move, or deallocate it. When the library releases it, the contents are in
140 * their final form, and you can copy them out (if appropriate) and dispose of
141 * the memory as you wish.
143 * To allow this, the library implements gidispatch_set_retained_registry().
145 * Again, you pass in two function pointers:
147 * #gidispatch_rock_t my_vm_reg_array(void *array, #glui32 len, char *typecode);
148 * void my_vm_unreg_array(void *array, #glui32 len, char *typecode, #gidispatch_rock_t objrock);
151 * Whenever a Glk function retains an array, it will call my_vm_reg_array().
152 * This occurs only if you pass an array to an argument with the
153 * <code>"#!"</code> prefix.
156 * But not in every such case. Wait for the my_vm_reg_array() call to confirm
160 * The library passes the array and its length, exactly as you put them in the
161 * #gluniversal_t array. It also passes the string which describes the argument.
164 * Currently, the only calls that retain arrays are glk_request_line_event(),
165 * glk_stream_open_memory(), glk_request_line_event_uni(), and
166 * glk_stream_open_memory_uni(). The first two of these use arrays of
167 * characters, so the string is <code>"&+#!Cn"</code>. The latter two use
168 * arrays of #glui32, so the string is <code>"&+#!Iu"</code>.
171 * You can return any value in the #gidispatch_rock_t object; the library will
172 * stash this away with the array.
174 * When a Glk function releases a retained array, it will call
175 * my_vm_unreg_array(). It passes back the same @array, @len, and @typecode
176 * parameters, as well as the #gidispatch_rock_t you returned from
179 * With these callbacks, you can maintain a collection of retained arrays. You
180 * can use this to copy data from C arrays to your own data structures, or keep
181 * relocatable memory locked, or prevent a garbage-collection system from
182 * deallocating an array while Glk is writing to it.
185 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))
187 ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
188 glk_data->register_arr = regi;
189 glk_data->unregister_arr = unregi;