[caribou/gtk3-introspection: 5/7] Got most of scanning working. Yay.



commit 7c7bcb7ace2d54b1289301000f60a7112ee6e737
Author: Eitan Isaacson <eitan monotonous org>
Date:   Fri Jan 7 01:17:18 2011 -0800

    Got most of scanning working. Yay.

 bin/caribou.in                     |   15 +-
 caribou/common/settings_manager.py |    2 +-
 caribou/ui/keyboard.py             |   56 ++++-
 caribou/ui/main.py                 |   77 ++----
 caribou/ui/scan.py                 |  515 ++++++++++--------------------------
 caribou/ui/window.py               |    7 +-
 6 files changed, 226 insertions(+), 446 deletions(-)
---
diff --git a/bin/caribou.in b/bin/caribou.in
index 1c2235c..35ef584 100644
--- a/bin/caribou.in
+++ b/bin/caribou.in
@@ -27,7 +27,7 @@
 from optparse import OptionParser
 import gettext
 import sys
-from gi.repository import Gtk
+import pyatspi
 import os
 
 # We can't rely on prefix if we're installed by relocated RPM. Instead, we 
@@ -55,8 +55,12 @@ import caribou.ui.keyboard as keyboard
 import caribou.ui.main as main
 
 _ = gettext.gettext
-
+    
 if __name__ == "__main__":
+    import signal
+
+    signal.signal(signal.SIGINT, signal.SIG_DFL)
+
     parser = OptionParser(usage="usage: %prog [options]",
                           version="%prog @VERSION@")
     parser.add_option("-d", "--debug",
@@ -69,4 +73,9 @@ if __name__ == "__main__":
     caribou = main.Caribou()
     caribou.window.hide()
  
-    Gtk.main()
+    try:
+        pyatspi.Registry.start()
+    except KeyboardInterrupt:
+        caribou.clean_exit()
+        pyatspi.Registry.stop()
+
diff --git a/caribou/common/settings_manager.py b/caribou/common/settings_manager.py
index 92b5137..37d178b 100644
--- a/caribou/common/settings_manager.py
+++ b/caribou/common/settings_manager.py
@@ -19,7 +19,7 @@ class _SettingsManager(object):
         try:
             return self._settings_map[name]
         except KeyError:
-            raise AttributeError
+            raise AttributeError, "no setting named '%s'" % name
 
     def _map_settings(self, setting):
         if self._settings_map.has_key(setting.name):
diff --git a/caribou/ui/keyboard.py b/caribou/ui/keyboard.py
index b6ca509..38bdfc3 100644
--- a/caribou/ui/keyboard.py
+++ b/caribou/ui/keyboard.py
@@ -145,10 +145,11 @@ class Key(Gtk.Button, BaseKey):
             return
         label.modify_font(None)
 
-    def set_color(self, normal_color, mouse_over_color):
+    def set_color(self, normal_color, mouse_over_color=None):
         self.modify_bg(Gtk.StateType.NORMAL, Gdk.color_parse(normal_color)[1])
-        self.modify_bg(Gtk.StateType.PRELIGHT,
-                       Gdk.color_parse(mouse_over_color)[1])
+        if mouse_over_color:
+            self.modify_bg(Gtk.StateType.PRELIGHT,
+                           Gdk.color_parse(mouse_over_color)[1])
 
     def reset_color(self):
         self.modify_bg(Gtk.StateType.NORMAL, None)
@@ -177,6 +178,39 @@ class KeyboardLayout(Gtk.Table):
                         Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL,
                         0, 0)
             last_col = next_col
