diff --git a/doc/terminatorrc.5 b/doc/terminatorrc.5 index b10407f7..d7d54410 100644 --- a/doc/terminatorrc.5 +++ b/doc/terminatorrc.5 @@ -19,7 +19,7 @@ If true, don't make a noise when applications send the escape sequence for the t Default value: \fBTrue\fR .TP .B background_color -Default colour of terminal background, as a colour specification (can be HTML-style hex digits, or a colour name such as "red"). +Default colour of terminal background, as a colour specification (can be HTML-style hex digits, or a colour name such as "red"). \fBNote:\fR You may need to set \fBuse_theme_colors=False\fR to force this setting to take effect. Default value: \fB#000000\fR .TP .B background_darkness @@ -51,7 +51,7 @@ An Pango font name. Examples are "Sans 12" or "Monospace Bold 14". Default value: \fBSerif 10\fR .TP .B foreground_color -Default colour of text in the terminal, as a colour specification (can be HTML-style hex digits, or a colour name such as "red"). +Default colour of text in the terminal, as a colour specification (can be HTML-style hex digits, or a colour name such as "red"). \fBNote:\fR You may need to set \fBuse_theme_colors=False\fR to force this setting to take effect. Default value: \fB#AAAAAA\fR .TP .B scrollbar_position diff --git a/terminator b/terminator index 651dd1b1..9cd4a9f7 100755 --- a/terminator +++ b/terminator @@ -50,10 +50,15 @@ if platform.system() == 'FreeBSD': try: from terminatorlib import freebsd pid_get_cwd = lambda pid: freebsd.get_process_cwd(pid) + dbg ('Using FreeBSD pid_get_cwd') except: + dbg ('FreeBSD version too old for pid_get_cwd') pass -elif platform.system == 'Linux': +elif platform.system() == 'Linux': + dbg ('Using Linux pid_get_cwd') pid_get_cwd = lambda pid: os.path.realpath ('/proc/%s/cwd' % pid) +else: + dbg ('Unable to set a pid_get_cwd, unknown system: %s'%platform.system) # import gtk libs # check just in case anyone runs it on a non-gnome system. @@ -323,6 +328,7 @@ text/plain pos = "bottom" return pos + def add_matches (self, lboundry="[[:<:]]", rboundry="[[:>:]]"): userchars = "-A-Za-z0-9" passchars = "-A-Za-z0-9,?;.:/!%$^*&~\"#'" @@ -393,8 +399,9 @@ text/plain """ Return the current working directory of the subprocess. This function requires OS specific behaviours """ - - return (pid_get_cwd(self._pid)) + cwd = pid_get_cwd (self._pid) + dbg ('get_cwd found: %s'%cwd) + return (cwd) def reconfigure_vte (self): # Set our emulation @@ -498,9 +505,6 @@ text/plain if self.scrollbar_position == 'hidden' or self.scrollbar_position == 'disabled': self._scrollbar.hide () else: - print - print self.scrollbar_position - print self._scrollbar.show () if self.scrollbar_position == 'right': self._termbox.reorder_child (self._vte, 0) @@ -608,7 +612,13 @@ text/plain elif keyname in ('Up', 'Down', 'Left', 'Right'): self.terminator.resizeterm (self, keyname) return (True) - + elif keyname == 'Page_Down': + self.terminator.move_tab(self, 'right') + return (True) + elif keyname == 'Page_Up': + self.terminator.move_tab(self, 'left') + return (True) + mask = gtk.gdk.CONTROL_MASK if (event.state & mask) == mask: if keyname == 'Page_Down': @@ -720,13 +730,6 @@ text/plain item = gtk.MenuItem () menu.append (item) - item = gtk.MenuItem (_("M_aximize/Unmaximize")) - item.connect ("activate", lambda menu_item: self.terminator.fullwindow (self)) - menu.append (item) - - item = gtk.MenuItem () - menu.append (item) - item = gtk.ImageMenuItem (gtk.STOCK_CLOSE) item.connect ("activate", lambda menu_item: self.terminator.closeterm (self)) menu.append (item) @@ -824,11 +827,9 @@ text/plain class Terminator: def __init__ (self, profile, command = None, fullscreen = False, maximise = False, borderless = False): - self.profile = profile self.command = command - - self._fullwindow = False + self._fullscreen = False self.term_list = [] stores = [] @@ -968,8 +969,6 @@ class Terminator: Add a term to another at position pos """ vertical = pos in ("top", "bottom") - - # create a new terminal and parent pane. pane = (vertical) and gtk.VPaned () or gtk.HPaned () # get the parent of the provided terminal @@ -1009,6 +1008,7 @@ class Terminator: parent.insert_page(pane, None, page) parent.set_tab_label_text(pane, widget._vte.get_window_title()) parent.set_tab_label_packing(pane, True, True, gtk.PACK_START) + parent.set_tab_reorderable(pane, True) parent.set_current_page(page) @@ -1053,51 +1053,131 @@ class Terminator: return (terminal) def on_page_reordered(self, notebook, child, page_num): + #page has been reordered, we need to get the + # first term and last term dbg ("Reordered: %d"%page_num) + nbpages = notebook.get_n_pages() + if nbpages == 1: + dbg("[ERROR] only one page in on_page_reordered") + first = self._notebook_first_term(notebook.get_nth_page(page_num)) + last = self._notebook_last_term(notebook.get_nth_page(page_num)) + firstidx = self.term_list.index(first) + lastidx = self.term_list.index(last) + termslice = self.term_list[firstidx:lastidx+1] + #remove them from the list + for term in termslice: + self.term_list.remove(term) + + if page_num == 0: + #first page, we insert before the first term of next page + nexttab = notebook.get_nth_page(1) + sibling = self._notebook_first_term(nexttab) + siblingindex = self.term_list.index(sibling) + for term in termslice: + self.term_list.insert(siblingindex, term) + siblingindex += 1 + else: + #other pages, we insert after the last term of previous page + previoustab = notebook.get_nth_page(page_num - 1) + sibling = self._notebook_last_term(previoustab) + print sibling + siblingindex = self.term_list.index(sibling) + for term in termslice: + siblingindex += 1 + self.term_list.insert(siblingindex, term) + + #for page reorder, we need to get the first term of a notebook + def notebook_first_term(self, notebook): + return self._notebook_first_term(notebook.get_nth_page(0)) + + def _notebook_first_term(self, child): + if isinstance(child, TerminatorTerm): + return child + elif isinstance(child, gtk.Paned): + return self._notebook_first_term(child.get_child1()) + elif isinstance(child, gtk.Notebook): + return self._notebook_first_term(child.get_nth_page(0)) + + dbg("[ERROR] unsupported class %s in _notebook_first_term" % child.__class__.__name__) + return None + + #for page reorder, we need to get the last term of a notebook + def notebook_last_term(self, notebook): + return self._notebook_last_term(notebook.get_nth_page(notebook.get_n_pages()-1)) + + def _notebook_last_term(self, child): + if isinstance(child, TerminatorTerm): + return child + elif isinstance(child, gtk.Paned): + return self._notebook_first_term(child.get_child2()) + elif isinstance(child, gtk.Notebook): + return self._notebook_first_term(child.get_nth_page(child.get_n_pages()-1)) + + dbg("[ERROR] unsupported class %s in _notebook_last_term" % child.__class__.__name__) + return None + def newtab(self,widget): terminal = TerminatorTerm (self, self.profile, None, widget.get_cwd()) - widgetbox = widget - parent = widgetbox.get_parent () + parent = widget.get_parent () if isinstance(parent, gtk.Paned) or isinstance(parent, gtk.Window): #no notebook yet. notebook = gtk.Notebook() + notebook.set_tab_pos(gtk.POS_TOP) notebook.connect('page-reordered',self.on_page_reordered) notebook.set_property('homogeneous', True) - notebook.set_tab_reorderable(widgetbox, True) + notebook.set_tab_reorderable(widget, True) if isinstance(parent, gtk.Paned): - if parent.get_child1() == widgetbox: - widgetbox.reparent(notebook) + if parent.get_child1() == widget: + widget.reparent(notebook) parent.pack1(notebook) else: - widgetbox.reparent(notebook) + widget.reparent(notebook) parent.pack2(notebook) elif isinstance(parent, gtk.Window): - widgetbox.reparent(notebook) + widget.reparent(notebook) parent.add(notebook) - notebook.set_tab_reorderable(widgetbox,True) + notebook.set_tab_reorderable(widget,True) notebooklabel = "" if widget._vte.get_window_title() is not None: notebooklabel = widget._vte.get_window_title() - notebook.set_tab_label_text(widgetbox, notebooklabel) - notebook. set_tab_label_packing(widgetbox, True, True, gtk.PACK_START) + notebook.set_tab_label_text(widget, notebooklabel) + notebook. set_tab_label_packing(widget, True, True, gtk.PACK_START) notebook.show() elif isinstance(parent, gtk.Notebook): notebook = parent else: return (False) - notebook.append_page(terminal,terminal._vte.get_window_title()) - notebook. set_tab_label_packing(terminal, True, True, gtk.PACK_START) - notebook.set_tab_reorderable(terminal,True) - notebook.set_current_page(-1) - index = self.term_list.index(widget) - self.term_list.insert (index + 1, terminal) + ## NOTE + ## Here we need to append to the notebook before we can + ## spawn the terminal (WINDOW_ID needs to be set) + + notebook.append_page(terminal,None) terminal.show () terminal.spawn_child () + ## Some gtk/vte weirdness + ## If we don't use this silly test, + ## terminal._vte.get_window_title() might return + ## bogus values + notebooklabel = "" + if terminal._vte.get_window_title() is not None: + notebooklabel = terminal._vte.get_window_title() + notebook.set_tab_label_text(terminal, notebooklabel) + notebook.set_tab_label_packing(terminal, True, True, gtk.PACK_START) + notebook.set_tab_reorderable(terminal,True) + ## Now, we set focus on the new term + notebook.set_current_page(-1) terminal._vte.grab_focus () + + #adding a new tab, thus we need to get the + # last term of the previous tab and add + # the new term just after + sibling = self._notebook_last_term(notebook.get_nth_page(notebook.page_num(terminal)-1)) + index = self.term_list.index(sibling) + self.term_list.insert (index + 1, terminal) return (True) @@ -1105,11 +1185,6 @@ class Terminator: def splitaxis (self, widget, vertical=True): """ Split the provided widget on the horizontal or vertical axis. """ - - #should disable splitaxis menu instead? - if self._fullwindow: - return - # create a new terminal and parent pane. terminal = TerminatorTerm (self, self.profile, None, widget.get_cwd()) pos = vertical and "bottom" or "right" @@ -1121,9 +1196,6 @@ class Terminator: def remove(self, widget): """Remove a TerminatorTerm from the Terminator view and terms list Returns True on success, False on failure""" - if self._fullwindow: - self.show_back_others(widget) - parent = widget.get_parent () sibling = None @@ -1159,6 +1231,8 @@ class Terminator: grandparent.remove_page(page) grandparent.insert_page(sibling, None,page) grandparent.set_tab_label_packing(sibling, True, True, gtk.PACK_START) + grandparent.set_tab_reorderable(sibling, True) + else: grandparent.remove (parent) @@ -1264,6 +1338,8 @@ class Terminator: break previousterm._vte.grab_focus () + + def resizeterm (self, widget, keyname): vertical = False @@ -1305,6 +1381,26 @@ class Terminator: notebook.next_page() return + def move_tab(self, term, direction): + dbg("moving to direction %s" % direction) + (notebook, page) = self.get_first_notebook_page(term) + page_num = notebook.page_num(page) + nbpages = notebook.get_n_pages() + #dbg ("%s %s %s %s" % (page_num, nbpages,notebook, page)) + if page_num == 0 and direction == 'left': + new_page_num = nbpages + elif page_num == nbpages - 1 and direction == 'right': + new_page_num = 0 + elif direction == 'left': + new_page_num = page_num - 1 + elif direction == 'right': + new_page_num = page_num + 1 + else: + dbg("[ERROR] unhandled combination in move_tab: direction = %s page_num = %d" % (direction, page_num)) + return False + notebook.reorder_child(page, new_page_num) + return True + def get_first_parent_notebook(self, widget): if isinstance (widget, gtk.Window): return None @@ -1344,43 +1440,6 @@ class Terminator: for term in self.term_list: term.reconfigure_vte () - def fullwindow(self, widget): - if not self._fullwindow: - self.hide_all_but_me(widget) - else: - self.show_back_others(widget) - - def hide_all_but_me (self, widget): - """Proof of concept: Maximize to full window - an instance of TerminatorTerm. - """ - self.old_parent = widget.get_parent() - if isinstance(self.old_parent, gtk.Window): - return - if isinstance(self.old_parent, gtk.Notebook): - self.old_page = self.old_parent.get_current_page() - self.window_child = self.window.get_children()[0] - self.window.remove(self.window_child) - self.old_parent.remove(widget) - self.window.add(widget) - self._fullwindow = True - - def show_back_others(self, widget): - """Proof of concept: Go back to previous application - widget structure. - """ - if self._fullwindow: - self.window.remove(widget) - self.window.add(self.window_child) - self.old_parent.add(widget) - if isinstance(self.old_parent, gtk.Notebook): - self.old_parent.set_current_page(self.old_page) - print "\nPARENT IS A NOTEBOOK\n" - self._fullwindow = False - return - else: - return - if __name__ == '__main__': def execute_cb (option, opt, value, parser): diff --git a/terminatorlib/config.py b/terminatorlib/config.py index 8e945dc0..751fef06 100755 --- a/terminatorlib/config.py +++ b/terminatorlib/config.py @@ -32,7 +32,7 @@ AttributeError. This is by design. If you want to look something up, set a default for it first.""" # import standard python libs -import os, sys +import os, sys, re # import unix-lib import pwd @@ -58,8 +58,8 @@ class TerminatorConfig: self.sources.append (source) def __getattr__ (self, keyname): - dbg ("TConfig: Looking for: '%s'"%keyname) for source in self.sources: + dbg ("TConfig: Looking for: '%s' in '%s'"%(keyname, source.type)) try: val = getattr (source, keyname) dbg (" TConfig: got: '%s' from a '%s'"%(val, source.type)) @@ -81,11 +81,12 @@ class TerminatorConfValuestore: 'profile_dir' : '/apps/gnome-terminal/profiles', 'titlebars' : True, 'titletips' : False, - 'allow_bold' : False, + 'allow_bold' : True, 'silent_bell' : True, 'background_color' : '#000000', 'background_darkness' : 0.5, 'background_type' : 'solid', + 'background_image' : '', 'backspace_binding' : 'ascii-del', 'delete_binding' : 'delete-sequence', 'cursor_blink' : False, @@ -112,12 +113,15 @@ class TerminatorConfValuestore: 'ignore_hosts' : ['localhost','127.0.0.0/8','*.local'], 'encoding' : 'UTF-8', 'active_encodings' : ['UTF-8', 'ISO-8859-1'], + 'background_image' : '', } def __getattr__ (self, keyname): if self.values.has_key (keyname): + dbg ("Returning '%s'"%keyname) return self.values[keyname] else: + dbg ("Failed to find '%s'"%keyname) raise (AttributeError) class TerminatorConfValuestoreDefault (TerminatorConfValuestore): @@ -127,6 +131,7 @@ class TerminatorConfValuestoreDefault (TerminatorConfValuestore): class TerminatorConfValuestoreRC (TerminatorConfValuestore): rcfilename = "" + splitter = re.compile("\s*=\s*") #FIXME: use inotify to watch the rc, split __init__ into a parsing function # that can be re-used when rc changes. def __init__ (self): @@ -141,14 +146,33 @@ class TerminatorConfValuestoreRC (TerminatorConfValuestore): try: item = item.strip () if item and item[0] != '#': - (key, value) = item.split ("=") - dbg (" VS_RCFile: Setting value %s to %s"%(key, value)) - if value == 'True': - self.values[key] = True - elif value == 'False': - self.values[key] = False - except: - dbg (" VS_RCFile: Exception handling: %s"%item) + (key, value) = self.splitter.split (item) + + # Check if this is actually a key we care about + if not self.defaults.has_key (key): + raise AttributeError; + + deftype = self.defaults[key].__class__.__name__ + if deftype == 'bool': + if value.lower () == 'true': + self.values[key] = True + elif value.lower () == 'false': + self.values[key] = False + else: + raise AttributeError + elif deftype == 'int': + self.values[key] = int (value) + elif deftype == 'float': + self.values[key] = float (value) + elif deftype == 'list': + print >> sys.stderr, _("Reading list values from .terminatorrc is not currently supported") + raise ValueError + else: + self.values[key] = value + + dbg (" VS_RCFile: Set value '%s' to '%s'"%(key, self.values[key])) + except Exception, e: + dbg (" VS_RCFile: %s Exception handling: %s" % (type(e), item)) pass class TerminatorConfValuestoreGConf (TerminatorConfValuestore): diff --git a/terminatorlib/freebsd.py b/terminatorlib/freebsd.py index 221d5146..8937dc4d 100644 --- a/terminatorlib/freebsd.py +++ b/terminatorlib/freebsd.py @@ -39,20 +39,19 @@ class kinfo_file(Structure): ('kf_sa_peer', sockaddr_storage), ] +libc = CDLL('libc.so') + +len = c_uint(sizeof(c_uint)) +ver = c_uint(0) + +if (libc.sysctlbyname('kern.osreldate', byref(ver), byref(len), None, 0) < 0): + raise OSError, "sysctlbyname returned < 0" + +# kern.proc.filedesc added for procstat(1) after these __FreeBSD_versions +if ver.value < 700104 and ver.value < 800019: + raise NotImplementedError, "cwd detection requires a recent 7.0-STABLE or 8-CURRENT" def get_process_cwd(pid): - libc = CDLL('libc.so') - - len = c_uint(sizeof(c_uint)) - ver = c_uint(0) - - if (libc.sysctlbyname('kern.osreldate', byref(ver), byref(len), None, 0) < 0): - return None - - # kern.proc.filedesc added for procstat(1) after these __FreeBSD_versions - if ver.value < 700104 and ver.value < 800019: - return None - # /usr/include/sys/sysctl.h # CTL_KERN, KERN_PROC, KERN_PROC_FILEDESC oid = (c_uint * 4)(1, 14, 14, pid)