Thread overview
Function pointer callback from C
Feb 26, 2007
Mike Johnson
Feb 26, 2007
Tyler Knott
(Solved) Re: Function pointer callback from C
Feb 26, 2007
Mike Johnson
Feb 26, 2007
Derek Parnell
Feb 26, 2007
Mike Johnson
Feb 26, 2007
Alan Knowles
February 26, 2007
Hello,

I've been beating my head against D's delegate support. I've probably read every mention in the docs and post on the news server multiple times and I'm just not getting it. Any help would be awesome.

I'm currently trying to connect a signal handler to a member function.

The member function needs access to the `this' pointer. The callback itself works, but I get undefined weirdness and crashes on trying to modify any D member variables.

(This is GTK.)

The signal handler is installed:

        this.sourceBuffer.connectSignal("changed",
                                        &on_sv_changed);

The function doing black magic:

    extern(C) public void connectSignal(
        char[] signalName,
        void delegate(int* widget, gpointer data) func,
        int data = 0,
        GConnectFlags flags = cast(GConnectFlags) 0) {

        g_signal_connect_data(this.self,
                              String.stringz(signalName),
                              func.funcptr,
                              cast(gpointer) data,
                              cast(int *) 0,
                              flags);
    }

Of course, I can pass void* data through the gpointer variable. But I can't convert a class instance to an pointer... which would be really *cough* cool *cough* :-) But maybe something else?

The signal handler itself:

    private extern(C) void on_sv_changed(int *widget, int *data) {
        printf("changed\n");
	this.changed = true; // GTK spews warnings and dies weirdly
    }

Thanks so much,
Mike Johnson
February 26, 2007
Mike Johnson wrote:
> 
> Of course, I can pass void* data through the gpointer variable. But I can't convert a class instance to an pointer... which would be really *cough* cool *cough* :-) But maybe something else?
> 

You can't convert /instances/, but you can cast any object /references/ to void pointers (because references are just pointers with syntactic sugar that hides all the details).  When you cast back from void* to a class type, D even checks to make sure it's a sane cast (the cast will return null if it's not sane).  The only caveat is that you're going to be careful to keep a reference to that object in memory the GC is aware of, otherwise it could get prematurely collected and cause weird runtime crashes.
February 26, 2007
On Sun, 25 Feb 2007 22:12:51 -0800, Mike Johnson wrote:

> The function doing black magic:
> 
>      extern(C) public void connectSignal(

 . . .

> The signal handler itself:
> 
>      private extern(C) void on_sv_changed(int *widget, int *data) {

Why do you use "extern (C)" ?

-- 
Derek
(skype: derek.j.parnell)
Melbourne, Australia
"Justice for David Hicks!"
26/02/2007 5:35:23 PM
February 26, 2007
Aw, geez. You're right. Works perfectly. I guess I misunderstood something I had read.

Thanks,
Mike

For google cache:

connect the signal:

        this.sourceBuffer.connectSignal("changed",
                                        &on_sv_changed,
                                        cast(gpointer) this);

callback:

    private extern(C) void on_sv_changed(int *widget, gpointer data) {
        printf("changed\n");

        GtkSourceView v = cast(GtkSourceView) data;
        if(v)
            v.changed = true;
    }


Tyler Knott wrote:
> Mike Johnson wrote:
>>
>> Of course, I can pass void* data through the gpointer variable. But I can't convert a class instance to an pointer... which would be really *cough* cool *cough* :-) But maybe something else?
>>
> 
> You can't convert /instances/, but you can cast any object /references/ to void pointers (because references are just pointers with syntactic sugar that hides all the details).  When you cast back from void* to a class type, D even checks to make sure it's a sane cast (the cast will return null if it's not sane).  The only caveat is that you're going to be careful to keep a reference to that object in memory the GC is aware of, otherwise it could get prematurely collected and cause weird runtime crashes.
February 26, 2007
I was having a lot of trouble getting the delegate declaration to work and dmd was saying something about not implicitly converting "void (C *) blah".

I didn't know how to declare a delegate with C conventions. When I added the extern(c), it works. I'm not sure I understand why yet.

Here's the error message without extern:
mainwindow.d(43): function gtk.gtkwidget.GtkWidget.connectSignal (char[],void delegate(int* widget, void* data),void*,GConnectFlags) does not match parameter types (char[11],void delegate(int* widget, void* data),void*,GConnectFlags)
mainwindow.d(44): Error: cannot implicitly convert expression (&this.on_toolNotebook_changePage) of type void delegate(int* widget, void* data) to void delegate(int* widget, void* data)

To my eyes, those types look the same. *shrugs*

Derek Parnell wrote:
> On Sun, 25 Feb 2007 22:12:51 -0800, Mike Johnson wrote:
> 
>> The function doing black magic:
>>
>>      extern(C) public void connectSignal(
> 
>  . . .
> 
>> The signal handler itself:
>>
>>      private extern(C) void on_sv_changed(int *widget, int *data) {
> 
> Why do you use "extern (C)" ?
> 
February 26, 2007
Did you know Ant has committed the SourceView bindings to subversion:

http://svn.dsource.org/projects/dui/trunk/gtkD/srcsv/gsv/

The bindings for addOnChanged() are in TextBuffer http://svn.dsource.org/projects/dui/trunk/gtkD/src/gtk/TextBuffer.d

Regards
Alan


Mike Johnson wrote:
> Hello,
> 
> I've been beating my head against D's delegate support. I've probably read every mention in the docs and post on the news server multiple times and I'm just not getting it. Any help would be awesome.
> 
> I'm currently trying to connect a signal handler to a member function.
> 
> The member function needs access to the `this' pointer. The callback itself works, but I get undefined weirdness and crashes on trying to modify any D member variables.
> 
> (This is GTK.)
> 
> The signal handler is installed:
> 
>         this.sourceBuffer.connectSignal("changed",
>                                         &on_sv_changed);
> 
> The function doing black magic:
> 
>     extern(C) public void connectSignal(
>         char[] signalName,
>         void delegate(int* widget, gpointer data) func,
>         int data = 0,
>         GConnectFlags flags = cast(GConnectFlags) 0) {
> 
>         g_signal_connect_data(this.self,
>                               String.stringz(signalName),
>                               func.funcptr,
>                               cast(gpointer) data,
>                               cast(int *) 0,
>                               flags);
>     }
> 
> Of course, I can pass void* data through the gpointer variable. But I can't convert a class instance to an pointer... which would be really *cough* cool *cough* :-) But maybe something else?
> 
> The signal handler itself:
> 
>     private extern(C) void on_sv_changed(int *widget, int *data) {
>         printf("changed\n");
>     this.changed = true; // GTK spews warnings and dies weirdly
>     }
> 
> Thanks so much,
> Mike Johnson