GTK signals in Ruby

Hello,

After investigating what Gtk::Builder does with callbacks I figured
out there are issues.

The first issue is mismatch between GTK C callbacks and GTK Ruby
callbacks.

In C the GTK functions have a required first argument which is pointer
to self. This is because C has no notion of object and self has to be
passed explicitly.

Then in C to get rid of a window you call gtk_widget_destroy(window)
but in ruby you call window.destroy meaning that methods take one
fewer argument than gtk C functions.

This is not accounted for by signal_connect in Ruby.

In C when you connect a signal the first argument passed to the
handler is the object that triggered the signal and it is passed as
pointer to that kind of object. Obviously, this is meant to be the
self pointer. If the signal passes additional data or the user
supplied additional data when connecting the signal this is passed in
additional arguments. When the signal is connected as swapped the user
data and self is swapped when calling the callback.

Now in Ruby you don’t connect a function, you connect a method. This
method is already attached to an object - ‘self’. The first argument
passed in by GTK is totally redundant when the receiver is the object
which triggers the signal. Worse, when connecting existing GTK
function as a signal handler and it takes any arguments in Ruby
(unlike destroy which takes none because it takes only one in C) you
have to wrap it to discard this first argument. Now I don’t expect
this to be very common use but the possibility exists in C but not in
Ruby.

Another issue is argument count. While in C extra arguments are
ignored in Ruby they are ignored so long as you connect a block. When
you connect a method and GTK passes extra arguments your callback
fails and your application crashes. In C extra arguments are just
ignored which is often used. Again, you may need to wrap a method in
Ruby to make it a useful callback if the argument count does not
match.

Either of this could be resolved by inserting a wrapper automatically
at gobj_sig_connect_impl to discard any extra args and/or discard the
first arg when it is the same as the receiver.
I am not sure if this is useful and wanted feature, though. It would
change the API but if anybody used the cases that would change then
they would see these issues for sure. Still it’s easy enough to
rearrange arguments and redispatch the callbacks in user Ruby code,
too.

The other issue is with Gtk::Builder. Given the issues above it does a
lousy job of connecting signals, it can’t do any better. The results
are nowhere near what the C connections would be.

What works properly are signals with no user data (object in glade
files). Builder calls the user supplied block to get a handler and
connects that. The swapped option does not make any sense in this case
and is rightfully ignored.

What somewhat works are swapped signals with user data. These are
often used to connect a “close” button to call a function which
disposes of a window when the button is clicked. As these functions
take only the window in C and no arguments in Ruby this works OK - all
arguments are ignored. Connecting a GTK function that takes arguments
would not work this way because of the extra argument generated when
going between C and Ruby.

What is broken are signals with user data which are not swapped.
They are simply handled as swapped, the swapped flag is ignored
completely. I guess these should be connected just like signals
without user data but pass in the extra argument. It’s not quite
consistent with C gtk and never will be so long as the extra argument
is generated but at least it would be an useful option.

Thanks

Michal

I just wanted to say I’m interested on this topic, but don’t quite have
time right now to give a thoughtfull answer.

I’ll try to get back to this topic before the week-end.

regards

Simon

Michal S. wrote in post #1019765:

Hello,

After investigating what Gtk::Builder does with callbacks I figured
[…]
data and self is swapped when calling the callback.

Agreed.

Now in Ruby you don’t connect a function, you connect a method. This
method is already attached to an object - ‘self’. The first argument
passed in by GTK is totally redundant when the receiver is the object
which triggers the signal.

I agree with this : The fist argument looks like self. But it is not.
For example :

require ‘gtk2’

def on_click(object)
puts object.label
end

my_button = Gtk::Button.new(“My label”)
my_button.signal_connect(‘clicked’) do |button|
on_click(button) # should always work
on_click(my_button) # works, but bad practice
on_click(self) # does not work (on 1.9.2 at least)
end

my_button.signal_emit(‘clicked’)

