This adds the neccessary keyboard handling, grabbing the input, switching to
the new activity, or canceling the operation. It is also responsible for
showing the frame during the tabbing operation.
---
src/view/keyhandler.py | 96 +++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 94 insertions(+), 2 deletions(-)
diff --git a/src/view/keyhandler.py b/src/view/keyhandler.py
index 306bb21..8dee50c 100644
--- a/src/view/keyhandler.py
+++ b/src/view/keyhandler.py
@@ -32,6 +32,10 @@ _BRIGHTNESS_STEP = 2
_VOLUME_STEP = 10
_BRIGHTNESS_MAX = 15
_VOLUME_MAX = 100
+# The modifier used for tabbing. Should the shortcuts ever be made user
+# configurable, then some code to figure out the apropriate modifier is
+# needed instead of hardcoding it.
+_TABBING_MODIFIER = gtk.gdk.MOD1_MASK
_actions_table = {
'F1' : 'zoom_mesh',
@@ -77,10 +81,13 @@ class KeyHandler(object):
self._keycode_pressed = 0
self._keystate_pressed = 0
self._speech_proxy = None
+ self._tabbing_windows = False
self._key_grabber = KeyGrabber()
self._key_grabber.connect('key-pressed',
self._key_pressed_cb)
+ self._key_grabber.connect('key-released',
+ self._key_released_cb)
for key in _actions_table.keys():
self._key_grabber.grab(key)
@@ -131,15 +138,75 @@ class KeyHandler(object):
self._get_speech_proxy().SayText(text, reply_handler=lambda: None, \
error_handler=self._on_speech_err)
+ def _window_tabbing(self, direction):
+ if not self._tabbing_windows:
+ logging.debug('Grabing the input.')
+
+ screen = gtk.gdk.screen_get_default()
+ window = screen.get_root_window()
+ keyboard_grab_result = gtk.gdk.keyboard_grab(window)
+ pointer_grab_result = gtk.gdk.pointer_grab(window)
+
+ self._tabbing_windows = (keyboard_grab_result == gtk.gdk.GRAB_SUCCESS and
+ pointer_grab_result == gtk.gdk.GRAB_SUCCESS)
+
+ # Now test that the modifier is still active to prevent race
+ # conditions. We also test if one of the grabs failed.
+ mask = window.get_pointer()[2]
+ if not self._tabbing_windows or not (mask & _TABBING_MODIFIER):
+ logging.debug('Releasing grabs again.')
+
+ if keyboard_grab_result != gtk.gdk.GRAB_SUCCESS:
+ gtk.gdk.keyboard_ungrab()
+ if pointer_grab_result != gtk.gdk.GRAB_SUCCESS:
+ gtk.gdk.pointer_ungrab()
+ self._tabbing_windows = False
+
+ if self._tabbing_windows:
+ # We have the grab, so show the frame.
+ shell = view.Shell.get_instance()
+ frame = shell.get_frame()
+ frame.show(frame.MODE_NON_INTERACTIVE)
+
+ if direction == 1:
+ shell.tabbing_next_activity()
+ else:
+ shell.tabbing_previous_activity()
+
+ return self._tabbing_windows
+
+ def _stop_window_tabbing(self, cancel=True):
+ # Some useless key was pressed, or <Alt> released.
+ if not self._tabbing_windows:
+ return
+
+ logging.debug('Releasing grabs again.')
+ gtk.gdk.keyboard_ungrab()
+ gtk.gdk.pointer_ungrab()
+
+ shell = view.Shell.get_instance()
+ frame = shell.get_frame()
+
+ if not cancel:
+ shell.tabbing_activate_current()
+ else:
+ shell.tabbing_cancel()
+
+ frame.hide()
+
+ self._tabbing_windows = False
+
def handle_say_text(self):
clipboard = gtk.clipboard_get(selection="PRIMARY")
clipboard.request_text(self._primary_selection_cb)
def handle_previous_window(self):
- view.Shell.get_instance().activate_previous_activity()
+ if not self._window_tabbing(-1):
+ view.Shell.get_instance().activate_previous_activity()
def handle_next_window(self):
- view.Shell.get_instance().activate_next_activity()
+ if not self._window_tabbing(1):
+ view.Shell.get_instance().activate_next_activity()
def handle_close_window(self):
view.Shell.get_instance().close_current_activity()
@@ -218,9 +285,34 @@ class KeyHandler(object):
self._keystate_pressed = state
action = _actions_table[key]
+ if self._tabbing_windows:
+ # Only accept window tabbing events, everything else
+ # cancels the tabbing operation.
+ if not action in ["next_window", "previous_window"]:
+ self._stop_window_tabbing(True)
+ return True
+
method = getattr(self, 'handle_' + action)
method()
return True
+ else:
+ # If this is not a registered key, then cancel any active
+ # tabbing.
+ if self._tabbing_windows:
+ if not grabber.is_modifier(keycode):
+ self._stop_window_tabbing(True)
+ return True
return False
+
+ def _key_released_cb(self, grabber, keycode, state):
+ if self._tabbing_windows:
+ # We stop tabbing and switch to the new window as soon as the
+ # modifier key is raised again.
+ if grabber.is_specific_modifier(keycode, _TABBING_MODIFIER):
+ self._stop_window_tabbing(False)
+
+ return True
+ return False
+
_______________________________________________
Sugar mailing list
[email protected]
http://lists.laptop.org/listinfo/sugar