Wx::NewClass(3pm)

πŸ’… Wx::NewClass β€” adding a new class to wxPerl ✨

okay bestie, welcome to Wx::NewClass, a page from the User Contributed Perl Documentation era that teaches you how to add a whole new class to wxPerl. yes, you. you're gonna wrap a C++ class and make it live in Perl. iconic behavior. 🫢


🌸 CHECKLIST 🌸

before you do ANYTHING, vibe check yourself against these:

  • 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 πŸŽ€

step one, gorgeous: add a new file XS/NewClass.xsp and update the MANIFEST. (yes, actually update it, don't ghost the MANIFEST, she notices.)

then pick a relevant .xs file in the top level directory (like, say, Controls.xs) and slide this line into it:

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

and here's your little starter pack 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 );
};

then add the typemap definition to typemap.tmpl. which one tho?? β†’ "CHOOSING A TYPEMAP" has you. πŸ’–

and hmm, if you're adding a class related to one of the wxPerl submodules ("Wx::RichText", "Wx::Html", ...) then you do it different: drop the .xsp file into the relevant subdirectory and modify the .xs and typemap files in that subdirectory. stay in your lane (affectionately). πŸ¦‹


🌈 CHOOSING A TYPEMAP 🌈

there are five typemaps that should work for most wxWidgets objects, and choosing the right one is literally the whole game:

  • "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 (peep "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 (again: "DESTRUCTORS AND THREADS").
  • "O_WXEVTHANDLER" β€” for all classes that derive from wxEvtHandler. also go look at "CONSTRUCTORS".

✨ CONSTRUCTORS ✨

so for O_WXEVTHANDLER typemaps there's extra code you gotta sprinkle into the constructor. like this:

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

no notes, just vibes and a %code% block. πŸ‘‘


πŸ’€ DESTRUCTORS AND THREADS πŸ’€

okay bestie this is the part where it gets real. for MANY classes not derived from wxEvtHandler you need to add a destructor to free the C++ object when the Perl object gets garbage collected. at the XS++ level that means adding

~wxNewClass();

to the class definition. but here's the catch (and it's a big one): the Perl threading model. 😭

without going into the whole lore, this stuff 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 🧚

good news!! wrapping virtual functions whose arguments are simple C++ types (integrals, bool, floating point) and common wxWidgets types (wxString) should be automatic. the wrapping does itself. main character energy fr fr. 🌟

first, at the top of the file, load the plugin that handles virtual methods:

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

then decorate your 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;
heads up: if the class contains pure virtual methods, it will be marked as abstract, and it will have no constructors. 🚫

and for abstract classes, XS++ will create an additional Perl-level class called Wx::Pl<classname>. so to override the virtual methods you must derive from that class β€” not from Wx::<classname>. don't get it twisted. πŸ’…


⭐ TODO (aka the "we'll get to it bestie" pile) ⭐

  • 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

that's the whole page, angel. now go forth and wrap a class. slay. 🩷

written against the docs from perl v5.42.3, dated 2026-08-20, and shipped as Wx::NewClass(3pm) under User Contributed Perl Documentation. bye bestie πŸ’–

πŸ“¦ where this page comes from