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")
|
gdk = CDLL("libgdk-x11-2.0.so.0")
|
||||||
gtk = CDLL("libgtk-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):
|
class GlobalKeyBinding(GObject.GObject, threading.Thread):
|
||||||
__gsignals__ = {
|
__gsignals__ = {
|
||||||
'activate': (GObject.SignalFlags.RUN_LAST, None, ()),
|
'activate': (GObject.SignalFlags.RUN_LAST, None, ()),
|
||||||
@ -57,6 +66,7 @@ class GlobalKeyBinding(GObject.GObject, threading.Thread):
|
|||||||
def is_hotkey(self, key, modifier):
|
def is_hotkey(self, key, modifier):
|
||||||
keymatch = False
|
keymatch = False
|
||||||
modmatch = False
|
modmatch = False
|
||||||
|
modifier = modifier & ~Gdk.ModifierType.SUPER_MASK
|
||||||
modint = int(modifier)
|
modint = int(modifier)
|
||||||
if self.get_keycode(key) == self.keycode:
|
if self.get_keycode(key) == self.keycode:
|
||||||
keymatch = True
|
keymatch = True
|
||||||
@ -72,7 +82,7 @@ class GlobalKeyBinding(GObject.GObject, threading.Thread):
|
|||||||
Gdk.ModifierType.SUPER_MASK, Gdk.ModifierType.HYPER_MASK)
|
Gdk.ModifierType.SUPER_MASK, Gdk.ModifierType.HYPER_MASK)
|
||||||
self.known_modifiers_mask = 0
|
self.known_modifiers_mask = 0
|
||||||
for modifier in gdk_modifiers:
|
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
|
self.known_modifiers_mask |= modifier
|
||||||
|
|
||||||
def get_keycode(self, keyval):
|
def get_keycode(self, keyval):
|
||||||
@ -84,6 +94,7 @@ class GlobalKeyBinding(GObject.GObject, threading.Thread):
|
|||||||
|
|
||||||
def grab(self, key):
|
def grab(self, key):
|
||||||
accelerator = key
|
accelerator = key
|
||||||
|
accelerator = accelerator.replace("<Super>", "<Mod4>")
|
||||||
keyval, modifiers = Gtk.accelerator_parse(accelerator)
|
keyval, modifiers = Gtk.accelerator_parse(accelerator)
|
||||||
if not accelerator or (not keyval and not modifiers):
|
if not accelerator or (not keyval and not modifiers):
|
||||||
self.keycode = None
|
self.keycode = None
|
||||||
@ -152,82 +163,51 @@ class KeybindingWidget(Gtk.HBox):
|
|||||||
__gsignals__ = {
|
__gsignals__ = {
|
||||||
'accel-edited': (GObject.SignalFlags.RUN_LAST, None, ()),
|
'accel-edited': (GObject.SignalFlags.RUN_LAST, None, ()),
|
||||||
}
|
}
|
||||||
def __init__(self, desc):
|
def __init__(self, desc, mainwindow):
|
||||||
super(KeybindingWidget, self).__init__()
|
super(KeybindingWidget, self).__init__()
|
||||||
self.desc = desc
|
self.desc = desc
|
||||||
|
self.win = mainwindow
|
||||||
self.label = Gtk.Label(desc)
|
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 != "":
|
if self.desc != "":
|
||||||
self.pack_start(self.label, False, False, 0)
|
self.pack_start(self.label, False, False, 0)
|
||||||
shadow = Gtk.Frame()
|
self.button = Gtk.Button()
|
||||||
shadow.set_shadow_type(Gtk.ShadowType.ETCHED_IN)
|
self.button.set_tooltip_text(_("Click to set a new accelerator key for opening and closing the menu. ") +
|
||||||
shadow.add(self.tree)
|
_("Press Escape to cancel the operation"))
|
||||||
self.pack_start(shadow, False, False, 2)
|
self.button.connect("clicked", self.focus_grabbed)
|
||||||
|
self.button.set_size_request(200, -1)
|
||||||
self.combomodel = Gtk.ListStore(str, str)
|
self.pack_start(self.button, False, False, 4)
|
||||||
|
|
||||||
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.show_all()
|
self.show_all()
|
||||||
|
self.event_id = None
|
||||||
|
|
||||||
def on_combo_changed(self, widget):
|
def focus_grabbed(self, widget):
|
||||||
tree_iter = widget.get_active_iter()
|
self.button.set_label(_("Pick an accelerator"))
|
||||||
if tree_iter != None:
|
self.event_id = self.win.connect( "key-release-event", self.on_key_release )
|
||||||
value = self.combomodel[tree_iter][1]
|
|
||||||
self.set_val(value)
|
|
||||||
self.emit("accel-edited")
|
|
||||||
|
|
||||||
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
|
gtk.gtk_accelerator_name.restype = c_char_p
|
||||||
accel_string = gtk.gtk_accelerator_name(keyval, mask)
|
accel_string = gtk.gtk_accelerator_name(event.keyval, event.state)
|
||||||
accel_string = accel_string.replace("<Mod2>", "")
|
accel_string = self.sanitize(accel_string)
|
||||||
self.value = accel_string
|
self.value = accel_string
|
||||||
self.emit("accel-edited")
|
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):
|
def get_val(self):
|
||||||
return self.value
|
return self.value
|
||||||
|
|
||||||
def set_val(self, value):
|
def set_val(self, value):
|
||||||
self.cell.handler_block(self.change_id)
|
|
||||||
self.value = value
|
self.value = value
|
||||||
self.model.clear()
|
self.button.set_label(value)
|
||||||
self.model.append((self.value, self))
|
|
||||||
self.cell.handler_unblock(self.change_id)
|
|
||||||
|
@ -142,7 +142,7 @@ class mintMenuConfig( object ):
|
|||||||
self.headingColorLabel = self.builder.get_object( "headingColorLabel" )
|
self.headingColorLabel = self.builder.get_object( "headingColorLabel" )
|
||||||
self.showButtonIcon = self.builder.get_object( "showButtonIcon" )
|
self.showButtonIcon = self.builder.get_object( "showButtonIcon" )
|
||||||
self.buttonText = self.builder.get_object( "buttonText" )
|
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 = self.builder.get_object( "main_table" )
|
||||||
table.attach(self.hotkeyWidget, 0, 2, 2, 3, Gtk.AttachOptions.FILL, Gtk.AttachOptions.FILL, 0, 0)
|
table.attach(self.hotkeyWidget, 0, 2, 2, 3, Gtk.AttachOptions.FILL, Gtk.AttachOptions.FILL, 0, 0)
|
||||||
self.buttonIcon = self.builder.get_object( "buttonIcon" )
|
self.buttonIcon = self.builder.get_object( "buttonIcon" )
|
||||||
|
Loading…
Reference in New Issue
Block a user