Forum: Ruby-Gnome 2 Docs for boxed types and signal handling???

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Andrew S. Townley (Guest)
on 2008-10-17 22:29
(Received via mailing list)
Hmmmm.... the lack of any type of responses to my previous questions
isn't giving me a great deal of confidence that I'll be able to
accomplish my task.  However, I'll ask again:

Is there any kind of documentation/tutorial around about how you create
a new set of bindings?  I can appreciate that the macros and all of the
supporting functions are really there for a reason, but so far, I
haven't really been able to figure out what I'm supposed to do beyond
cloning the boilerplate-like code in the existing bindings.

I figured out a way to get my struct problem solved using the raw Ruby
Data_Wrap_Struct and Data_Get_Struct, but I'm sure that I should be
doing it a different way.  I've seen places in the source where some
helper structs were created (GdkAtomData) so that things could
participate in the various BOXED macros, but I'm not really sure if
that's the path I need to go down or not.  How do I decide?

At the moment, I have basic class/method functionality working fine for
normal types.  This is pretty-much what I can do from cloning the
bindings that I see.  However, I'm now having trouble trying to figure
out how to marshal my struct for callback functions.  This is
essentially a show-stopper for what I'm doing at the moment.

I've tried the G_DEF_SIGNAL_FUNC approach, but I'm sure that since I
didn't use the appropriate gobject/boxed magic earlier, I can't use this
macro.  I've no idea where to go from here.

I've now spent about 10 hours on this trying to figure out what I need
to do to get this part of the binding working.  I really don't think
what I'm trying to do is that hard, however, I haven't found the key to
unlock all of the magic in the core ruby-gnome2 libraries.

After figuring out how to deal with arbitrary structures and callbacks,
I think I've more-or-less got an understanding of how to implement a new
library binding, and I can probably finish the rest of what I need in a
day or two.

*ANY* ideas/assistance with how to attack the above would be really,
really appreciated.

Thanks in advance,

ast
--
Andrew S. Townley <removed_email_address@domain.invalid>
http://atownley.org
Kouhei S. (Guest)
on 2008-10-18 09:36
(Received via mailing list)
Hi,

In <1224268107.12922.62.camel@linna>
  "[ruby-gnome2-devel-en] Docs for boxed types and signal handling???"
on Fri, 17 Oct 2008 18:28:27 +0000,
  "Andrew S. Townley" <removed_email_address@domain.invalid> wrote:

> Is there any kind of documentation/tutorial around about how you create
> a new set of bindings?

Did you see them?
  http://ruby-gnome2.sourceforge.jp/hiki.cgi?How+to+...
  http://ruby-gnome2.sourceforge.jp/hiki.cgi?Naming+...

Thanks,
--
kou
Andrew S. Townley (Guest)
on 2008-10-18 11:17
(Received via mailing list)
Kou,

Thanks for all the responses!  I really appreciate it.  Sorry for the
frustration...

On Sat, 2008-10-18 at 14:35 +0900, Kouhei S. wrote:
>   http://ruby-gnome2.sourceforge.jp/hiki.cgi?How+to+...
>   http://ruby-gnome2.sourceforge.jp/hiki.cgi?Naming+...
>

No, obviously.  Thanks for pointing them out.  After my pain with trying
to navigate the API documentation on the Hiki as a user of the library,
I don't have the reflex to check there for information anymore.  Is it
possible to easily mirror this somewhere else, or locally at least?

Can I suggest that this information should also be part of the source
tree?  Is there a reason why it isn't there?

Having had a quick scan of the docs, I still think I have one issue that
isn't addressed.

One of the types I'm dealing with should never be created in Ruby code.
It's allocated inside the library by another class.  What's the best way
to deal with this to ensure that there aren't memory leaks?

At the moment, all I could come up with was using the standard ruby
allocation function to allocate a copy of the structure.  Where I get
the newly created structures, I'm essentially doing an object copy, e.g.
MEMCPY of the structure contents to the one managed by ruby.

This works, and the one managed by ruby is deleted, but I haven't
figured out a good way to free the original.  It seems that all of what
I've read so far assumes that you're going to create the instance
directly instead of having it created by a factory object.

