Papierkorb / qt5.cr

Qt5 bindings for Crystal, based on Bindgen
Mozilla Public License 2.0
211 stars 20 forks source link

Qt signal handlers are not using type converters #32

Closed HertzDevil closed 4 years ago

HertzDevil commented 4 years ago

Consider for example void QWidget::windowTitleChanged(const QString &title) and the following snippet

require "qt5"

qApp = Qt::Application.new
wnd = Qt::Widget.new
wnd.on_window_title_changed do |str|
  puts str
end
wnd.window_title = "string arg test"
wnd.show
Qt::Application.exec

This might or might not crash, and will most likely print a bunch of garbage, because str is not really a String but a Qt::Binding::CrystalString instead. The definition of on_window_title_changed is

module Qt
  lib Binding
    fun bg_QWidget_CONNECT_windowTitleChanged_CrystalProc_void_const_QString_R(_self_ : QWidget*, _proc_ : CrystalProc) : QMetaObjectConnection*
  end

  class Widget
    def on_window_title_changed(&_proc_ : Proc(String, Void)) : SignalConnection
      SignalConnection.new(unwrap: Binding.bg_QWidget_CONNECT_windowTitleChanged_CrystalProc_void_const_QString_R(self, BindgenHelper.wrap_proc(_proc_)))
    end
  end
end

The underlying C++ function is

extern "C" QMetaObject::Connection * bg_QWidget_CONNECT_windowTitleChanged_CrystalProc_void_const_QString_R(QWidget * _self_, CrystalProc<void, const CrystalString> _proc_) {
  return new (UseGC) QMetaObject::Connection (QObject::connect(_self_, (void(QWidget::*)(const QString &))&QWidget::windowTitleChanged, [_proc_](const QString & title){ _proc_(qstring_to_crystal(title)); }));
}

which also stops at Qt::Binding::CrystalString. Casting the string to that type inside the handler doesn't seem to work, but this will:

handler = ->(str : Qt::Binding::CrystalString) do
  puts Qt::Converter::QString.unwrap(str)
end
Qt::SignalConnection.new(unwrap: Qt::Binding.bg_QWidget_CONNECT_windowTitleChanged_CrystalProc_void_const_QString_R(wnd, Qt::BindgenHelper.wrap_proc(handler)))

and the converter Qt::Converter::QString is specified right at the top of config/types.yml:

types: # Type rewrite rules
  QString: # Convert QString instances using that:
    converter: Qt::Converter::QString

All this suggests that _proc_ is implicitly converted from Proc(String, Void) in Crystal to CrystalProc<void, const CrystalString> in C++, and the converter is never invoked. This is tested on linux-gnu-x86_64-qt5.12 + Clang 9 but the same should apply to all Qt bindings.

HertzDevil commented 4 years ago

Moving to Bindgen: https://github.com/Papierkorb/bindgen/issues/62