/*
# DO NOT EDIT THIS FILE.
#
# Any changes made here will be lost.
#
# This file is generated automatically by config/gen/opengl.pm

Copyright (C) 2008, 2014, Parrot Foundation.

=head1 NAME

src/glut_callbacks.c - GLUT Callback Function Handling

=head1 DESCRIPTION

GLUT callbacks are always synchronous and have void return type.  None
of them accept user data parameters, so normal Parrot callback handling
cannot be used.

=head2 Functions

=over 4

=cut

*/

#define PARROT_IN_EXTENSION

#include "parrot/parrot.h"
#include "parrot/extend.h"
/* workaround freeglut problem from 2.0 to at least 2.8, see [GH #1070] */
#ifndef __APPLE__
# define __APPLE__ 0
#endif
#include <GLUT/glut.h>

typedef enum {
    GLUT_CB_DISPLAY,
    GLUT_CB_IDLE,
    GLUT_CB_ENTRY,
    GLUT_CB_MENU_STATE,
    GLUT_CB_VISIBILITY,
    GLUT_CB_MOTION,
    GLUT_CB_PASSIVE_MOTION,
    GLUT_CB_RESHAPE,
    GLUT_CB_KEYBOARD,
    GLUT_CB_MOUSE,
    GLUT_CB_BUTTON_BOX,
    GLUT_CB_DIALS,
    GLUT_CB_SPACEBALL_BUTTON,
    GLUT_CB_TABLET_MOTION,
    GLUT_CB_SPACEBALL_MOTION,
    GLUT_CB_SPACEBALL_ROTATE,
    GLUT_CB_SPECIAL,
    GLUT_CB_TABLET_BUTTON,
    GLUT_CB_OVERLAY_DISPLAY,
    GLUT_CB_MENU_STATUS,
    GLUT_CB_WINDOW_STATUS,
    GLUT_CB_KEYBOARD_UP,
    GLUT_CB_SPECIAL_UP,
    GLUT_CB_WM_CLOSE,

    GLUT_CB_TIMER,

#if GLUT_API_VERSION >= 4
    GLUT_CB_JOYSTICK,
#endif

    GLUT_NUM_CALLBACKS
} GLUT_CALLBACKS;

typedef struct GLUT_CB_data {
    Parrot_Interp  interp;
    PMC            *sub;
} GLUT_CB_data;

GLUT_CB_data callback_data[GLUT_NUM_CALLBACKS];


                     int  is_safe(Parrot_Interp, PMC *);

                     void glut_timer_func(int);
PARROT_DYNEXT_EXPORT void glutcbTimerFunc(Parrot_Interp, PMC *, unsigned int, int);

#if GLUT_API_VERSION >= 4
                void glut_joystick_func(unsigned int, int, int, int);
PARROT_DYNEXT_EXPORT void glutcbJoystickFunc(Parrot_Interp, PMC *, int);
#endif

                     void glut_display_func(void);
                     void glut_idle_func(void);
                     void glut_entry_func(int);
                     void glut_menu_state_func(int);
                     void glut_visibility_func(int);
                     void glut_motion_func(int, int);
                     void glut_passive_motion_func(int, int);
                     void glut_reshape_func(int, int);
                     void glut_keyboard_func(unsigned char, int, int);
                     void glut_mouse_func(int, int, int, int);
                     void glut_button_box_func(int, int);
                     void glut_dials_func(int, int);
                     void glut_spaceball_button_func(int, int);
                     void glut_tablet_motion_func(int, int);
                     void glut_spaceball_motion_func(int, int, int);
                     void glut_spaceball_rotate_func(int, int, int);
                     void glut_special_func(int, int, int);
                     void glut_tablet_button_func(int, int, int, int);
                     void glut_overlay_display_func(void);
                     void glut_menu_status_func(int, int, int);
                     void glut_window_status_func(int);
                     void glut_keyboard_up_func(unsigned char, int, int);
                     void glut_special_up_func(int, int, int);
                     void glut_wm_close_func(void);

