summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Konrath <ben@bagu.org>2009-12-03 15:43:13 -0500
committerBen Konrath <ben@bagu.org>2009-12-03 15:43:13 -0500
commit6b9c16c10aaedea38ec1d9fb8e74aae3311acd12 (patch)
tree4f07647e6f7692648a11c080ce1d1a7555a16f00
parent54ad8c3474e8d9f0232364d4a3b045c68780f6e0 (diff)
downloadcaribou-6b9c16c10aaedea38ec1d9fb8e74aae3311acd12.tar.gz
Separate window placement code from the keyboard code
This leaves the door open for the CaribouWindow to host things besides keyboards - so dasher, namon or any other text entry mechanism.
-rw-r--r--src/caribou.py56
-rw-r--r--src/keyboard.py169
-rw-r--r--src/window.py183
3 files changed, 213 insertions, 195 deletions
diff --git a/src/caribou.py b/src/caribou.py
index b8ebf98..4db0e28 100644
--- a/src/caribou.py
+++ b/src/caribou.py
@@ -20,7 +20,8 @@
import pyatspi
import gtk
-import keyboard
+import gtk.gdk as gdk
+import window
import gettext
import getopt
import sys
@@ -29,7 +30,7 @@ _ = gettext.gettext
debug = False
-class Test:
+class Caribou:
def __init__(self):
self.__current_acc = None
@@ -37,34 +38,35 @@ class Test:
if self.__current_acc == event.source:
self.__set_location(event.source)
if debug == True:
- print "object:text-caret-moved in", event.host_application.name, event.detail1, event.source.description
+ print "object:text-caret-moved in", event.host_application.name,
+ print event.detail1, event.source.description
def __set_text_location(self, acc):
text = acc.queryText()
[x, y, width, height] = text.getCharacterExtents(text.caretOffset, pyatspi.DESKTOP_COORDS)
- cp.set_cursor_location(gtk.gdk.Rectangle(x, y, width, height))
+ caribouwindow.set_cursor_location(gdk.Rectangle(x, y, width, height))
component = acc.queryComponent()
entry_bb = component.getExtents(pyatspi.DESKTOP_COORDS)
- cp.set_entry_location(entry_bb)
- cp.show_all()
+ caribouwindow.set_entry_location(entry_bb)
+ caribouwindow.show_all()
def __set_entry_location(self, acc):
text = acc.queryText()
- cursor_bb = gtk.gdk.Rectangle(
- *text.getCharacterExtents(text.caretOffset,
+ cursor_bb = gdk.Rectangle(
+ *text.getCharacterExtents(text.caretOffset,
pyatspi.DESKTOP_COORDS))
component = acc.queryComponent()
entry_bb = component.getExtents(pyatspi.DESKTOP_COORDS)
- if cursor_bb == gtk.gdk.Rectangle(0, 0, 0, 0):
+ if cursor_bb == gdk.Rectangle(0, 0, 0, 0):
cursor_bb = entry_bb
- cp.set_cursor_location(cursor_bb)
- cp.set_entry_location(entry_bb)
+ caribouwindow.set_cursor_location(cursor_bb)
+ caribouwindow.set_entry_location(entry_bb)
- cp.show_all()
+ caribouwindow.show_all()
def on_state_changed_focused(self, event):
acc = event.source
@@ -77,7 +79,7 @@ class Test:
if debug == True:
print "enter text widget in", event.host_application.name
elif event.detail1 == 0:
- cp.hide_all()
+ caribouwindow.hide_all()
self.__current_acc = None
self.__set_location = None
if debug == True:
@@ -91,7 +93,7 @@ class Test:
if debug == True:
print "enter entry widget in", event.host_application.name
elif event.detail1 == 0:
- cp.hide_all()
+ caribouwindow.hide_all()
self.__current_acc = None
self.__set_location = None
if debug == True:
@@ -103,18 +105,17 @@ class Test:
# This could be a way to get the entry widget leave events.
#else:
# if event.detail1 == 1:
- # cp.hide_all()
+ # caribouwindow.hide_all()
# print "--> LEAVE EDITABLE TEXT <--"
def on_key_down(self, event):
# key binding for controling the row column scanning
- # TODO: needs implementing
if event.event_string == "Shift_R":
+ # TODO: implement keyboard scanning
pass
elif event.event_string == "Control_R":
if debug == True:
print "quitting ..."
- # TODO: use for loop here? see below
result = pyatspi.Registry.deregisterEventListener(self.on_text_caret_moved, "object:text-caret-moved")
if debug == True:
print "deregisterEventListener - object:text-caret-moved ...",
@@ -129,7 +130,7 @@ class Test:
print "OK"
else:
print "FAIL"
- result = pyatspi.Registry.deregisterKeystrokeListener(self.on_key_down, mask = None, kind = (pyatspi.KEY_PRESSED_EVENT,))
+ result = pyatspi.Registry.deregisterKeystrokeListener(self.on_key_down, mask=None, kind=(pyatspi.KEY_PRESSED_EVENT,))
if debug == True:
print "deregisterKeystrokeListener"
gtk.main_quit()
@@ -148,7 +149,8 @@ def usage():
if __name__ == "__main__":
try:
- options, xargs = getopt.getopt(sys.argv[1:], "dhv", ["debug", "help", "version"])
+ options, xargs = getopt.getopt(sys.argv[1:], "dhv",
+ ["debug", "help", "version"])
except getopt.GetoptError, e:
print "Error: " + e.__str__() + "\n"
usage()
@@ -166,18 +168,14 @@ if __name__ == "__main__":
print "caribou @VERSION@"
sys.exit(0)
- test = Test()
- # TODO: make a for loop
- #EVENTS = ["object:state-changed:focused", "object:text-caret-moved"]
- #for f in dir(test):
- # print f, isinstance(f, str)
- pyatspi.Registry.registerEventListener(test.on_state_changed_focused, "object:state-changed:focused")
- pyatspi.Registry.registerEventListener(test.on_text_caret_moved, "object:text-caret-moved")
- pyatspi.Registry.registerKeystrokeListener(test.on_key_down, mask = None, kind = (pyatspi.KEY_PRESSED_EVENT,))
+ caribou = Caribou()
+ pyatspi.Registry.registerEventListener(caribou.on_state_changed_focused, "object:state-changed:focused")
+ pyatspi.Registry.registerEventListener(caribou.on_text_caret_moved, "object:text-caret-moved")
+ pyatspi.Registry.registerKeystrokeListener(caribou.on_key_down, mask=None, kind=(pyatspi.KEY_PRESSED_EVENT,))
# TODO: move text entry detection to its own file
- cp = keyboard.CaribouWindowEntry()
- cp.hide_all()
+ caribouwindow = window.CaribouWindowEntry()
+ caribouwindow.hide_all()
gtk.main()
diff --git a/src/keyboard.py b/src/keyboard.py
index dd55ec0..eb25335 100644
--- a/src/keyboard.py
+++ b/src/keyboard.py
@@ -20,13 +20,8 @@
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import gtk
-import gobject
-import gtk.gdk as gdk
-import pango
import virtkey
-from keyboards import qwerty
-import rsvg
-import cairo
+import window
class CaribouPredicitionArea(gtk.HBox):
pass
@@ -133,167 +128,9 @@ class CaribouKeyboard(gtk.Frame):
self.add(data)
self.show_all()
-class CaribouWindow(gtk.Window):
- __gtype_name__ = "CaribouWindow"
-
- def __init__(self, default_placement=None):
- super(CaribouWindow, self).__init__(gtk.WINDOW_POPUP)
- self.set_name("CaribouWindow")
-
- self._vbox = gtk.VBox()
- self.add(self._vbox)
-
- self._vbox.pack_start(CaribouKeyboard(qwerty))
-
- self.connect("size-allocate", lambda w, a: self._update_position())
-
- self._cursor_location = gtk.gdk.Rectangle()
- self._entry_location = gtk.gdk.Rectangle()
- self._default_placement = default_placement or \
- CaribouKeyboardPlacement()
-
- def set_cursor_location(self, cursor_location):
- self._cursor_location = cursor_location
- self._update_position()
-
- def set_entry_location(self, entry_location):
- self._entry_location = entry_location
- self._update_position()
-
- def set_default_placement(self, default_placement):
- self._default_placement = default_placement
- self._update_position()
-
- def _get_root_bbox(self):
- root_window = gdk.get_default_root_window()
- args = root_window.get_position() + root_window.get_size()
- return gdk.Rectangle(*args)
-
- def _calculate_position(self, placement=None):
- root_bbox = self._get_root_bbox()
- placement = placement or self._default_placement
-
- x = self._calculate_axis(placement.x, root_bbox)
- y = self._calculate_axis(placement.y, root_bbox)
-
-
- return x, y
-
- def _update_position(self):
- x, y = self._calculate_position()
- root_bbox = self._get_root_bbox()
- proposed_position = \
- gdk.Rectangle(x, y, self.allocation.width, self.allocation.height)
-
- x += self._default_placement.x.adjust_to_bounds(root_bbox, proposed_position)
- y += self._default_placement.y.adjust_to_bounds(root_bbox, proposed_position)
- self.move(x, y)
-
- def _calculate_axis(self, axis_placement, root_bbox):
- bbox = root_bbox
-
- if axis_placement.stickto == CaribouKeyboardPlacement.CURSOR:
- bbox = self._cursor_location
- elif axis_placement.stickto == CaribouKeyboardPlacement.ENTRY:
- bbox = self._entry_location
-
- offset = axis_placement.get_offset(bbox)
-
- if axis_placement.align == CaribouKeyboardPlacement.END:
- offset += axis_placement.get_length(bbox)
- if axis_placement.gravitate == CaribouKeyboardPlacement.INSIDE:
- offset -= axis_placement.get_length(self.allocation)
- elif axis_placement.align == CaribouKeyboardPlacement.START:
- if axis_placement.gravitate == CaribouKeyboardPlacement.OUTSIDE:
- offset -= axis_placement.get_length(self.allocation)
- elif axis_placement.align == CaribouKeyboardPlacement.CENTER:
- offset += axis_placement.get_length(bbox)/2
-
- return offset
-
-class CaribouWindowEntry(CaribouWindow):
- __gtype_name__ = "CaribouWindowEntry"
-
- def __init__(self):
- placement = CaribouKeyboardPlacement(
- xalign=CaribouKeyboardPlacement.START,
- xstickto=CaribouKeyboardPlacement.ENTRY,
- ystickto=CaribouKeyboardPlacement.ENTRY,
- xgravitate=CaribouKeyboardPlacement.INSIDE,
- ygravitate=CaribouKeyboardPlacement.OUTSIDE)
-
- CaribouWindow.__init__(self, placement)
-
- def _calculate_axis(self, axis_placement, root_bbox):
- offset = CaribouWindow._calculate_axis(self, axis_placement, root_bbox)
-
- if axis_placement.axis == 'y':
- if offset + self.allocation.height > root_bbox.height + root_bbox.y:
- new_axis_placement = axis_placement.copy(align=CaribouKeyboardPlacement.START)
- offset = CaribouWindow._calculate_axis(self, new_axis_placement, root_bbox)
-
- return offset
-
-class CaribouKeyboardPlacement(object):
- START = 'start'
- END = 'end'
- CENTER = 'center'
-
- SCREEN = 'screen'
- ENTRY = 'entry'
- CURSOR = 'cursor'
-
- INSIDE = 'inside'
- OUTSIDE = 'outside'
-
- class _AxisPlacement(object):
- def __init__(self, axis, align, stickto, gravitate):
- self.axis = axis
- self.align = align
- self.stickto = stickto
- self.gravitate = gravitate
-
- def copy(self, align=None, stickto=None, gravitate=None):
- return self.__class__(self.axis,
- align or self.align,
- stickto or self.stickto,
- gravitate or self.gravitate)
-
- def get_offset(self, bbox):
- return bbox.x if self.axis == 'x' else bbox.y
-
- def get_length(self, bbox):
- return bbox.width if self.axis == 'x' else bbox.height
-
- def adjust_to_bounds(self, root_bbox, child_bbox):
- child_vector_start = self.get_offset(child_bbox)
- child_vector_end = self.get_length(child_bbox) + child_vector_start
- root_vector_start = self.get_offset(root_bbox)
- root_vector_end = self.get_length(root_bbox) + root_vector_start
-
- if root_vector_end < child_vector_end:
- return root_vector_end - child_vector_end
-
- if root_vector_start > child_vector_start:
- return root_vector_start - child_vector_start
-
- return 0
-
-
- def __init__(self,
- xalign=None, xstickto=None, xgravitate=None,
- yalign=None, ystickto=None, ygravitate=None):
- self.x = self._AxisPlacement('x',
- xalign or self.END,
- xstickto or self.CURSOR,
- xgravitate or self.OUTSIDE)
- self.y = self._AxisPlacement('y',
- yalign or self.END,
- ystickto or self.CURSOR,
- ygravitate or self.OUTSIDE)
if __name__ == "__main__":
- ckbd = CaribouWindow()
- ckbd.show_all()
+ window = window.CaribouWindow()
+ window.show_all()
gtk.main()
diff --git a/src/window.py b/src/window.py
new file mode 100644
index 0000000..cb0dbef
--- /dev/null
+++ b/src/window.py
@@ -0,0 +1,183 @@
+# -*- coding: utf-8 -*-
+#
+# Carbou - text entry and UI navigation application
+#
+# Copyright (C) 2009 Eitan Isaacson <eitan@monotonous.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by the
+# Free Software Foundation; either version 2.1 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 Lesser General Public License
+# for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+import gtk
+import gtk.gdk as gdk
+import keyboard
+from keyboards import qwerty
+
+class CaribouWindow(gtk.Window):
+ __gtype_name__ = "CaribouWindow"
+
+ def __init__(self, default_placement=None):
+ super(CaribouWindow, self).__init__(gtk.WINDOW_POPUP)
+ self.set_name("CaribouWindow")
+
+ self._vbox = gtk.VBox()
+ self.add(self._vbox)
+
+ self._vbox.pack_start(keyboard.CaribouKeyboard(qwerty))
+
+ self.connect("size-allocate", lambda w, a: self._update_position())
+
+ self._cursor_location = gdk.Rectangle()
+ self._entry_location = gdk.Rectangle()
+ self._default_placement = default_placement or \
+ CaribouWindowPlacement()
+
+ def set_cursor_location(self, cursor_location):
+ self._cursor_location = cursor_location
+ self._update_position()
+
+ def set_entry_location(self, entry_location):
+ self._entry_location = entry_location
+ self._update_position()
+
+ def set_default_placement(self, default_placement):
+ self._default_placement = default_placement
+ self._update_position()
+
+ def _get_root_bbox(self):
+ root_window = gdk.get_default_root_window()
+ args = root_window.get_position() + root_window.get_size()
+ return gdk.Rectangle(*args)
+
+ def _calculate_position(self, placement=None):
+ root_bbox = self._get_root_bbox()
+ placement = placement or self._default_placement
+
+ x = self._calculate_axis(placement.x, root_bbox)
+ y = self._calculate_axis(placement.y, root_bbox)
+
+ return x, y
+
+ def _update_position(self):
+ x, y = self._calculate_position()
+ root_bbox = self._get_root_bbox()
+ proposed_position = \
+ gdk.Rectangle(x, y, self.allocation.width, self.allocation.height)
+
+ x += self._default_placement.x.adjust_to_bounds(root_bbox, proposed_position)
+ y += self._default_placement.y.adjust_to_bounds(root_bbox, proposed_position)
+ self.move(x, y)
+
+ def _calculate_axis(self, axis_placement, root_bbox):
+ bbox = root_bbox
+
+ if axis_placement.stickto == CaribouWindowPlacement.CURSOR:
+ bbox = self._cursor_location
+ elif axis_placement.stickto == CaribouWindowPlacement.ENTRY:
+ bbox = self._entry_location
+
+ offset = axis_placement.get_offset(bbox)
+
+ if axis_placement.align == CaribouWindowPlacement.END:
+ offset += axis_placement.get_length(bbox)
+ if axis_placement.gravitate == CaribouWindowPlacement.INSIDE:
+ offset -= axis_placement.get_length(self.allocation)
+ elif axis_placement.align == CaribouWindowPlacement.START:
+ if axis_placement.gravitate == CaribouWindowPlacement.OUTSIDE:
+ offset -= axis_placement.get_length(self.allocation)
+ elif axis_placement.align == CaribouWindowPlacement.CENTER:
+ offset += axis_placement.get_length(bbox)/2
+
+ return offset
+
+class CaribouWindowEntry(CaribouWindow):
+ __gtype_name__ = "CaribouWindowEntry"
+
+ def __init__(self):
+ placement = CaribouWindowPlacement(
+ xalign=CaribouWindowPlacement.START,
+ xstickto=CaribouWindowPlacement.ENTRY,
+ ystickto=CaribouWindowPlacement.ENTRY,
+ xgravitate=CaribouWindowPlacement.INSIDE,
+ ygravitate=CaribouWindowPlacement.OUTSIDE)
+
+ CaribouWindow.__init__(self, placement)
+
+ def _calculate_axis(self, axis_placement, root_bbox):
+ offset = CaribouWindow._calculate_axis(self, axis_placement, root_bbox)
+
+ if axis_placement.axis == 'y':
+ if offset + self.allocation.height > root_bbox.height + root_bbox.y:
+ new_axis_placement = axis_placement.copy(align=CaribouWindowPlacement.START)
+ offset = CaribouWindow._calculate_axis(self, new_axis_placement, root_bbox)
+
+ return offset
+
+class CaribouWindowPlacement(object):
+ START = 'start'
+ END = 'end'
+ CENTER = 'center'
+
+ SCREEN = 'screen'
+ ENTRY = 'entry'
+ CURSOR = 'cursor'
+
+ INSIDE = 'inside'
+ OUTSIDE = 'outside'
+
+ class _AxisPlacement(object):
+ def __init__(self, axis, align, stickto, gravitate):
+ self.axis = axis
+ self.align = align
+ self.stickto = stickto
+ self.gravitate = gravitate
+
+ def copy(self, align=None, stickto=None, gravitate=None):
+ return self.__class__(self.axis,
+ align or self.align,
+ stickto or self.stickto,
+ gravitate or self.gravitate)
+
+ def get_offset(self, bbox):
+ return bbox.x if self.axis == 'x' else bbox.y
+
+ def get_length(self, bbox):
+ return bbox.width if self.axis == 'x' else bbox.height
+
+ def adjust_to_bounds(self, root_bbox, child_bbox):
+ child_vector_start = self.get_offset(child_bbox)
+ child_vector_end = self.get_length(child_bbox) + child_vector_start
+ root_vector_start = self.get_offset(root_bbox)
+ root_vector_end = self.get_length(root_bbox) + root_vector_start
+
+ if root_vector_end < child_vector_end:
+ return root_vector_end - child_vector_end
+
+ if root_vector_start > child_vector_start:
+ return root_vector_start - child_vector_start
+
+ return 0
+
+
+ def __init__(self,
+ xalign=None, xstickto=None, xgravitate=None,
+ yalign=None, ystickto=None, ygravitate=None):
+ self.x = self._AxisPlacement('x',
+ xalign or self.END,
+ xstickto or self.CURSOR,
+ xgravitate or self.OUTSIDE)
+ self.y = self._AxisPlacement('y',
+ yalign or self.END,
+ ystickto or self.CURSOR,
+ ygravitate or self.OUTSIDE)
+