cleaning up mixed tabs and spaces
[freeglut] / src / fg_callback_macros.h
index 1c70587..a1b8c38 100644 (file)
@@ -3,9 +3,8 @@
  *
  * The freeglut library callback macro file.
  *
- * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
- * Written by Pawel W. Olszta, <olszta@sourceforge.net>
- * Creation date: Thu Dec 2 1999
+ * Copyright (C) 2016 Vincent Simonetti
+ * Creation date: Sat Jan 16 2016
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
 #ifndef FREEGLUT_CALLBACK_MACROS_H
 #define FREEGLUT_CALLBACK_MACROS_H
 
-#ifndef FREEGLUT_INTERNAL_H
-#error "fg_internal.h needs to be included before this header"
-#endif
-
-#if 0 /* old. Remove once other testing is complete */
 /*
- * EXPAND_WCB() is used as:
- * 
- *     EXPAND_WCB arg_list
- * 
- * ... where {(arg_list)} is the parameter list.
- *
- * This will take the arg_list and extend it by one argument, adding
- * the argument "userData" to the end of the list.
- * 
- * All additional args are to get around trailing ',', argument counts,
- * and not needing a GCC extension to make this work.
- *
- * Minor modification of:
- * http://stackoverflow.com/questions/5355241/generating-function-declaration-using-a-macro-iteration/5355946#5355946
- *
- * Supports up to five arguments
+ * ----------------------------------------------------------------------------------------------------------------------
+ * There are two sets of macros here. One is for executing window callbacks, the others are for setting window callbacks.
+ * ----------------------------------------------------------------------------------------------------------------------
  */
 
-/* GCC-specific design that doesn't require per-callback defines */
-
-#define PP_HAS_ARGS_IMPL2(_0, _1, _2, _3, _4, _5, N, ...) N
-#define PP_HAS_ARGS_SOURCE() \
-    ONE_OR_MORE, ONE_OR_MORE, ONE_OR_MORE, ONE_OR_MORE, ONE_OR_MORE, ZERO
-
-#define PP_HAS_ARGS_IMPL(...) \
-    PP_HAS_ARGS_IMPL2(__VA_ARGS__)
-#define PP_HAS_ARGS(...) \
-    PP_HAS_ARGS_IMPL(NOT_EXIST, ##__VA_ARGS__, PP_HAS_ARGS_SOURCE())
-
-#define EXPAND_WCB_ZERO(x) \
-    (userData)
-#define EXPAND_WCB_ONE_OR_MORE(...) \
-    (__VA_ARGS__, userData)
-
-#define EXPAND_WCB_DISAMBIGUATE2(has_args, ...) \
-    EXPAND_WCB_ ## has_args (__VA_ARGS__)
-#define EXPAND_WCB_DISAMBIGUATE(has_args, ...) \
-    EXPAND_WCB_DISAMBIGUATE2(has_args, __VA_ARGS__)
-#define EXPAND_WCB(...) \
-    EXPAND_WCB_DISAMBIGUATE(PP_HAS_ARGS(__VA_ARGS__), __VA_ARGS__)
-#endif
-
 /*
- * Compiler defines:
- * FG_COMPILER_SUPPORTS_GCC_VA_ARGS_HACK: if the compiler supports GCC's varadic macro implementation (AKA, ##__VA_ARGS__)
- * FG_COMPILER_SUPPORTS_VA_ARGS: if the compiler supports varadic macros
+ * Compiler define: FG_COMPILER_SUPPORTS_VA_ARGS: if the compiler supports variadic macros
  */
 
-#ifdef FG_COMPILER_SUPPORTS_GCC_VA_ARGS_HACK
+/* What supports variadic macros based off Wikipedia article on it (GCC-like must support C99 or higher to use variadic macros) */
+#if (((defined(__GNUC__) && (__GNUC__ >= 3)) || \
+      (defined(__clang__))) && \
+        (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L))) || \
+    (defined(_MSC_VER) && (_MSC_VER >= 1400)) || \
+    (defined(__BORLANDC__) && (__BORLANDC__ >= 0x570)) || \
+    (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x530))
+#define FG_COMPILER_SUPPORTS_VA_ARGS 1
+#else
+#define FG_COMPILER_SUPPORTS_VA_ARGS 0
+#endif
 
- /*
- * EXPAND_WCB() is used as:
+/*
+ * --------------------------
+ * Executing window callbacks
+ * --------------------------
  *
- *     EXPAND_WCB arg_list
+ * Info:
  *
- * ... where {(arg_list)} is the parameter list.
+ * This took a while to figure out, so be sure try to understand what is happening so that you can ensure that whatever you
+ * change won't break other areas.
  *
- * This will take the arg_list and extend it by one argument, adding
- * the argument "userData" to the end of the list.
+ * If you are just adding a new callback/changing it's argument count, just go to the bottom of the file.
  *
- * All additional args are to get around trailing ',', argument counts,
- * and not needing a GCC extension to make this work.
+ * This whole file exists purely for the sake of preventing the need to implement additional parsing logic for each callback
+ * to pass user arguments. Of course, the necessity to support older compilers means that, as seen in the line above, there
+ * is still a requirement to add/modify code to handle callbacks. If freeglut ever requires newer compilers (at minimum, ones
+ * that support C99 or higher), code can very slowly be removed from this file. Even better would be if the C standard eventually
+ * supports something similar to what GCC has implemented or offers an alternative. Another option is if C++ would be "allowed" by
+ * project maintaners, as then templates can be used and function overloading. Ironically, the template would probably look worse
+ * then the GCC macro, so maybe it's good to stay as is.
  *
- * Modification of:
- * http://stackoverflow.com/questions/5355241/generating-function-declaration-using-a-macro-iteration/5355946#5355946
+ * Onto the different "versions" of macros:
  *
- * --------------
+ * The first is for any compiler that supports C99 by default. It requires each callback to have a specific argument count
+ * passthrough macro. The only reason there are specific count macros is so that (see paraghraph below) don't need have their own
+ * set of callback macros. Ideally, there would only be ZERO and ONE_OR_MORE. This works by having callback-specific macros call a
+ * specific handler macro to return user data (ZERO) or return one or more arguments along with userData (ONE_OR_MORE) where, with
+ * variadic macros, it just reuses the arguments.
  *
- * GCC-specific design that doesn't require per-callback defines
+ * 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
+ * it at all. Stuff like MSVC6... It works by having a specific-count macro that "extracts" each argument to have them reused without
+ * the parathesis.
  *
- * The naming is terrible... and it's very convuluted and complex, but
- * should not require any modification unless additional arguments are to 
- * be supported.
- * 
- * Supports callbacks up to 5 args (follow the pattern of PP_HAS_ARGS_IMPL2
- * and PP_HAS_ARGS_SOURCE to add more)
- *
- * Edit with care.
+ * 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.
+ * Not sure at this time what the SVN number is.) as it's a non-standard functionality.
  */
 
-#define EXPAND_WCB_UNPARAN(...) __VA_ARGS__
-
-#define PP_HAS_ARGS_IMPL2(_0, _1, _2, _3, _4, _5, N, ...) N
-#define PP_HAS_ARGS_SOURCE() ONE_OR_MORE, ONE_OR_MORE, ONE_OR_MORE, ONE_OR_MORE, ONE_OR_MORE, ZERO
-
-#define PP_HAS_ARGS_IMPL(...) PP_HAS_ARGS_IMPL2( __VA_ARGS__ )
-#define PP_HAS_ARGS(...) PP_HAS_ARGS_IMPL( NOT_EXIST, ##__VA_ARGS__, PP_HAS_ARGS_SOURCE() )
-
-#define EXPAND_WCB_ZERO(args, userData) ( userData )
-#define EXPAND_WCB_ONE_OR_MORE(args, userData) ( EXPAND_WCB_UNPARAN args, userData )
-
-#define EXPAND_WCB_DISAMBIGUATE(has_args, args, userData) EXPAND_WCB_ ## has_args ( args, userData )
-
-#define EXPAND_WCB_UNWRAP_ARGS2(args, userData) EXPAND_WCB_DISAMBIGUATE( PP_HAS_ARGS args, args, userData )
-#define EXPAND_WCB_UNWRAP_ARGS(args) EXPAND_WCB_UNWRAP_ARGS2 args
-
-#define EXPAND_WCB(cbname) EXPAND_WCB_UNWRAP_ARGS
-
-#else
-
 /*
  * EXPAND_WCB() is used as:
- * 
+ *
  *     EXPAND_WCB( cbname )(( arg_list, userData ))
- * 
+ *
  * ... where {(arg_list)} is the parameter list and userData is user
  * provided data.
  *
  * #define EXPAND_WCB_SUB_Entry(args) EXPAND_WCB_ONE args
  */
 
-#define FG_COMPILER_SUPPORTS_VA_ARGS //XXX (should be compiler defined)
-#ifdef FG_COMPILER_SUPPORTS_VA_ARGS
+#if FG_COMPILER_SUPPORTS_VA_ARGS
 
 #define EXPAND_WCB_UNPARAN(...) __VA_ARGS__
 #define EXPAND_WCB_ONE_OR_MORE(args, userData) ( EXPAND_WCB_UNPARAN args, userData )
 
 #else
 
