[cairo] Progressive slowness

Nicolas Rougier Nicolas.Rougier at loria.fr
Thu Oct 11 13:02:44 PDT 2007

Hi all,

I've been using cairo to do a very simple application in python: moving
and zooming a box in a window. The app (see below) is ok but when I zoom
in, the app is getting very slow and speed up again when I zoom out. I
guess I did something wrong but I cannot find it. The only reason I see
for the progressive slowness would be that I'm drawing part of the box
far beyond the visible surface (when it's zoomed in) but I thought the
clipping what responsible for handling such cases. Any idea ?


Source follows:

#!/usr/bin/env python
import gtk

class Grid (gtk.DrawingArea):

    zoom     = 1
    position = (0,0)
    _drag_to = (0,0)

    def __init__(self):
                        | gtk.gdk.LEAVE_NOTIFY_MASK
                        | gtk.gdk.BUTTON_PRESS_MASK
                        | gtk.gdk.BUTTON_RELEASE_MASK
                        | gtk.gdk.BUTTON_RELEASE_MASK
                        | gtk.gdk.SCROLL_MASK
                        | gtk.gdk.POINTER_MOTION_MASK
                        | gtk.gdk.POINTER_MOTION_HINT_MASK)
        self.connect ("expose-event",         self.expose)
        self.connect ("button-press-event",   self.button_press)
        self.connect ("scroll-event",         self.scroll)
        self.connect ("button-release-event", self.button_release)
        self.connect ("motion-notify-event",  self.motion)

    def expose (self, widget, event):
        self.context = widget.window.cairo_create()
        self.context.rectangle (event.area.x, event.area.y,
                                event.area.width, event.area.height)
        self.draw ()
        return False

    def button_press (self, widget, event):
        if event.button == 1:
            window = widget.get_parent_window()
            window.set_cursor (gtk.gdk.Cursor(gtk.gdk.FLEUR))
            self.drag_start (event.x, event.y)
    def scroll (self, widget, event):
        if event.direction == gtk.gdk.SCROLL_UP:
        elif event.direction == gtk.gdk.SCROLL_DOWN:

    def button_release (self, widget, event):
        window = widget.get_parent_window()
        window.set_cursor (gtk.gdk.Cursor(gtk.gdk.TOP_LEFT_ARROW))
        self.drag_end ()

    def motion (self, widget, event):
        if event.is_hint:
            x, y, state = event.window.get_pointer()
            x = event.x
            y = event.y
            state = event.state
        if state & gtk.gdk.BUTTON1_MASK:
            self.drag_to (x,y)

    def zoom_in (self):
        self.zoom = self.zoom * 1.1

    def zoom_out (self):
        self.zoom = self.zoom / 1.1

    def drag_start (self, x, y):
        self._drag_start = x,y

    def drag_to (self, x, y):
        dx = x - self._drag_start[0]
        dy = y - self._drag_start[1]
        self._drag_to = dx,dy

    def drag_end (self):
        self._drag_to = 0,0
        self.position = (self.position[0]+self._translated_drag_to[0], 

    def draw (self):
        cr = self.context
        x, y, width, height = self.get_allocation()

        # Set a normalized and undeformed scale
        size = min (width, height)/1.0
        size *= self.zoom
        cr.scale (size,size)
        width  = width/size
        height = height/size

        # White background
        cr.set_source_rgb (1.0, 1.0, 1.0)
        cr.rectangle (0, 0, width, height)
        cr.set_source_rgb (0, 0, 0)
        # cr.set_line_width (max (cr.device_to_user_distance (1,1)))
        cr.set_line_width (.001)

        # Compute current move in user_distance
        dx,dy = self._drag_to
        self._translated_drag_to = cr.device_to_user_distance (dx,dy)
        dx,dy = self._translated_drag_to
        dx += self.position[0]
        dy += self.position[1]

        # Draw the box
        cr.move_to ((width-1.0)/2.0  + dx, (height-1.0)/2.0 + dy) 
        cr.rel_line_to (0,1)
        cr.rel_line_to (1,0)
        cr.rel_line_to (0,-1)
        cr.rel_line_to (-1,0)

def main():
    window = gtk.Window()
    window.set_default_size (512,512)
    grid = Grid ()
    window.connect("destroy", gtk.main_quit)

if __name__ == "__main__":

More information about the cairo mailing list