import time, gobject, gtk class TreeTips: timeout = None widget = None item = None time = 0 def show(self, parent): if self.timeout: gobject.source_remove(self.timeout) self.timeout = None if self.widget: self.widget.destroy() self.widget = None if self.item is None: return text = self.get_tooltip_text(self.item) if not text: return self.widget = gtk.Window(gtk.WINDOW_POPUP) self.widget.set_app_paintable(True) self.widget.set_name('gtk-tooltips') self.widget.connect('expose-event', self.tooltip_draw) label = gtk.Label(text) label.set_line_wrap(True) label.set_padding(4, 2) self.widget.add(label) label.show() w, h = self.widget.size_request() if hasattr(parent, 'get_screen'): screen = parent.get_screen() root = screen.get_root_window() else: root = gtk.gdk.get_default_root_window() px, py, mask = gtk.gdk.Window.get_pointer(root) #m = gtk.gdk.screen_get_default().get_monitor_at_point(px, py) x = px - w / 2 y = py + 12 # Test if pointer is over the tooltip window if py >= y and py <= y + h: y = py - h - 2 self.widget.move(x, y) self.widget.show() self.widget.connect('destroy', self.tooltip_destroyed) self.time = time.time() def prime(self, parent, item): self.hide() assert self.timeout is None self.item = item now = time.time() if now - self.time > 2: delay = 1000 else: delay = 100 self.timeout = gobject.timeout_add(delay, lambda: self.show(parent)) def tooltip_draw(self, widget, ev): widget.window.draw_rectangle(widget.style.fg_gc[widget.state], False, 0, 0, widget.allocation.width - 1, widget.allocation.height - 1) def tooltip_destroyed(self, widget): pass def hide(self): self.item = None self.show(None) def get_tooltip_text(self, item): "Override in subclasses." return str(item)