-//TODO
-#error "Compiler does not support varadic argument macros"
+#define EXPAND_WCB_EXTRACT_ONE_ARGS(arg1) arg1
+#define EXPAND_WCB_EXTRACT_TWO_ARGS(arg1, arg2) arg1, arg2
+#define EXPAND_WCB_EXTRACT_THREE_ARGS(arg1, arg2, arg3) arg1, arg2, arg3
+#define EXPAND_WCB_EXTRACT_FOUR_ARGS(arg1, arg2, arg3, arg4) arg1, arg2, arg3, arg4
+#define EXPAND_WCB_EXTRACT_FIVE_ARGS(arg1, arg2, arg3, arg4, arg5) arg1, arg2, arg3, arg4, arg5
+
+#define EXPAND_WCB_ONE(args, userData) (EXPAND_WCB_EXTRACT_ONE_ARGS args, userData)
+#define EXPAND_WCB_TWO(args, userData) (EXPAND_WCB_EXTRACT_TWO_ARGS args, userData)
+#define EXPAND_WCB_THREE(args, userData) (EXPAND_WCB_EXTRACT_THREE_ARGS args, userData)
+#define EXPAND_WCB_FOUR(args, userData) (EXPAND_WCB_EXTRACT_FOUR_ARGS args, userData)
+#define EXPAND_WCB_FIVE(args, userData) (EXPAND_WCB_EXTRACT_FIVE_ARGS args, userData)
 
 #endif
 
 
 #define EXPAND_WCB(cbname) EXPAND_WCB_SUB_ ## cbname
 
