Index: trunk/matplotlib/lib/matplotlib/backend_bases.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backend_bases.py	(revision 4908)
+++ trunk/matplotlib/lib/matplotlib/backend_bases.py	(working copy)
@@ -1151,7 +1151,13 @@
         """
         return self.callbacks.disconnect(cid)
 
+    def flush_events(self):
+        """ Flush the GUI events for the figure. Implemented only for
+        backends with GUIs.
+        """
+        raise NotImplementedError
 
+
 class FigureManagerBase:
     """
     Helper class for matlab mode, wraps everything up into a neat bundle
Index: trunk/matplotlib/lib/matplotlib/ginput.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/ginput.py	(revision 0)
+++ trunk/matplotlib/lib/matplotlib/ginput.py	(revision 0)
@@ -0,0 +1,80 @@
+
+from matplotlib.pyplot import gcf
+import time
+
+class BlockingMouseInput(object):
+    """ Class that creates a callable object to retrieve mouse click 
+        in a blocking way, a la MatLab. 
+    """
+
+    callback = None 
+    verbose = False
+
+    def on_click(self, event):
+        """ Event handler that will be passed to the current figure to
+            retrieve clicks.
+        """
+        # if it's a valid click, append the coordinates to the list
+        if event.inaxes:
+            self.clicks.append((event.xdata, event.ydata))
+            if self.verbose: 
+                print "input %i: %f,%f" % (len(self.clicks), 
+                                    event.xdata, event.ydata)
+
+    def __call__(self, fig, n=1, timeout=30, verbose=False):
+        """ Blocking call to retrieve n coordinate pairs through mouse 
+            clicks.
+        """
+
+        assert isinstance(n, int), "Requires an integer argument"
+
+        # Ensure that the current figure is shown 
+        fig.show()
+        # connect the click events to the on_click function call
+        self.callback = fig.canvas.mpl_connect('button_press_event', 
+                                                    self.on_click)
+
+        # initialize the list of click coordinates
+        self.clicks = []
+
+        self.verbose = verbose
+
+        # wait for n clicks
+        counter = 0
+        while len(self.clicks) < n:
+            fig.canvas.flush_events()
+            # rest for a moment
+            time.sleep(0.01)
+
+            # check for a timeout
+            counter += 1
+            if timeout > 0 and counter > timeout/0.01: 
+                print "ginput timeout"; 
+                break;
+
+        # All done! Disconnect the event and return what we have
+        fig.canvas.mpl_disconnect(self.callback)
+        self.callback = None
+        return self.clicks
+
+
+def ginput(n=1, timeout=30, verbose=False):
+    """
+    Blocking call to interact with the figure. 
+
+    This will wait for n clicks from the user and return a list of the 
+    coordinates of each click.
+
+    If timeout is negative, does not timeout.
+    """
+
+    blocking_mouse_input = BlockingMouseInput()
+    return blocking_mouse_input(gcf(), n, timeout, verbose=verbose)
+
+if __name__ == "__main__":
+    import pylab
+    t = pylab.arange(10)
+    pylab.plot(t, pylab.sin(t))
+    print "Please click"
+    ginput(3, verbose=True)
+
Index: trunk/matplotlib/lib/matplotlib/backends/backend_qt.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_qt.py	(revision 4908)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_qt.py	(working copy)
@@ -175,6 +175,9 @@
 
         return key
 
+    def flush_events(self):
+        qt.qApp.processEvents()
+
 class FigureManagerQT( FigureManagerBase ):
     """
     Public attributes
Index: trunk/matplotlib/lib/matplotlib/backends/backend_gtk.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_gtk.py	(revision 4908)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_gtk.py	(working copy)
@@ -386,6 +386,13 @@
     def get_default_filetype(self):
         return 'png'
 
+    def flush_events(self):
+        gtk.gdk.threads_enter()        
+        while gtk.events_pending():
+            gtk.main_iteration(True)
+        gtk.gdk.flush()
+        gtk.gdk.threads_leave()
+        
             
 class FigureManagerGTK(FigureManagerBase):
     """
Index: trunk/matplotlib/lib/matplotlib/backends/backend_tkagg.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_tkagg.py	(revision 4908)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_tkagg.py	(working copy)
@@ -269,8 +269,9 @@
         key = self._get_key(event)
         FigureCanvasBase.key_release_event(self, key, guiEvent=event)
 
+    def flush_events(self):
+        self._master.update()
 
-
 class FigureManagerTkAgg(FigureManagerBase):
     """
     Public attributes
Index: trunk/matplotlib/lib/matplotlib/backends/backend_qt4.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_qt4.py	(revision 4908)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_qt4.py	(working copy)
@@ -13,7 +13,7 @@
 from matplotlib.mathtext import MathTextParser
 from matplotlib.widgets import SubplotTool
 
-from PyQt4 import QtCore, QtGui
+from PyQt4 import QtCore, QtGui, Qt
 
 backend_version = "0.9.1"
 def fn_name(): return sys._getframe(1).f_code.co_name
@@ -174,6 +174,9 @@
 
         return key
 
+    def flush_events(self):
+        Qt.qApp.processEvents()
+
 class FigureManagerQT( FigureManagerBase ):
     """
     Public attributes
