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()
Exemple #2
0
    def __init__(self, window):
        """Class initialiser"""
        if isinstance(window.get_child(), Gtk.Notebook):
            err('There is already a Notebook at the top of this window')
            raise(ValueError)

        Container.__init__(self)
        GObject.GObject.__init__(self)
        self.terminator = Terminator()
        self.window = window
        GObject.type_register(Notebook)
        self.register_signals(Notebook)
        self.connect('switch-page', self.deferred_on_tab_switch)
        self.connect('scroll-event', self.on_scroll_event)
        self.configure()

        child = window.get_child()
        window.remove(child)
        window.add(self)
        window_last_active_term = window.last_active_term
        self.newtab(widget=child)
        if window_last_active_term:
            self.set_last_active_term(window_last_active_term)
            window.last_active_term = None

        self.show_all()
Exemple #3
0
    def __init__(self):
        self.config = Config().plugin_get_config(self.__class__.__name__)
        self.watches = {}

        self.images = self.load_images()
        dbg(self.images)

        global_config = Terminator().config
        # Create ssh profiles
        self.ssh_profiles = {}
        for f in glob.glob(self.images):
            dbg(f)
            name = os.path.splitext(os.path.basename(f))[0]
            self.ssh_profiles[name] = f
            global_config.add_profile(name)
            profile = global_config.base.profiles[name]
            profile["background_darkness"] = 0.88
            profile["background_image"] = f
            profile["background_type"] = "image"

        dbg(repr(self.ssh_profiles))

        for v in global_config.list_profiles():
            dbg(repr(v))

        self.failback_profile = self.get_failback()
        self.last_profile = self.failback_profile
        self.load_patterns()
        self.update_watches()
Exemple #4
0
    def __init__(self, terminal):
        """Class initialiser"""
        GObject.GObject.__init__(self)

        self.terminator = Terminator()
        self.terminal = terminal
        self.config = self.terminal.config

        self.label = EditableLabel()
        self.label.connect('edit-done', self.on_edit_done)
        self.ebox = Gtk.EventBox()
        grouphbox = Gtk.HBox()
        self.grouplabel = Gtk.Label(ellipsize='end')
        self.groupicon = Gtk.Image()
        self.bellicon = Gtk.Image()
        self.bellicon.set_no_show_all(True)

        self.groupentry = Gtk.Entry()
        self.groupentry.set_no_show_all(True)
        self.groupentry.connect('focus-out-event', self.groupentry_cancel)
        self.groupentry.connect('activate', self.groupentry_activate)
        self.groupentry.connect('key-press-event', self.groupentry_keypress)

        groupsend_type = self.terminator.groupsend_type
        if self.terminator.groupsend == groupsend_type['all']:
            icon_name = 'all'
        elif self.terminator.groupsend == groupsend_type['group']:
            icon_name = 'group'
        elif self.terminator.groupsend == groupsend_type['off']:
            icon_name = 'off'
        self.set_from_icon_name('_active_broadcast_%s' % icon_name,
                                Gtk.IconSize.MENU)

        grouphbox.pack_start(self.groupicon, False, True, 2)
        grouphbox.pack_start(self.grouplabel, False, True, 2)
        grouphbox.pack_start(self.groupentry, False, True, 2)

        self.ebox.add(grouphbox)
        self.ebox.show_all()

        self.bellicon.set_from_icon_name('terminal-bell', Gtk.IconSize.MENU)

        viewport = Gtk.Viewport(hscroll_policy='natural')
        viewport.add(self.label)

        hbox = Gtk.HBox()
        hbox.pack_start(self.ebox, False, True, 0)
        hbox.pack_start(Gtk.VSeparator(), False, True, 0)
        hbox.pack_start(viewport, True, True, 0)
        hbox.pack_end(self.bellicon, False, False, 2)

        self.add(hbox)
        hbox.show_all()
        self.set_no_show_all(True)
        self.show()

        self.connect('button-press-event', self.on_clicked)
Exemple #5
0
class JumpUp(plugin.MenuItem):
    capabilities = ['terminal_menu']
    last_cursor_pos = 0

    def __init__(self):
        plugin.MenuItem.__init__(self)
        self.entry = Terminator().windows[0]
        self.entry.connect('key-release-event', self.onKeyRelease)
        self.entry.connect('key-press-event', self.onKeyPress)

    def callback(self, menuitems, menu, terminal):
        item = Gtk.MenuItem(_('JumpUp!'))
        item.connect("activate", self.jumpUp)
        menuitems.append(item)

    def jumpUp(self, widget):
        t = Terminator().last_focused_term
        t.scrollbar_jump(self.last_cursor_pos)

    def onKeyRelease(self, widget, event):
        if float(APP_VERSION) <= 0.98:
            if (event.state & Gtk.gdk.MOD1_MASK == Gtk.gdk.MOD1_MASK) and (
                    event.keyval == 74
                    or event.keyval == 106):  # Alt+J or Alt+j
                self.jumpUp(widget)
        else:
            if (event.state & Gdk.ModifierType.MOD1_MASK
                    == Gdk.ModifierType.MOD1_MASK) and (
                        event.keyval == 74
                        or event.keyval == 106):  # Alt+J or Alt+j
                self.jumpUp(widget)

    def onKeyPress(self, widget, event):
        if event.keyval == 65293:
            t = Terminator().last_focused_term
            col, row = t.get_vte().get_cursor_position()
            if float(APP_VERSION) <= 0.98:
                content = t.get_vte().get_text_range(
                    row - 3, 0, row, col, lambda *a: True).split("\n")
                if re.match("\w+@\w+", content[-2].split(":")
                            [0]) and not content[-2].endswith("$ "):
                    self.last_cursor_pos = row
            else:
                content = t.get_vte().get_text_range(
                    row - 3, 0, row, col, lambda *a: True)[0].split("\n")
                if re.match("\w+@\w+", content[-1].split(":")
                            [0]) and not content[-1].endswith("$ "):
                    self.last_cursor_pos = row
Exemple #6
0
 def onKeyPress(self, widget, event):
     if event.keyval == 65293:
         t = Terminator().last_focused_term
         col, row = t.get_vte().get_cursor_position()
         if float(APP_VERSION) <= 0.98:
             content = t.get_vte().get_text_range(
                 row - 3, 0, row, col, lambda *a: True).split("\n")
             if re.match("\w+@\w+", content[-2].split(":")
                         [0]) and not content[-2].endswith("$ "):
                 self.last_cursor_pos = row
         else:
             content = t.get_vte().get_text_range(
                 row - 3, 0, row, col, lambda *a: True)[0].split("\n")
             if re.match("\w+@\w+", content[-1].split(":")
                         [0]) and not content[-1].endswith("$ "):
                 self.last_cursor_pos = row
 def multiKill(self, widget):
     for t in Terminator().terminals:
         try:
             t.vte.feed_child("\x03", len("\x03"))
         except Exception, ex:
             err('\033[1;31mMultikill failed: %s\033[0m' % ex)
             pass
 def multiSource(self, widget):
     for t in Terminator().terminals:
         try:
             command = "source ~/.bashrc\n"
             t.vte.feed_child(command, len(command))
         except Exception, ex:
             err('\033[1;31mMultisource failed: %s\033[0m' % ex)
             pass
Exemple #9
0
 def unload(self):
     """Handle being removed"""
     if not self.match:
         err('unload called without self.handler_name being set')
         return
     terminator = Terminator()
     for terminal in terminator.terminals:
         terminal.match_remove(self.handler_name)
Exemple #10
0
 def prepare_attributes(self):
     """Ensure we are populated"""
     if not self.bus_name:
         dbg('Checking for bus name availability: %s' % BUS_NAME)
         bus = dbus.SessionBus()
         proxy = bus.get_object('org.freedesktop.DBus',
                                '/org/freedesktop/DBus')
         flags = 1 | 4  # allow replacement | do not queue
         if not proxy.RequestName(BUS_NAME, dbus.UInt32(flags)) in (1, 4):
             dbg('bus name unavailable: %s' % BUS_NAME)
             raise dbus.exceptions.DBusException(
                 "Couldn't get DBus name %s: Name exists" % BUS_NAME)
         self.bus_name = dbus.service.BusName(BUS_NAME,
                                              bus=dbus.SessionBus())
     if not self.bus_path:
         self.bus_path = BUS_PATH
     if not self.terminator:
         self.terminator = Terminator()
Exemple #11
0
 def __init__(self):
     """Class initialiser"""
     self.terminator = Terminator()
     self.maker = Factory()
     Container.__init__(self)
     self.signals.append({'name'       : 'resize-term',
                          'flags'      : GObject.SignalFlags.RUN_LAST,
                          'return_type': None,
                          'param_types': (GObject.TYPE_STRING,)})
Exemple #12
0
    def __init__(self):
        """
        Class initialiser
        """
        self.terminator = Terminator()
        self.terminator.register_window(self)

        Container.__init__(self)
        GObject.GObject.__init__(self)
        GObject.type_register(Window)
        self.register_signals(Window)

        self.get_style_context().add_class("terminator-terminal-window")

        #        self.set_property('allow-shrink', True)  # FIXME FOR GTK3, or do we need this actually?
        icon_to_apply = ''

        self.register_callbacks()
        self.apply_config()

        self.title = WindowTitle(self)
        self.title.update()

        self.preventHide = False

        options = self.config.options_get()
        if options:
            if options.forcedtitle:
                self.title.force_title(options.forcedtitle)

            if options.role:
                self.set_role(options.role)

            if options.forcedicon is not None:
                icon_to_apply = options.forcedicon

            if options.geometry:
                if not self.parse_geometry(options.geometry):
                    err('Window::__init__: Unable to parse geometry: %s' %
                        options.geometry)

        self.apply_icon(icon_to_apply)
        self.pending_set_rough_geometry_hint = False
class MultiKill(plugin.MenuItem):
    capabilities = ['terminal_menu']

    def __init__(self):
        plugin.MenuItem.__init__(self)
        self.entry = Terminator().windows[0]
        self.entry.connect('key-release-event', self.onKeyPress)

    def callback(self, menuitems, menu, terminal):
        item = Gtk.MenuItem(_('MultiKill!'))
        item.connect("activate", self.multiKill)
        menuitems.append(item)

    def multiKill(self, widget):
        for t in Terminator().terminals:
            try:
                t.vte.feed_child("\x03", len("\x03"))
            except Exception, ex:
                err('\033[1;31mMultikill failed: %s\033[0m' % ex)
                pass
class MultiSource(plugin.MenuItem):
    capabilities = ['terminal_menu']

    def __init__(self):
        plugin.MenuItem.__init__(self)
        self.entry = Terminator().windows[0]
        self.entry.connect('key-release-event', self.onKeyPress)

    def callback(self, menuitems, menu, terminal):
        item = Gtk.MenuItem(_('MultiSource!'))
        item.connect("activate", self.multiSource)
        menuitems.append(item)

    def multiSource(self, widget):
        for t in Terminator().terminals:
            try:
                command = "source ~/.bashrc\n"
                t.vte.feed_child(command, len(command))
            except Exception, ex:
                err('\033[1;31mMultisource failed: %s\033[0m' % ex)
                pass
 def get_terminal_container(self, terminal, container=None):
     terminator = Terminator()
     if not container:
         for window in terminator.windows:
             owner = self.get_terminal_container(terminal, window)
             if owner: return owner
     else:
         for child in container.get_children():
             if isinstance(child, Terminal) and child == terminal:
                 return container
             if isinstance(child, Container):
                 owner = self.get_terminal_container(terminal, child)
                 if owner: return owner
Exemple #16
0
 def update_watched(self):
     """Updates the list of watched terminals"""
     new_watched = set()
     for term in Terminator().terminals:
         new_watched.add(term)
         if not term in self.watched:
             vte = term.get_vte()
             term.connect('focus-out', self.update_watched_delayed, None)
             vte.connect('focus-out-event', self.update_watched_delayed,
                         None)
             notify = vte.connect('notification-received',
                                  self.notification_received, term)
         else:
             notify = None
     self.watched = new_watched
Exemple #17
0
    def __init__(self, title, notebook):
        """Class initialiser"""
        GObject.GObject.__init__(self)

        self.notebook = notebook
        self.terminator = Terminator()
        self.config = Config()

        self.label = EditableLabel(title)
        self.update_angle()

        self.pack_start(self.label, True, True, 0)

        self.update_button()
        self.show_all()
Exemple #18
0
    def wrapcloseterm(self, widget):
        """A child terminal has closed, so this container must die"""
        dbg('Paned::wrapcloseterm: Called on %s' % widget)

        if self.closeterm(widget):
            # At this point we only have one child, which is the surviving term
            sibling = self.children[0]
            first_term_sibling = sibling
            cur_tabnum = None

            focus_sibling = True
            if self.get_toplevel().is_child_notebook():
                notebook = self.get_toplevel().get_children()[0]
                cur_tabnum = notebook.get_current_page()
                tabnum = notebook.page_num_descendant(self)
                nth_page = notebook.get_nth_page(tabnum)
                exiting_term_was_last_active = (
                    notebook.last_active_term[nth_page] == widget.uuid)
                if exiting_term_was_last_active:
                    first_term_sibling = enumerate_descendants(self)[1][0]
                    notebook.set_last_active_term(first_term_sibling.uuid)
                    notebook.clean_last_active_term()
                    self.get_toplevel().last_active_term = None
                if cur_tabnum != tabnum:
                    focus_sibling = False
            elif self.get_toplevel().last_active_term != widget.uuid:
                focus_sibling = False

            self.remove(sibling)

            metadata = None
            parent = self.get_parent()
            metadata = parent.get_child_metadata(self)
            dbg('metadata obtained for %s: %s' % (self, metadata))
            parent.remove(self)
            self.cnxids.remove_all()
            parent.add(sibling, metadata)
            if cur_tabnum:
                notebook.set_current_page(cur_tabnum)
            if focus_sibling:
                first_term_sibling.grab_focus()
            elif not sibling.get_toplevel().is_child_notebook():
                Terminator().find_terminal_by_uuid(
                    sibling.get_toplevel().last_active_term.urn).grab_focus()
        else:
            dbg("Paned::wrapcloseterm: self.closeterm failed")
    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
Exemple #20
0
 def __init__(self):
     plugin.MenuItem.__init__(self)
     self.entry = Terminator().windows[0]
     self.entry.connect('key-release-event', self.onKeyRelease)
     self.entry.connect('key-press-event', self.onKeyPress)
class LayoutLauncher:
    """Class implementing the various parts of the preferences editor"""
    terminator = None
    config = None
    registry = None
    plugins = None
    keybindings = None
    window = None
    builder = None
    layouttreeview = None
    layouttreestore = None

    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 on_destroy_event(self, widget, data=None):
        """Handle window destruction"""
        dbg('destroying self')
        self.terminator.deregister_launcher_window(self)
        self.window.destroy()
        del self.window

    def update_layouts(self):
        """Update the contents of the layout"""
        self.layouttreestore.clear()
        layouts = self.config.list_layouts()
        for layout in sorted(layouts,
                             key=lambda x, y: cmp(x.lower(), y.lower())):
            if layout != "default":
                self.layouttreestore.append([layout])
            else:
                self.layouttreestore.prepend([layout])

    def on_launchbutton_clicked(self, widget):
        """Handle button click"""
        self.launch_layout()

    def on_row_activated(self, widget, path, view_column):
        """Handle item double-click and return"""
        self.launch_layout()

    def launch_layout(self):
        """Launch the selected layout as new instance"""
        dbg('We have takeoff!')
        selection = self.layouttreeview.get_selection()
        (listmodel, rowiter) = selection.get_selected()
        if not rowiter:
            # Something is wrong, just jump to the first item in the list
            selection.select_iter(self.layouttreestore.get_iter_first())
            (listmodel, rowiter) = selection.get_selected()
        layout = listmodel.get_value(rowiter, 0)
        dbg(f'Clicked for {layout}')
        spawn_new_terminator(self.terminator.origcwd, ['-u', '-l', layout])
 def __init__(self, terminal):
     """Class initialiser"""
     self.terminal = terminal
     self.terminator = Terminator()
     self.config = Config()
Exemple #23
0
        if OPTIONS.nodbus:
            dbg('dbus disabled by command line')
            raise ImportError
        from terminatorlib import ipc
        try:
            dbus_service = ipc.DBusService()
        except ipc.DBusException:
            dbg('Unable to become master process, requesting a new window')
            ipc.new_window(OPTIONS.layout)
            sys.exit()
    except ImportError:
        dbg('dbus not imported')
        pass

    MAKER = Factory()
    TERMINATOR = Terminator()
    TERMINATOR.set_origcwd(ORIGCWD)
    TERMINATOR.set_dbus_data(dbus_service)
    TERMINATOR.reconfigure()
    try:
        dbg('Creating a terminal with layout: %s' % OPTIONS.layout)
        TERMINATOR.create_layout(OPTIONS.layout)
    except (KeyError,ValueError), ex:
        err('layout creation failed, creating a window ("%s")' % ex)
        TERMINATOR.new_window()
    TERMINATOR.layout_done()

    if OPTIONS.debug > 2:
        import terminatorlib.debugserver as debugserver
        # pylint: disable-msg=W0611
        import threading
Exemple #24
0
 def __init__(self):
     plugin.Plugin.__init__(self)
     self.terminator = Terminator()
     gobject.timeout_add_seconds(5, self.update_clock)
Exemple #25
0
class Window(Container, Gtk.Window):
    # pylint: disable-msg=R0904
    """
    Class implementing a top-level Terminator window
    """

    terminator = None
    title = None
    isfullscreen = None
    ismaximised = None
    hidebound = None
    hidefunc = None
    losefocus_time = 0
    position = None
    ignore_startup_show = None
    set_pos_by_ratio = None
    last_active_term = None
    preventHide = None

    zoom_data = None

    term_zoomed = False

    __gproperties__ = {
        'term_zoomed':
        (GObject.TYPE_BOOLEAN, 'terminal zoomed',
         'whether the terminal is zoomed', False, GObject.PARAM_READWRITE)
    }

    def __init__(self):
        """
        Class initialiser
        """
        self.terminator = Terminator()
        self.terminator.register_window(self)

        Container.__init__(self)
        GObject.GObject.__init__(self)
        GObject.type_register(Window)
        self.register_signals(Window)

        self.get_style_context().add_class("terminator-terminal-window")

        #        self.set_property('allow-shrink', True)  # FIXME FOR GTK3, or do we need this actually?
        icon_to_apply = ''

        self.register_callbacks()
        self.apply_config()

        self.title = WindowTitle(self)
        self.title.update()

        self.preventHide = False

        options = self.config.options_get()
        if options:
            if options.forcedtitle:
                self.title.force_title(options.forcedtitle)

            if options.role:
                self.set_role(options.role)

            if options.forcedicon is not None:
                icon_to_apply = options.forcedicon

            if options.geometry:
                if not self.parse_geometry(options.geometry):
                    err('Window::__init__: Unable to parse geometry: %s' %
                        options.geometry)

        self.apply_icon(icon_to_apply)
        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']:
            return self.term_zoomed
        else:
            raise AttributeError('unknown property %s' % prop.name)

    def do_set_property(self, prop, value):
        """Handle gobject setting a property"""
        if prop.name in ['term_zoomed', 'term-zoomed']:
            self.term_zoomed = value
        else:
            raise AttributeError('unknown property %s' % prop.name)

    def register_callbacks(self):
        """
        Connect the GTK+ signals we care about
        """
        self.connect('key-press-event', self.on_key_press)
        self.connect('button-press-event', self.on_button_press)
        self.connect('delete_event', self.on_delete_event)
        self.connect('destroy', self.on_destroy_event)
        self.connect('window-state-event', self.on_window_state_changed)
        self.connect('focus-out-event', self.on_focus_out)
        self.connect('focus-in-event', self.on_focus_in)

        # Attempt to grab a global hotkey for hiding the window.
        # If we fail, we'll never hide the window, iconifying instead.
        if self.config['keybindings']['hide_window'] != None:
            if display_manager() == 'X11':
                try:
                    self.hidebound = Keybinder.bind(
                        self.config['keybindings']['hide_window'].replace(
                            '<Shift>', ''), self.on_hide_window)
                except (KeyError, NameError):
                    pass

                if not self.hidebound:
                    err('Unable to bind hide_window key, another instance/window has it.'
                        )
                    self.hidefunc = self.iconify
                else:
                    self.hidefunc = self.hide

    def apply_config(self):
        """Apply various configuration options"""
        options = self.config.options_get()
        maximise = self.config['window_state'] == 'maximise'
        fullscreen = self.config['window_state'] == 'fullscreen'
        hidden = self.config['window_state'] == 'hidden'
        borderless = self.config['borderless']
        skiptaskbar = self.config['hide_from_taskbar']
        alwaysontop = self.config['always_on_top']
        sticky = self.config['sticky']

        if options:
            if options.maximise:
                maximise = True
            if options.fullscreen:
                fullscreen = True
            if options.hidden:
                hidden = True
            if options.borderless:
                borderless = True

        self.set_fullscreen(fullscreen)
        self.set_maximised(maximise)
        self.set_borderless(borderless)
        self.set_always_on_top(alwaysontop)
        self.set_real_transparency()
        self.set_sticky(sticky)
        if self.hidebound:
            self.set_hidden(hidden)
            self.set_skip_taskbar_hint(skiptaskbar)
        else:
            self.set_iconified(hidden)

    def apply_icon(self, requested_icon):
        """Set the window icon"""
        icon_theme = Gtk.IconTheme.get_default()
        icon_name_list = [APP_NAME]  # disable self.wmclass_name, n/a in GTK3

        if requested_icon:
            try:
                self.set_icon_from_file(requested_icon)
                return
            except (NameError, GObject.GError):
                dbg('Unable to load %s icon as file' % (repr(requested_icon)))

            icon_name_list.insert(0, requested_icon)

        for icon_name in icon_name_list:
            # Test if the icon is available first
            if icon_theme.lookup_icon(icon_name, 48, 0):
                self.set_icon_name(icon_name)
                return  # Success! We're done.
            else:
                dbg('Unable to load %s icon' % (icon_name))

        icon = self.render_icon(Gtk.STOCK_DIALOG_INFO, Gtk.IconSize.BUTTON)
        self.set_icon(icon)

    def on_key_press(self, window, event):
        """Handle a keyboard event"""
        maker = Factory()

        self.set_urgency_hint(False)

        mapping = self.terminator.keybindings.lookup(event)

        if mapping:
            dbg('Window::on_key_press: looked up %r' % mapping)
            if mapping == 'full_screen':
                self.set_fullscreen(not self.isfullscreen)
            elif mapping == 'close_window':
                if not self.on_delete_event(
                        window, Gdk.Event.new(Gdk.EventType.DELETE)):
                    self.on_destroy_event(window,
                                          Gdk.Event.new(Gdk.EventType.DESTROY))
            else:
                return False
            return True

    def on_button_press(self, window, event):
        """Handle a mouse button event. Mainly this is just a clean way to
        cancel any urgency hints that are set."""
        self.set_urgency_hint(False)
        return False

    def on_focus_out(self, window, event):
        """Focus has left the window"""
        for terminal in self.get_visible_terminals():
            terminal.on_window_focus_out()

        self.losefocus_time = time.time()

        if self.preventHide:
            self.preventHide = False
        else:
            if self.config['hide_on_lose_focus'] and self.get_property(
                    'visible'):
                self.position = self.get_position()
                self.hidefunc()

    def on_focus_in(self, window, event):
        """Focus has entered the window"""
        self.set_urgency_hint(False)
        if not self.terminator.doing_layout:
            self.terminator.last_active_window = self.uuid
        # FIXME: Cause the terminal titlebars to update here

    def is_child_notebook(self):
        """Returns True if this Window's child is a Notebook"""
        maker = Factory()
        return maker.isinstance(self.get_child(), 'Notebook')

    def tab_new(self, widget=None, debugtab=False, _param1=None, _param2=None):
        """Make a new tab"""
        cwd = None
        profile = None

        if self.get_property('term_zoomed') == True:
            err("You can't create a tab while a terminal is maximised/zoomed")
            return

        if widget:
            cwd = widget.get_cwd()
            profile = widget.get_profile()

        maker = Factory()
        if not self.is_child_notebook():
            dbg('Making a new Notebook')
            notebook = maker.make('Notebook', window=self)
        self.show()
        self.present()
        return self.get_child().newtab(debugtab, cwd=cwd, profile=profile)

    def on_delete_event(self, window, event, data=None):
        """Handle a window close request"""
        maker = Factory()
        if maker.isinstance(self.get_child(), 'Terminal'):
            if self.get_property('term_zoomed') == True:
                return self.confirm_close(window, _('window'))
            else:
                dbg('Window::on_delete_event: Only one child, closing is fine')
                return False
        elif maker.isinstance(self.get_child(), 'Container'):
            return self.confirm_close(window, _('window'))
        else:
            dbg('unknown child: %s' % self.get_child())

    def confirm_close(self, window, type):
        """Display a confirmation dialog when the user is closing multiple
        terminals in one window"""

        return not (self.construct_confirm_close(window, type)
                    == Gtk.ResponseType.ACCEPT)

    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_hide_window(self, data=None):
        """Handle a request to hide/show the window"""

        if not self.get_property('visible'):
            # Don't show if window has just been hidden because of
            # lost focus
            if (time.time() - self.losefocus_time < 0.1) and \
                    self.config['hide_on_lose_focus']:
                return
            if self.position:
                self.move(self.position[0], self.position[1])
            self.show()
            self.grab_focus()
            try:
                t = GdkX11.x11_get_server_time(self.get_window())
            except (TypeError, AttributeError):
                t = 0
            self.get_window().focus(t)
        else:
            self.position = self.get_position()
            self.hidefunc()

    # pylint: disable-msg=W0613
    def on_window_state_changed(self, window, event):
        """Handle the state of the window changing"""
        self.isfullscreen = bool(event.new_window_state
                                 & Gdk.WindowState.FULLSCREEN)
        self.ismaximised = bool(event.new_window_state
                                & Gdk.WindowState.MAXIMIZED)
        dbg('Window::on_window_state_changed: fullscreen=%s, maximised=%s' %
            (self.isfullscreen, self.ismaximised))

        return False

    def set_maximised(self, value):
        """Set the maximised state of the window from the supplied value"""
        if value == True:
            self.maximize()
        else:
            self.unmaximize()

    def set_fullscreen(self, value):
        """Set the fullscreen state of the window from the supplied value"""
        if value == True:
            self.fullscreen()
        else:
            self.unfullscreen()

    def set_borderless(self, value):
        """Set the state of the window border from the supplied value"""
        self.set_decorated(not value)

    def set_hidden(self, value):
        """Set the visibility of the window from the supplied value"""
        if value == True:
            self.ignore_startup_show = True
        else:
            self.ignore_startup_show = False

    def set_iconified(self, value):
        """Set the minimised state of the window from the supplied value"""
        if value == True:
            self.iconify()

    def set_always_on_top(self, value):
        """Set the always on top window hint from the supplied value"""
        self.set_keep_above(value)

    def set_sticky(self, value):
        """Set the sticky hint from the supplied value"""
        if value == True:
            self.stick()

    def set_real_transparency(self, value=True):
        """Enable RGBA if supported on the current screen"""
        if self.is_composited() == False:
            value = False

        screen = self.get_screen()
        if value:
            dbg('setting rgba visual')
            visual = screen.get_rgba_visual()
            if visual:
                self.set_visual(visual)

    def show(self, startup=False):
        """Undo the startup show request if started in hidden mode"""
        # Present is necessary to grab focus when window is hidden from taskbar.
        # It is important to call present() before show(), otherwise the window
        # won't be brought to front if an another application has the focus.
        # Last note: present() will implicitly call Gtk.Window.show()
        self.present()

        # Window must be shown, then hidden for the hotkeys to be registered
        if (self.ignore_startup_show and startup == True):
            self.position = self.get_position()
            self.hide()

    def add(self, widget, metadata=None):
        """Add a widget to the window by way of Gtk.Window.add()"""
        maker = Factory()
        Gtk.Window.add(self, widget)
        if maker.isinstance(widget, 'Terminal'):
            signals = {
                'close-term': self.closeterm,
                'title-change': self.title.set_title,
                'split-horiz': self.split_horiz,
                'split-vert': self.split_vert,
                'unzoom': self.unzoom,
                'tab-change': self.tab_change,
                'group-all': self.group_all,
                'group-all-toggle': self.group_all_toggle,
                'ungroup-all': self.ungroup_all,
                'group-tab': self.group_tab,
                'group-tab-toggle': self.group_tab_toggle,
                'ungroup-tab': self.ungroup_tab,
                'move-tab': self.move_tab,
                'tab-new': [self.tab_new, widget],
                'navigate': self.navigate_terminal
            }

            for signal in signals:
                args = []
                handler = signals[signal]
                if isinstance(handler, list):
                    args = handler[1:]
                    handler = handler[0]
                self.connect_child(widget, signal, handler, *args)

            widget.grab_focus()

    def remove(self, widget):
        """Remove our child widget by way of Gtk.Window.remove()"""
        Gtk.Window.remove(self, widget)
        self.disconnect_child(widget)
        return True

    def get_children(self):
        """Return a single list of our child"""
        children = []
        children.append(self.get_child())
        return children

    def hoover(self):
        """Ensure we still have a reason to exist"""
        if not self.get_child():
            self.emit('destroy')

    def closeterm(self, widget):
        """Handle a terminal closing"""
        Container.closeterm(self, widget)
        self.hoover()

    def split_axis(self,
                   widget,
                   vertical=True,
                   cwd=None,
                   sibling=None,
                   widgetfirst=True):
        """Split the window"""
        if self.get_property('term_zoomed') == True:
            err("You can't split while a terminal is maximised/zoomed")
            return

        order = None
        maker = Factory()
        self.remove(widget)

        if vertical:
            container = maker.make('VPaned')
        else:
            container = maker.make('HPaned')

        self.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.add(container)
        container.show_all()

        order = [widget, sibling]
        if widgetfirst is False:
            order.reverse()

        for term in order:
            container.add(term)
        container.show_all()

        while Gtk.events_pending():
            Gtk.main_iteration_do(False)
        sibling.grab_focus()
        self.set_pos_by_ratio = False

    def zoom(self, widget, font_scale=True):
        """Zoom a terminal widget"""
        children = self.get_children()

        if widget in children:
            # This widget is a direct child of ours and we're a Window
            # so zooming is a no-op
            return

        self.zoom_data = widget.get_zoom_data()
        self.zoom_data['widget'] = widget
        self.zoom_data['old_child'] = children[0]
        self.zoom_data['font_scale'] = font_scale

        self.remove(self.zoom_data['old_child'])
        self.zoom_data['old_parent'].remove(widget)
        self.add(widget)
        self.set_property('term_zoomed', True)

        if font_scale:
            widget.cnxids.new(widget, 'size-allocate', widget.zoom_scale,
                              self.zoom_data)

        widget.grab_focus()

    def unzoom(self, widget):
        """Restore normal terminal layout"""
        if not self.get_property('term_zoomed'):
            # We're not zoomed anyway
            dbg('Window::unzoom: not zoomed, no-op')
            return

        widget = self.zoom_data['widget']
        if self.zoom_data['font_scale']:
            widget.vte.set_font(self.zoom_data['old_font'])

        self.remove(widget)
        self.add(self.zoom_data['old_child'])
        self.zoom_data['old_parent'].add(widget)
        widget.grab_focus()
        self.zoom_data = None
        self.set_property('term_zoomed', False)

    def rotate(self, widget, clockwise):
        """Rotate children in this window"""
        self.set_pos_by_ratio = True
        maker = Factory()
        child = self.get_child()

        # If our child is a Notebook, reset to work from its visible child
        if maker.isinstance(child, 'Notebook'):
            pagenum = child.get_current_page()
            child = child.get_nth_page(pagenum)

        if maker.isinstance(child, 'Paned'):
            parent = child.get_parent()
            # Need to get the allocation before we remove the child,
            # otherwise _sometimes_ we get incorrect values.
            alloc = child.get_allocation()
            parent.remove(child)
            child.rotate_recursive(parent, alloc.width, alloc.height,
                                   clockwise)

            self.show_all()
            while Gtk.events_pending():
                Gtk.main_iteration_do(False)
            widget.grab_focus()

        self.set_pos_by_ratio = False

    def get_visible_terminals(self):
        """Walk down the widget tree to find all of the visible terminals.
        Mostly using Container::get_visible_terminals()"""
        terminals = {}
        if not hasattr(self, 'cached_maker'):
            self.cached_maker = Factory()
        maker = self.cached_maker
        child = self.get_child()

        if not child:
            return []

        # If our child is a Notebook, reset to work from its visible child
        if maker.isinstance(child, 'Notebook'):
            pagenum = child.get_current_page()
            child = child.get_nth_page(pagenum)

        if maker.isinstance(child, 'Container'):
            terminals.update(child.get_visible_terminals())
        elif maker.isinstance(child, 'Terminal'):
            terminals[child] = child.get_allocation()
        else:
            err('Unknown child type %s' % type(child))

        return terminals

    def get_focussed_terminal(self):
        """Find which terminal we want to have focus"""
        terminals = self.get_visible_terminals()
        for terminal in terminals:
            if terminal.vte.is_focus():
                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"""
        if self.ismaximised == True:
            return
        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

        terminals = self.get_visible_terminals()
        column_sum = 0
        row_sum = 0

        for terminal in terminals:
            rect = terminal.get_allocation()
            if rect.x == 0:
                cols, rows = terminal.get_size()
                row_sum = row_sum + rows
            if rect.y == 0:
                cols, rows = terminal.get_size()
                column_sum = column_sum + cols

        if column_sum == 0 or row_sum == 0:
            dbg('column_sum=%s,row_sum=%s. No terminals found in >=1 axis' %
                (column_sum, row_sum))
            return

        # FIXME: I don't think we should just use whatever font size info is on
        # the last terminal we inspected. Looking up the default profile font
        # size and calculating its character sizes would be rather expensive
        # though.
        font_width, font_height = terminal.get_font_size()
        total_font_width = font_width * column_sum
        total_font_height = font_height * row_sum

        win_width, win_height = self.get_size()
        extra_width = win_width - total_font_width
        extra_height = win_height - total_font_height

        dbg('setting geometry hints: (ewidth:%s)(eheight:%s),\
(fwidth:%s)(fheight:%s)' %
            (extra_width, extra_height, font_width, font_height))
        geometry = Gdk.Geometry()
        geometry.base_width = extra_width
        geometry.base_height = extra_height
        geometry.width_inc = font_width
        geometry.height_inc = font_height
        self.set_geometry_hints(
            self, geometry,
            Gdk.WindowHints.BASE_SIZE | Gdk.WindowHints.RESIZE_INC)

    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 set_groups(self, new_group, term_list):
        """Set terminals in term_list to new_group"""
        for terminal in term_list:
            terminal.set_group(None, new_group)
        self.terminator.focus_changed(self.terminator.last_focused_term)

    def group_all(self, widget):
        """Group all terminals"""
        # FIXME: Why isn't this being done by Terminator() ?
        group = _('All')
        self.terminator.create_group(group)
        self.set_groups(group, self.terminator.terminals)

    def group_all_toggle(self, widget):
        """Toggle grouping to all"""
        if widget.group == 'All':
            self.ungroup_all(widget)
        else:
            self.group_all(widget)

    def ungroup_all(self, widget):
        """Ungroup all terminals"""
        self.set_groups(None, self.terminator.terminals)

    def group_tab(self, widget):
        """Group all terminals in the current tab"""
        maker = Factory()
        notebook = self.get_child()

        if not maker.isinstance(notebook, 'Notebook'):
            dbg('not in a notebook, refusing to group tab')
            return

        pagenum = notebook.get_current_page()
        while True:
            group = _('Tab %d') % pagenum
            if group not in self.terminator.groups:
                break
            pagenum += 1
        self.set_groups(group, self.get_visible_terminals())

    def group_tab_toggle(self, widget):
        """Blah"""
        if widget.group and widget.group[:4] == 'Tab ':
            self.ungroup_tab(widget)
        else:
            self.group_tab(widget)

    def ungroup_tab(self, widget):
        """Ungroup all terminals in the current tab"""
        maker = Factory()
        notebook = self.get_child()

        if not maker.isinstance(notebook, 'Notebook'):
            dbg('note in a notebook, refusing to ungroup tab')
            return

        self.set_groups(None, self.get_visible_terminals())

    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 navigate_terminal(self, terminal, direction):
        """Navigate around terminals"""
        _containers, terminals = enumerate_descendants(self)
        visibles = self.get_visible_terminals()
        current = terminals.index(terminal)
        length = len(terminals)
        next = None

        if length <= 1 or len(visibles) <= 1:
            return

        if direction in ['next', 'prev']:
            tmpterms = copy.copy(terminals)
            tmpterms = tmpterms[current + 1:]
            tmpterms.extend(terminals[0:current])

            if direction == 'next':
                tmpterms.reverse()

            next = 0
            while len(tmpterms) > 0:
                tmpitem = tmpterms.pop()
                if tmpitem in visibles:
                    next = terminals.index(tmpitem)
                    break
        elif direction in ['left', 'right', 'up', 'down']:
            layout = self.get_visible_terminals()
            allocation = terminal.get_allocation()
            possibles = []

            # Get the co-ordinate of the appropriate edge for this direction
            edge, p1, p2 = get_edge(allocation, direction)
            # Find all visible terminals which are, in their entirity, in the
            # direction we want to move, and are at least partially spanning
            # p1 to p2
            for term in layout:
                rect = layout[term]
                if get_nav_possible(edge, rect, direction, p1, p2):
                    possibles.append(term)

            if len(possibles) == 0:
                return

            # Find out how far away each of the possible terminals is, then
            # find the smallest distance. The winning terminals are all of
            # those who are that distance away.
            offsets = {}
            for term in possibles:
                rect = layout[term]
                offsets[term] = get_nav_offset(edge, rect, direction)
            keys = offsets.values()
            keys.sort()
            winners = [k for k, v in offsets.iteritems() if v == keys[0]]
            next = terminals.index(winners[0])

            if len(winners) > 1:
                # Break an n-way tie using the cursor position
                term_alloc = terminal.get_allocation()
                cursor_x = term_alloc.x + term_alloc.width / 2
                cursor_y = term_alloc.y + term_alloc.height / 2

                for term in winners:
                    rect = layout[term]
                    if get_nav_tiebreak(direction, cursor_x, cursor_y, rect):
                        next = terminals.index(term)
                        break
        else:
            err('Unknown navigation direction: %s' % direction)

        if next is not None:
            terminals[next].grab_focus()

    def create_layout(self, layout):
        """Apply any config items from our layout"""
        if 'children' not in layout:
            err('layout describes no children: %s' % layout)
            return
        children = layout['children']
        if len(children) != 1:
            # We're a Window, we can only have one child
            err('incorrect number of children for Window: %s' % layout)
            return

        child = children[children[0]]
        terminal = self.get_children()[0]
        dbg('Making a child of type: %s' % child['type'])
        if child['type'] == 'VPaned':
            self.split_axis(terminal, True)
        elif child['type'] == 'HPaned':
            self.split_axis(terminal, False)
        elif child['type'] == 'Notebook':
            self.tab_new()
            i = 2
            while i < len(child['children']):
                self.tab_new()
                i = i + 1
        elif child['type'] == 'Terminal':
            pass
        else:
            err('unknown child type: %s' % child['type'])
            return

        self.get_children()[0].create_layout(child)

        if 'last_active_term' in layout and layout['last_active_term'] not in [
                '', None
        ]:
            self.last_active_term = make_uuid(layout['last_active_term'])

        if 'last_active_window' in layout and layout[
                'last_active_window'] == 'True':
            self.terminator.last_active_window = self.uuid
Exemple #26
0
class Titlebar(Gtk.EventBox):
    # pylint: disable-msg=R0904
    # pylint: disable-msg=W0613
    """Class implementing the Titlebar widget"""

    terminator = None
    terminal = None
    config = None
    oldtitle = None
    termtext = None
    sizetext = None
    label = None
    ebox = None
    groupicon = None
    grouplabel = None
    groupentry = None
    bellicon = None

    __gsignals__ = {
        'clicked': (GObject.SignalFlags.RUN_LAST, None, ()),
        'edit-done': (GObject.SignalFlags.RUN_LAST, None, ()),
        'create-group':
        (GObject.SignalFlags.RUN_LAST, None, (GObject.TYPE_STRING, )),
    }

    def __init__(self, terminal):
        """Class initialiser"""
        GObject.GObject.__init__(self)

        self.terminator = Terminator()
        self.terminal = terminal
        self.config = self.terminal.config

        self.label = EditableLabel()
        self.label.connect('edit-done', self.on_edit_done)
        self.ebox = Gtk.EventBox()
        grouphbox = Gtk.HBox()
        self.grouplabel = Gtk.Label(ellipsize='end')
        self.groupicon = Gtk.Image()
        self.bellicon = Gtk.Image()
        self.bellicon.set_no_show_all(True)

        self.groupentry = Gtk.Entry()
        self.groupentry.set_no_show_all(True)
        self.groupentry.connect('focus-out-event', self.groupentry_cancel)
        self.groupentry.connect('activate', self.groupentry_activate)
        self.groupentry.connect('key-press-event', self.groupentry_keypress)

        groupsend_type = self.terminator.groupsend_type
        if self.terminator.groupsend == groupsend_type['all']:
            icon_name = 'all'
        elif self.terminator.groupsend == groupsend_type['group']:
            icon_name = 'group'
        elif self.terminator.groupsend == groupsend_type['off']:
            icon_name = 'off'
        self.set_from_icon_name('_active_broadcast_%s' % icon_name,
                                Gtk.IconSize.MENU)

        grouphbox.pack_start(self.groupicon, False, True, 2)
        grouphbox.pack_start(self.grouplabel, False, True, 2)
        grouphbox.pack_start(self.groupentry, False, True, 2)

        self.ebox.add(grouphbox)
        self.ebox.show_all()

        self.bellicon.set_from_icon_name('terminal-bell', Gtk.IconSize.MENU)

        viewport = Gtk.Viewport(hscroll_policy='natural')
        viewport.add(self.label)

        hbox = Gtk.HBox()
        hbox.pack_start(self.ebox, False, True, 0)
        hbox.pack_start(Gtk.VSeparator(), False, True, 0)
        hbox.pack_start(viewport, True, True, 0)
        hbox.pack_end(self.bellicon, False, False, 2)

        self.add(hbox)
        hbox.show_all()
        self.set_no_show_all(True)
        self.show()

        self.connect('button-press-event', self.on_clicked)

    def connect_icon(self, func):
        """Connect the supplied function to clicking on the group icon"""
        self.ebox.connect('button-press-event', func)

    def update(self, other=None):
        """Update our contents"""
        default_bg = False
        if self.config['title_hide_sizetext']:
            self.label.set_text("%s" % self.termtext)
        else:
            self.label.set_text("%s %s" % (self.termtext, self.sizetext))

        if (not self.config['title_use_system_font']
            ) and self.config['title_font']:
            title_font = Pango.FontDescription(self.config['title_font'])
        else:
            title_font = Pango.FontDescription(
                self.config.get_system_prop_font())
        self.label.modify_font(title_font)
        self.grouplabel.modify_font(title_font)

        if other:
            term = self.terminal
            terminator = self.terminator
            if other == 'window-focus-out':
                title_fg = self.config['title_inactive_fg_color']
                title_bg = self.config['title_inactive_bg_color']
                icon = '_receive_off'
                default_bg = True
                group_fg = self.config['title_inactive_fg_color']
                group_bg = self.config['title_inactive_bg_color']
            elif term != other and term.group and term.group == other.group:
                if terminator.groupsend == terminator.groupsend_type['off']:
                    title_fg = self.config['title_inactive_fg_color']
                    title_bg = self.config['title_inactive_bg_color']
                    icon = '_receive_off'
                    default_bg = True
                else:
                    title_fg = self.config['title_receive_fg_color']
                    title_bg = self.config['title_receive_bg_color']
                    icon = '_receive_on'
                group_fg = self.config['title_receive_fg_color']
                group_bg = self.config['title_receive_bg_color']
            elif term != other and not term.group or term.group != other.group:
                if terminator.groupsend == terminator.groupsend_type['all']:
                    title_fg = self.config['title_receive_fg_color']
                    title_bg = self.config['title_receive_bg_color']
                    icon = '_receive_on'
                else:
                    title_fg = self.config['title_inactive_fg_color']
                    title_bg = self.config['title_inactive_bg_color']
                    icon = '_receive_off'
                    default_bg = True
                group_fg = self.config['title_inactive_fg_color']
                group_bg = self.config['title_inactive_bg_color']
            else:
                # We're the active terminal
                title_fg = self.config['title_transmit_fg_color']
                title_bg = self.config['title_transmit_bg_color']
                if terminator.groupsend == terminator.groupsend_type['all']:
                    icon = '_active_broadcast_all'
                elif terminator.groupsend == terminator.groupsend_type[
                        'group']:
                    icon = '_active_broadcast_group'
                else:
                    icon = '_active_broadcast_off'
                group_fg = self.config['title_transmit_fg_color']
                group_bg = self.config['title_transmit_bg_color']

            self.label.modify_fg(Gtk.StateType.NORMAL,
                                 Gdk.color_parse(title_fg))
            self.grouplabel.modify_fg(Gtk.StateType.NORMAL,
                                      Gdk.color_parse(group_fg))
            self.modify_bg(Gtk.StateType.NORMAL, Gdk.color_parse(title_bg))
            if not self.get_desired_visibility():
                if default_bg == True:
                    color = term.get_style_context().get_background_color(
                        Gtk.StateType.NORMAL)  # VERIFY FOR GTK3
                else:
                    color = Gdk.color_parse(title_bg)
            self.update_visibility()
            self.ebox.modify_bg(Gtk.StateType.NORMAL,
                                Gdk.color_parse(group_bg))
            self.set_from_icon_name(icon, Gtk.IconSize.MENU)

    def update_visibility(self):
        """Make the titlebar be visible or not"""
        if not self.get_desired_visibility():
            dbg('hiding titlebar')
            self.hide()
            self.label.hide()
        else:
            dbg('showing titlebar')
            self.show()
            self.label.show()

    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 set_from_icon_name(self, name, size=Gtk.IconSize.MENU):
        """Set an icon for the group label"""
        if not name:
            self.groupicon.hide()
            return

        self.groupicon.set_from_icon_name(APP_NAME + name, size)
        self.groupicon.show()

    def update_terminal_size(self, width, height):
        """Update the displayed terminal size"""
        self.sizetext = "%sx%s" % (width, height)
        self.update()

    def set_terminal_title(self, widget, title):
        """Update the terminal title"""
        self.termtext = title
        self.update()
        # Return False so we don't interrupt any chains of signal handling
        return False

    def set_group_label(self, name):
        """Set the name of the group"""
        if name:
            self.grouplabel.set_text(name)
            self.grouplabel.show()
        else:
            self.grouplabel.set_text('')
            self.grouplabel.hide()
        self.update_visibility()

    def on_clicked(self, widget, event):
        """Handle a click on the label"""
        self.show()
        self.label.show()
        self.emit('clicked')

    def on_edit_done(self, widget):
        """Re-emit an edit-done signal from an EditableLabel"""
        self.emit('edit-done')

    def editing(self):
        """Determine if we're currently editing a group name or title"""
        return (self.groupentry.get_property('visible')
                or self.label.editing())

    def create_group(self):
        """Create a new group"""
        if self.terminal.group:
            self.groupentry.set_text(self.terminal.group)
        else:
            defaultmembers = [
                _('Alpha'),
                _('Beta'),
                _('Gamma'),
                _('Delta'),
                _('Epsilon'),
                _('Zeta'),
                _('Eta'),
                _('Theta'),
                _('Iota'),
                _('Kappa'),
                _('Lambda'),
                _('Mu'),
                _('Nu'),
                _('Xi'),
                _('Omicron'),
                _('Pi'),
                _('Rho'),
                _('Sigma'),
                _('Tau'),
                _('Upsilon'),
                _('Phi'),
                _('Chi'),
                _('Psi'),
                _('Omega')
            ]
            currentgroups = set(self.terminator.groups)
            for i in range(1, 4):
                defaultgroups = set(
                    map(''.join,
                        list(itertools.product(defaultmembers, repeat=i))))
                freegroups = list(defaultgroups - currentgroups)
                if freegroups:
                    self.groupentry.set_text(random.choice(freegroups))
                    break
            else:
                self.groupentry.set_text('')
        self.groupentry.show()
        self.grouplabel.hide()
        self.groupentry.grab_focus()
        self.update_visibility()

    def groupentry_cancel(self, widget, event):
        """Hide the group name entry"""
        self.groupentry.set_text('')
        self.groupentry.hide()
        self.grouplabel.show()
        self.get_parent().grab_focus()

    def groupentry_activate(self, widget):
        """Actually cause a group to be created"""
        groupname = self.groupentry.get_text() or None
        dbg('Titlebar::groupentry_activate: creating group: %s' % groupname)
        self.groupentry_cancel(None, None)
        last_focused_term = self.terminator.last_focused_term
        if self.terminal.targets_for_new_group:
            [
                term.titlebar.emit('create-group', groupname)
                for term in self.terminal.targets_for_new_group
            ]
            self.terminal.targets_for_new_group = None
        else:
            self.emit('create-group', groupname)
        last_focused_term.grab_focus()
        self.terminator.focus_changed(last_focused_term)

    def groupentry_keypress(self, widget, event):
        """Handle keypresses on the entry widget"""
        key = Gdk.keyval_name(event.keyval)
        if key == 'Escape':
            self.groupentry_cancel(None, None)

    def icon_bell(self):
        """A bell signal requires we display our bell icon"""
        self.bellicon.show()
        GObject.timeout_add(1000, self.icon_bell_hide)

    def icon_bell_hide(self):
        """Handle a timeout which means we now hide the bell icon"""
        self.bellicon.hide()
        return (False)

    def get_custom_string(self):
        """If we have a custom string set, return it, otherwise None"""
        if self.label.is_custom():
            return (self.label.get_text())
        else:
            return (None)

    def set_custom_string(self, string):
        """Set a custom string"""
        self.label.set_text(string)
        self.label.set_custom()
Exemple #27
0
 def __init__(self):
     """Class initialiser"""
     Plugin.__init__(self)
     terminator = Terminator()
     for terminal in terminator.terminals:
         terminal.match_add(self.handler_name, self.match)
Exemple #28
0
class Notebook(Container, Gtk.Notebook):
    """Class implementing a Gtk.Notebook container"""
    window = None
    last_active_term = None
    pending_on_tab_switch = None
    pending_on_tab_switch_args = None

    def __init__(self, window):
        """Class initialiser"""
        if isinstance(window.get_child(), Gtk.Notebook):
            err('There is already a Notebook at the top of this window')
            raise(ValueError)

        Container.__init__(self)
        GObject.GObject.__init__(self)
        self.terminator = Terminator()
        self.window = window
        GObject.type_register(Notebook)
        self.register_signals(Notebook)
        self.connect('switch-page', self.deferred_on_tab_switch)
        self.connect('scroll-event', self.on_scroll_event)
        self.configure()

        child = window.get_child()
        window.remove(child)
        window.add(self)
        window_last_active_term = window.last_active_term
        self.newtab(widget=child)
        if window_last_active_term:
            self.set_last_active_term(window_last_active_term)
            window.last_active_term = None

        self.show_all()

    def configure(self):
        """Apply widget-wide settings"""
        # FIXME: The old reordered handler updated Terminator.terminals with
        # the new order of terminals. We probably need to preserve this for
        # navigation to next/prev terminals.
        #self.connect('page-reordered', self.on_page_reordered)
        self.set_scrollable(self.config['scroll_tabbar'])

        if self.config['tab_position'] == 'hidden' or self.config['hide_tabbar']:
            self.set_show_tabs(False)
        else:
            self.set_show_tabs(True)
            pos = getattr(Gtk.PositionType, self.config['tab_position'].upper())
            self.set_tab_pos(pos)

        for tab in range(0, self.get_n_pages()):
            label = self.get_tab_label(self.get_nth_page(tab))
            label.update_angle()

#        style = Gtk.RcStyle()  # FIXME FOR GTK3 how to do it there? actually do we really want to override the theme?
#        style.xthickness = 0
#        style.ythickness = 0
#        self.modify_style(style)
        self.last_active_term = {}

    def create_layout(self, layout):
        """Apply layout configuration"""
        def child_compare(a, b):
            order_a = children[a]['order']
            order_b = children[b]['order']

            if (order_a == order_b):
                return 0
            if (order_a < order_b):
                return -1
            if (order_a > order_b):
                return 1

        if not layout.has_key('children'):
            err('layout specifies no children: %s' % layout)
            return

        children = layout['children']
        if len(children) <= 1:
            #Notebooks should have two or more children
            err('incorrect number of children for Notebook: %s' % layout)
            return

        num = 0
        keys = children.keys()
        keys.sort(child_compare)

        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':
                page = self.get_nth_page(num)
                self.split_axis(page, True)
            elif child['type'] == 'HPaned':
                page = self.get_nth_page(num)
                self.split_axis(page, False)
            num = num + 1

        num = 0
        for child_key in keys:
            page = self.get_nth_page(num)
            if not page:
                # This page does not yet exist, so make it
                self.newtab(children[child_key])
                page = self.get_nth_page(num)
            if layout.has_key('labels'):
                labeltext = layout['labels'][num]
                if labeltext and labeltext != "None":
                    label = self.get_tab_label(page)
                    label.set_custom_label(labeltext)
            page.create_layout(children[child_key])

            if  layout.get('last_active_term',  None):
                self.last_active_term[page] = make_uuid(layout['last_active_term'][num])
            num = num + 1

        if layout.has_key('active_page'):
            # Need to do it later, or layout changes result
            GObject.idle_add(self.set_current_page, int(layout['active_page']))
        else:
            self.set_current_page(0)

    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

        GObject.idle_add(terminal.ensure_visible_and_focussed)

    def add(self, widget, metadata=None):
        """Add a widget to the container"""
        dbg('adding a new tab')
        self.newtab(widget=widget, metadata=metadata)

    def remove(self, widget):
        """Remove a widget from the container"""
        page_num = self.page_num(widget)
        if page_num == -1:
            err('%s not found in Notebook. Actual parent is: %s' % (widget, widget.get_parent()))
            return False
        self.remove_page(page_num)
        self.disconnect_child(widget)
        return True

    def replace(self, oldwidget, newwidget):
        """Replace a tab's contents with a new widget"""
        page_num = self.page_num(oldwidget)
        self.remove(oldwidget)
        self.add(newwidget)
        self.reorder_child(newwidget, page_num)

    def get_child_metadata(self, widget):
        """Fetch the relevant metadata for a widget which we'd need
        to recreate it when it's readded"""
        metadata = {}
        metadata['tabnum'] = self.page_num(widget)
        label = self.get_tab_label(widget)
        if not label:
            dbg('unable to find label for widget: %s' % widget)
        elif label.get_custom_label():
            metadata['label'] = label.get_custom_label()
        else:
            dbg('don\'t grab the label as it was not customised')
        return metadata

    def get_children(self):
        """Return an ordered list of our children"""
        children = []
        for page in range(0,self.get_n_pages()):
            children.append(self.get_nth_page(page))
        return(children)

    def newtab(self, debugtab=False, widget=None, cwd=None, metadata=None, profile=None):
        """Add a new tab, optionally supplying a child widget"""
        dbg('making a new tab')
        maker = Factory()
        top_window = self.get_toplevel()

        if not widget:
            widget = maker.make('Terminal')
            if cwd:
                widget.set_cwd(cwd)
            if profile and self.config['always_split_with_profile']:
                widget.force_set_profile(None, profile)
            widget.spawn_child(debugserver=debugtab)
        elif profile and self.config['always_split_with_profile']:
            widget.force_set_profile(None, profile)

        signals = {'close-term': self.wrapcloseterm,
                   'split-horiz': self.split_horiz,
                   'split-vert': self.split_vert,
                   'title-change': self.propagate_title_change,
                   'unzoom': self.unzoom,
                   'tab-change': top_window.tab_change,
                   'group-all': top_window.group_all,
                   'group-all-toggle': top_window.group_all_toggle,
                   'ungroup-all': top_window.ungroup_all,
                   'group-tab': top_window.group_tab,
                   'group-tab-toggle': top_window.group_tab_toggle,
                   'ungroup-tab': top_window.ungroup_tab,
                   'move-tab': top_window.move_tab,
                   'tab-new': [top_window.tab_new, widget],
                   'navigate': top_window.navigate_terminal}

        if maker.isinstance(widget, 'Terminal'):
            for signal in signals:
                args = []
                handler = signals[signal]
                if isinstance(handler, list):
                    args = handler[1:]
                    handler = handler[0]
                self.connect_child(widget, signal, handler, *args)

        if metadata and metadata.has_key('tabnum'):
            tabpos = metadata['tabnum']
        else:
            tabpos = -1

        label = TabLabel(self.window.get_title(), self)
        if metadata and metadata.has_key('label'):
            dbg('creating TabLabel with text: %s' % metadata['label'])
            label.set_custom_label(metadata['label'])
        label.connect('close-clicked', self.closetab)

        label.show_all()
        widget.show_all()

        dbg('inserting page at position: %s' % tabpos)
        self.insert_page(widget, None, tabpos)

        if maker.isinstance(widget, 'Terminal'):
            containers, objects = ([], [widget])
        else:
            containers, objects = enumerate_descendants(widget)

        term_widget = None
        for term_widget in objects:
            if maker.isinstance(term_widget, 'Terminal'):
                self.set_last_active_term(term_widget.uuid)
                break

        self.set_tab_label(widget, label)
        self.child_set_property(widget, 'tab-expand', True)
        self.child_set_property(widget, 'tab-fill', True)

        self.set_tab_reorderable(widget, True)
        self.set_current_page(tabpos)
        self.show_all()
        if maker.isinstance(term_widget, 'Terminal'):
            widget.grab_focus()

    def wrapcloseterm(self, widget):
        """A child terminal has closed"""
        dbg('Notebook::wrapcloseterm: called on %s' % widget)
        if self.closeterm(widget):
            dbg('Notebook::wrapcloseterm: closeterm succeeded')
            self.hoover()
        else:
            dbg('Notebook::wrapcloseterm: closeterm failed')

    def closetab(self, widget, label):
        """Close a tab"""
        tabnum = None
        try:
            nb = widget.notebook
        except AttributeError:
            err('TabLabel::closetab: called on non-Notebook: %s' % widget)
            return

        for i in range(0, nb.get_n_pages() + 1):
            if label == nb.get_tab_label(nb.get_nth_page(i)):
                tabnum = i
                break

        if tabnum is None:
            err('TabLabel::closetab: %s not in %s. Bailing.' % (label, nb))
            return

        maker = Factory()
        child = nb.get_nth_page(tabnum)

        if maker.isinstance(child, 'Terminal'):
            dbg('Notebook::closetab: child is a single Terminal')
            del nb.last_active_term[child]
            child.close()
            # FIXME: We only do this del and return here to avoid removing the
            # page below, which child.close() implicitly does
            del(label)
            return
        elif maker.isinstance(child, 'Container'):
            dbg('Notebook::closetab: child is a Container')
            result = self.construct_confirm_close(self.window, _('tab'))

            if result == Gtk.ResponseType.ACCEPT:
                containers = None
                objects = None
                containers, objects = enumerate_descendants(child)

                while len(objects) > 0:
                    descendant = objects.pop()
                    descendant.close()
                    while Gtk.events_pending():
                        Gtk.main_iteration()
                return
            else:
                dbg('Notebook::closetab: user cancelled request')
                return
        else:
            err('Notebook::closetab: child is unknown type %s' % child)
            return

    def resizeterm(self, widget, keyname):
        """Handle a keyboard event requesting a terminal resize"""
        raise NotImplementedError('resizeterm')

    def zoom(self, widget, fontscale = False):
        """Zoom a terminal"""
        raise NotImplementedError('zoom')

    def unzoom(self, widget):
        """Unzoom a terminal"""
        raise NotImplementedError('unzoom')

    def find_tab_root(self, widget):
        """Look for the tab child which is or ultimately contains the supplied
        widget"""
        parent = widget.get_parent()
        previous = parent

        while parent is not None and parent is not self:
            previous = parent
            parent = parent.get_parent()

        if previous == self:
            return(widget)
        else:
            return(previous)

    def update_tab_label_text(self, widget, text):
        """Update the text of a tab label"""
        notebook = self.find_tab_root(widget)
        label = self.get_tab_label(notebook)
        if not label:
            err('Notebook::update_tab_label_text: %s not found' % widget)
            return

        label.set_label(text)

    def hoover(self):
        """Clean up any empty tabs and if we only have one tab left, die"""
        numpages = self.get_n_pages()
        while numpages > 0:
            numpages = numpages - 1
            page = self.get_nth_page(numpages)
            if not page:
                dbg('Removing empty page: %d' % numpages)
                self.remove_page(numpages)

        if self.get_n_pages() == 1:
            dbg('Last page, removing self')
            child = self.get_nth_page(0)
            self.remove_page(0)
            parent = self.get_parent()
            parent.remove(self)
            self.cnxids.remove_all()
            parent.add(child)
            del(self)
            # Find the last terminal in the new parent and give it focus
            terms = parent.get_visible_terminals()
            terms.keys()[-1].grab_focus()

    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 set_last_active_term(self, uuid):
        """Set the last active term for uuid"""
        widget = self.terminator.find_terminal_by_uuid(uuid.urn)
        if not widget:
            err("Cannot find terminal with uuid: %s, so cannot make it active" % (uuid.urn))
            return
        tabnum = self.page_num_descendant(widget)
        if tabnum == -1:
            err("No tabnum found for terminal with uuid: %s" % (uuid.urn))
            return
        nth_page = self.get_nth_page(tabnum)
        self.last_active_term[nth_page] = uuid

    def clean_last_active_term(self):
        """Clean up old entries in last_active_term"""
        if self.terminator.doing_layout == True:
            return
        last_active_term = {}
        for tabnum in range(0, self.get_n_pages()):
            nth_page = self.get_nth_page(tabnum)
            if nth_page in self.last_active_term:
                last_active_term[nth_page] = self.last_active_term[nth_page]
        self.last_active_term = last_active_term

    def deferred_on_tab_switch(self, notebook, page,  page_num,  data=None):
        """Prime a single idle tab switch signal, using the most recent set of params"""
        tabs_last_active_term = self.last_active_term.get(self.get_nth_page(page_num),  None)
        data = {'tabs_last_active_term': tabs_last_active_term}

        self.pending_on_tab_switch_args = (notebook, page,  page_num,  data)
        if self.pending_on_tab_switch == True:
            return
        GObject.idle_add(self.do_deferred_on_tab_switch)
        self.pending_on_tab_switch = True

    def do_deferred_on_tab_switch(self):
        """Perform the latest tab switch signal, and resetting the pending flag"""
        self.on_tab_switch(*self.pending_on_tab_switch_args)
        self.pending_on_tab_switch = False
        self.pending_on_tab_switch_args = None

    def on_tab_switch(self, notebook, page,  page_num,  data=None):
        """Do the real work for a tab switch"""
        tabs_last_active_term = data['tabs_last_active_term']
        if tabs_last_active_term:
            term = self.terminator.find_terminal_by_uuid(tabs_last_active_term.urn)
            GObject.idle_add(term.ensure_visible_and_focussed)
        return True

    def on_scroll_event(self, notebook, event):
        '''Handle scroll events for scrolling through tabs'''
        #print "self: %s" % self
        #print "event: %s" % event
        child = self.get_nth_page(self.get_current_page())
        if child == None:
            print("Child = None,  return false")
            return False

        event_widget = Gtk.get_event_widget(event)

        if event_widget == None or \
           event_widget == child or \
           event_widget.is_ancestor(child):
            print("event_widget is wrong one,  return false")
            return False

        # Not sure if we need these. I don't think wehave any action widgets
        # at this point.
        action_widget = self.get_action_widget(Gtk.PackType.START)
        if event_widget == action_widget or \
           (action_widget != None and event_widget.is_ancestor(action_widget)):
            return False
        action_widget = self.get_action_widget(Gtk.PackType.END)
        if event_widget == action_widget or \
           (action_widget != None and event_widget.is_ancestor(action_widget)):
            return False

        if event.direction in [Gdk.ScrollDirection.RIGHT,
                               Gdk.ScrollDirection.DOWN]:
            self.next_page()
        elif event.direction in [Gdk.ScrollDirection.LEFT,
                                 Gdk.ScrollDirection.UP]:
            self.prev_page()
        elif event.direction == Gdk.ScrollDirection.SMOOTH:
            if self.get_tab_pos() in [Gtk.PositionType.LEFT,
                                      Gtk.PositionType.RIGHT]:
                if event.delta_y > 0:
                    self.next_page()
                elif event.delta_y < 0:
                    self.prev_page()
            elif self.get_tab_pos() in [Gtk.PositionType.TOP,
                                        Gtk.PositionType.BOTTOM]:
                if event.delta_x > 0:
                    self.next_page()
                elif event.delta_x < 0:
                    self.prev_page()
        return True
Exemple #29
0
 def update_watches(self):
     for terminal in Terminator().terminals:
         if terminal not in self.watches:
             self.watches[terminal] = terminal.get_vte().connect(
                 'contents-changed', self._on_terminal_change, terminal)
Exemple #30
0
def parse_options():
    """Parse the command line options"""
    is_x_terminal_emulator = os.path.basename(
        sys.argv[0]) == 'x-terminal-emulator'

    parser = argparse.ArgumentParser()

    parser.add_argument('-v',
                        '--version',
                        action='store_true',
                        dest='version',
                        help=_('Display program version'))
    parser.add_argument('-m',
                        '--maximise',
                        action='store_true',
                        dest='maximise',
                        help=_('Maximize the window'))
    parser.add_argument('-M',
                        '--maximize',
                        action='store_true',
                        dest='maximise',
                        help=_('Maximize the window'))
    parser.add_argument('-f',
                        '--fullscreen',
                        action='store_true',
                        dest='fullscreen',
                        help=_('Make the window fill the screen'))
    parser.add_argument('-b',
                        '--borderless',
                        action='store_true',
                        dest='borderless',
                        help=_('Disable window borders'))
    parser.add_argument('-H',
                        '--hidden',
                        action='store_true',
                        dest='hidden',
                        help=_('Hide the window at startup'))
    parser.add_argument('-T',
                        '--title',
                        dest='forcedtitle',
                        help=_('Specify a title for the window'))
    parser.add_argument('--geometry',
                        dest='geometry',
                        type=str,
                        help=_(
                            'Set the preferred size and position of the window'
                            '(see X man page)'))
    if not is_x_terminal_emulator:
        parser.add_argument(
            '-e',
            '--command',
            dest='command',
            help=_('Specify a command to execute inside the terminal'))
    else:
        parser.add_argument(
            '--command',
            dest='command',
            help=_('Specify a command to execute inside the terminal'))
        parser.add_argument(
            '-e',
            '--execute2',
            dest='execute',
            action=ExecuteCallback,
            help=_('Use the rest of the command line as a command to '
                   'execute inside the terminal, and its arguments'))
    parser.add_argument('-g',
                        '--config',
                        dest='config',
                        help=_('Specify a config file'))
    parser.add_argument('-j',
                        '--config-json',
                        dest='configjson',
                        help=_('Specify a partial config json file'))
    parser.add_argument(
        '-x',
        '--execute',
        dest='execute',
        action=ExecuteCallback,
        help=_('Use the rest of the command line as a command to execute '
               'inside the terminal, and its arguments'))
    parser.add_argument('--working-directory',
                        metavar='DIR',
                        dest='working_directory',
                        help=_('Set the working directory'))
    parser.add_argument('-i',
                        '--icon',
                        dest='forcedicon',
                        help=_('Set a custom \
icon for the window (by file or name)'))
    parser.add_argument(
        '-r',
        '--role',
        dest='role',
        help=_('Set a custom WM_WINDOW_ROLE property on the window'))
    parser.add_argument('-l',
                        '--layout',
                        dest='layout',
                        help=_('Launch with the given layout'))
    parser.add_argument('-s',
                        '--select-layout',
                        action='store_true',
                        dest='select',
                        help=_('Select a layout from a list'))
    parser.add_argument('-p',
                        '--profile',
                        dest='profile',
                        help=_('Use a different profile as the default'))
    parser.add_argument('-u',
                        '--no-dbus',
                        action='store_true',
                        dest='nodbus',
                        help=_('Disable DBus'))
    parser.add_argument(
        '-d',
        '--debug',
        action='count',
        dest='debug',
        help=_('Enable debugging information (twice for debug server)'))
    parser.add_argument(
        '--debug-classes',
        action='store',
        dest='debug_classes',
        help=_('Comma separated list of classes to limit debugging to'))
    parser.add_argument(
        '--debug-methods',
        action='store',
        dest='debug_methods',
        help=_('Comma separated list of methods to limit debugging to'))
    parser.add_argument(
        '--new-tab',
        action='store_true',
        dest='new_tab',
        help=_('If Terminator is already running, just open a new tab'))
    parser.add_argument(
        '--unhide',
        action='store_true',
        dest='unhide',
        help=_(
            'If Terminator is already running, just unhide all hidden windows')
    )
    parser.add_argument('--list-profiles',
                        action='store_true',
                        dest='list_profiles',
                        help=_('List all profiles'))
    parser.add_argument('--list-layouts',
                        action='store_true',
                        dest='list_layouts',
                        help=_('List all layouts'))

    for item in [
            '--sm-client-id', '--sm-config-prefix', '--screen', '-n',
            '--no-gconf'
    ]:
        parser.add_argument(item,
                            dest='dummy',
                            action='store',
                            help=argparse.SUPPRESS)

    global options
    options = parser.parse_args()

    if options.version:
        print('%s %s' % (version.APP_NAME, version.APP_VERSION))
        sys.exit(0)

    if options.list_profiles:
        for p in Terminator().config.list_profiles():
            print(p)
        sys.exit(0)
    if options.list_layouts:
        for l in Terminator().config.list_layouts():
            print(l)
        sys.exit(0)

    if options.debug_classes or options.debug_methods:
        if not options.debug > 0:
            options.debug = 1

    if options.debug:
        util.DEBUG = True
        if options.debug > 1:
            util.DEBUGFILES = True
        if options.debug_classes:
            classes = options.debug_classes.split(',')
            for item in classes:
                util.DEBUGCLASSES.append(item.strip())
        if options.debug_methods:
            methods = options.debug_methods.split(',')
            for item in methods:
                util.DEBUGMETHODS.append(item.strip())

    if options.working_directory:
        if os.path.exists(os.path.expanduser(options.working_directory)):
            options.working_directory = os.path.expanduser(
                options.working_directory)
            os.chdir(options.working_directory)
        else:
            err('OptionParse::parse_options: %s does not exist' %
                options.working_directory)
            options.working_directory = ''

    if options.layout is None:
        options.layout = 'default'

    configobj = config.Config()
    if options.profile and options.profile not in configobj.list_profiles():
        options.profile = None

    configobj.options_set(options)

    optionslist = {}
    for opt, val in list(options.__dict__.items()):
        if type(val) == type([]):
            val = ' '.join(val)
        if val == True:
            val = 'True'
        optionslist[opt] = val and '%s' % val or ''
    # optionslist = dbus.Dictionary(optionslist, signature='ss')
    if util.DEBUG == True:
        dbg('command line options: %s' % options)

    return (options, optionslist)
Exemple #31
0
 def jumpUp(self, widget):
     t = Terminator().last_focused_term
     t.scrollbar_jump(self.last_cursor_pos)