#! /usr/bin/ruby require 'socket' require 'thread' require 'monitor' require 'gtk2' def gtk_thread_protect(&proc) if Thread.current == Thread.main proc.call else $gtk_pending_calls.synchronize { $gtk_pending_calls << proc } end end def gtk_thread_flush closure = nil continue = true begin $gtk_pending_calls.synchronize { closure = $gtk_pending_calls.shift continue = $gtk_pending_calls.size > 0 } if closure closure.call end end while continue end Thread.abort_on_exception = true Gtk.init w = Gtk::Window.new w.add(vb = Gtk::VBox.new) vb.add(pb = Gtk::ProgressBar.new) vb.add(Gtk::Button.new("hover me, to show I'm responsive")) w.window_position = Gtk::Window::POS_CENTER w.show_all $gtk_pending_calls = [] $gtk_pending_calls.extend(MonitorMixin) Gtk.timeout_add(100) { gtk_thread_flush true } Thread.new { s = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0) sockaddr_server = [Socket::AF_INET, 80, Socket.gethostbyname('rubyforge.iasi.roedu.net')[3], 0, 0].pack("snA4NN") begin s.connect(sockaddr_server) rescue puts "error: #{$!}" else s.print "GET /files/rubyinstaller/ruby186-26.exe HTTP/1.0\r\nHost: rubyforge.iasi.roedu.net\r\n\r\n" count = 0 while result = s.read(4096) count += result.length gtk_thread_protect { pb.text = "Received #{count} bytes..."; pb.fraction = count.to_f / 24868801 } end gtk_thread_protect { pb.text = "Completed download." } s.close end } Gtk.main