Implemented a better keybinding widget - recognizes lone modifiers
as hotkeys (like Gtk3 can).
This commit is contained in:
parent
b07f97c35e
commit
3cf26cf96c
@ -36,6 +36,15 @@ import capi
|
||||
gdk = CDLL("libgdk-x11-2.0.so.0")
|
||||
gtk = CDLL("libgtk-x11-2.0.so.0")
|
||||
|
||||
SPECIAL_MODS = (["Super_L", "<Super>"],
|
||||
["Super_R", "<Super>"],
|
||||
["Alt_L", "<Alt>"],
|
||||
["Alt_R", "<Alt>"],
|
||||
["Control_L", "<Primary>"],
|
||||
["Control_R", "<Primary>"],
|
||||
["Shift_L", "<Shift>"],
|
||||
["Shift_R", "<Shift>"])
|
||||
|
||||
class GlobalKeyBinding(GObject.GObject, threading.Thread):
|
||||
__gsignals__ = {
|
||||
'activate': (GObject.SignalFlags.RUN_LAST, None, ()),
|
||||
@ -57,6 +66,7 @@ class GlobalKeyBinding(GObject.GObject, threading.Thread):
|
||||
def is_hotkey(self, key, modifier):
|
||||
keymatch = False
|
||||
modmatch = False
|
||||
modifier = modifier & ~Gdk.ModifierType.SUPER_MASK
|
||||
modint = int(modifier)
|
||||
if self.get_keycode(key) == self.keycode:
|
||||
keymatch = True
|
||||
@ -72,7 +82,7 @@ class GlobalKeyBinding(GObject.GObject, threading.Thread):
|
||||
Gdk.ModifierType.SUPER_MASK, Gdk.ModifierType.HYPER_MASK)
|
||||
self.known_modifiers_mask = 0
|
||||
for modifier in gdk_modifiers:
|
||||
if "Mod" not in Gtk.accelerator_name(0, modifier):
|
||||
if "Mod" not in Gtk.accelerator_name(0, modifier) or "Mod4" in Gtk.accelerator_name(0, modifier):
|
||||
self.known_modifiers_mask |= modifier
|
||||
|
||||
def get_keycode(self, keyval):
|
||||
@ -84,6 +94,7 @@ class GlobalKeyBinding(GObject.GObject, threading.Thread):
|
||||
|
||||
def grab(self, key):
|
||||
accelerator = key
|
||||
accelerator = accelerator.replace("<Super>", "<Mod4>")
|
||||
keyval, modifiers = Gtk.accelerator_parse(accelerator)
|
||||
if not accelerator or (not keyval and not modifiers):
|
||||
self.keycode = None
|
||||
@ -152,82 +163,51 @@ class KeybindingWidget(Gtk.HBox):
|
||||
__gsignals__ = {
|
||||
'accel-edited': (GObject.SignalFlags.RUN_LAST, None, ()),
|
||||
}
|
||||
def __init__(self, desc):
|
||||
def __init__(self, desc, mainwindow):
|
||||
super(KeybindingWidget, self).__init__()
|
||||
self.desc = desc
|
||||
self.win = mainwindow
|
||||
self.label = Gtk.Label(desc)
|
||||
self.model = Gtk.ListStore(str, object)
|
||||
self.tree = Gtk.TreeView.new()
|
||||
self.tree.set_headers_visible(False)
|
||||
self.cell = Gtk.CellRendererAccel()
|
||||
self.cell.set_alignment(.5, .5)
|
||||
self.change_id = self.cell.connect('accel-edited', self.on_my_value_changed)
|
||||
self.cell.set_property('editable', True)
|
||||
self.cell.set_property('accel-mode', Gtk.CellRendererAccelMode.OTHER)
|
||||
col = Gtk.TreeViewColumn("col", self.cell, text=0)
|
||||
col.set_min_width(200)
|
||||
col.set_alignment(.5)
|
||||
self.tree.append_column(col)
|
||||
self.value = ""
|
||||
self.tree.set_model(self.model)
|
||||
self.model.append((self.value, self))
|
||||
if self.desc != "":
|
||||
self.pack_start(self.label, False, False, 0)
|
||||
shadow = Gtk.Frame()
|
||||
shadow.set_shadow_type(Gtk.ShadowType.ETCHED_IN)
|
||||
shadow.add(self.tree)
|
||||
self.pack_start(shadow, False, False, 2)
|
||||
|
||||
self.combomodel = Gtk.ListStore(str, str)
|
||||
|
||||
customs = (["Select a single modifier...", "x"],
|
||||
["Left Super", "Super_L" ],
|
||||
["Right Super", "Super_R" ],
|
||||
["Left Control", "Control_L" ],
|
||||
["Right Control", "Control_R" ],
|
||||
["Left Alt", "Alt_L" ],
|
||||
["Right Alt", "Alt_R" ])
|
||||
|
||||
first = None
|
||||
for option in customs:
|
||||
iter = self.combomodel.insert_before(None, None)
|
||||
self.combomodel.set_value(iter, 0, option[0])
|
||||
self.combomodel.set_value(iter, 1, option[1])
|
||||
if first is None:
|
||||
first = iter
|
||||
|
||||
self.combo = Gtk.ComboBox.new_with_model(self.combomodel)
|
||||
renderer_text = Gtk.CellRendererText()
|
||||
self.combo.pack_start(renderer_text, True)
|
||||
self.combo.add_attribute(renderer_text, "text", 0)
|
||||
|
||||
self.combo.set_active_iter(first)
|
||||
self.combo.connect('changed', self.on_combo_changed)
|
||||
|
||||
self.pack_start(self.combo, False, False, 0)
|
||||
self.button = Gtk.Button()
|
||||
self.button.set_tooltip_text(_("Click to set a new accelerator key for opening and closing the menu. ") +
|
||||
_("Press Escape to cancel the operation"))
|
||||
self.button.connect("clicked", self.focus_grabbed)
|
||||
self.button.set_size_request(200, -1)
|
||||
self.pack_start(self.button, False, False, 4)
|
||||
|
||||
self.show_all()
|
||||
self.event_id = None
|
||||
|
||||
def on_combo_changed(self, widget):
|
||||
tree_iter = widget.get_active_iter()
|
||||
if tree_iter != None:
|
||||
value = self.combomodel[tree_iter][1]
|
||||
self.set_val(value)
|
||||
self.emit("accel-edited")
|
||||
def focus_grabbed(self, widget):
|
||||
self.button.set_label(_("Pick an accelerator"))
|
||||
self.event_id = self.win.connect( "key-release-event", self.on_key_release )
|
||||
|
||||
def on_my_value_changed(self, cell, path, keyval, mask, keycode):
|
||||
def on_key_release(self, widget, event):
|
||||
self.win.disconnect(self.event_id)
|
||||
if event.keyval == Gdk.KEY_Escape:
|
||||
self.button.set_label(self.value)
|
||||
return True
|
||||
gtk.gtk_accelerator_name.restype = c_char_p
|
||||
accel_string = gtk.gtk_accelerator_name(keyval, mask)
|
||||
accel_string = accel_string.replace("<Mod2>", "")
|
||||
accel_string = gtk.gtk_accelerator_name(event.keyval, event.state)
|
||||
accel_string = self.sanitize(accel_string)
|
||||
self.value = accel_string
|
||||
self.emit("accel-edited")
|
||||
self.button.set_label(self.value)
|
||||
return True
|
||||
|
||||
def sanitize(self, string):
|
||||
accel_string = string.replace("<Mod2>", "")
|
||||
accel_string = accel_string.replace("<Mod4>", "")
|
||||
for single, mod in SPECIAL_MODS:
|
||||
if single in accel_string and mod in accel_string:
|
||||
accel_string = accel_string.replace(mod, "")
|
||||
return accel_string
|
||||
|
||||
def get_val(self):
|
||||
return self.value
|
||||
|
||||
def set_val(self, value):
|
||||
self.cell.handler_block(self.change_id)
|
||||
self.value = value
|
||||
self.model.clear()
|
||||
self.model.append((self.value, self))
|
||||
self.cell.handler_unblock(self.change_id)
|
||||
self.button.set_label(value)
|
||||
|
@ -142,7 +142,7 @@ class mintMenuConfig( object ):
|
||||
self.headingColorLabel = self.builder.get_object( "headingColorLabel" )
|
||||
self.showButtonIcon = self.builder.get_object( "showButtonIcon" )
|
||||
self.buttonText = self.builder.get_object( "buttonText" )
|
||||
self.hotkeyWidget = keybinding.KeybindingWidget(_("Keyboard shortcut:"))
|
||||
self.hotkeyWidget = keybinding.KeybindingWidget(_("Keyboard shortcut:"), self.mainWindow)
|
||||
table = self.builder.get_object( "main_table" )
|
||||
table.attach(self.hotkeyWidget, 0, 2, 2, 3, Gtk.AttachOptions.FILL, Gtk.AttachOptions.FILL, 0, 0)
|
||||
self.buttonIcon = self.builder.get_object( "buttonIcon" )
|
||||
|
Loading…
Reference in New Issue
Block a user