Skip to content
This repository has been archived by the owner on Aug 13, 2019. It is now read-only.

Callback parameters (and mapping plain-old-data structs to Go) #14

Open
raichu opened this issue Sep 19, 2013 · 8 comments
Open

Callback parameters (and mapping plain-old-data structs to Go) #14

raichu opened this issue Sep 19, 2013 · 8 comments

Comments

@raichu
Copy link

raichu commented Sep 19, 2013

I'm a bit confused about how to obtain the parameters in a signal handler. As an example (source):

void frame_callback(GtkWindow *window, 
      GdkEvent *event, gpointer data)
{
   int x, y;
   char buf[10];
   x = event->configure.x;
   y = event->configure.y;
   sprintf(buf, "%d, %d", x, y);
   gtk_window_set_title(window, buf);
}

...

 g_signal_connect(G_OBJECT(window), "configure-event",
        G_CALLBACK(frame_callback), NULL);

How can I access the event->configure struct? According to the signal example, the only parameter I can pass to the event handler function in Go is ctx *glib.CallbackContext. Does ctx.Arg(0) correspond to the C-pointer event above?

If that is the case (about which I'm not sure), the type of ctx.Arg(0) is CallbackArg but I need to add a function like

func (c CallbackArg) Configure() *EventConfigure {
    return wrapEventConfigure(event->configure)
}

and EventConfigure struct?

Similar to the issue with GdkRectangle, if we simply define

type EventConfigure {
    C.GdkEventConfigure
}

it's fields won't be accessible to user code. Maybe it's time to establish a convention for this?

@raichu
Copy link
Author

raichu commented Sep 19, 2013

Whoops. I can't do that apparently, because CallbackArg is in glib package whereas Event and related stuff are in gdk, and gdk uses glib already!

@raichu
Copy link
Author

raichu commented Sep 19, 2013

I just push some initial draft in 087681c
It can be used as

    w.Connect("configure-event", func(ctx *glib.CallbackContext) {
        ev := gdk.ToEvent(ctx.Arg(0))
        w := ev.Configure().Width
        ...
    })

EventConfigure is not compatible with the GtkEventConfigure (since C.int and enum are int32)

@jrick
Copy link
Member

jrick commented Sep 19, 2013

Yes, you've discovered one of the bigger issues with gotk3, and one that I want to fix when I get some more time. What I am thinking of doing is changing the callback func signature to actually expect the Go types for the same C types you would see, and then use type assertion or the reflect package and cast or use the wrap* functions to create the Go types we need for the C parameters.

Only issue I can see with this though is that it's not really type safe (just like C). What happens if your callback forces a *GtkWidget to be created, but what was actually passed was a gint? So, I'm still open on suggestions on how to best handle this.

edit: just to be clear, I'm not completely against type unsafeness as long as it's documented clearly. (glib.Object).Emit() is already type unsafe, for the same reasons as I explained above. Would love to find a good way to do this while still enforcing type safety, but with the limited information we can glean from a void, such is life.

@raichu
Copy link
Author

raichu commented Sep 20, 2013

Instead of having manual casting, maybe it's better to extend gdk.Event type.
One can verify the cast to an extent by checking the Type field of the GdkEvent (087681c is baby steps towards that direction).
But of course, the signature is a problem: glib package cannot have gdk.Event as a parameter since gdk uses glib.

@raichu
Copy link
Author

raichu commented Oct 5, 2013

What do you think about this?

I also checked his fork and there are too many things to merge. Branches are diverging, so hopefully you'll start doing some merging :)

@raichu
Copy link
Author

raichu commented Oct 11, 2013

Ping? :)

@jrick
Copy link
Member

jrick commented Oct 11, 2013

I took a look at his branch and he has a lot of good work done. I also checked his blog, where he explained the design desicion he took and how he went out about implementing it, and there were some other comments from him saying that he does think his work is ready for inclusion back into our branch. I welcome the change (and using GClosure looks better than the plan I had to solve this), but at the moment it doesn't seem ready to add.

I'll try to get in contact with him and see what the status of this feature is, and ask about inclusion into Conformal's repo.

@weberc2
Copy link
Contributor

weberc2 commented Aug 20, 2014

I'm not sure what you guys came up with, but I solved the problem this way:

// EventKey is a representation of GDK's GdkEventKey.
type EventKey struct {
       *Event
}

// Native returns a pointer to the underlying GdkEventKey.
func (v *EventKey) Native() uintptr {
       return uintptr(unsafe.Pointer(v.native()))
}

func (v *EventKey) native() *C.GdkEventKey {
       return (*C.GdkEventKey)(unsafe.Pointer(v.Event.native()))
}

func (v *EventKey) KeyVal() uint {
       c := v.native().keyval
       return uint(c)
}

The fields aren't user accessible, but we can expose them as methods. Also, by wrapping the EventKey around Event, you don't have to worry about Event.free() being called twice (maybe that's a non-issue? I'm too tired to think through the implications at the moment).

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants