def __init__(self): plugin.MenuItem.__init__(self) self.config = Config() self.pluginConfig = parsePluginConfig(self.config) self.loggingTerminals = {} self.scrollbackLines = self.config['scrollback_lines'] dbg("using config: %s" % self.pluginConfig)
def configure(self, widget): store_factory = StoreFactory() gen_store = store_factory.create_gen_store(self.config) action_stores = {} for pattern in self.config.keys(): action_stores[pattern] = store_factory.create_action_store( self.config[pattern]['actions']) dialog = RunWithDialog(gen_store, action_stores, widget, title='RunWith configuration') icon_theme = Gtk.IconTheme.get_default() if icon_theme.lookup_icon('terminator-run-with', 48, 0): dialog.set_icon_name('terminator-run-with') else: dbg('Cannot load Terminator RunWith icon') icon = dialog.render_icon(Gtk.STOCK_DIALOG_INFO, Gtk.IconSize.BUTTON) dialog.set_icon(icon) while True: result = dialog.run() if result == Gtk.ResponseType.OK: if dialog.is_gen_store_valid(): self.save_config(dialog) break else: break dialog.destroy() return
def __init__(self): super(TerminalExporter, self).__init__() self.config = Config() self.plugin_config = parse_plugin_config(self.config) self.logging_terminals = {} self.scrollback_lines = self.config['scrollback_lines'] dbg('using config: %s' % self.plugin_config)
def group_emit(self, terminal, group, type, event): """Emit to each terminal in a group""" dbg('Terminator::group_emit: emitting a keystroke for group %s' % group) for term in self.terminals: if term != terminal and term.group == group: term.vte.emit(type, eventkey2gdkevent(event))
def __init__(self): self.terminator = Terminator() self.terminator.register_launcher_window(self) self.config = config.Config() self.config.base.reload() self.builder = Gtk.Builder() try: # Figure out where our library is on-disk so we can open our UI (head, _tail) = os.path.split(config.__file__) librarypath = os.path.join(head, 'layoutlauncher.glade') with open(librarypath, mode='rt') as f: gladedata = f.read() except Exception as ex: print("Failed to find layoutlauncher.glade") print(ex) return self.builder.add_from_string(gladedata) self.window = self.builder.get_object('layoutlauncherwin') icon_theme = Gtk.IconTheme.get_default() if icon_theme.lookup_icon('terminator-layout', 48, 0): self.window.set_icon_name('terminator-layout') else: dbg('Unable to load Terminator layout launcher icon') icon = self.window.render_icon(Gtk.STOCK_DIALOG_INFO, Gtk.IconSize.BUTTON) self.window.set_icon(icon) self.builder.connect_signals(self) self.window.connect('destroy', self.on_destroy_event) self.window.show_all() self.layouttreeview = self.builder.get_object('layoutlist') self.layouttreestore = self.builder.get_object('layoutstore') self.update_layouts()
def tab_change(self, widget, num=None): """Change to a specific tab""" if num is None: err('must specify a tab to change to') maker = Factory() child = self.get_child() if not maker.isinstance(child, 'Notebook'): dbg('child is not a notebook, nothing to change to') return if num == -1: # Go to the next tab cur = child.get_current_page() pages = child.get_n_pages() if cur == pages - 1: num = 0 else: num = cur + 1 elif num == -2: # Go to the previous tab cur = child.get_current_page() if cur > 0: num = cur - 1 else: num = child.get_n_pages() - 1 child.set_current_page(num) # Work around strange bug in gtk-2.12.11 and pygtk-2.12.1 # Without it, the selection changes, but the displayed page doesn't # change child.set_current_page(child.get_current_page())
def get_pid_cwd(): """Determine an appropriate cwd function for the OS we are running on""" func = lambda pid: None system = platform.system() if system == 'Linux': dbg('Using Linux get_pid_cwd') func = linux_get_pid_cwd elif system == 'FreeBSD': try: import freebsd func = freebsd.get_process_cwd dbg('Using FreeBSD get_pid_cwd') except (OSError, NotImplementedError, ImportError): dbg('FreeBSD version too old for get_pid_cwd') elif system == 'SunOS': dbg('Using SunOS get_pid_cwd') func = sunos_get_pid_cwd elif psutil_avail: func = psutil_cwd else: dbg('Unable to determine a get_pid_cwd for OS: %s' % system) return (func)
def __init__(self): config = Config() sections = config.plugin_get_config(self.__class__.__name__) if not isinstance(sections, dict): return noord_cmds = [] for part in sections: s = sections[part] if not ("regexp" in s and "command" in s): dbg("Ignoring section %s" % s) continue regexp = s["regexp"] command = s["command"] enabled = s["enabled"] and s["enabled"] or False if "position" in s: self.cmd_list[int(s["position"])] = { 'enabled': enabled, 'regexp': regexp, 'command': command } else: noord_cmds.append({ 'enabled': enabled, 'regexp': regexp, 'command': command }) for cmd in noord_cmds: self.cmd_list[len(self.cmd_list)] = cmd self._load_configured_handlers()
def _load_configured_handlers(self): """Forge an URLhandler plugin and hide it in the available ones.""" me = sys.modules[__name__] # Current module. config = Config() for key, handler in [(key, self.cmd_list[key]) for key in sorted(self.cmd_list.keys())]: # Forge a hidden/managed plugin # (names starting with an underscore will not be displayed in the preference/plugins window). rcom_name = "_RunCmdOnMatch_{}".format( key) # key is just the index # Make a handler class. RCOM = MetaRCOM(rcom_name, handler["regexp"], handler["command"]) # Instanciate the class. setattr(me, rcom_name, RCOM) if rcom_name not in AVAILABLE: AVAILABLE.append(rcom_name) dbg("add {} to the list of URL handlers: '{}' -> '{}'".format( rcom_name, RCOM.match, RCOM.cmd)) if handler['enabled'] and rcom_name not in config[ "enabled_plugins"]: config["enabled_plugins"].append(rcom_name) config.save()
def move_tab(self, widget, direction): """Handle a keyboard shortcut for moving tab positions""" maker = Factory() notebook = self.get_child() if not maker.isinstance(notebook, 'Notebook'): dbg('not in a notebook, refusing to move tab %s' % direction) return dbg('moving tab %s' % direction) numpages = notebook.get_n_pages() page = notebook.get_current_page() child = notebook.get_nth_page(page) if direction == 'left': if page == 0: page = numpages else: page = page - 1 elif direction == 'right': if page == numpages - 1: page = 0 else: page = page + 1 else: err('unknown direction: %s' % direction) return notebook.reorder_child(child, page)
def save(self): """Save the config to a file""" dbg('ConfigBase::save: saving config') parser = ConfigObj() parser.indent_type = ' ' for section_name in ['global_config', 'keybindings']: dbg('ConfigBase::save: Processing section: %s' % section_name) section = getattr(self, section_name) parser[section_name] = dict_diff(DEFAULTS[section_name], section) parser['profiles'] = {} for profile in self.profiles: dbg('ConfigBase::save: Processing profile: %s' % profile) parser['profiles'][profile] = dict_diff( DEFAULTS['profiles']['default'], self.profiles[profile]) parser['layouts'] = {} for layout in self.layouts: dbg('ConfigBase::save: Processing layout: %s' % layout) parser['layouts'][layout] = self.layouts[layout] parser['plugins'] = {} for plugin in self.plugins: dbg('ConfigBase::save: Processing plugin: %s' % plugin) parser['plugins'][plugin] = self.plugins[plugin] config_dir = get_config_dir() if not os.path.isdir(config_dir): os.makedirs(config_dir) try: parser.write(open(self.command_line_options.config, 'w')) except Exception as ex: err('ConfigBase::save: Unable to save config: %s' % ex)
def create_layout(self, layout): """Apply layout configuration""" if 'children' not in layout: err('layout specifies no children: %s' % layout) return children = layout['children'] if len(children) != 2: # Paned widgets can only have two children err('incorrect number of children for Paned: %s' % layout) return keys = [] # FIXME: This seems kinda ugly. All we want here is to know the order # of children based on child['order'] try: child_order_map = {} for child in children: key = children[child]['order'] child_order_map[key] = child map_keys = child_order_map.keys() map_keys.sort() for map_key in map_keys: keys.append(child_order_map[map_key]) except KeyError: # We've failed to figure out the order. At least give the terminals # in the wrong order keys = children.keys() num = 0 for child_key in keys: child = children[child_key] dbg('Making a child of type: %s' % child['type']) if child['type'] == 'Terminal': pass elif child['type'] == 'VPaned': if num == 0: terminal = self.get_child1() else: terminal = self.get_child2() self.split_axis(terminal, True) elif child['type'] == 'HPaned': if num == 0: terminal = self.get_child1() else: terminal = self.get_child2() self.split_axis(terminal, False) else: err('unknown child type: %s' % child['type']) num = num + 1 self.get_child1().create_layout(children[keys[0]]) self.get_child2().create_layout(children[keys[1]]) # Set the position with ratio. For some reason more reliable than by pos. if 'ratio' in layout: self.ratio = float(layout['ratio']) self.set_position_by_ratio()
def get_last_line(self, terminal): """Retrieve last line of terminal (contains 'user@hostname')""" ret=None vte = terminal.get_vte() cursor = vte.get_cursor_position() column_count = vte.get_column_count() row_position = cursor[1] start_row = row_position start_col = 0 end_row = row_position end_col = column_count is_interesting_char = lambda a, b, c, d: True """ manage text wrapping : usecases : - PS1 too long - componant of PS1 forcing display on several lines (e.g working directory) - window resizing - ... So, very ugly algorithm if current line too short, we assume prompt is wrapped we the search for 1st line of prompt, that is : first line following the last line containing LF we iterate back until LF found (means : end of output of last command), then forward one line """ lines= vte.get_text_range(start_row, start_col, end_row, end_col, is_interesting_char) if lines and lines[0]: # line too short, iterate back if len(lines)<=self.prompt_minlen: dbg("line below prompt min size of "+str(self.prompt_minlen)+ " chars : must iterate back '"+lines+"'") start_row=start_row-1 end_row=start_row lines = vte.get_text_range(start_row, start_col, end_row, end_col, is_interesting_char) prev_lines=lines # we iterate back to first line of terminal, including history... while lines != None and start_row>=0: # LF found, PS1 first line is next line... eeeer previous pushed line if lines[len(lines)-1] == '\n': lines=prev_lines break lines = vte.get_text_range(start_row, start_col, end_row, end_col, is_interesting_char) start_row=start_row-1 end_row=start_row prev_lines=lines lines=lines.splitlines() if lines and lines[0]: if len(lines[0])>=self.line_minlen: ret=lines[0] else: # should never happen since we browse back in history dbg("line '"+lines[0]+"' too short, won't use : "+str(len(lines[0]))) return ret
def find_window_by_uuid(self, uuid): """Search our terminals for one matching the supplied UUID""" dbg(f'searching self.terminals for: {uuid}') for window in self.windows: dbg(f'checking: {window.uuid.urn} ({window})') if window.uuid.urn == uuid: return window return None
def set_cwd(self, cwd=None): if cwd is None: cwd = self.terminal.get_cwd() if cwd == self.cwd: return self.cwd = cwd cwd = self.clisnips.SetWorkingDirectory(cwd) dbg('clisnips.SetWorkingDirectory "%s"' % cwd)
def watch(self, _widget, terminal): """Watch a terminal""" vte = terminal.get_vte() self.watches[terminal] = vte.connect('contents-changed', self.reset_timer, terminal) timeout_id = gobject.timeout_add(5000, self.check_times, terminal) self.timers[terminal] = timeout_id dbg('timer %s added for %s' % (timeout_id, terminal))
def find_terminal_by_uuid(self, uuid): """Search our terminals for one matching the supplied UUID""" dbg(f'searching self.terminals for: {uuid}') for terminal in self.terminals: dbg(f'checking: {terminal.uuid.urn} ({terminal})') if terminal.uuid.urn == uuid: return terminal return None
def watch(self, _widget, terminal): """Watch a terminal""" vte = terminal.get_vte() self.watches[terminal] = vte.connect('contents-changed', self.reset_timer, terminal) timeout_id = gobject.timeout_add(5000, self.check_times, terminal) self.timers[terminal] = timeout_id dbg('timer %s added for %s' %(timeout_id, terminal))
def find_window_by_uuid(self, uuid): """Search our terminals for one matching the supplied UUID""" dbg('searching self.terminals for: %s' % uuid) for window in self.windows: dbg('checking: %s (%s)' % (window.uuid.urn, window)) if window.uuid.urn == uuid: return window return None
def remove_widget(self, widget): """Remove all signal handlers for a widget""" if widget not in self.cnxids: dbg(f'{widget} not registered') return signals = tuple(self.cnxids[widget].keys()) for signal in signals: self.remove_signal(widget, signal)
def remove_widget(self, widget): """Remove all signal handlers for a widget""" if widget not in self.cnxids: dbg('%s not registered' % widget) return signals = self.cnxids[widget].keys() for signal in list(signals): self.remove_signal(widget, signal)
def spawn(env): PythonConsoleServer.env = env tcpserver = socketserver.TCPServer(('127.0.0.1', 0), PythonConsoleServer) dbg("debugserver: listening on %s" % str(tcpserver.server_address)) debugserver = threading.Thread(target=tcpserver.serve_forever, name="DebugServer") debugserver.setDaemon(True) debugserver.start() return(debugserver, tcpserver)
def new_window_cmdline(self, options=dbus.Dictionary()): """Create a new Window""" dbg('dbus method called: new_window with parameters %s' % (options)) oldopts = self.terminator.config.options_get() oldopts.__dict__ = options self.terminator.config.options_set(oldopts) self.terminator.create_layout(oldopts.layout) self.terminator.layout_done()
def new_tab_cmdline(self, options=dbus.Dictionary()): """Create a new tab""" dbg('dbus method called: new_tab with parameters %s' % (options)) oldopts = self.terminator.config.options_get() oldopts.__dict__ = options self.terminator.config.options_set(oldopts) window = self.terminator.get_windows()[0] window.tab_new()
def find_terminal_by_uuid(self, uuid): """Search our terminals for one matching the supplied UUID""" dbg('searching self.terminals for: %s' % uuid) for terminal in self.terminals: dbg('checking: %s (%s)' % (terminal.uuid.urn, terminal)) if terminal.uuid.urn == uuid: return terminal return None
def spawn(env): PythonConsoleServer.env = env tcpserver = SocketServer.TCPServer(('127.0.0.1', 0), PythonConsoleServer) dbg("debugserver: listening on %s" % str(tcpserver.server_address)) debugserver = threading.Thread(target=tcpserver.serve_forever, name="DebugServer") debugserver.setDaemon(True) debugserver.start() return(debugserver, tcpserver)
def split_axis(self, widget, vertical=True, cwd=None, sibling=None, widgetfirst=True): """Split the axis of a terminal inside us""" dbg('called for widget: %s' % widget) order = None page_num = self.page_num(widget) if page_num == -1: err('Notebook::split_axis: %s not found in Notebook' % widget) return label = self.get_tab_label(widget) self.remove(widget) maker = Factory() if vertical: container = maker.make('vpaned') else: container = maker.make('hpaned') self.get_toplevel().set_pos_by_ratio = True if not sibling: sibling = maker.make('terminal') sibling.set_cwd(cwd) if self.config['always_split_with_profile']: sibling.force_set_profile(None, widget.get_profile()) sibling.spawn_child() if widget.group and self.config['split_to_group']: sibling.set_group(None, widget.group) elif self.config['always_split_with_profile']: sibling.force_set_profile(None, widget.get_profile()) self.insert_page(container, None, page_num) self.child_set_property(container, 'tab-expand', True) self.child_set_property(container, 'tab-fill', True) self.set_tab_reorderable(container, True) self.set_tab_label(container, label) self.show_all() order = [widget, sibling] if widgetfirst is False: order.reverse() for terminal in order: container.add(terminal) self.set_current_page(page_num) self.show_all() while Gtk.events_pending(): Gtk.main_iteration_do(False) self.get_toplevel().set_pos_by_ratio = False GLib.idle_add(terminal.ensure_visible_and_focussed)
def on_destroy_event(self, widget, data=None): """Handle window destruction""" dbg('destroying self') for terminal in self.get_visible_terminals(): terminal.close() self.cnxids.remove_all() self.terminator.deregister_window(self) self.destroy() del (self)
def on_terminal_key_pressed(self, vt, event): kv = event.keyval if kv in (gtk.keysyms.Return, gtk.keysyms.KP_Enter): # Although we registered the emission hook on vte.Terminal, # the event is also fired by terminatorlib.window.Window ... if isinstance(vt, vte.Terminal): dbg('CliSnipsMenu :: Enter pressed %s' % vt) self.on_keypress_enter() return True
def hoover(self): """Check that we still have a reason to exist""" if len(self.children) == 1: dbg('Paned::hoover: We only have one child, die') parent = self.get_parent() child = self.children[0] self.remove(child) parent.replace(self, child) del self
def get_plugins_by_capability(self, capability): """Return a list of plugins with a particular capability""" result = [] dbg('PluginRegistry::get_plugins_by_capability: searching %d plugins \ for %s' % (len(self.instances), capability)) for plugin in self.instances: if capability in self.instances[plugin].capabilities: result.append(self.instances[plugin]) return result
def page_num_descendant(self, widget): """Find the tabnum of the tab containing a widget at any level""" tabnum = self.page_num(widget) dbg("widget is direct child if not equal -1 - tabnum: %d" % tabnum) while tabnum == -1 and widget.get_parent(): widget = widget.get_parent() tabnum = self.page_num(widget) dbg("found tabnum containing widget: %d" % tabnum) return tabnum
def on_resize(self, widget, allocation): # current = self.term.vte.get_font() config = pango.FontDescription(self.term.config['font']) # dbg(current.get_size()) dbg(config.get_size()) dbg(allocation) if allocation.width < 600 or allocation.height < 400: config.set_size(int(config.get_size() * 0.85)) self.term.set_font(config)
def get_desired_visibility(self): """Returns True if the titlebar is supposed to be visible. False if not""" if self.editing() == True or self.terminal.group: dbg('implicit desired visibility') return (True) else: dbg('configured visibility: %s' % self.config['show_titlebar']) return (self.config['show_titlebar'])
def callback(self, menuitems, menu, terminal): """Add our menu items to the menu""" if not self.watches.has_key(terminal): item = gtk.MenuItem(_("Watch for silence")) item.connect("activate", self.watch, terminal) else: item = gtk.MenuItem(_("Stop watching for silence")) item.connect("activate", self.unwatch, terminal) menuitems.append(item) dbg('Menu items appended')
def tryAddLayoutMenuItem(self, name, terminal, menu): (isLayout, shortname) = self.tryGetLayoutShortName(name) if isLayout: layoutItem = gtk.MenuItem(_(shortname)) layoutItem.connect(EVENT_ACTIVATE, self.loadCallback, terminal) menu.append(layoutItem) return True else: dbg("ignoring [%s] : %s" % (name, shortname)) return False
def callback(self, menuitems, menu, terminal): """Add our menu item to the menu""" item = gtk.CheckMenuItem(_("Watch for _silence")) item.set_active(self.watches.has_key(terminal)) if item.get_active(): item.connect("activate", self.unwatch, terminal) else: item.connect("activate", self.watch, terminal) menuitems.append(item) dbg('Menu items appended')
def callback(self, menuitems, menu, terminal): """Add our menu item to the menu""" item = Gtk.CheckMenuItem.new_with_mnemonic(_('Watch for _activity')) item.set_active(self.watches.has_key(terminal)) if item.get_active(): item.connect("activate", self.unwatch, terminal) else: item.connect("activate", self.watch, terminal) menuitems.append(item) dbg('Menu item appended')
def writeXmlToFile (self, element, filename = None): if filename is None: newFilename = inputBox(title=SAVE_BOX_TITLE, message=SAVE_BOX_MESSAGE, default_text="") if not (newFilename is None or newFilename == ""): self.writeXmlToFile(element, newFilename) else: dbg("no filename provided; abort saving") else: targetFileName = join(self.configDir,filename) targetFileName = targetFileName + LAYOUT_EXTENSION ET.ElementTree(element).write(targetFileName)
def write_xml_to_file(self, element, filename=None): if filename is None: new_filename = input_box(title=SAVE_BOX_TITLE, message=SAVE_BOX_MESSAGE, default_text="") if not (new_filename is None or new_filename == ""): return self.write_xml_to_file(element, new_filename) else: dbg('no filename provided; abort saving') return target_filename = join(self.config_dir, filename) target_filename += LAYOUT_EXTENSION ElementTree.ElementTree(element).write(target_filename)
def try_add_layout_menu_item(self, name, terminal, menu): """ Checks if given file is a layout and add a context menu item if so. @param name: The file name of the possible layout. @param terminal: The terminal this context menu item belongs to. @param menu: Full gtk menu instance; not used here. """ is_layout, short_name = self.try_get_layout_short_name(name) if is_layout: layout_item = gtk.MenuItem(short_name) layout_item.connect(EVENT_ACTIVATE, self.load_callback, terminal) menu.append(layout_item) return True dbg('ignoring [%s] : %s' % (name, short_name)) return False
def check_times(self, terminal): """Check if this terminal has gone silent""" time_now = time.mktime(time.gmtime()) if not self.last_activities.has_key(terminal): dbg('Terminal %s has no last activity' % terminal) return True dbg('seconds since last activity: %f (%s)' % (time_now - self.last_activities[terminal], terminal)) if time_now - self.last_activities[terminal] >= 10.0: del(self.last_activities[terminal]) note = pynotify.Notification('Terminator', 'Silence in: %s' % terminal.get_window_title(), 'terminator') note.show() return True
def doExport(self, widget, terminal): """ Export complete terminal content into file. """ vte = terminal.get_vte() (startRow, endRow, endColumn) = self.getVteBufferRange(vte) content = vte.get_text_range(startRow, 0, endRow, endColumn, lambda widget, col, row, junk: True) filename = self.getFilename() with open(filename, "w") as outputFile: outputFile.writelines(content) outputFile.close() dbg("terminal content written to [%s]" % filename) if self.pluginConfig[SETTING_EXPORT_ENV] != "": terminal.feed('%s="%s"\n' % (self.pluginConfig[SETTING_EXPORT_ENV] ,filename)) return filename
def check_host(self, _vte, terminal): """Our host might have changed...""" self.update_watches() last_line = self.get_last_line(terminal) if last_line: patterns = self.get_patterns() for profile, pattern in patterns.iteritems(): match = re.match(pattern, last_line) if match: if profile in self.profiles and profile != terminal.get_profile(): dbg("switching to profile : "+profile) terminal.set_profile(None, profile, False) return True
def tryAddLayoutMenuItem(self, name, terminal, menu): """ Checks if given file is a layout and add a context menu item if so. @param name: The file name of the possible layout. @param terminal: The terminal this context menu item belongs to. @param menu: Full gtk menu instance; not used here. """ isLayout, shortname = self.tryGetLayoutShortName(name) if isLayout: layoutItem = gtk.MenuItem(_(shortname)) layoutItem.connect(EVENT_ACTIVATE, self.loadCallback, terminal) menu.append(layoutItem) return True else: dbg("ignoring [%s] : %s" % (name, shortname)) return False
def do_export(self, _, terminal): """ Export complete terminal content into file. """ vte = terminal.get_vte() (start_row, end_row, end_column) = self.get_vte_buffer_range(vte) content = vte.get_text_range(start_row, 0, end_row, end_column, lambda widget, col, row, junk: True) filename = self.get_filename() with open(filename, "w") as output_file: output_file.writelines(content) output_file.close() dbg('terminal content written to [%s]' % filename) if self.plugin_config[SETTING_EXPORT_ENV] != '': terminal.feed('%s="%s"\n' % (self.plugin_config[SETTING_EXPORT_ENV], filename)) return filename
def check_times(self, terminal): """Check if this terminal has gone silent""" time_now = time.mktime(time.gmtime()) if not self.last_activities.has_key(terminal): dbg('Terminal %s has no last activity' % terminal) return True dbg('seconds since last activity: %f (%s)' % (time_now - self.last_activities[terminal], terminal)) if time_now - self.last_activities[terminal] >= self.timelimit: del(self.last_activities[terminal]) note = pynotify.Notification('Terminator', 'Silence in: %s' % terminal.get_window_title(), 'terminator') note.show() beeper = pyglet.media.load('/home/dave/unix_settings/install/ubuntu/terminator_beeping/doorbell.wav') beeper.play() return True
def load_profile_mappings(self): """ get profile mapping as declared with profile_patterns config key and append profile names as patterns profiles are saved as compiled patterns in an ordered dictionary so patterns mappings are parsed prior to profiles """ if self.config and 'profile_patterns' in self.config: # we have to parse and create dict since configuration doesnt allow this for pre in self.config['profile_patterns']: kv=pre.split(":") if len(kv)==2: # config recovered as ugly string with leading and trailing quotes removed, must remove ' and " dbg("profile mapping : %s -> %s"%(kv[0].replace("'","").replace('"',''),kv[1].replace("'","").replace('"',''))) self.profile_mappings[re.compile(kv[0].replace("'","").replace('"',''))]=kv[1].replace("'","").replace('"','') # we load profile name as plain regex for v in Terminator().config.list_profiles(): self.profile_mappings[re.compile(v)]=v
def check_host(self, _vte, terminal): """Our host might have changed...""" self.update_watches() last_line = self.get_last_line(terminal) if last_line: profiles = Terminator().config.list_profiles() patterns = self.get_patterns() for pattern in patterns: match = re.match(pattern, last_line) if match: hostname = match.group(1) if hostname in profiles and hostname != terminal.get_profile(): dbg("switching to profile " + hostname + ", because line '" + last_line + "' matches pattern '" + pattern + "'") terminal.set_profile(None, hostname, False) break return True
def ssh_sessions(self): """ SSH Connections List return: list """ ssh_sessions_list = [] proc_list = self.get_proc_list for proc in proc_list: if 'ssh' == proc['name']: pid = proc['pid'] pid_cmdfile = '/proc/%s/cmdline' % pid with open(pid_cmdfile, 'r') as f: line = f.readlines()[0].split('\x00')[1] f.close() ssh_sessions_list.append(line) dbg("Sessions List: %s" % list(set(ssh_sessions_list))) return list(set(ssh_sessions_list))
def connect_signals(self): # Install DBus handlers dbg('CliSnipsMenu :: Connecting to Session Bus') self.bus = dbus.SessionBus() clisnips_service = self.bus.get_object(BUS_NAME, BUS_PATH) self.clisnips = dbus.Interface(clisnips_service, BUS_NAME) self.bus.add_signal_receiver(self.on_insert_snippet, dbus_interface=BUS_NAME, signal_name='InsertSnippet') # Connect terminal focus signal self.handlers['focus'] = gobject.add_emission_hook( Terminal, 'focus-in', self.on_terminal_focus_in ) self.handlers["keypress"] = gobject.add_emission_hook( vte.Terminal, 'key-press-event', self.on_terminal_key_pressed )
def check_host(self, _vte, terminal): """Our host might have changed...""" self.update_watches() last_line = self.get_last_line(terminal) if last_line: sel_profile=self.failback_profile for prompt_pattern in self.patterns: match = prompt_pattern.match(last_line) if match: hostname = match.group(1) dbg("match search pattern : %s (%s) ->%s"%( prompt_pattern.pattern,last_line,hostname)) # since dict is ordered, iterate regexp/mapping, then profiles for profile_pattern,profile in self.profile_mappings.items(): # we create a pattern based on profile name #profile_pattern=re.compile(profile) if hostname == profile or profile_pattern.match(hostname): dbg("matching profile '" + profile + "' found : line '" + last_line + "' matches prompt pattern '" + prompt_pattern.pattern + "' and profile pattern '"+profile_pattern.pattern+"'") sel_profile=profile # break on first profile match break # avoid re-applying profile if no change if sel_profile != self.last_profile: dbg("setting profile "+sel_profile) terminal.set_profile(None, sel_profile, False) self.last_profile=sel_profile # break on first pattern match break return True
def configure(self, widget, data = None): ui = {} dbox = Gtk.Dialog( _("Custom Commands Configuration"), None, Gtk.DialogFlags.MODAL, ( Gtk.STOCK_CANCEL, Gtk.ResponseType.REJECT, Gtk.STOCK_OK, Gtk.ResponseType.ACCEPT ) ) icon_theme = Gtk.IconTheme() try: icon = icon_theme.load_icon('terminator-custom-commands', 48, 0) except (NameError, GObject.GError): dbg('Unable to load 48px Terminator preferences icon') icon = dbox.render_icon(Gtk.STOCK_DIALOG_INFO, Gtk.IconSize.BUTTON) dbox.set_icon(icon) store = Gtk.ListStore(bool, str, str) for command in [ self.cmd_list[key] for key in sorted(self.cmd_list.keys()) ]: store.append([command['enabled'], command['name'], command['command']]) treeview = Gtk.TreeView(store) #treeview.connect("cursor-changed", self.on_cursor_changed, ui) selection = treeview.get_selection() selection.set_mode(Gtk.SelectionMode.SINGLE) selection.connect("changed", self.on_selection_changed, ui) ui['treeview'] = treeview renderer = Gtk.CellRendererToggle() renderer.connect('toggled', self.on_toggled, ui) column = Gtk.TreeViewColumn("Enabled", renderer, active=CC_COL_ENABLED) treeview.append_column(column) renderer = Gtk.CellRendererText() column = Gtk.TreeViewColumn("Name", renderer, text=CC_COL_NAME) treeview.append_column(column) renderer = Gtk.CellRendererText() column = Gtk.TreeViewColumn("Command", renderer, text=CC_COL_COMMAND) treeview.append_column(column) scroll_window = Gtk.ScrolledWindow() scroll_window.set_size_request(500, 250) scroll_window.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) scroll_window.add_with_viewport(treeview) hbox = Gtk.HBox() hbox.pack_start(scroll_window, True, True) dbox.vbox.pack_start(hbox, True, True, 0) button_box = Gtk.VBox() button = Gtk.Button(stock=Gtk.STOCK_GOTO_TOP) button_box.pack_start(button, False, True) button.connect("clicked", self.on_goto_top, ui) button.set_sensitive(False) ui['button_top'] = button button = Gtk.Button(stock=Gtk.STOCK_GO_UP) button_box.pack_start(button, False, True) button.connect("clicked", self.on_go_up, ui) button.set_sensitive(False) ui['button_up'] = button button = Gtk.Button(stock=Gtk.STOCK_GO_DOWN) button_box.pack_start(button, False, True) button.connect("clicked", self.on_go_down, ui) button.set_sensitive(False) ui['button_down'] = button button = Gtk.Button(stock=Gtk.STOCK_GOTO_LAST) button_box.pack_start(button, False, True) button.connect("clicked", self.on_goto_last, ui) button.set_sensitive(False) ui['button_last'] = button button = Gtk.Button(stock=Gtk.STOCK_NEW) button_box.pack_start(button, False, True) button.connect("clicked", self.on_new, ui) ui['button_new'] = button button = Gtk.Button(stock=Gtk.STOCK_EDIT) button_box.pack_start(button, False, True) button.set_sensitive(False) button.connect("clicked", self.on_edit, ui) ui['button_edit'] = button button = Gtk.Button(stock=Gtk.STOCK_DELETE) button_box.pack_start(button, False, True) button.connect("clicked", self.on_delete, ui) button.set_sensitive(False) ui['button_delete'] = button hbox.pack_start(button_box, False, True) dbox.show_all() res = dbox.run() if res == Gtk.ResponseType.ACCEPT: self.update_cmd_list(store) self._save_config() dbox.destroy() return
def load_xml_tree(self, layout_menu_item): filename = layout_menu_item.props.label + LAYOUT_EXTENSION filename = join(self.config_dir, filename) dbg('loading Layout config [%s]' % filename) return parse(filename)
except ImportError: print('You need to install the python bindings for ' \ 'gobject, gtk and pango to run Terminator.') sys.exit(1) import terminatorlib.optionparse from terminatorlib.terminator import Terminator from terminatorlib.factory import Factory from terminatorlib.version import APP_NAME, APP_VERSION from terminatorlib.util import dbg, err if __name__ == '__main__': dbus_service = None dbg ("%s starting up, version %s" % (APP_NAME, APP_VERSION)) OPTIONS = terminatorlib.optionparse.parse_options() # Attempt to import our dbus server. If one exists already we will just # connect to that and ask for a new window. If not, we will create one and # continue. Failure to import dbus, or the global config option "dbus" # being False will cause us to continue without the dbus server and open a # window. try: if OPTIONS.nodbus: dbg('dbus disabled by command line') raise ImportError from terminatorlib import ipc try: dbus_service = ipc.DBusService()
def reset_timer(self, _vte, terminal): """Reset the last-changed time for a terminal""" time_now = time.mktime(time.gmtime()) self.last_activities[terminal] = time_now dbg('reset activity time for %s' % terminal)