summaryrefslogtreecommitdiff
path: root/src/utilities/bindingManager.vala
diff options
context:
space:
mode:
Diffstat (limited to 'src/utilities/bindingManager.vala')
-rw-r--r--src/utilities/bindingManager.vala196
1 files changed, 196 insertions, 0 deletions
diff --git a/src/utilities/bindingManager.vala b/src/utilities/bindingManager.vala
new file mode 100644
index 0000000..8795124
--- /dev/null
+++ b/src/utilities/bindingManager.vala
@@ -0,0 +1,196 @@
+/*
+Copyright (c) 2011 by Simon Schneegans
+
+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 3 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, see <http://www.gnu.org/licenses/>.
+*/
+
+namespace GnomePie {
+
+/////////////////////////////////////////////////////////////////////////
+/// Globally binds key stroke to given ID's. When one of the bound
+/// strokes is invoked, a signal with the according ID is emitted.
+/////////////////////////////////////////////////////////////////////////
+
+public class BindingManager : GLib.Object {
+
+ /////////////////////////////////////////////////////////////////////
+ /// Called when a stored binding is invoked. The according ID is
+ /// passed as argument.
+ /////////////////////////////////////////////////////////////////////
+
+ public signal void on_press(string id);
+
+ /////////////////////////////////////////////////////////////////////
+ /// A list storing bindings, which are invoked even if Gnome-Pie
+ /// doesn't have the current focus
+ /////////////////////////////////////////////////////////////////////
+
+ private Gee.List<Keybinding> bindings = new Gee.ArrayList<Keybinding>();
+
+ /////////////////////////////////////////////////////////////////////
+ /// Ignored modifier masks, used to grab all keys even if these locks
+ /// are active.
+ /////////////////////////////////////////////////////////////////////
+
+ private static uint[] lock_modifiers = {
+ 0,
+ Gdk.ModifierType.MOD2_MASK,
+ Gdk.ModifierType.LOCK_MASK,
+ Gdk.ModifierType.MOD5_MASK,
+ Gdk.ModifierType.MOD2_MASK|Gdk.ModifierType.LOCK_MASK,
+ Gdk.ModifierType.MOD2_MASK|Gdk.ModifierType.MOD5_MASK,
+ Gdk.ModifierType.LOCK_MASK|Gdk.ModifierType.MOD5_MASK,
+ Gdk.ModifierType.MOD2_MASK|Gdk.ModifierType.LOCK_MASK|Gdk.ModifierType.MOD5_MASK
+ };
+
+ /////////////////////////////////////////////////////////////////////
+ /// Helper class to store keybinding
+ /////////////////////////////////////////////////////////////////////
+
+ private class Keybinding {
+
+ public Keybinding(string accelerator, int keycode, Gdk.ModifierType modifiers, string id) {
+ this.accelerator = accelerator;
+ this.keycode = keycode;
+ this.modifiers = modifiers;
+ this.id = id;
+ }
+
+ public string accelerator { get; set; }
+ public int keycode { get; set; }
+ public Gdk.ModifierType modifiers { get; set; }
+ public string id { get; set; }
+ }
+
+ /////////////////////////////////////////////////////////////////////
+ /// C'tor adds the event filter to the root window.
+ /////////////////////////////////////////////////////////////////////
+
+ public BindingManager() {
+ // init filter to retrieve X.Events
+ Gdk.Window rootwin = Gdk.get_default_root_window();
+ if(rootwin != null) {
+ rootwin.add_filter(event_filter);
+ }
+ }
+
+ /////////////////////////////////////////////////////////////////////
+ /// Binds the ID to the given accelerator.
+ /////////////////////////////////////////////////////////////////////
+
+ public void bind(string accelerator, string id) {
+ uint keysym;
+ Gdk.ModifierType modifiers;
+ Gtk.accelerator_parse(accelerator, out keysym, out modifiers);
+
+ if (keysym == 0) {
+ warning("Invalid keystroke: " + accelerator);
+ return;
+ }
+
+ Gdk.Window rootwin = Gdk.get_default_root_window();
+ X.Display display = Gdk.x11_drawable_get_xdisplay(rootwin);
+ X.ID xid = Gdk.x11_drawable_get_xid(rootwin);
+ int keycode = display.keysym_to_keycode(keysym);
+
+ if(keycode != 0) {
+ Gdk.error_trap_push();
+
+ foreach(uint lock_modifier in lock_modifiers) {
+ display.grab_key(keycode, modifiers|lock_modifier, xid, false, X.GrabMode.Async, X.GrabMode.Async);
+ }
+
+ Gdk.flush();
+
+ Keybinding binding = new Keybinding(accelerator, keycode, modifiers, id);
+ bindings.add(binding);
+ }
+ }
+
+ /////////////////////////////////////////////////////////////////////
+ /// Unbinds the accelerator of the given ID.
+ /////////////////////////////////////////////////////////////////////
+
+ public void unbind(string id) {
+ Gdk.Window rootwin = Gdk.get_default_root_window();
+ X.Display display = Gdk.x11_drawable_get_xdisplay(rootwin);
+ X.ID xid = Gdk.x11_drawable_get_xid(rootwin);
+ Gee.List<Keybinding> remove_bindings = new Gee.ArrayList<Keybinding>();
+ foreach(var binding in bindings) {
+ if(id == binding.id) {
+ foreach(uint lock_modifier in lock_modifiers) {
+ display.ungrab_key(binding.keycode, binding.modifiers, xid);
+ }
+ remove_bindings.add(binding);
+ }
+ }
+
+ bindings.remove_all(remove_bindings);
+ }
+
+ /////////////////////////////////////////////////////////////////////
+ /// Returns a human readable accelerator for the given ID.
+ /////////////////////////////////////////////////////////////////////
+
+ public string get_accelerator_label_of(string id) {
+ string accelerator = this.get_accelerator_of(id);
+
+ if (accelerator == "")
+ return _("Not bound");
+
+ uint key = 0;
+ Gdk.ModifierType mods;
+ Gtk.accelerator_parse(accelerator, out key, out mods);
+ return Gtk.accelerator_get_label(key, mods);
+ }
+
+ /////////////////////////////////////////////////////////////////////
+ /// Returns the accelerator to which the given ID is bound.
+ /////////////////////////////////////////////////////////////////////
+
+ public string get_accelerator_of(string id) {
+ foreach (var binding in bindings) {
+ if (binding.id == id) {
+ return binding.accelerator;
+ }
+ }
+
+ return "";
+ }
+
+ /////////////////////////////////////////////////////////////////////
+ /// Event filter method needed to fetch X.Events
+ /////////////////////////////////////////////////////////////////////
+
+ private Gdk.FilterReturn event_filter(Gdk.XEvent gdk_xevent, Gdk.Event gdk_event) {
+ Gdk.FilterReturn filter_return = Gdk.FilterReturn.CONTINUE;
+
+ void* pointer = &gdk_xevent;
+ X.Event* xevent = (X.Event*) pointer;
+
+ if(xevent->type == X.EventType.KeyPress) {
+ foreach(var binding in bindings) {
+ // remove NumLock, CapsLock and ScrollLock from key state
+ uint event_mods = xevent.xkey.state & ~ (lock_modifiers[7]);
+ if(xevent->xkey.keycode == binding.keycode && event_mods == binding.modifiers) {
+ on_press(binding.id);
+ }
+ }
+ }
+
+ return filter_return;
+ }
+}
+
+}