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 on Ubuntu 10.10 and 11.04, and implement searching
by regular expression (Roberto Aguilar #709018)
* Optimise various low level components so they are dramatically
faster (Stephen Boddy)
terminator 0.95:
* 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):
"""Walk the widget tree to find all of the visible terminals. That is,
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 = {}
for child in self.get_offspring():

View File

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

View File

@ -12,7 +12,7 @@ from factory import Factory
from container import Container
from editablelabel import EditableLabel
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 implementing a gtk.Notebook container"""
@ -173,7 +173,7 @@ class Notebook(Container, gtk.Notebook):
def newtab(self, debugtab=False, widget=None, cwd=None):
"""Add a new tab, optionally supplying a child widget"""
maker = Factory()
top_window = get_top_window(self)
top_window = self.get_toplevel()
if not widget:
widget = maker.make('Terminal')

View File

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

View File

@ -15,7 +15,7 @@ import pango
import subprocess
import urllib
from util import dbg, err, gerr, get_top_window
from util import dbg, err, gerr
import util
from config import Config
from cwd import get_default_cwd
@ -118,6 +118,8 @@ class Terminal(gtk.VBox):
self.origcwd = self.terminator.origcwd
self.clipboard = gtk.clipboard_get(gtk.gdk.SELECTION_CLIPBOARD)
self.pending_on_vte_size_allocate = False
self.vte = vte.Terminal()
self.vte.set_size(80, 24)
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.vte.connect('grab-focus', self.on_vte_focus)
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.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?
groupsend = self.terminator.groupsend
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 self.group and groupsend == groupsend_type['group']:
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):
"""Make sure that we're visible and focussed"""
window = util.get_top_window(self)
window = self.get_toplevel()
topchild = window.get_child()
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"""
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):
self.titlebar.update_terminal_size(self.vte.get_column_count(),
self.vte.get_row_count())
if self.vte.window and self.config['geometry_hinting']:
window = util.get_top_window(self)
window.set_rough_geometry_hints()
window = self.get_toplevel()
window.deferred_set_rough_geometry_hints()
def on_vte_notify_enter(self, term, event):
"""Handle the mouse entering this terminal"""
@ -1079,7 +1093,7 @@ for %s (%s)' % (name, urlplugin.__class__.__name__))
"""Determine if we are a zoomed terminal"""
prop = None
parent = self.get_parent()
window = get_top_window(self)
window = self.get_toplevel()
try:
prop = window.get_property('term-zoomed')
@ -1313,7 +1327,7 @@ for %s (%s)' % (name, urlplugin.__class__.__name__))
def on_beep(self, widget):
"""Set the urgency hint for our window"""
if self.config['urgent_bell'] == True:
window = util.get_top_window(self)
window = self.get_toplevel()
window.set_urgency_hint(True)
if self.config['icon_bell'] == True:
self.titlebar.icon_bell()

View File

@ -89,14 +89,6 @@ def has_ancestor(widget, wtype):
return(True)
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):
'''Find a command in our path'''
if os.path.isabs(command):

View File

@ -81,6 +81,8 @@ class Window(Container, gtk.Window):
err('Window::__init__: Unable to parse geometry: %s' %
options.geometry)
self.pending_set_rough_geometry_hint = False
def do_get_property(self, prop):
"""Handle gobject getting a property"""
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.
Mostly using Container::get_visible_terminals()"""
terminals = {}
maker = Factory()
if not hasattr(self, 'cached_maker'):
self.cached_maker = Factory()
maker = self.cached_maker
child = self.get_child()
if not child:
@ -508,10 +512,24 @@ class Window(Container, gtk.Window):
return(terminal)
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):
"""Walk all the terminals along the top and left edges to fake up how
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'):
dbg("We don't currently support geometry hinting with tabs")
return