#!/usr/bin/env python2 import os, threading, locale, sys from gi.repository import GObject, Gtk, Gdk GObject.threads_init() Gdk.threads_init() encoding = locale.getpreferredencoding() utf8conv = lambda x : unicode(x, encoding).encode('utf8') class Command(Gtk.ScrolledWindow): def __init__(self): super(Command, self).__init__() self.view = Gtk.TextView() self.view.set_editable(False) self.view.set_cursor_visible(False) self.buffer = self.view.get_buffer() self.add(self.view) self.listeners = [] def clear(self): self.buffer.set_text('') #self.buffer.insert_at_cursor('=======\n') def add_listener(self, listener): self.listeners.append(listener) def run(self, command): thread = threading.Thread(target=self._read_command_output, args=(command,)) thread.start() def _read_command_output(self, command): stdin, stdouterr = os.popen4(command) while 1: line = stdouterr.readline() if not line: break Gdk.threads_enter() self.add_text(utf8conv(line)) Gdk.threads_leave() for listener in self.listeners: listener(command, self.buffer.get_text()) def add_text(self, line): if not line.endswith('\n'): line += '\n' self.buffer.insert_at_cursor(line) adj = self.get_vadjustment() adj.set_value(adj.get_upper() - adj.get_page_size()) if __name__ == '__main__': import signal signal.signal(signal.SIGINT, signal.SIG_DFL) command = Command(' '.join(sys.argv[1:])) window = Gtk.Window() window.add(command) window.set_default_size(800, 600) window.show_all() window.connect("delete-event", Gtk.main_quit) Gtk.main()