# Copyright (c) 2023 M.J.N. Corino, The Netherlands # # This software is released under the MIT license. ### # wxRuby3 wxWidgets interface director ### module WXRuby3 class Director class DataObject < Director include Typemap::DataFormat include Typemap::DataObjectData def setup super spec.items.concat %w[wxDataObjectSimple wxDataObjectComposite wxBitmapDataObject wxFileDataObject wxTextDataObject wxCustomDataObject wxImageDataObject wxURLDataObject] spec.gc_as_object # we only allow Ruby derivatives from wxDataObject but not of any of the C++ implemented # specializations %w[wxDataObjectSimple wxDataObjectComposite wxBitmapDataObject wxFileDataObject wxTextDataObject wxCustomDataObject wxImageDataObject wxURLDataObject].each do |kls| spec.no_proxy kls end # ignore the shortened 'convenience' forms spec.ignore 'wxDataObjectSimple::GetDataHere(void *) const' spec.ignore 'wxDataObjectSimple::SetData(size_t, const void *)' spec.ignore 'wxDataObjectSimple::GetDataSize() const' # ignore this as all derivatives have a fixed format spec.ignore 'wxDataObjectSimple::SetFormat' # ignore these as all fully implemented in derived and not useful in Ruby spec.ignore 'wxCustomDataObject::Alloc' spec.ignore 'wxCustomDataObject::Free' spec.ignore 'wxCustomDataObject::GetData' spec.ignore 'wxCustomDataObject::SetData' spec.ignore 'wxCustomDataObject::GetSize' spec.ignore 'wxCustomDataObject::TakeData' # all available in bases spec.ignore 'wxTextDataObject::GetFormatCount' spec.ignore 'wxTextDataObject::GetFormat' spec.ignore 'wxTextDataObject::GetAllFormats' %w[wxDataObjectComposite wxBitmapDataObject wxFileDataObject wxTextDataObject wxImageDataObject wxURLDataObject].each do |kls| # SWIG gets confused and doesn't realise that various virtual methods # from wxDataObject are implemented fully in these subclasses, and so, # believing it to be abstract doesn't provide an allocator for this # class. This overrides this. spec.make_concrete kls end # Once a DataObject has been added, it belongs to the wxDataObjectComposite object, # and will be freed by it on destruction. spec.disown 'wxDataObjectSimple* dataObject' # Add GC management for the DataObjectSimple instances added to a DataObjectComposite instance. spec.add_header_code <<~__HEREDOC #include #include typedef std::vector data_object_list_t; typedef std::map composite_data_object_map_t; static composite_data_object_map_t CompositeDataObject_Map; static void GC_mark_wxCompositeDataObject(void* ptr) { composite_data_object_map_t::iterator it = CompositeDataObject_Map.find(static_cast (ptr)); if (it != CompositeDataObject_Map.end()) { data_object_list_t &do_list = it->second; for (VALUE data_obj : do_list) { #ifdef __WXRB_DEBUG__ if (wxRuby_TraceLevel()>1) { void *c_ptr = (TYPE(data_obj) == T_DATA ? DATA_PTR(data_obj) : 0); std::wcout << "**** wxRuby_markCompositeDataObjects : " << it->first << "|" << (void*)c_ptr << std::endl; } #endif rb_gc_mark(data_obj); } } } // custom implementation for wxRuby so we can handle de-registering composites class WxRuby_DataObjectComposite : public wxDataObjectComposite { public: WxRuby_DataObjectComposite() : wxDataObjectComposite() {} virtual ~WxRuby_DataObjectComposite() { CompositeDataObject_Map.erase(this); } }; #if wxUSE_RICHTEXT #include #endif // Add custom object wrapper for DataObjectComposite#get_object result static VALUE wxRuby_WrapDataObjectSimple(wxDataObjectSimple* d_obj) { if (!d_obj) return Qnil; // check if we have this object tracked VALUE r_obj = SWIG_RubyInstanceFor(d_obj); if (r_obj != Qnil) { swig_class* sklass = (swig_class *) SWIGTYPE_p_wxDataObjectSimple->clientdata; if (rb_obj_is_kind_of(r_obj, sklass->klass)) return r_obj; } // Otherwise check the returned type and create a new object wrapper void* do_ptr; if ((do_ptr = dynamic_cast (d_obj))) { return SWIG_NewPointerObj(do_ptr, SWIGTYPE_p_wxBitmapDataObject, 0); } if ((do_ptr = dynamic_cast (d_obj))) { return SWIG_NewPointerObj(do_ptr, SWIGTYPE_p_wxImageDataObject, 0); } if ((do_ptr = dynamic_cast (d_obj))) { return SWIG_NewPointerObj(do_ptr, SWIGTYPE_p_wxCustomDataObject, 0); } if ((do_ptr = dynamic_cast (d_obj))) { return SWIG_NewPointerObj(do_ptr, SWIGTYPE_p_wxFileDataObject, 0); } if ((do_ptr = dynamic_cast (d_obj))) { return SWIG_NewPointerObj(do_ptr, SWIGTYPE_p_wxTextDataObject, 0); } #if wxUSE_HTML && (wxVERSION_NUMBER >= 3300) if ((do_ptr = dynamic_cast (d_obj))) { VALUE r_class = rb_eval_string("Wx::HTML::HTMLDataObject"); swig_type_info* swig_type = wxRuby_GetSwigTypeForClass(r_class); return SWIG_NewPointerObj(do_ptr, swig_type, 0); } #endif /** Leave these for now. RichText has special needs #if wxUSE_RICHTEXT if ((do_ptr = dynamic_cast (d_obj))) { VALUE r_class = rb_eval_string("Wx::RTC::RichTextBufferDataObject"); swig_type_info* swig_type = wxRuby_GetSwigTypeForClass(r_class); return SWIG_NewPointerObj(do_ptr, swig_type, 0); } #endif **/ return SWIG_NewPointerObj(SWIG_as_voidptr(d_obj), SWIGTYPE_p_wxDataObjectSimple, 0); } __HEREDOC # install GC marker spec.add_swig_code '%markfunc wxDataObjectComposite "GC_mark_wxCompositeDataObject";' # use custom implementation class spec.use_class_implementation 'wxDataObjectComposite', 'WxRuby_DataObjectComposite' # make sure to return the right derived type spec.map 'wxDataObjectSimple*' => 'Wx::DataObjectSimple' do map_out code: '$result = wxRuby_WrapDataObjectSimple($1);' end # disable generating the default Add method (keep docs) spec.ignore 'wxDataObjectComposite::Add', ignore_doc: false # Add custom Add implementation spec.add_extend_code 'wxDataObjectComposite', <<~__HEREDOC void add(VALUE rb_dataObject, bool preferred=false) { // convert simple object wxDataObjectSimple *simple_do; int res = SWIG_ConvertPtr(rb_dataObject, SWIG_as_voidptrptr(&simple_do), SWIGTYPE_p_wxDataObjectSimple, SWIG_POINTER_DISOWN); if (!SWIG_IsOK(res)) { rb_raise(rb_eArgError, "Expected Wx::DataObjectSimple for 1"); } // add new simple instance to registration for this composite CompositeDataObject_Map[$self].push_back(rb_dataObject); // add to composite $self->Add(simple_do); } __HEREDOC end end # class DataObject def doc_generator DataObjectDocGenerator.new(self) end end # class Director class DataObjectDocGenerator < DocGenerator def get_class_doc(clsdef) if clsdef.name == 'wxDataObjectSimple' [] else super end end protected :get_class_doc def get_method_doc(mtd) if Extractor::MethodDef === mtd && mtd.class_name == 'wxDataObject' && mtd.name == 'GetDataSize' {} else super end end protected :get_method_doc end end # module WXRuby3