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