PARROT_DYNEXT_EXPORT void glutcbDisplayFunc(Parrot_Interp, PMC *);
PARROT_DYNEXT_EXPORT void glutcbIdleFunc(Parrot_Interp, PMC *);
PARROT_DYNEXT_EXPORT void glutcbEntryFunc(Parrot_Interp, PMC *);
PARROT_DYNEXT_EXPORT void glutcbMenuStateFunc(Parrot_Interp, PMC *);
PARROT_DYNEXT_EXPORT void glutcbVisibilityFunc(Parrot_Interp, PMC *);
PARROT_DYNEXT_EXPORT void glutcbMotionFunc(Parrot_Interp, PMC *);
PARROT_DYNEXT_EXPORT void glutcbPassiveMotionFunc(Parrot_Interp, PMC *);
PARROT_DYNEXT_EXPORT void glutcbReshapeFunc(Parrot_Interp, PMC *);
PARROT_DYNEXT_EXPORT void glutcbKeyboardFunc(Parrot_Interp, PMC *);
PARROT_DYNEXT_EXPORT void glutcbMouseFunc(Parrot_Interp, PMC *);
PARROT_DYNEXT_EXPORT void glutcbButtonBoxFunc(Parrot_Interp, PMC *);
PARROT_DYNEXT_EXPORT void glutcbDialsFunc(Parrot_Interp, PMC *);
PARROT_DYNEXT_EXPORT void glutcbSpaceballButtonFunc(Parrot_Interp, PMC *);
PARROT_DYNEXT_EXPORT void glutcbTabletMotionFunc(Parrot_Interp, PMC *);
PARROT_DYNEXT_EXPORT void glutcbSpaceballMotionFunc(Parrot_Interp, PMC *);
PARROT_DYNEXT_EXPORT void glutcbSpaceballRotateFunc(Parrot_Interp, PMC *);
PARROT_DYNEXT_EXPORT void glutcbSpecialFunc(Parrot_Interp, PMC *);
PARROT_DYNEXT_EXPORT void glutcbTabletButtonFunc(Parrot_Interp, PMC *);
PARROT_DYNEXT_EXPORT void glutcbOverlayDisplayFunc(Parrot_Interp, PMC *);
PARROT_DYNEXT_EXPORT void glutcbMenuStatusFunc(Parrot_Interp, PMC *);
PARROT_DYNEXT_EXPORT void glutcbWindowStatusFunc(Parrot_Interp, PMC *);
PARROT_DYNEXT_EXPORT void glutcbKeyboardUpFunc(Parrot_Interp, PMC *);
PARROT_DYNEXT_EXPORT void glutcbSpecialUpFunc(Parrot_Interp, PMC *);
PARROT_DYNEXT_EXPORT void glutcbWMCloseFunc(Parrot_Interp, PMC *);


/* Make sure that interp and sub are sane before running callback sub */
/* XXXX: Should this do the moral equivalent of PANIC? */
int
is_safe(SHIM_INTERP, PMC *sub)
{
    /* XXXX: Verify that interp still exists */

    /* XXXX: Verify that sub exists in interp */

    return PMC_IS_NULL(sub) ? 0 : 1;
}


/*

# glutTimerFunc and glutJoystickFunc must be hardcoded because they have
# special timer-related arguments that do not follow the template of all
# of the other GLUT callbacks

=item C<void glutcbTimerFunc(PARROT_INTERP, sub, milliseconds, data)>

Register a Sub PMC to handle GLUT Timer callbacks.

=cut

*/

void
glut_timer_func(int data)
{
    Parrot_Interp interp = callback_data[GLUT_CB_TIMER].interp;
    PMC           *sub   = callback_data[GLUT_CB_TIMER].sub;

    if (is_safe(interp, sub))
        Parrot_ext_call(interp, sub, "I->", (INTVAL) data);
}

PARROT_DYNEXT_EXPORT
void
glutcbTimerFunc(PARROT_INTERP, PMC *sub, unsigned int milliseconds, int data)
{
    callback_data[GLUT_CB_TIMER].interp = interp;
    callback_data[GLUT_CB_TIMER].sub    = sub;

    if (PMC_IS_NULL(sub))
        glutTimerFunc(0, NULL, 0);
    else
        glutTimerFunc(milliseconds, glut_timer_func, data);
}


#if GLUT_API_VERSION >= 4
/*

=item C<void glutcbJoystickFunc(PARROT_INTERP, sub, pollinterval)>

Register a Sub PMC to handle GLUT Joystick callbacks.

=cut

*/

