NewClass(3) adding a new class to wxPerl

CHECKLIST

  • Are there constants or events that need to be wrapped?

    see ``CONSTANTS'' and ``EVENTS''.

  • Is the class is derived from wxObject, from wxEvtHandler or from another class?

    see ``CHOOSING A TYPEMAP''.

  • Are class instances destroyed by wxWidgets or should they be garbage collected like normal Perl objects?

    see ``DESTRUCTORS AND THREADS''.

  • Does the class have overloaded methods?

    see ``OVERLOADING''.

  • Does the class have virtual methods that should be overridable from Perl?

    see ``VIRTUAL METHODS''.

SKELETON

Add a new file XS/NewClass.xsp and update the MANIFEST. Choose a relevant .xs file in the top level directory (eg. Controls.xs) and add this line:

    INCLUDE_COMMAND: $^X -MExtUtils::XSpp::Cmd -e xspp -- -t typemap.xsp XS/NewClass.xsp

A skeleton for NewClass.xsp:

    %module{Wx};
    #include <wx/newclass.h> // use the relevant wxWidgets header(s)
    %name{Wx::NewClass} class wxNewClass : public wxSomeBaseClass
    {
        # constructors see the CONSTRUCTORS section
        wxNewClass( wxWindow* some_window, const wxString& str );
        # destructors
        ~wxNewClass();
        # methods
        wxString GetString() const;
        void SetString( const wxString& str );
    };

Add the typemap definition to typemap.tmpl. See ``CHOOSING A TYPEMAP''.

If adding a class related to one of the wxPerl submodules ("Wx::RichText", "Wx::Html", ...) add the .xsp file to the relevant subdirectory and modify the .xs and typemap files in that subdirectory.

CHOOSING A TYPEMAP

There are five typemaps that should work for most wxWidgets objects:
  • "O_NON_WXOBJECT"

    for all classes that do not derive from "wxObject" AND do not need to be garbage collected.

  • "O_NON_WXOBJECT_THR"

    for all classes that do not derive from "wxObject" AND need to be garbage collected (see ``DESTRUCTORS AND THREADS'').

  • "O_WXOBJECT"

    for all classes that derive from "wxObject" AND do not need to be garbage collected.

  • "O_WXOBJECT_THR"

    for all classes derived from "wxObject" AND need to be garbage collected (see ``DESTRUCTORS AND THREADS'').

  • "O_WXEVTHANDLER"

    for all classes that derive from "wxEvtHandler". See also ``CONSTRUCTORS''.

CONSTRUCTORS

For "O_WXEVTHANDLER" typemaps, there is some additional code that needs to be added to the constructor:

    wxNewClass( wxWindow* some_window, const wxString& str )
        %code{% RETVAL = new wxNewClass( some_window, str );
                wxPli_create_evthandler( aTHX_ RETVAL, CLASS );
                %};

DESTRUCTORS AND THREADS

For many classes not derived from "wxEvtHandler" you need to add a destructor to free the C++ object when the Perl object is garbage collected. At the XS++ level this means adding

    ~wxNewClass();

to the class definition, but there is a catch: the Perl threading model.

Without going into details, this is needed for Perl threads compatibility:

  • Use the correct typemap

    choose either "O_NON_WXOBJECT_THR" or "O_WXOBJECT_THR".

  • Implement a "CLONE" method

    add this code inside the class declaration:

        %{
        static void
        wxNewClass::CLONE()
          CODE:
            wxPli_thread_sv_clone( aTHX_ CLASS, (wxPliCloneSV)wxPli_detach_object );
        %}
    
  • Fix the destructor.

    modify the destructor like this:

        ~wxNewClass()
            %code%{  wxPli_thread_sv_unregister( aTHX_ "Wx::NewClass", THIS, ST(0) );
                     delete THIS;
                     %};
    

VIRTUAL METHODS

The wrapping of virtual functions whose arguments are simple C++ types (integrals, bool, floating point) and common wxWidgets types (wxString) should be automatic: at the top of the file, load the plugin that handles virtual methods

    %loadplugin{build::Wx::XSP::Virtual};

and decorate virtual/pure virtual methods using the %Virtual directive

    // pure virtual
    virtual wxString GetTitle() const = 0 %Virtual{pure};
    // virtual, not pure
    virtual int GetBestFittingWidth(unsigned int idx) const %Virtual;

If the class contains pure virtual methods, it will be marked as abstract, and it will have no constructors.

For abstract classes, XS++ will create an additional Perl-level class, called "Wx::Pl<classname>"; in order to override the virtual methods, you must derive from this class, and not from "Wx::<classname>".

TODO allow changing the default behaviour for abstract/concrete classes

TODO allow overriding the class name

TODO allow specifying custom code

TODO handle multiple return values

TODO customized type mapping