mirror of
https://github.com/Guake/guake.git
synced 2025-10-26 11:27:13 +00:00
645 lines
24 KiB
Python
645 lines
24 KiB
Python
# -*- coding: utf-8; -*-
|
|
"""
|
|
Copyright (C) 2007-2018 Guake authors
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License as
|
|
published by the Free Software Foundation; either version 2 of the
|
|
License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public
|
|
License along with this program; if not, write to the
|
|
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
Boston, MA 02110-1301 USA
|
|
"""
|
|
|
|
from guake.about import AboutDialog
|
|
from guake.boxes import RootTerminalBox
|
|
from guake.boxes import TabLabelEventBox
|
|
from guake.boxes import TerminalBox
|
|
from guake.callbacks import MenuHideCallback
|
|
from guake.callbacks import NotebookScrollCallback
|
|
from guake.dialogs import PromptQuitDialog
|
|
from guake.globals import PROMPT_ALWAYS
|
|
from guake.globals import PROMPT_PROCESSES
|
|
from guake.menus import mk_notebook_context_menu
|
|
from guake.prefs import PrefsDialog
|
|
from guake.utils import HidePrevention
|
|
from guake.utils import gdk_is_x11_display
|
|
from guake.utils import get_process_name
|
|
from guake.utils import save_tabs_when_changed
|
|
|
|
import gi
|
|
import os
|
|
|
|
gi.require_version("Gtk", "3.0")
|
|
gi.require_version("Wnck", "3.0")
|
|
from gi.repository import GObject
|
|
from gi.repository import Gdk
|
|
from gi.repository import Gtk
|
|
from gi.repository import Wnck
|
|
from guake.terminal import GuakeTerminal
|
|
|
|
import logging
|
|
import posix
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
class TerminalNotebook(Gtk.Notebook):
|
|
def __init__(self, *args, **kwargs):
|
|
Gtk.Notebook.__init__(self, *args, **kwargs)
|
|
self.last_terminal_focused = None
|
|
|
|
self.set_name("notebook-teminals")
|
|
self.set_tab_pos(Gtk.PositionType.BOTTOM)
|
|
self.set_property("show-tabs", True)
|
|
self.set_property("enable-popup", False)
|
|
self.set_property("scrollable", True)
|
|
self.set_property("show-border", False)
|
|
self.set_property("visible", True)
|
|
self.set_property("has-focus", True)
|
|
self.set_property("can-focus", True)
|
|
self.set_property("is-focus", True)
|
|
self.set_property("expand", True)
|
|
|
|
if GObject.signal_lookup("terminal-spawned", TerminalNotebook) == 0:
|
|
GObject.signal_new(
|
|
"terminal-spawned",
|
|
TerminalNotebook,
|
|
GObject.SignalFlags.RUN_LAST,
|
|
GObject.TYPE_NONE,
|
|
(GObject.TYPE_PYOBJECT, GObject.TYPE_INT),
|
|
)
|
|
GObject.signal_new(
|
|
"page-deleted",
|
|
TerminalNotebook,
|
|
GObject.SignalFlags.RUN_LAST,
|
|
GObject.TYPE_NONE,
|
|
(),
|
|
)
|
|
|
|
self.scroll_callback = NotebookScrollCallback(self)
|
|
self.add_events(Gdk.EventMask.SCROLL_MASK)
|
|
self.connect("scroll-event", self.scroll_callback.on_scroll)
|
|
self.notebook_on_button_press_id = self.connect(
|
|
"button-press-event", self.on_button_press, None
|
|
)
|
|
|
|
# Action box
|
|
self.pin_button = Gtk.ToggleButton(
|
|
image=Gtk.Image.new_from_icon_name("view-pin-symbolic", Gtk.IconSize.MENU),
|
|
visible=False,
|
|
)
|
|
self.pin_button.connect("clicked", self.on_pin_clicked)
|
|
self.new_page_button = Gtk.Button(
|
|
image=Gtk.Image.new_from_icon_name("tab-new-symbolic", Gtk.IconSize.MENU),
|
|
visible=True,
|
|
)
|
|
self.new_page_button.connect("clicked", self.on_new_tab)
|
|
|
|
self.tab_selection_button = Gtk.Button(
|
|
image=Gtk.Image.new_from_icon_name("pan-down-symbolic", Gtk.IconSize.MENU),
|
|
visible=True,
|
|
)
|
|
self.popover = Gtk.Popover()
|
|
self.popover_window = None
|
|
self.tab_selection_button.connect("clicked", self.on_tab_selection)
|
|
|
|
self.action_box = Gtk.Box(visible=True)
|
|
self.action_box.pack_start(self.pin_button, 0, 0, 0)
|
|
self.action_box.pack_start(self.new_page_button, 0, 0, 0)
|
|
self.action_box.pack_start(self.tab_selection_button, 0, 0, 0)
|
|
self.set_action_widget(self.action_box, Gtk.PackType.END)
|
|
|
|
def attach_guake(self, guake):
|
|
self.guake = guake
|
|
|
|
self.guake.settings.general.onChangedValue("window-losefocus", self.on_lose_focus_toggled)
|
|
self.pin_button.set_visible(self.guake.settings.general.get_boolean("window-losefocus"))
|
|
|
|
def on_button_press(self, target, event, user_data):
|
|
if event.button == 3:
|
|
menu = mk_notebook_context_menu(self)
|
|
menu.connect("hide", MenuHideCallback(self.guake.window).on_hide)
|
|
|
|
try:
|
|
menu.popup_at_pointer(event)
|
|
except AttributeError:
|
|
# Gtk 3.18 fallback ("'Menu' object has no attribute 'popup_at_pointer'")
|
|
menu.popup(None, None, None, None, event.button, event.time)
|
|
elif (
|
|
event.type == Gdk.EventType.DOUBLE_BUTTON_PRESS
|
|
and event.button == 1
|
|
and event.window.get_height() < 60
|
|
):
|
|
# event.window.get_height() reports the height of the clicked frame
|
|
self.new_page_with_focus()
|
|
|
|
return False
|
|
|
|
def on_pin_clicked(self, user_data=None):
|
|
hide_prevention = HidePrevention(self.guake.window)
|
|
if self.pin_button.get_active():
|
|
hide_prevention.prevent()
|
|
else:
|
|
hide_prevention.allow()
|
|
|
|
def on_lose_focus_toggled(self, settings, key, user_data=None):
|
|
self.pin_button.set_visible(settings.get_boolean(key))
|
|
|
|
@save_tabs_when_changed
|
|
def on_new_tab(self, user_data):
|
|
self.new_page_with_focus()
|
|
|
|
def on_tab_selection(self, user_data):
|
|
"""Construct the tab selection popover
|
|
|
|
Since we did not use Gtk.ListStore to store tab information, we will construct the
|
|
tab selection popover content each time when user click them.
|
|
"""
|
|
|
|
# Remove previous window
|
|
if self.popover_window:
|
|
self.popover.remove(self.popover_window)
|
|
|
|
# This makes the list's background transparent
|
|
# ref: epiphany
|
|
css_provider = Gtk.CssProvider()
|
|
css_provider.load_from_data(
|
|
b"#popover-window list { border-style: none; background-color: transparent; }"
|
|
)
|
|
Gtk.StyleContext.add_provider_for_screen(
|
|
Gdk.Screen.get_default(),
|
|
css_provider,
|
|
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION,
|
|
)
|
|
|
|
# Construct popover properties
|
|
BOX_HEIGHT = 30
|
|
LISTBOX_MARGIN = 12
|
|
self.popover_window = Gtk.ScrolledWindow(name="popover-window")
|
|
self.popover_listbox = Gtk.ListBox()
|
|
self.popover_listbox.set_property("margin", LISTBOX_MARGIN)
|
|
self.popover_window.add_with_viewport(self.popover_listbox)
|
|
|
|
max_height = (
|
|
self.guake.window.get_allocation().height - BOX_HEIGHT
|
|
if self.guake
|
|
else BOX_HEIGHT * 10
|
|
)
|
|
height = BOX_HEIGHT * self.get_n_pages() + LISTBOX_MARGIN * 4
|
|
self.popover_window.set_min_content_height(min(max_height, height))
|
|
self.popover_window.set_min_content_width(325)
|
|
self.popover.add(self.popover_window)
|
|
|
|
# Construct content
|
|
current_term = self.get_current_terminal()
|
|
selected_row = 0
|
|
for i in range(self.get_n_pages()):
|
|
row = Gtk.ListBoxRow()
|
|
box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
|
|
box.set_size_request(200, BOX_HEIGHT)
|
|
label = Gtk.Label(self.get_tab_text_index(i))
|
|
label.set_xalign(0.0)
|
|
box.pack_start(label, 0, 0, 5)
|
|
row.add(box)
|
|
setattr(row, "page_index", i)
|
|
self.popover_listbox.add(row)
|
|
if current_term in self.get_terminals_for_page(i):
|
|
self.popover_listbox.select_row(row)
|
|
selected_row = i
|
|
|
|
# Signal
|
|
self.popover_listbox.connect("row-activated", self.on_popover_tab_select)
|
|
|
|
# Show popup
|
|
self.popover.set_position(Gtk.PositionType.TOP)
|
|
self.popover.set_relative_to(user_data)
|
|
self.popover.show_all()
|
|
try:
|
|
# For GTK >= 3.22
|
|
self.popover.popup()
|
|
except AttributeError:
|
|
pass
|
|
|
|
# Adjust scrollor
|
|
while Gtk.events_pending():
|
|
Gtk.main_iteration()
|
|
|
|
if selected_row:
|
|
adj = self.popover_window.get_vadjustment()
|
|
v = adj.get_upper() - adj.get_page_size()
|
|
part = v / self.get_n_pages()
|
|
adj.set_value(part * (selected_row + 1))
|
|
|
|
def on_popover_tab_select(self, list_box, row):
|
|
page_index = getattr(row, "page_index", -1)
|
|
if page_index != -1:
|
|
self.set_current_page(page_index)
|
|
self.get_terminals_for_page(page_index)[0].grab_focus()
|
|
|
|
def set_tabbar_visible(self, v):
|
|
self.set_property("show-tabs", v)
|
|
|
|
def set_last_terminal_focused(self, terminal):
|
|
self.last_terminal_focused = terminal
|
|
|
|
def get_focused_terminal(self):
|
|
for terminal in self.iter_terminals():
|
|
if terminal.has_focus():
|
|
return terminal
|
|
|
|
def get_current_terminal(self):
|
|
# TODO NOTEBOOK the name of this method should
|
|
# be changed, for now it returns the last focused terminal
|
|
return self.last_terminal_focused
|
|
|
|
def get_terminals_for_page(self, index):
|
|
page = self.get_nth_page(index)
|
|
return page.get_terminals()
|
|
|
|
def get_terminals(self):
|
|
terminals = []
|
|
for page in self.iter_pages():
|
|
terminals += page.get_terminals()
|
|
return terminals
|
|
|
|
def get_running_fg_processes(self):
|
|
processes = []
|
|
for page in self.iter_pages():
|
|
processes += self.get_running_fg_processes_page(page)
|
|
return processes
|
|
|
|
def get_running_fg_processes_page(self, page):
|
|
processes = []
|
|
for terminal in page.get_terminals():
|
|
pty = terminal.get_pty()
|
|
if not pty:
|
|
continue
|
|
fdpty = pty.get_fd()
|
|
term_pid = terminal.pid
|
|
try:
|
|
fgpid = posix.tcgetpgrp(fdpty)
|
|
log.debug("found running pid: %s", fgpid)
|
|
if fgpid not in (-1, term_pid):
|
|
processes.append((fgpid, get_process_name(fgpid)))
|
|
except OSError:
|
|
log.debug(
|
|
"Cannot retrieve any pid from terminal %s, looks like it is already dead",
|
|
terminal,
|
|
)
|
|
return processes
|
|
|
|
def has_page(self):
|
|
return self.get_n_pages() > 0
|
|
|
|
def iter_terminals(self):
|
|
for page in self.iter_pages():
|
|
if page is not None:
|
|
yield from page.iter_terminals()
|
|
|
|
def iter_tabs(self):
|
|
for page_num in range(self.get_n_pages()):
|
|
yield self.get_tab_label(self.get_nth_page(page_num))
|
|
|
|
def iter_pages(self):
|
|
for page_num in range(self.get_n_pages()):
|
|
yield self.get_nth_page(page_num)
|
|
|
|
def delete_page(self, page_num, kill=True, prompt=0):
|
|
log.debug("Deleting page index %s", page_num)
|
|
if page_num >= self.get_n_pages() or page_num < 0:
|
|
log.error("Can not delete page %s no such index", page_num)
|
|
return
|
|
|
|
page = self.get_nth_page(page_num)
|
|
# TODO NOTEBOOK it would be nice if none of the "ui" stuff
|
|
# (PromptQuitDialog) would be in here
|
|
procs = self.get_running_fg_processes_page(page)
|
|
if prompt == PROMPT_ALWAYS or (prompt == PROMPT_PROCESSES and procs):
|
|
# TODO NOTEBOOK remove call to guake
|
|
if not PromptQuitDialog(self.guake.window, procs, -1, None).close_tab():
|
|
return
|
|
|
|
for terminal in page.get_terminals():
|
|
if kill:
|
|
terminal.kill()
|
|
terminal.destroy()
|
|
|
|
if self.get_nth_page(page_num) is page:
|
|
# NOTE: GitHub issue #1438
|
|
# Previous line `terminal.destroy()` will finally called `on_terminal_exited`,
|
|
# and called `RootTerminalBox.remove_dead_child`, then called `remove_page`.
|
|
#
|
|
# But in some cases (e.g. #1438), it will not remove the page by
|
|
# `terminal.destory() chain`.
|
|
#
|
|
# Check this by compare same page_num page with previous saved page instance,
|
|
# and remove the page if it really didn't remove it.
|
|
self.remove_page(page_num)
|
|
|
|
@save_tabs_when_changed
|
|
def remove_page(self, page_num):
|
|
super().remove_page(page_num)
|
|
# focusing the first terminal on the previous page
|
|
if self.get_current_page() > -1:
|
|
page = self.get_nth_page(self.get_current_page())
|
|
if page.get_terminals():
|
|
page.get_terminals()[0].grab_focus()
|
|
|
|
self.hide_tabbar_if_one_tab()
|
|
self.emit("page-deleted")
|
|
|
|
def delete_page_by_label(self, label, kill=True, prompt=0):
|
|
self.delete_page(self.find_tab_index_by_label(label), kill, prompt)
|
|
|
|
def delete_page_current(self, kill=True, prompt=0):
|
|
self.delete_page(self.get_current_page(), kill, prompt)
|
|
|
|
def new_page(self, directory=None, position=None, empty=False, open_tab_cwd=False):
|
|
terminal_box = TerminalBox()
|
|
if empty:
|
|
terminal = None
|
|
else:
|
|
terminal = self.terminal_spawn(directory, open_tab_cwd)
|
|
terminal_box.set_terminal(terminal)
|
|
root_terminal_box = RootTerminalBox(self.guake, self)
|
|
root_terminal_box.set_child(terminal_box)
|
|
page_num = self.insert_page(
|
|
root_terminal_box, None, position if position is not None else -1
|
|
)
|
|
self.set_tab_reorderable(root_terminal_box, True)
|
|
self.show_all() # needed to show newly added tabs and pages
|
|
# this is needed because self.window.show_all() results in showing every
|
|
# thing which includes the scrollbar too
|
|
self.guake.settings.general.triggerOnChangedValue(
|
|
self.guake.settings.general, "use-scrollbar"
|
|
)
|
|
# this is needed to initially set the last_terminal_focused,
|
|
# one could also call terminal.get_parent().on_terminal_focus()
|
|
if not empty:
|
|
self.terminal_attached(terminal)
|
|
self.hide_tabbar_if_one_tab()
|
|
|
|
if self.guake:
|
|
# Attack background image draw callback to root terminal box
|
|
root_terminal_box.connect_after("draw", self.guake.background_image_manager.draw)
|
|
return root_terminal_box, page_num, terminal
|
|
|
|
def hide_tabbar_if_one_tab(self):
|
|
"""Hide the tab bar if hide-tabs-if-one-tab is true and there is only one
|
|
notebook page"""
|
|
if self.guake.settings.general.get_boolean("window-tabbar"):
|
|
if self.guake.settings.general.get_boolean("hide-tabs-if-one-tab"):
|
|
self.set_property("show-tabs", self.get_n_pages() != 1)
|
|
else:
|
|
self.set_property("show-tabs", True)
|
|
|
|
def terminal_spawn(self, directory=None, open_tab_cwd=False):
|
|
terminal = GuakeTerminal(self.guake)
|
|
terminal.grab_focus()
|
|
terminal.connect(
|
|
"key-press-event",
|
|
lambda x, y: self.guake.accel_group.activate(x, y) if self.guake.accel_group else False,
|
|
)
|
|
if not isinstance(directory, str):
|
|
directory = os.environ["HOME"]
|
|
try:
|
|
if self.guake.settings.general.get_boolean("open-tab-cwd") or open_tab_cwd:
|
|
# Do last focused terminal still alive?
|
|
active_terminal = self.get_current_terminal()
|
|
if not active_terminal:
|
|
# If not alive, can we get any focused terminal?
|
|
active_terminal = self.get_focused_terminal()
|
|
directory = os.path.expanduser("~")
|
|
if active_terminal:
|
|
# If found, we will use its directory as new terminal's directory
|
|
directory = active_terminal.get_current_directory()
|
|
except BaseException:
|
|
pass
|
|
log.info("Spawning new terminal at %s", directory)
|
|
terminal.spawn_sync_pid(directory)
|
|
return terminal
|
|
|
|
def terminal_attached(self, terminal):
|
|
terminal.emit("focus", Gtk.DirectionType.TAB_FORWARD)
|
|
self.emit("terminal-spawned", terminal, terminal.pid)
|
|
|
|
def new_page_with_focus(
|
|
self,
|
|
directory=None,
|
|
label=None,
|
|
user_set=False,
|
|
position=None,
|
|
empty=False,
|
|
open_tab_cwd=False,
|
|
):
|
|
box, page_num, terminal = self.new_page(
|
|
directory, position=position, empty=empty, open_tab_cwd=open_tab_cwd
|
|
)
|
|
self.set_current_page(page_num)
|
|
if not label:
|
|
self.rename_page(page_num, self.guake.compute_tab_title(terminal), False)
|
|
else:
|
|
self.rename_page(page_num, label, user_set)
|
|
if terminal is not None:
|
|
terminal.grab_focus()
|
|
return box, page_num, terminal
|
|
|
|
def rename_page(self, page_index, new_text, user_set=False):
|
|
"""Rename an already added page by its index. Use user_set to define
|
|
if the rename was triggered by the user (eg. rename dialog) or by
|
|
an update from the vte (eg. vte:window-title-changed)
|
|
"""
|
|
page = self.get_nth_page(page_index)
|
|
if not getattr(page, "custom_label_set", False) or user_set:
|
|
old_label = self.get_tab_label(page)
|
|
if isinstance(old_label, TabLabelEventBox):
|
|
old_label.set_text(new_text)
|
|
else:
|
|
label = TabLabelEventBox(self, new_text, self.guake.settings)
|
|
label.add_events(Gdk.EventMask.SCROLL_MASK)
|
|
label.connect("scroll-event", self.scroll_callback.on_scroll)
|
|
|
|
self.set_tab_label(page, label)
|
|
if user_set:
|
|
setattr(page, "custom_label_set", new_text != "-")
|
|
|
|
def find_tab_index_by_label(self, eventbox):
|
|
for index, tab_eventbox in enumerate(self.iter_tabs()):
|
|
if eventbox is tab_eventbox:
|
|
return index
|
|
return -1
|
|
|
|
def find_page_index_by_terminal(self, terminal):
|
|
for index, page in enumerate(self.iter_pages()):
|
|
for t in page.iter_terminals():
|
|
if t is terminal:
|
|
return index
|
|
return -1
|
|
|
|
def get_tab_text_index(self, index):
|
|
return self.get_tab_label(self.get_nth_page(index)).get_text()
|
|
|
|
def get_tab_text_page(self, page):
|
|
return self.get_tab_label(page).get_text()
|
|
|
|
def on_show_preferences(self, user_data):
|
|
self.guake.hide()
|
|
PrefsDialog(self.guake.settings).show()
|
|
|
|
def on_show_about(self, user_data):
|
|
self.guake.hide()
|
|
AboutDialog()
|
|
|
|
def on_quit(self, user_data):
|
|
self.guake.accel_quit()
|
|
|
|
def on_save_tabs(self, user_data):
|
|
self.guake.save_tabs()
|
|
|
|
def on_restore_tabs(self, user_data):
|
|
self.guake.restore_tabs()
|
|
|
|
def on_restore_tabs_with_dialog(self, user_data):
|
|
dialog = Gtk.MessageDialog(
|
|
parent=self.guake.window,
|
|
flags=Gtk.DialogFlags.MODAL,
|
|
buttons=Gtk.ButtonsType.OK_CANCEL,
|
|
message_format=_(
|
|
"You are going to restore *all* the tabs!\n"
|
|
"which means all your terminals & pages "
|
|
"will be replaced.\n\nDo you want to continue?"
|
|
),
|
|
)
|
|
dialog.connect("response", self.restore_tabs_dialog_response)
|
|
dialog.show()
|
|
|
|
def restore_tabs_dialog_response(self, widget, response_id):
|
|
widget.destroy()
|
|
if response_id == Gtk.ResponseType.OK:
|
|
self.guake.restore_tabs()
|
|
|
|
|
|
class NotebookManager(GObject.Object):
|
|
def __init__(
|
|
self,
|
|
window,
|
|
notebook_parent,
|
|
workspaces_enabled,
|
|
terminal_spawned_cb,
|
|
page_deleted_cb,
|
|
):
|
|
GObject.Object.__init__(self)
|
|
if not GObject.signal_lookup("notebook-created", self):
|
|
GObject.signal_new(
|
|
"notebook-created",
|
|
self,
|
|
GObject.SignalFlags.RUN_LAST,
|
|
GObject.TYPE_NONE,
|
|
(GObject.TYPE_PYOBJECT, GObject.TYPE_INT),
|
|
)
|
|
self.current_notebook = 0
|
|
self.notebooks = {}
|
|
self.window = window
|
|
self.notebook_parent = notebook_parent
|
|
self.terminal_spawned_cb = terminal_spawned_cb
|
|
self.page_deleted_cb = page_deleted_cb
|
|
if workspaces_enabled and gdk_is_x11_display(Gdk.Display.get_default()):
|
|
# NOTE: Wnck didn't support non-X11 display backend, so we need to check if the display
|
|
# is X11 or not, if not, it will not able to enable workspace-specific-tab-sets
|
|
#
|
|
# TODO: Is there anyway to support this in non-X11 display backend?
|
|
self.screen = Wnck.Screen.get_default()
|
|
self.screen.connect("active-workspace-changed", self.__workspace_changed_cb)
|
|
|
|
def __workspace_changed_cb(self, screen, previous_workspace):
|
|
self.set_workspace(self.screen.get_active_workspace().get_number())
|
|
|
|
def get_notebook(self, workspace_index: int):
|
|
if not self.has_notebook_for_workspace(workspace_index):
|
|
self.notebooks[workspace_index] = TerminalNotebook()
|
|
self.emit("notebook-created", self.notebooks[workspace_index], workspace_index)
|
|
self.notebooks[workspace_index].connect("terminal-spawned", self.terminal_spawned_cb)
|
|
self.notebooks[workspace_index].connect("page-deleted", self.page_deleted_cb)
|
|
log.info("created fresh notebook for workspace %d", self.current_notebook)
|
|
|
|
# add a tab if there is none
|
|
if not self.notebooks[workspace_index].has_page():
|
|
self.notebooks[workspace_index].new_page_with_focus(None)
|
|
|
|
return self.notebooks[workspace_index]
|
|
|
|
def get_current_notebook(self):
|
|
return self.get_notebook(self.current_notebook)
|
|
|
|
def has_notebook_for_workspace(self, workspace_index):
|
|
return workspace_index in self.notebooks
|
|
|
|
def set_workspace(self, index: int):
|
|
self.notebook_parent.remove(self.get_current_notebook())
|
|
self.current_notebook = index
|
|
log.info("current workspace is %d", self.current_notebook)
|
|
notebook = self.get_current_notebook()
|
|
self.notebook_parent.add(notebook)
|
|
if self.window.get_property("visible") and notebook.last_terminal_focused is not None:
|
|
notebook.last_terminal_focused.grab_focus()
|
|
|
|
# Restore pending page terminal split
|
|
notebook.guake.restore_pending_terminal_split()
|
|
|
|
# Restore config to workspace
|
|
notebook.guake.load_config()
|
|
|
|
def set_notebooks_tabbar_visible(self, v):
|
|
for nb in self.iter_notebooks():
|
|
nb.set_tabbar_visible(v)
|
|
|
|
def get_notebooks(self):
|
|
return self.notebooks
|
|
|
|
def get_terminals(self):
|
|
terminals = []
|
|
for k in self.notebooks:
|
|
terminals += self.notebooks[k].get_terminals()
|
|
return terminals
|
|
|
|
def iter_terminals(self):
|
|
for k in self.notebooks:
|
|
yield from self.notebooks[k].iter_terminals()
|
|
|
|
def get_terminal_by_uuid(self, terminal_uuid):
|
|
for t in self.iter_terminals():
|
|
if t.uuid == terminal_uuid:
|
|
return t
|
|
return None
|
|
|
|
def iter_pages(self):
|
|
for k in self.notebooks:
|
|
yield from self.notebooks[k].iter_pages()
|
|
|
|
def iter_notebooks(self):
|
|
for k in self.notebooks:
|
|
yield self.notebooks[k]
|
|
|
|
def get_n_pages(self):
|
|
n = 0
|
|
for k in self.notebooks:
|
|
n += self.notebooks[k].get_n_pages()
|
|
return n
|
|
|
|
def get_n_notebooks(self):
|
|
return len(self.notebooks.keys())
|
|
|
|
def get_running_fg_processes(self):
|
|
processes = []
|
|
for k in self.notebooks:
|
|
processes += self.notebooks[k].get_running_fg_processes()
|
|
return processes
|