Search code examples
pythongtk

Show terminal output in a gui window using python Gtk


I am developing a program, in which I want a window that will display the output thrown by the terminal (like a package manager does ). For example, if I give the install command, the installation process should be outptutted to my window and not the terminal. Is there a way to do this in python Gtk?

I am using an Ubuntu 13.04.


Solution

  • If you are on Linux (as you state), something like this should work:

    import gtk 
    import gobject
    import pango
    import os
    from subprocess import Popen, PIPE
    import fcntl
    
    wnd = gtk.Window()
    wnd.set_default_size(400, 400)
    wnd.connect("destroy", gtk.main_quit)
    textview = gtk.TextView()
    fontdesc = pango.FontDescription("monospace")
    textview.modify_font(fontdesc)
    scroll = gtk.ScrolledWindow()
    scroll.add(textview)
    exp = gtk.Expander("Details")
    exp.add(scroll)
    wnd.add(exp)
    wnd.show_all()
    sub_proc = Popen("ping -c 10 localhost", stdout=PIPE, shell=True)
    sub_outp = ""
    
    
    def non_block_read(output):
        fd = output.fileno()
        fl = fcntl.fcntl(fd, fcntl.F_GETFL)
        fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
        try:
            return output.read().decode("utf-8")
        except:
            return ''
    
    
    def update_terminal():
        textview.get_buffer().insert_at_cursor(non_block_read(sub_proc.stdout))
        return sub_proc.poll() is None
    
    gobject.timeout_add(100, update_terminal)
    gtk.main()
    

    The nonblocking read idea is from here.

    Using a Label to display the text:

    import gtk 
    import gobject
    import os
    from subprocess import Popen, PIPE
    import fcntl
    
    wnd = gtk.Window()
    wnd.set_default_size(400, 400)
    wnd.connect("destroy", gtk.main_quit)
    label = gtk.Label()
    label.set_alignment(0, 0)
    wnd.add(label)
    wnd.show_all()
    sub_proc = Popen("ping -c 10 localhost", stdout=PIPE, shell=True)
    sub_outp = ""
    
    
    def non_block_read(output):
        ''' even in a thread, a normal read with block until the buffer is full '''
        fd = output.fileno()
        fl = fcntl.fcntl(fd, fcntl.F_GETFL)
        fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
        try:
            return output.read().decode("utf-8")
        except:
            return ''
    
    
    def update_terminal():
        label.set_text(label.get_text() + non_block_read(sub_proc.stdout))
        return sub_proc.poll() is None
    
    gobject.timeout_add(100, update_terminal)
    gtk.main()