Optimise various low level parts (Stephen Boddy)

This commit is contained in:
Chris Jones 2011-08-20 14:53:23 +01:00
commit 32b8d04695
8 changed files with 71 additions and 31 deletions

View File

@ -3,6 +3,8 @@ terminator 0.96:
* Fix searching with infinite scrollback (Julien Thewys #755077) * Fix searching with infinite scrollback (Julien Thewys #755077)
* Fix searching on Ubuntu 10.10 and 11.04, and implement searching * Fix searching on Ubuntu 10.10 and 11.04, and implement searching
by regular expression (Roberto Aguilar #709018) by regular expression (Roberto Aguilar #709018)
* Optimise various low level components so they are dramatically
faster (Stephen Boddy)
terminator 0.95: terminator 0.95:
* Add a configuration option to enable a DBus server * Add a configuration option to enable a DBus server

View File

@ -195,7 +195,9 @@ the %s will also close all terminals within it.') % (reqtype, reqtype))
def get_visible_terminals(self): def get_visible_terminals(self):
"""Walk the widget tree to find all of the visible terminals. That is, """Walk the widget tree to find all of the visible terminals. That is,
any terminals which are not hidden in another Notebook pane""" any terminals which are not hidden in another Notebook pane"""
maker = Factory() if not hasattr(self, 'cached_maker'):
self.cached_maker = Factory()
maker = self.cached_maker
terminals = {} terminals = {}
for child in self.get_offspring(): for child in self.get_offspring():

View File

@ -33,6 +33,9 @@ class Factory(Borg):
'Notebook': 'notebook', 'Notebook': 'notebook',
'Container': 'container', 'Container': 'container',
'Window': 'window'} 'Window': 'window'}
types_keys = types.keys()
instance_types = {}
instance_types_keys = []
def __init__(self): def __init__(self):
"""Class initialiser""" """Class initialiser"""
@ -45,16 +48,25 @@ class Factory(Borg):
def isinstance(self, product, classtype): def isinstance(self, product, classtype):
"""Check if a given product is a particular type of object""" """Check if a given product is a particular type of object"""
if classtype in self.types.keys(): if classtype in self.types_keys:
# This is quite ugly, but we're importing from the current # This is now very ugly, but now it's fast :-)
# directory if that makes sense, otherwise falling back to # Someone with real Python skills should fix this to be less insane.
# terminatorlib. Someone with real Python skills should fix # Optimisations:
# this to be less insane. # - swap order of imports, otherwise we throw ImportError
# almost every time
# - cache everything we can
try: try:
module = __import__(self.types[classtype], None, None, ['']) type_key = 'terminatorlib.%s' % self.types[classtype]
if type_key not in self.instance_types_keys:
self.instance_types[type_key] = __import__(type_key, None, None, [''])
self.instance_types_keys.append(type_key)
module = self.instance_types[type_key]
except ImportError: except ImportError:
module = __import__('terminatorlib.%s' % self.types[classtype], type_key = self.types[classtype]
None, None, ['']) if type_key not in self.instance_types_keys:
self.instance_types[type_key] = __import__(type_key, None, None, [''])
self.instance_types_keys.append(type_key)
module = self.instance_types[type_key]
return(isinstance(product, getattr(module, classtype))) return(isinstance(product, getattr(module, classtype)))
else: else:
err('Factory::isinstance: unknown class type: %s' % classtype) err('Factory::isinstance: unknown class type: %s' % classtype)

View File

@ -12,7 +12,7 @@ from factory import Factory
from container import Container from container import Container
from editablelabel import EditableLabel from editablelabel import EditableLabel
from translation import _ from translation import _
from util import err, dbg, get_top_window, enumerate_descendants from util import err, dbg, enumerate_descendants
class Notebook(Container, gtk.Notebook): class Notebook(Container, gtk.Notebook):
"""Class implementing a gtk.Notebook container""" """Class implementing a gtk.Notebook container"""
@ -173,7 +173,7 @@ class Notebook(Container, gtk.Notebook):
def newtab(self, debugtab=False, widget=None, cwd=None): def newtab(self, debugtab=False, widget=None, cwd=None):
"""Add a new tab, optionally supplying a child widget""" """Add a new tab, optionally supplying a child widget"""
maker = Factory() maker = Factory()
top_window = get_top_window(self) top_window = self.get_toplevel()
if not widget: if not widget:
widget = maker.make('Terminal') widget = maker.make('Terminal')

View File