void
glut_joystick_func(unsigned int buttons, int xaxis, int yaxis, int zaxis)
{
    Parrot_Interp interp = callback_data[GLUT_CB_JOYSTICK].interp;
    PMC           *sub   = callback_data[GLUT_CB_JOYSTICK].sub;

    if (is_safe(interp, sub))
        Parrot_ext_call(interp, sub, "IIII->",
            (INTVAL) buttons, (INTVAL) xaxis, (INTVAL) yaxis, (INTVAL) zaxis);
}

PARROT_DYNEXT_EXPORT
void
glutcbJoystickFunc(PARROT_INTERP, PMC *sub, int pollinterval)
{
    callback_data[GLUT_CB_JOYSTICK].interp = interp;
    callback_data[GLUT_CB_JOYSTICK].sub    = sub;

    if (PMC_IS_NULL(sub))
        glutJoystickFunc(NULL, 0);
    else
        glutJoystickFunc(glut_joystick_func, pollinterval);
}
#endif


/*

=item C<void glutcbDisplayFunc(PARROT_INTERP, sub)>

Register a Sub PMC to handle GLUT Display callbacks.

=cut

*/

void
glut_display_func(void)
{
    Parrot_Interp interp = callback_data[GLUT_CB_DISPLAY].interp;
    PMC           *sub   = callback_data[GLUT_CB_DISPLAY].sub;

    if (is_safe(interp, sub))
        Parrot_ext_call(interp, sub, "->");
}

PARROT_DYNEXT_EXPORT
void
glutcbDisplayFunc(PARROT_INTERP, PMC *sub)
{
    callback_data[GLUT_CB_DISPLAY].interp = interp;
    callback_data[GLUT_CB_DISPLAY].sub    = sub;

    if (PMC_IS_NULL(sub))
        glutDisplayFunc(NULL);
    else
        glutDisplayFunc(glut_display_func);
}


/*

=item C<void glutcbIdleFunc(PARROT_INTERP, sub)>

Register a Sub PMC to handle GLUT Idle callbacks.

=cut

*/

void
glut_idle_func(void)
{
    Parrot_Interp interp = callback_data[GLUT_CB_IDLE].interp;
    PMC           *sub   = callback_data[GLUT_CB_IDLE].sub;

    if (is_safe(interp, sub))
        Parrot_ext_call(interp, sub, "->");
}

PARROT_DYNEXT_EXPORT
void
glutcbIdleFunc(PARROT_INTERP, PMC *sub)
{
    callback_data[GLUT_CB_IDLE].interp = interp;
    callback_data[GLUT_CB_IDLE].sub    = sub;

    if (PMC_IS_NULL(sub))
        glutIdleFunc(NULL);
    else
        glutIdleFunc(glut_idle_func);
}


/*

=item C<void glutcbEntryFunc(PARROT_INTERP, sub)>

Register a Sub PMC to handle GLUT Entry callbacks.

=cut

*/

void
glut_entry_func(int state)
{
    Parrot_Interp interp = callback_data[GLUT_CB_ENTRY].interp;
    PMC           *sub   = callback_data[GLUT_CB_ENTRY].sub;

    if (is_safe(interp, sub))
        Parrot_ext_call(interp, sub, "I->", (INTVAL) state);
}

PARROT_DYNEXT_EXPORT
void
glutcbEntryFunc(PARROT_INTERP, PMC *sub)
{
    callback_data[GLUT_CB_ENTRY].interp = interp;
    callback_data[GLUT_CB_ENTRY].sub    = sub;

    if (PMC_IS_NULL(sub))
        glutEntryFunc(NULL);
    else
        glutEntryFunc(glut_entry_func);
}


/*

=item C<void glutcbMenuStateFunc(PARROT_INTERP, sub)>

Register a Sub PMC to handle GLUT Menu State callbacks.

=cut

*/

void
glut_menu_state_func(int status)
{
    Parrot_Interp interp = callback_data[GLUT_CB_MENU_STATE].interp;
    PMC           *sub   = callback_data[GLUT_CB_MENU_STATE].sub;

    if (is_safe(interp, sub))
        Parrot_ext_call(interp, sub, "I->", (INTVAL) status);
}

