Hi fxruby-users, I want to set the text (setText/appendText) of an FXText widget out of a thread. As soon as the scroll bar appears in the widget the gui is not responsive anymore. This behaviour only occurs under windows (Win7-64). Under Linux it just works fine. Using FXDataTarget is not possible because it produces a big delay on updating the widget. Additionally, if I use an FXDataTarget it seems that all my other message handlers disapear. Here''s the sample code which triggers the behaviour: -------------8<-------------------- #!/usr/bin/env ruby require ''rubygems'' require ''fox16'' include Fox class MyWorker @@pool_mutex = Mutex.new def subscribe(event, &callback) (@event_dispatcher_listeners[event] ||= []) << callback end def notify(event, *args) if @event_dispatcher_listeners[event] @@pool_mutex.synchronize do @event_dispatcher_listeners[event].each do |m| m.call(*args) if m.respond_to? :call end end end end def run progress = {} @total.times do |i| Thread.new(i) { |ii| msg = "#{@name}: #{ii}\n" puts msg + " - running ..." notify(:logger, msg) sleep 1 puts msg + " - finished!" } end end def initialize(name, total = 100) @event_dispatcher_listeners = {} @total = total @name = name end end class MTTextTest < FXMainWindow @@textMutex = Mutex.new def initialize(app) # Call base class initializer first super(app, "Producer Test", :width => 800, :height => 600) frame = FXVerticalFrame.new(self, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y) @textbox = FXText.new(frame, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y|TEXT_AUTOSCROLL) showButton = FXButton.new(frame, "&Thread", :opts => FRAME_THICK|FRAME_RAISED|LAYOUT_FILL_X|LAYOUT_TOP|LAYOUT_LEFT) showButton.connect(SEL_COMMAND) do # @textbox.hide @tl = [] 10.times do |x| # print "\n* starting worker #{x}..." name = "w#{x}" worker = MyWorker.new(name, x*3) worker.subscribe(:logger) { |msg| begin @@textMutex.synchronize do @textbox.appendText( msg, false ) end rescue => bang puts bang puts bang.backtrace end } worker.run end # @textbox.appendText "ALL WORKERS STARTED !!!\n" # @tl.each do |t| t.join; end end end # Create and show the main window def create super # Create the windows show(PLACEMENT_SCREEN) # Make the main window appear end end if __FILE__ == $0 # Construct the application object application = FXApp.new(''Multi-Thread-Producer Test'', ''FoxTest'') # Construct the main window scribble = MTTextTest.new(application) # Create the application application.create application.run end -------------8<-------------------- C:\Users\andy>ruby -e "require ''fox16''; puts \"Ruby: #{RUBY_VERSION}\nFox: #{Fox .fxversion}\"" Ruby: 1.9.2 Fox: 1.6.44 Does anybody know what''s wrong here? Thanks, Andy
You''re not allowed to interact with the GUI from threads. You need to put any GUI function calls inside of a timeout handler so that they execute in the main thread. Ryan -----Original Message----- From: fxruby-users-bounces at rubyforge.org [mailto:fxruby-users-bounces at rubyforge.org] On Behalf Of watobo Sent: Wednesday, February 15, 2012 12:28 AM To: fxruby-users at rubyforge.org Subject: [fxruby-users] FXText update within threads Hi fxruby-users, I want to set the text (setText/appendText) of an FXText widget out of a thread. As soon as the scroll bar appears in the widget the gui is not responsive anymore. This behaviour only occurs under windows (Win7-64). Under Linux it just works fine. Using FXDataTarget is not possible because it produces a big delay on updating the widget. Additionally, if I use an FXDataTarget it seems that all my other message handlers disapear. Here''s the sample code which triggers the behaviour: -------------8<-------------------- #!/usr/bin/env ruby require ''rubygems'' require ''fox16'' include Fox class MyWorker @@pool_mutex = Mutex.new def subscribe(event, &callback) (@event_dispatcher_listeners[event] ||= []) << callback end def notify(event, *args) if @event_dispatcher_listeners[event] @@pool_mutex.synchronize do @event_dispatcher_listeners[event].each do |m| m.call(*args) if m.respond_to? :call end end end end def run progress = {} @total.times do |i| Thread.new(i) { |ii| msg = "#{@name}: #{ii}\n" puts msg + " - running ..." notify(:logger, msg) sleep 1 puts msg + " - finished!" } end end def initialize(name, total = 100) @event_dispatcher_listeners = {} @total = total @name = name end end class MTTextTest < FXMainWindow @@textMutex = Mutex.new def initialize(app) # Call base class initializer first super(app, "Producer Test", :width => 800, :height => 600) frame = FXVerticalFrame.new(self, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y) @textbox = FXText.new(frame, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y|TEXT_AUTOSCROLL) showButton = FXButton.new(frame, "&Thread", :opts => FRAME_THICK|FRAME_RAISED|LAYOUT_FILL_X|LAYOUT_TOP|LAYOUT_LEFT) showButton.connect(SEL_COMMAND) do # @textbox.hide @tl = [] 10.times do |x| # print "\n* starting worker #{x}..." name = "w#{x}" worker = MyWorker.new(name, x*3) worker.subscribe(:logger) { |msg| begin @@textMutex.synchronize do @textbox.appendText( msg, false ) end rescue => bang puts bang puts bang.backtrace end } worker.run end # @textbox.appendText "ALL WORKERS STARTED !!!\n" # @tl.each do |t| t.join; end end end # Create and show the main window def create super # Create the windows show(PLACEMENT_SCREEN) # Make the main window appear end end if __FILE__ == $0 # Construct the application object application = FXApp.new(''Multi-Thread-Producer Test'', ''FoxTest'') # Construct the main window scribble = MTTextTest.new(application) # Create the application application.create application.run end -------------8<-------------------- C:\Users\andy>ruby -e "require ''fox16''; puts \"Ruby: #{RUBY_VERSION}\nFox: #{Fox .fxversion}\"" Ruby: 1.9.2 Fox: 1.6.44 Does anybody know what''s wrong here? Thanks, Andy _______________________________________________ fxruby-users mailing list fxruby-users at rubyforge.org http://rubyforge.org/mailman/listinfo/fxruby-users This message and any enclosures are intended only for the addressee. Please notify the sender by email if you are not the intended recipient. If you are not the intended recipient, you may not use, copy, disclose, or distribute this message or its contents or enclosures to any other person and any such actions may be unlawful. Ball reserves the right to monitor and review all messages and enclosures sent to or from this email address.
Hi watobo,> You''re not allowed to interact with the GUI from threads. ? You need to put any GUI function calls inside of a timeout handler so that they execute in the main thread.That''s right, fxruby isn''t thread safe. You could use a Queue object to collect blocks with the GUI calls and execute them from a timeout method. -- Regards, Lars
Hi Ryan, why not? Even in the groupbox.rb example a thread is used to update the clock. I''ve often used threads to control widgets and it worked all the time with Ruby 1.8. In Ruby 1.9 a lot of the thread managment changed, you can use threads to control FXTables, FXLabel or FXProgressBar without any problems. But I experienced this problem with FXText widget and I don''t understand where this problem lies. Is it a problem of FXRuby or of the Fox-Toolkit? thanks, -andy Am 15.02.2012 16:53, schrieb Melton, Ryan:> You''re not allowed to interact with the GUI from threads. You need to put any GUI function calls inside of a timeout handler so that they execute in the main thread. > > Ryan > > -----Original Message----- > From: fxruby-users-bounces at rubyforge.org [mailto:fxruby-users-bounces at rubyforge.org] On Behalf Of watobo > Sent: Wednesday, February 15, 2012 12:28 AM > To: fxruby-users at rubyforge.org > Subject: [fxruby-users] FXText update within threads > > Hi fxruby-users, > > I want to set the text (setText/appendText) of an FXText widget out of a > thread. As soon as the scroll bar appears in the widget the gui is not > responsive anymore. This behaviour only occurs under windows (Win7-64). Under > Linux it just works fine. > > Using FXDataTarget is not possible because it produces a big delay on > updating the widget. Additionally, if I use an FXDataTarget it seems that all my other message handlers disapear. > > Here''s the sample code which triggers the behaviour: > > -------------8<-------------------- > > #!/usr/bin/env ruby > require ''rubygems'' > require ''fox16'' > > include Fox > > class MyWorker > > @@pool_mutex = Mutex.new > > def subscribe(event, &callback) > (@event_dispatcher_listeners[event] ||= []) << callback > end > > def notify(event, *args) > if @event_dispatcher_listeners[event] > @@pool_mutex.synchronize do > @event_dispatcher_listeners[event].each do |m| > m.call(*args) if m.respond_to? :call > end > end > end > end > > def run > progress = {} > @total.times do |i| > Thread.new(i) { |ii| > msg = "#{@name}: #{ii}\n" > puts msg + " - running ..." > > notify(:logger, msg) > > sleep 1 > puts msg + " - finished!" > } > end > > end > > def initialize(name, total = 100) > @event_dispatcher_listeners = {} > @total = total > @name = name > end > end > > class MTTextTest < FXMainWindow > @@textMutex = Mutex.new > def initialize(app) > # Call base class initializer first > super(app, "Producer Test", :width => 800, :height => 600) > frame = FXVerticalFrame.new(self, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y) > > @textbox = FXText.new(frame, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y|TEXT_AUTOSCROLL) > > showButton = FXButton.new(frame, "&Thread", :opts => FRAME_THICK|FRAME_RAISED|LAYOUT_FILL_X|LAYOUT_TOP|LAYOUT_LEFT) > > showButton.connect(SEL_COMMAND) do > # @textbox.hide > @tl = [] > 10.times do |x| > > # print "\n* starting worker #{x}..." > name = "w#{x}" > worker = MyWorker.new(name, x*3) > > worker.subscribe(:logger) { |msg| > begin > > @@textMutex.synchronize do > @textbox.appendText( msg, false ) > end > > rescue => bang > puts bang > puts bang.backtrace > end > > } > worker.run > end > # @textbox.appendText "ALL WORKERS STARTED !!!\n" > # @tl.each do |t| t.join; end > end > > end > > # Create and show the main window > def create > super # Create the windows > show(PLACEMENT_SCREEN) # Make the main window appear > end > end > > if __FILE__ == $0 > # Construct the application object > application = FXApp.new(''Multi-Thread-Producer Test'', ''FoxTest'') > > # Construct the main window > scribble = MTTextTest.new(application) > > # Create the application > application.create > > application.run > end > > -------------8<-------------------- > > C:\Users\andy>ruby -e "require ''fox16''; puts \"Ruby: #{RUBY_VERSION}\nFox: #{Fox > .fxversion}\"" > Ruby: 1.9.2 > Fox: 1.6.44 > > > Does anybody know what''s wrong here? > > Thanks, > > Andy > > _______________________________________________ > fxruby-users mailing list > fxruby-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/fxruby-users > > > > This message and any enclosures are intended only for the addressee. Please > notify the sender by email if you are not the intended recipient. If you are > not the intended recipient, you may not use, copy, disclose, or distribute this > message or its contents or enclosures to any other person and any such actions > may be unlawful. Ball reserves the right to monitor and review all messages > and enclosures sent to or from this email address. > _______________________________________________ > fxruby-users mailing list > fxruby-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/fxruby-users
Most GUI frameworks (including FOX) are designed to the reactor pattern http://en.wikipedia.org/wiki/Reactor_pattern much like the EventMachine library (ie. one thread that services events) and are not thread safe. What that means is that things may work sometimes, but not always if you touch the GUI outside of the main thread. Due to Ruby 1.9 using native threads, problems jump out a lot faster when running 1.9, but they still existed in 1.8. I''ve learned this the hard way with some very subtle and "spurious" failures in applications I have written. Note that code that is not thread safe will work just fine across threads as long as a context switch does not occur while it is executing. Calls that take a long time, like calls to FXText, are much more likely to have a context switch occur while they are executing. If any of the example code touches the GUI from a Thread.new, then it is a BAD example. May work sometimes, or even most of the time, but othertimes you will get a nice "spurious" crash. :) Ryan -----Original Message----- From: fxruby-users-bounces at rubyforge.org [mailto:fxruby-users-bounces at rubyforge.org] On Behalf Of Andreas Schmidt Sent: Wednesday, February 15, 2012 1:19 PM To: fxruby-users at rubyforge.org Subject: Re: [fxruby-users] FXText update within threads Hi Ryan, why not? Even in the groupbox.rb example a thread is used to update the clock. I''ve often used threads to control widgets and it worked all the time with Ruby 1.8. In Ruby 1.9 a lot of the thread managment changed, you can use threads to control FXTables, FXLabel or FXProgressBar without any problems. But I experienced this problem with FXText widget and I don''t understand where this problem lies. Is it a problem of FXRuby or of the Fox-Toolkit? thanks, -andy Am 15.02.2012 16:53, schrieb Melton, Ryan:> You''re not allowed to interact with the GUI from threads. You need to put any GUI function calls inside of a timeout handler so that they execute in the main thread. > > Ryan > > -----Original Message----- > From: fxruby-users-bounces at rubyforge.org [mailto:fxruby-users-bounces at rubyforge.org] On Behalf Of watobo > Sent: Wednesday, February 15, 2012 12:28 AM > To: fxruby-users at rubyforge.org > Subject: [fxruby-users] FXText update within threads > > Hi fxruby-users, > > I want to set the text (setText/appendText) of an FXText widget out of a > thread. As soon as the scroll bar appears in the widget the gui is not > responsive anymore. This behaviour only occurs under windows (Win7-64). Under > Linux it just works fine. > > Using FXDataTarget is not possible because it produces a big delay on > updating the widget. Additionally, if I use an FXDataTarget it seems that all my other message handlers disapear. > > Here''s the sample code which triggers the behaviour: > > -------------8<-------------------- > > #!/usr/bin/env ruby > require ''rubygems'' > require ''fox16'' > > include Fox > > class MyWorker > > @@pool_mutex = Mutex.new > > def subscribe(event, &callback) > (@event_dispatcher_listeners[event] ||= []) << callback > end > > def notify(event, *args) > if @event_dispatcher_listeners[event] > @@pool_mutex.synchronize do > @event_dispatcher_listeners[event].each do |m| > m.call(*args) if m.respond_to? :call > end > end > end > end > > def run > progress = {} > @total.times do |i| > Thread.new(i) { |ii| > msg = "#{@name}: #{ii}\n" > puts msg + " - running ..." > > notify(:logger, msg) > > sleep 1 > puts msg + " - finished!" > } > end > > end > > def initialize(name, total = 100) > @event_dispatcher_listeners = {} > @total = total > @name = name > end > end > > class MTTextTest < FXMainWindow > @@textMutex = Mutex.new > def initialize(app) > # Call base class initializer first > super(app, "Producer Test", :width => 800, :height => 600) > frame = FXVerticalFrame.new(self, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y) > > @textbox = FXText.new(frame, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y|TEXT_AUTOSCROLL) > > showButton = FXButton.new(frame, "&Thread", :opts => FRAME_THICK|FRAME_RAISED|LAYOUT_FILL_X|LAYOUT_TOP|LAYOUT_LEFT) > > showButton.connect(SEL_COMMAND) do > # @textbox.hide > @tl = [] > 10.times do |x| > > # print "\n* starting worker #{x}..." > name = "w#{x}" > worker = MyWorker.new(name, x*3) > > worker.subscribe(:logger) { |msg| > begin > > @@textMutex.synchronize do > @textbox.appendText( msg, false ) > end > > rescue => bang > puts bang > puts bang.backtrace > end > > } > worker.run > end > # @textbox.appendText "ALL WORKERS STARTED !!!\n" > # @tl.each do |t| t.join; end > end > > end > > # Create and show the main window > def create > super # Create the windows > show(PLACEMENT_SCREEN) # Make the main window appear > end > end > > if __FILE__ == $0 > # Construct the application object > application = FXApp.new(''Multi-Thread-Producer Test'', ''FoxTest'') > > # Construct the main window > scribble = MTTextTest.new(application) > > # Create the application > application.create > > application.run > end > > -------------8<-------------------- > > C:\Users\andy>ruby -e "require ''fox16''; puts \"Ruby: #{RUBY_VERSION}\nFox: #{Fox > .fxversion}\"" > Ruby: 1.9.2 > Fox: 1.6.44 > > > Does anybody know what''s wrong here? > > Thanks, > > Andy > > _______________________________________________ > fxruby-users mailing list > fxruby-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/fxruby-users > > > > This message and any enclosures are intended only for the addressee. Please > notify the sender by email if you are not the intended recipient. If you are > not the intended recipient, you may not use, copy, disclose, or distribute this > message or its contents or enclosures to any other person and any such actions > may be unlawful. Ball reserves the right to monitor and review all messages > and enclosures sent to or from this email address. > _______________________________________________ > fxruby-users mailing list > fxruby-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/fxruby-users_______________________________________________ fxruby-users mailing list fxruby-users at rubyforge.org http://rubyforge.org/mailman/listinfo/fxruby-users This message and any enclosures are intended only for the addressee. Please notify the sender by email if you are not the intended recipient. If you are not the intended recipient, you may not use, copy, disclose, or distribute this message or its contents or enclosures to any other person and any such actions may be unlawful. Ball reserves the right to monitor and review all messages and enclosures sent to or from this email address.
Hi Ryan, thanks a lot for this detailed explanation. But I don''t like the answer because it means a lot of work ;) After all, I should have read this earlier: http://www.fox-toolkit.net/faq#TOC-Is-FOX-thread-safe-Can-I-write-mult -andy Am 15.02.2012 23:18, schrieb Melton, Ryan:> Most GUI frameworks (including FOX) are designed to the reactor pattern http://en.wikipedia.org/wiki/Reactor_pattern much like the EventMachine library (ie. one thread that services events) and are not thread safe. What that means is that things may work sometimes, but not always if you touch the GUI outside of the main thread. Due to Ruby 1.9 using native threads, problems jump out a lot faster when running 1.9, but they still existed in 1.8. I''ve learned this the hard way with some very subtle and "spurious" failures in applications I have written. > > Note that code that is not thread safe will work just fine across threads as long as a context switch does not occur while it is executing. Calls that take a long time, like calls to FXText, are much more likely to have a context switch occur while they are executing. > > If any of the example code touches the GUI from a Thread.new, then it is a BAD example. May work sometimes, or even most of the time, but othertimes you will get a nice "spurious" crash. :) > > Ryan > > -----Original Message----- > From: fxruby-users-bounces at rubyforge.org [mailto:fxruby-users-bounces at rubyforge.org] On Behalf Of Andreas Schmidt > Sent: Wednesday, February 15, 2012 1:19 PM > To: fxruby-users at rubyforge.org > Subject: Re: [fxruby-users] FXText update within threads > > Hi Ryan, > > why not? Even in the groupbox.rb example a thread is used to update the > clock. I''ve often used threads to control widgets and it worked all the > time with Ruby 1.8. In Ruby 1.9 a lot of the thread managment changed, > you can use threads to control FXTables, FXLabel or FXProgressBar > without any problems. But I experienced this problem with FXText widget > and I don''t understand where this problem lies. Is it a problem of > FXRuby or of the Fox-Toolkit? > > thanks, > -andy > > > Am 15.02.2012 16:53, schrieb Melton, Ryan: >> You''re not allowed to interact with the GUI from threads. You need to put any GUI function calls inside of a timeout handler so that they execute in the main thread. >> >> Ryan >> >> -----Original Message----- >> From: fxruby-users-bounces at rubyforge.org [mailto:fxruby-users-bounces at rubyforge.org] On Behalf Of watobo >> Sent: Wednesday, February 15, 2012 12:28 AM >> To: fxruby-users at rubyforge.org >> Subject: [fxruby-users] FXText update within threads >> >> Hi fxruby-users, >> >> I want to set the text (setText/appendText) of an FXText widget out of a >> thread. As soon as the scroll bar appears in the widget the gui is not >> responsive anymore. This behaviour only occurs under windows (Win7-64). Under >> Linux it just works fine. >> >> Using FXDataTarget is not possible because it produces a big delay on >> updating the widget. Additionally, if I use an FXDataTarget it seems that all my other message handlers disapear. >> >> Here''s the sample code which triggers the behaviour: >> >> -------------8<-------------------- >> >> #!/usr/bin/env ruby >> require ''rubygems'' >> require ''fox16'' >> >> include Fox >> >> class MyWorker >> >> @@pool_mutex = Mutex.new >> >> def subscribe(event, &callback) >> (@event_dispatcher_listeners[event] ||= []) << callback >> end >> >> def notify(event, *args) >> if @event_dispatcher_listeners[event] >> @@pool_mutex.synchronize do >> @event_dispatcher_listeners[event].each do |m| >> m.call(*args) if m.respond_to? :call >> end >> end >> end >> end >> >> def run >> progress = {} >> @total.times do |i| >> Thread.new(i) { |ii| >> msg = "#{@name}: #{ii}\n" >> puts msg + " - running ..." >> >> notify(:logger, msg) >> >> sleep 1 >> puts msg + " - finished!" >> } >> end >> >> end >> >> def initialize(name, total = 100) >> @event_dispatcher_listeners = {} >> @total = total >> @name = name >> end >> end >> >> class MTTextTest < FXMainWindow >> @@textMutex = Mutex.new >> def initialize(app) >> # Call base class initializer first >> super(app, "Producer Test", :width => 800, :height => 600) >> frame = FXVerticalFrame.new(self, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y) >> >> @textbox = FXText.new(frame, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y|TEXT_AUTOSCROLL) >> >> showButton = FXButton.new(frame, "&Thread", :opts => FRAME_THICK|FRAME_RAISED|LAYOUT_FILL_X|LAYOUT_TOP|LAYOUT_LEFT) >> >> showButton.connect(SEL_COMMAND) do >> # @textbox.hide >> @tl = [] >> 10.times do |x| >> >> # print "\n* starting worker #{x}..." >> name = "w#{x}" >> worker = MyWorker.new(name, x*3) >> >> worker.subscribe(:logger) { |msg| >> begin >> >> @@textMutex.synchronize do >> @textbox.appendText( msg, false ) >> end >> >> rescue => bang >> puts bang >> puts bang.backtrace >> end >> >> } >> worker.run >> end >> # @textbox.appendText "ALL WORKERS STARTED !!!\n" >> # @tl.each do |t| t.join; end >> end >> >> end >> >> # Create and show the main window >> def create >> super # Create the windows >> show(PLACEMENT_SCREEN) # Make the main window appear >> end >> end >> >> if __FILE__ == $0 >> # Construct the application object >> application = FXApp.new(''Multi-Thread-Producer Test'', ''FoxTest'') >> >> # Construct the main window >> scribble = MTTextTest.new(application) >> >> # Create the application >> application.create >> >> application.run >> end >> >> -------------8<-------------------- >> >> C:\Users\andy>ruby -e "require ''fox16''; puts \"Ruby: #{RUBY_VERSION}\nFox: #{Fox >> .fxversion}\"" >> Ruby: 1.9.2 >> Fox: 1.6.44 >> >> >> Does anybody know what''s wrong here? >> >> Thanks, >> >> Andy >> >> _______________________________________________ >> fxruby-users mailing list >> fxruby-users at rubyforge.org >> http://rubyforge.org/mailman/listinfo/fxruby-users >> >> >> >> This message and any enclosures are intended only for the addressee. Please >> notify the sender by email if you are not the intended recipient. If you are >> not the intended recipient, you may not use, copy, disclose, or distribute this >> message or its contents or enclosures to any other person and any such actions >> may be unlawful. Ball reserves the right to monitor and review all messages >> and enclosures sent to or from this email address. >> _______________________________________________ >> fxruby-users mailing list >> fxruby-users at rubyforge.org >> http://rubyforge.org/mailman/listinfo/fxruby-users > _______________________________________________ > fxruby-users mailing list > fxruby-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/fxruby-users > > > > This message and any enclosures are intended only for the addressee. Please > notify the sender by email if you are not the intended recipient. If you are > not the intended recipient, you may not use, copy, disclose, or distribute this > message or its contents or enclosures to any other person and any such actions > may be unlawful. Ball reserves the right to monitor and review all messages > and enclosures sent to or from this email address. > _______________________________________________ > fxruby-users mailing list > fxruby-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/fxruby-users