Create  Edit  FrontPage  Index  Search  Changes  History  RSS  Login

tut-gtk2-glib-mainloop

Main Loop, Timeouts And Idle Method

Need I remind you we are talking about GLib here and not the GTK+!

Main Loop

So far in this tutorial, we have used the GTK+'s main loop (Gtk.main) without any mentioning of the fact that internally it in really creates the GLib's main loop. In fact most of the main loop functionality is implemented in GLib. The GTK+ merely provides widget signals to the system. The GTK+ main loop also connects GDK's X server events to the GLib system.

The purpose of the main loop is to sleep idle until some event has occurred. At that point, a callback function will be invoked, if available. On Linux systems GLib's main loop is implemented using the poll() system call. Events and signals are associated with file descriptor, which are watched using poll().

The advantage of the poll() system call is that GLib does not have to continuously monitor for new events and can sleep away until some event or signal is emitted. By doing so your application will take almost no processor cycles.

Again original C GLib implementation provides more access to the main loop low level structures than one needs in Ruby environment. The only thing that may be beneficial to you here is to appreciate the general principles on which GTK+ main loop operates, because there are ways to take advantage of this idle time, if you need to keep the user happy while still processing certain tasks that need no user interaction while everything looks idle.

Timeouts

It is possible to create functions or methods that ar called at a specified intervals of time.They are referred to as timeouts. Another type of callback function, referred as an idle function, is called when the operating system is not busy. Both of these are part of GLib.

Timeout methods are called at specified time intervals until false is returned. They are added to the main loop by either GLib::Timeout.add(interval){ ... } or GLib::Timeout.add_seconds(interval){ ... }.

Our simple example program pulses a progress bar every tenth of a second since the interval is measured in milliseconds and we set it to 100 milliseconds (100 * 1/1000 second). As the progress bar ha s its pulse step set to 0.1, it will take approximately one second for the progress bar to travel the from one end of the progress bar to the other end. The timeout object is removed after 25 calls.

glib-timeouts.png

#!/usr/bin/env ruby
require 'gtk2'

$count = 0
# Pulse the progress bar and return TRUE so the
# timeout is called again.
def pulse_progress (progress)
  progress.pulse
  $count += 1
  return ($count < 25);
end
window = Gtk::Window.new(Gtk::Window::TOPLEVEL)
window.resizable = true
window.title = "Timeouts"
window.border_width = 10
window.signal_connect('delete_event') { Gtk.main_quit }
window.set_size_request(200, -1)
pbar = Gtk::ProgressBar.new
pbar.pulse_step = 0.1

GLib::Timeout.add(100){ pulse_progress(pbar) }

window.add(pbar)
window.show_all
Gtk.main

Idle Method

GLib provides yet another special method called an idle method that will be invoked when there are no events with a higher priority pending. They run over and over again when there is nothing else to do in the main loop. Idle methods are added to main loop GLib::Idle.add {...}. Note that ordinarily one would not need to use timeouts and idle methods, and that as far as I can tell there may still be a few wrinkles to straighten in this area especially with idle. I provide the following example only for the sake of completeness, and truly suggest to Ruby GTK+ novices to stay away from these functions for a while. Following is a program that will, if you try it out and test it a bit, demonstrate just mentioned points.

#!/usr/bin/env ruby
require 'gtk2'

def button_clicked
  puts "Button pressed"
  i = 0
  $stdout.sync = true 
  GLib::Idle.add {print "%i " % (i += 1); sleep 1}
end

window = Gtk::Window.new(Gtk::Window::TOPLEVEL)
window.resizable = true
window.title = "Testing idle"
window.border_width = 0
window.signal_connect('delete_event') { Gtk.main_quit }
window.set_size_request(200, -1)

button = Gtk::Button.new("Click me!")
button.signal_connect('clicked') { |w| button_clicked }
hbox = Gtk::HBox.new(false, 5)
hbox.border_width = 10
hbox.pack_start(button, false, false, 5)

window.add(hbox)
window.show_all
Gtk.main
Last modified:2009/02/02 23:22:31
Keyword(s):
References:[tut-gtk2-glib] [tut-gtk]