+    
+    def get_scan_rows(self):
+        return [filter(lambda x: x.is_sensitive(), row) for row in self.rows]
+
+    def get_scan_blocks(self, optimal_block_size=8):
+        # TODO: smarter division using optimal block size.
+        scan_rows = self.get_scan_rows()
+        col_num = max([len(row) for row in scan_rows])
+        blocks = []
+        
+        for row_index in xrange(len(scan_rows)):
+            for col_index in xrange(max([len(row) for row in scan_rows])):
+                try:
+                    key = scan_rows[row_index][col_index]
+                except IndexError:
+                    continue
+
+                try:
+                    group = blocks[row_index/2]
+                except IndexError:
+                    group = []
+                    blocks.append(group)
+                
+                try:
+                    group[col_index/3].append(key)
+                except IndexError:
+                    block = []
+                    block.append(key)
+                    group.append(block)
+
+        return reduce(lambda a, b: a + b, blocks)
+        
+                                    
 
 class KbLayoutDeserializer(object):
     def __init__(self):
@@ -307,7 +341,7 @@ class CaribouKeyboard(Gtk.Notebook):
         self._update_key_style()
 
     def _set_layouts(self, layout_list):
-        self._clear()
+        self._clear()            
         for layout in layout_list:
             self.append_page(layout, None)
             for row in layout.rows:
@@ -374,7 +408,7 @@ class CaribouKeyboard(Gtk.Notebook):
             self.current_mask |= key.value
             self.vk.latch_mod(self.current_mask)
 
-    def show_all(self):
+    def show_all_(self):
         self.set_current_page(self.current_page)
         Gtk.Notebook.show_all(self)
 
@@ -384,11 +418,6 @@ class CaribouKeyboard(Gtk.Notebook):
         p.run()
         p.destroy()
 
-    def destroy(self):
-        for id in self._gconf_connections:
-            self.client.notify_remove(id)
-        super(Gtk.Notebook, self).destroy()
-
     def _switch_to_layout(self, name):
         n_pages = self.get_n_pages()
         for i in range(n_pages):
@@ -397,6 +426,13 @@ class CaribouKeyboard(Gtk.Notebook):
                 self.current_page = i
                 break
 
+    def get_current_layout(self):
+        i = self.get_current_page()
+        return self.get_nth_page(i)
+
+    def get_layouts(self):
+        return [self.get_nth_page(i) for i in xrange(self.get_n_pages())]
+
 if __name__ == "__main__":
     import signal
     signal.signal(signal.SIGINT, signal.SIG_DFL)
diff --git a/caribou/ui/main.py b/caribou/ui/main.py
index 49058a2..5175bb0 100644
--- a/caribou/ui/main.py
+++ b/caribou/ui/main.py
@@ -2,12 +2,13 @@ import pyatspi
 from gi.repository import GConf
 from gi.repository import Gtk
 from gi.repository import Gdk
-import signal
 
 from window import CaribouWindowEntry, Rectangle
 from keyboard import CaribouKeyboard
+from caribou.common.settings_manager import SettingsManager
 from caribou.ui.i18n import _
 import caribou.common.const as const
+from scan import ScanMaster
 
 debug = False
 
@@ -20,12 +21,19 @@ class Caribou:
         self.__current_acc = None
         self.window_factory = window_factory
         self.kb_factory = kb_factory
-        self.window = window_factory(kb_factory())
+        kb = kb_factory()
+        self.window = window_factory(kb)
         self.client = GConf.Client.get_default()
         self._register_event_listeners()