It fails with “undefined method `label’ for main:Object”, because self
is not anymore the button when the callback is called.
That’s because ‘self’ is not the object the method is called from, but
the current object.
So, while you might think ‘self’ is ‘button’, it is not when the
callback is called.

Worse, when connecting existing GTK
function as a signal handler and it takes any arguments in Ruby
(unlike destroy which takes none because it takes only one in C) you
have to wrap it to discard this first argument. Now I don’t expect
this to be very common use but the possibility exists in C but not in
Ruby.

It seems you are confusing the ‘destroy’ method, and the ‘destroy’
signal.
The ‘destroy’ method takes no argument, but the ‘destroy’ signal does.

method :
http://ruby-gnome2.sourceforge.jp/hiki.cgi?Gtk%3A%3AObject#destroy
signal :
http://ruby-gnome2.sourceforge.jp/hiki.cgi?Gtk%3A%3AObject#destroy%3A+self

Also, I’m not sure I get your point. Are you talking about auto calling
a method on the widget based on event-type ?

Or are you talking about glade, and you want to directly connect the
handler you create as a method call to the object which received the
event ?
So, instead of :
builder.connect_signals {|handler| method(handler) }

you would like the default to be something like :
def my_connect(handler, *args)
args[0].send(handler)
end

Am I right ?

Another issue is argument count. While in C extra arguments are
ignored in Ruby they are ignored so long as you connect a block. When
you connect a method and GTK passes extra arguments your callback
fails and your application crashes. In C extra arguments are just
ignored which is often used. Again, you may need to wrap a method in
Ruby to make it a useful callback if the argument count does not
match.

Reading this, I really think you are trying to connect signal to methods
directly, and that you should write a custom method to use in
‘connect_signals’.

I’m not a C programmer, but, are you saying that I can call something
like this, and it will work ?

gtk_window_move(p_win, 100, 200, 345, “foo”, NULL);

I really doubt it.

Or is it gtk_builder in C which discards the extra args ?

Either of this could be resolved by inserting a wrapper automatically
at gobj_sig_connect_impl to discard any extra args and/or discard the
first arg when it is the same as the receiver.

I think it should be done by the programmer, not by Ruby-gnome.

I am not sure if this is useful and wanted feature, though. It would]
change the API but if anybody used the cases that would change then
they would see these issues for sure. Still it’s easy enough to
rearrange arguments and redispatch the callbacks in user Ruby code,
too.

My code would not work with what you are proposing. I almost never use
the handler name to call a method of the same name.

The other issue is with Gtk::Builder. Given the issues above it does a
lousy job of connecting signals, it can’t do any better. The results
are nowhere near what the C connections would be.

I disagree, it does its job good, lacking only one feature : user_data.
The results are just the same as in C, afaik.

What works properly are signals with no user data (object in glade
files). Builder calls the user supplied block to get a handler and
connects that. The swapped option does not make any sense in this case
and is rightfully ignored.

Agreed.

What somewhat works are swapped signals with user data. These are
often used to connect a “close” button to call a function which
disposes of a window when the button is clicked. As these functions
take only the window in C and no arguments in Ruby this works OK - all
arguments are ignored. Connecting a GTK function that takes arguments
would not work this way because of the extra argument generated when
going between C and Ruby.

Just to be sure, you are talking about having a swapped handler with
name ‘gtk_window_destroy’ ? So, C code calls
gtk_window_destroy(user_data) where user_data is the window, without
writing any code ?

If that’s it, I think it’s a corner case of C, where you use functions,
and not methods. I don’t think it is ruby to mimic this behaviour.

What is broken are signals with user data which are not swapped.
They are simply handled as swapped, the swapped flag is ignored
completely. I guess these should be connected just like signals
without user data but pass in the extra argument. It’s not quite
consistent with C gtk and never will be so long as the extra argument
is generated but at least it would be an useful option.

I agree there is something strange going on with user_data. However I
disagree that swapped signals function properly.

the connect_signals from Gtk::Builder should pass user_data, as last
argument if not swapped, or as first if swapped. And it should be up to
the programmer to connect as he wants to.

regards

Simon

On 21 September 2011 15:01, Simon A.
[email protected] wrote:

method is already attached to an object - ‘self’. The first argument
end
It fails with “undefined method `label’ for main:Object”, because self
is not anymore the button when the callback is called.

It depends on the method invoked as the callback.

It is perfectly possible to detect if the callback is attached to the
triggering object or another object at attach time and it is also
possible to detect that a callback is triggered on the triggering
object at trigger time.

That’s because ‘self’ is not the object the method is called from, but
the current object.

The ‘current’ object is the object whose method was attached as the
signal handler. You can pick it so that the ‘self’ matches or not, and
you can also know in advance if it will (such as in the builder
connect_signals).

It seems you are confusing the ‘destroy’ method, and the ‘destroy’
signal.
The ‘destroy’ method takes no argument, but the ‘destroy’ signal does.

