On Tue, 29 May 2001, Patrik Sundberg wrote:
> So, I want to have functionality similair to the gtk_input_add_* functions in
> my ruby-gtk application. I want to update the GUI depending on data from a
UDP
> socket and the data is sent asynchronous - how would I accomplish this?

Hi Patrik, I needed exactly the same functionality, searched through this
list via google, but all that I found were your two postings. I really
wonder why nobody has implemented it yet -- you really need this for any
single thread GUI application that communicates over the net.

There are basically two solutions to this problem: Either get the file
descriptor for X11 somehow out of Gtk, then implement the application main
loop yourself, adding this file descriptor to your select call, and then
call Gtk::main_iteration() from there when apropriate, avoiding
Gtk::main() completely.

Or implement the missing input_add functions youself.

It seems both solutions require that you extend the current ruby/gtk
binding, and the second sounds like less effort.

I tried to implement the missing functions, and it seems to work. See the
diff below, but beware: I only know about ruby since 3 weeks.

I've got a question to the group regarding the handling of a block
argument in a ruby extension:

The code in the idle_add, idle_remove, timeout_add, timeout_remove methods
looks to me like a memory leak. (File src/rbgtkmain.c)

The *_add functions contain a call to a function add_relative that
basically stores a reference to the block in an Array which is an instance
variable of "self". (BTW what does self mean in this context? Gtk is a
module, and these are module functions.) I suppose this saves the block
and its scope from the garbage collection?

This reference is not removed by the corresponding *_remove functions. So,
if I was right with the garbage collection thing, periodic calls to *_add
and *_remove functions would eat up memory that is never freed again,
right?

Greetings, Tobias


This is a diff against ruby/gtk version 0.24. The new input_add/remove
functions are modified versions of the timeout functions, so if there is
really a memory leak problem in these, then the input functions will have
it too.

Below the diff  is a small example script, which uses the new Gtk::input_add
method to wait for input on stdin.

*** rbgtkmain.c.orig	Sun Oct 22 13:31:08 2000
--- rbgtkmain.c	Wed May 30 21:06:00 2001
***************
*** 80,85 ****
--- 80,118 ----
      return Qnil;
  }
  
+ static void
+ exec_input (gpointer data,
+             gint     source,
+             GdkInputCondition condition)
+ {
+     rb_funcall((VALUE)data, id_call, 0);
+ }
+ 
+ static VALUE
+ input_add(self, filedescriptor, gdk_input_condition)
+     VALUE self, filedescriptor, gdk_input_condition;
+ {
+     int id;
+     VALUE func;
+ 
+     func = rb_f_lambda();
+     add_relative(self, func);
+ 
+     id = gdk_input_add(NUM2INT(rb_funcall(filedescriptor, rb_intern("to_i"),
0)),
+                        (GdkInputCondition)NUM2INT(gdk_input_condition),
+                        (GdkInputFunction)exec_input,
+                        (gpointer)func);
+     return INT2FIX(id);
+ }
+ 
+ static VALUE
+ input_remove(self, id)
+     VALUE self, id;
+ {
+     gdk_input_remove(NUM2INT(id));
+     return Qnil;
+ }
+ 
  static VALUE
  idle_add(self)
      VALUE self;
***************
*** 187,192 ****
--- 220,227 ----
      rb_define_module_function(mGtk, "main_iteration", gtk_m_main_iteration,
0);
      rb_define_module_function(mGtk, "timeout_add", timeout_add, 1);
      rb_define_module_function(mGtk, "timeout_remove", timeout_remove, 1);
+     rb_define_module_function(mGtk, "input_add", input_add, 2);
+     rb_define_module_function(mGtk, "input_remove", input_remove, 1);
      rb_define_module_function(mGtk, "idle_add", idle_add, 0);
      rb_define_module_function(mGtk, "idle_remove", idle_remove, 1);
      rb_define_module_function(mGtk, "get_current_event",
gtk_m_get_current_event, 0);





require "gtk"

GDK_INPUT_READ       = 1 << 0
GDK_INPUT_WRITE      = 1 << 1
GDK_INPUT_EXCEPTION  = 1 << 2

STDIN_FILENO = 0

Gtk::input_add($stdin, GDK_INPUT_READ) {
  chars = $stdin.sysread(5)
  puts("input pending! Reading no more than 5 chars: <<#{chars.dump()}>>")
  if (chars[0,4] == "quit")
    Gtk::main_quit()
  end
}

Gtk::main()