-/* 
+/*
  * Freeglut callbacks type definitions macros
  *
  * Every time a callback is updated in fg_internal.h is updated, this needs updated
 #define EXPAND_WCB_SUB_InitContext(args) EXPAND_WCB_ZERO args
 #define EXPAND_WCB_SUB_AppStatus(args) EXPAND_WCB_ONE args
 
-#endif
+/*
+ * ------------------------
+ * Setting window callbacks
+ * ------------------------
+ *
+ * These originally existed in fg_callbacks.c
+ */
+
+/*
+ * All of the window-specific callbacks setting methods can be generalized to this:
+ */
+#define SET_CURRENT_WINDOW_CALLBACK(a)                                    \
+do                                                                        \
+{                                                                         \
+    if( fgStructure.CurrentWindow == NULL )                               \
+        return;                                                           \
+    SET_WCB( ( *( fgStructure.CurrentWindow ) ), a, callback, userData ); \
+} while( 0 )
+
+/*
+ * Types need to be defined for callbacks. It's not ideal, but it works for this.
+ */
+#define IMPLEMENT_CALLBACK_FUNC_CB_ARG0(a,b)                              \
+static void fgh##a##FuncCallback( FGCBUserData userData )                 \
+{                                                                         \
+    FGCB##b* callback = (FGCB##b*)&userData;                              \
+    (*callback)();                                                        \
+}
+#define IMPLEMENT_CALLBACK_FUNC_CB_ARG1(a,b)                              \
+static void fgh##a##FuncCallback( int arg1val, FGCBUserData userData )    \
+{                                                                         \
+    FGCB##b* callback = (FGCB##b*)&userData;                              \
+    (*callback)( arg1val );                                               \
+}
+#define IMPLEMENT_CALLBACK_FUNC_CB_ARG2(a,b)                              \
+static void fgh##a##FuncCallback( int arg1val, int arg2val, FGCBUserData userData ) \
+{                                                                         \
+    FGCB##b* callback = (FGCB##b*)&userData;                              \
+    (*callback)( arg1val, arg2val );                                      \
+}
+#define IMPLEMENT_CALLBACK_FUNC_CB_ARG3_USER(a,b,arg1,arg2,arg3)          \
+static void fgh##a##FuncCallback( arg1 arg1val, arg2 arg2val, arg3 arg3val, FGCBUserData userData ) \
+{                                                                         \
+    FGCB##b* callback = (FGCB##b*)&userData;                              \
+    (*callback)( arg1val, arg2val, arg3val );                             \
+}
+#define IMPLEMENT_CALLBACK_FUNC_CB_ARG3(a,b) IMPLEMENT_CALLBACK_FUNC_CB_ARG3_USER(a,b,int,int,int)
+#define IMPLEMENT_CALLBACK_FUNC_CB_ARG4(a,b)                              \
+static void fgh##a##FuncCallback( int arg1val, int arg2val, int arg3val, int arg4val, FGCBUserData userData ) \
+{                                                                         \
+    FGCB##b* callback = (FGCB##b*)&userData;                              \
+    (*callback)( arg1val, arg2val, arg3val, arg4val );                    \
+}
+#define IMPLEMENT_CALLBACK_FUNC_CB_ARG5(a,b)                              \
+static void fgh##a##FuncCallback( int arg1val, int arg2val, int arg3val, int arg4val, int arg5val, FGCBUserData userData ) \
+{                                                                         \
+    FGCB##b* callback = (FGCB##b*)&userData;                              \
+    (*callback)( arg1val, arg2val, arg3val, arg4val, arg5val );           \
+}
+
+/*
+ * And almost every time the callback setter function can be implemented with these:
+ */
+#define IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT_UCALL(a,b)      \
+void FGAPIENTRY glut##a##FuncUcall( FGCB##b##UC callback, FGCBUserData userData ) \
+{                                                                         \
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glut"#a"FuncUcall" );             \
+    SET_CURRENT_WINDOW_CALLBACK( b );                                     \
+}
+#define IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT_BASE(a,b)                      \
+void FGAPIENTRY glut##a##Func( FGCB##b callback )                         \
+{                                                                         \
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glut"#a"Func" );                  \
+    if( callback )                                                        \
+    {                                                                     \
+        FGCB##b* reference = &callback;                                   \
+        glut##a##FuncUcall( fgh##a##FuncCallback, *((FGCBUserData*)reference) ); \
+    }                                                                     \
+    else                                                                  \
+        glut##a##FuncUcall( NULL, NULL );                                 \
+}
+
+#define IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT(a,b)            \
+        IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT_UCALL(a,b)      \
+        IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT_BASE(a,b)
+
+/*
+ * Combine _glut and _cb macros:
+ */
+#define IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG0(a)                     \
+        IMPLEMENT_CALLBACK_FUNC_CB_ARG0(a,a)                               \
+        IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT(a,a)
+
+#define IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG0_2NAME(a,b)             \
+        IMPLEMENT_CALLBACK_FUNC_CB_ARG0(a,b)                               \
+        IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT(a,b)
+
+#define IMPLEMENT_GLUT_CALLBACK_FUNC_ARG0(a)                               \
+        IMPLEMENT_CALLBACK_FUNC_CB_ARG0(a,a)                               \
+        IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT_BASE(a,a)
+
+#define IMPLEMENT_GLUT_CALLBACK_FUNC_ARG0_2NAME(a,b)                       \
+        IMPLEMENT_CALLBACK_FUNC_CB_ARG0(a,b)                               \
+        IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT_BASE(a,b)
+
+#define IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG1(a)                     \
+        IMPLEMENT_CALLBACK_FUNC_CB_ARG1(a,a)                               \
+        IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT(a,a)
+
+#define IMPLEMENT_GLUT_CALLBACK_FUNC_ARG1(a)                               \
+        IMPLEMENT_CALLBACK_FUNC_CB_ARG1(a,a)                               \
+        IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT_BASE(a,a)
+
+#define IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG2(a)                     \
+        IMPLEMENT_CALLBACK_FUNC_CB_ARG2(a,a)                               \
+        IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT(a,a)
+
+#define IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG2_2NAME(a,b)             \
+        IMPLEMENT_CALLBACK_FUNC_CB_ARG2(a,b)                               \
+        IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT(a,b)
+
+#define IMPLEMENT_GLUT_CALLBACK_FUNC_ARG2(a)                               \
+        IMPLEMENT_CALLBACK_FUNC_CB_ARG2(a,a)                               \
+        IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT_BASE(a,a)
+
+#define IMPLEMENT_GLUT_CALLBACK_FUNC_ARG2_2NAME(a,b)                       \
+        IMPLEMENT_CALLBACK_FUNC_CB_ARG2(a,b)                               \
+        IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT_BASE(a,b)
+
+#define IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG3(a)                     \
+        IMPLEMENT_CALLBACK_FUNC_CB_ARG3(a,a)                               \
+        IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT(a,a)
+
+#define IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG3_USER(a,arg1,arg2,arg3) \
+        IMPLEMENT_CALLBACK_FUNC_CB_ARG3_USER(a,a,arg1,arg2,arg3)           \
+        IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT(a,a)
+
+#define IMPLEMENT_GLUT_CALLBACK_FUNC_ARG3(a)                               \
+        IMPLEMENT_CALLBACK_FUNC_CB_ARG3(a,a)                               \
+        IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT_BASE(a,a)
+
+#define IMPLEMENT_GLUT_CALLBACK_FUNC_ARG3_2NAME(a,b)                       \
+        IMPLEMENT_CALLBACK_FUNC_CB_ARG3(a,b)                               \
+        IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT_BASE(a,b)
+
+#define IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG4(a)                     \
+        IMPLEMENT_CALLBACK_FUNC_CB_ARG4(a,a)                               \
+        IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT(a,a)
+
+#define IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG5(a)                     \
+        IMPLEMENT_CALLBACK_FUNC_CB_ARG5(a,a)                               \
+        IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT(a,a)
 
 #endif /* FREEGLUT_CALLBACK_MACROS_H */