mintmenu/usr/lib/linuxmint/mintMenu/plugins/terminal.py

101 lines
4.0 KiB
Python

#!/usr/bin/python
# -*- coding: utf-8 -*-
import os
import gi
gi.require_version("Gtk", "3.0")
gi.require_version('Vte', '2.91')
from gi.repository import Gtk, Gdk, GLib, Vte
class IntegratedTerminal(Gtk.Window):
def __init__(self, command, title=None, shell=None, cwd=None, width=600, height=500):
try:
self.terminal=Vte.Terminal()
self.terminal.set_scrollback_lines(-1)
# Setting the font doesn't work for some reason, let's leave it
# self.terminal.set_font(Pango.FontDescription(string='Monospace'))
self.command = command
self.ready = False
self.output_handler = self.terminal.connect("cursor-moved",
self.on_cursor_moved)
# apparently Vte.Terminal.spawn_sync() is deprecated in favour of
# the non-existent Vte.Terminal.spawn_async()...
self.terminal.spawn_sync(
Vte.PtyFlags.DEFAULT, # pty_flags
cwd or os.environ.get("HOME"), # working_directory
shell or [os.environ.get("SHELL")], # argv
[], # envv
GLib.SpawnFlags.DO_NOT_REAP_CHILD, # spawn_flags
None, # child_setup
None, # child_setup_data
None # cancellable
)
except Exception as e:
self.close()
raise Exception(e)
Gtk.Window.__init__(self, title=title or "mintMenu Integrated Terminal")
self.set_icon_name("utilities-terminal")
box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
self.scrolled_window = Gtk.ScrolledWindow()
self.scrolled_window.set_hexpand(True)
self.scrolled_window.set_vexpand(True)
self.scrolled_window.set_size_request(width, height)
self.scrolled_window.add(self.terminal)
box.pack_start(self.scrolled_window, False, True, 0)
self.add(box)
self.connect("key-press-event", self.on_key_press_event)
self.terminal.connect("child-exited", self.exit)
self.terminal.connect("eof", self.exit)
self.terminal.set_rewrap_on_resize(True)
def on_cursor_moved(self, terminal):
if not self.ready:
# we have to run the command on a callback because the
# spawn_sync() method doesn't wait for the shell to load,
# so instead we have to wait for the shell to create a prompt
self.ready = True
# if we don't show the terminal once after this it won't
# always receive output, so we show it and hide it again right
# away. Whatever works...
self.show_all()
self.hide()
# Now we can go:
command = "%s\n" % self.command
self.terminal.feed_child(command, len(command))
return
# Unfortunately we cannot guarantee that the command is on the first
# line (the shell may display somethinge else first), so we have to
# search for it:
x, y = terminal.get_cursor_position()
contents, dummy = terminal.get_text_range(0, 0, x, y, None, None)
lines = contents.split("\n")
prefix = ""
command_found = False
for line in lines:
if not line:
continue
if command_found:
if not line.lstrip(prefix):
# we got a command prompt, exit
self.exit()
return
# the command generated output, show the terminal
terminal.disconnect(self.output_handler)
self.show_all()
return
if self.command in line:
# this is our command line
prefix = line.split(self.command, 1)[0]
command_found = True
def on_key_press_event(self, widget, event):
if event.keyval == Gdk.KEY_Escape:
self.exit()
def exit(self, *args):
# Gtk.main_quit()
self.close()