I am trying to redraw the part of the DrawingArea that is visible in the Viewport in the expose-event handler. However, it seems that I am doing something wrong with the coordinates that are passed to the event handler because there is garbage at the edge of the Viewport when scrolling. Can anyone tell what I am doing wrong? Here is a small example:
import pygtk
pygtk.require("2.0")
import gtk
from numpy import array
from math import pi
class Circle(object):
    def init(self, position = [0., 0.], radius = 0., edge = (0., 0., 0.), fill = None):
        self.position = position
        self.radius = radius
        self.edge = edge
        self.fill = fill
    def draw(self, ctx):
        rect = array(ctx.clip_extents())
        rect[2] -= rect[0]
        rect[3] -= rect[1]
        center = rect[2:4] / 2
        ctx.arc(center[0], center[1], self.radius, 0., 2. * pi)
        if self.fill != None:
            ctx.set_source_rgb(*self.fill)
            ctx.fill_preserve()
        ctx.set_source_rgb(*self.edge)
        ctx.stroke()
class Scene(object):
    class Proxy(object):
        directory = {}
        def init(self, target, layers = set()):
            self.target = target
            self.layers = layers
            Scene.Proxy.directory[target] = self
def __init__(self, viewport):
    self.objects = {}
    self.layers = [set()]
    self.viewport = viewport
    self.signals = {}
def draw(self, ctx):
    x = self.viewport.get_hadjustment().value
    y = self.viewport.get_vadjustment().value
    ctx.set_source_rgb(1., 1., 1.)
    ctx.paint()
    ctx.translate(x, y)
    for obj in self:
        obj.draw(ctx)
def add(self, item, layer = 0):
    item = Scene.Proxy(item, layers = set((layer,)))
    assert(hasattr(item.target, "draw"))
    assert(isinstance(layer, int))
    item.layers.add(layer)
    while not layer < len(self.layers):
        self.layers.append(set())
    self.layers[layer].add(item)
    if not item in self.objects:
        self.objects[item] = set()
    self.objects[item].add(layer)
def remove(self, item, layers = None):
    item = Scene.Proxy.directory[item]
    if layers == None:
        layers = self.objects[item]
    for layer in layers:
        layer.remove(item)
        item.layers.remove(layer)
    if len(item.layers) == 0:
        self.objects.remove(item)
def __iter__(self):
    for layer in self.layers:
        for item in layer:
            yield item.target
class App(object):
    def init(self):
        signals = {
            "canvas_exposed": self.update_canvas,
            "gtk_main_quit": gtk.main_quit
        }
        self.builder = gtk.Builder()
        self.builder.add_from_file("graphics_glitch.glade")
        self.window = self.builder.get_object("window")
        self.viewport = self.builder.get_object("viewport")
        self.canvas = self.builder.get_object("canvas")
        self.scene = Scene(self.viewport)
        signals.update(self.scene.signals)
        self.builder.connect_signals(signals)
        self.window.show()
def update_canvas(self, widget, event):
    ctx = self.canvas.window.cairo_create()
    self.scene.draw(ctx)
    ctx.clip()
if name == "main":
    app = App()
    scene = app.scene
    scene.add(Circle((0., 0.), 10.))
    gtk.main()
And the Glade file "graphics_glitch.glade":
<?xml version="1.0"?>
<interface>
    <requires lib="gtk+" version="2.16"/>
    <!-- interface-naming-policy project-wide -->
    <object class="GtkWindow" id="window">
        <property name="width_request">200</property>
        <property name="height_request">200</property>
        <property name="visible">True</property>
        <signal name="destroy" handler="gtk_main_quit"/>
        <child>
            <object class="GtkScrolledWindow" id="scrolledwindow1">
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="hadjustment">h_adjust</property>
                <property name="vadjustment">v_adjust</property>
                <property name="hscrollbar_policy">automatic</property>
                <property name="vscrollbar_policy">automatic</property>
                <child>
                    <object class="GtkViewport" id="viewport">
                        <property name="visible">True</property>
                        <property name="resize_mode">queue</property>
                        <child>
                            <object class="GtkDrawingArea" id="canvas">
                                <property name="width_request">640</property>
                                <property name="height_request">480</property>
                                <property name="visible">True</property>
                                <signal name="expose_event" handler="canvas_exposed"/>
                            </object>
                        </child>
                    </object>
                </child>
            </object>
        </child>
    </object>
    <object class="GtkAdjustment" id="h_adjust">
        <property name="lower">-1000</property>
        <property name="upper">1000</property>
        <property name="step_increment">1</property>
        <property name="page_increment">25</property>
        <property name="page_size">25</property>
    </object>
    <object class="GtkAdjustment" id="v_adjust">
        <property name="lower">-1000</property>
        <property name="upper">1000</property>
        <property name="step_increment">1</property>
        <property name="page_increment">25</property>
        <property name="page_size">25</property>
    </object>
</interface>
Thanks!
--Dan