Document all incomplete symbols
[projects/chimara/chimara.git] / libchimara / dispatch.c
1 #include <libchimara/glk.h>
2 #include "chimara-glk-private.h"
3 #include "window.h"
4 #include "stream.h"
5 #include "fileref.h"
6 #include "schannel.h"
7
8 extern GPrivate *glk_data_key;
9
10 /**
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.
14  *
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.
18  * 
19  * <note><para>
20  *   For example, it might keep a hash table for each opaque object class,
21  *   mapping integer identifiers to object pointers.
22  * </para></note>
23  * 
24  * To make this possible, a Glk library must implement 
25  * gidispatch_set_object_registry().
26  * 
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:
30  * |[
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);
33  * ]|
34  * 
35  * Whenever the Glk library creates an object, it will call 
36  * <function>my_vm_reg_object&lpar;&rpar;</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().)
40  * 
41  * You can return any value in the #gidispatch_rock_t object; the library will
42  * stash this away inside the object.
43  * 
44  * <note><para>
45  *   Note that this is entirely separate from the regular Glk rock, which is
46  *   always a #glui32 and can be set independently.
47  * </para></note>
48  * 
49  * Whenever the Glk library destroys an object, it will call
50  * <function>my_vm_unreg_object&lpar;&rpar;</function>. It passes you the object
51  * pointer, class number, and the object rock.
52  *
53  * One significant detail: It is possible that some Glk objects will already
54  * exist when your glk_main() function is called.
55  * 
56  * <note><para>
57  *   For example, MacGlk can open a stream when the user double-clicks a file;
58  *   this occurs before glk_main().
59  * </para></note>
60  * 
61  * So when you call gidispatch_set_object_registry(), it may immediately call
62  * your <function>my_vm_reg_object&lpar;&rpar;</function> callback, notifying 
63  * you of the existing objects. You must be prepared for this possibility.
64  * 
65  * <note><para>
66  *   If you are keeping hash tables, for example, create them before you call
67  *   gidispatch_set_object_registry().
68  * </para></note>
69  */
70 void 
71 gidispatch_set_object_registry(gidispatch_rock_t (*regi)(void *obj, glui32 objclass), void (*unregi)(void *obj, glui32 objclass, gidispatch_rock_t objrock))
72 {
73         ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
74         winid_t win;
75     strid_t str;
76     frefid_t fref;
77     
78     glk_data->register_obj = regi;
79     glk_data->unregister_obj = unregi;
80     
81     if(glk_data->register_obj) 
82         {
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);
90     }
91 }
92
93 /**
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.
98  *
99  * You can, at any time, get the object rock of an object. The library
100  * implements this function.
101  * 
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.
107  */
108 gidispatch_rock_t 
109 gidispatch_get_objrock(void *obj, glui32 objclass)
110 {
111         g_return_val_if_fail(obj, (gidispatch_rock_t)NULL);
112         
113         switch(objclass) 
114         {
115                 case gidisp_Class_Window:
116                         return ((winid_t)obj)->disprock;
117                 case gidisp_Class_Stream:
118                         return ((strid_t)obj)->disprock;
119                 case gidisp_Class_Fileref:
120                         return ((frefid_t)obj)->disprock;
121                 case gidisp_Class_Schannel:
122                         return ((schanid_t)obj)->disprock;
123                 default: 
124                 {
125                         gidispatch_rock_t dummy;
126                         dummy.num = 0;
127                         return dummy;
128                 }
129         }
130 }
131
132 /**
133  * gidispatch_set_retained_registry:
134  * @regi: Function to call whenever the Glk library assumes ownership of an
135  * array.
136  * @unregi: Function to call whenever the Glk library releases ownership of an
137  * array.
138  *
139  * A few Glk functions take an array and hold onto it. The memory is 
140  * <quote>owned</quote> by the library until some future Glk call releases it.
141  * While the library retains the array, your program should not read, write,
142  * move, or deallocate it. When the library releases it, the contents are in
143  * their final form, and you can copy them out (if appropriate) and dispose of
144  * the memory as you wish.
145  * 
146  * To allow this, the library implements gidispatch_set_retained_registry().
147  * 
148  * Again, you pass in two function pointers:
149  * |[
150  * gidispatch_rock_t my_vm_reg_array(void *array, glui32 len, char *typecode);
151  * void my_vm_unreg_array(void *array, glui32 len, char *typecode, gidispatch_rock_t objrock);
152  * ]|
153  *
154  * Whenever a Glk function retains an array, it will call 
155  * <function>my_vm_reg_array&lpar;&rpar;</function>. This occurs only if you 
156  * pass an array to an argument with the <code>"#!"</code> prefix.
157  *
158  * <note><para>
159  *   But not in every such case. Wait for the
160  *   <function>my_vm_reg_array&lpar;&rpar;</function> call to confirm it.
161  * </para></note>
162  *
163  * The library passes the array and its length, exactly as you put them in the
164  * #gluniversal_t array. It also passes the string which describes the argument.
165  *
166  * <note><para>
167  *   Currently, the only calls that retain arrays are glk_request_line_event(),
168  *   glk_stream_open_memory(), glk_request_line_event_uni(), and
169  *   glk_stream_open_memory_uni(). The first two of these use arrays of
170  *   characters, so the string is <code>"&+#!Cn"</code>. The latter two use
171  *   arrays of #glui32, so the string is <code>"&+#!Iu"</code>.
172  * </para></note>
173  * 
174  * You can return any value in the #gidispatch_rock_t object; the library will
175  * stash this away with the array.
176  * 
177  * When a Glk function releases a retained array, it will call
178  * <function>my_vm_unreg_array&lpar;&rpar;</function>. It passes back the same
179  * @array, @len, and @typecode parameters, as well as the #gidispatch_rock_t you
180  * returned from <function>my_vm_reg_array&lpar;&rpar;</function>.
181  * 
182  * With these callbacks, you can maintain a collection of retained arrays. You
183  * can use this to copy data from C arrays to your own data structures, or keep
184  * relocatable memory locked, or prevent a garbage-collection system from
185  * deallocating an array while Glk is writing to it.
186  */
187 void 
188 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))
189 {
190         ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
191         glk_data->register_arr = regi;
192         glk_data->unregister_arr = unregi;
193 }