#ifndef fltk_pm_h
#define fltk_pm_h
#define FLTK_DEBUG 0
#define PERL_NO_GET_CONTEXT 1
#include <EXTERN.h>
#include <perl.h>
#define NO_XSLOCKS // XSUB.h will otherwise override various things we need
#include <XSUB.h>
#define NEED_sv_2pv_flags
#include "ppport.h"
#define NO_XSLOCKS // XSUB.h will otherwise override various things we need
//#define NEED_sv_2pv_flags
#define NEED_newSVpvn_flags
#define NO_INIT '\0'
void _cache( const char * ptr, const char * cls );
void _cache( void * ptr, const char * cls );
const char * _cache( const char * ptr );
const char * _cache( void * ptr );
void _delete_cache( void * ptr );
void _delete_cache( const char * ptr );
#ifdef WIN32
#include <windows.h>
HINSTANCE dllInstance( );
#endif // #ifdef WIN32
#include <FL/Fl_Widget.H>
const char * object2package ( Fl_Widget * w );
// Widget wrapper!
struct CTX {
int algorithm;
Fl_Widget * cp_ctx;
const char * cp_cls;
};
const char * object2package ( CTX * w );
template<typename T>
class WidgetSubclass : public T {
private:
int algorithm;
public:
WidgetSubclass( const char * cls, int x, int y, int w, int h, const char * lbl ) : T( x, y, w, h, lbl ) {
// Just about everything
dTHX;
_cache( ( void * ) this, cls );
};
WidgetSubclass( const char * cls, Fl_Boxtype type, int x, int y, int w, int h, const char * lbl ) : T( type, x, y, w, h, lbl ) {
// Fl_Box
dTHX;
_cache( ( void * ) this, cls );
};
WidgetSubclass( const char * cls, int w, int h, const char * lbl ) : T( w, h, lbl ) {
// Fl_Window
dTHX;
_cache( ( void * ) this, cls );
};
WidgetSubclass( Fl_Widget * w ) {
dTHX;
}
~WidgetSubclass( ) {
dTHX;
//warn( "%s->destroy( )", object2package( this ) );
_delete_cache( ( void * ) this );
this->T::~T( );
}
void draw( bool only ) {
dTHX;
T::draw();
//warn( "%s->draw( TRUE )", object2package( this ) );
};
int handle( bool only, int event ) {
return T::handle( event );
};
private:
void draw( ) {
dTHX;
call_perl_method( "draw", NULL, G_DISCARD );
};
int handle( int e ) {
dTHX;
return call_perl_method( "handle", newSViv( e ) );
};
int call_perl_method( const char * method, SV * args, int context = G_SCALAR ) {
dTHX;
dSP;
int count = 0;
SV * widget;
CTX * ctx;
Newx( ctx, 1, CTX );
ctx->cp_ctx = this;
{
widget = newSV( 1 );
sv_setref_pv( widget, object2package( this ), ( void* )ctx );
}
int result = 0;
ENTER;
SAVETMPS;
PUSHMARK( SP );
XPUSHs( widget );
if ( args != NULL && SvOK( args ) )
mXPUSHs( args );
PUTBACK;
count = call_method( method, context );
SPAGAIN;
if ( count == 1 && context != G_DISCARD )
/* if threads not loaded or an error occurs return 0 */
result = POPi;
PUTBACK;
FREETMPS;
LEAVE;
return result;
};
};
const char * object2package ( WidgetSubclass<Fl_Widget> * w );
class Callback {
private:
SV * callback;
SV * args;
CTX * ctx;
public:
~Callback() {
if ( ctx != NULL ) Safefree( ctx );
};
Callback( SV * cb ) {
dTHX;
callback = newSVsv( cb ); //sv_mortalcopy(cb);
args = ( SV* ) & PL_sv_undef;
};
Callback( SV * cb, SV * as ) {
dTHX;
callback = newSVsv( cb ); //sv_mortalcopy(cb);
args = newSVsv( as ); //sv_mortalcopy(as);
};
void trigger( Fl_Widget * w ) {
dTHX;
//warn ("%s->trigger()", object2package(w));
SV * widget;
CTX * ctx;
Newx( ctx, 1, CTX );
ctx->cp_ctx = w;
{
SV * RETVALSV;
RETVALSV = newSV( 1 );// sv_newmortal();
sv_setref_pv( RETVALSV, object2package( w ), ( void* )ctx );
widget = RETVALSV;
}
dSP;
ENTER;
SAVETMPS;
PUSHMARK( SP );
if ( SvOK( widget ) )
XPUSHs( widget );
if ( args != NULL && SvOK( args ) )
XPUSHs( args );
PUTBACK;
call_sv( callback, G_DISCARD ); // TODO: Should this be eval?
SPAGAIN;
PUTBACK;
FREETMPS;
LEAVE;
return;
};
SV * triggerOLD( Fl_Widget * w ) {
dTHX;
dSP;
int context = G_DISCARD;
SV * widget;
int count = 0;
if ( ctx == NULL )
Newx( ctx, 1, CTX );
ctx->cp_ctx = w;
{
widget = newSV( 1 );
sv_setref_pv( widget, object2package( w ) , ( void* )ctx );
}
SV * result = newSV( 1 );
ENTER;
SAVETMPS;
PUSHMARK( SP );
XPUSHs( widget );
if ( args != NULL && SvOK( args ) )
XPUSHs( args );
PUTBACK;
count = call_sv( callback, context );
SPAGAIN;
if ( count == 1 && context != G_DISCARD )
/* if threads not loaded or an error occurs return 0 */
result = POPs;
PUTBACK;
FREETMPS;
LEAVE;
return result;
};
};
#endif // #ifndef fltk_pm_h