If this isn't clear, it looks something like this:

factory = factory_class_new();
sstruct = factory_class_create_struct(factory);

To clean things up, you're supposed to do:

struct_class_destroy(sstruct);

Any suggestions?

It doesn't look like this is covered in the "Implement class which does
not conform to GType system" section.

One more question that I probably also missed in the docs on the Hiki:
is there a recommended mechanism for producing the class/method
documentation?  I can add the RDoc to the C source, but it doesn't seem
like that's how the rest of the library works.

Thanks in advance, and, again, sorry for missing the docs.

ast
--
Andrew S. Townley <removed_email_address@domain.invalid>
http://atownley.org
Kouhei S. (Guest)
on 2008-10-18 19:11
(Received via mailing list)
Hi,

In <1224314229.12922.111.camel@linna>
  "Re: [ruby-gnome2-devel-en] Docs for boxed types and signal
handling???" on Sat, 18 Oct 2008 07:17:09 +0000,
  "Andrew S. Townley" <removed_email_address@domain.invalid> wrote:

> I don't have the reflex to check there for information anymore.  Is it
> possible to easily mirror this somewhere else, or locally at least?
>
> Can I suggest that this information should also be part of the source
> tree?  Is there a reason why it isn't there?

I wrote a reply for that:

In <removed_email_address@domain.invalid>
  "Re: [ruby-gnome2-devel-en] Additional info Re: Hopefully trivial
question regarding UIManager & Menu items" on Sat, 18 Oct 2008 15:29:57
+0900 (JST),
  Kouhei S. <removed_email_address@domain.invalid> wrote:

> You can get it as RD format:
>   % svn co https://ruby-gnome2.svn.sourceforge.net/svnroot/ru...
>
> You can see it by rbbr:
>   http://ruby-gnome2.sourceforge.jp/hiki.cgi?rbbr
>
> Put RD formatted documentation to rbbr's data
> dir. (e.g. /usr/share/rbbr/rd/, /usr/local/share/rbbr/rd/
> and so on)


> If this isn't clear, it looks something like this:
>
> factory = factory_class_new();
> sstruct = factory_class_create_struct(factory);
>
> To clean things up, you're supposed to do:
>
> struct_class_destroy(sstruct);
>
> Any suggestions?

I'm sorry but I couldn't understand. Could you show me an
example code that is executable?

> One more question that I probably also missed in the docs on the Hiki:
> is there a recommended mechanism for producing the class/method
> documentation?  I can add the RDoc to the C source, but it doesn't seem
> like that's how the rest of the library works.

I'm using update-rd.rb to generate template and update
documents:
  https://ruby-gnome2.svn.sourceforge.net/svnroot/ru...

Thanks,
--
kou
Andrew S. Townley (Guest)
on 2008-10-18 20:48
(Received via mailing list)
On Sun, 2008-10-19 at 00:09 +0900, Kouhei S. wrote:
> > You can see it by rbbr:
> >   http://ruby-gnome2.sourceforge.jp/hiki.cgi?rbbr
> >
> > Put RD formatted documentation to rbbr's data
> > dir. (e.g. /usr/share/rbbr/rd/, /usr/local/share/rbbr/rd/
> > and so on)

Sorry, Kouhei.  I got the replies out of order.  Cheers, and thanks for
the fix!

>
> I'm sorry but I couldn't understand. Could you show me an
> example code that is executable?

I guess the simplest example is here:

http://svn.gnome.org/viewvc/gtkhtml/trunk/gtkhtml/...

On line 121, the GtkHTMLStream is created through the call to
gtk_html_begin().

On line 79 or 82, the GtkHTMLStream is closed via the call to
gtk_html_stream_close().

I don't claim that it's pretty (or even correct), but you can see what
I'm doing either via

http://www.atownley.org/projects/ruby-gtkhtml3/bzr...
http://www.atownley.org/projects/ruby-gtkhtml3/bzr...

or via

bzr pull
http://www.atownley.org/projects/ruby-gtkhtml3/bzr...

and looking at the src/rbgthkthmlstream.c and rbgtkhtml.c files.