PARROT_DYNEXT_EXPORT
void
glutcbMenuStateFunc(PARROT_INTERP, PMC *sub)
{
    callback_data[GLUT_CB_MENU_STATE].interp = interp;
    callback_data[GLUT_CB_MENU_STATE].sub    = sub;

    if (PMC_IS_NULL(sub))
        glutMenuStateFunc(NULL);
    else
        glutMenuStateFunc(glut_menu_state_func);
}


/*

=item C<void glutcbVisibilityFunc(PARROT_INTERP, sub)>

Register a Sub PMC to handle GLUT Visibility callbacks.

=cut

*/

void
glut_visibility_func(int state)
{
    Parrot_Interp interp = callback_data[GLUT_CB_VISIBILITY].interp;
    PMC           *sub   = callback_data[GLUT_CB_VISIBILITY].sub;

    if (is_safe(interp, sub))
        Parrot_ext_call(interp, sub, "I->", (INTVAL) state);
}

PARROT_DYNEXT_EXPORT
void
glutcbVisibilityFunc(PARROT_INTERP, PMC *sub)
{
    callback_data[GLUT_CB_VISIBILITY].interp = interp;
    callback_data[GLUT_CB_VISIBILITY].sub    = sub;

    if (PMC_IS_NULL(sub))
        glutVisibilityFunc(NULL);
    else
        glutVisibilityFunc(glut_visibility_func);
}


/*

=item C<void glutcbMotionFunc(PARROT_INTERP, sub)>

Register a Sub PMC to handle GLUT Motion callbacks.

=cut

*/

void
glut_motion_func(int x, int y)
{
    Parrot_Interp interp = callback_data[GLUT_CB_MOTION].interp;
    PMC           *sub   = callback_data[GLUT_CB_MOTION].sub;

    if (is_safe(interp, sub))
        Parrot_ext_call(interp, sub, "II->", (INTVAL) x, (INTVAL) y);
}

PARROT_DYNEXT_EXPORT
void
glutcbMotionFunc(PARROT_INTERP, PMC *sub)
{
    callback_data[GLUT_CB_MOTION].interp = interp;
    callback_data[GLUT_CB_MOTION].sub    = sub;

    if (PMC_IS_NULL(sub))
        glutMotionFunc(NULL);
    else
        glutMotionFunc(glut_motion_func);
}


/*

=item C<void glutcbPassiveMotionFunc(PARROT_INTERP, sub)>

Register a Sub PMC to handle GLUT Passive Motion callbacks.

=cut

*/

void
glut_passive_motion_func(int x, int y)
{
    Parrot_Interp interp = callback_data[GLUT_CB_PASSIVE_MOTION].interp;
    PMC           *sub   = callback_data[GLUT_CB_PASSIVE_MOTION].sub;

    if (is_safe(interp, sub))
        Parrot_ext_call(interp, sub, "II->", (INTVAL) x, (INTVAL) y);
}

PARROT_DYNEXT_EXPORT
void
glutcbPassiveMotionFunc(PARROT_INTERP, PMC *sub)
{
    callback_data[GLUT_CB_PASSIVE_MOTION].interp = interp;
    callback_data[GLUT_CB_PASSIVE_MOTION].sub    = sub;

    if (PMC_IS_NULL(sub))
        glutPassiveMotionFunc(NULL);
    else
        glutPassiveMotionFunc(glut_passive_motion_func);
}


/*

=item C<void glutcbReshapeFunc(PARROT_INTERP, sub)>

Register a Sub PMC to handle GLUT Reshape callbacks.

=cut

*/

void
glut_reshape_func(int width, int height)
{
    Parrot_Interp interp = callback_data[GLUT_CB_RESHAPE].interp;
    PMC           *sub   = callback_data[GLUT_CB_RESHAPE].sub;

    if (is_safe(interp, sub))
        Parrot_ext_call(interp, sub, "II->", (INTVAL) width, (INTVAL) height);
}

PARROT_DYNEXT_EXPORT
void
glutcbReshapeFunc(PARROT_INTERP, PMC *sub)
{
    callback_data[GLUT_CB_RESHAPE].interp = interp;
    callback_data[GLUT_CB_RESHAPE].sub    = sub;

    if (PMC_IS_NULL(sub))
        glutReshapeFunc(NULL);
    else
        glutReshapeFunc(glut_reshape_func);
}


