mirror of
https://github.com/Guake/guake.git
synced 2025-10-26 11:27:13 +00:00
rewrite the notebook
This commit is contained in:
parent
d7674bad12
commit
1311cb0b6b
147
guake/boxes.py
Normal file
147
guake/boxes.py
Normal file
@ -0,0 +1,147 @@
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
|
||||
|
||||
class TerminalHolder():
|
||||
def get_terminals(self):
|
||||
pass
|
||||
|
||||
def iter_terminals(self):
|
||||
pass
|
||||
|
||||
def replace_child(self, old, new):
|
||||
pass
|
||||
|
||||
def get_guake(self):
|
||||
pass
|
||||
|
||||
class RootTerminalBox(Gtk.Box, TerminalHolder):
|
||||
|
||||
def __init__(self, guake):
|
||||
super().__init__(orientation=Gtk.Orientation.HORIZONTAL)
|
||||
self.guake = guake
|
||||
self.child = None
|
||||
|
||||
def get_terminals(self):
|
||||
return self.get_child().get_terminals()
|
||||
|
||||
def iter_terminals(self):
|
||||
if self.get_child() is not None:
|
||||
for t in self.get_child().iter_terminals():
|
||||
yield t
|
||||
|
||||
def replace_child(self, old, new):
|
||||
self.remove(old)
|
||||
self.set_child(new_child)
|
||||
|
||||
def set_child(self, terminal_holder):
|
||||
if isinstance(terminal_holder, TerminalHolder) or True:
|
||||
self.child = terminal_holder
|
||||
self.pack_start(terminal_holder, True, True, 0)
|
||||
else:
|
||||
print("wtf, what have you added to me???"
|
||||
"(RootTerminalBox.add(%s))" % type(terminal_holder))
|
||||
|
||||
def get_child(self):
|
||||
return self.child
|
||||
|
||||
def get_guake(self):
|
||||
return self.guake
|
||||
|
||||
class TerminalBox(Gtk.Box, TerminalHolder):
|
||||
|
||||
"""A box to group the terminal and a scrollbar.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(orientation=Gtk.Orientation.HORIZONTAL)
|
||||
|
||||
def set_terminal(self, terminal):
|
||||
"""Packs the terminal widget.
|
||||
"""
|
||||
self.terminal = terminal
|
||||
self.pack_start(self.terminal, True, True, 0)
|
||||
self.terminal.show()
|
||||
self.add_scroll_bar()
|
||||
|
||||
def add_scroll_bar(self):
|
||||
"""Packs the scrollbar.
|
||||
"""
|
||||
adj = self.terminal.get_vadjustment()
|
||||
scroll = Gtk.VScrollbar(adj)
|
||||
scroll.show()
|
||||
self.pack_start(scroll, False, False, 0)
|
||||
|
||||
def get_terminal(self):
|
||||
return self.terminal
|
||||
|
||||
def get_terminals(self):
|
||||
return [self.terminal]
|
||||
|
||||
def iter_terminals(self):
|
||||
yield self.terminal
|
||||
|
||||
def replace_child(self, old, new):
|
||||
print("why would you call this on me?")
|
||||
pass
|
||||
|
||||
def split_h(self):
|
||||
self.split(DualTerminalBox.ORIENT_H)
|
||||
|
||||
def split_v(self):
|
||||
self.split(DualTerminalBox.ORIENT_V)
|
||||
|
||||
def split(self, orientation):
|
||||
parent = self.get_parent()
|
||||
dual_terminal_box = DualTerminalBox(orientation)
|
||||
parent.replace_child(self, dual_terminal_box)
|
||||
dual_terminal_box.set_child_first(self)
|
||||
dual_terminal_box.set_child_second(GuakeTerminal())
|
||||
|
||||
def get_guake(self):
|
||||
return self.get_parent().get_guake()
|
||||
|
||||
|
||||
class DualTerminalBox(Gtk.Paned, TerminalHolder):
|
||||
|
||||
ORIENT_H = 0
|
||||
ORIENT_V = 1
|
||||
|
||||
def __init__(self, orientation):
|
||||
super().__init__()
|
||||
|
||||
if orientation is DualTerminalBox.ORIENT_H:
|
||||
self.set_orientation(orientation=Gtk.Orientation.HORIZONTAL)
|
||||
else:
|
||||
self.set_orientation(orientation=Gtk.Orientation.VERTICAL)
|
||||
|
||||
def set_child_first(self, terminal_holder):
|
||||
if isinstance(terminal_holder, TerminalHolder):
|
||||
self.add1(terminal_holder)
|
||||
else:
|
||||
print("wtf, what have you added to me???")
|
||||
|
||||
def set_child_second(self, terminal_holder):
|
||||
if isinstance(terminal_holder, TerminalHolder):
|
||||
self.add2(terminal_holder)
|
||||
else:
|
||||
print("wtf, what have you added to me???")
|
||||
|
||||
def get_terminals(self):
|
||||
return self.get_child1().get_terminals() + self.get_child2().get_terminals()
|
||||
|
||||
def iter_terminals(self):
|
||||
self.get_child1().iter_terminals(self)
|
||||
self.get_child2().iter_terminals(self)
|
||||
|
||||
def replace_child(self, old, new):
|
||||
if self.get_child1() is old:
|
||||
self.set_child_first(new)
|
||||
elif self.get_child2() is old:
|
||||
self.set_child_second(new)
|
||||
else:
|
||||
print("I have never seen this widget!")
|
||||
|
||||
def get_guake(self):
|
||||
return self.get_parent().get_guake()
|
||||
@ -84,7 +84,7 @@ class DbusManager(dbus.service.Object):
|
||||
|
||||
@dbus.service.method(DBUS_NAME, out_signature='i')
|
||||
def get_tab_count(self):
|
||||
return len(self.guake.notebook.term_list)
|
||||
return len(self.guake.notebook.get_terminals())
|
||||
|
||||
@dbus.service.method(DBUS_NAME, in_signature='s')
|
||||
def set_bgcolor(self, bgcolor):
|
||||
@ -100,7 +100,7 @@ class DbusManager(dbus.service.Object):
|
||||
|
||||
@dbus.service.method(DBUS_NAME, in_signature='i', out_signature='s')
|
||||
def get_tab_name(self, tab_index=0):
|
||||
return self.guake.notebook.term_list[int(tab_index)].get_window_title() or ''
|
||||
return self.guake.notebook.get_tab_text_index(tab_index)
|
||||
|
||||
@dbus.service.method(DBUS_NAME, in_signature='ss')
|
||||
def rename_tab_uuid(self, tab_uuid, new_text):
|
||||
|
||||
@ -213,7 +213,7 @@ class GSettingHandler():
|
||||
log.error("Error: unable to find font name (%s)", font_name)
|
||||
return
|
||||
font = Pango.FontDescription(font_name)
|
||||
if not font or True:
|
||||
if not font:
|
||||
log.error("Error: unable to load font (%s)", font_name)
|
||||
return
|
||||
for i in self.guake.notebook.iter_terminals():
|
||||
|
||||
@ -64,8 +64,8 @@ from guake.globals import ALWAYS_ON_PRIMARY
|
||||
from guake.globals import NAME
|
||||
from guake.gsettings import GSettingHandler
|
||||
from guake.guake_logging import setupLogging
|
||||
from guake.guake_notebook import GuakeNotebook
|
||||
from guake.keybindings import Keybindings
|
||||
from guake.notebook import TerminalNotebook
|
||||
from guake.paths import LOCALE_DIR
|
||||
from guake.paths import SCHEMA_DIR
|
||||
from guake.paths import try_to_compile_glib_schemas
|
||||
@ -73,7 +73,7 @@ from guake.prefs import PrefsDialog
|
||||
from guake.prefs import refresh_user_start
|
||||
from guake.settings import Settings
|
||||
from guake.simplegladeapp import SimpleGladeApp
|
||||
from guake.terminal import GuakeTerminalBox
|
||||
from guake.terminal import GuakeTerminal
|
||||
from guake.theme import get_gtk_theme
|
||||
from guake.theme import select_gtk_theme
|
||||
from guake.utils import get_server_time
|
||||
@ -229,7 +229,7 @@ class Guake(SimpleGladeApp):
|
||||
self.window.set_keep_above(True)
|
||||
self.mainframe = self.get_widget('mainframe')
|
||||
self.mainframe.remove(self.get_widget('notebook-teminals'))
|
||||
self.notebook = GuakeNotebook()
|
||||
self.notebook = TerminalNotebook(self)
|
||||
self.notebook.set_name("notebook-teminals")
|
||||
|
||||
# help(Gtk.PositionType)
|
||||
@ -591,6 +591,7 @@ class Guake(SimpleGladeApp):
|
||||
log.debug("setting background color to: %r", fgcolor)
|
||||
page_num = self.notebook.get_current_page()
|
||||
terminal = self.notebook.get_nth_page(page_num).terminal
|
||||
# TODO this should be fgcolor right?
|
||||
terminal.set_color_foreground(bgcolor)
|
||||
# self.notebook.get_current_terminal().set_color_foreground(fgcolor)
|
||||
|
||||
@ -600,7 +601,7 @@ class Guake(SimpleGladeApp):
|
||||
tab. Command should end with '\n', otherwise it will be
|
||||
appended to the string.
|
||||
"""
|
||||
if not self.notebook.has_term():
|
||||
if not self.notebook.has_page():
|
||||
self.add_tab()
|
||||
|
||||
if command[-1] != '\n':
|
||||
@ -608,7 +609,7 @@ class Guake(SimpleGladeApp):
|
||||
|
||||
index = self.notebook.get_current_page()
|
||||
index = tab or self.notebook.get_current_page()
|
||||
for terminal in self.notebook.get_terminals_for_tab(index):
|
||||
for terminal in self.notebook.get_terminals_for_page(index):
|
||||
terminal.feed_child(command)
|
||||
break
|
||||
|
||||
@ -619,15 +620,14 @@ class Guake(SimpleGladeApp):
|
||||
command += '\n'
|
||||
try:
|
||||
tab_uuid = uuid.UUID(tab_uuid)
|
||||
tab_index, = (
|
||||
page_index, = (
|
||||
index for index, t in enumerate(self.notebook.iter_terminals())
|
||||
if t.get_uuid() == tab_uuid
|
||||
)
|
||||
self.tabs.get_children()[tab_index] # pylint: disable=expression-not-assigned
|
||||
except ValueError:
|
||||
pass
|
||||
else:
|
||||
terminals = self.notebook.get_terminals_for_tab(tab_index)
|
||||
terminals = self.notebook.get_terminals_for_page(page_index)
|
||||
for current_vte in terminals:
|
||||
current_vte.feed_child(command)
|
||||
|
||||
@ -797,7 +797,7 @@ class Guake(SimpleGladeApp):
|
||||
user_data is a Gtk.Label which is displayed in an eventbox in the clicked tab
|
||||
"""
|
||||
if event.button == 3:
|
||||
self.tab_context_menu_helper.show(event, self.notebook.get_tab_label_index(user_data))
|
||||
self.tab_context_menu_helper.show(event, self.notebook.find_tab_index_label(user_data))
|
||||
self.notebook.get_current_terminal().grab_focus()
|
||||
return True
|
||||
self.notebook.get_current_terminal().grab_focus()
|
||||
@ -808,7 +808,7 @@ class Guake(SimpleGladeApp):
|
||||
user_data is a Gtk.Label which is displayed in an eventbox in the clicked tab
|
||||
"""
|
||||
if event.button == 2 and event.type == Gdk.EventType.BUTTON_PRESS:
|
||||
self.delete_tab(self.notebook.get_tab_label_index(user_data))
|
||||
self.notebook.delete_page_by_label(user_data)
|
||||
|
||||
def show_about(self, *args):
|
||||
"""Hides the main window and creates an instance of the About
|
||||
@ -940,7 +940,7 @@ class Guake(SimpleGladeApp):
|
||||
|
||||
# add tab must be called before window.show to avoid a
|
||||
# blank screen before adding the tab.
|
||||
if not self.notebook.has_term():
|
||||
if not self.notebook.has_page():
|
||||
self.add_tab()
|
||||
|
||||
self.window.set_keep_below(False)
|
||||
@ -1289,8 +1289,8 @@ class Guake(SimpleGladeApp):
|
||||
def accel_quit(self, *args):
|
||||
"""Callback to prompt the user whether to quit Guake or not.
|
||||
"""
|
||||
procs = self.notebook.get_running_fg_processes()
|
||||
tabs = self.notebook.get_tab_count()
|
||||
procs = self.notebook.get_running_fg_processes_count()
|
||||
tabs = self.notebook.get_n_pages()
|
||||
prompt_cfg = self.settings.general.get_boolean('prompt-on-quit')
|
||||
prompt_tab_cfg = self.settings.general.get_int('prompt-on-close-tab')
|
||||
# "Prompt on tab close" config overrides "prompt on quit" config
|
||||
@ -1487,7 +1487,7 @@ class Guake(SimpleGladeApp):
|
||||
|
||||
# -- callbacks --
|
||||
|
||||
def on_terminal_exited(self, term, status, widget):
|
||||
def on_terminal_exited(self, term, status, term1):
|
||||
"""When a terminal is closed, shell process should be killed,
|
||||
this is the method that does that, or, at least calls
|
||||
`delete_tab' method to do the work.
|
||||
@ -1495,7 +1495,7 @@ class Guake(SimpleGladeApp):
|
||||
log.debug("Terminal exited: %s", term)
|
||||
if libutempter is not None:
|
||||
libutempter.utempter_remove_record(term.get_pty())
|
||||
self.delete_tab(self.notebook.page_num(widget), kill=False, prompt=False)
|
||||
self.delete_tab(self.notebook.find_page_index_for_terminal(term), kill=False, prompt=False)
|
||||
|
||||
def recompute_tabs_titles(self):
|
||||
"""Updates labels on all tabs. This is required when `self.abbreviate`
|
||||
@ -1507,7 +1507,7 @@ class Guake(SimpleGladeApp):
|
||||
|
||||
# TODO NOTEBOOK this code only works if there is only one terminal in a
|
||||
# page, this need to be rewritten
|
||||
for terminal in self.notebook.term_list:
|
||||
for terminal in self.notebook.iter_terminals():
|
||||
page_num = self.notebook.page_num(terminal.get_parent())
|
||||
self.rename_tab(page_num, self.compute_tab_title(terminal), False)
|
||||
|
||||
@ -1534,7 +1534,8 @@ class Guake(SimpleGladeApp):
|
||||
text = "..." + text[-max_name_length:]
|
||||
return text
|
||||
|
||||
def on_terminal_title_changed(self, vte, box):
|
||||
def on_terminal_title_changed(self, vte, term):
|
||||
box = term.get_parent()
|
||||
use_vte_titles = self.settings.general.get_boolean('use-vte-titles')
|
||||
if not use_vte_titles:
|
||||
return
|
||||
@ -1545,7 +1546,7 @@ class Guake(SimpleGladeApp):
|
||||
self.rename_tab(page_num, title, False)
|
||||
self.update_window_title(title)
|
||||
else:
|
||||
text = self.notebook.get_tab_label(page).get_children()[0].get_text()
|
||||
text = self.notebook.get_tab_text_page(page)
|
||||
if text:
|
||||
self.update_window_title(text)
|
||||
|
||||
@ -1601,9 +1602,10 @@ class Guake(SimpleGladeApp):
|
||||
"""Tab context menu close handler
|
||||
"""
|
||||
page_num = self.tab_context_menu_helper.last_invoked_on_tab_index
|
||||
self.delete_tab(page_num)
|
||||
self.notebook.delete_page(page_num)
|
||||
|
||||
def on_drag_data_received(self, widget, context, x, y, selection, target, timestamp, box):
|
||||
def on_drag_data_received(self, widget, context, x, y, selection, target, timestamp, term):
|
||||
box = term.get_parent()
|
||||
droppeduris = selection.get_uris()
|
||||
|
||||
# url-unquote the list, strip file:// schemes, handle .desktop-s
|
||||
@ -1643,8 +1645,8 @@ class Guake(SimpleGladeApp):
|
||||
def close_tab(self, *args):
|
||||
"""Closes the current tab.
|
||||
"""
|
||||
pagepos = self.notebook.get_current_page()
|
||||
self.delete_tab(pagepos)
|
||||
page_num = self.notebook.get_current_page()
|
||||
self.delete_page(page_num)
|
||||
|
||||
def rename_tab_uuid(self, term_uuid, new_text, user_set=True):
|
||||
"""Rename an already added tab by its UUID
|
||||
@ -1676,11 +1678,6 @@ class Guake(SimpleGladeApp):
|
||||
if user_set:
|
||||
setattr(page_box, "custom_label_set", new_text != "-")
|
||||
|
||||
# TODO TABS do we still need this, testing
|
||||
# terminals = self.notebook.get_terminals_for_tab(tab_index)
|
||||
# for current_vte in terminals:
|
||||
# current_vte.emit('window-title-changed')
|
||||
|
||||
def rename_current_tab(self, new_text, user_set=False):
|
||||
page_num = self.notebook.get_current_page()
|
||||
self.rename_tab(page_num, new_text, user_set)
|
||||
@ -1776,48 +1773,42 @@ class Guake(SimpleGladeApp):
|
||||
os.environ['https_proxy'] = "http://{!s}:{:d}".format(ssl_host, ssl_port)
|
||||
|
||||
def setup_new_terminal(self, directory=None):
|
||||
box = GuakeTerminalBox(self.window, self.settings)
|
||||
box.terminal.grab_focus()
|
||||
terminal = GuakeTerminal(self)
|
||||
terminal.grab_focus()
|
||||
|
||||
box.terminal.connect('button-press-event', self.show_context_menu)
|
||||
box.terminal.connect('child-exited', self.on_terminal_exited, box)
|
||||
box.terminal.connect('window-title-changed', self.on_terminal_title_changed, box)
|
||||
box.terminal.connect('drag-data-received', self.on_drag_data_received, box)
|
||||
terminal.connect('button-press-event', self.show_context_menu)
|
||||
terminal.connect('child-exited', self.on_terminal_exited, terminal)
|
||||
terminal.connect('window-title-changed', self.on_terminal_title_changed, terminal)
|
||||
terminal.connect('drag-data-received', self.on_drag_data_received, terminal)
|
||||
|
||||
# TODO PORT is this still the case with the newer vte version?
|
||||
# -- Ubuntu has a patch to libvte which disables mouse scrolling in apps
|
||||
# -- like vim and less by default. If this is the case, enable it back.
|
||||
if hasattr(box.terminal, "set_alternate_screen_scroll"):
|
||||
box.terminal.set_alternate_screen_scroll(True)
|
||||
if hasattr(terminal, "set_alternate_screen_scroll"):
|
||||
terminal.set_alternate_screen_scroll(True)
|
||||
|
||||
box.show()
|
||||
|
||||
pid = self.spawn_sync_pid(directory, box.terminal)
|
||||
pid = self.spawn_sync_pid(directory, terminal)
|
||||
|
||||
if libutempter is not None:
|
||||
libutempter.utempter_add_record(box.terminal.get_pty().get_fd(), os.uname()[1])
|
||||
box.terminal.pid = pid
|
||||
return box
|
||||
libutempter.utempter_add_record(terminal.get_pty().get_fd(), os.uname()[1])
|
||||
terminal.pid = pid
|
||||
return terminal
|
||||
|
||||
def add_tab(self, directory=None):
|
||||
"""Adds a new tab to the terminal notebook.
|
||||
"""
|
||||
box = self.setup_new_terminal(directory)
|
||||
# TODO NOTEBOOK
|
||||
|
||||
text = self.compute_tab_title(box.terminal)
|
||||
page_num = self.notebook.append_page(box, None)
|
||||
self.notebook.set_tab_reorderable(box, True)
|
||||
|
||||
self.notebook.append_tab(box.terminal)
|
||||
box, page_num = self.notebook.new_page()
|
||||
text = self.compute_tab_title(box.get_terminals()[0])
|
||||
self.notebook.set_current_page(page_num)
|
||||
self.rename_tab(page_num, text, False)
|
||||
box.terminal.grab_focus()
|
||||
self.load_config()
|
||||
|
||||
if self.is_fullscreen:
|
||||
self.fullscreen()
|
||||
|
||||
return str(box.terminal.get_uuid())
|
||||
return str(box.get_terminals()[0].get_uuid())
|
||||
|
||||
def save_tab(self, directory=None):
|
||||
self.preventHide = True
|
||||
@ -1903,22 +1894,22 @@ class Guake(SimpleGladeApp):
|
||||
# elif response_id == RESPONSE_BACKWARD:
|
||||
# buffer.search_backward(search_string, self)
|
||||
|
||||
def delete_tab(self, pagepos, kill=True, prompt=True):
|
||||
def delete_tab(self, page_num, kill=True, prompt=True):
|
||||
"""This function will destroy the notebook page, terminal and
|
||||
tab widgets and will call the function to kill interpreter
|
||||
forked by vte.
|
||||
"""
|
||||
# Run prompt if necessary
|
||||
if prompt:
|
||||
procs = self.notebook.get_running_fg_processes_tab(pagepos)
|
||||
procs = self.notebook.get_running_fg_processes_count_page(page_num)
|
||||
prompt_cfg = self.settings.general.get_int('prompt-on-close-tab')
|
||||
if (prompt_cfg == 1 and procs > 0) or (prompt_cfg == 2):
|
||||
if not self.run_quit_dialog(procs, -1):
|
||||
return
|
||||
|
||||
self.notebook.delete_tab(pagepos, kill=kill)
|
||||
self.notebook.delete_page(page_num, kill=kill)
|
||||
|
||||
if not self.notebook.has_term():
|
||||
if not self.notebook.has_page():
|
||||
self.hide()
|
||||
# avoiding the delay on next Guake show request
|
||||
self.add_tab()
|
||||
@ -1927,7 +1918,7 @@ class Guake(SimpleGladeApp):
|
||||
|
||||
self.was_deleted_tab = True
|
||||
abbreviate_tab_names = self.settings.general.get_boolean('abbreviate-tab-names')
|
||||
if abbreviate_tab_names and not self.is_tabs_scrollbar_visible():
|
||||
if abbreviate_tab_names:
|
||||
self.abbreviate = False
|
||||
self.recompute_tabs_titles()
|
||||
|
||||
@ -1935,13 +1926,12 @@ class Guake(SimpleGladeApp):
|
||||
"""Grabs the focus on the current tab.
|
||||
"""
|
||||
self.notebook.set_current_page(self.notebook.get_current_page())
|
||||
self.notebook.get_current_terminal().grab_focus()
|
||||
|
||||
def get_selected_uuidtab(self):
|
||||
"""Returns the uuid of the current selected terminal
|
||||
"""
|
||||
pagepos = self.notebook.get_current_page()
|
||||
terminals = self.notebook.get_terminals_for_tab(pagepos)
|
||||
page_num = self.notebook.get_current_page()
|
||||
terminals = self.notebook.get_terminals_for_page(page_num)
|
||||
return str(terminals[0].get_uuid())
|
||||
|
||||
def search_on_web(self, *args):
|
||||
|
||||
@ -1,121 +0,0 @@
|
||||
# -*- coding: utf-8; -*-
|
||||
"""
|
||||
Copyright (C) 2007-2013 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
|
||||
"""
|
||||
|
||||
import logging
|
||||
import posix
|
||||
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GuakeNotebook(Gtk.Notebook):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
Gtk.Notebook.__init__(self, *args, **kwargs)
|
||||
|
||||
# List of vte.Terminal widgets, it will be useful when needed
|
||||
# to get a widget by the current page in self.notebook
|
||||
self.term_list = []
|
||||
|
||||
# This is the pid of shells forked by each terminal. Will be
|
||||
# used to kill the process when closing a tab
|
||||
self.pid_list = []
|
||||
|
||||
def reorder_child(self, child, position):
|
||||
""" We should also reorder elements in term_list
|
||||
"""
|
||||
old_pos = self.get_children().index(child)
|
||||
self.term_list.insert(position, self.term_list.pop(old_pos))
|
||||
super(GuakeNotebook, self).reorder_child(child, position)
|
||||
|
||||
def has_term(self):
|
||||
return self.term_list
|
||||
|
||||
def get_tab_count(self):
|
||||
return len(self.term_list)
|
||||
|
||||
def get_terminals_for_tab(self, index):
|
||||
return [self.term_list[index]]
|
||||
|
||||
def get_current_terminal(self):
|
||||
if self.get_current_page() == -1:
|
||||
return None
|
||||
return self.term_list[self.get_current_page()]
|
||||
|
||||
def get_running_fg_processes(self):
|
||||
total_procs = 0
|
||||
for page_index in range(self.get_tab_count()):
|
||||
total_procs += self.get_running_fg_processes_tab(page_index)
|
||||
return total_procs
|
||||
|
||||
def get_running_fg_processes_tab(self, index):
|
||||
total_procs = 0
|
||||
for terminal in self.get_terminals_for_tab(index):
|
||||
|
||||
fdpty = terminal.get_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):
|
||||
total_procs += 1
|
||||
except OSError:
|
||||
log.debug(
|
||||
"Cannot retrieve any pid from terminal %s, looks like it is already dead", index
|
||||
)
|
||||
return 0
|
||||
return total_procs
|
||||
|
||||
def iter_terminals(self):
|
||||
for t in self.term_list:
|
||||
yield t
|
||||
|
||||
def delete_tab(self, pagepos, kill=True):
|
||||
for terminal in self.get_terminals_for_tab(pagepos):
|
||||
if kill:
|
||||
terminal.kill()
|
||||
|
||||
terminal.destroy()
|
||||
|
||||
self.remove_page(pagepos)
|
||||
self.term_list.pop(pagepos)
|
||||
|
||||
def append_tab(self, terminal):
|
||||
self.term_list.append(terminal)
|
||||
|
||||
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 get_tab_eventbox_index(self, eventbox):
|
||||
for index, tab_eventbox in enumerate(self.iter_tabs()):
|
||||
if eventbox is tab_eventbox:
|
||||
return index
|
||||
return -1
|
||||
|
||||
def get_tab_label_index(self, label):
|
||||
return self.get_tab_eventbox_index(label.get_parent())
|
||||
|
||||
def iter_pages(self):
|
||||
for page_num in range(self.get_n_pages()):
|
||||
yield self.get_nth_page(page_num)
|
||||
@ -27,7 +27,6 @@ from guake import notifier
|
||||
from guake.common import pixmapfile
|
||||
from locale import gettext as _
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
||||
143
guake/notebook.py
Normal file
143
guake/notebook.py
Normal file
@ -0,0 +1,143 @@
|
||||
# -*- 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 boxes import RootTerminalBox
|
||||
from boxes import TerminalBox
|
||||
from boxes import DualTerminalBox
|
||||
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
from guake.terminal import GuakeTerminal
|
||||
|
||||
import logging
|
||||
import posix
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class TerminalNotebook(Gtk.Notebook):
|
||||
|
||||
def __init__(self, guake, *args, **kwargs):
|
||||
Gtk.Notebook.__init__(self, *args, **kwargs)
|
||||
self.guake = guake
|
||||
|
||||
def get_focused_terminal(self):
|
||||
for terminal in self.iter_terminals():
|
||||
if terminal.has_focus():
|
||||
return terminal
|
||||
|
||||
def get_current_terminal(self):
|
||||
return self.get_focused_terminal()
|
||||
|
||||
def get_terminals_for_page(self, index):
|
||||
page = self.get_nth_page(index)
|
||||
return page.get_terminals()
|
||||
|
||||
def get_terminals(self, index):
|
||||
terminals = []
|
||||
for page in self.iter_pages():
|
||||
terminals += page.get_terminals()
|
||||
return terminals
|
||||
|
||||
def get_running_fg_processes_count(self):
|
||||
fg_proc_count = 0
|
||||
for page in self.iter_pages():
|
||||
fg_proc_count += self.get_running_fg_processes_count_page(self.page_num(page))
|
||||
return fg_proc_count
|
||||
|
||||
def get_running_fg_processes_count_page(self, index):
|
||||
total_procs = 0
|
||||
for terminal in self.get_terminals_for_page(index):
|
||||
fdpty = terminal.get_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):
|
||||
total_procs += 1
|
||||
except OSError:
|
||||
log.debug(
|
||||
"Cannot retrieve any pid from terminal %s, looks like it is already dead", index
|
||||
)
|
||||
return 0
|
||||
return total_procs
|
||||
|
||||
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:
|
||||
for t in page.iter_terminals():
|
||||
yield t
|
||||
|
||||
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):
|
||||
if page_num >= self.get_n_pages():
|
||||
log.debug("Can not delete page %s no such index", page_num)
|
||||
return
|
||||
for terminal in self.get_terminals_for_page(page_num):
|
||||
if kill:
|
||||
terminal.kill()
|
||||
terminal.destroy()
|
||||
self.remove_page(page_num)
|
||||
|
||||
def delete_page_by_label(self, label, kill=True):
|
||||
self.delete_page(self.find_tab_index_label(label), True)
|
||||
|
||||
def new_page(self):
|
||||
terminal_box = TerminalBox()
|
||||
terminal_box.set_terminal(self.guake.setup_new_terminal())
|
||||
root_terminal_box = RootTerminalBox(self.guake)
|
||||
root_terminal_box.set_child(terminal_box)
|
||||
page_num = self.append_page(root_terminal_box, None)
|
||||
self.set_tab_reorderable(root_terminal_box, True)
|
||||
self.show_all() # needed to show newly added tabs and pages
|
||||
return root_terminal_box, page_num
|
||||
|
||||
def find_tab_index_eventbox(self, eventbox):
|
||||
for index, tab_eventbox in enumerate(self.iter_tabs()):
|
||||
if eventbox is tab_eventbox:
|
||||
return index
|
||||
return -1
|
||||
|
||||
def find_tab_index_label(self, label):
|
||||
return self.find_tab_index_eventbox(label.get_parent())
|
||||
|
||||
def find_page_index_for_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_children()[0].get_text()
|
||||
|
||||
def get_tab_text_page(self, page):
|
||||
return self.get_tab_label(page).get_children()[0].get_text()
|
||||
@ -699,7 +699,13 @@ class PrefsDialog(SimpleGladeApp):
|
||||
column.add_attribute(renderer, "accel-key", 1)
|
||||
treeview.append_column(column)
|
||||
|
||||
self.demo_terminal = GuakeTerminal(self.window, self.settings)
|
||||
class fake_guake():
|
||||
pass
|
||||
|
||||
fg = fake_guake()
|
||||
fg.window = self.window
|
||||
fg.settings = self.settings
|
||||
self.demo_terminal = GuakeTerminal(fg)
|
||||
self.demo_terminal_box = self.get_widget('demo_terminal_box')
|
||||
self.demo_terminal_box.add(self.demo_terminal)
|
||||
|
||||
|
||||
@ -55,45 +55,19 @@ def halt(loc):
|
||||
code.interact(local=loc)
|
||||
|
||||
|
||||
__all__ = ['TerminalBox', 'GuakeTerminal', 'GuakeTerminalBox']
|
||||
__all__ = ['GuakeTerminal']
|
||||
|
||||
# pylint: enable=anomalous-backslash-in-string
|
||||
|
||||
|
||||
class TerminalBox(Gtk.HBox):
|
||||
"""A box to group the terminal and a scrollbar.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super(TerminalBox, self).__init__()
|
||||
self.terminal = Terminal()
|
||||
self.add_terminal()
|
||||
self.add_scrollbar()
|
||||
|
||||
def add_terminal(self):
|
||||
"""Packs the terminal widget.
|
||||
"""
|
||||
self.pack_start(self.terminal, True, True, 0)
|
||||
self.terminal.show()
|
||||
|
||||
def add_scrollbar(self):
|
||||
"""Packs the scrollbar.
|
||||
"""
|
||||
adj = self.terminal.get_vadjustment()
|
||||
scroll = Gtk.VScrollbar.new(adj)
|
||||
scroll.set_no_show_all(True)
|
||||
self.pack_start(scroll, False, False, 0)
|
||||
|
||||
|
||||
class GuakeTerminal(Vte.Terminal):
|
||||
|
||||
"""Just a vte.Terminal with some properties already set.
|
||||
"""
|
||||
|
||||
def __init__(self, window, settings):
|
||||
def __init__(self, guake):
|
||||
super(GuakeTerminal, self).__init__()
|
||||
self.window = window
|
||||
self.settings = settings
|
||||
self.guake = guake
|
||||
self.configure_terminal()
|
||||
self.add_matches()
|
||||
self.connect('button-press-event', self.button_press)
|
||||
@ -132,20 +106,20 @@ class GuakeTerminal(Vte.Terminal):
|
||||
if self.get_has_selection():
|
||||
super(GuakeTerminal, self).copy_clipboard()
|
||||
elif self.matched_value:
|
||||
guake_clipboard = Gtk.Clipboard.get_default(self.window.get_display())
|
||||
guake_clipboard = Gtk.Clipboard.get_default(self.guake.window.get_display())
|
||||
guake_clipboard.set_text(self.matched_value)
|
||||
|
||||
def configure_terminal(self):
|
||||
"""Sets all customized properties on the terminal
|
||||
"""
|
||||
client = self.settings.general
|
||||
client = self.guake.settings.general
|
||||
word_chars = client.get_string('word-chars')
|
||||
if word_chars:
|
||||
self.set_word_char_exceptions(word_chars)
|
||||
self.set_audible_bell(client.get_boolean('use-audible-bell'))
|
||||
self.set_sensitive(True)
|
||||
|
||||
cursor_blink_mode = self.settings.style.get_int('cursor-blink-mode')
|
||||
cursor_blink_mode = self.guake.settings.style.get_int('cursor-blink-mode')
|
||||
self.set_property('cursor-blink-mode', cursor_blink_mode)
|
||||
|
||||
if (Vte.MAJOR_VERSION, Vte.MINOR_VERSION) >= (0, 50):
|
||||
@ -309,7 +283,7 @@ class GuakeTerminal(Vte.Terminal):
|
||||
found_matcher = False
|
||||
log.debug("matched string: %s", matched_string)
|
||||
# First searching in additional matchers
|
||||
use_quick_open = self.settings.general.get_boolean("quick-open-enable")
|
||||
use_quick_open = self.guake.settings.general.get_boolean("quick-open-enable")
|
||||
if use_quick_open:
|
||||
found_matcher = self._find_quick_matcher(value)
|
||||
if not found_matcher:
|
||||
@ -341,7 +315,7 @@ class GuakeTerminal(Vte.Terminal):
|
||||
def _execute_quick_open(self, filepath, line_number):
|
||||
if not filepath:
|
||||
return
|
||||
cmdline = self.settings.general.get_string("quick-open-command-line")
|
||||
cmdline = self.guake.settings.general.get_string("quick-open-command-line")
|
||||
if not line_number:
|
||||
line_number = ""
|
||||
else:
|
||||
@ -349,7 +323,7 @@ class GuakeTerminal(Vte.Terminal):
|
||||
logging.debug("Opening file %s at line %s", filepath, line_number)
|
||||
resolved_cmdline = cmdline % {"file_path": filepath, "line_number": line_number}
|
||||
logging.debug("Command line: %s", resolved_cmdline)
|
||||
quick_open_in_current_terminal = self.settings.general.get_boolean(
|
||||
quick_open_in_current_terminal = self.guake.settings.general.get_boolean(
|
||||
"quick-open-in-current-terminal"
|
||||
)
|
||||
if quick_open_in_current_terminal:
|
||||
@ -453,29 +427,3 @@ class GuakeTerminal(Vte.Terminal):
|
||||
# if this part of code was reached, means that SIGTERM
|
||||
# did the work and SIGKILL wasnt needed.
|
||||
pass
|
||||
|
||||
|
||||
class GuakeTerminalBox(Gtk.Box):
|
||||
|
||||
"""A box to group the terminal and a scrollbar.
|
||||
"""
|
||||
|
||||
def __init__(self, window, settings):
|
||||
super(GuakeTerminalBox, self).__init__(orientation=Gtk.Orientation.HORIZONTAL)
|
||||
self.terminal = GuakeTerminal(window, settings)
|
||||
self.add_terminal()
|
||||
self.add_scroll_bar()
|
||||
|
||||
def add_terminal(self):
|
||||
"""Packs the terminal widget.
|
||||
"""
|
||||
self.pack_start(self.terminal, True, True, 0)
|
||||
self.terminal.show()
|
||||
|
||||
def add_scroll_bar(self):
|
||||
"""Packs the scrollbar.
|
||||
"""
|
||||
adj = self.terminal.get_vadjustment()
|
||||
scroll = Gtk.VScrollbar(adj)
|
||||
scroll.show()
|
||||
self.pack_start(scroll, False, False, 0)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user