--- src/view/keyhandler.py | 91 +++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 89 insertions(+), 2 deletions(-)
diff --git a/src/view/keyhandler.py b/src/view/keyhandler.py index 16f5a43..b42b93c 100644 --- a/src/view/keyhandler.py +++ b/src/view/keyhandler.py @@ -33,6 +33,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', @@ -78,10 +82,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) @@ -132,15 +139,70 @@ class KeyHandler(object): self._get_speech_proxy().SayText(text, reply_handler=lambda: None, \ error_handler=self._on_speech_err) + def _window_tabbing(self, direction): + shell = view.Shell.get_instance() + 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 + else: + shell.tabbing_start() + + first_switch = True + else: + first_switch = False + + if self._tabbing_windows: + if direction == 1: + shell.tabbing_next_activity(first_switch) + else: + shell.tabbing_previous_activity(first_switch) + + return self._tabbing_windows + + def _stop_window_tabbing(self): + # 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() + shell.tabbing_stop() + + 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() @@ -252,9 +314,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() + 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() + 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() + + return True + return False + _______________________________________________ Sugar mailing list Sugar@lists.laptop.org http://lists.laptop.org/listinfo/sugar