cleaning up mixed tabs and spaces
[freeglut] / src / fg_callback_macros.h
1 /*
2  * fg_callback_macros.h
3  *
4  * The freeglut library callback macro file.
5  *
6  * Copyright (C) 2016 Vincent Simonetti
7  * Creation date: Sat Jan 16 2016
8  *
9  * Permission is hereby granted, free of charge, to any person obtaining a
10  * copy of this software and associated documentation files (the "Software"),
11  * to deal in the Software without restriction, including without limitation
12  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13  * and/or sell copies of the Software, and to permit persons to whom the
14  * Software is furnished to do so, subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice shall be included
17  * in all copies or substantial portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
22  * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
23  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25  */
26
27 #ifndef FREEGLUT_CALLBACK_MACROS_H
28 #define FREEGLUT_CALLBACK_MACROS_H
29
30 /*
31  * ----------------------------------------------------------------------------------------------------------------------
32  * There are two sets of macros here. One is for executing window callbacks, the others are for setting window callbacks.
33  * ----------------------------------------------------------------------------------------------------------------------
34  */
35
36 /*
37  * Compiler define: FG_COMPILER_SUPPORTS_VA_ARGS: if the compiler supports variadic macros
38  */
39
40 /* What supports variadic macros based off Wikipedia article on it (GCC-like must support C99 or higher to use variadic macros) */
41 #if (((defined(__GNUC__) && (__GNUC__ >= 3)) || \
42       (defined(__clang__))) && \
43         (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L))) || \
44     (defined(_MSC_VER) && (_MSC_VER >= 1400)) || \
45     (defined(__BORLANDC__) && (__BORLANDC__ >= 0x570)) || \
46     (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x530))
47 #define FG_COMPILER_SUPPORTS_VA_ARGS 1
48 #else
49 #define FG_COMPILER_SUPPORTS_VA_ARGS 0
50 #endif
51
52 /*
53  * --------------------------
54  * Executing window callbacks
55  * --------------------------
56  *
57  * Info:
58  *
59  * This took a while to figure out, so be sure try to understand what is happening so that you can ensure that whatever you
60  * change won't break other areas.
61  *
62  * If you are just adding a new callback/changing it's argument count, just go to the bottom of the file.
63  *
64  * This whole file exists purely for the sake of preventing the need to implement additional parsing logic for each callback
65  * to pass user arguments. Of course, the necessity to support older compilers means that, as seen in the line above, there
66  * is still a requirement to add/modify code to handle callbacks. If freeglut ever requires newer compilers (at minimum, ones
67  * that support C99 or higher), code can very slowly be removed from this file. Even better would be if the C standard eventually
68  * supports something similar to what GCC has implemented or offers an alternative. Another option is if C++ would be "allowed" by
69  * project maintaners, as then templates can be used and function overloading. Ironically, the template would probably look worse
70  * then the GCC macro, so maybe it's good to stay as is.
71  *
72  * Onto the different "versions" of macros:
73  *
74  * The first is for any compiler that supports C99 by default. It requires each callback to have a specific argument count
75  * passthrough macro. The only reason there are specific count macros is so that (see paraghraph below) don't need have their own
76  * set of callback macros. Ideally, there would only be ZERO and ONE_OR_MORE. This works by having callback-specific macros call a
77  * specific handler macro to return user data (ZERO) or return one or more arguments along with userData (ONE_OR_MORE) where, with
78  * variadic macros, it just reuses the arguments.
79  *
80  * The last macro set is for the poor individual who has to use a compiler that doesn't support C99 by default, or may not support
81  * it at all. Stuff like MSVC6... It works by having a specific-count macro that "extracts" each argument to have them reused without
82  * the parathesis.
83  *
84  * There is a 3rd macro set that only worked on GCC/Clang, and thus was removed (last seen in revision e9676fc of the GIT mirror.
85  * Not sure at this time what the SVN number is.) as it's a non-standard functionality.
86  */
87
88 /*
89  * EXPAND_WCB() is used as:
90  *
91  *     EXPAND_WCB( cbname )(( arg_list, userData ))
92  *
93  * ... where {(arg_list)} is the parameter list and userData is user
94  * provided data.
95  *
96  * This will take the arg_list and extend it by one argument, adding
97  * the argument "userData" to the end of the list.
98  *
99  * In order for this to work, each callback must have a define that
100  * properly handles the arguments as needed by the callback.
101  * This callback is in the format of EXPAND_WCB_SUB_<cbname>.
102  * Helper functions exist for zero to five parameters: EXPAND_WCB_ZERO,
103  * EXPAND_WCB_ONE, EXPAND_WCB_TWO, EXPAND_WCB_THREE< EXPAND_WCB_FOUR,
104  * and EXPAND_WCB_FIVE. Each handle the callback argument counts.
105  *
106  * An example for the "Entry" callback, where "Entry" is the cbname:
107  * typedef void (* FGCBEntry  )( int );
108  * typedef void (* FGCBEntryUC)( int, FGCBUserData );
109  * #define EXPAND_WCB_SUB_Entry(args) EXPAND_WCB_ONE args
110  */
111
112 #if FG_COMPILER_SUPPORTS_VA_ARGS
113
114 #define EXPAND_WCB_UNPARAN(...) __VA_ARGS__
115 #define EXPAND_WCB_ONE_OR_MORE(args, userData) ( EXPAND_WCB_UNPARAN args, userData )
116
117 #define EXPAND_WCB_ONE(args, userData) EXPAND_WCB_ONE_OR_MORE( args, userData )
118 #define EXPAND_WCB_TWO(args, userData) EXPAND_WCB_ONE_OR_MORE( args, userData )
119 #define EXPAND_WCB_THREE(args, userData) EXPAND_WCB_ONE_OR_MORE( args, userData )
120 #define EXPAND_WCB_FOUR(args, userData) EXPAND_WCB_ONE_OR_MORE( args, userData )
121 #define EXPAND_WCB_FIVE(args, userData) EXPAND_WCB_ONE_OR_MORE( args, userData )
122
123 #else
124
125 #define EXPAND_WCB_EXTRACT_ONE_ARGS(arg1) arg1
126 #define EXPAND_WCB_EXTRACT_TWO_ARGS(arg1, arg2) arg1, arg2
127 #define EXPAND_WCB_EXTRACT_THREE_ARGS(arg1, arg2, arg3) arg1, arg2, arg3
128 #define EXPAND_WCB_EXTRACT_FOUR_ARGS(arg1, arg2, arg3, arg4) arg1, arg2, arg3, arg4
129 #define EXPAND_WCB_EXTRACT_FIVE_ARGS(arg1, arg2, arg3, arg4, arg5) arg1, arg2, arg3, arg4, arg5
130
131 #define EXPAND_WCB_ONE(args, userData) (EXPAND_WCB_EXTRACT_ONE_ARGS args, userData)
132 #define EXPAND_WCB_TWO(args, userData) (EXPAND_WCB_EXTRACT_TWO_ARGS args, userData)
133 #define EXPAND_WCB_THREE(args, userData) (EXPAND_WCB_EXTRACT_THREE_ARGS args, userData)
134 #define EXPAND_WCB_FOUR(args, userData) (EXPAND_WCB_EXTRACT_FOUR_ARGS args, userData)
135 #define EXPAND_WCB_FIVE(args, userData) (EXPAND_WCB_EXTRACT_FIVE_ARGS args, userData)
136
137 #endif
138
139 #define EXPAND_WCB_ZERO(args, userData) ( userData )
140
141 #define EXPAND_WCB(cbname) EXPAND_WCB_SUB_ ## cbname
142
143 /*
144  * Freeglut callbacks type definitions macros
145  *
146  * Every time a callback is updated in fg_internal.h is updated, this needs updated
147  * if argument counts change, new callbacks are added, or callbacks are removed.
148  */
149
150 #define EXPAND_WCB_SUB_Display(args) EXPAND_WCB_ZERO args
151 #define EXPAND_WCB_SUB_Reshape(args) EXPAND_WCB_TWO args
152 #define EXPAND_WCB_SUB_Position(args) EXPAND_WCB_TWO args
153 #define EXPAND_WCB_SUB_Visibility(args) EXPAND_WCB_ONE args
154 #define EXPAND_WCB_SUB_Keyboard(args) EXPAND_WCB_THREE args
155 #define EXPAND_WCB_SUB_KeyboardUp(args) EXPAND_WCB_THREE args
156 #define EXPAND_WCB_SUB_Special(args) EXPAND_WCB_THREE args
157 #define EXPAND_WCB_SUB_SpecialUp(args) EXPAND_WCB_THREE args
158 #define EXPAND_WCB_SUB_Mouse(args) EXPAND_WCB_FOUR args
159 #define EXPAND_WCB_SUB_MouseWheel(args) EXPAND_WCB_FOUR args
160 #define EXPAND_WCB_SUB_Motion(args) EXPAND_WCB_TWO args
161 #define EXPAND_WCB_SUB_Passive(args) EXPAND_WCB_TWO args
162 #define EXPAND_WCB_SUB_Entry(args) EXPAND_WCB_ONE args
163 #define EXPAND_WCB_SUB_WindowStatus(args) EXPAND_WCB_ONE args
164 #define EXPAND_WCB_SUB_Joystick(args) EXPAND_WCB_FOUR args
165 #define EXPAND_WCB_SUB_OverlayDisplay(args) EXPAND_WCB_ZERO args
166 #define EXPAND_WCB_SUB_SpaceMotion(args) EXPAND_WCB_THREE args
167 #define EXPAND_WCB_SUB_SpaceRotation(args) EXPAND_WCB_THREE args
168 #define EXPAND_WCB_SUB_SpaceButton(args) EXPAND_WCB_TWO args
169 #define EXPAND_WCB_SUB_Dials(args) EXPAND_WCB_TWO args
170 #define EXPAND_WCB_SUB_ButtonBox(args) EXPAND_WCB_TWO args
171 #define EXPAND_WCB_SUB_TabletMotion(args) EXPAND_WCB_TWO args
172 #define EXPAND_WCB_SUB_TabletButton(args) EXPAND_WCB_FOUR args
173 #define EXPAND_WCB_SUB_Destroy(args) EXPAND_WCB_ZERO args
174 #define EXPAND_WCB_SUB_MultiEntry(args) EXPAND_WCB_TWO args
175 #define EXPAND_WCB_SUB_MultiButton(args) EXPAND_WCB_FIVE args
176 #define EXPAND_WCB_SUB_MultiMotion(args) EXPAND_WCB_THREE args
177 #define EXPAND_WCB_SUB_MultiPassive(args) EXPAND_WCB_THREE args
178 #define EXPAND_WCB_SUB_InitContext(args) EXPAND_WCB_ZERO args
179 #define EXPAND_WCB_SUB_AppStatus(args) EXPAND_WCB_ONE args
180
181 /*
182  * ------------------------
183  * Setting window callbacks
184  * ------------------------
185  *
186  * These originally existed in fg_callbacks.c
187  */
188
189 /*
190  * All of the window-specific callbacks setting methods can be generalized to this:
191  */
192 #define SET_CURRENT_WINDOW_CALLBACK(a)                                    \
193 do                                                                        \
194 {                                                                         \
195     if( fgStructure.CurrentWindow == NULL )                               \
196         return;                                                           \
197     SET_WCB( ( *( fgStructure.CurrentWindow ) ), a, callback, userData ); \
198 } while( 0 )
199
200 /*
201  * Types need to be defined for callbacks. It's not ideal, but it works for this.
202  */
203 #define IMPLEMENT_CALLBACK_FUNC_CB_ARG0(a,b)                              \
204 static void fgh##a##FuncCallback( FGCBUserData userData )                 \
205 {                                                                         \
206     FGCB##b* callback = (FGCB##b*)&userData;                              \
207     (*callback)();                                                        \
208 }
209 #define IMPLEMENT_CALLBACK_FUNC_CB_ARG1(a,b)                              \
210 static void fgh##a##FuncCallback( int arg1val, FGCBUserData userData )    \
211 {                                                                         \
212     FGCB##b* callback = (FGCB##b*)&userData;                              \
213     (*callback)( arg1val );                                               \
214 }
215 #define IMPLEMENT_CALLBACK_FUNC_CB_ARG2(a,b)                              \
216 static void fgh##a##FuncCallback( int arg1val, int arg2val, FGCBUserData userData ) \
217 {                                                                         \
218     FGCB##b* callback = (FGCB##b*)&userData;                              \
219     (*callback)( arg1val, arg2val );                                      \
220 }
221 #define IMPLEMENT_CALLBACK_FUNC_CB_ARG3_USER(a,b,arg1,arg2,arg3)          \
222 static void fgh##a##FuncCallback( arg1 arg1val, arg2 arg2val, arg3 arg3val, FGCBUserData userData ) \
223 {                                                                         \
224     FGCB##b* callback = (FGCB##b*)&userData;                              \
225     (*callback)( arg1val, arg2val, arg3val );                             \
226 }
227 #define IMPLEMENT_CALLBACK_FUNC_CB_ARG3(a,b) IMPLEMENT_CALLBACK_FUNC_CB_ARG3_USER(a,b,int,int,int)
228 #define IMPLEMENT_CALLBACK_FUNC_CB_ARG4(a,b)                              \
229 static void fgh##a##FuncCallback( int arg1val, int arg2val, int arg3val, int arg4val, FGCBUserData userData ) \
230 {                                                                         \
231     FGCB##b* callback = (FGCB##b*)&userData;                              \
232     (*callback)( arg1val, arg2val, arg3val, arg4val );                    \
233 }
234 #define IMPLEMENT_CALLBACK_FUNC_CB_ARG5(a,b)                              \
235 static void fgh##a##FuncCallback( int arg1val, int arg2val, int arg3val, int arg4val, int arg5val, FGCBUserData userData ) \
236 {                                                                         \
237     FGCB##b* callback = (FGCB##b*)&userData;                              \
238     (*callback)( arg1val, arg2val, arg3val, arg4val, arg5val );           \
239 }
240
241 /*
242  * And almost every time the callback setter function can be implemented with these:
243  */
244 #define IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT_UCALL(a,b)      \
245 void FGAPIENTRY glut##a##FuncUcall( FGCB##b##UC callback, FGCBUserData userData ) \
246 {                                                                         \
247     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glut"#a"FuncUcall" );             \
248     SET_CURRENT_WINDOW_CALLBACK( b );                                     \
249 }
250 #define IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT_BASE(a,b)                      \
251 void FGAPIENTRY glut##a##Func( FGCB##b callback )                         \
252 {                                                                         \
253     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glut"#a"Func" );                  \
254     if( callback )                                                        \
255     {                                                                     \
256         FGCB##b* reference = &callback;                                   \
257         glut##a##FuncUcall( fgh##a##FuncCallback, *((FGCBUserData*)reference) ); \
258     }                                                                     \
259     else                                                                  \
260         glut##a##FuncUcall( NULL, NULL );                                 \
261 }
262
263 #define IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT(a,b)            \
264         IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT_UCALL(a,b)      \
265         IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT_BASE(a,b)
266
267 /*
268  * Combine _glut and _cb macros:
269  */
270 #define IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG0(a)                     \
271         IMPLEMENT_CALLBACK_FUNC_CB_ARG0(a,a)                               \
272         IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT(a,a)
273
274 #define IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG0_2NAME(a,b)             \
275         IMPLEMENT_CALLBACK_FUNC_CB_ARG0(a,b)                               \
276         IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT(a,b)
277
278 #define IMPLEMENT_GLUT_CALLBACK_FUNC_ARG0(a)                               \
279         IMPLEMENT_CALLBACK_FUNC_CB_ARG0(a,a)                               \
280         IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT_BASE(a,a)
281
282 #define IMPLEMENT_GLUT_CALLBACK_FUNC_ARG0_2NAME(a,b)                       \
283         IMPLEMENT_CALLBACK_FUNC_CB_ARG0(a,b)                               \
284         IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT_BASE(a,b)
285
286 #define IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG1(a)                     \
287         IMPLEMENT_CALLBACK_FUNC_CB_ARG1(a,a)                               \
288         IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT(a,a)
289
290 #define IMPLEMENT_GLUT_CALLBACK_FUNC_ARG1(a)                               \
291         IMPLEMENT_CALLBACK_FUNC_CB_ARG1(a,a)                               \
292         IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT_BASE(a,a)
293
294 #define IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG2(a)                     \
295         IMPLEMENT_CALLBACK_FUNC_CB_ARG2(a,a)                               \
296         IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT(a,a)
297
298 #define IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG2_2NAME(a,b)             \
299         IMPLEMENT_CALLBACK_FUNC_CB_ARG2(a,b)                               \
300         IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT(a,b)
301
302 #define IMPLEMENT_GLUT_CALLBACK_FUNC_ARG2(a)                               \
303         IMPLEMENT_CALLBACK_FUNC_CB_ARG2(a,a)                               \
304         IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT_BASE(a,a)
305
306 #define IMPLEMENT_GLUT_CALLBACK_FUNC_ARG2_2NAME(a,b)                       \
307         IMPLEMENT_CALLBACK_FUNC_CB_ARG2(a,b)                               \
308         IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT_BASE(a,b)
309
310 #define IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG3(a)                     \
311         IMPLEMENT_CALLBACK_FUNC_CB_ARG3(a,a)                               \
312         IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT(a,a)
313
314 #define IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG3_USER(a,arg1,arg2,arg3) \
315         IMPLEMENT_CALLBACK_FUNC_CB_ARG3_USER(a,a,arg1,arg2,arg3)           \
316         IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT(a,a)
317
318 #define IMPLEMENT_GLUT_CALLBACK_FUNC_ARG3(a)                               \
319         IMPLEMENT_CALLBACK_FUNC_CB_ARG3(a,a)                               \
320         IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT_BASE(a,a)
321
322 #define IMPLEMENT_GLUT_CALLBACK_FUNC_ARG3_2NAME(a,b)                       \
323         IMPLEMENT_CALLBACK_FUNC_CB_ARG3(a,b)                               \
324         IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT_BASE(a,b)
325
326 #define IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG4(a)                     \
327         IMPLEMENT_CALLBACK_FUNC_CB_ARG4(a,a)                               \
328         IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT(a,a)
329
330 #define IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG5(a)                     \
331         IMPLEMENT_CALLBACK_FUNC_CB_ARG5(a,a)                               \
332         IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT(a,a)
333
334 #endif /* FREEGLUT_CALLBACK_MACROS_H */
335
336 /*** END OF FILE ***/