Like I said, this was the only approach that I could come up with that
didn't result in segfaults.  However, I'm interested in how to do it
more cleanly.

The "interesting" functions are:

in rbgtkhtml.c:

static VALUE
rb_gtk_html_stream_obj_from_struct(stream)
    GtkHTMLStream *stream;
{
    VALUE rval;
    GtkHTMLStream *rval_stream = NULL;

    printf("creating stream object\n");
    rval = rb_eval_string("Gtk::Html::Stream.new");
    Data_Get_Struct(rval, GtkHTMLStream, rval_stream);
    MEMCPY(rval_stream, stream, GtkHTMLStream, 1);
    return rval;
}

in rbgtkhtmlstream.c:

static void
rb_gtk_html_stream_free(stream)
    GtkHTMLStream *stream;
{
// FIXME:  How do we tell if we've already been destroyed?
//    printf("destroying stream: %p\n", stream);
//    gtk_html_stream_destroy(stream);
}

static VALUE
rb_gtk_html_stream_alloc(klass)
    VALUE klass;
{
    VALUE obj;
    GtkHTMLStream *stream = NULL;

    stream = gtk_html_stream_new(NULL, NULL, NULL, NULL, NULL);
    printf("created stream: %p\n", stream);
    obj = Data_Wrap_Struct(klass, NULL, rb_gtk_html_stream_free,
stream);
    return obj;
}

Is this enough to go on?  It really needs to be fixed because each time
you request a separate resource from within a given HTML document, the
stream_from_struct function is called.  It was the only way I could come
up with to get the block parameter marshalling to work, but I'm positive
that the original structure is leaking somewhere.

I also had to remove the rb_gtk_html_stream_free functionality because
the stream is destroyed within the gtk_html_stream_close call, but I
don't have any way to tell if there aren't streams created that aren't
closed.  With the code uncommented, the stream was getting freed twice.

Any suggestions/advice would be appreciated.

> > One more question that I probably also missed in the docs on the Hiki:
> > is there a recommended mechanism for producing the class/method
> > documentation?  I can add the RDoc to the C source, but it doesn't seem
> > like that's how the rest of the library works.
>
> I'm using update-rd.rb to generate template and update
> documents:
>   https://ruby-gnome2.svn.sourceforge.net/svnroot/ru...

I'll have a look at that.  Thanks for the pointer.

Cheers,

ast
--
Andrew S. Townley <removed_email_address@domain.invalid>
http://atownley.org
Robert H. (Guest)
on 2008-10-18 23:23
"Hmmmm.... the lack of any type of responses to my previous questions
isn't giving me a great deal of confidence that I'll be able to
accomplish my task."

Hi Andrew,

rest assured I pretty much read (almost) everything on the list :-)

but I often can not help because I do not really know the answer :(
(I am still learning C in little baby steps as well.... Ruby is so
much easier than C for my brain...)
Andrew S. Townley (Guest)
on 2008-10-19 00:36
(Received via mailing list)
On Sat, 2008-10-18 at 21:23 +0200, Marc H. wrote:
> Hi Andrew,
>
> rest assured I pretty much read (almost) everything on the list :-)
>
> but I often can not help because I do not really know the answer :(
> (I am still learning C in little baby steps as well.... Ruby is so
> much easier than C for my brain...)

Cheers for that, Marc.  Kou seems to be on the case, and I really do
appreciate his assistance.  Hopefully, with his latest replies, I'll
have what I need to finish the binding and get back to building my
app! :)

My problem is my C's rusty, and I'm not really familiar with all of the
GLib API, idioms and semantics.  As Martin F. once quipped, "these
day's, I'm too lazy to take out my own garbage." (or something to that
effect).  As such, I try and keep to languages like Ruby, Java, C# and
Python, leaving the C to people more accustomed to segfaults.  Somehow,
stack traces just don't feel quite as bad.... ;)
--
Andrew S. Townley <removed_email_address@domain.invalid>
http://atownley.org
Kouhei S. (Guest)
on 2008-10-19 06:01
(Received via mailing list)
Hi,

In <1224348418.15929.21.camel@linna>
  "Re: [ruby-gnome2-devel-en] Docs for boxed types and signal