/*

=item C<void glutcbKeyboardFunc(PARROT_INTERP, sub)>

Register a Sub PMC to handle GLUT Keyboard callbacks.

=cut

*/

void
glut_keyboard_func(unsigned char key, int x, int y)
{
    Parrot_Interp interp = callback_data[GLUT_CB_KEYBOARD].interp;
    PMC           *sub   = callback_data[GLUT_CB_KEYBOARD].sub;

    if (is_safe(interp, sub))
        Parrot_ext_call(interp, sub, "III->", (INTVAL) key, (INTVAL) x, (INTVAL) y);
}

PARROT_DYNEXT_EXPORT
void
glutcbKeyboardFunc(PARROT_INTERP, PMC *sub)
{
    callback_data[GLUT_CB_KEYBOARD].interp = interp;
    callback_data[GLUT_CB_KEYBOARD].sub    = sub;

    if (PMC_IS_NULL(sub))
        glutKeyboardFunc(NULL);
    else
        glutKeyboardFunc(glut_keyboard_func);
}


/*

=item C<void glutcbMouseFunc(PARROT_INTERP, sub)>

Register a Sub PMC to handle GLUT Mouse callbacks.

=cut

*/

void
glut_mouse_func(int button, int state, int x, int y)
{
    Parrot_Interp interp = callback_data[GLUT_CB_MOUSE].interp;
    PMC           *sub   = callback_data[GLUT_CB_MOUSE].sub;

    if (is_safe(interp, sub))
        Parrot_ext_call(interp, sub, "IIII->", (INTVAL) button, (INTVAL) state, (INTVAL) x, (INTVAL) y);
}

PARROT_DYNEXT_EXPORT
void
glutcbMouseFunc(PARROT_INTERP, PMC *sub)
{
    callback_data[GLUT_CB_MOUSE].interp = interp;
    callback_data[GLUT_CB_MOUSE].sub    = sub;

    if (PMC_IS_NULL(sub))
        glutMouseFunc(NULL);
    else
        glutMouseFunc(glut_mouse_func);
}


/*

=item C<void glutcbButtonBoxFunc(PARROT_INTERP, sub)>

Register a Sub PMC to handle GLUT Button Box callbacks.

=cut

*/

void
glut_button_box_func(int button, int state)
{
    Parrot_Interp interp = callback_data[GLUT_CB_BUTTON_BOX].interp;
    PMC           *sub   = callback_data[GLUT_CB_BUTTON_BOX].sub;

    if (is_safe(interp, sub))
        Parrot_ext_call(interp, sub, "II->", (INTVAL) button, (INTVAL) state);
}

PARROT_DYNEXT_EXPORT
void
glutcbButtonBoxFunc(PARROT_INTERP, PMC *sub)
{
    callback_data[GLUT_CB_BUTTON_BOX].interp = interp;
    callback_data[GLUT_CB_BUTTON_BOX].sub    = sub;

    if (PMC_IS_NULL(sub))
        glutButtonBoxFunc(NULL);
    else
        glutButtonBoxFunc(glut_button_box_func);
}


/*

=item C<void glutcbDialsFunc(PARROT_INTERP, sub)>

Register a Sub PMC to handle GLUT Dials callbacks.

=cut

*/

void
glut_dials_func(int dial, int value)
{
    Parrot_Interp interp = callback_data[GLUT_CB_DIALS].interp;
    PMC           *sub   = callback_data[GLUT_CB_DIALS].sub;

    if (is_safe(interp, sub))
        Parrot_ext_call(interp, sub, "II->", (INTVAL) dial, (INTVAL) value);
}

PARROT_DYNEXT_EXPORT
void
glutcbDialsFunc(PARROT_INTERP, PMC *sub)
{
    callback_data[GLUT_CB_DIALS].interp = interp;
    callback_data[GLUT_CB_DIALS].sub    = sub;

    if (PMC_IS_NULL(sub))
        glutDialsFunc(NULL);
    else
        glutDialsFunc(glut_dials_func);
}


