mirror of
https://github.com/Guake/guake.git
synced 2025-10-26 11:27:13 +00:00
move add, remove, and delete page methods from guake_app to notebook
remove context menus from the glade file since the are edited in code anyways rewrite the contextmenus to support per terminal menus remove fullscreen logic from guake_app (to Fullscreenmanager in utils) remove proxy code since it was diabled since the gtk3 port and needs to be ported but there also no issues on GH currently move dialogs to dialogs.py move a lot of code (menus, dialogs, customcommands, themes) to its own files move terminal related code (like init) to the terminal class remove a bunch of dead code mark some methods as keybindings/dbusinterface only
This commit is contained in:
parent
03c486a835
commit
0834bad4d1
209
data/guake.glade
209
data/guake.glade
@ -2,215 +2,6 @@
|
||||
<!-- Generated with glade 3.18.3 -->
|
||||
<interface domain="guake">
|
||||
<requires lib="gtk+" version="3.10"/>
|
||||
<object class="GtkMenu" id="context-menu">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="context_copy">
|
||||
<property name="label" translatable="yes">Copy</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_stock">False</property>
|
||||
<signal name="activate" handler="accel_copy_clipboard" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="context_paste">
|
||||
<property name="label" translatable="yes">Paste</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_stock">False</property>
|
||||
<signal name="activate" handler="accel_paste_clipboard" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSeparatorMenuItem" id="separador5">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="context_toggle_fullscreen">
|
||||
<property name="label" translatable="yes">Toggle Fullscreen</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_stock">False</property>
|
||||
<signal name="activate" handler="accel_toggle_fullscreen" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSeparatorMenuItem" id="separador2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="context_save_tab">
|
||||
<property name="label" translatable="yes">Save to File...</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_stock">False</property>
|
||||
<signal name="activate" handler="save_tab" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="context_reset_terminal">
|
||||
<property name="label" translatable="yes">Reset terminal</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_stock">False</property>
|
||||
<signal name="activate" handler="reset_terminal" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="context_find_tab">
|
||||
<property name="label" translatable="yes">Find...</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_stock">False</property>
|
||||
<signal name="activate" handler="find_tab" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSeparatorMenuItem" id="separador3">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="context_add_tab">
|
||||
<property name="label" translatable="yes">New Tab</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_stock">False</property>
|
||||
<signal name="activate" handler="add_tab" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="context_rename_tab">
|
||||
<property name="label" translatable="yes">Rename Tab</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_stock">False</property>
|
||||
<signal name="activate" handler="accel_rename_current_tab" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="context_close_tab">
|
||||
<property name="label" translatable="yes">Close Tab</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_stock">False</property>
|
||||
<signal name="activate" handler="close_tab" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSeparatorMenuItem" id="separator_search">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="context_browse_on_web">
|
||||
<property name="label" translatable="yes">Open link...</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_stock">False</property>
|
||||
<signal name="activate" handler="browse_on_web" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="context_search_on_web">
|
||||
<property name="label" translatable="yes">Search on Web</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_stock">False</property>
|
||||
<signal name="activate" handler="search_on_web" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="context_quick_open">
|
||||
<property name="label" translatable="yes">Quick Open</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_stock">False</property>
|
||||
<signal name="activate" handler="quick_open" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSeparatorMenuItem" id="separador1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="context_preferences">
|
||||
<property name="label">gtk-preferences</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
<signal name="activate" handler="show_prefs" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="context_about">
|
||||
<property name="label">gtk-about</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
<signal name="activate" handler="show_about" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSeparatorMenuItem" id="separador4">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="context_close">
|
||||
<property name="label" translatable="yes">Quit</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_stock">False</property>
|
||||
<signal name="activate" handler="accel_quit" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkMenu" id="tab-menu">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="add">
|
||||
<property name="label" translatable="yes">New Tab</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_stock">False</property>
|
||||
<signal name="activate" handler="add_tab" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="rename">
|
||||
<property name="label" translatable="yes">Rename</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_stock">False</property>
|
||||
<signal name="activate" handler="on_rename_current_tab_activate" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="close">
|
||||
<property name="label" translatable="yes">Close</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_stock">False</property>
|
||||
<signal name="activate" handler="on_close_activate" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkMenu" id="tray-menu">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
|
||||
105
guake/boxes.py
105
guake/boxes.py
@ -1,6 +1,17 @@
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gdk
|
||||
from gi.repository import Gtk
|
||||
from guake.callbacks import TerminalContextMenuCallbacks
|
||||
from guake.dialogs import RenameDialog
|
||||
from guake.menus import TabContextMenu
|
||||
from guake.menus import TerminalContextMenu
|
||||
from guake.utils import TabNameUtils
|
||||
from locale import gettext as _
|
||||
gi.require_version('Vte', '2.91') # vte-0.42
|
||||
from gi.repository import Vte
|
||||
|
||||
# TODO remove calls to guake
|
||||
|
||||
|
||||
class TerminalHolder():
|
||||
@ -17,6 +28,12 @@ class TerminalHolder():
|
||||
def get_guake(self):
|
||||
pass
|
||||
|
||||
def get_window(self):
|
||||
pass
|
||||
|
||||
def get_settings(self):
|
||||
pass
|
||||
|
||||
def get_root_box(self):
|
||||
pass
|
||||
|
||||
@ -57,6 +74,12 @@ class RootTerminalBox(Gtk.Box, TerminalHolder):
|
||||
def get_guake(self):
|
||||
return self.guake
|
||||
|
||||
def get_window(self):
|
||||
return self.guake.window
|
||||
|
||||
def get_settings(self):
|
||||
return self.guake.settings
|
||||
|
||||
def get_root_box(self):
|
||||
return self
|
||||
|
||||
@ -81,6 +104,7 @@ class TerminalBox(Gtk.Box, TerminalHolder):
|
||||
raise RuntimeError("TerminalBox: terminal already set")
|
||||
self.terminal = terminal
|
||||
self.terminal.connect("focus", self.on_terminal_focus)
|
||||
self.terminal.connect("button-press-event", self.on_button_press, None)
|
||||
self.pack_start(self.terminal, True, True, 0)
|
||||
self.terminal.show()
|
||||
self.add_scroll_bar()
|
||||
@ -122,12 +146,38 @@ class TerminalBox(Gtk.Box, TerminalHolder):
|
||||
def get_guake(self):
|
||||
return self.get_parent().get_guake()
|
||||
|
||||
def get_window(self):
|
||||
return self.get_parent().get_window()
|
||||
|
||||
def get_settings(self):
|
||||
return self.get_parent().get_settings()
|
||||
|
||||
def get_root_box(self):
|
||||
return self.get_parent()
|
||||
|
||||
def on_terminal_focus(self, direction, user_data):
|
||||
self.get_root_box().set_last_terminal_focused(self.terminal)
|
||||
|
||||
def on_button_press(self, target, event, user_data):
|
||||
if event.button == 3:
|
||||
# First send to background process if handled, do nothing else
|
||||
if not event.get_state() & Gdk.ModifierType.SHIFT_MASK:
|
||||
if Vte.Terminal.do_button_press_event(self.terminal, event):
|
||||
return True
|
||||
|
||||
menu = TerminalContextMenu(
|
||||
self.terminal, self.get_window(), self.get_settings(),
|
||||
TerminalContextMenuCallbacks(
|
||||
self.terminal, self.get_window(), self.get_settings(),
|
||||
self.get_guake().notebook
|
||||
)
|
||||
)
|
||||
menu.popup_at_pointer(event)
|
||||
self.terminal.grab_focus()
|
||||
return True
|
||||
self.terminal.grab_focus()
|
||||
return False
|
||||
|
||||
|
||||
class DualTerminalBox(Gtk.Paned, TerminalHolder):
|
||||
|
||||
@ -172,5 +222,60 @@ class DualTerminalBox(Gtk.Paned, TerminalHolder):
|
||||
def get_guake(self):
|
||||
return self.get_parent().get_guake()
|
||||
|
||||
def get_window(self):
|
||||
return self.get_parent().get_window()
|
||||
|
||||
def get_settings(self):
|
||||
return self.get_parent().get_settings()
|
||||
|
||||
def get_root_box(self):
|
||||
return self.get_parent()
|
||||
|
||||
|
||||
class TabLabelEventBox(Gtk.EventBox):
|
||||
|
||||
def __init__(self, notebook, text):
|
||||
super().__init__()
|
||||
self.notebook = notebook
|
||||
self.label = Gtk.Label(text)
|
||||
self.add(self.label)
|
||||
self.connect("button-press-event", self.on_button_press, self.label)
|
||||
self.label.show()
|
||||
|
||||
def set_text(self, text):
|
||||
self.label.set_text(text)
|
||||
|
||||
def get_text(self):
|
||||
return self.label.get_text()
|
||||
|
||||
def on_button_press(self, target, event, user_data):
|
||||
if event.button == 3:
|
||||
menu = TabContextMenu(self)
|
||||
menu.popup_at_pointer(event)
|
||||
self.notebook.get_current_terminal().grab_focus()
|
||||
return True
|
||||
if event.button == 2:
|
||||
self.notebook.delete_page_by_label(self)
|
||||
return True
|
||||
|
||||
self.notebook.get_current_terminal().grab_focus()
|
||||
return False
|
||||
|
||||
def on_new_tab(self, user_data):
|
||||
self.notebook.new_page_with_focus()
|
||||
|
||||
def on_rename(self, user_data):
|
||||
self.notebook.guake.preventHide = True
|
||||
dialog = RenameDialog(self.notebook.guake.window, self.label.get_text())
|
||||
r = dialog.run()
|
||||
if r == Gtk.ResponseType.ACCEPT:
|
||||
new_text = TabNameUtils.shorten(dialog.get_text(), self.notebook.guake.settings)
|
||||
page_num = self.notebook.find_tab_index_by_label(self)
|
||||
self.notebook.rename_page(page_num, new_text, True)
|
||||
dialog.destroy()
|
||||
self.notebook.guake.preventHide = False
|
||||
# TODO
|
||||
# self.set_terminal_focus()
|
||||
|
||||
def on_close(self, user_data):
|
||||
self.notebook.delete_page_by_label(self)
|
||||
|
||||
89
guake/callbacks.py
Normal file
89
guake/callbacks.py
Normal file
@ -0,0 +1,89 @@
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
from guake.utils import FullscreenManager
|
||||
from guake.utils import TabNameUtils
|
||||
from guake.dialogs import RenameDialog
|
||||
from guake.dialogs import SaveTerminalDialog
|
||||
from guake.about import AboutDialog
|
||||
from guake.prefs import PrefsDialog
|
||||
from urllib.parse import quote_plus
|
||||
from guake.utils import get_server_time
|
||||
|
||||
|
||||
class TerminalContextMenuCallbacks():
|
||||
|
||||
def __init__(self, terminal, window, settings, notebook):
|
||||
self.terminal = terminal
|
||||
self.window = window
|
||||
self.settings = settings
|
||||
self.notebook = notebook
|
||||
|
||||
def on_copy_clipboard(self, *args):
|
||||
self.terminal.copy_clipboard()
|
||||
|
||||
def on_paste_clipboard(self, *args):
|
||||
self.terminal.paste_clipboard()
|
||||
|
||||
def on_toggle_fullscreen(self, *args):
|
||||
FullscreenManager(self.window).toggle()
|
||||
|
||||
def on_save_to_file(self, *args):
|
||||
SaveTerminalDialog(self.terminal, self.window).run()
|
||||
|
||||
def on_reset_terminal(self, *args):
|
||||
self.terminal.reset(True, True)
|
||||
|
||||
def on_find(self):
|
||||
# this is not implemented jet
|
||||
pass
|
||||
|
||||
def on_new_tab(self, *args):
|
||||
self.notebook.new_page_with_focus(
|
||||
directory=self.terminal.get_current_directory()
|
||||
)
|
||||
|
||||
def on_rename_tab(self, *args):
|
||||
page_num = self.notebook.find_page_index_by_terminal(self.terminal)
|
||||
tab_text = self.notebook.get_tab_text_index(page_num)
|
||||
dialog = RenameDialog(self.window, tab_text)
|
||||
r = dialog.run()
|
||||
if r == Gtk.ResponseType.ACCEPT:
|
||||
new_text = TabNameUtils.shorten(dialog.get_text(), self.settings)
|
||||
self.notebook.rename_page(page_num, new_text, True)
|
||||
dialog.destroy()
|
||||
|
||||
def on_close_tab(self, *args):
|
||||
page_num = self.notebook.find_page_index_by_terminal(self.terminal)
|
||||
self.notebook.delete_page(page_num, False, True)
|
||||
|
||||
def on_open_link(self, *args):
|
||||
self.terminal.browse_link_under_cursor()
|
||||
|
||||
def on_search_on_web(self, *args):
|
||||
if self.terminal.get_has_selection():
|
||||
self.terminal.copy_clipboard()
|
||||
clipboard = Gtk.Clipboard.get_default(self.window.get_display())
|
||||
query = clipboard.wait_for_text()
|
||||
query = quote_plus(query)
|
||||
if query:
|
||||
search_url = "https://www.google.com/#q={!s}&safe=off".format(query)
|
||||
Gtk.show_uri(self.window.get_screen(), search_url, get_server_time(self.window))
|
||||
|
||||
def on_quick_open(self, *args):
|
||||
if self.terminal.get_has_selection():
|
||||
self.terminal.quick_open()
|
||||
|
||||
def on_command_selected(self, command):
|
||||
self.terminal.execute_command(command)
|
||||
|
||||
def on_show_preferences(self, *args):
|
||||
self.notebook.guake.hide()
|
||||
PrefsDialog(self.settings).show()
|
||||
|
||||
def on_show_about(self, *args):
|
||||
self.notebook.guake.hide()
|
||||
AboutDialog()
|
||||
|
||||
def on_quit(self, *args):
|
||||
self.notebook.guake.accel_quit()
|
||||
82
guake/customcommands.py
Normal file
82
guake/customcommands.py
Normal file
@ -0,0 +1,82 @@
|
||||
import os
|
||||
import json
|
||||
|
||||
from locale import gettext as _
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
|
||||
class CustomCommands():
|
||||
"""
|
||||
Example for a custom commands file
|
||||
[
|
||||
{
|
||||
"type": "menu",
|
||||
"description": "dir listing",
|
||||
"items": [
|
||||
{
|
||||
"description": "la",
|
||||
"cmd":["ls", "-la"]
|
||||
},
|
||||
{
|
||||
"description": "tree",
|
||||
"cmd":["tree", ""]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "less ls",
|
||||
"cmd": ["ls | less", ""]
|
||||
}
|
||||
]
|
||||
"""
|
||||
|
||||
def __init__(self, settings, callback):
|
||||
self.settings = settings
|
||||
self.callback = callback
|
||||
|
||||
def should_load(self):
|
||||
file_path = self.settings.general.get_string('custom-command-file')
|
||||
return file_path is not None
|
||||
|
||||
def get_file_path(self):
|
||||
return os.path.expanduser(self.settings.general.get_string('custom-command-file'))
|
||||
|
||||
def _load_json(self, file_name):
|
||||
try:
|
||||
with open(file_name) as f:
|
||||
data_file = f.read()
|
||||
return json.loads(data_file)
|
||||
except Exception as e:
|
||||
log.exception("Invalid custom command file %s. Exception: %s", data_file, str(e))
|
||||
|
||||
def build_menu(self):
|
||||
if not self.should_load():
|
||||
return None
|
||||
menu = Gtk.Menu()
|
||||
for obj in self._load_json(self.get_file_path()):
|
||||
self._parse_custom_commands(obj, menu)
|
||||
return menu
|
||||
|
||||
def _parse_custom_commands(self, json_object, menu):
|
||||
if json_object.get('type') == "menu":
|
||||
newmenu = Gtk.Menu()
|
||||
newmenuitem = Gtk.MenuItem(json_object['description'])
|
||||
newmenuitem.set_submenu(newmenu)
|
||||
newmenuitem.show()
|
||||
menu.append(newmenuitem)
|
||||
for item in json_object['items']:
|
||||
self._parse_custom_commands(item, newmenu)
|
||||
else:
|
||||
menu_item = Gtk.MenuItem(json_object['description'])
|
||||
custom_command = ""
|
||||
space = ""
|
||||
for command in json_object['cmd']:
|
||||
custom_command += (space + command)
|
||||
space = " "
|
||||
menu_item.connect("activate", self.on_menu_item_activated, custom_command)
|
||||
menu.append(menu_item)
|
||||
menu_item.show()
|
||||
|
||||
def on_menu_item_activated(self, item, cmd):
|
||||
self.callback.on_command_selected(cmd)
|
||||
@ -76,11 +76,11 @@ class DbusManager(dbus.service.Object):
|
||||
|
||||
@dbus.service.method(DBUS_NAME, out_signature='i')
|
||||
def get_selected_tab(self):
|
||||
return self.guake.get_selected_tab()
|
||||
return self.guake.notebook.get_current_page()
|
||||
|
||||
@dbus.service.method(DBUS_NAME, out_signature='s')
|
||||
def get_selected_tablabel(self):
|
||||
return self.guake.get_selected_tablabel()
|
||||
return self.guake.notebook.get_tab_text_index(self.guake.notebook.get_current_page())
|
||||
|
||||
@dbus.service.method(DBUS_NAME, out_signature='i')
|
||||
def get_tab_count(self):
|
||||
@ -108,7 +108,7 @@ class DbusManager(dbus.service.Object):
|
||||
|
||||
@dbus.service.method(DBUS_NAME, in_signature='is')
|
||||
def rename_tab(self, tab_index, new_text):
|
||||
self.guake.rename_tab(tab_index, new_text, True)
|
||||
self.guake.notebook.rename_page(tab_index, new_text, True)
|
||||
|
||||
@dbus.service.method(DBUS_NAME, in_signature='s')
|
||||
def rename_current_tab(self, new_text):
|
||||
|
||||
127
guake/dialogs.py
Normal file
127
guake/dialogs.py
Normal file
@ -0,0 +1,127 @@
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
from locale import gettext as _
|
||||
|
||||
|
||||
class RenameDialog(Gtk.Dialog):
|
||||
|
||||
def __init__(self, window, current_name):
|
||||
super().__init__(
|
||||
_("Rename tab"), window,
|
||||
Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
|
||||
(Gtk.STOCK_CANCEL, Gtk.ResponseType.REJECT, Gtk.STOCK_OK, Gtk.ResponseType.ACCEPT)
|
||||
)
|
||||
self.entry = Gtk.Entry()
|
||||
self.entry.set_text(current_name)
|
||||
self.entry.set_property('can-default', True)
|
||||
self.entry.show()
|
||||
|
||||
vbox = Gtk.VBox()
|
||||
vbox.set_border_width(6)
|
||||
vbox.show()
|
||||
|
||||
self.set_size_request(300, -1)
|
||||
self.vbox.pack_start(vbox, True, True, 0)
|
||||
self.set_border_width(4)
|
||||
self.set_default_response(Gtk.ResponseType.ACCEPT)
|
||||
self.add_action_widget(self.entry, Gtk.ResponseType.ACCEPT)
|
||||
self.entry.reparent(vbox)
|
||||
|
||||
def get_text(self):
|
||||
return self.entry.get_text()
|
||||
|
||||
class PromptQuitDialog(Gtk.MessageDialog):
|
||||
|
||||
"""Prompts the user whether to quit/close a tab.
|
||||
"""
|
||||
|
||||
def __init__(self, parent, procs, tabs):
|
||||
super(PromptQuitDialog, self).__init__(
|
||||
parent, Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
|
||||
Gtk.MessageType.QUESTION, Gtk.ButtonsType.YES_NO
|
||||
)
|
||||
|
||||
if tabs == -1:
|
||||
primary_msg = _("Do you want to close the tab?")
|
||||
tab_str = ''
|
||||
else:
|
||||
primary_msg = _("Do you really want to quit Guake?")
|
||||
if tabs == 1:
|
||||
tab_str = _(" and one tab open")
|
||||
else:
|
||||
tab_str = _(" and {0} tabs open").format(tabs)
|
||||
|
||||
if procs == 0:
|
||||
proc_str = _("There are no processes running")
|
||||
elif procs == 1:
|
||||
proc_str = _("There is a process still running")
|
||||
else:
|
||||
proc_str = _("There are {0} processes still running").format(procs)
|
||||
|
||||
self.set_markup(primary_msg)
|
||||
self.format_secondary_markup("<b>{0}{1}.</b>".format(proc_str, tab_str))
|
||||
|
||||
def quit(self):
|
||||
"""Run the "are you sure" dialog for quitting Guake
|
||||
"""
|
||||
# Stop an open "close tab" dialog from obstructing a quit
|
||||
response = self.run() == Gtk.ResponseType.YES
|
||||
self.destroy()
|
||||
# Keep Guake focussed after dismissing tab-close prompt
|
||||
# if tab == -1:
|
||||
# self.window.present()
|
||||
return response
|
||||
|
||||
def close_tab(self):
|
||||
response = self.run() == Gtk.ResponseType.YES
|
||||
self.destroy()
|
||||
# Keep Guake focussed after dismissing tab-close prompt
|
||||
# if tab == -1:
|
||||
# self.window.present()
|
||||
return response
|
||||
|
||||
class SaveTerminalDialog(Gtk.FileChooserDialog):
|
||||
|
||||
def __init__(self, terminal, window):
|
||||
super().__init__(
|
||||
_("Save to..."),
|
||||
window,
|
||||
Gtk.FileChooserAction.SAVE,
|
||||
(
|
||||
Gtk.STOCK_CANCEL,
|
||||
Gtk.ResponseType.CANCEL,
|
||||
Gtk.STOCK_SAVE,
|
||||
Gtk.ResponseType.OK
|
||||
)
|
||||
)
|
||||
self.set_default_response(Gtk.ResponseType.OK)
|
||||
self.terminal = terminal
|
||||
self.parent_window = window
|
||||
|
||||
def run(self):
|
||||
self.terminal.select_all()
|
||||
self.terminal.copy_clipboard()
|
||||
self.terminal.unselect_all()
|
||||
clipboard = Gtk.Clipboard.get_default(self.parent_window.get_display())
|
||||
selection = clipboard.wait_for_text()
|
||||
if not selection:
|
||||
return
|
||||
selection = selection.rstrip()
|
||||
filter = Gtk.FileFilter()
|
||||
filter.set_name(_("All files"))
|
||||
filter.add_pattern("*")
|
||||
self.add_filter(filter)
|
||||
|
||||
filter = Gtk.FileFilter()
|
||||
filter.set_name(_("Text and Logs"))
|
||||
filter.add_pattern("*.log")
|
||||
filter.add_pattern("*.txt")
|
||||
self.add_filter(filter)
|
||||
|
||||
response = super().run()
|
||||
if response == Gtk.ResponseType.OK:
|
||||
filename = self.get_filename()
|
||||
with open(filename, "w") as f:
|
||||
f.write(selection)
|
||||
self.destroy()
|
||||
File diff suppressed because it is too large
Load Diff
@ -104,7 +104,6 @@ class Keybindings():
|
||||
self.guake.window.remove_accel_group(self.accel_group)
|
||||
self.accel_group = Gtk.AccelGroup()
|
||||
self.guake.window.add_accel_group(self.accel_group)
|
||||
self.guake.context_menu.set_accel_group(self.accel_group)
|
||||
self.load_accelerators()
|
||||
|
||||
def load_accelerators(self):
|
||||
@ -132,7 +131,9 @@ class Keybindings():
|
||||
|
||||
key, mask = Gtk.accelerator_parse(getk('close-tab'))
|
||||
if key > 0:
|
||||
self.accel_group.connect(key, mask, Gtk.AccelFlags.VISIBLE, self.guake.close_tab)
|
||||
self.accel_group.connect(
|
||||
key, mask, Gtk.AccelFlags.VISIBLE, self.guake.notebook.delete_page_current
|
||||
)
|
||||
|
||||
key, mask = Gtk.accelerator_parse(getk('previous-tab'))
|
||||
if key > 0:
|
||||
|
||||
163
guake/menus.py
Normal file
163
guake/menus.py
Normal file
@ -0,0 +1,163 @@
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
from locale import gettext as _
|
||||
gi.require_version('Vte', '2.91') # vte-0.42
|
||||
from gi.repository import Vte
|
||||
from guake.customcommands import CustomCommands
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def TabContextMenu(callback_object):
|
||||
"""Create the context menu for a notebook tab
|
||||
"""
|
||||
menu = Gtk.Menu()
|
||||
mi1 = Gtk.MenuItem(_("New Tab"))
|
||||
mi1.connect("activate", callback_object.on_new_tab)
|
||||
menu.add(mi1)
|
||||
mi2 = Gtk.MenuItem(_("Rename"))
|
||||
mi2.connect("activate", callback_object.on_rename)
|
||||
menu.add(mi2)
|
||||
mi3 = Gtk.MenuItem(_("Close"))
|
||||
mi3.connect("activate", callback_object.on_close)
|
||||
menu.add(mi3)
|
||||
menu.show_all()
|
||||
return menu
|
||||
|
||||
|
||||
SEARCH_SELECTION_LENGTH = 20
|
||||
FILE_SELECTION_LENGTH = 30
|
||||
|
||||
def TerminalContextMenu(terminal, window, settings, callback_object):
|
||||
"""Create the context menu for a terminal
|
||||
"""
|
||||
menu = Gtk.Menu()
|
||||
mi = Gtk.MenuItem(_("Copy"))
|
||||
mi.connect("activate", callback_object.on_copy_clipboard)
|
||||
menu.add(mi)
|
||||
mi = Gtk.MenuItem(_("Paste"))
|
||||
mi.connect("activate", callback_object.on_paste_clipboard)
|
||||
# check if clipboard has text, if not disable the paste menuitem
|
||||
clipboard = Gtk.Clipboard.get_default(window.get_display())
|
||||
mi.set_sensitive(clipboard.wait_is_text_available())
|
||||
menu.add(mi)
|
||||
menu.add(Gtk.SeparatorMenuItem())
|
||||
mi = Gtk.MenuItem(_("Toggle Fullscreen"))
|
||||
mi.connect("activate", callback_object.on_toggle_fullscreen)
|
||||
menu.add(mi)
|
||||
menu.add(Gtk.SeparatorMenuItem())
|
||||
mi = Gtk.MenuItem(_("Save to File..."))
|
||||
mi.connect("activate", callback_object.on_save_to_file)
|
||||
menu.add(mi)
|
||||
mi = Gtk.MenuItem(_("Reset terminal"))
|
||||
mi.connect("activate", callback_object.on_reset_terminal)
|
||||
menu.add(mi)
|
||||
# TODO SEARCH uncomment menu.add()
|
||||
mi = Gtk.MenuItem(_("Find..."))
|
||||
mi.connect("activate", callback_object.on_find)
|
||||
# menu.add(mi)
|
||||
menu.add(Gtk.SeparatorMenuItem())
|
||||
mi = Gtk.MenuItem(_("New Tab"))
|
||||
mi.connect("activate", callback_object.on_new_tab)
|
||||
menu.add(mi)
|
||||
mi = Gtk.MenuItem(_("Rename Tab"))
|
||||
mi.connect("activate", callback_object.on_rename_tab)
|
||||
menu.add(mi)
|
||||
mi = Gtk.MenuItem(_("Close Tab"))
|
||||
mi.connect("activate", callback_object.on_close_tab)
|
||||
menu.add(mi)
|
||||
menu.add(Gtk.SeparatorMenuItem())
|
||||
mi = Gtk.MenuItem(_("Open link..."))
|
||||
mi.connect("activate", callback_object.on_open_link)
|
||||
link = get_link_under_cursor(terminal)
|
||||
# TODO CONTEXTMENU this is a mess Quick open should also be sensible
|
||||
# if the text in the selection is a url the current terminal
|
||||
# implementation does not support this at the moment
|
||||
if link:
|
||||
if len(link) >= FILE_SELECTION_LENGTH:
|
||||
mi.set_label(_("Open Link: {!s}...").format(link[:FILE_SELECTION_LENGTH-3]))
|
||||
else:
|
||||
mi.set_label(_("Open Link: {!s}").format(link))
|
||||
mi.set_sensitive(True)
|
||||
else:
|
||||
mi.set_sensitive(False)
|
||||
menu.add(mi)
|
||||
mi = Gtk.MenuItem(_("Search on Web"))
|
||||
mi.connect("activate", callback_object.on_search_on_web)
|
||||
selection = get_current_selection(terminal, window)
|
||||
if selection:
|
||||
search_text = selection.rstrip()
|
||||
if len(search_text) > SEARCH_SELECTION_LENGTH:
|
||||
search_text = search_text[:SEARCH_SELECTION_LENGTH-3] + "..."
|
||||
mi.set_label(_("Search on Web: '%s'") % search_text)
|
||||
mi.set_sensitive(True)
|
||||
else:
|
||||
mi.set_sensitive(False)
|
||||
menu.add(mi)
|
||||
mi = Gtk.MenuItem(_("Quick Open..."))
|
||||
mi.connect("activate", callback_object.on_quick_open)
|
||||
if selection:
|
||||
filename = get_filename_under_cursor(terminal, selection)
|
||||
if filename:
|
||||
filename_str = str(filename)
|
||||
if len(filename_str) > FILE_SELECTION_LENGTH:
|
||||
mi.set_label(
|
||||
_("Quick Open: {!s}...").format(
|
||||
filename_str[:FILE_SELECTION_LENGTH-3]
|
||||
)
|
||||
)
|
||||
else:
|
||||
mi.set_label(_("Quick Open: {!s}").format(filename_str))
|
||||
mi.set_sensitive(True)
|
||||
else:
|
||||
mi.set_sensitive(False)
|
||||
else:
|
||||
mi.set_sensitive(False)
|
||||
menu.add(mi)
|
||||
customcommands = CustomCommands(settings, callback_object)
|
||||
if customcommands.should_load():
|
||||
menu.add(Gtk.SeparatorMenuItem())
|
||||
mi = Gtk.MenuItem(_("Custom Commands"))
|
||||
mi.set_submenu(customcommands.build_menu())
|
||||
menu.add(mi)
|
||||
menu.add(Gtk.SeparatorMenuItem())
|
||||
mi = Gtk.ImageMenuItem("gtk-preferences")
|
||||
mi.set_use_stock(True)
|
||||
mi.connect("activate", callback_object.on_show_preferences)
|
||||
menu.add(mi)
|
||||
mi = Gtk.ImageMenuItem("gtk-about")
|
||||
mi.set_use_stock(True)
|
||||
mi.connect("activate", callback_object.on_show_about)
|
||||
menu.add(mi)
|
||||
menu.add(Gtk.SeparatorMenuItem())
|
||||
mi = Gtk.ImageMenuItem(_("Quit"))
|
||||
mi.connect("activate", callback_object.on_quit)
|
||||
menu.add(mi)
|
||||
menu.show_all()
|
||||
return menu
|
||||
|
||||
|
||||
def get_current_selection(terminal, window):
|
||||
if terminal.get_has_selection():
|
||||
terminal.copy_clipboard()
|
||||
clipboard = Gtk.Clipboard.get_default(window.get_display())
|
||||
return clipboard.wait_for_text()
|
||||
return None
|
||||
|
||||
|
||||
def get_filename_under_cursor(terminal, selection):
|
||||
filename, _1, _2 = terminal.is_file_on_local_server(selection)
|
||||
log.info("Current filename under cursor: %s", filename)
|
||||
if filename:
|
||||
return filename
|
||||
return None
|
||||
|
||||
|
||||
def get_link_under_cursor(terminal):
|
||||
link = terminal.found_link
|
||||
log.info("Current link under cursor: %s", link)
|
||||
if link:
|
||||
return link
|
||||
return None
|
||||
@ -20,12 +20,17 @@ Boston, MA 02110-1301 USA
|
||||
|
||||
from guake.boxes import DualTerminalBox
|
||||
from guake.boxes import RootTerminalBox
|
||||
from guake.boxes import TabLabelEventBox
|
||||
from guake.boxes import TerminalBox
|
||||
from guake.dialogs import PromptQuitDialog
|
||||
|
||||
import gi
|
||||
import os
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import GObject
|
||||
from gi.repository import Gtk
|
||||
from guake.terminal import GuakeTerminal
|
||||
from locale import gettext as _
|
||||
|
||||
import logging
|
||||
import posix
|
||||
@ -40,6 +45,24 @@ class TerminalNotebook(Gtk.Notebook):
|
||||
self.guake = guake
|
||||
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)
|
||||
|
||||
GObject.signal_new(
|
||||
'terminal-spawned', self, GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE,
|
||||
(GObject.TYPE_PYOBJECT, GObject.TYPE_INT)
|
||||
)
|
||||
GObject.signal_new('page-deleted', self, GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE, ())
|
||||
|
||||
def set_last_terminal_focused(self, terminal):
|
||||
self.last_terminal_focused = terminal
|
||||
|
||||
@ -103,21 +126,48 @@ class TerminalNotebook(Gtk.Notebook):
|
||||
for page_num in range(self.get_n_pages()):
|
||||
yield self.get_nth_page(page_num)
|
||||
|
||||
def delete_page(self, page_num, kill=True):
|
||||
def delete_page(self, page_num, kill=True, prompt=False):
|
||||
if page_num >= self.get_n_pages():
|
||||
log.debug("Can not delete page %s no such index", page_num)
|
||||
return
|
||||
# TODO NOTEBOOK it would be nice if none of the "ui" stuff
|
||||
# (PromptQuitDialog) would be in here
|
||||
if prompt:
|
||||
procs = self.get_running_fg_processes_count_page(page_num)
|
||||
# TODO NOTEBOOK remove call to guake
|
||||
prompt_cfg = self.guake.settings.general.get_int('prompt-on-close-tab')
|
||||
if (prompt_cfg == 1 and procs > 0) or (prompt_cfg == 2):
|
||||
if not PromptQuitDialog(self.guake.window, procs, -1).close_tab():
|
||||
return
|
||||
|
||||
for terminal in self.get_terminals_for_page(page_num):
|
||||
if kill:
|
||||
terminal.kill()
|
||||
terminal.destroy()
|
||||
self.remove_page(page_num)
|
||||
self.emit('page-deleted')
|
||||
|
||||
def delete_page_by_label(self, label, kill=True):
|
||||
self.delete_page(self.find_tab_index_label(label), True)
|
||||
self.delete_page(self.find_tab_index_by_label(label), kill)
|
||||
|
||||
def delete_page_current(self, kill=True):
|
||||
self.delete_page(self.get_current_page(), kill)
|
||||
|
||||
def new_page(self, directory=None):
|
||||
terminal = GuakeTerminal(self.guake)
|
||||
terminal.grab_focus()
|
||||
if not isinstance(directory, str):
|
||||
directory = os.environ['HOME']
|
||||
try:
|
||||
if self.guake.settings.general.get_boolean('open-tab-cwd'):
|
||||
active_terminal = self.get_current_terminal()
|
||||
if not active_terminal:
|
||||
directory = os.path.expanduser('~')
|
||||
directory = active_terminal.get_current_directory()
|
||||
except: # pylint: disable=bare-except
|
||||
pass
|
||||
terminal.spawn_sync_pid(directory)
|
||||
|
||||
def new_page(self):
|
||||
terminal = self.guake.setup_new_terminal()
|
||||
terminal_box = TerminalBox()
|
||||
terminal_box.set_terminal(terminal)
|
||||
root_terminal_box = RootTerminalBox(self.guake)
|
||||
@ -128,18 +178,37 @@ class TerminalNotebook(Gtk.Notebook):
|
||||
# this is needed to initially set the last_terminal_focused,
|
||||
# one could also call terminal.get_parent().on_terminal_focus()
|
||||
terminal.emit("focus", Gtk.DirectionType.TAB_FORWARD)
|
||||
return root_terminal_box, page_num
|
||||
self.emit('terminal-spawned', terminal, terminal.pid)
|
||||
return root_terminal_box, page_num, terminal
|
||||
|
||||
def find_tab_index_eventbox(self, eventbox):
|
||||
def new_page_with_focus(self, directory=None):
|
||||
box, page_num, terminal = self.new_page()
|
||||
self.set_current_page(page_num)
|
||||
self.rename_page(page_num, _("Terminal"), False)
|
||||
terminal.grab_focus()
|
||||
|
||||
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:
|
||||
self.set_tab_label(page, TabLabelEventBox(self, new_text))
|
||||
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_tab_index_label(self, label):
|
||||
return self.find_tab_index_eventbox(label.get_parent())
|
||||
|
||||
def find_page_index_for_terminal(self, terminal):
|
||||
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:
|
||||
@ -147,7 +216,7 @@ class TerminalNotebook(Gtk.Notebook):
|
||||
return -1
|
||||
|
||||
def get_tab_text_index(self, index):
|
||||
return self.get_tab_label(self.get_nth_page(index)).get_children()[0].get_text()
|
||||
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_children()[0].get_text()
|
||||
return self.get_tab_label(page).get_text()
|
||||
|
||||
@ -50,6 +50,30 @@ from guake.globals import TERMINAL_MATCH_TAGS
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
libutempter = None
|
||||
try:
|
||||
# this allow to run some commands that requires libuterm to
|
||||
# be injected in current process, as: wall
|
||||
from atexit import register as at_exit_call
|
||||
from ctypes import cdll
|
||||
libutempter = cdll.LoadLibrary('libutempter.so.0')
|
||||
if libutempter is not None:
|
||||
# We absolutely need to remove the old tty from the utmp !!!
|
||||
at_exit_call(libutempter.utempter_remove_added_record)
|
||||
except Exception as e:
|
||||
libutempter = None
|
||||
sys.stderr.write("[WARN] ===================================================================\n")
|
||||
sys.stderr.write("[WARN] Unable to load the library libutempter !\n")
|
||||
sys.stderr.write(
|
||||
"[WARN] Some feature might not work:\n"
|
||||
"[WARN] - 'exit' command might freeze the terminal instead of closing the tab\n"
|
||||
"[WARN] - the 'wall' command is know to work badly\n"
|
||||
)
|
||||
sys.stderr.write("[WARN] Error: " + str(e) + '\n')
|
||||
sys.stderr.write(
|
||||
"[WARN] ===================================================================²\n"
|
||||
)
|
||||
|
||||
|
||||
def halt(loc):
|
||||
code.interact(local=loc)
|
||||
@ -71,6 +95,8 @@ class GuakeTerminal(Vte.Terminal):
|
||||
self.configure_terminal()
|
||||
self.add_matches()
|
||||
self.connect('button-press-event', self.button_press)
|
||||
self.connect('button-press-event', self.button_press)
|
||||
self.connect('child-exited', self.on_child_exited)
|
||||
self.matched_value = ''
|
||||
self.font_scale_index = 0
|
||||
self._pid = None
|
||||
@ -102,6 +128,11 @@ class GuakeTerminal(Vte.Terminal):
|
||||
else:
|
||||
super().feed_child(resolved_cmdline, len(resolved_cmdline))
|
||||
|
||||
def execute_command(self, command):
|
||||
if command[-1] != '\n':
|
||||
command += "\n"
|
||||
self.feed_child(command)
|
||||
|
||||
def copy_clipboard(self):
|
||||
if self.get_has_selection():
|
||||
super(GuakeTerminal, self).copy_clipboard()
|
||||
@ -125,6 +156,12 @@ class GuakeTerminal(Vte.Terminal):
|
||||
if (Vte.MAJOR_VERSION, Vte.MINOR_VERSION) >= (0, 50):
|
||||
self.set_allow_hyperlink(True)
|
||||
|
||||
# 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(self, "set_alternate_screen_scroll"):
|
||||
self.set_alternate_screen_scroll(True)
|
||||
|
||||
self.set_can_default(True)
|
||||
self.set_can_focus(True)
|
||||
|
||||
@ -269,6 +306,10 @@ class GuakeTerminal(Vte.Terminal):
|
||||
self.found_link = self.handleTerminalMatch(matched_string)
|
||||
self.matched_value = matched_string[0]
|
||||
|
||||
def on_child_exited(self, target, status, *user_data):
|
||||
if libutempter is not None:
|
||||
libutempter.utempter_remove_record(self.get_pty())
|
||||
|
||||
def quick_open(self):
|
||||
self.copy_clipboard()
|
||||
clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
|
||||
@ -427,3 +468,35 @@ class GuakeTerminal(Vte.Terminal):
|
||||
# if this part of code was reached, means that SIGTERM
|
||||
# did the work and SIGKILL wasnt needed.
|
||||
pass
|
||||
|
||||
def spawn_sync_pid(self, directory):
|
||||
|
||||
argv = list()
|
||||
user_shell = self.guake.settings.general.get_string('default-shell')
|
||||
if user_shell and os.path.exists(user_shell):
|
||||
argv.append(user_shell)
|
||||
else:
|
||||
argv.append(os.environ['SHELL'])
|
||||
|
||||
login_shell = self.guake.settings.general.get_boolean('use-login-shell')
|
||||
if login_shell:
|
||||
argv.append('--login')
|
||||
|
||||
pid = self.spawn_sync(
|
||||
Vte.PtyFlags.DEFAULT, directory, argv, [], GLib.SpawnFlags.DO_NOT_REAP_CHILD, None,
|
||||
None, None
|
||||
)
|
||||
try:
|
||||
tuple_type = gi._gi.ResultTuple # pylint: disable=c-extension-no-member
|
||||
except: # pylint: disable=bare-except
|
||||
tuple_type = tuple
|
||||
if isinstance(pid, (tuple, tuple_type)):
|
||||
# Return a tuple in 2.91
|
||||
# https://lazka.github.io/pgi-docs/Vte-2.91/classes/Terminal.html#Vte.Terminal.spawn_sync
|
||||
pid = pid[1]
|
||||
assert isinstance(pid, int)
|
||||
|
||||
if libutempter is not None:
|
||||
libutempter.utempter_add_record(self.get_pty().get_fd(), os.uname()[1])
|
||||
self.pid = pid
|
||||
return pid
|
||||
|
||||
@ -8,6 +8,9 @@ import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import GLib
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import Gdk
|
||||
from textwrap import dedent
|
||||
|
||||
|
||||
from guake.paths import GUAKE_THEME_DIR
|
||||
|
||||
@ -58,3 +61,44 @@ def get_gtk_theme(settings):
|
||||
gtk_theme_name = settings.general.get_string('gtk-theme-name')
|
||||
prefer_dark_theme = settings.general.get_boolean('gtk-prefer-dark-theme')
|
||||
return (gtk_theme_name, "dark" if prefer_dark_theme else None)
|
||||
|
||||
def patch_gtk_theme(style_context, settings):
|
||||
theme_name, variant = get_gtk_theme(settings)
|
||||
|
||||
def rgba_to_hex(color):
|
||||
return "#{0:02x}{1:02x}{2:02x}".format(
|
||||
int(color.red * 255), int(color.green * 255), int(color.blue * 255)
|
||||
)
|
||||
|
||||
# for n in [
|
||||
# "inverted_bg_color",
|
||||
# "inverted_fg_color",
|
||||
# "selected_bg_color",
|
||||
# "selected_fg_color",
|
||||
# "theme_inverted_bg_color",
|
||||
# "theme_inverted_fg_color",
|
||||
# "theme_selected_bg_color",
|
||||
# "theme_selected_fg_color",
|
||||
# ]:
|
||||
# s = style_context.lookup_color(n)
|
||||
# print(n, s, rgba_to_hex(s[1]))
|
||||
selected_fg_color = rgba_to_hex(style_context.lookup_color("theme_selected_fg_color")[1])
|
||||
selected_bg_color = rgba_to_hex(style_context.lookup_color("theme_selected_bg_color")[1])
|
||||
log.debug(
|
||||
"Patching theme '%s' (prefer dark = '%r'), overriding tab 'checked' state': "
|
||||
"foreground: %r, background: %r", theme_name, "yes"
|
||||
if variant == "dark" else "no", selected_fg_color, selected_bg_color
|
||||
)
|
||||
css_data = dedent(
|
||||
"""
|
||||
.custom_tab:checked {{
|
||||
color: {selected_fg_color};
|
||||
background: {selected_bg_color};
|
||||
}}
|
||||
""".format(selected_bg_color=selected_bg_color, selected_fg_color=selected_fg_color)
|
||||
).encode()
|
||||
style_provider = Gtk.CssProvider()
|
||||
style_provider.load_from_data(css_data)
|
||||
Gtk.StyleContext.add_provider_for_screen(
|
||||
Gdk.Screen.get_default(), style_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
|
||||
)
|
||||
|
||||
@ -35,3 +35,40 @@ def get_server_time(widget):
|
||||
# Use local timestamp instead
|
||||
ts = time.time()
|
||||
return ts
|
||||
|
||||
class TabNameUtils():
|
||||
@classmethod
|
||||
def shorten(cls, text, settings):
|
||||
use_vte_titles = settings.general.get_boolean('use-vte-titles')
|
||||
if not use_vte_titles:
|
||||
return text
|
||||
max_name_length = settings.general.get_int("max-tab-name-length")
|
||||
if max_name_length != 0 and len(text) > max_name_length:
|
||||
text = "..." + text[-max_name_length:]
|
||||
return text
|
||||
|
||||
class FullscreenManager():
|
||||
|
||||
def __init__(self, window):
|
||||
self.window = window
|
||||
self.is_in_fullscreen = False
|
||||
|
||||
def is_fullscreen(self):
|
||||
return getattr(self.window, 'is_fullscreen', False)
|
||||
|
||||
def fullscreen(self):
|
||||
self.window.fullscreen()
|
||||
setattr(self.window, 'is_fullscreen', True)
|
||||
|
||||
def unfullscreen(self):
|
||||
# TODO do we still need this fix with gtk3?
|
||||
# Fixes "Guake cannot restore from fullscreen" (#628)
|
||||
self.window.unmaximize()
|
||||
self.window.unfullscreen()
|
||||
setattr(self.window, 'is_fullscreen', False)
|
||||
|
||||
def toggle(self):
|
||||
if self.is_fullscreen():
|
||||
self.unfullscreen()
|
||||
else:
|
||||
self.fullscreen()
|
||||
|
||||
Loading…
Reference in New Issue
Block a user