handling???" on Sat, 18 Oct 2008 17:46:57 +0100,
  "Andrew S. Townley" <removed_email_address@domain.invalid> wrote:

> bzr pull http://www.atownley.org/projects/ruby-gtkhtml3/bzr...

What about the following patch?

=== modified file 'src/lib/gtkhtml3.rb'
--- src/lib/gtkhtml3.rb  2008-10-17 22:13:11 +0000
+++ src/lib/gtkhtml3.rb  2008-10-19 01:45:23 +0000
@@ -9,23 +9,3 @@
     self.__end(stream, status)
   end
 end
-
-class Gtk::Html::Stream
-  def initialize
-    @closed = false
-  end
-
-  def <<(data)
-    write(data)
-  end
-
-  def closed?
-    @closed
-  end
-
-  def close(status = true)
-    return if @closed
-    self.__close(status)
-    @closed = true
-  end
-end

=== modified file 'src/rbgtkhtml.c'
--- src/rbgtkhtml.c  2008-10-17 21:41:26 +0000
+++ src/rbgtkhtml.c  2008-10-19 01:56:55 +0000
@@ -19,12 +19,10 @@
     GtkHTMLStream *stream;
 {
     VALUE rval;
-    GtkHTMLStream *rval_stream = NULL;

     printf("creating stream object\n");
     rval = rb_eval_string("Gtk::Html::Stream.new");
-    Data_Get_Struct(rval, GtkHTMLStream, rval_stream);
-    MEMCPY(rval_stream, stream, GtkHTMLStream, 1);
+    DATA_PTR(rval) = stream;
     return rval;
 }


=== modified file 'src/rbgtkhtmlstream.c'
--- src/rbgtkhtmlstream.c  2008-10-17 21:41:26 +0000
+++ src/rbgtkhtmlstream.c  2008-10-19 01:57:33 +0000
@@ -20,8 +20,8 @@
     GtkHTMLStream *stream;
 {
 // FIXME:  How do we tell if we've already been destroyed?
-//    printf("destroying stream: %p\n", stream);
-//    gtk_html_stream_destroy(stream);
+   printf("destroying stream: %p\n", stream);
+   gtk_html_stream_destroy(stream);
 }

 static VALUE
@@ -29,11 +29,9 @@
     VALUE klass;
 {
     VALUE obj;
-    GtkHTMLStream *stream = NULL;

-    stream = gtk_html_stream_new(NULL, NULL, NULL, NULL, NULL);
-    printf("created stream: %p\n", stream);
-    obj = Data_Wrap_Struct(klass, NULL, rb_gtk_html_stream_free,
stream);
+    printf("created stream\n");
+    obj = Data_Wrap_Struct(klass, NULL, rb_gtk_html_stream_free, NULL);
     return obj;
 }

@@ -53,14 +51,19 @@
 }

 static VALUE
-rb_gtk_html_stream_close(self, status)
-    VALUE self;
+rb_gtk_html_stream_close(int argc, VALUE *argv, VALUE self)
 {
-    GtkHTMLStream   *stream;
+    GtkHTMLStream *stream;
+    VALUE status;
+
+    rb_scan_args(argc, argv, "01", &status);
+
     Data_Get_Struct(self, GtkHTMLStream, stream);
+    if (!stream)
+  return self;

     printf("stream_close: %p\n", stream);
-    if(RVAL2CBOOL(status))
+    if (RVAL2CBOOL(status))
     {
         gtk_html_stream_close(stream, GTK_HTML_STREAM_OK);
     }
@@ -68,6 +71,7 @@
     {
         gtk_html_stream_close(stream, GTK_HTML_STREAM_ERROR);
     }
+    DATA_PTR(self) = NULL;

     return self;
 }
@@ -84,6 +88,6 @@

     /* Writing */
     rb_define_method(klass, "write", rb_gtk_html_stream_write, 1);
-    rb_define_method(klass, "__close", rb_gtk_html_stream_close, 1);
+    rb_define_method(klass, "close", rb_gtk_html_stream_close, -1);
 }