/*

=item C<void glutcbSpaceballButtonFunc(PARROT_INTERP, sub)>

Register a Sub PMC to handle GLUT Spaceball Button callbacks.

=cut

*/

void
glut_spaceball_button_func(int button, int state)
{
    Parrot_Interp interp = callback_data[GLUT_CB_SPACEBALL_BUTTON].interp;
    PMC           *sub   = callback_data[GLUT_CB_SPACEBALL_BUTTON].sub;

    if (is_safe(interp, sub))
        Parrot_ext_call(interp, sub, "II->", (INTVAL) button, (INTVAL) state);
}

PARROT_DYNEXT_EXPORT
void
glutcbSpaceballButtonFunc(PARROT_INTERP, PMC *sub)
{
    callback_data[GLUT_CB_SPACEBALL_BUTTON].interp = interp;
    callback_data[GLUT_CB_SPACEBALL_BUTTON].sub    = sub;

    if (PMC_IS_NULL(sub))
        glutSpaceballButtonFunc(NULL);
    else
        glutSpaceballButtonFunc(glut_spaceball_button_func);
}


/*

=item C<void glutcbTabletMotionFunc(PARROT_INTERP, sub)>

Register a Sub PMC to handle GLUT Tablet Motion callbacks.

=cut

*/

void
glut_tablet_motion_func(int x, int y)
{
    Parrot_Interp interp = callback_data[GLUT_CB_TABLET_MOTION].interp;
    PMC           *sub   = callback_data[GLUT_CB_TABLET_MOTION].sub;

    if (is_safe(interp, sub))
        Parrot_ext_call(interp, sub, "II->", (INTVAL) x, (INTVAL) y);
}

PARROT_DYNEXT_EXPORT
void
glutcbTabletMotionFunc(PARROT_INTERP, PMC *sub)
{
    callback_data[GLUT_CB_TABLET_MOTION].interp = interp;
    callback_data[GLUT_CB_TABLET_MOTION].sub    = sub;

    if (PMC_IS_NULL(sub))
        glutTabletMotionFunc(NULL);
    else
        glutTabletMotionFunc(glut_tablet_motion_func);
}


/*

=item C<void glutcbSpaceballMotionFunc(PARROT_INTERP, sub)>

Register a Sub PMC to handle GLUT Spaceball Motion callbacks.

=cut

*/

void
glut_spaceball_motion_func(int x, int y, int z)
{
    Parrot_Interp interp = callback_data[GLUT_CB_SPACEBALL_MOTION].interp;
    PMC           *sub   = callback_data[GLUT_CB_SPACEBALL_MOTION].sub;

    if (is_safe(interp, sub))
        Parrot_ext_call(interp, sub, "III->", (INTVAL) x, (INTVAL) y, (INTVAL) z);
}

PARROT_DYNEXT_EXPORT
void
glutcbSpaceballMotionFunc(PARROT_INTERP, PMC *sub)
{
    callback_data[GLUT_CB_SPACEBALL_MOTION].interp = interp;
    callback_data[GLUT_CB_SPACEBALL_MOTION].sub    = sub;

    if (PMC_IS_NULL(sub))
        glutSpaceballMotionFunc(NULL);
    else
        glutSpaceballMotionFunc(glut_spaceball_motion_func);
}


/*

=item C<void glutcbSpaceballRotateFunc(PARROT_INTERP, sub)>

Register a Sub PMC to handle GLUT Spaceball Rotate callbacks.

=cut

*/

void
glut_spaceball_rotate_func(int x, int y, int z)
{
    Parrot_Interp interp = callback_data[GLUT_CB_SPACEBALL_ROTATE].interp;
    PMC           *sub   = callback_data[GLUT_CB_SPACEBALL_ROTATE].sub;

    if (is_safe(interp, sub))
        Parrot_ext_call(interp, sub, "III->", (INTVAL) x, (INTVAL) y, (INTVAL) z);
}

PARROT_DYNEXT_EXPORT
void
glutcbSpaceballRotateFunc(PARROT_INTERP, PMC *sub)
{
    callback_data[GLUT_CB_SPACEBALL_ROTATE].interp = interp;
    callback_data[GLUT_CB_SPACEBALL_ROTATE].sub    = sub;

    if (PMC_IS_NULL(sub))
        glutSpaceballRotateFunc(NULL);
    else
        glutSpaceballRotateFunc(glut_spaceball_rotate_func);
}


