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 ***/ 337