Thanks,
--
kou
Andrew S. Townley (Guest)
on 2008-10-19 13:54
(Received via mailing list)
Hi Kou,

Thanks for the patch.

On Sun, 2008-10-19 at 11:00 +0900, Kouhei S. wrote:
> === modified file 'src/lib/gtkhtml3.rb'
> -  end
> -    return if @closed
> -    self.__close(status)
> -    @closed = true
> -  end
> -end

A few questions:

1) Since the above is now gone, does the Stream object still support the
<< operator?  Seems to me that it'd be a handy thing to have.

2) The reason I didn't just expose the close method directly into Ruby
space is that when you close the stream using gtk_html_stream_close, it
actually calls gtk_html_stream_destroy.  Therefore, calling close
multiple times crashes the Ruby interpreter with a segfault.  The same
thing was happening during garbage collection when this function was
called after I'd called stream.close in the ruby code.  That was the
main reason I'd commented it out.

I put the @closed sentinel there to allow me to ensure that normal usage
wouldn't cause crashes.  Is there a reason that you took this out?

>      rval = rb_eval_string("Gtk::Html::Stream.new");
> @@ -20,8 +20,8 @@
>      GtkHTMLStream *stream;
>  {
>  // FIXME:  How do we tell if we've already been destroyed?
> -//    printf("destroying stream: %p\n", stream);
> -//    gtk_html_stream_destroy(stream);
> +   printf("destroying stream: %p\n", stream);
> +   gtk_html_stream_destroy(stream);
>  }

I'm still not convinced about this one, because this will call
stream_destroy twice if the stream was closed normally with the ruby
close method.

What I think is really needed is a way from within this function to
determine if the stream was closed or not.  Is there a way to define
finalizers?  If so, the finalizer could check the status of the @closed
sentinel and close the stream, thus ensuring that it was destroyed
appropriately.

I guess the alternative is to add another, intermediate structure like
this:

struct StateTrackingStruct
{
  GtkHTMLStream  *stream;
  gboolean  closed;
}

and use it instead of the raw GtkHTMLStream structure in the wrapper
methods.

What do you think would make the most sense?

> +    printf("created stream\n");
> +rb_gtk_html_stream_close(int argc, VALUE *argv, VALUE self)
>
> +    DATA_PTR(self) = NULL;
>
>      return self;
>  }
> @@ -84,6 +88,6 @@
>
>      /* Writing */
>      rb_define_method(klass, "write", rb_gtk_html_stream_write, 1);
> -    rb_define_method(klass, "__close", rb_gtk_html_stream_close, 1);
> +    rb_define_method(klass, "close", rb_gtk_html_stream_close, -1);
>  }

I think the key thing I was missing was the DATA_PTR macro.  I didn't
see a reference to it in the Pickaxe (2nd ed.), but that's exactly what
I was looking for.

If I used this in the rbgtkhtml.c:rb_gtk_html_stream_obj_from_struct
function instead, I might be able to eliminate part of the problem,
since it was effectively duplicating most of what was happening in the
rbgtkhtmlstream.c:rb_gtk_html_stream_alloc function anyway.

Actually, the more I think about it, the managed structure approach is
probably the only way to ensure that if a user doesn't close the stream,
it will get properly destroyed.  Does this make sense?

Cheers,

ast
--
Andrew S. Townley <removed_email_address@domain.invalid>
http://atownley.org
Kouhei S. (Guest)
on 2008-10-19 14:37
(Received via mailing list)
Hi,

In <1224409996.15929.58.camel@linna>
  "Re: [ruby-gnome2-devel-en] Docs for boxed types and signal
handling???" on Sun, 19 Oct 2008 10:53:16 +0100,
  "Andrew S. Townley" <removed_email_address@domain.invalid> wrote:

> A few questions:
>
> 1) Since the above is now gone, does the Stream object still support the
> << operator?  Seems to me that it'd be a handy thing to have.

It's my mistake. Use rb_define_alias().