/*

=item C<void glutcbSpecialFunc(PARROT_INTERP, sub)>

Register a Sub PMC to handle GLUT Special callbacks.

=cut

*/

void
glut_special_func(int key, int x, int y)
{
    Parrot_Interp interp = callback_data[GLUT_CB_SPECIAL].interp;
    PMC           *sub   = callback_data[GLUT_CB_SPECIAL].sub;

    if (is_safe(interp, sub))
        Parrot_ext_call(interp, sub, "III->", (INTVAL) key, (INTVAL) x, (INTVAL) y);
}

PARROT_DYNEXT_EXPORT
void
glutcbSpecialFunc(PARROT_INTERP, PMC *sub)
{
    callback_data[GLUT_CB_SPECIAL].interp = interp;
    callback_data[GLUT_CB_SPECIAL].sub    = sub;

    if (PMC_IS_NULL(sub))
        glutSpecialFunc(NULL);
    else
        glutSpecialFunc(glut_special_func);
}


/*

=item C<void glutcbTabletButtonFunc(PARROT_INTERP, sub)>

Register a Sub PMC to handle GLUT Tablet Button callbacks.

=cut

*/

void
glut_tablet_button_func(int button, int state, int x, int y)
{
    Parrot_Interp interp = callback_data[GLUT_CB_TABLET_BUTTON].interp;
    PMC           *sub   = callback_data[GLUT_CB_TABLET_BUTTON].sub;

    if (is_safe(interp, sub))
        Parrot_ext_call(interp, sub, "IIII->", (INTVAL) button, (INTVAL) state, (INTVAL) x, (INTVAL) y);
}

PARROT_DYNEXT_EXPORT
void
glutcbTabletButtonFunc(PARROT_INTERP, PMC *sub)
{
    callback_data[GLUT_CB_TABLET_BUTTON].interp = interp;
    callback_data[GLUT_CB_TABLET_BUTTON].sub    = sub;

    if (PMC_IS_NULL(sub))
        glutTabletButtonFunc(NULL);
    else
        glutTabletButtonFunc(glut_tablet_button_func);
}


/*

=item C<void glutcbOverlayDisplayFunc(PARROT_INTERP, sub)>

Register a Sub PMC to handle GLUT Overlay Display callbacks.

=cut

*/

void
glut_overlay_display_func(void)
{
    Parrot_Interp interp = callback_data[GLUT_CB_OVERLAY_DISPLAY].interp;
    PMC           *sub   = callback_data[GLUT_CB_OVERLAY_DISPLAY].sub;

    if (is_safe(interp, sub))
        Parrot_ext_call(interp, sub, "->");
}

PARROT_DYNEXT_EXPORT
void
glutcbOverlayDisplayFunc(PARROT_INTERP, PMC *sub)
{
    callback_data[GLUT_CB_OVERLAY_DISPLAY].interp = interp;
    callback_data[GLUT_CB_OVERLAY_DISPLAY].sub    = sub;

    if (PMC_IS_NULL(sub))
        glutOverlayDisplayFunc(NULL);
    else
        glutOverlayDisplayFunc(glut_overlay_display_func);
}


/*

=item C<void glutcbMenuStatusFunc(PARROT_INTERP, sub)>

Register a Sub PMC to handle GLUT Menu Status callbacks.

=cut

*/

void
glut_menu_status_func(int status, int x, int y)
{
    Parrot_Interp interp = callback_data[GLUT_CB_MENU_STATUS].interp;
    PMC           *sub   = callback_data[GLUT_CB_MENU_STATUS].sub;

    if (is_safe(interp, sub))
        Parrot_ext_call(interp, sub, "III->", (INTVAL) status, (INTVAL) x, (INTVAL) y);
}

PARROT_DYNEXT_EXPORT
void
glutcbMenuStatusFunc(PARROT_INTERP, PMC *sub)
{
    callback_data[GLUT_CB_MENU_STATUS].interp = interp;
    callback_data[GLUT_CB_MENU_STATUS].sub    = sub;

    if (PMC_IS_NULL(sub))
        glutMenuStatusFunc(NULL);
    else
        glutMenuStatusFunc(glut_menu_status_func);
}


