diff options
Diffstat (limited to 'sugar/chat/richtext.py')
-rw-r--r-- | sugar/chat/richtext.py | 832 |
1 files changed, 416 insertions, 416 deletions
diff --git a/sugar/chat/richtext.py b/sugar/chat/richtext.py index 7a6f179..ebd8b1c 100644 --- a/sugar/chat/richtext.py +++ b/sugar/chat/richtext.py @@ -21,431 +21,431 @@ import pango import xml.sax class RichTextView(gtk.TextView): - - __gsignals__ = { - 'link-clicked': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, - ([gobject.TYPE_STRING])) - } - - def __init__(self): - gtk.TextView.__init__(self, RichTextBuffer()) - self.connect("motion-notify-event", self.__motion_notify_cb) - self.connect("button-press-event", self.__button_press_cb) - self.__hover_link = False - - def _set_hover_link(self, hover_link): - if hover_link != self.__hover_link: - self.__hover_link = hover_link - display = self.get_toplevel().get_display() - child_window = self.get_window(gtk.TEXT_WINDOW_TEXT) - - if hover_link: - cursor = gtk.gdk.Cursor(display, gtk.gdk.HAND2) - else: - cursor = gtk.gdk.Cursor(display, gtk.gdk.XTERM) - - child_window.set_cursor(cursor) - gtk.gdk.flush() - - def __iter_is_link(self, it): - item = self.get_buffer().get_tag_table().lookup("link") - if item: - return it.has_tag(item) - return False - - def __get_event_iter(self, event): - return self.get_iter_at_location(int(event.x), int(event.y)) - - def __motion_notify_cb(self, widget, event): - if event.is_hint: - event.window.get_pointer(); - - it = self.__get_event_iter(event) - if it: - hover_link = self.__iter_is_link(it) - else: - hover_link = False - - self._set_hover_link(hover_link) - - def __button_press_cb(self, widget, event): - it = self.__get_event_iter(event) - if it and self.__iter_is_link(it): - buf = self.get_buffer() - address_tag = buf.get_tag_table().lookup("object-id") - - address_end = it.copy() - address_end.backward_to_tag_toggle(address_tag) - - address_start = address_end.copy() - address_start.backward_to_tag_toggle(address_tag) - - address = buf.get_text(address_start, address_end) - self.emit("link-clicked", address) + + __gsignals__ = { + 'link-clicked': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, + ([gobject.TYPE_STRING])) + } + + def __init__(self): + gtk.TextView.__init__(self, RichTextBuffer()) + self.connect("motion-notify-event", self.__motion_notify_cb) + self.connect("button-press-event", self.__button_press_cb) + self.__hover_link = False + + def _set_hover_link(self, hover_link): + if hover_link != self.__hover_link: + self.__hover_link = hover_link + display = self.get_toplevel().get_display() + child_window = self.get_window(gtk.TEXT_WINDOW_TEXT) + + if hover_link: + cursor = gtk.gdk.Cursor(display, gtk.gdk.HAND2) + else: + cursor = gtk.gdk.Cursor(display, gtk.gdk.XTERM) + + child_window.set_cursor(cursor) + gtk.gdk.flush() + + def __iter_is_link(self, it): + item = self.get_buffer().get_tag_table().lookup("link") + if item: + return it.has_tag(item) + return False + + def __get_event_iter(self, event): + return self.get_iter_at_location(int(event.x), int(event.y)) + + def __motion_notify_cb(self, widget, event): + if event.is_hint: + event.window.get_pointer(); + + it = self.__get_event_iter(event) + if it: + hover_link = self.__iter_is_link(it) + else: + hover_link = False + + self._set_hover_link(hover_link) + + def __button_press_cb(self, widget, event): + it = self.__get_event_iter(event) + if it and self.__iter_is_link(it): + buf = self.get_buffer() + address_tag = buf.get_tag_table().lookup("object-id") + + address_end = it.copy() + address_end.backward_to_tag_toggle(address_tag) + + address_start = address_end.copy() + address_start.backward_to_tag_toggle(address_tag) + + address = buf.get_text(address_start, address_end) + self.emit("link-clicked", address) class RichTextBuffer(gtk.TextBuffer): - def __init__(self): - gtk.TextBuffer.__init__(self) - - self.connect_after("insert-text", self.__insert_text_cb) - - self.__create_tags() - self.active_tags = [] - - def append_link(self, title, address): - it = self.get_iter_at_mark(self.get_insert()) - self.insert_with_tags_by_name(it, address, "link", "object-id") - self.insert_with_tags_by_name(it, title, "link") - - def append_icon(self, name, it = None): - if not it: - it = self.get_iter_at_mark(self.get_insert()) - - self.insert_with_tags_by_name(it, name, "icon", "object-id") - icon_theme = gtk.icon_theme_get_default() - try: - pixbuf = icon_theme.load_icon(name, 16, 0) - self.insert_pixbuf(it, pixbuf) - except gobject.GError: - pass - - def apply_tag(self, tag_name): - self.active_tags.append(tag_name) - - bounds = self.get_selection_bounds() - if bounds: - [start, end] = bounds - self.apply_tag_by_name(tag_name, start, end) - - def unapply_tag(self, tag_name): - self.active_tags.remove(tag_name) - - bounds = self.get_selection_bounds() - if bounds: - [start, end] = bounds - self.remove_tag_by_name(tag_name, start, end) - - def __create_tags(self): - tag = self.create_tag("icon") - - tag = self.create_tag("link") - tag.set_property("underline", pango.UNDERLINE_SINGLE) - tag.set_property("foreground", "#0000FF") - - tag = self.create_tag("object-id") - tag.set_property("invisible", True) - - tag = self.create_tag("bold") - tag.set_property("weight", pango.WEIGHT_BOLD) - - tag = self.create_tag("italic") - tag.set_property("style", pango.STYLE_ITALIC) - - tag = self.create_tag("font-size-xx-small") - tag.set_property("scale", pango.SCALE_XX_SMALL) - - tag = self.create_tag("font-size-x-small") - tag.set_property("scale", pango.SCALE_X_SMALL) - - tag = self.create_tag("font-size-small") - tag.set_property("scale", pango.SCALE_SMALL) - - tag = self.create_tag("font-size-large") - tag.set_property("scale", pango.SCALE_LARGE) - - tag = self.create_tag("font-size-x-large") - tag.set_property("scale", pango.SCALE_X_LARGE) - - tag = self.create_tag("font-size-xx-large") - tag.set_property("scale", pango.SCALE_XX_LARGE) - - def __insert_text_cb(self, widget, pos, text, length): - for tag in self.active_tags: - pos_end = pos.copy() - pos_end.backward_chars(length) - self.apply_tag_by_name(tag, pos, pos_end) - + def __init__(self): + gtk.TextBuffer.__init__(self) + + self.connect_after("insert-text", self.__insert_text_cb) + + self.__create_tags() + self.active_tags = [] + + def append_link(self, title, address): + it = self.get_iter_at_mark(self.get_insert()) + self.insert_with_tags_by_name(it, address, "link", "object-id") + self.insert_with_tags_by_name(it, title, "link") + + def append_icon(self, name, it = None): + if not it: + it = self.get_iter_at_mark(self.get_insert()) + + self.insert_with_tags_by_name(it, name, "icon", "object-id") + icon_theme = gtk.icon_theme_get_default() + try: + pixbuf = icon_theme.load_icon(name, 16, 0) + self.insert_pixbuf(it, pixbuf) + except gobject.GError: + pass + + def apply_tag(self, tag_name): + self.active_tags.append(tag_name) + + bounds = self.get_selection_bounds() + if bounds: + [start, end] = bounds + self.apply_tag_by_name(tag_name, start, end) + + def unapply_tag(self, tag_name): + self.active_tags.remove(tag_name) + + bounds = self.get_selection_bounds() + if bounds: + [start, end] = bounds + self.remove_tag_by_name(tag_name, start, end) + + def __create_tags(self): + tag = self.create_tag("icon") + + tag = self.create_tag("link") + tag.set_property("underline", pango.UNDERLINE_SINGLE) + tag.set_property("foreground", "#0000FF") + + tag = self.create_tag("object-id") + tag.set_property("invisible", True) + + tag = self.create_tag("bold") + tag.set_property("weight", pango.WEIGHT_BOLD) + + tag = self.create_tag("italic") + tag.set_property("style", pango.STYLE_ITALIC) + + tag = self.create_tag("font-size-xx-small") + tag.set_property("scale", pango.SCALE_XX_SMALL) + + tag = self.create_tag("font-size-x-small") + tag.set_property("scale", pango.SCALE_X_SMALL) + + tag = self.create_tag("font-size-small") + tag.set_property("scale", pango.SCALE_SMALL) + + tag = self.create_tag("font-size-large") + tag.set_property("scale", pango.SCALE_LARGE) + + tag = self.create_tag("font-size-x-large") + tag.set_property("scale", pango.SCALE_X_LARGE) + + tag = self.create_tag("font-size-xx-large") + tag.set_property("scale", pango.SCALE_XX_LARGE) + + def __insert_text_cb(self, widget, pos, text, length): + for tag in self.active_tags: + pos_end = pos.copy() + pos_end.backward_chars(length) + self.apply_tag_by_name(tag, pos, pos_end) + class RichTextToolbox(gtk.HBox): - def __init__(self, buf): - gtk.HBox.__init__(self, False, 6) - - self.buf = buf - - self._font_size = "normal" - self._font_scales = [ "xx-small", "x-small", "small", \ - "normal", \ - "large", "x-large", "xx-large" ] - - image = gtk.Image() - image.set_from_stock(gtk.STOCK_BOLD, gtk.ICON_SIZE_SMALL_TOOLBAR) - - item = gtk.ToggleButton() - item.set_image(image) - item.connect("toggled", self.__toggle_style_cb, "bold") - item.unset_flags(gtk.CAN_FOCUS) - self.pack_start(item, False) - item.show() - - image.show() - - image = gtk.Image() - image.set_from_stock(gtk.STOCK_ITALIC, gtk.ICON_SIZE_SMALL_TOOLBAR) - - item = gtk.ToggleButton() - item.set_image(image) - item.unset_flags(gtk.CAN_FOCUS) - item.connect("toggled", self.__toggle_style_cb, "italic") - self.pack_start(item, False) - item.show() - - image = gtk.Image() - image.set_from_stock(gtk.STOCK_GO_UP, gtk.ICON_SIZE_SMALL_TOOLBAR) - - self._font_size_up = gtk.Button() - self._font_size_up.set_image(image) - self._font_size_up.unset_flags(gtk.CAN_FOCUS) - self._font_size_up.connect("clicked", self.__font_size_up_cb) - self.pack_start(self._font_size_up, False) - self._font_size_up.show() - - image.show() - - image = gtk.Image() - image.set_from_stock(gtk.STOCK_GO_DOWN, gtk.ICON_SIZE_SMALL_TOOLBAR) - - self._font_size_down = gtk.Button() - self._font_size_down.set_image(image) - self._font_size_down.unset_flags(gtk.CAN_FOCUS) - self._font_size_down.connect("clicked", self.__font_size_down_cb) - self.pack_start(self._font_size_down, False) - self._font_size_down.show() - - image.show() - - def _get_font_size_index(self): - return self._font_scales.index(self._font_size); - - def __toggle_style_cb(self, toggle, tag_name): - if toggle.get_active(): - self.buf.apply_tag(tag_name) - else: - self.buf.unapply_tag(tag_name) - - def _set_font_size(self, font_size): - if self._font_size != "normal": - self.buf.unapply_tag("font-size-" + self._font_size) - if font_size != "normal": - self.buf.apply_tag("font-size-" + font_size) - - self._font_size = font_size - - can_up = self._get_font_size_index() < len(self._font_scales) - 1 - can_down = self._get_font_size_index() > 0 - self._font_size_up.set_sensitive(can_up) - self._font_size_down.set_sensitive(can_down) - - def __font_size_up_cb(self, button): - index = self._get_font_size_index() - if index + 1 < len(self._font_scales): - self._set_font_size(self._font_scales[index + 1]) - - def __font_size_down_cb(self, button): - index = self._get_font_size_index() - if index > 0: - self._set_font_size(self._font_scales[index - 1]) - + def __init__(self, buf): + gtk.HBox.__init__(self, False, 6) + + self.buf = buf + + self._font_size = "normal" + self._font_scales = [ "xx-small", "x-small", "small", \ + "normal", \ + "large", "x-large", "xx-large" ] + + image = gtk.Image() + image.set_from_stock(gtk.STOCK_BOLD, gtk.ICON_SIZE_SMALL_TOOLBAR) + + item = gtk.ToggleButton() + item.set_image(image) + item.connect("toggled", self.__toggle_style_cb, "bold") + item.unset_flags(gtk.CAN_FOCUS) + self.pack_start(item, False) + item.show() + + image.show() + + image = gtk.Image() + image.set_from_stock(gtk.STOCK_ITALIC, gtk.ICON_SIZE_SMALL_TOOLBAR) + + item = gtk.ToggleButton() + item.set_image(image) + item.unset_flags(gtk.CAN_FOCUS) + item.connect("toggled", self.__toggle_style_cb, "italic") + self.pack_start(item, False) + item.show() + + image = gtk.Image() + image.set_from_stock(gtk.STOCK_GO_UP, gtk.ICON_SIZE_SMALL_TOOLBAR) + + self._font_size_up = gtk.Button() + self._font_size_up.set_image(image) + self._font_size_up.unset_flags(gtk.CAN_FOCUS) + self._font_size_up.connect("clicked", self.__font_size_up_cb) + self.pack_start(self._font_size_up, False) + self._font_size_up.show() + + image.show() + + image = gtk.Image() + image.set_from_stock(gtk.STOCK_GO_DOWN, gtk.ICON_SIZE_SMALL_TOOLBAR) + + self._font_size_down = gtk.Button() + self._font_size_down.set_image(image) + self._font_size_down.unset_flags(gtk.CAN_FOCUS) + self._font_size_down.connect("clicked", self.__font_size_down_cb) + self.pack_start(self._font_size_down, False) + self._font_size_down.show() + + image.show() + + def _get_font_size_index(self): + return self._font_scales.index(self._font_size); + + def __toggle_style_cb(self, toggle, tag_name): + if toggle.get_active(): + self.buf.apply_tag(tag_name) + else: + self.buf.unapply_tag(tag_name) + + def _set_font_size(self, font_size): + if self._font_size != "normal": + self.buf.unapply_tag("font-size-" + self._font_size) + if font_size != "normal": + self.buf.apply_tag("font-size-" + font_size) + + self._font_size = font_size + + can_up = self._get_font_size_index() < len(self._font_scales) - 1 + can_down = self._get_font_size_index() > 0 + self._font_size_up.set_sensitive(can_up) + self._font_size_down.set_sensitive(can_down) + + def __font_size_up_cb(self, button): + index = self._get_font_size_index() + if index + 1 < len(self._font_scales): + self._set_font_size(self._font_scales[index + 1]) + + def __font_size_down_cb(self, button): + index = self._get_font_size_index() + if index > 0: + self._set_font_size(self._font_scales[index - 1]) + class RichTextHandler(xml.sax.handler.ContentHandler): - def __init__(self, serializer, buf): - xml.sax.handler.ContentHandler.__init__(self) - self.buf = buf - self.serializer = serializer - self.tags = [] - self._in_richtext = False - self._done = False - - def startElement(self, name, attrs): - # Look for, and only start parsing after 'richtext' - if not self._in_richtext and name == "richtext": - self._in_richtext = True - if not self._in_richtext: - return - - if name != "richtext": - tag = self.serializer.deserialize_element(name, attrs) - self.tags.append(tag) - if name == "link": - self.href = attrs['href'] - elif name == "icon": - self.buf.append_icon(attrs['name'], self.buf.get_end_iter()) + def __init__(self, serializer, buf): + xml.sax.handler.ContentHandler.__init__(self) + self.buf = buf + self.serializer = serializer + self.tags = [] + self._in_richtext = False + self._done = False + + def startElement(self, name, attrs): + # Look for, and only start parsing after 'richtext' + if not self._in_richtext and name == "richtext": + self._in_richtext = True + if not self._in_richtext: + return + + if name != "richtext": + tag = self.serializer.deserialize_element(name, attrs) + self.tags.append(tag) + if name == "link": + self.href = attrs['href'] + elif name == "icon": + self.buf.append_icon(attrs['name'], self.buf.get_end_iter()) - def characters(self, data): - start_it = it = self.buf.get_end_iter() - mark = self.buf.create_mark(None, start_it, True) - self.buf.insert(it, data) - start_it = self.buf.get_iter_at_mark(mark) - - for tag in self.tags: - self.buf.apply_tag_by_name(tag, start_it, it) - if tag == "link": - self.buf.insert_with_tags_by_name(start_it, self.href, - "link", "object-id") - - def endElement(self, name): - if not self._done and self._in_richtext: - if name != "richtext": - self.tags.pop() - if name == "richtext": - self._done = True - self._in_richtext = False + def characters(self, data): + start_it = it = self.buf.get_end_iter() + mark = self.buf.create_mark(None, start_it, True) + self.buf.insert(it, data) + start_it = self.buf.get_iter_at_mark(mark) + + for tag in self.tags: + self.buf.apply_tag_by_name(tag, start_it, it) + if tag == "link": + self.buf.insert_with_tags_by_name(start_it, self.href, + "link", "object-id") + + def endElement(self, name): + if not self._done and self._in_richtext: + if name != "richtext": + self.tags.pop() + if name == "richtext": + self._done = True + self._in_richtext = False class RichTextSerializer: - def __init__(self): - self._open_tags = [] - - def deserialize_element(self, el_name, attributes): - if el_name == "bold": - return "bold" - elif el_name == "italic": - return "italic" - elif el_name == "font": - return "font-size-" + attributes["size"] - elif el_name == "link": - return "link" - elif el_name == "icon": - return "icon" - else: - return None - - def _parse_object_id(self, it): - object_id_tag = self.buf.get_tag_table().lookup("object-id") - end = it.copy() - end.forward_to_tag_toggle(object_id_tag) - return self.buf.get_text(it, end) - - def serialize_tag_start(self, tag, it): - name = tag.get_property("name") - if name == "bold": - return "<bold>" - elif name == "italic": - return "<italic>" - elif name == "link": - address = self._parse_object_id(it) - return "<link " + "href=\"" + address + "\">" - elif name == "icon": - name = self._parse_object_id(it) - return "<icon " + "name=\"" + name + "\"/>" - elif name == "object-id": - return "" - elif name.startswith("font-size-"): - tag_name = name.replace("font-size-", "", 1) - return "<font size=\"" + tag_name + "\">" - else: - return "<unknown>" - - def serialize_tag_end(self, tag): - name = tag.get_property("name") - if name == "bold": - return "</bold>" - elif name == "italic": - return "</italic>" - elif name == "link": - return "</link>" - elif name == "icon": - return "" - elif name == "object-id": - return "" - elif name.startswith("font-size-"): - return "</font>" - else: - return "</unknown>" - - def serialize(self, buf): - self.buf = buf - - res = "<richtext>" - - next_it = buf.get_start_iter() - while not next_it.is_end(): - it = next_it.copy() - if not next_it.forward_to_tag_toggle(None): - next_it = buf.get_end_iter() - - tags_to_reopen = [] - - for tag in it.get_toggled_tags(False): - while 1: - open_tag = self._open_tags.pop() - res += self.serialize_tag_end(tag) - if open_tag == tag: - break - tags_to_reopen.append(open_tag) - - for tag in tags_to_reopen: - self._open_tags.append(tag) - res += self.serialize_tag_start(tag, it) - - for tag in it.get_toggled_tags(True): - self._open_tags.append(tag) - res += self.serialize_tag_start(tag, it) - - res += buf.get_text(it, next_it, False) - - if next_it.is_end(): - self._open_tags.reverse() - for tag in self._open_tags: - res += self.serialize_tag_end(tag) - - res += "</richtext>" - - return res - - def deserialize(self, xml_string, buf): - parser = xml.sax.make_parser() - handler = RichTextHandler(self, buf) - parser.setContentHandler(handler) - parser.feed(xml_string) - parser.close() + def __init__(self): + self._open_tags = [] + + def deserialize_element(self, el_name, attributes): + if el_name == "bold": + return "bold" + elif el_name == "italic": + return "italic" + elif el_name == "font": + return "font-size-" + attributes["size"] + elif el_name == "link": + return "link" + elif el_name == "icon": + return "icon" + else: + return None + + def _parse_object_id(self, it): + object_id_tag = self.buf.get_tag_table().lookup("object-id") + end = it.copy() + end.forward_to_tag_toggle(object_id_tag) + return self.buf.get_text(it, end) + + def serialize_tag_start(self, tag, it): + name = tag.get_property("name") + if name == "bold": + return "<bold>" + elif name == "italic": + return "<italic>" + elif name == "link": + address = self._parse_object_id(it) + return "<link " + "href=\"" + address + "\">" + elif name == "icon": + name = self._parse_object_id(it) + return "<icon " + "name=\"" + name + "\"/>" + elif name == "object-id": + return "" + elif name.startswith("font-size-"): + tag_name = name.replace("font-size-", "", 1) + return "<font size=\"" + tag_name + "\">" + else: + return "<unknown>" + + def serialize_tag_end(self, tag): + name = tag.get_property("name") + if name == "bold": + return "</bold>" + elif name == "italic": + return "</italic>" + elif name == "link": + return "</link>" + elif name == "icon": + return "" + elif name == "object-id": + return "" + elif name.startswith("font-size-"): + return "</font>" + else: + return "</unknown>" + + def serialize(self, buf): + self.buf = buf + + res = "<richtext>" + + next_it = buf.get_start_iter() + while not next_it.is_end(): + it = next_it.copy() + if not next_it.forward_to_tag_toggle(None): + next_it = buf.get_end_iter() + + tags_to_reopen = [] + + for tag in it.get_toggled_tags(False): + while 1: + open_tag = self._open_tags.pop() + res += self.serialize_tag_end(tag) + if open_tag == tag: + break + tags_to_reopen.append(open_tag) + + for tag in tags_to_reopen: + self._open_tags.append(tag) + res += self.serialize_tag_start(tag, it) + + for tag in it.get_toggled_tags(True): + self._open_tags.append(tag) + res += self.serialize_tag_start(tag, it) + + res += buf.get_text(it, next_it, False) + + if next_it.is_end(): + self._open_tags.reverse() + for tag in self._open_tags: + res += self.serialize_tag_end(tag) + + res += "</richtext>" + + return res + + def deserialize(self, xml_string, buf): + parser = xml.sax.make_parser() + handler = RichTextHandler(self, buf) + parser.setContentHandler(handler) + parser.feed(xml_string) + parser.close() def test_quit(w, rb): - print RichTextSerializer().serialize(rb) - gtk.main_quit() - + print RichTextSerializer().serialize(rb) + gtk.main_quit() + def link_clicked(v, address): - print "Link clicked " + address + print "Link clicked " + address if __name__ == "__main__": - window = gtk.Window() - window.set_default_size(400, 300) - - vbox = gtk.VBox() - - view = RichTextView() - view.connect("link-clicked", link_clicked) - vbox.pack_start(view) - view.show() - - rich_buf = view.get_buffer() - - test_xml = "<richtext>" - - test_xml += "<bold><italic>Test</italic>one</bold>\n" - test_xml += "<bold><italic>Test two</italic></bold>" - test_xml += "<font size=\"xx-small\">Test three</font>" - test_xml += "<link href=\"http://www.gnome.org\">Test link</link>" - test_xml += "<icon name=\"stock_help-chat\"/>" - test_xml += "</richtext>" - - RichTextSerializer().deserialize(test_xml, rich_buf) - - toolbar = RichTextToolbar(rich_buf) - vbox.pack_start(toolbar, False) - toolbar.show() - - window.add(vbox) - vbox.show() - - window.show() - - window.connect("destroy", test_quit, rich_buf) - - gtk.main() + window = gtk.Window() + window.set_default_size(400, 300) + + vbox = gtk.VBox() + + view = RichTextView() + view.connect("link-clicked", link_clicked) + vbox.pack_start(view) + view.show() + + rich_buf = view.get_buffer() + + test_xml = "<richtext>" + + test_xml += "<bold><italic>Test</italic>one</bold>\n" + test_xml += "<bold><italic>Test two</italic></bold>" + test_xml += "<font size=\"xx-small\">Test three</font>" + test_xml += "<link href=\"http://www.gnome.org\">Test link</link>" + test_xml += "<icon name=\"stock_help-chat\"/>" + test_xml += "</richtext>" + + RichTextSerializer().deserialize(test_xml, rich_buf) + + toolbar = RichTextToolbar(rich_buf) + vbox.pack_start(toolbar, False) + toolbar.show() + + window.add(vbox) + vbox.show() + + window.show() + + window.connect("destroy", test_quit, rich_buf) + + gtk.main() |