-        #self.client.notify_add(const.CARIBOU_GCONF + "/layout", 
-        #                        self._on_layout_changed)
-        signal.signal(signal.SIGINT, self.signal_handler)
+        SettingsManager.layout.connect("value-changed",
+                                       self._on_layout_changed)
+
+        # Scanning
+        self.scan_master = ScanMaster(self.window, kb)
+        SettingsManager.scan_enabled.connect("value-changed",
+                                             self._on_scan_toggled)
+        if SettingsManager.scan_enabled.value:
+            self.scan_master.start()
 
     def _register_event_listeners(self):
         pyatspi.Registry.registerEventListener(
@@ -33,8 +41,6 @@ class Caribou:
         pyatspi.Registry.registerEventListener(self.on_focus, "focus")
         pyatspi.Registry.registerEventListener(
             self.on_text_caret_moved, "object:text-caret-moved")
-        pyatspi.Registry.registerKeystrokeListener(
-            self.on_key_down, mask=0, kind=(pyatspi.KEY_PRESSED_EVENT,))
 
     def _deregister_event_listeners(self):
         pyatspi.Registry.deregisterEventListener(
@@ -42,17 +48,23 @@ class Caribou:
         pyatspi.Registry.deregisterEventListener(self.on_focus, "focus")
         pyatspi.Registry.deregisterEventListener(
             self.on_text_caret_moved, "object:text-caret-moved")
-        pyatspi.Registry.deregisterKeystrokeListener(
-            self.on_key_down, mask=0, kind=pyatspi.KEY_PRESSED_EVENT)
 
-    def _on_layout_changed(self, client, connection_id, entry, args):
+    def _on_scan_toggled(self, setting, val):
+        if val:
+            self.scan_master.start()
+        else:
+            self.scan_master.stop()
+
+    def _on_layout_changed(self, setting, val):
         self._deregister_event_listeners()
         self.window.destroy()
         self._update_window()
         self._register_event_listeners()
 
     def _update_window(self):
-        self.window = self.window_factory(self.kb_factory())
+        kb = self.kb_factory()
+        self.scan_master.set_keyboard(kb)
+        self.window = self.window_factory(kb)
 
     def _get_a11y_enabled(self):
         try:
@@ -134,7 +146,7 @@ class Caribou:
                         print "leave entry widget in", event.host_application.name
             else:
                 if debug == True:
-                    print _("WARNING - Caribou: unhandled editable widget:"), event.source         
+                    print _("WARNING - Caribou: unhandled editable widget:"), event.source
 
         # Firefox does not report leave entry widget events.
         # This could be a way to get the entry widget leave events.
@@ -143,45 +155,8 @@ class Caribou:
         #        self.window.hide()
         #        print "--> LEAVE EDITABLE TEXT <--"
 
-    def on_key_down(self, event):
-        # key binding for controlling the row column scanning
-        if event.event_string == "Shift_R":
-            # TODO: implement keyboard scanning
-            pass 
-        elif event.event_string == "Control_R":
-            self.clean_exit()
-
-    def signal_handler(self,signal,frame):
-        # Clean exit pressing Control + C
-        self.clean_exit()
-
     def clean_exit(self):
-        if debug == True:
-            print "quitting ..."
-        result = pyatspi.Registry.deregisterEventListener(self.on_text_caret_moved, "object:text-caret-moved")
-        if debug == True:
-            print "deregisterEventListener - object:text-caret-moved ...",
-            if result == False:
-                print "OK"
-            else:
-                print "FAIL"
-        result = pyatspi.Registry.deregisterEventListener(self.on_focus, "object:state-changed:focused")
-        if debug == True:
-            print "deregisterEventListener - object:state-changed:focused ...",
-            if result == False:
-                print "OK"
-            else:
-                print "FAIL"
-        result = pyatspi.Registry.deregisterEventListener(self.on_focus, "focus")
-        if debug == True:
-            print "deregisterEventListener - focus ...",
-            if result == False:
-                print "OK"
-            else:
-                print "FAIL"
-        result = pyatspi.Registry.deregisterKeystrokeListener(self.on_key_down, mask=None, kind=pyatspi.KEY_PRESSED_EVENT)
-        if debug == True:
-            print "deregisterKeystrokeListener"
-        Gtk.main_quit()
+        self.scan_master.stop()
+        self._deregister_event_listeners()
         
         
diff --git a/caribou/ui/scan.py b/caribou/ui/scan.py
index f845903..55feabf 100644
--- a/caribou/ui/scan.py
+++ b/caribou/ui/scan.py
@@ -5,7 +5,7 @@ from gi.repository import Gtk
 import caribou.common.const as const
 from caribou.common.settings_manager import SettingsManager
 
-# Scan constans
+# Scan constants
 BUTTON = 'button'
 ROW = 'row'
 BLOCK = 'block'
@@ -27,400 +27,159 @@ DEFAULT_STEP_TIME = 1000
 DEFAULT_SCANNING_TYPE = ROW
 DEFAULT_SWITCH_TYPE = KEYBOARD_SWITCH_TYPE
 
-class ScanService():
-    def __init__(self, keyboard, root_window):
-        self.keyboard = keyboard
+class ScanMaster():
+    def __init__(self, root_window, keyboard=None):
         self.root_window = root_window
-        self.selected_row = None
-        self.selected_button = None
-        self.button_index = 0
-        self.row_index = 0
-        self.index_i = 0
-        self.index_j = 0
-        self.is_stop = True
-        self.timerid = None
-        self.reverse = False
-        self.selected_block = []
-
-        # Settings we are interested in.
-        for name in ["step_time", "reverse_scanning", "scanning_type"]:
-            getattr(SettingsManager, name).connect("value-changed",
-                                                   self._on_switch_changed)
-
-        for name in ["switch_type", "mouse_button", "keyboard_key"]:
-            getattr(SettingsManager, name).connect("value-changed",
-                                                   self._on_switch_changed)
-        
-        for name in ["default_colors", "normal_color", "mouse_over_color",
-                     "row_scanning_color", "button_scanning_color",
-                     "cancel_scanning_color", "block_scanning_color"]:
-            getattr(SettingsManager, name).connect("value-changed",
-                                                   self._on_color_changed)
-
-        SettingsManager.scan_enabled.connect("value-changed",
-                                             self._on_scan_toggled)
-
-        self._configure_scanning()
-        self._set_colors()
-        self._configure_switch()
-
-    def destroy(self):
-        self.stop()
-        self.clean()
-        self._deregister_events()
-
-
-    def _configure_switch(self):
-        self.switch_type = SettingsManager.switch_type.value
-        if self.switch_type == MOUSE_SWITCH_TYPE:
-            self.switch_key = SettingsManager.mouse_button.value
-        elif self.switch_type == KEYBOARD_SWITCH_TYPE:
-            self.switch_key = SettingsManager.keyboard_key
+        self._timer = 0
+        self._scan_path = None
+        self.started = False
 
-        try:
-            pyatspi.Registry.registerKeystrokeListener(self._on_key_pressed, 
-                                mask=None, kind=(pyatspi.KEY_PRESSED_EVENT,))
-            pyatspi.Registry.registerKeystrokeListener(self._on_key_released, 
-                                mask=None, kind=(pyatspi.KEY_RELEASED_EVENT,))
-        except:
-            print "Error while registering keyboard events in scan.py"
-
-    def _deregister_events(self):
-        try:
-            pyatspi.Registry.deregisterKeystrokeListener(self._on_key_pressed, 
-                                mask=None, kind=pyatspi.KEY_PRESSED_EVENT)
-            pyatspi.Registry.deregisterKeystrokeListener(
-                                self._on_key_released, 
-                                mask=None, kind=pyatspi.KEY_RELEASED_EVENT)
-        except:
-            print "Error while deregistering keyboard events in scan.py"
-
-    def _on_switch_changed(self, settings, val):
-        self._deregister_events()
-        self._configure_switch()
-
-    def _on_scan_toggled(self, settings, val):
-        if val:
-            self.start()
-        else:
-            self.stop()
+        SettingsManager.step_time.connect("value-changed",
+                                          self._on_step_time_changed)
+        SettingsManager.scanning_type.connect("value-changed",
+                                              self._on_scanning_type_changed)
+        if keyboard:
+            self.set_keyboard(keyboard)
 
-    def _on_color_changed(self, settings, val):
-        self._set_colors()
+    def start(self):
+        if self.started: return
 
-    def _on_scanning_type_changed(self, settings, val):
-        self._configure_scanning()
+        if self._timer == 0:
+            self._timer = gobject.timeout_add(
+                int(SettingsManager.step_time.value*1000), self._scan)
 
-    def _configure_scanning(self):
-        if not self.is_stop:
-            self._stop()
-        self.scanning_type = SettingsManager.scanning_type.value
-        self.reverse = SettingsManager.reverse_scanning.value
-        self.step_time = SettingsManager.step_time.value
+        self._grab_mouse_events()
+
+        pyatspi.Registry.registerKeystrokeListener(
+            self._on_key_pressed, mask=0, kind=(pyatspi.KEY_PRESSED_EVENT,))
 
-        if self.scanning_type == BLOCK:
-            self.selected_block = []
-        else:
-            self.selected_block = self.keyboard
-        self.scanning = self.scanning_type
-
-    def _set_colors(self):
-        self.default_colors = SettingsManager.default_colors.value
-        self.normal_color = SettingsManager.normal_color.value
-        self.mouse_over_color = SettingsManager.mouse_over_color.value
-        self.row_scanning_color = SettingsManager.row_scanning_color.value
-        self.button_scanning_color = \
-            SettingsManager.button_scanning_color.value
-        self.cancel_scanning_color = \
-            SettingsManager.cancel_scanning_color.value
-        self.block_scanning_color = SettingsManager.block_scanning_color.value
-
-    # public start
-    def start(self, scanning=None):
-        self.scanning = scanning or self.scanning_type
-        self.clean()
-        if self.root_window and \
-            self.switch_type == MOUSE_SWITCH_TYPE:
-            self._grab_mouse_events()
-
-        if not self.reverse:
-            self.reset(self.scanning)
-
-    # public stop
     def stop(self):
-        if self.switch_type == MOUSE_SWITCH_TYPE:
-            self._ungrab_mouse_events()
-        self.clean()
-        self._stop()
-
-    #private start
-    def _start(self, scanning=ROW):
-        if self.is_stop == True and self.timerid == None:
-            self.is_stop = False
-            self.button_index = -1
-            self.row_index = -1
-            if scanning == ROW:
-                self.selected_row = []
-                self.timerid = gobject.timeout_add(
-                    int(1000*self.step_time), self._scan_row)
-            elif scanning == BUTTON:
-                self.selected_button = None
-                self.timerid = gobject.timeout_add(
-                    int(1000*self.step_time), self._scan_button)
-            elif scanning == BLOCK:
-                self.selected_block = []
-                self.selected_row = []
-                self.clean()
-                self.index_i = 2
-                self.index_j = 1
-                self.timerid = gobject.timeout_add(
-                    int(1000*self.step_time), self._scan_block)
-
-    # private stop
-    def _stop(self):
-        self.is_stop = True
-        if self.timerid:
-            gobject.source_remove(self.timerid)
-            self.timerid = None
-
-    def reset(self, scanning=ROW):
-        self._stop()
-        self._start(scanning)
-
-    def clean(self):
-        for row in self.keyboard:
-            for button in row:
-                self.select_button(button, False)
-
-
-    def change_keyboard(self, keyboard):
-        if not self.is_stop:
-            self._stop()
-        self.keyboard = keyboard
-        self.scanning = self.scanning_type
-        self.start(self.scanning_type)
-        if self.scanning == ROW:
-            self.selected_block = keyboard
+        if self.started: return
 
+        self._ungrab_mouse_events()
 
-    def _grab_mouse_events(self):
-        Gdk.event_handler_set(self._mouse_handler)
+        if self._last_block is not None:
+            self._multi_map(lambda x: x.reset_color(), self._last_block)
 
-    def _ungrab_mouse_events(self):
-        Gdk.event_handler_set(Gtk.main_do_event)
+        if self._timer != 0:
+            gobject.source_remove(self._timer)
+            self._timer = 0
 
-    def _mouse_handler(self, event):
-        if self.root_window.window.is_visible():
-            if event.type == Gdk.EventType.BUTTON_PRESS and \
-                str(event.button) == self.switch_key.value:
-                self._handle_press()
-            elif event.type == Gdk.BUTTON_RELEASE and \
-                str(event.button) == self.switch_key.value:
-                self._handle_release()
-            elif not event.type == Gdk.ENTER_NOTIFY:
-                Gtk.main_do_event(event)
-        else:
-            Gtk.main_do_event(event)
+        pyatspi.Registry.deregisterKeystrokeListener(
+            self._on_key_pressed, mask=0, kind=pyatspi.KEY_PRESSED_EVENT)
 
-    def _scan_block(self):
-        if self.is_stop:
-            return False
-        # Clean the previous block
-        self.select_block(self.selected_block, False)
-        # Update indexes, three horizontal blocks, and two vertical
-        if self.index_j < 2:
-            self.index_j += 1
-        elif self.index_i < 1:
-            self.index_i += 1
-            self.index_j = 0
+    def _on_scanning_type_changed(self, setting, val):
+        layout = self.keyboard.get_current_layout()
+        if SettingsManager.scanning_type.value == ROW:
+            self._blocks = layout.get_scan_rows()
         else:
-            self.index_j = 0
-            self.index_i = 0
-
-        self.selected_block = []
-        #width = self.root_window.size_request()[0]
-        #height = self.root_window.size_request()[1]
-        root_x = self.root_window.get_position()[0]
-        root_y = self.root_window.get_position()[1]
-        offset_w = self.index_j*(width/3)
-        offset_h = self.index_i*(height/2)
-
-        block_window = (root_x + offset_w, 
-                                         root_y + offset_h, 
-                                         width/3, 
-                                         height/2)
-        empty_r = ()
-        try:
-            for row in self.keyboard:
-                line = []
-                for button in row:
-                    abs_b_x = button.get_allocation()[0] + \
-                              button.window.get_position()[0]
-                    abs_b_y = button.get_allocation()[1] + \
-                              button.window.get_position()[1]
-                    abs_b_r = (abs_b_x, 
-                                               abs_b_y,
-                                               button.size_request()[0],
-                                               button.size_request()[1])
-
-            # If button rectangle is inside the block:
-                    intersect = block_window.intersect(abs_b_r)
-                # If the intersected rectangle != empty
-                    if intersect != empty_r:
-                        # If the witdth of intersection is bigger than half 
-                        # of button width and height, we append button to line
-                        if (intersect.width > (abs_b_r.width / 2)) and \
-                           (intersect.height > (abs_b_r.height / 2)):
-                           line.append(button)
-
-
-                if len(line) > 0:
-                    self.selected_block.append(line)
-                    
-        except Exception as e:
-            self.is_stop = True
-            return False
-            
-        self.select_block(self.selected_block, True,
-                           self.block_scanning_color)
-        return True       
-                                               
-
-
-    def _scan_row(self):
-        if self.is_stop:
-            return False
+            self._blocks = layout.get_scan_blocks()
 
+    def _on_step_time_changed(self, setting, val):
+        if self._timer != 0:
+            gobject.source_remove(self._timer)
+            self._timer = gobject.timeout_add(int(1000*val), self._scan)
+
+    def _on_layout_activated(self, keyboard, layout, num):
+        if SettingsManager.scanning_type.value == ROW:
+            self._blocks = layout.get_scan_rows()
         else:
-            self.select_row(self.selected_row, 
-                            self.scanning_type == BLOCK, 
-                            self.block_scanning_color)
-            self.row_index += 1
-            if self.row_index >= len(self.selected_block):
-                self.row_index = 0
-            self.selected_row = self.selected_block[self.row_index]
-            self.select_row(self.selected_row, True, self.row_scanning_color)
-            return True
-
-    def _scan_button(self):
-        if self.scanning == CANCEL:
-            self.scanning = BUTTON
-            self.selected_button = None
-            self.select_row(self.selected_row, True, self.row_scanning_color)
-            return True
+            self._blocks = layout.get_scan_blocks()
+        self._scan_path = [-1]
+
+    def set_keyboard(self, keyboard):
+        self._last_block = None
+        keyboard.connect("switch-page", self._on_layout_activated)
+        self.keyboard = keyboard
+
+    def _multi_map(self, func, array):
+        if isinstance(array, list):
+            for item in array:
+                self._multi_map(func, item)
         else:
-            if self.selected_button and self.selected_button in self.selected_row:
-                self.select_button(self.selected_button, True, self.row_scanning_color)
-
-            if self.is_stop:
-                return False
-
-            self.button_index += 1
-            if self.button_index >= len(self.selected_row):
-                self.select_row(self.selected_row, True, self.cancel_scanning_color)
-                self.button_index = -1
-                self.scanning = CANCEL
-                return True
-
-            self.selected_button = self.selected_row[self.button_index]
-            while self.selected_button.key_type == const.DUMMY_KEY_TYPE:
-                self.button_index += 1
-                if self.button_index >= len(self.selected_row):
-                    self.select_row(self.selected_row, True, self.cancel_scanning_color)
-                    self.button_index = -1
-                    self.scanning = CANCEL
-                    return True
-
-                self.selected_button = self.selected_row[self.button_index]
-            self.select_button(self.selected_button, True, self.button_scanning_color)
-            return True
-
-    def select_block(self, block, state, color=None):
-        for row in block:
-            self.select_row(row, state, color)
-
-    def select_row(self, row, state, color=None):
-        for button in row:
-            self.select_button(button, state, color)
-
-    def select_button(self, button, state, color=None):
-        if state:
-            button.set_color(color, self.mouse_over_color)
-        elif self.default_colors:
-            button.reset_color()
+            func(array)
+
+    def _get_element_at_path(self, array, path):
+        element = array
+        for index in path:
+            element = element[index]
+        return element
+
+    def _get_next_block(self):
+        cancel = False
+        self._scan_path += [self._scan_path.pop() + 1]
+        try:
+            block = self._get_element_at_path(self._blocks,
+                                              self._scan_path)
+        except IndexError:
+            if len(self._scan_path) == 1:
+                block = self._blocks[0]
+                self._scan_path = [0]
+            else:
+                block = self._get_element_at_path(
+                    self._blocks, self._scan_path[:-1])
+                self._scan_path = self._scan_path[:-1] + [-1]
+                cancel = True
+
+        return cancel, block
+
+    def _scan(self):
+        if self._scan_path is None: return True
+
+        if self._last_block is not None:
+            self._multi_map(lambda x: x.reset_color(),
+                                       self._last_block)
+
+        self._cancel, next_block = self._get_next_block()
+
+        color = SettingsManager.button_scanning_color.value
+
+        if self._cancel:
+            color = SettingsManager.cancel_scanning_color.value
+        elif isinstance(next_block, list):
+            if SettingsManager.scanning_type.value == ROW:
+                color = SettingsManager.row_scanning_color.value
+            else:
+                color = SettingsManager.block_scanning_color.value
+
+        self._multi_map(lambda x: x.set_color(color, None), next_block)
+        self._last_block = next_block
+        return True
+
+    def _do_switch(self):
+        if self._cancel:
+            assert(len(self._scan_path) > 1)
+            self._scan_path.pop()
+        elif isinstance(self._last_block, list):
+            assert(len(self._last_block) > 0)
+            self._scan_path.append(-1)
         else:
-            button.set_color(self.normal_color,
-                             self.mouse_over_color)
+            self._last_block.clicked()
 
-    def _on_key_pressed(self, event):
-        if event.event_string == "Escape":
-            SettingsManager.scan_enabled.value = False
-        elif self.switch_type == KEYBOARD_SWITCH_TYPE and \
-             self.switch_key.value == event.event_string:
-            self._handle_press()
-
-    def _on_key_released(self, event):
-        if self.switch_type == KEYBOARD_SWITCH_TYPE and \
-                self.switch_key.value == event.event_string:
-            self._handle_release()
-        elif event.event_string != "Escape": 
-            self._stop()
-            self.start()
-
-    def _handle_press(self):
-        if self.reverse:
-            self._start(self.scanning)
-
-    def _handle_release(self):
-        if self.reverse:
-            if not self.is_stop:
-                if self.scanning == ROW and \
-                        len(self.selected_row) > 0:
-                    self.scanning = BUTTON
-                elif self.scanning == BLOCK and \
-                        len(self.selected_block) > 0:
-                    self.scanning = ROW
-                elif self.scanning == BUTTON and \
-                        self.selected_button:
-                    self.clean()
-                    if self.selected_button.key_type == const.PREFERENCES_KEY_TYPE:
-                        self.stop()
-                    self.selected_button.clicked()
-                    self.selected_button = None
-                    self.scanning = self.scanning_type
-                    self.reset()
-
-                elif self.scanning == CANCEL:
-                    self.clean()
-                    self.scanning = self.scanning_type
-                self._stop()
+    def _grab_mouse_events(self):
+        Gdk.event_handler_set(self._mouse_handler, None)
+
+    def _ungrab_mouse_events(self):
+        Gdk.event_handler_set(Gtk.main_do_event, None)
+
+    def _mouse_handler(self, event, user_data):
+        if SettingsManager.switch_type.value != MOUSE_SWITCH_TYPE or \
+                event.type not in (Gdk.EventType.BUTTON_PRESS,
+                                   Gdk.EventType.ENTER_NOTIFY):
+            Gtk.main_do_event(event)
+            return
 
+        if self.root_window.get_window().is_visible():
+            if event.type == Gdk.EventType.BUTTON_PRESS and \
+                    str(event.button.button) == \
+                    SettingsManager.mouse_button.value:
+                self._do_switch()
+            elif event.type != Gdk.EventType.ENTER_NOTIFY:
+                Gtk.main_do_event(event)
         else:
-            if not self.is_stop:
-                if self.scanning == ROW and \
-                        len(self.selected_row) > 0:
-                    self.scanning = BUTTON
-                    self.reset(BUTTON)
-
-                elif self.scanning == BLOCK and \
-                        len(self.selected_block) > 0:
-                    self.scanning = ROW
-                    self.reset(ROW)
-                elif self.scanning == BUTTON and \
-                        self.selected_button:
-                    self.selected_button.clicked()
-                    self.scanning = ROW
-                    if self.selected_button.key_type \
-                            == const.PREFERENCES_KEY_TYPE:
-                        self.selected_button = None
-                        self.stop()
-                    else: 
-                        self.selected_button = None
-                        self.scanning = self.scanning_type
-
-                elif self.scanning == CANCEL:
-                    self.scanning = self.scanning_type
-                    self.clean()
-                    self.reset(self.scanning_type)
-
-               
+            Gtk.main_do_event(event)
+
+    def _on_key_pressed(self, event):
+        if SettingsManager.switch_type.value == KEYBOARD_SWITCH_TYPE and \
+                SettingsManager.keyboard_key.value == event.event_string:
+            self._do_switch()
diff --git a/caribou/ui/window.py b/caribou/ui/window.py
index 5e45d13..d6739f1 100644
--- a/caribou/ui/window.py
+++ b/caribou/ui/window.py
@@ -21,11 +21,13 @@
 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 
 from caribou import data_path
+from opacity import ProximityWindowBase
+from caribou.common.settings_manager import SettingsManager
+
 from gi.repository import GConf
 from gi.repository import Gtk
 from gi.repository import Gdk
 from gi.repository import Clutter
-from opacity import ProximityWindowBase
 import os
 import sys
 import gobject
@@ -204,8 +206,7 @@ class CaribouWindow(Gtk.Window, Clutter.Animatable, ProximityWindowBase):
         return offset
 
     def _get_keyboard_conf(self):
-        layout = self._gconf_client.get_string(CARIBOU_GCONF_LAYOUT_KEY) \
-            or "qwerty"
+        layout = SettingsManager.layout.value
         conf_file_path = os.path.join(data_path, CARIBOU_LAYOUT_DIR, layout)
 
         if os.path.exists(conf_file_path):



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]