/*

=item C<void glutcbWindowStatusFunc(PARROT_INTERP, sub)>

Register a Sub PMC to handle GLUT Window Status callbacks.

=cut

*/

void
glut_window_status_func(int state)
{
    Parrot_Interp interp = callback_data[GLUT_CB_WINDOW_STATUS].interp;
    PMC           *sub   = callback_data[GLUT_CB_WINDOW_STATUS].sub;

    if (is_safe(interp, sub))
        Parrot_ext_call(interp, sub, "I->", (INTVAL) state);
}

PARROT_DYNEXT_EXPORT
void
glutcbWindowStatusFunc(PARROT_INTERP, PMC *sub)
{
    callback_data[GLUT_CB_WINDOW_STATUS].interp = interp;
    callback_data[GLUT_CB_WINDOW_STATUS].sub    = sub;

    if (PMC_IS_NULL(sub))
        glutWindowStatusFunc(NULL);
    else
        glutWindowStatusFunc(glut_window_status_func);
}


/*

=item C<void glutcbKeyboardUpFunc(PARROT_INTERP, sub)>

Register a Sub PMC to handle GLUT Keyboard Up callbacks.

=cut

*/

void
glut_keyboard_up_func(unsigned char key, int x, int y)
{
    Parrot_Interp interp = callback_data[GLUT_CB_KEYBOARD_UP].interp;
    PMC           *sub   = callback_data[GLUT_CB_KEYBOARD_UP].sub;

    if (is_safe(interp, sub))
        Parrot_ext_call(interp, sub, "III->", (INTVAL) key, (INTVAL) x, (INTVAL) y);
}

PARROT_DYNEXT_EXPORT
void
glutcbKeyboardUpFunc(PARROT_INTERP, PMC *sub)
{
    callback_data[GLUT_CB_KEYBOARD_UP].interp = interp;
    callback_data[GLUT_CB_KEYBOARD_UP].sub    = sub;

    if (PMC_IS_NULL(sub))
        glutKeyboardUpFunc(NULL);
    else
        glutKeyboardUpFunc(glut_keyboard_up_func);
}


/*

=item C<void glutcbSpecialUpFunc(PARROT_INTERP, sub)>

Register a Sub PMC to handle GLUT Special Up callbacks.

=cut

*/

void
glut_special_up_func(int key, int x, int y)
{
    Parrot_Interp interp = callback_data[GLUT_CB_SPECIAL_UP].interp;
    PMC           *sub   = callback_data[GLUT_CB_SPECIAL_UP].sub;

    if (is_safe(interp, sub))
        Parrot_ext_call(interp, sub, "III->", (INTVAL) key, (INTVAL) x, (INTVAL) y);
}

PARROT_DYNEXT_EXPORT
void
glutcbSpecialUpFunc(PARROT_INTERP, PMC *sub)
{
    callback_data[GLUT_CB_SPECIAL_UP].interp = interp;
    callback_data[GLUT_CB_SPECIAL_UP].sub    = sub;

    if (PMC_IS_NULL(sub))
        glutSpecialUpFunc(NULL);
    else
        glutSpecialUpFunc(glut_special_up_func);
}


/*

=item C<void glutcbWMCloseFunc(PARROT_INTERP, sub)>

Register a Sub PMC to handle GLUT WM Close callbacks.

=cut

*/

void
glut_wm_close_func(void)
{
    Parrot_Interp interp = callback_data[GLUT_CB_WM_CLOSE].interp;
    PMC           *sub   = callback_data[GLUT_CB_WM_CLOSE].sub;

    if (is_safe(interp, sub))
        Parrot_ext_call(interp, sub, "->");
}

PARROT_DYNEXT_EXPORT
void
glutcbWMCloseFunc(PARROT_INTERP, PMC *sub)
{
    callback_data[GLUT_CB_WM_CLOSE].interp = interp;
    callback_data[GLUT_CB_WM_CLOSE].sub    = sub;

    if (PMC_IS_NULL(sub))
        glutWMCloseFunc(NULL);
    else
        glutWMCloseFunc(glut_wm_close_func);
}

/*

=back

=cut

*/