Indeed, that’s the difference between Ruby and C.

In C the destroy method takes ‘self’, and the signal callback gets
‘self’ and ‘data’, possibly swapped.

In Ruby the destroy method takes no arguments, and the callback still
gets ‘self’ and ‘data’, and the method is no longer compatible with
the signal.

Also, I’m not sure I get your point. Are you talking about auto calling
a method on the widget based on event-type ?

I am talking about using existing methods as signal handlers.

Or are you talking about glade, and you want to directly connect the
handler you create as a method call to the object which received the
event ?
So, instead of :
builder.connect_signals {|handler| method(handler) }

you would like the default to be something like :
def my_connect(handler, *args)
args[0].send(handler)
args[0].send(handler, *(args[1…-1])) more precisely to make it look
like what C does

Plus extra arguments should be discarded.

end

Am I right ?

That’s one way of using the signal connections in Glade, and one that
works quite well for quite a few signals in C.

For the most common which take only ‘self’ in C it is hacked in
connect_signals in Ruby Builder so that it works but it’s not exactly
consistent. The moment you try to call a method that takes arguments
it will fail.

directly, and that you should write a custom method to use in
‘connect_signals’.

Yes, I can write wrappers for any methods I want to connect as
callbacks, sure.

The wrapper can handle extra arguments or whatnot without any issues.

I’m not a C programmer, but, are you saying that I can call something
like this, and it will work ?

gtk_window_move(p_win, 100, 200, 345, “foo”, NULL);

I really doubt it.

I am not sure what you are trying to demonstrate here.

You can definitely call gtk_widget_destroy(p_win, 100, 200, 345,
“foo”, NULL) and it will work and it is what the callbacks do all the
time. They call gtk_widget_destroy(p_win, p_button).

Or is it gtk_builder in C which discards the extra args ?

Don’t think so. C calling convention discards extra arguments
automagically.

Either of this could be resolved by inserting a wrapper automatically
at gobj_sig_connect_impl to discard any extra args and/or discard the
first arg when it is the same as the receiver.

I think it should be done by the programmer, not by Ruby-gnome.

At the very least it should be well documented what the builder does
because it is very inconsistent for various cases and very different
from the C builder.

I am not sure if this is useful and wanted feature, though. It would]
change the API but if anybody used the cases that would change then
they would see these issues for sure. Still it’s easy enough to
rearrange arguments and redispatch the callbacks in user Ruby code,
too.

My code would not work with what you are proposing. I almost never use
the handler name to call a method of the same name.

Then your code would work.

The other issue is with Gtk::Builder. Given the issues above it does a
lousy job of connecting signals, it can’t do any better. The results
are nowhere near what the C connections would be.

I disagree, it does its job good, lacking only one feature : user_data.
The results are just the same as in C, afaik.

Well, when you remove half of the features and then say that the other
half works … even that is not true.

It handles user_data as the swapped flag, and ignores the swapped flag.

That’s definitely bogus.

disposes of a window when the button is clicked. As these functions
take only the window in C and no arguments in Ruby this works OK - all
arguments are ignored. Connecting a GTK function that takes arguments
would not work this way because of the extra argument generated when
going between C and Ruby.

Just to be sure, you are talking about having a swapped handler with
name ‘gtk_window_destroy’ ? So, C code calls
gtk_window_destroy(user_data) where user_data is the window, without
writing any code ?

Yes, it does that.

If that’s it, I think it’s a corner case of C, where you use functions,
and not methods. I don’t think it is ruby to mimic this behaviour.

But it is glade to do such, and ruby-gnome2 claims to support glade.

What is broken are signals with user data which are not swapped.
They are simply handled as swapped, the swapped flag is ignored
completely. I guess these should be connected just like signals
without user data but pass in the extra argument. It’s not quite
consistent with C gtk and never will be so long as the extra argument
is generated but at least it would be an useful option.

I agree there is something strange going on with user_data. However I
disagree that swapped signals function properly.

yes, they won’t if multiple arguments were passed in to the callback
but there are quite few such signals, if any.

the connect_signals from Gtk::Builder should pass user_data, as last
argument if not swapped, or as first if swapped. And it should be up to
the programmer to connect as he wants to.

That would definitely suck more, especially since you do not get
anything but the method name to decide what to do when connecting the
handler.

For the user to be able to decide how to connect the signal they would
have to know all of

  • signal name
  • triggering object
  • user data

