mirror of
https://github.com/Guake/guake.git
synced 2025-10-26 11:27:13 +00:00
289 lines
11 KiB
Python
289 lines
11 KiB
Python
# -*- 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
|
|
|
|
from collections import defaultdict
|
|
|
|
import gi
|
|
|
|
gi.require_version("Gtk", "3.0")
|
|
from gi.repository import Gdk
|
|
from gi.repository import Gtk
|
|
|
|
from guake import notifier
|
|
from guake.common import pixmapfile
|
|
from guake.split_utils import FocusMover
|
|
from guake.split_utils import SplitMover
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
class Keybindings:
|
|
"""Handles changes in keyboard shortcuts."""
|
|
|
|
def __init__(self, guake):
|
|
"""Constructor of Keyboard, only receives the guake instance
|
|
to be used in internal methods.
|
|
"""
|
|
self.guake = guake
|
|
self.accel_group = None # see reload_accelerators
|
|
self._lookup = None
|
|
self._masks = None
|
|
self.keymap = Gdk.Keymap.get_for_display(Gdk.Display.get_default())
|
|
|
|
# Setup global keys
|
|
self.globalhotkeys = {}
|
|
globalkeys = ["show-hide", "show-focus"]
|
|
for key in globalkeys:
|
|
guake.settings.keybindingsGlobal.onChangedValue(key, self.reload_global)
|
|
guake.settings.keybindingsGlobal.triggerOnChangedValue(
|
|
guake.settings.keybindingsGlobal, key, None
|
|
)
|
|
|
|
def x(*args):
|
|
prompt_cfg = self.guake.settings.general.get_int("prompt-on-close-tab")
|
|
self.guake.get_notebook().delete_page_current(prompt=prompt_cfg)
|
|
|
|
# Setup local keys
|
|
self.keys = [
|
|
("toggle-fullscreen", self.guake.accel_toggle_fullscreen),
|
|
("new-tab", self.guake.accel_add),
|
|
("new-tab-home", self.guake.accel_add_home),
|
|
("new-tab-cwd", self.guake.accel_add_cwd),
|
|
("close-tab", x),
|
|
("rename-current-tab", self.guake.accel_rename_current_tab),
|
|
("previous-tab", self.guake.accel_prev),
|
|
("previous-tab-alt", self.guake.accel_prev),
|
|
("next-tab", self.guake.accel_next),
|
|
("next-tab-alt", self.guake.accel_next),
|
|
("clipboard-copy", self.guake.accel_copy_clipboard),
|
|
("clipboard-paste", self.guake.accel_paste_clipboard),
|
|
("select-all", self.guake.accel_select_all),
|
|
("quit", self.guake.accel_quit),
|
|
("zoom-in", self.guake.accel_zoom_in),
|
|
("zoom-in-alt", self.guake.accel_zoom_in),
|
|
("zoom-out", self.guake.accel_zoom_out),
|
|
("increase-height", self.guake.accel_increase_height),
|
|
("decrease-height", self.guake.accel_decrease_height),
|
|
("increase-transparency", self.guake.accel_increase_transparency),
|
|
("decrease-transparency", self.guake.accel_decrease_transparency),
|
|
("toggle-transparency", self.guake.accel_toggle_transparency),
|
|
("search-on-web", self.guake.search_on_web),
|
|
("open-link-under-terminal-cursor", self.guake.open_link_under_terminal_cursor),
|
|
("move-tab-left", self.guake.accel_move_tab_left),
|
|
("move-tab-right", self.guake.accel_move_tab_right),
|
|
("switch-tab1", self.guake.gen_accel_switch_tabN(0)),
|
|
("switch-tab2", self.guake.gen_accel_switch_tabN(1)),
|
|
("switch-tab3", self.guake.gen_accel_switch_tabN(2)),
|
|
("switch-tab4", self.guake.gen_accel_switch_tabN(3)),
|
|
("switch-tab5", self.guake.gen_accel_switch_tabN(4)),
|
|
("switch-tab6", self.guake.gen_accel_switch_tabN(5)),
|
|
("switch-tab7", self.guake.gen_accel_switch_tabN(6)),
|
|
("switch-tab8", self.guake.gen_accel_switch_tabN(7)),
|
|
("switch-tab9", self.guake.gen_accel_switch_tabN(8)),
|
|
("switch-tab10", self.guake.gen_accel_switch_tabN(9)),
|
|
("switch-tab-last", self.guake.accel_switch_tab_last),
|
|
("reset-terminal", self.guake.accel_reset_terminal),
|
|
(
|
|
"split-tab-vertical",
|
|
lambda *args: self.guake.get_notebook()
|
|
.get_current_terminal()
|
|
.get_parent()
|
|
.split_v()
|
|
or True,
|
|
),
|
|
(
|
|
"split-tab-horizontal",
|
|
lambda *args: self.guake.get_notebook()
|
|
.get_current_terminal()
|
|
.get_parent()
|
|
.split_h()
|
|
or True,
|
|
),
|
|
(
|
|
"close-terminal",
|
|
lambda *args: self.guake.get_notebook().get_current_terminal().kill() or True,
|
|
),
|
|
(
|
|
"focus-terminal-up",
|
|
(
|
|
lambda *args: FocusMover(self.guake.window).move_up(
|
|
self.guake.get_notebook().get_current_terminal()
|
|
)
|
|
or True
|
|
),
|
|
),
|
|
(
|
|
"focus-terminal-down",
|
|
(
|
|
lambda *args: FocusMover(self.guake.window).move_down(
|
|
self.guake.get_notebook().get_current_terminal()
|
|
)
|
|
or True
|
|
),
|
|
),
|
|
(
|
|
"focus-terminal-right",
|
|
(
|
|
lambda *args: FocusMover(self.guake.window).move_right(
|
|
self.guake.get_notebook().get_current_terminal()
|
|
)
|
|
or True
|
|
),
|
|
),
|
|
(
|
|
"focus-terminal-left",
|
|
(
|
|
lambda *args: FocusMover(self.guake.window).move_left(
|
|
self.guake.get_notebook().get_current_terminal()
|
|
)
|
|
or True
|
|
),
|
|
),
|
|
(
|
|
"move-terminal-split-up",
|
|
(
|
|
lambda *args: SplitMover.move_up( # keep make style from concat this lines
|
|
self.guake.get_notebook().get_current_terminal()
|
|
)
|
|
or True
|
|
),
|
|
),
|
|
(
|
|
"move-terminal-split-down",
|
|
(
|
|
lambda *args: SplitMover.move_down( # keep make style from concat this lines
|
|
self.guake.get_notebook().get_current_terminal()
|
|
)
|
|
or True
|
|
),
|
|
),
|
|
(
|
|
"move-terminal-split-left",
|
|
(
|
|
lambda *args: SplitMover.move_left( # keep make style from concat this lines
|
|
self.guake.get_notebook().get_current_terminal()
|
|
)
|
|
or True
|
|
),
|
|
),
|
|
(
|
|
"move-terminal-split-right",
|
|
(
|
|
lambda *args: SplitMover.move_right( # keep make style from concat this lines
|
|
self.guake.get_notebook().get_current_terminal()
|
|
)
|
|
or True
|
|
),
|
|
),
|
|
("search-terminal", self.guake.accel_search_terminal),
|
|
("toggle-hide-on-lose-focus", self.guake.accel_toggle_hide_on_lose_focus),
|
|
]
|
|
for key, _ in self.keys:
|
|
guake.settings.keybindingsLocal.onChangedValue(key, self.reload_accelerators)
|
|
self.reload_accelerators()
|
|
|
|
def reload_global(self, settings, key, user_data):
|
|
value = settings.get_string(key)
|
|
if value == "disabled":
|
|
return
|
|
|
|
try:
|
|
self.guake.hotkeys.unbind(self.globalhotkeys[key])
|
|
except BaseException:
|
|
pass
|
|
|
|
self.globalhotkeys[key] = value
|
|
if key == "show-hide":
|
|
log.debug("reload_global: %r", value)
|
|
if not self.guake.hotkeys.bind(value, self.guake.show_hide):
|
|
keyval, mask = Gtk.accelerator_parse(value)
|
|
label = Gtk.accelerator_get_label(keyval, mask)
|
|
filename = pixmapfile("guake-notification.png")
|
|
notifier.showMessage(
|
|
_("Guake Terminal"),
|
|
_(
|
|
"A problem happened when binding <b>%s</b> key.\n"
|
|
"Please use Guake Preferences dialog to choose another "
|
|
"key"
|
|
)
|
|
% label,
|
|
filename,
|
|
)
|
|
elif key == "show-focus" and not self.guake.hotkeys.bind(value, self.guake.show_focus):
|
|
log.warning("can't bind show-focus key")
|
|
|
|
def activate(self, window, event):
|
|
"""If keystroke matches a key binding, activate keybinding. Otherwise, allow
|
|
keystroke to pass through."""
|
|
key = event.keyval
|
|
mod = event.state
|
|
|
|
# Set keyval to the first available English keyboard value if character is non-latin
|
|
# and a english keyval is found
|
|
if event.keyval > 126:
|
|
for i in self.keymap.get_entries_for_keycode(event.hardware_keycode)[2]:
|
|
if 0 < i <= 126:
|
|
key = i
|
|
break
|
|
|
|
if mod & Gdk.ModifierType.SHIFT_MASK:
|
|
if key == Gdk.KEY_ISO_Left_Tab:
|
|
key = Gdk.KEY_Tab
|
|
else:
|
|
key = Gdk.keyval_to_lower(key)
|
|
else:
|
|
keys = Gdk.keyval_convert_case(key)
|
|
if key != keys[1]:
|
|
key = keys[0]
|
|
mod &= ~Gdk.ModifierType.SHIFT_MASK
|
|
|
|
mask = mod & self._masks
|
|
|
|
func = self._lookup[mask].get(key, None)
|
|
if func:
|
|
func()
|
|
return True
|
|
|
|
return False
|
|
|
|
def reload_accelerators(self, *args):
|
|
"""Reassign an accel_group to guake main window and guake
|
|
context menu and calls the load_accelerators method.
|
|
"""
|
|
self._lookup = defaultdict(dict)
|
|
self._masks = 0
|
|
|
|
self.load_accelerators()
|
|
self.guake.accel_group = self
|
|
|
|
def load_accelerators(self):
|
|
"""Reads all gconf paths under /org/guake/keybindings/local
|
|
and adds to the _lookup.
|
|
"""
|
|
|
|
for binding, action in self.keys:
|
|
key, mask = Gtk.accelerator_parse(
|
|
self.guake.settings.keybindingsLocal.get_string(binding)
|
|
)
|
|
if key > 0:
|
|
self._lookup[mask][key] = action
|
|
self._masks |= mask
|