Add libwx-perl
[pkg-perl] / deb-src / libwx-perl / libwx-perl-0.96 / cpp / helpers.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        cpp/helpers.cpp
3 // Purpose:     implementation for helpers.h
4 // Author:      Mattia Barbon
5 // Modified by:
6 // Created:     29/10/2000
7 // RCS-ID:      $Id: helpers.cpp 2682 2009-11-21 10:39:46Z mbarbon $
8 // Copyright:   (c) 2000-2009 Mattia Barbon
9 // Licence:     This program is free software; you can redistribute it and/or
10 //              modify it under the same terms as Perl itself
11 /////////////////////////////////////////////////////////////////////////////
12
13 #include <wx/geometry.h>
14
15 #include "cpp/streams.h"
16 #include "cpp/streams.cpp"
17
18 #if WXPERL_W_VERSION_GE( 2, 5, 1 )
19     #include <wx/arrstr.h>
20 #endif
21 #if WXPERL_W_VERSION_GE( 2, 6, 0 )
22     #include <wx/gbsizer.h>
23 #endif
24 #if WXPERL_W_VERSION_GE( 2, 9, 0 )
25     #include <wx/position.h>
26 #endif
27
28 #define wxPL_USE_MAGIC 1
29
30 // ----------------------------------------------------------------------------
31 // wxMSW DLL intialisation
32 // ----------------------------------------------------------------------------
33
34 #ifdef __WXMSW__
35
36 extern "C" 
37 BOOL WINAPI DllMain( HANDLE hModule, DWORD fdwReason, LPVOID lpReserved )
38 {
39     if( fdwReason == DLL_PROCESS_ATTACH && !wxGetInstance() )
40         wxSetInstance( (HINSTANCE)hModule );
41     return TRUE;
42 }
43
44 #endif
45
46 // ----------------------------------------------------------------------------
47 // Utility functions for working with MAGIC
48 // ----------------------------------------------------------------------------
49
50 struct my_magic
51 {
52     my_magic() : object( NULL ), deleteable( true ) { }
53
54     wxObject*  object;
55     bool       deleteable;
56 };
57
58 my_magic* wxPli_get_magic( pTHX_ SV* rv )
59 {
60     // check for reference
61     if( !SvROK( rv ) )
62         return NULL;
63     SV* ref = SvRV( rv );
64
65     // if it isn't a SvPVMG, then it can't have MAGIC
66     // so it is deleteable
67     if( !ref || SvTYPE( ref ) < SVt_PVMG )
68         return NULL;
69
70     // search for '~' magic, and check the value
71     MAGIC* magic = mg_find( ref, '~' );
72
73     if( !magic )
74         return NULL;
75
76     return (my_magic*)magic->mg_ptr;
77 }
78
79 my_magic* wxPli_get_or_create_magic( pTHX_ SV* rv )
80 {
81     // check for reference
82     if( !SvROK( rv ) )
83         croak( "PANIC: object is not a reference" );
84     SV* ref = SvRV( rv );
85
86     // must be at least a PVMG
87     if( SvTYPE( ref ) < SVt_PVMG )
88         SvUPGRADE( ref, SVt_PVMG );
89
90     // search for '~' magic, and check the value
91     MAGIC* magic;
92
93     while( !( magic = mg_find( ref, '~' ) ) )
94     {
95         my_magic tmp;
96
97         sv_magic( ref, 0, '~', (char*)&tmp, sizeof( tmp ) );
98     }
99
100     return (my_magic*)magic->mg_ptr;
101 }
102
103 // ----------------------------------------------------------------------------
104 // ----------------------------------------------------------------------------
105
106 void wxPliSelfRef::DeleteSelf( bool fromDestroy )
107 {
108     if( !m_self )
109         return;
110
111     dTHX;
112
113     SV* self = m_self;
114     m_self = NULL;
115     wxPli_detach_object( aTHX_ self );
116     if( SvROK( self ) )
117     {
118         if( fromDestroy )
119         {
120             SvROK_off( self );
121             SvRV( self ) = NULL;
122         }
123         if( SvREFCNT( self ) > 0 )
124             SvREFCNT_dec( self );
125     }
126 }
127
128 int wxCALLBACK ListCtrlCompareFn( long item1, long item2, long comparefn )
129 {
130     dTHX;
131     dSP;
132     SV* func = (SV*)comparefn;
133
134     ENTER;
135     SAVETMPS;
136
137     PUSHMARK( SP );
138     XPUSHs( sv_2mortal( newSViv( item1 ) ) );
139     XPUSHs( sv_2mortal( newSViv( item2 ) ) );
140     PUTBACK;
141
142     int count = call_sv( (SV*)func, G_SCALAR );
143     SPAGAIN;
144
145     int retval = POPi;
146
147     PUTBACK;
148
149     FREETMPS;
150     LEAVE;
151
152     if( count != 1 )
153     {
154         croak( "Comparison function returned %d values ( 1 expected )",
155                count );
156     }
157
158     return retval;
159 }
160
161 const char* wxPli_cpp_class_2_perl( const wxChar* className,
162                                     char buffer[WXPL_BUF_SIZE] ) 
163 {
164     strcpy( buffer, "Wx::" );
165
166     if( className[0] == wxT('w') && className[1] == wxT('x') )
167         className += 2;
168     if( className[0] == wxT('P') && className[1] == wxT('l') )
169     {
170         if( className[2] == wxT('i') )
171             className += 3;
172         else
173             className += 2;
174     }
175 #if wxUSE_UNICODE
176     wxConvUTF8.WC2MB( buffer+4, className, WXPL_BUF_SIZE - 8 );
177 #else
178     strcpy( buffer+4, className );
179 #endif
180
181     return buffer;
182 }
183
184 void wxPli_push_arguments( pTHX_ SV*** psp, const char* argtypes, ... )
185 {
186     va_list arglist;
187     va_start( arglist, argtypes );
188
189     wxPli_push_args( aTHX_ psp, argtypes, arglist );
190     
191     va_end( arglist );
192 }
193
194 void wxPli_delayed_delete( pTHX_ SV* sv )
195 {
196     wxPli_detach_object( aTHX_ sv );
197     SvREFCNT_dec( sv );
198 }
199
200 void wxPli_push_args( pTHX_ SV*** psp, const char* argtypes, va_list& args ) 
201 {
202     SV** sp = *psp;
203 #if WXPERL_P_VERSION_GE( 5, 5, 0 )
204     dTHR;
205 #endif
206
207     if( argtypes == 0 )
208         return;
209
210     bool bval;
211     IV ival;
212     UV uval;
213     long lval;
214     unsigned long ulval;
215     char* stval;
216     wxChar* wstval;
217     SV* svval;
218     wxObject* oval;
219     void* pval;
220     wxString* wxsval;
221     const char* package;
222     double dval;
223
224     while( *argtypes ) 
225     {
226         switch( *argtypes ) 
227         {
228         case 'b':
229             bval = va_arg( args, int );
230             XPUSHs( bval ? &PL_sv_yes : &PL_sv_no );
231             break;
232         case 'i':
233             ival = va_arg( args, int );
234             XPUSHs( sv_2mortal( newSViv( ival ) ) );
235             break;
236         case 'I':
237             uval = va_arg( args, unsigned int );
238             XPUSHs( sv_2mortal( newSVuv( uval ) ) );
239             break;
240         case 'l':
241             lval = va_arg( args, long );
242             XPUSHs( sv_2mortal( newSViv( lval ) ) );
243             break;
244         case 'L':
245             ulval = va_arg( args, unsigned long );
246             XPUSHs( sv_2mortal( newSVuv( ulval ) ) );
247             break;
248         case 'd':
249             dval = va_arg( args, double );
250             XPUSHs( sv_2mortal( newSVnv( dval ) ) );
251             break;
252         case 'p':
253             stval = va_arg( args, char* );
254             XPUSHs( sv_2mortal( newSVpv( stval, 0 ) ) );
255             break;
256         case 'P':
257         {
258             wxsval = va_arg( args, wxString* );
259             SV* sv = sv_newmortal();
260             wxPli_wxString_2_sv( aTHX_ *wxsval, sv );
261             XPUSHs( sv );
262             break;
263         }
264         case 'w':
265         {
266             wstval = va_arg( args, wxChar* );
267             SV* sv = sv_newmortal();
268             wxPli_wxChar_2_sv( aTHX_ wstval, sv );
269             XPUSHs( sv );
270             break;
271         }
272         case 'S':
273             svval = va_arg( args, SV* );
274             XPUSHs( sv_2mortal( newSVsv( svval ) ) );
275             break;
276         case 's':
277             svval = va_arg( args, SV* );
278             XPUSHs( svval );
279             break;
280         case 'O':
281         case 'Q':
282         {
283             oval = va_arg( args, wxObject* );
284             SV* sv = wxPli_object_2_sv( aTHX_ newSViv( 0 ), oval ); 
285             if( *argtypes == 'Q' ) {
286                 SvREFCNT_inc( sv );
287                 SAVEDESTRUCTOR_X( wxPli_delayed_delete, sv );
288             }
289             XPUSHs( sv_2mortal( sv ) );
290             break;
291         }
292         case 'o':
293         case 'q':
294         {
295             pval = va_arg( args, void* );
296             package = va_arg( args, const char* );
297             SV * sv = wxPli_non_object_2_sv( aTHX_ newSViv( 0 ),
298                                              pval, package );
299             if( *argtypes == 'q' ) {
300                 SvREFCNT_inc( sv );
301                 SAVEDESTRUCTOR_X( wxPli_delayed_delete, sv );
302             }
303             XPUSHs( sv_2mortal( sv ) );
304             break;
305         }
306         default:
307             croak( "Internal error: unrecognized type '%c'\n", *argtypes );
308         }
309
310         ++argtypes;
311     }
312
313     *psp = sp;
314 }
315
316 #if !wxPL_USE_MAGIC
317
318 // this use of static is deprecated, but we need to
319 // cope with C++ compilers
320 static SV* _key;
321 static U32 _hash;
322
323 static U32 calc_hash( const char* key, size_t klen )
324 {
325     U32 h;
326     PERL_HASH( h, (char*)key, klen );
327     return h;
328 }
329
330 // precalculate key and hash value for "_WXTHIS"
331 class wxHashModule : public wxModule {
332     DECLARE_DYNAMIC_CLASS( wxHashModule );
333 public:
334     wxHashModule() {};
335
336     bool OnInit()
337     {
338         const char* kname = "_WXTHIS";
339         const int klen = 7;
340         dTHX;
341
342         _key = newSVpvn( CHAR_P kname, klen );
343         _hash = calc_hash( kname, klen );
344
345         return true;
346     };
347
348     void OnExit()
349     {
350         dTHX;
351         SvREFCNT_dec( _key );
352     };
353 };
354
355 IMPLEMENT_DYNAMIC_CLASS( wxHashModule, wxModule );
356
357 #endif // !wxPL_USE_MAGIC
358
359 // gets 'this' pointer from a blessed scalar/hash reference
360 void* wxPli_sv_2_object( pTHX_ SV* scalar, const char* classname ) 
361 {
362     // is it correct to use undef as 'NULL'?
363     if( !SvOK( scalar ) ) 
364     {
365         return NULL;
366     }
367
368     if( !SvROK( scalar ) )
369         croak( "variable is not an object: it must have type %s", classname );
370
371     if( !classname || sv_derived_from( scalar, CHAR_P classname ) ) 
372     {
373         SV* ref = SvRV( scalar );
374
375 #if wxPL_USE_MAGIC
376         my_magic* mg = wxPli_get_magic( aTHX_ scalar );
377
378         // rationale: if this is an hash-ish object, it always
379         // has both mg and mg->object; if however this is a
380         // scalar-ish object that has been marked/unmarked deletable
381         // it has mg, but not mg->object
382         if( !mg || !mg->object )
383             return INT2PTR( void*, SvOK( ref ) ? SvIV( ref ) : 0 );
384
385         return mg->object;
386 #else // if !wxPL_USE_MAGIC
387         if( SvTYPE( ref ) == SVt_PVHV ) 
388         {
389             HV* hv = (HV*) ref;
390             HE* value = hv_fetch_ent( hv, _key, 0, _hash );
391
392             if( value ) 
393             {
394                 SV* sv = HeVAL( value );
395                 return (void*)SvIV( sv );
396             }
397             else 
398             {
399                 croak( "the associative array (hash) "
400                        " does not have a '_WXTHIS' key" );
401                 return NULL; // dummy, for compiler
402             }
403         }
404         else
405             return (void*)SvIV( (SV*) ref );
406 #endif // wxPL_USE_MAGIC / !wxPL_USE_MAGIC
407     }
408     else 
409     {
410         croak( "variable is not of type %s", classname );
411         return NULL; // dummy, for compiler
412     }
413 }
414
415 SV* wxPli_non_object_2_sv( pTHX_ SV* var, const void* data, const char* package )
416 {
417     if( data == NULL )
418     {
419         sv_setsv( var, &PL_sv_undef );
420     }
421     else
422     {
423         sv_setref_pv( var, CHAR_P package, const_cast<void*>(data) );
424     }
425
426     return var;
427 }
428
429 SV* wxPli_clientdatacontainer_2_sv( pTHX_ SV* var, wxClientDataContainer* cdc, const char* klass )
430 {
431     if( cdc == NULL )
432     {
433         sv_setsv( var, &PL_sv_undef );
434         return var;
435     }
436
437     wxPliUserDataCD* clientData = (wxPliUserDataCD*) cdc->GetClientObject();
438
439     if( clientData != NULL )
440     {
441         SvSetSV_nosteal( var, clientData->GetData() );
442         return var;
443     }
444
445     return wxPli_non_object_2_sv( aTHX_ var, cdc, klass );
446 }
447
448 SV* wxPli_evthandler_2_sv( pTHX_ SV* var, wxEvtHandler* cdc )
449 {
450     if( cdc == NULL )
451     {
452         sv_setsv( var, &PL_sv_undef );
453         return var;
454     }
455
456     wxPliUserDataCD* clientData = (wxPliUserDataCD*)cdc->GetClientObject();
457
458     if( clientData )
459     {     
460         SvSetSV_nosteal( var, clientData->GetData() );
461         return var;
462     }
463
464     // blech, duplicated code
465     wxClassInfo *ci = cdc->GetClassInfo();
466     const wxChar* classname = ci->GetClassName();
467
468     char buffer[WXPL_BUF_SIZE];
469     const char* CLASS = wxPli_cpp_class_2_perl( classname, buffer );
470
471     sv_setref_pv( var, CHAR_P CLASS, cdc );
472
473     return var;
474 }
475
476 SV* wxPli_object_2_sv( pTHX_ SV* var, const wxObject* object ) 
477 {
478     if( object == NULL )
479     {
480         sv_setsv( var, &PL_sv_undef );
481         return var;
482     }
483
484     wxClassInfo *ci = object->GetClassInfo();
485     const wxChar* classname = ci->GetClassName();
486     wxEvtHandler* evtHandler = wxDynamicCast( object, wxEvtHandler );
487
488     if( evtHandler && evtHandler->GetClientObject() )
489         return wxPli_evthandler_2_sv( aTHX_ var, evtHandler );
490
491 #if wxUSE_UNICODE
492     if( wcsncmp( classname, wxT("wxPl"), 4 ) == 0 ) 
493 #else
494     if( strnEQ( classname, "wxPl", 4 ) ) 
495 #endif
496     {
497         wxPliClassInfo* cci = (wxPliClassInfo*)ci;
498         wxPliSelfRef* sr = cci->m_func( const_cast<wxObject*>(object) );
499
500         if( sr && sr->m_self )
501         {
502             SvSetSV_nosteal( var, sr->m_self );
503             return var;
504         }
505     }
506
507     char buffer[WXPL_BUF_SIZE];
508     const char* CLASS = wxPli_cpp_class_2_perl( classname, buffer );
509
510     if( strcmp( CLASS, "Wx::Object" ) == 0 ) {
511         warn( "Missing wxRTTI information, using Wx::Object as class" );
512     }
513
514     sv_setref_pv( var, CHAR_P CLASS, const_cast<wxObject*>(object) );
515
516     return var;
517 }
518
519 void wxPli_attach_object( pTHX_ SV* object, void* ptr )
520 {
521     SV* ref = SvRV( object );
522
523     if( SvTYPE( ref ) >= SVt_PVHV )
524     {
525 #if wxPL_USE_MAGIC
526         my_magic* mg = wxPli_get_or_create_magic( aTHX_ object );
527
528         mg->object = (wxObject*)ptr;
529 #else
530         SV* value = newSViv( (IV)ptr );
531         if( !hv_store_ent( (HV*)ref, _key, value, _hash ) )
532         {
533             SvREFCNT_dec( value );
534             croak( "error storing '_WXTHIS' value" );
535         }
536 #endif
537     }
538     else
539     {
540         sv_setiv( ref, PTR2IV( ptr ) );
541     }
542 }
543
544 void* wxPli_detach_object( pTHX_ SV* object )
545 {
546     if( !SvROK( object ) )
547         return NULL;
548     SV* ref = SvRV( object );
549
550     if( SvTYPE( ref ) >= SVt_PVHV )
551     {
552 #if wxPL_USE_MAGIC
553         my_magic* mg = wxPli_get_magic( aTHX_ object );
554
555         if( mg )
556         {
557             void* tmp = mg->object;
558
559             mg->object = NULL;
560             return tmp;
561         }
562
563         return NULL;
564 #else
565         HE* value = hv_fetch_ent( (HV*)ref, _key, 0, _hash );
566
567         if( value ) 
568         {
569             SV* sv = HeVAL( value );
570             void* tmp = (void*)SvIV( sv );
571
572             sv_setiv( sv, 0 );
573             return tmp;
574         }
575
576         return NULL;
577 #endif
578     }
579     else
580     {
581         void* tmp = INT2PTR( void*, SvIV( ref ) );
582
583         sv_setiv( ref, 0 );
584         return tmp;
585     }
586 }
587
588 /*
589 SV* wxPli_create_clientdatacontainer( pTHX_ wxClientDataContainer* object,
590                                       const char* classname )
591 {
592     SV* sv = wxPli_make_object( object, classname );
593     wxPliUserDataCD* clientData = new wxPliUserDataCD( sv );
594
595     object->SetClientObject( clientData );
596
597     return sv;
598 }
599 */
600
601 SV* wxPli_create_evthandler( pTHX_ wxEvtHandler* object,
602                              const char* classname )
603 {
604     SV* sv = wxPli_make_object( object, classname );
605     wxPliUserDataCD* clientData = new wxPliUserDataCD( sv );
606
607     object->SetClientObject( clientData );
608
609     return sv;
610 }
611
612 SV* wxPli_make_object( void* object, const char* classname ) 
613 {
614     dTHX;
615     SV* ret;
616     HV* hv;
617     HV* stash = gv_stashpv( CHAR_P classname, 0 );
618
619     hv = newHV();
620     ret = newRV_noinc( (SV*) hv );
621     // OK: if you want to keep it, just use SetSelf( sv, true );
622     sv_2mortal( ret ); 
623
624     wxPli_attach_object( aTHX_ ret, object );
625
626     return sv_bless( ret, stash );
627 }
628
629 bool wxPli_object_is_deleteable( pTHX_ SV* object )
630 {
631     my_magic* mg = wxPli_get_magic( aTHX_ object );
632
633     return mg             ? mg->deleteable :
634            SvRV( object ) ? true           :
635                             false;
636 }
637
638 void wxPli_object_set_deleteable( pTHX_ SV* object, bool deleteable )
639 {
640     // check for reference
641     if( !SvROK( object ) )
642         return;
643     SV* rv = SvRV( object );
644
645     // non-PVMG are always deletable
646     if( deleteable && SvTYPE( rv ) < SVt_PVMG )
647         return;
648
649     my_magic* mg = wxPli_get_or_create_magic( aTHX_ object );
650
651     mg->deleteable = deleteable;
652 }
653
654 void wxPli_stringarray_push( pTHX_ const wxArrayString& strings )
655 {
656     dSP;
657
658     size_t mx = strings.GetCount();
659     EXTEND( SP, int(mx) );
660     for( size_t i = 0; i < mx; ++i )
661     {
662 #if wxUSE_UNICODE
663         SV* tmp = sv_2mortal( newSVpv( strings[i].mb_str(wxConvUTF8), 0 ) );
664         SvUTF8_on( tmp );
665         PUSHs( tmp );
666 #else
667         PUSHs( sv_2mortal( newSVpvn( CHAR_P strings[i].c_str(),
668                                      strings[i].size() ) ) );
669 #endif
670     }
671
672     PUTBACK;
673 }
674
675 void wxPli_intarray_push( pTHX_ const wxArrayInt& ints )
676 {
677     dSP;
678
679     size_t mx = ints.GetCount();
680     EXTEND( SP, int(mx) );
681     for( size_t i = 0; i < mx; ++i )
682     {
683         PUSHs( sv_2mortal( newSViv( ints[i] ) ) );
684     }
685
686     PUTBACK;
687 }
688
689 #if WXPERL_W_VERSION_GE( 2, 7, 2 )
690
691 void wxPli_doublearray_push( pTHX_ const wxArrayDouble& doubles )
692 {
693     dSP;
694
695     size_t mx = doubles.GetCount();
696     EXTEND( SP, int(mx) );
697     for( size_t i = 0; i < mx; ++i )
698     {
699         PUSHs( sv_2mortal( newSVnv( doubles[i] ) ) );
700     }
701
702     PUTBACK;
703 }
704
705 #endif
706
707 void wxPli_objlist_push( pTHX_ const wxList& objs )
708 {
709     dSP;
710
711     wxList::compatibility_iterator node;
712
713     EXTEND( SP, objs.GetCount() );
714     for( node = objs.GetFirst(); node; node = node->GetNext() )
715     {
716         SV* tmp = wxPli_object_2_sv( aTHX_ sv_newmortal(), node->GetData() );
717         PUSHs( tmp );
718     }
719
720     PUTBACK;
721 }
722
723 AV* wxPli_objlist_2_av( pTHX_ const wxList& objs )
724 {
725     AV* av = newAV();
726     size_t i;
727     wxList::compatibility_iterator node;
728
729     av_extend( av, objs.GetCount() );
730     for( node = objs.GetFirst(), i = 0; node; ++i, node = node->GetNext() )
731     {
732         SV* tmp = wxPli_object_2_sv( aTHX_ sv_newmortal(), node->GetData() ); 
733         SvREFCNT_inc( tmp );
734         av_store( av, i, tmp );
735     }
736
737     return av;
738 }
739
740 AV* wxPli_stringarray_2_av( pTHX_ const wxArrayString& strings )
741 {
742     AV* av = newAV();
743     size_t i, n = strings.GetCount();
744     SV* tmp;
745
746     av_extend( av, n );
747     for( i = 0; i < n; ++i )
748     {
749 #if wxUSE_UNICODE
750         tmp = newSVpv( strings[i].mb_str(wxConvUTF8), 0 );
751         SvUTF8_on( tmp );
752 #else
753         tmp = newSVpv( CHAR_P strings[i].c_str(), 0 );
754 #endif
755         av_store( av, i, tmp );
756     }
757
758     return av;
759 }
760
761 AV* wxPli_uchararray_2_av( pTHX_ const unsigned char* array, int count )
762 {
763     AV* av = newAV();
764
765     av_extend( av, count );
766     for( int i = 0; i < count; ++i )
767     {
768         av_store( av, i, newSViv( array[i] ) );
769     }
770
771     return av;
772 }
773
774 template<class A> class array_thingy
775 {
776 public:
777     typedef A** lvalue;
778     typedef A* rvalue;
779
780     rvalue create( size_t n ) const { return new A[n]; }
781     void assign( lvalue lv, rvalue rv ) const { *lv = rv; }
782     void free( rvalue rv ) const { delete[] rv; }
783 };
784
785 template<class F, class C>
786 int wxPli_av_2_thingarray( pTHX_ SV* avref, typename C::lvalue array,
787                            const F& convertf, const C& thingy )
788 {
789     AV* av;
790
791     if( !SvROK( avref ) || 
792         ( SvTYPE( (SV*) ( av = (AV*) SvRV( avref ) ) ) != SVt_PVAV ) )
793     {
794         croak( "the value is not an array reference" );
795         return 0;
796     }
797     
798     int n = av_len( av ) + 1;
799     typename C::rvalue arr = thingy.create( n );
800
801     for( int i = 0; i < n; ++i )
802     {
803         SV* t = *av_fetch( av, i, 0 );
804         if( !convertf( aTHX_ arr[i], t ) )
805         {
806             thingy.free( arr );
807             croak( "invalid conversion for array element" );
808             return 0;
809         }
810     }
811
812     thingy.assign( array, arr );
813
814     return n;
815 }
816
817 class convert_sv
818 {
819 public:
820     bool operator()( pTHX_ SV*& dest, SV* src ) const
821     {
822         dest = src;
823         return true;
824     }
825 };
826
827 int wxPli_av_2_svarray( pTHX_ SV* avref, SV*** array )
828 {
829     return wxPli_av_2_thingarray( aTHX_ avref, array, convert_sv(),
830                                   array_thingy<SV*>() );
831 }
832
833 class convert_udatacd
834 {
835 public:
836     bool operator()( pTHX_ wxPliUserDataCD*& dest, SV* src ) const
837     {
838         dest = SvOK( src ) ? new wxPliUserDataCD( src ) : NULL;
839         return true;
840     }
841 };
842
843 int wxPli_av_2_userdatacdarray( pTHX_ SV* avref, wxPliUserDataCD*** array )
844 {
845     return wxPli_av_2_thingarray( aTHX_ avref, array, convert_udatacd(),
846                                   array_thingy<wxPliUserDataCD*>() );
847 }
848
849 class convert_uchar
850 {
851 public:
852     bool operator()( pTHX_ unsigned char& dest, SV* src ) const
853     {
854         dest = (unsigned char) SvUV( src );
855         return true;
856     }
857 };
858
859 int wxPli_av_2_uchararray( pTHX_ SV* avref, unsigned char** array )
860 {
861     return wxPli_av_2_thingarray( aTHX_ avref, array, convert_uchar(),
862                                   array_thingy<unsigned char>() );
863 }
864
865 class convert_int
866 {
867 public:
868     bool operator()( pTHX_ int& dest, SV* src ) const
869     {
870         dest = (int) SvIV( src );
871         return true;
872     }
873 };
874
875 int wxPli_av_2_intarray( pTHX_ SV* avref, int** array )
876 {
877     return wxPli_av_2_thingarray( aTHX_ avref, array, convert_int(),
878                                   array_thingy<int>() );
879 }
880
881 #include <wx/menu.h>
882 #include <wx/timer.h>
883
884 wxWindowID wxPli_get_wxwindowid( pTHX_ SV* var )
885 {
886     if( sv_isobject( var ) )
887     {
888         if( sv_derived_from( var, "Wx::Window" ) ) {
889             wxWindow* window = (wxWindow*)
890                 wxPli_sv_2_object( aTHX_ var, "Wx::Window" );
891
892             return window->GetId();
893         }
894         else if( sv_derived_from( var, "Wx::MenuItem" ) )
895         {
896             wxMenuItem* item = (wxMenuItem*)
897                 wxPli_sv_2_object( aTHX_ var, "Wx::MenuItem" );
898
899             return item->GetId();
900         }
901         else if( sv_derived_from( var, "Wx::Timer" ) )
902         {
903             wxTimer* timer = (wxTimer*)
904                 wxPli_sv_2_object( aTHX_ var, "Wx::Timer" );
905
906             return timer->GetId();
907         }
908     }
909
910     return SvIV( var );
911 }
912
913 class convert_wxstring
914 {
915 public:
916     bool operator()( pTHX_ wxString& dest, SV* src ) const
917     {
918         WXSTRING_INPUT( dest, const char*, src );
919         return true;
920     }
921 };
922
923 int wxPli_av_2_stringarray( pTHX_ SV* avref, wxString** array )
924 {
925     return wxPli_av_2_thingarray( aTHX_ avref, array, convert_wxstring(),
926                                   array_thingy<wxString>() );
927 }
928
929 template<class A, class B, B init>
930 class wxarray_thingy
931 {
932 public:
933     typedef A* lvalue;
934     typedef A& rvalue;
935
936     wxarray_thingy( lvalue lv ) : m_value( lv ) { }
937     rvalue create( size_t n ) const
938     {
939         m_value->Alloc( n );
940         for( size_t i = 0; i < n; ++i )
941             m_value->Add( init );
942         return *m_value;
943     }
944     void assign( lvalue, rvalue ) const { }
945     void free( rvalue ) const {}
946 private:
947     A* m_value;
948 };
949
950 extern const wxChar wxPliEmptyString[];
951
952 int wxPli_av_2_arraystring( pTHX_ SV* avref, wxArrayString* array )
953 {
954     return wxPli_av_2_thingarray( aTHX_ avref, array, convert_wxstring(),
955                                   wxarray_thingy<wxArrayString, const wxChar*, wxPliEmptyString>( array ) );
956 }
957
958 int wxPli_av_2_arrayint( pTHX_ SV* avref, wxArrayInt* array )
959 {
960     return wxPli_av_2_thingarray( aTHX_ avref, array, convert_int(),
961                                   wxarray_thingy<wxArrayInt, int, 0>( array ) );
962 }
963
964 const wxChar wxPliEmptyString[] = wxT("");
965
966 #if wxUSE_UNICODE
967 wxChar* my_strdup( const wxChar* s, size_t len )
968 {
969     wxChar* t = (wxChar*)malloc( (len + 1) * sizeof(wxChar) );
970
971     t[len] = 0;
972     memcpy( t, s, len * sizeof(wxChar) );
973
974     return t;
975 }
976 #endif
977
978 char* my_strdup( const char* s, size_t len )
979 {
980     char* t = (char*)malloc( len + 1 );
981
982     t[len] = 0;
983     memcpy( t, s, len );
984
985     return t;
986 }
987
988 class convert_charp
989 {
990 public:
991     bool operator()( pTHX_ char*& dest, SV* src ) const
992     {
993         STRLEN len;
994         char* t = SvPV( src, len );
995         dest = my_strdup( t, len );
996         return true;
997     }
998 };
999
1000 int wxPli_av_2_charparray( pTHX_ SV* avref, char*** array )
1001 {
1002     return wxPli_av_2_thingarray( aTHX_ avref, array, convert_charp(),
1003                                   array_thingy<char*>() );
1004 }
1005
1006 class convert_wxcharp
1007 {
1008 public:
1009     bool operator()( pTHX_ wxChar*& dest, SV* src ) const
1010     {
1011         wxString str;
1012         WXSTRING_INPUT( str, wxString, src );
1013         dest = my_strdup( (const wxChar*)str.c_str(), str.length() );
1014         return true;
1015     }
1016 };
1017
1018 int wxPli_av_2_wxcharparray( pTHX_ SV* avref, wxChar*** array )
1019 {
1020     return wxPli_av_2_thingarray( aTHX_ avref, array, convert_wxcharp(),
1021                                   array_thingy<wxChar*>() );
1022 }
1023
1024 #if wxUSE_UNICODE
1025 static wxChar* wxPli_copy_string( SV* scalar, wxChar** )
1026 {
1027     dTHX;
1028     STRLEN length;
1029     wxWCharBuffer tmp = ( SvUTF8( scalar ) ) ?
1030       wxConvUTF8.cMB2WX( SvPVutf8( scalar, length ) ) :
1031       wxWCharBuffer( wxString( SvPV( scalar, length ),
1032                                wxConvLocal ).wc_str() );
1033     
1034     wxChar* buffer = new wxChar[length + 1];
1035     memcpy( buffer, tmp.data(), length * sizeof(wxChar) );
1036     buffer[length] = wxT('\0');
1037     return buffer;
1038 }
1039 #endif
1040
1041 static char* wxPli_copy_string( SV* scalar, char** )
1042 {
1043     dTHX;
1044     STRLEN length;
1045     const char* tmp = SvPV( scalar, length );
1046
1047     char* buffer = new char[length + 1];
1048     memcpy( buffer, tmp, length * sizeof(char) );
1049     buffer[length] = 0;
1050     return buffer;
1051 }
1052
1053 void wxPli_delete_argv( void*** argv, bool unicode )
1054 {
1055 #if wxUSE_UNICODE
1056     if( unicode )
1057     {
1058         wxChar** arg = *(wxChar***)argv;
1059         if( arg != NULL )
1060             for( wxChar** i = arg; *i; ++i ) delete[] *i;
1061         delete[] arg;
1062         *(wxChar***)argv = NULL;
1063     }
1064     else
1065     {
1066 #endif
1067         char** arg = *(char***)argv;
1068         if( arg != NULL )
1069             for( char** i = arg; *i; ++i ) delete[] *i;
1070         delete[] arg;
1071         *(char***)argv = NULL;
1072 #if wxUSE_UNICODE
1073     }
1074 #endif
1075 }
1076
1077 int wxPli_get_args_argc_argv( void*** argvp, bool unicode ) 
1078 {
1079     dTHX;
1080 #if wxUSE_UNICODE
1081     wxChar** argv_w;
1082 #endif
1083     char ** argv_a;
1084     AV* args = get_av( "main::ARGV" , 0 );
1085     SV* progname = get_sv( "main::0", 0 );
1086     int arg_num = args ? av_len( args ) + 1 : 0;
1087     I32 argc = arg_num + 1;
1088     I32 i;
1089
1090     if( !progname ) progname = &PL_sv_undef;
1091
1092 #if wxUSE_UNICODE
1093     if( unicode )
1094     {
1095         argv_w = new wxChar*[ arg_num + 2 ];
1096         argv_w[argc] = 0;
1097         argv_w[0] = wxPli_copy_string( progname, argv_w );
1098
1099         for( i = 0; i < arg_num; ++i )
1100         {
1101             argv_w[i + 1] = wxPli_copy_string( *av_fetch( args, i, 0 ), argv_w );
1102         }
1103
1104         *(wxChar***)argvp = argv_w;
1105     }
1106     else
1107     {
1108 #endif
1109         argv_a = new char*[ arg_num + 2 ];
1110         argv_a[argc] = 0;
1111         argv_a[0] = wxPli_copy_string( progname, argv_a );
1112
1113         for( i = 0; i < arg_num; ++i )
1114         {
1115             argv_a[i + 1] = wxPli_copy_string( *av_fetch( args, i, 0 ), argv_a );
1116         }
1117
1118         *(char***)argvp = argv_a;
1119 #if wxUSE_UNICODE
1120     }
1121 #endif
1122
1123     return argc;
1124 }
1125
1126 const char* wxPli_get_class( pTHX_ SV* ref )
1127 {
1128     const char* ret;
1129
1130     if( sv_isobject( ref ) )
1131     {
1132         ret = HvNAME( SvSTASH( SvRV( ref ) ) );
1133     }
1134     else
1135     {
1136         ret = SvPV_nolen( ref );
1137     }
1138
1139     return ret;
1140 }
1141
1142 template<class R, class E, class F>
1143 R wxPli_sv_2_wxpoint_test( pTHX_ SV* scalar, const F& convertf,
1144                            const char* klass, bool* ispoint )
1145 {
1146     static R dummy;
1147
1148     if( ispoint )
1149         *ispoint = true;
1150
1151     if( SvROK( scalar ) ) 
1152     {
1153         SV* ref = SvRV( scalar );
1154         
1155         if( sv_derived_from( scalar, CHAR_P klass ) ) 
1156         {
1157             return *INT2PTR( R*, SvIV( ref ) );
1158         }
1159         else if( SvTYPE( ref ) == SVt_PVAV )
1160         {
1161             AV* av = (AV*) ref;
1162             
1163             if( av_len( av ) != 1 )
1164             {
1165                 if( ispoint )
1166                 {
1167                     *ispoint = false;
1168                     return dummy;
1169                 }
1170                 else
1171                 {
1172                     croak( "the array reference must have 2 elements" );
1173                 }
1174             }
1175             else
1176             {
1177                 E x, y;
1178                 convertf( aTHX_ x, *av_fetch( av, 0, 0 ) );
1179                 convertf( aTHX_ y, *av_fetch( av, 1, 0 ) );
1180                 
1181                 return R( x, y );
1182             }
1183         }
1184     }
1185     
1186     if( ispoint )
1187     {
1188         *ispoint = false;
1189         return dummy;
1190     }
1191     else
1192     {
1193         croak( "variable is not of type Wx::Point" );
1194     }
1195
1196     return dummy;
1197 }
1198
1199 wxPoint wxPli_sv_2_wxpoint_test( pTHX_ SV* scalar, bool* ispoint )
1200 {
1201     return wxPli_sv_2_wxpoint_test<wxPoint, int, convert_int>
1202                ( aTHX_ scalar, convert_int(), "Wx::Point", ispoint );
1203 }
1204
1205 wxPoint wxPli_sv_2_wxpoint( pTHX_ SV* scalar )
1206 {
1207     return wxPli_sv_2_wxpoint_test<wxPoint, int, convert_int>
1208                ( aTHX_ scalar, convert_int(), "Wx::Point", 0 );
1209 }
1210
1211 template<class T>
1212 inline T wxPli_sv_2_wxthing( pTHX_ SV* scalar, const char* name )
1213 {
1214     if( SvROK( scalar ) ) 
1215     {
1216         SV* ref = SvRV( scalar );
1217         
1218         if( sv_derived_from( scalar, CHAR_P name ) ) 
1219             return *INT2PTR( T*, SvIV( ref ) );
1220         else if( SvTYPE( ref ) == SVt_PVAV )
1221         {
1222             AV* av = (AV*) ref;
1223             
1224             if( av_len( av ) != 1 )
1225                 croak( "the array reference must have 2 elements" );
1226             else
1227                 return T( SvIV( *av_fetch( av, 0, 0 ) ),
1228                           SvIV( *av_fetch( av, 1, 0 ) ) );
1229         }
1230     }
1231     
1232     croak( "variable is not of type %s", name );
1233     return T(); // to appease the compilers
1234 }
1235
1236 wxSize wxPli_sv_2_wxsize( pTHX_ SV* scalar )
1237 {
1238     return wxPli_sv_2_wxthing<wxSize>( aTHX_ scalar, "Wx::Size" );
1239 }
1240
1241 #if WXPERL_W_VERSION_GE( 2, 6, 0 )
1242
1243 wxGBPosition wxPli_sv_2_wxgbposition( pTHX_ SV* scalar )
1244 {
1245     return wxPli_sv_2_wxthing<wxGBPosition>( aTHX_ scalar, "Wx::GBPosition" );
1246 }
1247
1248 wxGBSpan wxPli_sv_2_wxgbspan( pTHX_ SV* scalar )
1249 {
1250     return wxPli_sv_2_wxthing<wxGBSpan>( aTHX_ scalar, "Wx::GBSpan" );
1251 }
1252
1253 #endif
1254
1255 #if WXPERL_W_VERSION_GE( 2, 9, 0 )
1256
1257 wxPosition wxPli_sv_2_wxposition( pTHX_ SV* scalar )
1258 {
1259     return wxPli_sv_2_wxthing<wxPosition>( aTHX_ scalar, "Wx::Position" );
1260 }
1261
1262 #endif
1263
1264 wxKeyCode wxPli_sv_2_keycode( pTHX_ SV* sv )
1265 {
1266     if( SvIOK( sv ) || SvNOK( sv ) )
1267     {
1268         return (wxKeyCode) SvIV( sv );
1269     }
1270     else if( SvPOK( sv ) && SvCUR( sv ) == 1 )
1271     {
1272         return (wxKeyCode) ( SvPV_nolen( sv ) )[0];
1273     }
1274     else
1275     {
1276         croak( "You must supply either a number or a 1-character string" );
1277     }
1278
1279     return wxKeyCode( 0 ); // just to silence a possible warning
1280 }
1281
1282 wxVariant wxPli_sv_2_wxvariant( pTHX_ SV* sv )
1283 {
1284     if( !SvOK( sv ) ) {
1285         return wxVariant();
1286     } else if( SvROK( sv ) ) {
1287         // TODO
1288         return wxVariant();
1289     } else if( SvNOK( sv ) ) {
1290         return wxVariant( (double)SvNV( sv ) );
1291     } else if( SvIOK( sv ) ) {
1292 #if INTSIZE > LONGSIZE
1293         return wxVariant( (int)SvIV( sv ) );
1294 #else
1295         return wxVariant( (long)SvIV( sv ) );
1296 #endif
1297     }
1298
1299     return wxVariant();
1300 }
1301
1302 class convert_wxpoint
1303 {
1304 public:
1305     bool operator()( pTHX_ wxPoint& dest, SV* src ) const
1306     {
1307         bool ispoint;
1308         dest = wxPli_sv_2_wxpoint_test<wxPoint, int, convert_int>
1309                    ( aTHX_ src, convert_int(), "Wx::Point", &ispoint );
1310         return ispoint;
1311     }
1312 };
1313
1314 int wxPli_av_2_pointarray( pTHX_ SV* avref, wxPoint** array )
1315 {
1316     return wxPli_av_2_thingarray( aTHX_ avref, array, convert_wxpoint(),
1317                                   array_thingy<wxPoint>() );
1318 }
1319
1320 class convert_double
1321 {
1322 public:
1323     bool operator()( pTHX_ double& dest, SV* src ) const
1324     {
1325         dest = (double) SvNV( src );
1326         return true;
1327     }
1328 };
1329
1330 class convert_wxpoint2ddouble
1331 {
1332 public:
1333     bool operator()( pTHX_ wxPoint2DDouble& dest, SV* src ) const
1334     {
1335         bool ispoint;
1336         dest = wxPli_sv_2_wxpoint_test<wxPoint2DDouble, double,
1337                                        convert_double>
1338                    ( aTHX_ src, convert_double(), "Wx::Point2DDouble",
1339                      &ispoint );
1340         return ispoint;
1341     }
1342 };
1343
1344 int wxPli_av_2_point2ddoublearray( pTHX_ SV* avref, wxPoint2DDouble** array )
1345 {
1346     return wxPli_av_2_thingarray( aTHX_ avref, array,
1347                                   convert_wxpoint2ddouble(),
1348                                   array_thingy<wxPoint2DDouble>() );
1349 }
1350
1351 #if WXPERL_W_VERSION_GE( 2, 9, 0 )
1352 int wxPli_av_2_pointlist( pTHX_ SV* arr, wxPointList *points, wxPoint** tmp )
1353 #else
1354 int wxPli_av_2_pointlist( pTHX_ SV* arr, wxList *points, wxPoint** tmp )
1355 #endif
1356 {
1357     *tmp = 0;
1358
1359     if( !SvROK( arr ) || SvTYPE( SvRV( arr ) ) != SVt_PVAV )
1360     {
1361         croak( "variable is not an array reference" );
1362     }
1363
1364     AV* array = (AV*) SvRV( arr );
1365     int itm = av_len( array ) + 1, i;
1366
1367     if( itm == 0 )
1368         return 0;
1369
1370     *tmp = new wxPoint[ itm ];
1371     int used = 0;
1372
1373     for( i = 0; i < itm; ++i )
1374     {
1375         SV* scalar = *av_fetch( array, i, 0 );
1376
1377         if( SvROK( scalar ) ) 
1378         {
1379             SV* ref = SvRV( scalar );
1380         
1381             if( sv_derived_from( scalar, CHAR_P "Wx::Point" ) ) 
1382             {
1383 #if WXPERL_W_VERSION_GE( 2, 9, 0 )
1384                 points->Append( INT2PTR( wxPoint*, SvIV( ref ) ) );
1385 #else
1386                 points->Append( INT2PTR( wxObject*, SvIV( ref ) ) );
1387 #endif
1388                 continue;
1389             }
1390             else if( SvTYPE( ref ) == SVt_PVAV )
1391             {
1392                 AV* av = (AV*) ref;
1393             
1394                 if( av_len( av ) != 1 )
1395                 {
1396                     croak( "the array reference must have 2 elements" );
1397                     delete [] *tmp;
1398                     return 0;
1399                 }
1400                 else
1401                 {
1402                     int x = SvIV( *av_fetch( av, 0, 0 ) );
1403                     int y = SvIV( *av_fetch( av, 1, 0 ) );
1404
1405                     (*tmp)[used] = wxPoint( x, y );
1406 #if WXPERL_W_VERSION_GE( 2, 9, 0 )
1407                     points->Append( reinterpret_cast<wxPoint*>( *tmp + used ) );
1408 #else
1409                     points->Append( reinterpret_cast<wxObject*>( *tmp + used ) );
1410 #endif
1411                     ++used;
1412                     continue;
1413                 }
1414             }
1415         }
1416
1417         croak( "variable is not of type Wx::Point" );
1418         delete [] *tmp;
1419         return 0;
1420     }
1421
1422     return itm;
1423 }
1424
1425 void wxPli_sv_2_istream( pTHX_ SV* scalar, wxPliInputStream& stream )
1426 {
1427     stream = wxPliInputStream( scalar );
1428 }
1429
1430 void wxPli_sv_2_ostream( pTHX_ SV* scalar, wxPliOutputStream& stream )
1431 {
1432     stream = wxPliOutputStream( scalar );
1433 }
1434
1435 void wxPli_stream_2_sv( pTHX_ SV* scalar, wxStreamBase* stream,
1436                         const char* package )
1437 {
1438     if( !stream )
1439     {
1440         SvSetSV_nosteal( scalar, &PL_sv_undef );
1441         return;
1442     }
1443
1444     static SV* tie = eval_pv
1445         ( "require Symbol; sub { my $x = Symbol::gensym(); my $c = shift; tie *$x, $c, @_; return $x }", 1 );
1446     static SV* dummy = SvREFCNT_inc( tie );
1447
1448     dSP;
1449
1450     PUSHMARK( SP );
1451     XPUSHs( newSVpv( CHAR_P package, 0 ) );
1452     XPUSHs( newSViv( PTR2IV( stream ) ) );
1453     PUTBACK;
1454
1455     call_sv( tie, G_SCALAR );
1456
1457     SPAGAIN;
1458     SV* ret = POPs;
1459     SvSetSV_nosteal( scalar, ret );
1460     PUTBACK;
1461 }
1462
1463 I32 my_looks_like_number( pTHX_ SV* sv )
1464 {
1465     if( SvROK( sv ) || !SvOK( sv ) ) return 0;
1466     if( SvIOK( sv ) || SvNOK( sv ) ) return 1;
1467     return looks_like_number( sv );
1468 }
1469
1470 #if wxPERL_USE_THREADS
1471
1472 #define dwxHash( package, create )             \
1473     char wxrbuffer[512];                       \
1474     strcpy( wxrbuffer, (package) );            \
1475     strcat( wxrbuffer, "::_thr_register" );    \
1476     HV* wxhash = get_hv( wxrbuffer, (create) ) \
1477
1478 #define dwxKey( ptr )              \
1479     char wxkey[40];                \
1480     sprintf( wxkey, "%p", (ptr) ); \
1481
1482 void wxPli_thread_sv_register( pTHX_ const char* package,
1483                                const void* ptr, SV* sv )
1484 {
1485     if( !SvROK( sv ) )
1486         croak( "PANIC: no sense in registering a non-reference" );
1487
1488     dwxHash( package, 1 );
1489     dwxKey( ptr );
1490
1491     SV* nsv = newRV( SvRV( sv ) );
1492     hv_store( wxhash, wxkey, strlen(wxkey), nsv, 0 );
1493
1494     sv_rvweaken( nsv );
1495 }
1496
1497 void wxPli_thread_sv_unregister( pTHX_ const char* package,
1498                                  const void* ptr, SV* sv )
1499 {
1500     if( !ptr )
1501         return;
1502
1503     dwxHash( package, 0 );
1504     if( !wxhash )
1505       return;
1506     dwxKey( ptr );
1507
1508     hv_delete( wxhash, wxkey, strlen(wxkey), 0 );   
1509 }
1510
1511 void wxPli_thread_sv_clone( pTHX_ const char* package, wxPliCloneSV clonefn )
1512 {
1513     dwxHash( package, 0 );
1514     if( !wxhash )
1515       return;
1516
1517     hv_iterinit( wxhash );
1518     HE* he;
1519     while( ( he = hv_iternext( wxhash ) ) != NULL ) {
1520         SV* val = hv_iterval( wxhash, he );
1521         clonefn( aTHX_ val );
1522
1523         // hack around Scalar::Util::weaken() producing warnings
1524         if( MAGIC* magic = mg_find( SvRV( val ), '<' ) )
1525         {
1526             SvREFCNT_inc( magic->mg_obj );
1527             mg_free( SvRV( val ) );
1528         }
1529     }
1530
1531     hv_undef( wxhash );
1532 }
1533
1534 #endif // wxPERL_USE_THREADS
1535
1536 // helpers for declaring event macros
1537 #include "cpp/e_cback.h"
1538
1539 // THIS, (any)
1540 XS(ConnectDummy);
1541 XS(ConnectDummy)
1542 {
1543     dXSARGS;
1544     SV* THISs = ST(0);
1545     wxEvtHandler *THISo = // not needed, but sanity check
1546         (wxEvtHandler*)wxPli_sv_2_object( aTHX_ THISs, "Wx::EvtHandler" );
1547 }
1548
1549 // THIS, function
1550 XS(Connect2);
1551 XS(Connect2)
1552 {
1553     dXSARGS;
1554     assert( items == 2 );
1555     SV* THISs = ST(0);
1556     wxEvtHandler *THISo =
1557         (wxEvtHandler*)wxPli_sv_2_object( aTHX_ THISs, "Wx::EvtHandler" );
1558     SV* func = ST(1);
1559     wxEventType evtID = CvXSUBANY(cv).any_i32;
1560
1561     if( SvOK( func ) )
1562     {
1563
1564         THISo->Connect( wxID_ANY, wxID_ANY, evtID,
1565                         wxPliCastEvtHandler( &wxPliEventCallback::Handler ),
1566                         new wxPliEventCallback( func, THISs ) );
1567     }
1568     else
1569     {
1570         THISo->Disconnect( wxID_ANY, wxID_ANY, evtID,
1571                            wxPliCastEvtHandler( &wxPliEventCallback::Handler ),
1572                            0 );
1573     }
1574 }
1575
1576 // THIS, ID, function
1577 XS(Connect3);
1578 XS(Connect3)
1579 {
1580     dXSARGS;
1581     assert( items == 3 );
1582     SV* THISs = ST(0);
1583     wxEvtHandler *THISo =
1584         (wxEvtHandler*)wxPli_sv_2_object( aTHX_ THISs, "Wx::EvtHandler" );
1585     wxWindowID id = wxPli_get_wxwindowid( aTHX_ ST(1) );
1586     SV* func = ST(2);
1587     wxEventType evtID = CvXSUBANY(cv).any_i32;
1588
1589     if( SvOK( func ) )
1590     {
1591         THISo->Connect( id, wxID_ANY, evtID,
1592                         wxPliCastEvtHandler( &wxPliEventCallback::Handler ),
1593                         new wxPliEventCallback( func, THISs ) );
1594     }
1595     else
1596     {
1597         THISo->Disconnect( id, wxID_ANY, evtID,
1598                            wxPliCastEvtHandler( &wxPliEventCallback::Handler ),
1599                            0 );
1600     }
1601 }
1602
1603 // THIS, ID, wxEventId, function
1604 XS(Connect4);
1605 XS(Connect4)
1606 {
1607     dXSARGS;
1608     assert( items == 4 );
1609     SV* THISs = ST(0);
1610     wxEvtHandler *THISo =
1611         (wxEvtHandler*)wxPli_sv_2_object( aTHX_ THISs, "Wx::EvtHandler" );
1612     wxWindowID id = wxPli_get_wxwindowid( aTHX_ ST(1) );
1613     wxEventType evtID = SvIV( ST(2) );
1614     SV* func = ST(3);
1615
1616     if( SvOK( func ) )
1617     {
1618         THISo->Connect( id, wxID_ANY, evtID,
1619                         wxPliCastEvtHandler( &wxPliEventCallback::Handler ),
1620                         new wxPliEventCallback( func, THISs ) );
1621     }
1622     else
1623     {
1624         THISo->Disconnect( id, wxID_ANY, evtID,
1625                            wxPliCastEvtHandler( &wxPliEventCallback::Handler ),
1626                            0 );
1627     }
1628 }
1629
1630 void CreateEventMacro( const char* name, unsigned char args, int id )
1631 {
1632     char buffer[1024];
1633     CV* cv;
1634     dTHX;
1635
1636     strcpy( buffer, "Wx::Event::" );
1637     strcat( buffer, name );
1638
1639     switch( args )
1640     {
1641     case 0:
1642         cv = (CV*)newXS( buffer, ConnectDummy, (char*)"Constants.xs" );
1643         break;
1644     case 2:
1645         cv = (CV*)newXS( buffer, Connect2, (char*)"Constants.xs" );
1646         sv_setpv((SV*)cv, "$$");
1647         break;
1648     case 3:
1649         cv = (CV*)newXS( buffer, Connect3, (char*)"Constants.xs" );
1650         sv_setpv((SV*)cv, "$$$");
1651         break;
1652     case 4:
1653         cv = (CV*)newXS( buffer, Connect4, (char*)"Constants.xs" );
1654         sv_setpv((SV*)cv, "$$$$");
1655         break;
1656     default:
1657         return;
1658     }
1659
1660     CvXSUBANY(cv).any_i32 = id;
1661 }
1662
1663 void wxPli_set_events( const struct wxPliEventDescription* events )
1664 {
1665     for( size_t i = 0; events[i].name != 0; ++i )
1666         CreateEventMacro( events[i].name, events[i].args, events[i].evtID );
1667 }
1668
1669 // Local variables: //
1670 // mode: c++ //
1671 // End: //