@ -7,7 +7,7 @@ variants"""
import gobject import gobject
import gtk import gtk
from util import dbg, err, get_top_window from util import dbg, err
from terminator import Terminator from terminator import Terminator
from factory import Factory from factory import Factory
from container import Container from container import Container
@ -86,7 +86,7 @@ class Paned(Container):
raise ValueError('Paned widgets can only have two children') raise ValueError('Paned widgets can only have two children')
if maker.isinstance(widget, 'Terminal'): if maker.isinstance(widget, 'Terminal'):
top_window = get_top_window(self) top_window = self.get_toplevel()
signals = {'close-term': self.wrapcloseterm, signals = {'close-term': self.wrapcloseterm,
'split-horiz': self.split_horiz, 'split-horiz': self.split_horiz,
'split-vert': self.split_vert, 'split-vert': self.split_vert,

View File

@ -15,7 +15,7 @@ import pango
import subprocess import subprocess
import urllib import urllib
from util import dbg, err, gerr, get_top_window from util import dbg, err, gerr
import util import util
from config import Config from config import Config
from cwd import get_default_cwd from cwd import get_default_cwd
@ -118,6 +118,8 @@ class Terminal(gtk.VBox):
self.origcwd = self.terminator.origcwd self.origcwd = self.terminator.origcwd
self.clipboard = gtk.clipboard_get(gtk.gdk.SELECTION_CLIPBOARD) self.clipboard = gtk.clipboard_get(gtk.gdk.SELECTION_CLIPBOARD)
self.pending_on_vte_size_allocate = False
self.vte = vte.Terminal() self.vte = vte.Terminal()
self.vte.set_size(80, 24) self.vte.set_size(80, 24)
self.vte._expose_data = None self.vte._expose_data = None
@ -335,7 +337,7 @@ for %s (%s)' % (name, urlplugin.__class__.__name__))
self.emit('title-change', self.get_window_title())) self.emit('title-change', self.get_window_title()))
self.vte.connect('grab-focus', self.on_vte_focus) self.vte.connect('grab-focus', self.on_vte_focus)
self.vte.connect('focus-in-event', self.on_vte_focus_in) self.vte.connect('focus-in-event', self.on_vte_focus_in)
self.vte.connect('size-allocate', self.on_vte_size_allocate) self.vte.connect('size-allocate', self.deferred_on_vte_size_allocate)
self.vte.add_events(gtk.gdk.ENTER_NOTIFY_MASK) self.vte.add_events(gtk.gdk.ENTER_NOTIFY_MASK)
self.vte.connect('enter_notify_event', self.vte.connect('enter_notify_event',
@ -747,7 +749,7 @@ for %s (%s)' % (name, urlplugin.__class__.__name__))
# maybe we can emit the key event and let Terminator() care? # maybe we can emit the key event and let Terminator() care?
groupsend = self.terminator.groupsend groupsend = self.terminator.groupsend
groupsend_type = self.terminator.groupsend_type groupsend_type = self.terminator.groupsend_type
window_focussed = get_top_window(self.vte).get_property('has-toplevel-focus') window_focussed = self.vte.get_toplevel().get_property('has-toplevel-focus')
if groupsend != groupsend_type['off'] and window_focussed and self.vte.is_focus(): if groupsend != groupsend_type['off'] and window_focussed and self.vte.is_focus():
if self.group and groupsend == groupsend_type['group']: if self.group and groupsend == groupsend_type['group']:
self.terminator.group_emit(self, self.group, 'key-press-event', self.terminator.group_emit(self, self.group, 'key-press-event',
@ -961,7 +963,7 @@ for %s (%s)' % (name, urlplugin.__class__.__name__))
def ensure_visible_and_focussed(self): def ensure_visible_and_focussed(self):
"""Make sure that we're visible and focussed""" """Make sure that we're visible and focussed"""
window = util.get_top_window(self) window = self.get_toplevel()
topchild = window.get_child() topchild = window.get_child()
maker = Factory() maker = Factory()
@ -1002,12 +1004,24 @@ for %s (%s)' % (name, urlplugin.__class__.__name__))
"""A child widget is done editing a label, return focus to VTE""" """A child widget is done editing a label, return focus to VTE"""
self.vte.grab_focus() self.vte.grab_focus()
def deferred_on_vte_size_allocate(self, widget, allocation):
# widget & allocation are not used in on_vte_size_allocate, so we
# can use the on_vte_size_allocate instead of duplicating the code
if self.pending_on_vte_size_allocate == True:
return
self.pending_on_vte_size_allocate = True
gobject.idle_add(self.do_deferred_on_vte_size_allocate, widget, allocation)
def do_deferred_on_vte_size_allocate(self, widget, allocation):
self.pending_on_vte_size_allocate = False
self.on_vte_size_allocate(widget, allocation)
def on_vte_size_allocate(self, widget, allocation): def on_vte_size_allocate(self, widget, allocation):
self.titlebar.update_terminal_size(self.vte.get_column_count(), self.titlebar.update_terminal_size(self.vte.get_column_count(),
self.vte.get_row_count()) self.vte.get_row_count())
if self.vte.window and self.config['geometry_hinting']: if self.vte.window and self.config['geometry_hinting']:
window = util.get_top_window(self) window = self.get_toplevel()
window.set_rough_geometry_hints() window.deferred_set_rough_geometry_hints()
def on_vte_notify_enter(self, term, event): def on_vte_notify_enter(self, term, event):
"""Handle the mouse entering this terminal""" """Handle the mouse entering this terminal"""
@ -1079,7 +1093,7 @@ for %s (%s)' % (name, urlplugin.__class__.__name__))
"""Determine if we are a zoomed terminal""" """Determine if we are a zoomed terminal"""
prop = None prop = None
parent = self.get_parent() parent = self.get_parent()
window = get_top_window(self) window = self.get_toplevel()
try: try:
prop = window.get_property('term-zoomed') prop = window.get_property('term-zoomed')
@ -1313,7 +1327,7 @@ for %s (%s)' % (name, urlplugin.__class__.__name__))
def on_beep(self, widget): def on_beep(self, widget):
"""Set the urgency hint for our window""" """Set the urgency hint for our window"""
if self.config['urgent_bell'] == True: if self.config['urgent_bell'] == True:
window = util.get_top_window(self) window = self.get_toplevel()
window.set_urgency_hint(True) window.set_urgency_hint(True)
if self.config['icon_bell'] == True: if self.config['icon_bell'] == True:
self.titlebar.icon_bell() self.titlebar.icon_bell()

View File

@ -89,14 +89,6 @@ def has_ancestor(widget, wtype):
return(True) return(True)
return(False) return(False)
def get_top_window(widget):
"""Return the Window instance a widget belongs to"""
parent = widget.get_parent()
while parent:
widget = parent
parent = widget.get_parent()
return(widget)
def path_lookup(command): def path_lookup(command):
'''Find a command in our path''' '''Find a command in our path'''
if os.path.isabs(command): if os.path.isabs(command):

View File

@ -81,6 +81,8 @@ class Window(Container, gtk.Window):
err('Window::__init__: Unable to parse geometry: %s' % err('Window::__init__: Unable to parse geometry: %s' %
options.geometry) options.geometry)
self.pending_set_rough_geometry_hint = False
def do_get_property(self, prop): def do_get_property(self, prop):
"""Handle gobject getting a property""" """Handle gobject getting a property"""
if prop.name in ['term_zoomed', 'term-zoomed']: if prop.name in ['term_zoomed', 'term-zoomed']:
@ -480,7 +482,9 @@ class Window(Container, gtk.Window):
"""Walk down the widget tree to find all of the visible terminals. """Walk down the widget tree to find all of the visible terminals.
Mostly using Container::get_visible_terminals()""" Mostly using Container::get_visible_terminals()"""
terminals = {} terminals = {}
maker = Factory() if not hasattr(self, 'cached_maker'):
self.cached_maker = Factory()
maker = self.cached_maker
child = self.get_child() child = self.get_child()
if not child: if not child:
@ -508,10 +512,24 @@ class Window(Container, gtk.Window):
return(terminal) return(terminal)
return(None) return(None)
def deferred_set_rough_geometry_hints(self):
# no parameters are used in set_rough_geometry_hints, so we can
# use the set_rough_geometry_hints
if self.pending_set_rough_geometry_hint == True:
return
self.pending_set_rough_geometry_hint = True
gobject.idle_add(self.do_deferred_set_rough_geometry_hints)
def do_deferred_set_rough_geometry_hints(self):
self.pending_set_rough_geometry_hint = False
self.set_rough_geometry_hints()
def set_rough_geometry_hints(self): def set_rough_geometry_hints(self):
"""Walk all the terminals along the top and left edges to fake up how """Walk all the terminals along the top and left edges to fake up how
many columns/rows we sort of have""" many columns/rows we sort of have"""
maker = Factory() if not hasattr(self, 'cached_maker'):
self.cached_maker = Factory()
maker = self.cached_maker
if maker.isinstance(self.get_child(), 'Notebook'): if maker.isinstance(self.get_child(), 'Notebook'):
dbg("We don't currently support geometry hinting with tabs") dbg("We don't currently support geometry hinting with tabs")
return return