> 2) The reason I didn't just expose the close method directly into Ruby
> space is that when you close the stream using gtk_html_stream_close, it
> actually calls gtk_html_stream_destroy.  Therefore, calling close
> multiple times crashes the Ruby interpreter with a segfault.  The same
> thing was happening during garbage collection when this function was
> called after I'd called stream.close in the ruby code.  That was the
> main reason I'd commented it out.

Really? Please show me an executable test script that
reproduces the problem.


Thanks,
--
kou
Andrew S. Townley (Guest)
on 2008-10-19 14:58
(Received via mailing list)
On Sun, 2008-10-19 at 19:36 +0900, Kouhei S. wrote:
>
> It's my mistake. Use rb_define_alias().

Ok.  I will.

> > 2) The reason I didn't just expose the close method directly into Ruby
> > space is that when you close the stream using gtk_html_stream_close, it
> > actually calls gtk_html_stream_destroy.  Therefore, calling close
> > multiple times crashes the Ruby interpreter with a segfault.  The same
> > thing was happening during garbage collection when this function was
> > called after I'd called stream.close in the ruby code.  That was the
> > main reason I'd commented it out.
>
> Really? Please show me an executable test script that
> reproduces the problem.

It should happen if you run the sample/test-stream.rb script with your
code.  I didn't apply your patch as-is, but I did try the approach with
using an intermediate C structure instead of the GtkHTMLStream directly
and binding it using the DATA_PTR macro in the obj_from_stream function.
I just tested it, and I'm seeing both the original streams from the
GtkHTML begin and my intermediate structures being freed as expected.

I'll make the change to the close method and the aliases after lunch.
Once I've done that, I'll put up a new branch for you to have a look at.

On the surface, it looks like this particular issue is sorted.  I'll
have to digest your other suggestions about the callbacks, but I don't
need the editing support just yet.

Thanks very much for your help!

ast
--
Andrew S. Townley <removed_email_address@domain.invalid>
http://atownley.org
Kouhei S. (Guest)
on 2008-10-19 15:21
(Received via mailing list)
Hi,

In <1224413816.15929.64.camel@linna>
  "Re: [ruby-gnome2-devel-en] Docs for boxed types and signal
handling???" on Sun, 19 Oct 2008 11:56:56 +0100,
  "Andrew S. Townley" <removed_email_address@domain.invalid> wrote:

>
> It should happen if you run the sample/test-stream.rb script with your
> code.

It should not happen.

>        I didn't apply your patch as-is

Why? Please reply after you tried and confirmed.


Thanks,
--
kou
Andrew S. Townley (Guest)
on 2008-10-19 18:26
(Received via mailing list)
On Sun, 2008-10-19 at 20:21 +0900, Kouhei S. wrote:
> > >
> > > Really? Please show me an executable test script that
> > > reproduces the problem.
> >
> > It should happen if you run the sample/test-stream.rb script with your
> > code.
>
> It should not happen.

You're right.  I stand corrected.  I had tried something similar last
night, but I didn't have any luck.  My apologies.

> >        I didn't apply your patch as-is
>
> Why? Please reply after you tried and confirmed.

Because I didn't realize that apparently the free function isn't called
if the pointer for DATA_PTR(obj) is NULL.  Is this correct?

I reverted back to your original approach.  It's cleaner, and it works
the way it is.

Previous version with intermediate structure:
http://www.atownley.org/projects/ruby-gtkhtml3/bzr...

Current version incorporating your original patch:
http://www.atownley.org/projects/ruby-gtkhtml3/bzr...

I'm pretty sure it doesn't leak now, but I need to go back and add some
more robustness in the event that a Gtk::Html::Stream object is created
by the user.  I'm not sure what the library will do in this case yet.

What I missed last night was setting the DATA_PTR(obj) = NULL, so the
free function was always getting called, resulting in the crashes--no
matter what I did.  I did try to use the value of the stream pointer as
a sentinel, but I guess because I wasn't aware of both the DATA_PTR
macro and the behavior if the pointer was NULL, I wasn't getting things
to work.

The intermediate version from 12:31 does work, but it isn't as simple as
your approach.

Thanks for all your help, as well as your patch.

Cheers,

ast
--
Andrew S. Townley <removed_email_address@domain.invalid>
http://atownley.org
This topic is locked and can not be replied to.