Then the connection function would be just something like
signals_each{
signal_connect *(connector signal, trigger, data, swapped)
}

that is the user would supply all the arguments based on all the
signal data read from the glade layout.

Thanks

Michal

On Wed, Sep 21, 2011 at 15:01, Simon A.
[email protected] wrote:

on_click(my_button) # works, but bad practice

Why is this a bad practice?

Nikolai W. wrote in post #1023132:

On Wed, Sep 21, 2011 at 15:01, Simon A.
[email protected] wrote:

on_click(my_button) # works, but bad practice

Why is this a bad practice?

It seems to me that when you have both the same object as external and
local scope, local should be used.

It will ease refactor also. This example might not be the best to
demonstrate the problem though.

I understand it is a subjective topic.

On 21 September 2011 18:31, Simon A.
[email protected] wrote:

When you define a method, ‘self’ is the object the method will be called
onto.
When you call a method which takes a block, inside the block, ‘self’ is
not the object you call the method onto, it is the object you are in.

This is true but does not apply to builder. Builder connects methods.

It’s obvious with an array :

a = [1, 2, 3]
a.each do |item|

self is not a

end

However, I understand you would like self to be set so it is the object
which triggered the signal.

Not necessarily. What I am saying is that when you attach a method on
the object which triggers the signal as signal handler you get
redundant reference to self passed as the first argument which makes
the signal interface incompatible with the ruby-gnome2 method
interface.

Just that I’m not a C programmer, at all. I didn’t think C would discard
any extras by itself.

Anyway, I feel you have a strong C background, and you would like ruby
to behave like C. However, I don’t think it can. In one languauge, you

No, I would like the builder to behave logically. If the current
behaviour were at least documented it would be obvious it’s bogus.

have global functions with arguments, and in another, you haves messages
sent to objects. While ruby can mimic C a great deal, I don’t think you
can imitate every corner case.

I understand the usefullness to call gtk_window_destroy(p_win,
p_button), and it will work without any effort in C, but I still think
it is a C corner case impossible to mimic in ruby.

It is already emulated partially. Builder already mimics this
particular case by attaching a block discarding the extra arguments
instead of the method when the provided method does not take
arguments.

In most (all?) cases, you will need a dispatcher.

Why should you need a dispatcher?

The glib signals system is done so that you shall not need any
additional dispatcher. It can trigger multiple handlers for a single
signal, you can register the handlers in a particular order, you can
pass the handler additional user data, and you can even swap the order
in which the triggering object and extra data are passed.

Thanks

Michal

On 22 September 2011 10:44, Michal S. [email protected] wrote:

redundant reference to self passed as the first argument which makes

instead of the method when the provided method does not take
arguments.

It’s also explained in the g_signal “hello world” :
http://developer.gnome.org/gtk-tutorial/2.90/x159.html

Thanks

Michal

Michal S. wrote in post #1023105:

That’s because ‘self’ is not the object the method is called from, but
the current object.

The ‘current’ object is the object whose method was attached as the
signal handler. You can pick it so that the ‘self’ matches or not, and
you can also know in advance if it will (such as in the builder
connect_signals).

What I wanted to say was not clear.
When you define a method, ‘self’ is the object the method will be called
onto.
When you call a method which takes a block, inside the block, ‘self’ is
not the object you call the method onto, it is the object you are in.

It’s obvious with an array :

a = [1, 2, 3]
a.each do |item|

self is not a

end

However, I understand you would like self to be set so it is the object
which triggered the signal.

I’m not a C programmer, but, are you saying that I can call something
like this, and it will work ?

gtk_window_move(p_win, 100, 200, 345, “foo”, NULL);

I really doubt it.

I am not sure what you are trying to demonstrate here.

Just that I’m not a C programmer, at all. I didn’t think C would discard
any extras by itself.

Anyway, I feel you have a strong C background, and you would like ruby
to behave like C. However, I don’t think it can. In one languauge, you
have global functions with arguments, and in another, you haves messages
sent to objects. While ruby can mimic C a great deal, I don’t think you
can imitate every corner case.

I understand the usefullness to call gtk_window_destroy(p_win,
p_button), and it will work without any effort in C, but I still think
it is a C corner case impossible to mimic in ruby.

In most (all?) cases, you will need a dispatcher.

I fully agree though that the documentation is not very good, and the
current behaviour is bogus and confusing.

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs