Moved as many callback setters as possible to macro function generators
[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 defines:
38  * FG_COMPILER_SUPPORTS_GCC_VA_ARGS_HACK: if the compiler supports GCC's variadic macro implementation (AKA, ##__VA_ARGS__)
39  * FG_COMPILER_SUPPORTS_VA_ARGS: if the compiler supports variadic macros
40  */
41
42 /* What supports variadic macros based off Wikipedia article on it (GCC-like must support C99 or higher to use variadic macros) */
43 #if (((defined(__GNUC__) && (__GNUC__ >= 3)) || \
44           (defined(__clang__))) && \
45                 (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L))) || \
46         (defined(_MSC_VER) && (_MSC_VER >= 1400)) || \
47         (defined(__BORLANDC__) && (__BORLANDC__ >= 0x570)) || \
48         (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x530))
49 #define FG_COMPILER_SUPPORTS_VA_ARGS 1
50 #else
51 #define FG_COMPILER_SUPPORTS_VA_ARGS 0
52 #endif
53
54 /* If __VA_ARGS__ is supported, it needs to be GCC(-like) or Clang (since Clang mimics GCC) */
55 #if FG_COMPILER_SUPPORTS_VA_ARGS && \
56         (defined(__GNUC__)) || \
57         (defined(__clang__))
58 #define FG_COMPILER_SUPPORTS_GCC_VA_ARGS_HACK 1
59 #else
60 #define FG_COMPILER_SUPPORTS_GCC_VA_ARGS_HACK 0
61 #endif
62
63 /*
64  * --------------------------
65  * Executing window callbacks
66  * --------------------------
67  *
68  * Info:
69  *
70  * This took a while to figure out, so be sure try to understand what is happening so that you can ensure that whatever you
71  * change won't break other areas.
72  * 
73  * If you are just adding a new callback/changing it's argument count, just go to the bottom of the file.
74  *
75  * This whole file exists purely for the sake of preventing the need to implement additional parsing logic for each callback
76  * to pass user arguments. Of course, the necessity to support older compilers means that, as seen in the line above, there
77  * is still a requirement to add/modify code to handle callbacks. If freeglut ever requires newer compilers (at minimum, ones
78  * that support C99 or higher), code can very slowly be removed from this file. Even better would be if the C standard eventually
79  * supports something similar to what GCC has implemented or offers an alternative. Another option is if C++ would be "allowed" by
80  * project maintaners, as then templates can be used and function overloading. Ironically, the template would probably look worse
81  * then the GCC macro, so maybe it's good to stay as is.
82  *
83  * Onto the different "versions" of macros:
84  * 
85  * There is one for GCC/Clang(/and supposedly the Intel compiler) which supports the non-standard ##__VA_ARGS__ token. The code may 
86  * look ugly, but the result is, if this was standard, no one would ever need to open this file unless they were curious (or needed 
87  * more then 5 arguments for a callback, but that's trivial to add). It works by adding many fake macros to a "picker" macro
88  * (PP_HAS_ARGS_IMPL2) which then indictaes which macro counter to use. As we can already use variadic macros (the VA in __VA_ARGS__),
89  * this just becomes a "reuse the arguments*.
90  * 
91  * The next is for any non-GCC/Clang/etc. compiler *cough* MSVC/compiler you probably shouldn't be using *cough* that supports C99
92  * by default. It requires each callback to have a specific argument count passthrough macro. The only reason there are specific
93  * count macros is so that (see paraghraph below) don't need have their own set of callback macros. Ideally, there would only be
94  * ZERO and ONE_OR_MORE. This works by having callback-specific macros call a specific handler macro to return user data (ZERO) or
95  * return one or more arguments along with userData (ONE_OR_MORE) where, with variadic macros, it just reuses the arguments.
96  *
97  * The last set is for the poor individual who has to use a compiler that doesn't support C99 by default, or may not support it at
98  * all. Stuff like MSVC6... It works by having a specific-count macro that "extracts" each argument to have them reused without the
99  * parathesis.
100  *
101  * A note on parathesis, as earlier mentioned, if the GCC variadic macro element was standard, then instead of needing:
102  *
103  * func EXPAND_WCB(Mouse)(( (GLUT_LEFT_BUTTON, GLUT_DOWN, 10, 30), userData));
104  *
105  * ...you can do the following:
106  *
107  * func EXPAND_WCB (GLUT_LEFT_BUTTON, GLUT_DOWN, 10, 30);
108  *
109  * Wow... so much nice and easier to understand. Sub-note: I have not worked on a version that explicitly takes userData, so for now
110  * if you can get to that version, look in the version control change history for this file and you'll find that version which
111  * implicitly passes "userData" and only works on GCC vardiac macro supporting compilers.
112  */
113
114 #if FG_COMPILER_SUPPORTS_GCC_VA_ARGS_HACK
115
116  /*
117  * EXPAND_WCB() is used as:
118  * 
119  *     EXPAND_WCB( cbname )(( arg_list, userData ))
120  * 
121  * ... where {(arg_list)} is the parameter list and userData is user
122  * provided data.
123  *
124  * All additional macros are to get around trailing ',' for zero-arg
125  * callbacks.
126  *
127  * Modification of:
128  * http://stackoverflow.com/questions/5355241/generating-function-declaration-using-a-macro-iteration/5355946#5355946
129  *
130  * --------------
131  *
132  * GCC-specific design that doesn't require per-callback defines
133  *
134  * The naming is terrible... and it's very convuluted and complex, but
135  * should not require any modification unless additional arguments are to 
136  * be supported.
137  * 
138  * Supports callbacks up to 5 args (follow the pattern of 
139  * EXPAND_WCB_PP_HAS_ARGS_IMPL2 and EXPAND_WCB_PP_HAS_ARGS_SOURCE to add more)
140  *
141  * Edit with care.
142  */
143
144 #define EXPAND_WCB_UNPARAN(...) __VA_ARGS__
145
146 #define EXPAND_WCB_PP_HAS_ARGS_IMPL2(_0, _1, _2, _3, _4, _5, N, ...) N
147 #define EXPAND_WCB_PP_HAS_ARGS_SOURCE() ONE_OR_MORE, ONE_OR_MORE, ONE_OR_MORE, ONE_OR_MORE, ONE_OR_MORE, ZERO
148
149 #define EXPAND_WCB_PP_HAS_ARGS_IMPL(...) EXPAND_WCB_PP_HAS_ARGS_IMPL2( __VA_ARGS__ )
150 #define EXPAND_WCB_PP_HAS_ARGS(...) EXPAND_WCB_PP_HAS_ARGS_IMPL( NOT_EXIST, ##__VA_ARGS__, EXPAND_WCB_PP_HAS_ARGS_SOURCE() )
151
152 #define EXPAND_WCB_ZERO(args, userData) ( userData )
153 #define EXPAND_WCB_ONE_OR_MORE(args, userData) ( EXPAND_WCB_UNPARAN args, userData )
154
155 #define EXPAND_WCB_DISAMBIGUATE2(has_args, args, userData) EXPAND_WCB_ ## has_args ( args, userData )
156 #define EXPAND_WCB_DISAMBIGUATE(has_args, args, userData) EXPAND_WCB_DISAMBIGUATE2( has_args, args, userData )
157
158 #define EXPAND_WCB_UNWRAP_ARGS2(args, userData) EXPAND_WCB_DISAMBIGUATE( EXPAND_WCB_PP_HAS_ARGS args, args, userData )
159 #define EXPAND_WCB_UNWRAP_ARGS(args) EXPAND_WCB_UNWRAP_ARGS2 args
160
161 #define EXPAND_WCB(cbname) EXPAND_WCB_UNWRAP_ARGS
162
163 #else
164
165 /*
166  * EXPAND_WCB() is used as:
167  * 
168  *     EXPAND_WCB( cbname )(( arg_list, userData ))
169  * 
170  * ... where {(arg_list)} is the parameter list and userData is user
171  * provided data.
172  *
173  * This will take the arg_list and extend it by one argument, adding
174  * the argument "userData" to the end of the list.
175  *
176  * In order for this to work, each callback must have a define that
177  * properly handles the arguments as needed by the callback.
178  * This callback is in the format of EXPAND_WCB_SUB_<cbname>.
179  * Helper functions exist for zero to five parameters: EXPAND_WCB_ZERO,
180  * EXPAND_WCB_ONE, EXPAND_WCB_TWO, EXPAND_WCB_THREE< EXPAND_WCB_FOUR,
181  * and EXPAND_WCB_FIVE. Each handle the callback argument counts.
182  *
183  * An example for the "Entry" callback, where "Entry" is the cbname:
184  * typedef void (* FGCBEntry  )( int );
185  * typedef void (* FGCBEntryUC)( int, FGCBUserData );
186  * #define EXPAND_WCB_SUB_Entry(args) EXPAND_WCB_ONE args
187  */
188
189 #if FG_COMPILER_SUPPORTS_VA_ARGS
190
191 #define EXPAND_WCB_UNPARAN(...) __VA_ARGS__
192 #define EXPAND_WCB_ONE_OR_MORE(args, userData) ( EXPAND_WCB_UNPARAN args, userData )
193
194 #define EXPAND_WCB_ONE(args, userData) EXPAND_WCB_ONE_OR_MORE( args, userData )
195 #define EXPAND_WCB_TWO(args, userData) EXPAND_WCB_ONE_OR_MORE( args, userData )
196 #define EXPAND_WCB_THREE(args, userData) EXPAND_WCB_ONE_OR_MORE( args, userData )
197 #define EXPAND_WCB_FOUR(args, userData) EXPAND_WCB_ONE_OR_MORE( args, userData )
198 #define EXPAND_WCB_FIVE(args, userData) EXPAND_WCB_ONE_OR_MORE( args, userData )
199
200 #else
201
202 #define EXPAND_WCB_EXTRACT_ONE_ARGS(arg1) arg1
203 #define EXPAND_WCB_EXTRACT_TWO_ARGS(arg1, arg2) arg1, arg2
204 #define EXPAND_WCB_EXTRACT_THREE_ARGS(arg1, arg2, arg3) arg1, arg2, arg3
205 #define EXPAND_WCB_EXTRACT_FOUR_ARGS(arg1, arg2, arg3, arg4) arg1, arg2, arg3, arg4
206 #define EXPAND_WCB_EXTRACT_FIVE_ARGS(arg1, arg2, arg3, arg4, arg5) arg1, arg2, arg3, arg4, arg5
207
208 #define EXPAND_WCB_ONE(args, userData) (EXPAND_WCB_EXTRACT_ONE_ARGS args, userData)
209 #define EXPAND_WCB_TWO(args, userData) (EXPAND_WCB_EXTRACT_TWO_ARGS args, userData)
210 #define EXPAND_WCB_THREE(args, userData) (EXPAND_WCB_EXTRACT_THREE_ARGS args, userData)
211 #define EXPAND_WCB_FOUR(args, userData) (EXPAND_WCB_EXTRACT_FOUR_ARGS args, userData)
212 #define EXPAND_WCB_FIVE(args, userData) (EXPAND_WCB_EXTRACT_FIVE_ARGS args, userData)
213
214 #endif
215
216 #define EXPAND_WCB_ZERO(args, userData) ( userData )
217
218 #define EXPAND_WCB(cbname) EXPAND_WCB_SUB_ ## cbname
219
220 /* 
221  * Freeglut callbacks type definitions macros
222  *
223  * Every time a callback is updated in fg_internal.h is updated, this needs updated
224  * if argument counts change, new callbacks are added, or callbacks are removed.
225  */
226
227 #define EXPAND_WCB_SUB_Display(args) EXPAND_WCB_ZERO args
228 #define EXPAND_WCB_SUB_Reshape(args) EXPAND_WCB_TWO args
229 #define EXPAND_WCB_SUB_Position(args) EXPAND_WCB_TWO args
230 #define EXPAND_WCB_SUB_Visibility(args) EXPAND_WCB_ONE args
231 #define EXPAND_WCB_SUB_Keyboard(args) EXPAND_WCB_THREE args
232 #define EXPAND_WCB_SUB_KeyboardUp(args) EXPAND_WCB_THREE args
233 #define EXPAND_WCB_SUB_Special(args) EXPAND_WCB_THREE args
234 #define EXPAND_WCB_SUB_SpecialUp(args) EXPAND_WCB_THREE args
235 #define EXPAND_WCB_SUB_Mouse(args) EXPAND_WCB_FOUR args
236 #define EXPAND_WCB_SUB_MouseWheel(args) EXPAND_WCB_FOUR args
237 #define EXPAND_WCB_SUB_Motion(args) EXPAND_WCB_TWO args
238 #define EXPAND_WCB_SUB_Passive(args) EXPAND_WCB_TWO args
239 #define EXPAND_WCB_SUB_Entry(args) EXPAND_WCB_ONE args
240 #define EXPAND_WCB_SUB_WindowStatus(args) EXPAND_WCB_ONE args
241 #define EXPAND_WCB_SUB_Joystick(args) EXPAND_WCB_FOUR args
242 #define EXPAND_WCB_SUB_OverlayDisplay(args) EXPAND_WCB_ZERO args
243 #define EXPAND_WCB_SUB_SpaceMotion(args) EXPAND_WCB_THREE args
244 #define EXPAND_WCB_SUB_SpaceRotation(args) EXPAND_WCB_THREE args
245 #define EXPAND_WCB_SUB_SpaceButton(args) EXPAND_WCB_TWO args
246 #define EXPAND_WCB_SUB_Dials(args) EXPAND_WCB_TWO args
247 #define EXPAND_WCB_SUB_ButtonBox(args) EXPAND_WCB_TWO args
248 #define EXPAND_WCB_SUB_TabletMotion(args) EXPAND_WCB_TWO args
249 #define EXPAND_WCB_SUB_TabletButton(args) EXPAND_WCB_FOUR args
250 #define EXPAND_WCB_SUB_Destroy(args) EXPAND_WCB_ZERO args
251 #define EXPAND_WCB_SUB_MultiEntry(args) EXPAND_WCB_TWO args
252 #define EXPAND_WCB_SUB_MultiButton(args) EXPAND_WCB_FIVE args
253 #define EXPAND_WCB_SUB_MultiMotion(args) EXPAND_WCB_THREE args
254 #define EXPAND_WCB_SUB_MultiPassive(args) EXPAND_WCB_THREE args
255 #define EXPAND_WCB_SUB_InitContext(args) EXPAND_WCB_ZERO args
256 #define EXPAND_WCB_SUB_AppStatus(args) EXPAND_WCB_ONE args
257
258 #endif
259
260 /*
261  * ------------------------
262  * Setting window callbacks
263  * ------------------------
264  *
265  * These originally existed in fg_callbacks.c
266  */
267
268 /*
269  * All of the window-specific callbacks setting methods can be generalized to this:
270  */
271 #define SET_CURRENT_WINDOW_CALLBACK(a)                                    \
272 do                                                                        \
273 {                                                                         \
274     if( fgStructure.CurrentWindow == NULL )                               \
275         return;                                                           \
276     SET_WCB( ( *( fgStructure.CurrentWindow ) ), a, callback, userData ); \
277 } while( 0 )
278
279 /*
280  * Types need to be defined for callbacks. It's not ideal, but it works for this.
281  */
282 #define IMPLEMENT_CALLBACK_FUNC_CB_ARG0(a,b)                              \
283 static void fgh##a##FuncCallback( FGCBUserData userData )                 \
284 {                                                                         \
285     FGCB##b callback = (FGCB##b)userData;                                 \
286     callback();                                                           \
287 }
288 #define IMPLEMENT_CALLBACK_FUNC_CB_ARG1(a,b)                              \
289 static void fgh##a##FuncCallback( int arg1val, FGCBUserData userData )    \
290 {                                                                         \
291     FGCB##b callback = (FGCB##b)userData;                                 \
292     callback( arg1val );                                                  \
293 }
294 #define IMPLEMENT_CALLBACK_FUNC_CB_ARG2(a,b)                              \
295 static void fgh##a##FuncCallback( int arg1val, int arg2val, FGCBUserData userData ) \
296 {                                                                         \
297     FGCB##b callback = (FGCB##b)userData;                                 \
298     callback( arg1val, arg2val );                                         \
299 }
300 #define IMPLEMENT_CALLBACK_FUNC_CB_ARG3_USER(a,b,arg1,arg2,arg3)          \
301 static void fgh##a##FuncCallback( arg1 arg1val, arg2 arg2val, arg3 arg3val, FGCBUserData userData ) \
302 {                                                                         \
303     FGCB##b callback = (FGCB##b)userData;                                 \
304     callback( arg1val, arg2val, arg3val );                                \
305 }
306 #define IMPLEMENT_CALLBACK_FUNC_CB_ARG3(a,b) IMPLEMENT_CALLBACK_FUNC_CB_ARG3_USER(a,b,int,int,int)
307 #define IMPLEMENT_CALLBACK_FUNC_CB_ARG4(a,b)                              \
308 static void fgh##a##FuncCallback( int arg1val, int arg2val, int arg3val, int arg4val, FGCBUserData userData ) \
309 {                                                                         \
310     FGCB##b callback = (FGCB##b)userData;                                 \
311     callback( arg1val, arg2val, arg3val, arg4val );                       \
312 }
313 #define IMPLEMENT_CALLBACK_FUNC_CB_ARG5(a,b)                              \
314 static void fgh##a##FuncCallback( int arg1val, int arg2val, int arg3val, int arg4val, int arg5val, FGCBUserData userData ) \
315 {                                                                         \
316     FGCB##b callback = (FGCB##b)userData;                                 \
317     callback( arg1val, arg2val, arg3val, arg4val, arg5val );              \
318 }
319
320 /*
321  * And almost every time the callback setter function can be implemented with these:
322  */
323 #define IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT_UCALL(a,b)      \
324 void FGAPIENTRY glut##a##FuncUcall( FGCB##b##UC callback, FGCBUserData userData ) \
325 {                                                                         \
326     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glut"#a"FuncUcall" );             \
327     SET_CURRENT_WINDOW_CALLBACK( b );                                     \
328 }
329 #define IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT_BASE(a,b)                      \
330 void FGAPIENTRY glut##a##Func( FGCB##b callback )                         \
331 {                                                                         \
332     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glut"#a"Func" );                  \
333     if( callback )                                                        \
334         glut##a##FuncUcall( fgh##a##FuncCallback, (FGCBUserData)callback ); \
335     else                                                                  \
336         glut##a##FuncUcall( NULL, NULL );                                 \
337 }
338
339 #define IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT(a,b)            \
340                 IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT_UCALL(a,b)      \
341                 IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT_BASE(a,b)
342
343 /*
344  * Combine _glut and _cb macros:
345  */
346 #define IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG0(a)                     \
347         IMPLEMENT_CALLBACK_FUNC_CB_ARG0(a,a)                               \
348         IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT(a,a)
349
350 #define IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG0_2NAME(a,b)             \
351         IMPLEMENT_CALLBACK_FUNC_CB_ARG0(a,b)                               \
352         IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT(a,b)
353
354 #define IMPLEMENT_GLUT_CALLBACK_FUNC_ARG0(a)                               \
355                 IMPLEMENT_CALLBACK_FUNC_CB_ARG0(a,a)                               \
356                 IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT_BASE(a,a)
357
358 #define IMPLEMENT_GLUT_CALLBACK_FUNC_ARG0_2NAME(a,b)                       \
359                 IMPLEMENT_CALLBACK_FUNC_CB_ARG0(a,b)                               \
360                 IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT_BASE(a,b)
361
362 #define IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG1(a)                     \
363         IMPLEMENT_CALLBACK_FUNC_CB_ARG1(a,a)                               \
364         IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT(a,a)
365
366 #define IMPLEMENT_GLUT_CALLBACK_FUNC_ARG1(a)                               \
367                 IMPLEMENT_CALLBACK_FUNC_CB_ARG1(a,a)                               \
368                 IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT_BASE(a,a)
369
370 #define IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG2(a)                     \
371         IMPLEMENT_CALLBACK_FUNC_CB_ARG2(a,a)                               \
372         IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT(a,a)
373
374 #define IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG2_2NAME(a,b)             \
375         IMPLEMENT_CALLBACK_FUNC_CB_ARG2(a,b)                               \
376         IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT(a,b)
377
378 #define IMPLEMENT_GLUT_CALLBACK_FUNC_ARG2(a)                               \
379                 IMPLEMENT_CALLBACK_FUNC_CB_ARG2(a,a)                               \
380                 IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT_BASE(a,a)
381
382 #define IMPLEMENT_GLUT_CALLBACK_FUNC_ARG2_2NAME(a,b)                       \
383                 IMPLEMENT_CALLBACK_FUNC_CB_ARG2(a,b)                               \
384                 IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT_BASE(a,b)
385
386 #define IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG3(a)                     \
387         IMPLEMENT_CALLBACK_FUNC_CB_ARG3(a,a)                               \
388         IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT(a,a)
389
390 #define IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG3_USER(a,arg1,arg2,arg3) \
391         IMPLEMENT_CALLBACK_FUNC_CB_ARG3_USER(a,a,arg1,arg2,arg3)           \
392         IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT(a,a)
393
394 #define IMPLEMENT_GLUT_CALLBACK_FUNC_ARG3(a)                               \
395                 IMPLEMENT_CALLBACK_FUNC_CB_ARG3(a,a)                               \
396                 IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT_BASE(a,a)
397
398 #define IMPLEMENT_GLUT_CALLBACK_FUNC_ARG3_2NAME(a,b)                       \
399                 IMPLEMENT_CALLBACK_FUNC_CB_ARG3(a,b)                               \
400                 IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT_BASE(a,b)
401
402 #define IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG4(a)                     \
403         IMPLEMENT_CALLBACK_FUNC_CB_ARG4(a,a)                               \
404         IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT(a,a)
405
406 #define IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG5(a)                     \
407         IMPLEMENT_CALLBACK_FUNC_CB_ARG5(a,a)                               \
408         IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT(a,a)
409
410 #endif /* FREEGLUT_CALLBACK_MACROS_H */
411
412 /*** END OF FILE ***/