[pygtk] Drawing over a gtksourceview2.View

Tony Houghton h at realh.co.uk
Thu Aug 21 05:48:41 WST 2008


I want to give a gtksourceview2.View (derived from gtk.TextView) a block
cursor like gnome-terminal etc and gvim have. It can be done by applying
a TextTag to the character under the cursor but it has some
disadvantages:

  It disappears when the cursor is on the invisible NL at the end of a
  line.

  You can't really change its appearance depending on whether the view
  is focused, because you might have more than one view on the same
  buffer and they share the same tag.

I thought of instead drawing an extra rectangle where I want the cursor
to appear, but I can't get it to work.  Specifically I tried to use a GC
with its function set to XOR and draw a rectangle in a colour worked out
by xoring the desired cursor colour with the background. The actual
drawing is done during a handler for "expose-event" connected with
connect_after(). Should this work or am I going about it in a wildly
wrong way? Is there some other way I can draw onto the View widget in my
own code or will I have to resort back to the TextTag?

The essentials of my code are below. I've verified that the expose event
handler is being called with expected coordinates (I have remembered to
convert between buffer and window coords where necessary) and does try
to draw the rectangle, but the rectangle doesn't appear on screen.

    @staticmethod
    def eor_colours(c1, c2):
        return gtk.gdk.Color(c1.red ^ c2.red, \
                c1.green ^ c2.green, c1.blue ^ c2.blue)

    ...

    def set_style(self, widget = None, old_style = None):
        ...
        # self.view is the gtksourceview2.View
        self.win = self.view.get_window(gtk.TEXT_WINDOW_WIDGET)
        ...
        c = self.eor_colours(style.base[gtk.STATE_NORMAL], self.colour)
        self.norm_gc = gtk.gdk.GC(self.win, c, c, None,
                gtk.gdk.XOR, gtk.gdk.SOLID,
                line_width = 1, line_style = gtk.gdk.LINE_SOLID)

    ...

    def enable(self):
        ...
        if self.expose_tag == None:
            self.expose_tag = self.view.connect_after("expose-event",
                    self.expose_handler)
        ...

    # ... there's some code to work out the cursor position and store it
    # in self.rect and call self.win.invalidate_rect() whenever it
    # moves, blinks or otherwise needs updating

    def expose_handler(self, widget, event):
        if self.blinked_off or not self.rect or not self.enabled:
            return True
        intersect = event.area.intersect(self.rect)
        if intersect.width and intersect.height:
            if not self.norm_gc:
                self.set_style()
            if self.in_selection:
                gc = self.sel_gc
            else:
                gc = self.norm_gc
            event.window.draw_rectangle(gc, self.has_focus,
                    self.rect.x, self.rect.y, self.rect.width, self.rect.height)
        return True     # I've tried False here, no apparent difference


-- 
TH * http://www.realh.co.uk


More information about the pygtk mailing list