jhass / crystal-gobject

gobject-introspection for Crystal
BSD 3-Clause "New" or "Revised" License
127 stars 13 forks source link

using event_handler_set #8

Closed aeosynth closed 4 years ago

aeosynth commented 8 years ago

hello again, here's another Lib usage:

def handler(event, data)
  puts event.value.type
end

LibGdk.event_handler_set ->handler, nil, nil

you can add this to the gdk_window sample, anywhere before GLib::MainLoop

jhass commented 8 years ago

I did some work on unions and added a nicer wrapper for that function, now you can:

Gdk::Event.on_event do |event|
  puts event.event_type
end

I also looked a bit into generating nicer wrappers for functions that take callbacks automatically, though that's quite hard since we can't pass a closured proc to a C function as, we need to pass the closure data via the usually present data attribute. Depending on the function we might even need to keep a reference to it ourselves (That's what ClosureDataManager is for) and register the usually present destroy or notify callback to free it again. So the generator would need to make a lot of guesses based on the function signature, names and types thereof. Not impossible, but not easy and just writing a couple of wrappers by hand, like I did for connect and now handler_set is probably easier.

aeosynth commented 8 years ago

the wrapper is not very useful, as it creates generic events, which i have to cast to more specific events:

key_event = event.to_unsafe.as(LibGdk::Event*).value.key

# can't cast Gdk::Event to Gdk::EventKey
key_event = event.as(Gdk::EventKey)

honestly the raw Lib bindings are fine for me; i can look up the official gdk docs and make a straightforward translation.

jhass commented 8 years ago

Well, there's no hierarchy info in the typelib for GdkEvent and its "subtypes", that is because it's a union and not a proper GObject. For now I added convenience getters for the unions fields, so now you can:

Gdk::Event.on_event do |event|
  case event.event_type
  when .expose?
    puts "Expose count: #{event.expose.count}"
  when .setting?
    puts "Setting #{event.setting.name} is #{event.setting.action}"
  else
    puts "Unhandled event: #{event.event_type}"
  end
end

Yielding the correct subtype directly would not really result in any cleaner interface:

Gdk::Event.on_event do |event|
  case event
  when Gdk::EventExpose
    puts "Expose count: #{event.count}"
  when Gdk::EventSetting
    puts "Setting #{event.name} is #{event.action}"
  else
    puts "Unhandled event: #{event.event_type}"
  end
end

I think the cost of manually maintaining the complete list of event_type -> GdkEvent* mappings doesn't out-weight the difference, in fact I can see benefits to the former interface, it doesn't create any Crystal union and the getter makes it perhaps a little more obvious that a event specific field is accessed.

My aim for this library is that you don't have to use the Lib bindings and instead provide safe interfaces to it, that is there ultimately shouldn't be any pointer casts or to_unsafe calls necessary by the user, they should only use the memory safe parts of Crystal, the unsafe parts should be abstracted away. But that doesn't mean I can forbid you to do that, nor does it mean I can force you to use the wrappers. Of course you're free to bypass them completely and operate just on the generated Libs.