Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--services/clipboard/ClipboardService.py82
-rw-r--r--services/nm/bubble.py216
-rw-r--r--services/nm/nmclient.py1584
-rw-r--r--services/nm/nminfo.py786
-rw-r--r--services/nm/wepkeydialog.py80
-rw-r--r--services/presence/Activity.py298
-rw-r--r--services/presence/Buddy.py942
-rw-r--r--services/presence/BuddyIconCache.py98
-rw-r--r--services/presence/PresenceService.py1614
-rw-r--r--services/presence/Service.py1080
-rwxr-xr-xshell/console/console.py2
-rw-r--r--shell/console/logviewer.py96
-rw-r--r--shell/console/memphis.py334
-rwxr-xr-xshell/console/plugin.py76
-rw-r--r--shell/console/plugins/clean_size/__init__.py20
-rw-r--r--shell/console/plugins/clean_size/info.py10
-rw-r--r--shell/console/plugins/cpu/__init__.py24
-rw-r--r--shell/console/plugins/cpu/info.py64
-rw-r--r--shell/console/plugins/dirty_size/__init__.py20
-rw-r--r--shell/console/plugins/dirty_size/info.py12
-rw-r--r--shell/console/plugins/memphis_init/__init__.py20
-rw-r--r--shell/console/plugins/memphis_init/info.py6
-rw-r--r--shell/console/procmem/analysis.py46
-rw-r--r--shell/console/procmem/proc.py172
-rw-r--r--shell/console/procmem/proc_smaps.py214
-rw-r--r--shell/console/terminal.py266
-rw-r--r--shell/model/BuddyModel.py238
-rw-r--r--shell/model/Friends.py116
-rw-r--r--shell/model/Invites.py52
-rw-r--r--shell/model/MeshModel.py264
-rw-r--r--shell/model/Owner.py174
-rw-r--r--shell/model/ShellModel.py58
-rw-r--r--shell/view/ActivityHost.py230
-rw-r--r--shell/view/BuddyIcon.py76
-rw-r--r--shell/view/BuddyMenu.py138
-rw-r--r--shell/view/ClipboardIcon.py56
-rw-r--r--shell/view/ClipboardMenu.py82
-rw-r--r--shell/view/FirstTimeDialog.py72
-rw-r--r--shell/view/OverlayWindow.py56
-rw-r--r--shell/view/Shell.py406
-rw-r--r--shell/view/dconmanager.py32
-rw-r--r--shell/view/frame/ActivitiesBox.py134
-rw-r--r--shell/view/frame/ClipboardBox.py60
-rw-r--r--shell/view/frame/Frame.py442
-rw-r--r--shell/view/frame/FriendsBox.py164
-rw-r--r--shell/view/frame/PanelWindow.py34
-rw-r--r--shell/view/frame/ZoomBox.py160
-rw-r--r--shell/view/frame/notificationtray.py20
-rw-r--r--shell/view/frame/overlaybox.py18
-rw-r--r--shell/view/frame/shutdownicon.py34
-rw-r--r--shell/view/home/FriendView.py104
-rw-r--r--shell/view/home/FriendsBox.py56
-rw-r--r--shell/view/home/HomeBox.py32
-rw-r--r--shell/view/home/HomeWindow.py68
-rw-r--r--shell/view/home/MeshBox.py168
-rw-r--r--shell/view/home/MyIcon.py6
-rw-r--r--shell/view/home/activitiesdonut.py140
-rw-r--r--shell/view/stylesheet.py40
-rw-r--r--sugar/TracebackUtils.py50
-rw-r--r--sugar/activity/Activity.py248
-rw-r--r--sugar/activity/ActivityFactory.py96
-rw-r--r--sugar/activity/__init__.py10
-rw-r--r--sugar/activity/bundle.py160
-rw-r--r--sugar/activity/bundlebuilder.py176
-rw-r--r--sugar/activity/bundleregistry.py86
-rw-r--r--sugar/chat/ActivityChat.py74
-rw-r--r--sugar/chat/Chat.py482
-rw-r--r--sugar/chat/ChatEditor.py140
-rw-r--r--sugar/chat/ChatToolbar.py252
-rw-r--r--sugar/chat/Emoticons.py120
-rw-r--r--sugar/chat/GroupChat.py20
-rw-r--r--sugar/chat/richtext.py832
-rw-r--r--sugar/chat/sketchpad/Sketch.py66
-rw-r--r--sugar/chat/sketchpad/SketchPad.py170
-rw-r--r--sugar/chat/sketchpad/Toolbox.py94
-rw-r--r--sugar/clipboard/ClipboardService.py118
-rw-r--r--sugar/emulator.py184
-rw-r--r--sugar/env.py48
-rw-r--r--sugar/graphics/ClipboardBubble.py210
-rw-r--r--sugar/graphics/bubble.py84
-rw-r--r--sugar/graphics/canvasicon.py240
-rw-r--r--sugar/graphics/grid.py24
-rw-r--r--sugar/graphics/iconcolor.py40
-rw-r--r--sugar/graphics/menu.py124
-rw-r--r--sugar/graphics/menuicon.py82
-rw-r--r--sugar/graphics/menushell.py160
-rw-r--r--sugar/graphics/snowflakebox.py100
-rw-r--r--sugar/graphics/spreadbox.py152
-rw-r--r--sugar/graphics/style.py24
-rw-r--r--sugar/graphics/stylesheet.py24
-rw-r--r--sugar/graphics/timeline.py182
-rw-r--r--sugar/logger.py118
-rw-r--r--sugar/p2p/MostlyReliablePipe.py2546
-rw-r--r--sugar/p2p/NotificationListener.py30
-rw-r--r--sugar/p2p/Notifier.py14
-rw-r--r--sugar/p2p/Stream.py242
-rw-r--r--sugar/p2p/network.py574
-rw-r--r--sugar/presence/Activity.py190
-rw-r--r--sugar/presence/Buddy.py340
-rw-r--r--sugar/presence/PresenceService.py394
-rw-r--r--sugar/presence/Service.py186
-rw-r--r--sugar/profile.py36
-rw-r--r--sugar/simulator.py226
-rw-r--r--sugar/util.py62
-rw-r--r--tests/bundle/Test.activity/testactivity.py4
-rw-r--r--tests/simulator/demo/others.py20
-rw-r--r--tests/sketch/sketchactivity.py386
-rwxr-xr-xtests/test-snowflake-box.py22
-rwxr-xr-xtests/test-spread-box.py10
-rw-r--r--tests/test-window-manager.py18
110 files changed, 11091 insertions, 11091 deletions
diff --git a/services/clipboard/ClipboardService.py b/services/clipboard/ClipboardService.py
index 7389c58..d8a151d 100644
--- a/services/clipboard/ClipboardService.py
+++ b/services/clipboard/ClipboardService.py
@@ -24,53 +24,53 @@ from sugar import env
class ClipboardDBusServiceHelper(dbus.service.Object):
- _CLIPBOARD_DBUS_INTERFACE = "org.laptop.Clipboard"
- _CLIPBOARD_OBJECT_PATH = "/org/laptop/Clipboard"
+ _CLIPBOARD_DBUS_INTERFACE = "org.laptop.Clipboard"
+ _CLIPBOARD_OBJECT_PATH = "/org/laptop/Clipboard"
- def __init__(self, parent):
- self._parent = parent
+ def __init__(self, parent):
+ self._parent = parent
- bus = dbus.SessionBus()
- bus_name = dbus.service.BusName(self._CLIPBOARD_DBUS_INTERFACE, bus=bus)
- dbus.service.Object.__init__(self, bus_name, self._CLIPBOARD_OBJECT_PATH)
-
- @dbus.service.method(_CLIPBOARD_DBUS_INTERFACE,
- in_signature="sss", out_signature="")
- def add_object(self, name, mimeType, fileName):
- self.object_added(name, mimeType, fileName)
- logging.debug('Added object of type ' + mimeType + ' with path at ' + fileName)
+ bus = dbus.SessionBus()
+ bus_name = dbus.service.BusName(self._CLIPBOARD_DBUS_INTERFACE, bus=bus)
+ dbus.service.Object.__init__(self, bus_name, self._CLIPBOARD_OBJECT_PATH)
+
+ @dbus.service.method(_CLIPBOARD_DBUS_INTERFACE,
+ in_signature="sss", out_signature="")
+ def add_object(self, name, mimeType, fileName):
+ self.object_added(name, mimeType, fileName)
+ logging.debug('Added object of type ' + mimeType + ' with path at ' + fileName)
- @dbus.service.method(_CLIPBOARD_DBUS_INTERFACE,
- in_signature="s", out_signature="")
- def delete_object(self, fileName):
- self.object_deleted(fileName)
- logging.debug('Deleted object with path at ' + fileName)
-
- @dbus.service.method(_CLIPBOARD_DBUS_INTERFACE,
- in_signature="si", out_signature="")
- def set_object_state(self, fileName, percent):
- logging.debug('Changed object with path at ' + fileName + ' with percent ' + str(percent))
- self.object_state_changed(fileName, percent)
+ @dbus.service.method(_CLIPBOARD_DBUS_INTERFACE,
+ in_signature="s", out_signature="")
+ def delete_object(self, fileName):
+ self.object_deleted(fileName)
+ logging.debug('Deleted object with path at ' + fileName)
+
+ @dbus.service.method(_CLIPBOARD_DBUS_INTERFACE,
+ in_signature="si", out_signature="")
+ def set_object_state(self, fileName, percent):
+ logging.debug('Changed object with path at ' + fileName + ' with percent ' + str(percent))
+ self.object_state_changed(fileName, percent)
- @dbus.service.signal(_CLIPBOARD_DBUS_INTERFACE, signature="sss")
- def object_added(self, name, mimeType, fileName):
- pass
+ @dbus.service.signal(_CLIPBOARD_DBUS_INTERFACE, signature="sss")
+ def object_added(self, name, mimeType, fileName):
+ pass
- @dbus.service.signal(_CLIPBOARD_DBUS_INTERFACE, signature="s")
- def object_deleted(self, fileName):
- pass
+ @dbus.service.signal(_CLIPBOARD_DBUS_INTERFACE, signature="s")
+ def object_deleted(self, fileName):
+ pass
- @dbus.service.signal(_CLIPBOARD_DBUS_INTERFACE, signature="si")
- def object_state_changed(self, fileName, percent):
- pass
+ @dbus.service.signal(_CLIPBOARD_DBUS_INTERFACE, signature="si")
+ def object_state_changed(self, fileName, percent):
+ pass
class ClipboardService(object):
- def __init__(self):
- self._dbus_helper = ClipboardDBusServiceHelper(self)
+ def __init__(self):
+ self._dbus_helper = ClipboardDBusServiceHelper(self)
- def run(self):
- loop = gobject.MainLoop()
- try:
- loop.run()
- except KeyboardInterrupt:
- print 'Ctrl+C pressed, exiting...'
+ def run(self):
+ loop = gobject.MainLoop()
+ try:
+ loop.run()
+ except KeyboardInterrupt:
+ print 'Ctrl+C pressed, exiting...'
diff --git a/services/nm/bubble.py b/services/nm/bubble.py
index 24e68ab..bb44cd0 100644
--- a/services/nm/bubble.py
+++ b/services/nm/bubble.py
@@ -22,111 +22,111 @@ import gtk
import hippo
class Bubble(hippo.CanvasBox, hippo.CanvasItem):
- __gtype_name__ = 'NetworkBubble'
-
- __gproperties__ = {
- 'fill-color': (object, None, None,
- gobject.PARAM_READWRITE),
- 'stroke-color': (object, None, None,
- gobject.PARAM_READWRITE),
- 'progress-color': (object, None, None,
- gobject.PARAM_READWRITE),
- 'percent' : (object, None, None,
- gobject.PARAM_READWRITE),
- }
-
- def __init__(self, **kwargs):
- self._stroke_color = 0xFFFFFFFF
- self._fill_color = 0xFFFFFFFF
- self._progress_color = 0x000000FF
- self._percent = 0
- self._radius = 8
-
- hippo.CanvasBox.__init__(self, **kwargs)
-
- def do_set_property(self, pspec, value):
- if pspec.name == 'fill-color':
- self._fill_color = value
- self.emit_paint_needed(0, 0, -1, -1)
- elif pspec.name == 'stroke-color':
- self._stroke_color = value
- self.emit_paint_needed(0, 0, -1, -1)
- elif pspec.name == 'progress-color':
- self._progress_color = value
- self.emit_paint_needed(0, 0, -1, -1)
- elif pspec.name == 'percent':
- self._percent = value
- self.emit_paint_needed(0, 0, -1, -1)
-
- def do_get_property(self, pspec):
- if pspec.name == 'fill-color':
- return self._fill_color
- elif pspec.name == 'stroke-color':
- return self._stroke_color
- elif pspec.name == 'progress-color':
- return self._progress_color
- elif pspec.name == 'percent':
- return self._percent
-
- def _int_to_rgb(self, int_color):
- red = (int_color >> 24) & 0x000000FF
- green = (int_color >> 16) & 0x000000FF
- blue = (int_color >> 8) & 0x000000FF
- alpha = int_color & 0x000000FF
- return (red / 255.0, green / 255.0, blue / 255.0)
-
- def do_paint_below_children(self, cr, damaged_box):
- [width, height] = self.get_allocation()
-
- line_width = 3.0
- x = line_width
- y = line_width
- width -= line_width * 2
- height -= line_width * 2
-
- cr.move_to(x + self._radius, y);
- cr.arc(x + width - self._radius, y + self._radius,
- self._radius, math.pi * 1.5, math.pi * 2);
- cr.arc(x + width - self._radius, x + height - self._radius,
- self._radius, 0, math.pi * 0.5);
- cr.arc(x + self._radius, y + height - self._radius,
- self._radius, math.pi * 0.5, math.pi);
- cr.arc(x + self._radius, y + self._radius, self._radius,
- math.pi, math.pi * 1.5);
-
- color = self._int_to_rgb(self._fill_color)
- cr.set_source_rgb(*color)
- cr.fill_preserve();
-
- color = self._int_to_rgb(self._stroke_color)
- cr.set_source_rgb(*color)
- cr.set_line_width(line_width)
- cr.stroke();
-
- if self._percent > 0:
- self._paint_progress_bar(cr, x, y, width, height, line_width)
-
- def _paint_progress_bar(self, cr, x, y, width, height, line_width):
- prog_x = x + line_width
- prog_y = y + line_width
- prog_width = (width - (line_width * 2)) * (self._percent / 100.0)
- prog_height = (height - (line_width * 2))
-
- x = prog_x
- y = prog_y
- width = prog_width
- height = prog_height
-
- cr.move_to(x + self._radius, y);
- cr.arc(x + width - self._radius, y + self._radius,
- self._radius, math.pi * 1.5, math.pi * 2);
- cr.arc(x + width - self._radius, x + height - self._radius,
- self._radius, 0, math.pi * 0.5);
- cr.arc(x + self._radius, y + height - self._radius,
- self._radius, math.pi * 0.5, math.pi);
- cr.arc(x + self._radius, y + self._radius, self._radius,
- math.pi, math.pi * 1.5);
-
- color = self._int_to_rgb(self._progress_color)
- cr.set_source_rgb(*color)
- cr.fill_preserve();
+ __gtype_name__ = 'NetworkBubble'
+
+ __gproperties__ = {
+ 'fill-color': (object, None, None,
+ gobject.PARAM_READWRITE),
+ 'stroke-color': (object, None, None,
+ gobject.PARAM_READWRITE),
+ 'progress-color': (object, None, None,
+ gobject.PARAM_READWRITE),
+ 'percent' : (object, None, None,
+ gobject.PARAM_READWRITE),
+ }
+
+ def __init__(self, **kwargs):
+ self._stroke_color = 0xFFFFFFFF
+ self._fill_color = 0xFFFFFFFF
+ self._progress_color = 0x000000FF
+ self._percent = 0
+ self._radius = 8
+
+ hippo.CanvasBox.__init__(self, **kwargs)
+
+ def do_set_property(self, pspec, value):
+ if pspec.name == 'fill-color':
+ self._fill_color = value
+ self.emit_paint_needed(0, 0, -1, -1)
+ elif pspec.name == 'stroke-color':
+ self._stroke_color = value
+ self.emit_paint_needed(0, 0, -1, -1)
+ elif pspec.name == 'progress-color':
+ self._progress_color = value
+ self.emit_paint_needed(0, 0, -1, -1)
+ elif pspec.name == 'percent':
+ self._percent = value
+ self.emit_paint_needed(0, 0, -1, -1)
+
+ def do_get_property(self, pspec):
+ if pspec.name == 'fill-color':
+ return self._fill_color
+ elif pspec.name == 'stroke-color':
+ return self._stroke_color
+ elif pspec.name == 'progress-color':
+ return self._progress_color
+ elif pspec.name == 'percent':
+ return self._percent
+
+ def _int_to_rgb(self, int_color):
+ red = (int_color >> 24) & 0x000000FF
+ green = (int_color >> 16) & 0x000000FF
+ blue = (int_color >> 8) & 0x000000FF
+ alpha = int_color & 0x000000FF
+ return (red / 255.0, green / 255.0, blue / 255.0)
+
+ def do_paint_below_children(self, cr, damaged_box):
+ [width, height] = self.get_allocation()
+
+ line_width = 3.0
+ x = line_width
+ y = line_width
+ width -= line_width * 2
+ height -= line_width * 2
+
+ cr.move_to(x + self._radius, y);
+ cr.arc(x + width - self._radius, y + self._radius,
+ self._radius, math.pi * 1.5, math.pi * 2);
+ cr.arc(x + width - self._radius, x + height - self._radius,
+ self._radius, 0, math.pi * 0.5);
+ cr.arc(x + self._radius, y + height - self._radius,
+ self._radius, math.pi * 0.5, math.pi);
+ cr.arc(x + self._radius, y + self._radius, self._radius,
+ math.pi, math.pi * 1.5);
+
+ color = self._int_to_rgb(self._fill_color)
+ cr.set_source_rgb(*color)
+ cr.fill_preserve();
+
+ color = self._int_to_rgb(self._stroke_color)
+ cr.set_source_rgb(*color)
+ cr.set_line_width(line_width)
+ cr.stroke();
+
+ if self._percent > 0:
+ self._paint_progress_bar(cr, x, y, width, height, line_width)
+
+ def _paint_progress_bar(self, cr, x, y, width, height, line_width):
+ prog_x = x + line_width
+ prog_y = y + line_width
+ prog_width = (width - (line_width * 2)) * (self._percent / 100.0)
+ prog_height = (height - (line_width * 2))
+
+ x = prog_x
+ y = prog_y
+ width = prog_width
+ height = prog_height
+
+ cr.move_to(x + self._radius, y);
+ cr.arc(x + width - self._radius, y + self._radius,
+ self._radius, math.pi * 1.5, math.pi * 2);
+ cr.arc(x + width - self._radius, x + height - self._radius,
+ self._radius, 0, math.pi * 0.5);
+ cr.arc(x + self._radius, y + height - self._radius,
+ self._radius, math.pi * 0.5, math.pi);
+ cr.arc(x + self._radius, y + self._radius, self._radius,
+ math.pi, math.pi * 1.5);
+
+ color = self._int_to_rgb(self._progress_color)
+ cr.set_source_rgb(*color)
+ cr.fill_preserve();
diff --git a/services/nm/nmclient.py b/services/nm/nmclient.py
index 9d96a2a..055b4ba 100644
--- a/services/nm/nmclient.py
+++ b/services/nm/nmclient.py
@@ -40,15 +40,15 @@ IW_AUTH_ALG_SHARED_KEY = 0x00000002
NM_DEVICE_STAGE_STRINGS=("Unknown",
- "Prepare",
- "Config",
- "Need Users Key",
- "IP Config",
- "IP Config Get",
- "IP Config Commit",
- "Activated",
- "Failed",
- "Cancled"
+ "Prepare",
+ "Config",
+ "Need Users Key",
+ "IP Config",
+ "IP Config Get",
+ "IP Config Commit",
+ "Activated",
+ "Failed",
+ "Cancled"
)
NM_SERVICE = 'org.freedesktop.NetworkManager'
@@ -70,278 +70,278 @@ sys_bus = dbus.SystemBus()
class Network(gobject.GObject):
- __gsignals__ = {
- 'init-failed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([]))
- }
-
- def __init__(self, op):
- gobject.GObject.__init__(self)
- self._op = op
- self._ssid = None
- self._mode = None
- self._strength = 0
- self._valid = False
-
- obj = sys_bus.get_object(NM_SERVICE, self._op)
- net = dbus.Interface(obj, NM_IFACE_DEVICES)
- net.getProperties(reply_handler=self._update_reply_cb,
- error_handler=self._update_error_cb)
-
- def _update_reply_cb(self, *props):
- self._ssid = props[1]
- self._strength = props[3]
- self._mode = props[6]
- self._valid = True
- logging.debug("Net(%s): ssid '%s', mode %d, strength %d" % (self._op,
- self._ssid, self._mode, self._strength))
-
- def _update_error_cb(self, err):
- logging.debug("Net(%s): failed to update. (%s)" % (self._op, err))
- self._valid = False
- self.emit('init-failed')
-
- def get_ssid(self):
- return self._ssid
-
- def get_op(self):
- return self._op
-
- def get_strength(self):
- return self._strength
-
- def set_strength(self, strength):
- self._strength = strength
-
- def is_valid(self):
- return self._valid
-
- def add_to_menu(self, menu, callback, dev):
- strength = self._strength
- if strength > 100:
- strength = 100
- elif strength < 0:
- strength = 0
- item = NetworkMenuItem(text=self._ssid, percent=strength)
- item.connect('button-press-event', callback, (dev, self))
- menu.add_item(item)
+ __gsignals__ = {
+ 'init-failed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([]))
+ }
+
+ def __init__(self, op):
+ gobject.GObject.__init__(self)
+ self._op = op
+ self._ssid = None
+ self._mode = None
+ self._strength = 0
+ self._valid = False
+
+ obj = sys_bus.get_object(NM_SERVICE, self._op)
+ net = dbus.Interface(obj, NM_IFACE_DEVICES)
+ net.getProperties(reply_handler=self._update_reply_cb,
+ error_handler=self._update_error_cb)
+
+ def _update_reply_cb(self, *props):
+ self._ssid = props[1]
+ self._strength = props[3]
+ self._mode = props[6]
+ self._valid = True
+ logging.debug("Net(%s): ssid '%s', mode %d, strength %d" % (self._op,
+ self._ssid, self._mode, self._strength))
+
+ def _update_error_cb(self, err):
+ logging.debug("Net(%s): failed to update. (%s)" % (self._op, err))
+ self._valid = False
+ self.emit('init-failed')
+
+ def get_ssid(self):
+ return self._ssid
+
+ def get_op(self):
+ return self._op
+
+ def get_strength(self):
+ return self._strength
+
+ def set_strength(self, strength):
+ self._strength = strength
+
+ def is_valid(self):
+ return self._valid
+
+ def add_to_menu(self, menu, callback, dev):
+ strength = self._strength
+ if strength > 100:
+ strength = 100
+ elif strength < 0:
+ strength = 0
+ item = NetworkMenuItem(text=self._ssid, percent=strength)
+ item.connect('button-press-event', callback, (dev, self))
+ menu.add_item(item)
class Device(gobject.GObject):
- __gsignals__ = {
- 'init-failed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([])),
- 'activated': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([])),
- 'strength-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT]))
- }
-
- def __init__(self, op):
- gobject.GObject.__init__(self)
- self._op = op
- self._iface = None
- self._type = DEVICE_TYPE_UNKNOWN
- self._udi = None
- self._active = False
- self._strength = 0
- self._link = False
- self._valid = False
- self._networks = {}
- self._active_net = None
- self._caps = 0
-
- obj = sys_bus.get_object(NM_SERVICE, self._op)
- dev = dbus.Interface(obj, NM_IFACE_DEVICES)
- dev.getProperties(reply_handler=self._update_reply_cb,
- error_handler=self._update_error_cb)
-
- def _update_reply_cb(self, *props):
- self._iface = props[1]
- self._type = props[2]
- self._udi = props[3]
- self._active = props[4]
- if self._active:
- self.emit('activated')
- self._link = props[15]
- self._caps = props[17]
-
- if self._type == DEVICE_TYPE_802_11_WIRELESS:
- old_strength = self._strength
- self._strength = props[14]
- if self._strength != old_strength:
- self.emit('strength-changed', self._strength)
- self._update_networks(props[20], props[19])
-
- self._valid = True
-
- def _update_networks(self, net_ops, active_op):
- for op in net_ops:
- net = Network(op)
- self._networks[op] = net
- net.connect('init-failed', self._net_init_failed)
- if op == active_op:
- self._active_net = op
-
- def _update_error_cb(self, err):
- logging.debug("Device(%s): failed to update. (%s)" % (self._op, err))
- self._valid = False
- self.emit('init-failed')
-
- def _net_init_failed(self, net):
- net_op = net.get_op()
- if not self._networks.has_key(net_op):
- return
- if net_op == self._active_net:
- self._active_net = None
- del self._networks[net_op]
-
- def _add_to_menu_wired(self, menu, callback):
- item = NetworkMenuItem(_("Wired Network"), stylesheet="nm.Bubble.Wired",
- hi_stylesheet="nm.Bubble.Wired.Hi",
- act_stylesheet="nm.Bubble.Wired.Activated")
- item.connect('button-press-event', callback, (self, None))
- menu.add_item(item)
-
- def _add_to_menu_wireless(self, menu, callback, active_only):
- act_net = None
- if self._active_net and self._networks.has_key(self._active_net):
- act_net = self._networks[self._active_net]
-
- # Only add the active network if active_only == True
- if active_only:
- if act_net:
- act_net.add_to_menu(menu, callback, self)
- return
-
- # Otherwise, add all networks _except_ the active one
- for net in self._networks.values():
- if not net.is_valid():
- continue
- if act_net == net:
- continue
- net.add_to_menu(menu, callback, self)
-
- def add_to_menu(self, menu, callback, active_only=False):
- if self._type == DEVICE_TYPE_802_3_ETHERNET:
- self._add_to_menu_wired(menu, callback)
- elif self._type == DEVICE_TYPE_802_11_WIRELESS:
- self._add_to_menu_wireless(menu, callback, active_only)
-
- def get_op(self):
- return self._op
-
- def get_network(self, op):
- if self._networks.has_key(op):
- return self._networks[op]
- return None
-
- def get_network_ops(self):
- return self._networks.keys()
-
- def get_strength(self):
- return self._strength
-
- def set_strength(self, strength):
- if strength == self._strength:
- return False
-
- if strength >= 0 and strength <= 100:
- self._strength = strength
- else:
- self._strength = 0
-
- self.emit('strength-changed', self._strength)
-
- def network_appeared(self, network):
- if self._networks.has_key(network):
- return
- net = Network(network)
- self._networks[network] = net
- net.connect('init-failed', self._net_init_failed)
-
- def network_disappeared(self, network):
- if not self._networks.has_key(network):
- return
- if network == self._active_net:
- self._active_net = None
- del self._networks[network]
-
- def get_active(self):
- return self._active
-
- def set_active(self, active, ssid=None):
- self._active = active
- if self._type == DEVICE_TYPE_802_11_WIRELESS:
- if not ssid:
- self._active_net = None
- else:
- for (op, net) in self._networks.items():
- if net.get_ssid() == ssid:
- self._active_net = op
-
- def get_type(self):
- return self._type
-
- def is_valid(self):
- return self._valid
-
- def set_carrier(self, on):
- self._link = on
-
- def get_capabilities(self):
- return self._caps
+ __gsignals__ = {
+ 'init-failed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([])),
+ 'activated': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([])),
+ 'strength-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT]))
+ }
+
+ def __init__(self, op):
+ gobject.GObject.__init__(self)
+ self._op = op
+ self._iface = None
+ self._type = DEVICE_TYPE_UNKNOWN
+ self._udi = None
+ self._active = False
+ self._strength = 0
+ self._link = False
+ self._valid = False
+ self._networks = {}
+ self._active_net = None
+ self._caps = 0
+
+ obj = sys_bus.get_object(NM_SERVICE, self._op)
+ dev = dbus.Interface(obj, NM_IFACE_DEVICES)
+ dev.getProperties(reply_handler=self._update_reply_cb,
+ error_handler=self._update_error_cb)
+
+ def _update_reply_cb(self, *props):
+ self._iface = props[1]
+ self._type = props[2]
+ self._udi = props[3]
+ self._active = props[4]
+ if self._active:
+ self.emit('activated')
+ self._link = props[15]
+ self._caps = props[17]
+
+ if self._type == DEVICE_TYPE_802_11_WIRELESS:
+ old_strength = self._strength
+ self._strength = props[14]
+ if self._strength != old_strength:
+ self.emit('strength-changed', self._strength)
+ self._update_networks(props[20], props[19])
+
+ self._valid = True
+
+ def _update_networks(self, net_ops, active_op):
+ for op in net_ops:
+ net = Network(op)
+ self._networks[op] = net
+ net.connect('init-failed', self._net_init_failed)
+ if op == active_op:
+ self._active_net = op
+
+ def _update_error_cb(self, err):
+ logging.debug("Device(%s): failed to update. (%s)" % (self._op, err))
+ self._valid = False
+ self.emit('init-failed')
+
+ def _net_init_failed(self, net):
+ net_op = net.get_op()
+ if not self._networks.has_key(net_op):
+ return
+ if net_op == self._active_net:
+ self._active_net = None
+ del self._networks[net_op]
+
+ def _add_to_menu_wired(self, menu, callback):
+ item = NetworkMenuItem(_("Wired Network"), stylesheet="nm.Bubble.Wired",
+ hi_stylesheet="nm.Bubble.Wired.Hi",
+ act_stylesheet="nm.Bubble.Wired.Activated")
+ item.connect('button-press-event', callback, (self, None))
+ menu.add_item(item)
+
+ def _add_to_menu_wireless(self, menu, callback, active_only):
+ act_net = None
+ if self._active_net and self._networks.has_key(self._active_net):
+ act_net = self._networks[self._active_net]
+
+ # Only add the active network if active_only == True
+ if active_only:
+ if act_net:
+ act_net.add_to_menu(menu, callback, self)
+ return
+
+ # Otherwise, add all networks _except_ the active one
+ for net in self._networks.values():
+ if not net.is_valid():
+ continue
+ if act_net == net:
+ continue
+ net.add_to_menu(menu, callback, self)
+
+ def add_to_menu(self, menu, callback, active_only=False):
+ if self._type == DEVICE_TYPE_802_3_ETHERNET:
+ self._add_to_menu_wired(menu, callback)
+ elif self._type == DEVICE_TYPE_802_11_WIRELESS:
+ self._add_to_menu_wireless(menu, callback, active_only)
+
+ def get_op(self):
+ return self._op
+
+ def get_network(self, op):
+ if self._networks.has_key(op):
+ return self._networks[op]
+ return None
+
+ def get_network_ops(self):
+ return self._networks.keys()
+
+ def get_strength(self):
+ return self._strength
+
+ def set_strength(self, strength):
+ if strength == self._strength:
+ return False
+
+ if strength >= 0 and strength <= 100:
+ self._strength = strength
+ else:
+ self._strength = 0
+
+ self.emit('strength-changed', self._strength)
+
+ def network_appeared(self, network):
+ if self._networks.has_key(network):
+ return
+ net = Network(network)
+ self._networks[network] = net
+ net.connect('init-failed', self._net_init_failed)
+
+ def network_disappeared(self, network):
+ if not self._networks.has_key(network):
+ return
+ if network == self._active_net:
+ self._active_net = None
+ del self._networks[network]
+
+ def get_active(self):
+ return self._active
+
+ def set_active(self, active, ssid=None):
+ self._active = active
+ if self._type == DEVICE_TYPE_802_11_WIRELESS:
+ if not ssid:
+ self._active_net = None
+ else:
+ for (op, net) in self._networks.items():
+ if net.get_ssid() == ssid:
+ self._active_net = op
+
+ def get_type(self):
+ return self._type
+
+ def is_valid(self):
+ return self._valid
+
+ def set_carrier(self, on):
+ self._link = on
+
+ def get_capabilities(self):
+ return self._caps
nm_bubble_wireless = {
- 'fill-color' : 0x646464FF,
- 'stroke-color' : 0x646464FF,
- 'progress-color': 0x333333FF,
- 'spacing' : style.space_unit,
- 'padding' : style.space_unit * 1.5
+ 'fill-color' : 0x646464FF,
+ 'stroke-color' : 0x646464FF,
+ 'progress-color': 0x333333FF,
+ 'spacing' : style.space_unit,
+ 'padding' : style.space_unit * 1.5
}
nm_bubble_wireless_hi = {
- 'fill-color' : 0x979797FF,
- 'stroke-color' : 0x979797FF,
- 'progress-color': 0x666666FF,
- 'spacing' : style.space_unit,
- 'padding' : style.space_unit * 1.5
+ 'fill-color' : 0x979797FF,
+ 'stroke-color' : 0x979797FF,
+ 'progress-color': 0x666666FF,
+ 'spacing' : style.space_unit,
+ 'padding' : style.space_unit * 1.5
}
nm_bubble_wireless_activated = {
- 'fill-color' : 0xA7A7A7FF,
- 'stroke-color' : 0xA7A7A7FF,
- 'progress-color': 0x777777FF,
- 'spacing' : style.space_unit,
- 'padding' : style.space_unit * 1.5
+ 'fill-color' : 0xA7A7A7FF,
+ 'stroke-color' : 0xA7A7A7FF,
+ 'progress-color': 0x777777FF,
+ 'spacing' : style.space_unit,
+ 'padding' : style.space_unit * 1.5
}
nm_bubble_wired = {
- 'fill-color' : 0x000000FF,
- 'stroke-color' : 0x000000FF,
- 'progress-color': 0x000000FF,
- 'spacing' : style.space_unit,
- 'padding' : style.space_unit * 1.5
+ 'fill-color' : 0x000000FF,
+ 'stroke-color' : 0x000000FF,
+ 'progress-color': 0x000000FF,
+ 'spacing' : style.space_unit,
+ 'padding' : style.space_unit * 1.5
}
nm_bubble_wired_hi = {
- 'fill-color' : 0x333333FF,
- 'stroke-color' : 0x333333FF,
- 'progress-color': 0x000000FF,
- 'spacing' : style.space_unit,
- 'padding' : style.space_unit * 1.5
+ 'fill-color' : 0x333333FF,
+ 'stroke-color' : 0x333333FF,
+ 'progress-color': 0x000000FF,
+ 'spacing' : style.space_unit,
+ 'padding' : style.space_unit * 1.5
}
nm_bubble_wired_activated = {
- 'fill-color' : 0x444444FF,
- 'stroke-color' : 0x444444FF,
- 'progress-color': 0x000000FF,
- 'spacing' : style.space_unit,
- 'padding' : style.space_unit * 1.5
+ 'fill-color' : 0x444444FF,
+ 'stroke-color' : 0x444444FF,
+ 'progress-color': 0x000000FF,
+ 'spacing' : style.space_unit,
+ 'padding' : style.space_unit * 1.5
}
nm_menu_item_title = {
- 'xalign': hippo.ALIGNMENT_START,
- 'padding-left': 5,
- 'color' : 0xFFFFFFFF,
- 'font' : style.get_font_description('Bold', 1.2)
+ 'xalign': hippo.ALIGNMENT_START,
+ 'padding-left': 5,
+ 'color' : 0xFFFFFFFF,
+ 'font' : style.get_font_description('Bold', 1.2)
}
@@ -354,63 +354,63 @@ style.register_stylesheet("nm.Bubble.Wired.Activated", nm_bubble_wired_activated
style.register_stylesheet("nm.MenuItem.Title", nm_menu_item_title)
class NetworkMenuItem(Bubble):
- def __init__(self, text, percent=0, stylesheet="nm.Bubble.Wireless",
- hi_stylesheet="nm.Bubble.Wireless.Hi",
- act_stylesheet="nm.Bubble.Wireless.Activated"):
- Bubble.__init__(self, percent=percent)
- self._hover = False
- self._default_stylesheet = stylesheet
- self._hi_stylesheet = hi_stylesheet
- self._act_stylesheet = act_stylesheet
- style.apply_stylesheet(self, stylesheet)
-
- text_item = hippo.CanvasText(text=text)
- style.apply_stylesheet(text_item, 'nm.MenuItem.Title')
- self.append(text_item)
-
- self.connect('motion-notify-event', self._motion_notify_event_cb)
- # Disable active hilight for now...
- #self.connect('button-press-event', self._button_press_event_cb)
-
- def _motion_notify_event_cb(self, widget, event):
- if event.detail == hippo.MOTION_DETAIL_ENTER:
- if not self._hover:
- self._hover = True
- style.apply_stylesheet(self, self._hi_stylesheet)
- elif event.detail == hippo.MOTION_DETAIL_LEAVE:
- if self._hover:
- self._hover = False
- style.apply_stylesheet(self, self._default_stylesheet)
- return True
-
- def _button_press_event_cb(self, widget, event):
- style.apply_stylesheet(self, self._act_stylesheet)
- return False
+ def __init__(self, text, percent=0, stylesheet="nm.Bubble.Wireless",
+ hi_stylesheet="nm.Bubble.Wireless.Hi",
+ act_stylesheet="nm.Bubble.Wireless.Activated"):
+ Bubble.__init__(self, percent=percent)
+ self._hover = False
+ self._default_stylesheet = stylesheet
+ self._hi_stylesheet = hi_stylesheet
+ self._act_stylesheet = act_stylesheet
+ style.apply_stylesheet(self, stylesheet)
+
+ text_item = hippo.CanvasText(text=text)
+ style.apply_stylesheet(text_item, 'nm.MenuItem.Title')
+ self.append(text_item)
+
+ self.connect('motion-notify-event', self._motion_notify_event_cb)
+ # Disable active hilight for now...
+ #self.connect('button-press-event', self._button_press_event_cb)
+
+ def _motion_notify_event_cb(self, widget, event):
+ if event.detail == hippo.MOTION_DETAIL_ENTER:
+ if not self._hover:
+ self._hover = True
+ style.apply_stylesheet(self, self._hi_stylesheet)
+ elif event.detail == hippo.MOTION_DETAIL_LEAVE:
+ if self._hover:
+ self._hover = False
+ style.apply_stylesheet(self, self._default_stylesheet)
+ return True
+
+ def _button_press_event_cb(self, widget, event):
+ style.apply_stylesheet(self, self._act_stylesheet)
+ return False
class NetworkMenu(gtk.Window):
- __gsignals__ = {
- 'action': (gobject.SIGNAL_RUN_FIRST,
- gobject.TYPE_NONE, ([int])),
- }
+ __gsignals__ = {
+ 'action': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([int])),
+ }
- def __init__(self):
- gtk.Window.__init__(self, gtk.WINDOW_POPUP)
+ def __init__(self):
+ gtk.Window.__init__(self, gtk.WINDOW_POPUP)
- canvas = hippo.Canvas()
- self.add(canvas)
- canvas.show()
+ canvas = hippo.Canvas()
+ self.add(canvas)
+ canvas.show()
- self._root = hippo.CanvasBox()
- style.apply_stylesheet(self._root, 'menu')
- canvas.set_root(self._root)
+ self._root = hippo.CanvasBox()
+ style.apply_stylesheet(self._root, 'menu')
+ canvas.set_root(self._root)
- def add_separator(self):
- separator = hippo.CanvasBox()
- style.apply_stylesheet(separator, 'menu.Separator')
- self._root.append(separator)
+ def add_separator(self):
+ separator = hippo.CanvasBox()
+ style.apply_stylesheet(separator, 'menu.Separator')
+ self._root.append(separator)
- def add_item(self, item):
- self._root.append(item)
+ def add_item(self, item):
+ self._root.append(item)
@@ -429,488 +429,488 @@ ICON_WIRELESS_61_80 = "stock-net-wireless-61-80"
ICON_WIRELESS_81_100 = "stock-net-wireless-81-100"
class NMClientApp:
- def __init__(self):
- self.nminfo = None
- self._nm_present = False
- self._nm_state = NM_STATE_UNKNOWN
- self._update_timer = 0
- self._active_device = None
- self._devices = {}
- self._key_dialog = None
-
- self._icon_theme = gtk.icon_theme_get_default()
- self._icons = {}
- self._cur_icon = None
- try:
- self._icons = self._load_icons()
- except RuntimeError:
- logging.debug("Couldn't find required icon resources, will exit.")
- os._exit(1)
- self._setup_trayicon()
-
- self._menu = None
- self._hover_menu = False
- self._timeline = Timeline(self)
- self._timeline.add_tag('popup', 6, 6)
- self._timeline.add_tag('before_popdown', 7, 7)
- self._timeline.add_tag('popdown', 8, 8)
-
- try:
- self.nminfo = nminfo.NMInfo(self)
- except RuntimeError:
- pass
- self._setup_dbus()
- if self._nm_present:
- self._get_nm_state()
- self._get_initial_devices()
-
- def _get_one_icon_pixbuf(self, name):
- info = self._icon_theme.lookup_icon(name, 75, 0)
- if not info or not info.get_filename():
- raise RuntimeError
- return gtk.gdk.pixbuf_new_from_file(info.get_filename())
-
- def _load_icons(self):
- icons = {}
- icons[ICON_WIRED] = self._get_one_icon_pixbuf(ICON_WIRED)
- icons[ICON_WIRELESS_00] = self._get_one_icon_pixbuf(ICON_WIRELESS_00)
- icons[ICON_WIRELESS_01_20] = self._get_one_icon_pixbuf(ICON_WIRELESS_01_20)
- icons[ICON_WIRELESS_21_40] = self._get_one_icon_pixbuf(ICON_WIRELESS_21_40)
- icons[ICON_WIRELESS_41_60] = self._get_one_icon_pixbuf(ICON_WIRELESS_41_60)
- icons[ICON_WIRELESS_61_80] = self._get_one_icon_pixbuf(ICON_WIRELESS_61_80)
- icons[ICON_WIRELESS_81_100] = self._get_one_icon_pixbuf(ICON_WIRELESS_81_100)
- return icons
-
- def _get_nm_state(self):
- # Grab NM's state
- self._nm_obj.state(reply_handler=self._get_state_reply_cb, \
- error_handler=self._get_state_error_cb)
-
- def _get_state_reply_cb(self, state):
- if self._nm_state != state:
- self._schedule_icon_update(immediate=True)
- self._nm_state = state
-
- def _get_state_error_cb(self, err):
- logging.debug("Failed to get NetworkManager state! %s" % err)
-
- def _get_icon(self):
- act_dev = None
- if self._active_device and self._devices.has_key(self._active_device):
- act_dev = self._devices[self._active_device]
-
- pixbuf = None
- if not self._nm_present \
- or not act_dev \
- or self._nm_state == NM_STATE_UNKNOWN \
- or self._nm_state == NM_STATE_ASLEEP \
- or self._nm_state == NM_STATE_DISCONNECTED:
- pixbuf = self._icons[ICON_WIRELESS_00]
- elif act_dev.get_type() == DEVICE_TYPE_802_3_ETHERNET:
- pixbuf = self._icons[ICON_WIRED]
- elif act_dev.get_type() == DEVICE_TYPE_802_11_WIRELESS:
- strength = act_dev.get_strength()
- if strength <= 0:
- pixbuf = self._icons[ICON_WIRELESS_00]
- elif strength >= 1 and strength <= 20:
- pixbuf = self._icons[ICON_WIRELESS_01_20]
- elif strength >= 21 and strength <= 40:
- pixbuf = self._icons[ICON_WIRELESS_21_40]
- elif strength >= 41 and strength <= 60:
- pixbuf = self._icons[ICON_WIRELESS_41_60]
- elif strength >= 61 and strength <= 80:
- pixbuf = self._icons[ICON_WIRELESS_61_80]
- elif strength >= 81 and strength:
- pixbuf = self._icons[ICON_WIRELESS_81_100]
-
- if not pixbuf:
- pixbuf = self._icons[ICON_WIRELESS_00]
- return pixbuf
-
- def _setup_trayicon(self):
- pixbuf = self._get_icon()
- self._trayicon = gtk.status_icon_new_from_pixbuf(pixbuf)
- self._trayicon.connect("popup_menu", self._status_icon_clicked)
- self._trayicon.connect("activate", self._status_icon_clicked)
- self._schedule_icon_update()
-
- def _status_icon_clicked(self, button=0, time=None):
- self._timeline.play(None, 'popup')
-
- def _get_menu_position(self, menu, item):
- (screen, rect, orientation) = item.get_geometry()
- [item_x, item_y, item_w, item_h] = rect
- [menu_w, menu_h] = menu.size_request()
-
- x = item_x + item_w - menu_w
- y = item_y + item_h
-
- x = min(x, screen.get_width() - menu_w)
- x = max(0, x)
-
- y = min(y, screen.get_height() - menu_h)
- y = max(0, y)
-
- return (x, y)
-
- def do_popup(self, current, n_frames):
- if self._menu:
- return
-
- self._menu = self._create_menu()
- self._menu.connect('enter-notify-event',
- self._menu_enter_notify_event_cb)
- self._menu.connect('leave-notify-event',
- self._menu_leave_notify_event_cb)
- (x, y) = self._get_menu_position(self._menu, self._trayicon)
- self._menu.move(x, y)
- self._menu.show_all()
-
- def do_popdown(self, current, frame):
- if self._menu:
- self._menu.destroy()
- self._menu = None
-
- def _popdown(self):
- self._timeline.play('popdown', 'popdown')
-
- def _menu_enter_notify_event_cb(self, widget, event):
- self._hover_menu = True
- self._timeline.play('popup', 'popup')
-
- def _menu_leave_notify_event_cb(self, widget, event):
- self._hover_menu = False
- self._popdown()
-
- def _create_menu(self):
- menu = NetworkMenu()
-
- # Active device goes above the separator
- act_dev = None
- if self._active_device and self._devices.has_key(self._active_device):
- act_dev = self._devices[self._active_device]
-
- if act_dev:
- act_dev.add_to_menu(menu, self._menu_item_clicked_cb, active_only=True)
- menu.add_separator()
-
- # Wired devices first, if they don't support carrier detect
- for dev in self._devices.values():
- if not dev.is_valid():
- continue
- if dev.get_type() != DEVICE_TYPE_802_3_ETHERNET:
- continue
- if dev.get_capabilities() & NM_DEVICE_CAP_CARRIER_DETECT:
- continue
- if dev == act_dev:
- continue
- dev.add_to_menu(menu, self._menu_item_clicked_cb)
-
- # Wireless devices second
- for dev in self._devices.values():
- if not dev.is_valid():
- continue
- if dev.get_type() != DEVICE_TYPE_802_11_WIRELESS:
- continue
- dev.add_to_menu(menu, self._menu_item_clicked_cb)
-
- return menu
-
- def _update_icon(self):
- pixbuf = self._get_icon()
- if self._cur_icon != pixbuf:
- self._trayicon.set_from_pixbuf(pixbuf)
- self._cur_icon = pixbuf
-
- blink = False
- if self._nm_state == NM_STATE_CONNECTING:
- blink = True
- self._trayicon.set_blinking(blink)
-
- self._update_timer = 0
- return False
-
- def _schedule_icon_update(self, immediate=False):
- if immediate and self._update_timer:
- gobject.source_remove(self._update_timer)
- self._update_timer = 0
-
- if self._update_timer != 0:
- # There is already an update scheduled
- return
-
- if immediate:
- self._update_timer = gobject.idle_add(self._update_icon)
- else:
- self._update_timer = gobject.timeout_add(2000, self._update_icon)
-
- def _get_initial_devices_reply_cb(self, ops):
- for op in ops:
- self._add_device(op)
-
- def _dev_init_failed_cb(self, dev):
- # Device failed to initialize, likely due to dbus errors or something
- op = dev.get_op()
- self._remove_device(op)
-
- def _get_initial_devices_error_cb(self, err):
- logging.debug("Error updating devices (%s)" % err)
-
- def _get_initial_devices(self):
- self._nm_obj.getDevices(reply_handler=self._get_initial_devices_reply_cb, \
- error_handler=self._get_initial_devices_error_cb)
-
- def _add_device(self, dev_op):
- if self._devices.has_key(dev_op):
- return
- dev = Device(dev_op)
- self._devices[dev_op] = dev
- dev.connect('init-failed', self._dev_init_failed_cb)
- dev.connect('activated', self._dev_activated_cb)
- dev.connect('strength-changed', self._dev_strength_changed_cb)
-
- def _remove_device(self, dev_op):
- if not self._devices.has_key(dev_op):
- return
- if self._active_device == dev_op:
- self._active_device = None
- dev = self._devices[dev_op]
- dev.disconnect('activated')
- dev.disconnect('init-failed')
- dev.disconnect('strength-changed')
- del self._devices[dev_op]
- self._schedule_icon_update(immediate=True)
-
- def _dev_activated_cb(self, dev):
- op = dev.get_op()
- if not self._devices.has_key(op):
- return
- if not dev.get_active():
- return
- self._active_device = op
- self._schedule_icon_update(immediate=True)
-
- def _dev_strength_changed_cb(self, dev, strength):
- op = dev.get_op()
- if not self._devices.has_key(op):
- return
- if not dev.get_active():
- return
- self._schedule_icon_update()
-
- def get_device(self, dev_op):
- if not self._devices.has_key(dev_op):
- return None
- return self._devices[dev_op]
-
- def _setup_dbus(self):
- self._sig_handlers = {
- 'StateChange': self.state_change_sig_handler,
- 'DeviceAdded': self.device_added_sig_handler,
- 'DeviceRemoved': self.device_removed_sig_handler,
- 'DeviceActivationStage': self.device_activation_stage_sig_handler,
- 'DeviceActivating': self.device_activating_sig_handler,
- 'DeviceNowActive': self.device_now_active_sig_handler,
- 'DeviceNoLongerActive': self.device_no_longer_active_sig_handler,
- 'DeviceCarrierOn': self.device_carrier_on_sig_handler,
- 'DeviceCarrierOff': self.device_carrier_off_sig_handler,
- 'DeviceStrengthChanged': self.wireless_device_strength_changed_sig_handler,
- 'WirelessNetworkAppeared': self.wireless_network_appeared_sig_handler,
- 'WirelessNetworkDisappeared': self.wireless_network_disappeared_sig_handler,
- 'WirelessNetworkStrengthChanged': self.wireless_network_strength_changed_sig_handler
- }
-
- self._nm_proxy = sys_bus.get_object(NM_SERVICE, NM_PATH)
- self._nm_obj = dbus.Interface(self._nm_proxy, NM_IFACE)
-
- sys_bus.add_signal_receiver(self.name_owner_changed_sig_handler,
- signal_name="NameOwnerChanged",
- dbus_interface="org.freedesktop.DBus")
-
- sys_bus.add_signal_receiver(self.catchall_signal_handler,
- dbus_interface=NM_IFACE)
-
- sys_bus.add_signal_receiver(self.catchall_signal_handler,
- dbus_interface=NM_IFACE + 'Devices')
-
- for (signal, handler) in self._sig_handlers.items():
- sys_bus.add_signal_receiver(handler, signal_name=signal, dbus_interface=NM_IFACE)
-
- # Find out whether or not NM is running
- try:
- bus_object = sys_bus.get_object('org.freedesktop.DBus', '/org/freedesktop/DBus')
- name = bus_object.GetNameOwner("org.freedesktop.NetworkManagerInfo", \
- dbus_interface='org.freedesktop.DBus')
- if name:
- self._nm_present = True
- except dbus.DBusException:
- pass
-
- @dbus.decorators.explicitly_pass_message
- def catchall_signal_handler(self, *args, **keywords):
- dbus_message = keywords['dbus_message']
- mem = dbus_message.get_member()
- iface = dbus_message.get_interface()
-
- if iface == NM_IFACE and mem in self._sig_handlers.keys():
- return
-
- logging.debug('Caught signal %s.%s' % (dbus_message.get_interface(), mem))
- for arg in args:
- logging.debug(' ' + str(arg))
-
- def _menu_item_clicked_cb(self, widget, event, dev_data):
- (device, network) = dev_data
- net_op = ""
- if network:
- net_op = network.get_op()
- try:
- # NM 0.6.4 and earlier have a bug which returns an
- # InvalidArguments error if no security information is passed
- # for wireless networks
- self._nm_obj.setActiveDevice(device.get_op(), network.get_ssid())
- except dbus.DBusException, e:
- if str(e).find("invalid arguments"):
- pass
- else:
- raise dbus.DBusException(e)
-
- self._popdown()
-
- def get_key_for_network(self, net, async_cb, async_err_cb):
- # Throw up a dialog asking for the key here, and set
- # the authentication algorithm to the given one, if any
- #
- # Key needs to be limited to _either_ 10 or 26 digits long,
- # and contain _only_ _hex_ digits, 0-9 or a-f
- #
- # Auth algorithm should be a dropdown of: [Open System, Shared Key],
- # mapping to the values [IW_AUTH_ALG_OPEN_SYSTEM, IW_AUTH_ALG_SHARED_KEY]
- # above
-
- self._key_dialog = WEPKeyDialog(net, async_cb, async_err_cb)
- self._key_dialog.connect("response", self._key_dialog_response_cb)
- self._key_dialog.connect("destroy", self._key_dialog_destroy_cb)
- self._key_dialog.show_all()
-
- def _key_dialog_destroy_cb(self, widget, foo=None):
- if widget != self._key_dialog:
- return
- self._key_dialog_response_cb(widget, gtk.RESPONSE_CANCEL)
-
- def _key_dialog_response_cb(self, widget, response_id):
- if widget != self._key_dialog:
- return
- key = self._key_dialog.get_key()
- wep_auth_alg = self._key_dialog.get_auth_alg()
- net = self._key_dialog.get_network()
- (async_cb, async_err_cb) = self._key_dialog.get_callbacks()
-
- # Clear self._key_dialog before we call destroy(), otherwise
- # the destroy will trigger and we'll get called again by
- # self._key_dialog_destroy_cb
- self._key_dialog = None
- widget.destroy()
-
- if response_id == gtk.RESPONSE_OK:
- self.nminfo.get_key_for_network_cb(
- net, key, wep_auth_alg, async_cb, async_err_cb, canceled=False)
- else:
- self.nminfo.get_key_for_network_cb(
- net, None, None, async_cb, async_err_cb, canceled=True)
-
- def cancel_get_key_for_network(self):
- # Close the wireless key dialog and just have it return
- # with the 'canceled' argument set to true
- if not self._key_dialog:
- return
- self._key_dialog_destroy_cb(self._key_dialog)
-
- def device_activation_stage_sig_handler(self, device, stage):
- logging.debug('Device Activation Stage "%s" for device %s' % (NM_DEVICE_STAGE_STRINGS[stage], device))
-
- def state_change_sig_handler(self, state):
- self._nm_state = state
- self._schedule_icon_update(immediate=True)
-
- def device_activating_sig_handler(self, device):
- self._active_device = device
-
- def device_now_active_sig_handler(self, device, ssid=None):
- if not self._devices.has_key(device):
- return
- self._active_device = device
- self._devices[device].set_active(True, ssid)
- self._schedule_icon_update(immediate=True)
-
- def device_no_longer_active_sig_handler(self, device):
- if not self._devices.has_key(device):
- return
- if self._active_device == device:
- self._active_device = None
- self._devices[device].set_active(False)
- self._schedule_icon_update(immediate=True)
-
- def name_owner_changed_sig_handler(self, name, old, new):
- if name != NM_SERVICE:
- return
- if (old and len(old)) and (not new and not len(new)):
- # NM went away
- self._nm_present = False
- self._schedule_icon_update(immediate=True)
- for op in self._devices.keys():
- del self._devices[op]
- self._devices = {}
- self._active_device = None
- self._nm_state = NM_STATE_UNKNOWN
- elif (not old and not len(old)) and (new and len(new)):
- # NM started up
- self._nm_present = True
- self._get_nm_state()
- self._get_initial_devices()
-
- def device_added_sig_handler(self, device):
- self._add_device(device)
-
- def device_removed_sig_handler(self, device):
- self._remove_device(device)
-
- def wireless_network_appeared_sig_handler(self, device, network):
- if not self._devices.has_key(device):
- return
- self._devices[device].network_appeared(network)
-
- def wireless_network_disappeared_sig_handler(self, device, network):
- if not self._devices.has_key(device):
- return
- self._devices[device].network_disappeared(network)
-
- def wireless_device_strength_changed_sig_handler(self, device, strength):
- if not self._devices.has_key(device):
- return
- self._devices[device].set_strength(strength)
-
- def wireless_network_strength_changed_sig_handler(self, device, network, strength):
- if not self._devices.has_key(device):
- return
- net = self._devices[device].get_network(network)
- if net:
- net.set_strength(strength)
-
- def device_carrier_on_sig_handler(self, device):
- if not self._devices.has_key(device):
- return
- self._devices[device].set_carrier(True)
-
- def device_carrier_off_sig_handler(self, device):
- if not self._devices.has_key(device):
- return
- self._devices[device].set_carrier(False)
-
- def run(self):
- loop = gobject.MainLoop()
- try:
- loop.run()
- except KeyboardInterrupt:
- pass
+ def __init__(self):
+ self.nminfo = None
+ self._nm_present = False
+ self._nm_state = NM_STATE_UNKNOWN
+ self._update_timer = 0
+ self._active_device = None
+ self._devices = {}
+ self._key_dialog = None
+
+ self._icon_theme = gtk.icon_theme_get_default()
+ self._icons = {}
+ self._cur_icon = None
+ try:
+ self._icons = self._load_icons()
+ except RuntimeError:
+ logging.debug("Couldn't find required icon resources, will exit.")
+ os._exit(1)
+ self._setup_trayicon()
+
+ self._menu = None
+ self._hover_menu = False
+ self._timeline = Timeline(self)
+ self._timeline.add_tag('popup', 6, 6)
+ self._timeline.add_tag('before_popdown', 7, 7)
+ self._timeline.add_tag('popdown', 8, 8)
+
+ try:
+ self.nminfo = nminfo.NMInfo(self)
+ except RuntimeError:
+ pass
+ self._setup_dbus()
+ if self._nm_present:
+ self._get_nm_state()
+ self._get_initial_devices()
+
+ def _get_one_icon_pixbuf(self, name):
+ info = self._icon_theme.lookup_icon(name, 75, 0)
+ if not info or not info.get_filename():
+ raise RuntimeError
+ return gtk.gdk.pixbuf_new_from_file(info.get_filename())
+
+ def _load_icons(self):
+ icons = {}
+ icons[ICON_WIRED] = self._get_one_icon_pixbuf(ICON_WIRED)
+ icons[ICON_WIRELESS_00] = self._get_one_icon_pixbuf(ICON_WIRELESS_00)
+ icons[ICON_WIRELESS_01_20] = self._get_one_icon_pixbuf(ICON_WIRELESS_01_20)
+ icons[ICON_WIRELESS_21_40] = self._get_one_icon_pixbuf(ICON_WIRELESS_21_40)
+ icons[ICON_WIRELESS_41_60] = self._get_one_icon_pixbuf(ICON_WIRELESS_41_60)
+ icons[ICON_WIRELESS_61_80] = self._get_one_icon_pixbuf(ICON_WIRELESS_61_80)
+ icons[ICON_WIRELESS_81_100] = self._get_one_icon_pixbuf(ICON_WIRELESS_81_100)
+ return icons
+
+ def _get_nm_state(self):
+ # Grab NM's state
+ self._nm_obj.state(reply_handler=self._get_state_reply_cb, \
+ error_handler=self._get_state_error_cb)
+
+ def _get_state_reply_cb(self, state):
+ if self._nm_state != state:
+ self._schedule_icon_update(immediate=True)
+ self._nm_state = state
+
+ def _get_state_error_cb(self, err):
+ logging.debug("Failed to get NetworkManager state! %s" % err)
+
+ def _get_icon(self):
+ act_dev = None
+ if self._active_device and self._devices.has_key(self._active_device):
+ act_dev = self._devices[self._active_device]
+
+ pixbuf = None
+ if not self._nm_present \
+ or not act_dev \
+ or self._nm_state == NM_STATE_UNKNOWN \
+ or self._nm_state == NM_STATE_ASLEEP \
+ or self._nm_state == NM_STATE_DISCONNECTED:
+ pixbuf = self._icons[ICON_WIRELESS_00]
+ elif act_dev.get_type() == DEVICE_TYPE_802_3_ETHERNET:
+ pixbuf = self._icons[ICON_WIRED]
+ elif act_dev.get_type() == DEVICE_TYPE_802_11_WIRELESS:
+ strength = act_dev.get_strength()
+ if strength <= 0:
+ pixbuf = self._icons[ICON_WIRELESS_00]
+ elif strength >= 1 and strength <= 20:
+ pixbuf = self._icons[ICON_WIRELESS_01_20]
+ elif strength >= 21 and strength <= 40:
+ pixbuf = self._icons[ICON_WIRELESS_21_40]
+ elif strength >= 41 and strength <= 60:
+ pixbuf = self._icons[ICON_WIRELESS_41_60]
+ elif strength >= 61 and strength <= 80:
+ pixbuf = self._icons[ICON_WIRELESS_61_80]
+ elif strength >= 81 and strength:
+ pixbuf = self._icons[ICON_WIRELESS_81_100]
+
+ if not pixbuf:
+ pixbuf = self._icons[ICON_WIRELESS_00]
+ return pixbuf
+
+ def _setup_trayicon(self):
+ pixbuf = self._get_icon()
+ self._trayicon = gtk.status_icon_new_from_pixbuf(pixbuf)
+ self._trayicon.connect("popup_menu", self._status_icon_clicked)
+ self._trayicon.connect("activate", self._status_icon_clicked)
+ self._schedule_icon_update()
+
+ def _status_icon_clicked(self, button=0, time=None):
+ self._timeline.play(None, 'popup')
+
+ def _get_menu_position(self, menu, item):
+ (screen, rect, orientation) = item.get_geometry()
+ [item_x, item_y, item_w, item_h] = rect
+ [menu_w, menu_h] = menu.size_request()
+
+ x = item_x + item_w - menu_w
+ y = item_y + item_h
+
+ x = min(x, screen.get_width() - menu_w)
+ x = max(0, x)
+
+ y = min(y, screen.get_height() - menu_h)
+ y = max(0, y)
+
+ return (x, y)
+
+ def do_popup(self, current, n_frames):
+ if self._menu:
+ return
+
+ self._menu = self._create_menu()
+ self._menu.connect('enter-notify-event',
+ self._menu_enter_notify_event_cb)
+ self._menu.connect('leave-notify-event',
+ self._menu_leave_notify_event_cb)
+ (x, y) = self._get_menu_position(self._menu, self._trayicon)
+ self._menu.move(x, y)
+ self._menu.show_all()
+
+ def do_popdown(self, current, frame):
+ if self._menu:
+ self._menu.destroy()
+ self._menu = None
+
+ def _popdown(self):
+ self._timeline.play('popdown', 'popdown')
+
+ def _menu_enter_notify_event_cb(self, widget, event):
+ self._hover_menu = True
+ self._timeline.play('popup', 'popup')
+
+ def _menu_leave_notify_event_cb(self, widget, event):
+ self._hover_menu = False
+ self._popdown()
+
+ def _create_menu(self):
+ menu = NetworkMenu()
+
+ # Active device goes above the separator
+ act_dev = None
+ if self._active_device and self._devices.has_key(self._active_device):
+ act_dev = self._devices[self._active_device]
+
+ if act_dev:
+ act_dev.add_to_menu(menu, self._menu_item_clicked_cb, active_only=True)
+ menu.add_separator()
+
+ # Wired devices first, if they don't support carrier detect
+ for dev in self._devices.values():
+ if not dev.is_valid():
+ continue
+ if dev.get_type() != DEVICE_TYPE_802_3_ETHERNET:
+ continue
+ if dev.get_capabilities() & NM_DEVICE_CAP_CARRIER_DETECT:
+ continue
+ if dev == act_dev:
+ continue
+ dev.add_to_menu(menu, self._menu_item_clicked_cb)
+
+ # Wireless devices second
+ for dev in self._devices.values():
+ if not dev.is_valid():
+ continue
+ if dev.get_type() != DEVICE_TYPE_802_11_WIRELESS:
+ continue
+ dev.add_to_menu(menu, self._menu_item_clicked_cb)
+
+ return menu
+
+ def _update_icon(self):
+ pixbuf = self._get_icon()
+ if self._cur_icon != pixbuf:
+ self._trayicon.set_from_pixbuf(pixbuf)
+ self._cur_icon = pixbuf
+
+ blink = False
+ if self._nm_state == NM_STATE_CONNECTING:
+ blink = True
+ self._trayicon.set_blinking(blink)
+
+ self._update_timer = 0
+ return False
+
+ def _schedule_icon_update(self, immediate=False):
+ if immediate and self._update_timer:
+ gobject.source_remove(self._update_timer)
+ self._update_timer = 0
+
+ if self._update_timer != 0:
+ # There is already an update scheduled
+ return
+
+ if immediate:
+ self._update_timer = gobject.idle_add(self._update_icon)
+ else:
+ self._update_timer = gobject.timeout_add(2000, self._update_icon)
+
+ def _get_initial_devices_reply_cb(self, ops):
+ for op in ops:
+ self._add_device(op)
+
+ def _dev_init_failed_cb(self, dev):
+ # Device failed to initialize, likely due to dbus errors or something
+ op = dev.get_op()
+ self._remove_device(op)
+
+ def _get_initial_devices_error_cb(self, err):
+ logging.debug("Error updating devices (%s)" % err)
+
+ def _get_initial_devices(self):
+ self._nm_obj.getDevices(reply_handler=self._get_initial_devices_reply_cb, \
+ error_handler=self._get_initial_devices_error_cb)
+
+ def _add_device(self, dev_op):
+ if self._devices.has_key(dev_op):
+ return
+ dev = Device(dev_op)
+ self._devices[dev_op] = dev
+ dev.connect('init-failed', self._dev_init_failed_cb)
+ dev.connect('activated', self._dev_activated_cb)
+ dev.connect('strength-changed', self._dev_strength_changed_cb)
+
+ def _remove_device(self, dev_op):
+ if not self._devices.has_key(dev_op):
+ return
+ if self._active_device == dev_op:
+ self._active_device = None
+ dev = self._devices[dev_op]
+ dev.disconnect('activated')
+ dev.disconnect('init-failed')
+ dev.disconnect('strength-changed')
+ del self._devices[dev_op]
+ self._schedule_icon_update(immediate=True)
+
+ def _dev_activated_cb(self, dev):
+ op = dev.get_op()
+ if not self._devices.has_key(op):
+ return
+ if not dev.get_active():
+ return
+ self._active_device = op
+ self._schedule_icon_update(immediate=True)
+
+ def _dev_strength_changed_cb(self, dev, strength):
+ op = dev.get_op()
+ if not self._devices.has_key(op):
+ return
+ if not dev.get_active():
+ return
+ self._schedule_icon_update()
+
+ def get_device(self, dev_op):
+ if not self._devices.has_key(dev_op):
+ return None
+ return self._devices[dev_op]
+
+ def _setup_dbus(self):
+ self._sig_handlers = {
+ 'StateChange': self.state_change_sig_handler,
+ 'DeviceAdded': self.device_added_sig_handler,
+ 'DeviceRemoved': self.device_removed_sig_handler,
+ 'DeviceActivationStage': self.device_activation_stage_sig_handler,
+ 'DeviceActivating': self.device_activating_sig_handler,
+ 'DeviceNowActive': self.device_now_active_sig_handler,
+ 'DeviceNoLongerActive': self.device_no_longer_active_sig_handler,
+ 'DeviceCarrierOn': self.device_carrier_on_sig_handler,
+ 'DeviceCarrierOff': self.device_carrier_off_sig_handler,
+ 'DeviceStrengthChanged': self.wireless_device_strength_changed_sig_handler,
+ 'WirelessNetworkAppeared': self.wireless_network_appeared_sig_handler,
+ 'WirelessNetworkDisappeared': self.wireless_network_disappeared_sig_handler,
+ 'WirelessNetworkStrengthChanged': self.wireless_network_strength_changed_sig_handler
+ }
+
+ self._nm_proxy = sys_bus.get_object(NM_SERVICE, NM_PATH)
+ self._nm_obj = dbus.Interface(self._nm_proxy, NM_IFACE)
+
+ sys_bus.add_signal_receiver(self.name_owner_changed_sig_handler,
+ signal_name="NameOwnerChanged",
+ dbus_interface="org.freedesktop.DBus")
+
+ sys_bus.add_signal_receiver(self.catchall_signal_handler,
+ dbus_interface=NM_IFACE)
+
+ sys_bus.add_signal_receiver(self.catchall_signal_handler,
+ dbus_interface=NM_IFACE + 'Devices')
+
+ for (signal, handler) in self._sig_handlers.items():
+ sys_bus.add_signal_receiver(handler, signal_name=signal, dbus_interface=NM_IFACE)
+
+ # Find out whether or not NM is running
+ try:
+ bus_object = sys_bus.get_object('org.freedesktop.DBus', '/org/freedesktop/DBus')
+ name = bus_object.GetNameOwner("org.freedesktop.NetworkManagerInfo", \
+ dbus_interface='org.freedesktop.DBus')
+ if name:
+ self._nm_present = True
+ except dbus.DBusException:
+ pass
+
+ @dbus.decorators.explicitly_pass_message
+ def catchall_signal_handler(self, *args, **keywords):
+ dbus_message = keywords['dbus_message']
+ mem = dbus_message.get_member()
+ iface = dbus_message.get_interface()
+
+ if iface == NM_IFACE and mem in self._sig_handlers.keys():
+ return
+
+ logging.debug('Caught signal %s.%s' % (dbus_message.get_interface(), mem))
+ for arg in args:
+ logging.debug(' ' + str(arg))
+
+ def _menu_item_clicked_cb(self, widget, event, dev_data):
+ (device, network) = dev_data
+ net_op = ""
+ if network:
+ net_op = network.get_op()
+ try:
+ # NM 0.6.4 and earlier have a bug which returns an
+ # InvalidArguments error if no security information is passed
+ # for wireless networks
+ self._nm_obj.setActiveDevice(device.get_op(), network.get_ssid())
+ except dbus.DBusException, e:
+ if str(e).find("invalid arguments"):
+ pass
+ else:
+ raise dbus.DBusException(e)
+
+ self._popdown()
+
+ def get_key_for_network(self, net, async_cb, async_err_cb):
+ # Throw up a dialog asking for the key here, and set
+ # the authentication algorithm to the given one, if any
+ #
+ # Key needs to be limited to _either_ 10 or 26 digits long,
+ # and contain _only_ _hex_ digits, 0-9 or a-f
+ #
+ # Auth algorithm should be a dropdown of: [Open System, Shared Key],
+ # mapping to the values [IW_AUTH_ALG_OPEN_SYSTEM, IW_AUTH_ALG_SHARED_KEY]
+ # above
+
+ self._key_dialog = WEPKeyDialog(net, async_cb, async_err_cb)
+ self._key_dialog.connect("response", self._key_dialog_response_cb)
+ self._key_dialog.connect("destroy", self._key_dialog_destroy_cb)
+ self._key_dialog.show_all()
+
+ def _key_dialog_destroy_cb(self, widget, foo=None):
+ if widget != self._key_dialog:
+ return
+ self._key_dialog_response_cb(widget, gtk.RESPONSE_CANCEL)
+
+ def _key_dialog_response_cb(self, widget, response_id):
+ if widget != self._key_dialog:
+ return
+ key = self._key_dialog.get_key()
+ wep_auth_alg = self._key_dialog.get_auth_alg()
+ net = self._key_dialog.get_network()
+ (async_cb, async_err_cb) = self._key_dialog.get_callbacks()
+
+ # Clear self._key_dialog before we call destroy(), otherwise
+ # the destroy will trigger and we'll get called again by
+ # self._key_dialog_destroy_cb
+ self._key_dialog = None
+ widget.destroy()
+
+ if response_id == gtk.RESPONSE_OK:
+ self.nminfo.get_key_for_network_cb(
+ net, key, wep_auth_alg, async_cb, async_err_cb, canceled=False)
+ else:
+ self.nminfo.get_key_for_network_cb(
+ net, None, None, async_cb, async_err_cb, canceled=True)
+
+ def cancel_get_key_for_network(self):
+ # Close the wireless key dialog and just have it return
+ # with the 'canceled' argument set to true
+ if not self._key_dialog:
+ return
+ self._key_dialog_destroy_cb(self._key_dialog)
+
+ def device_activation_stage_sig_handler(self, device, stage):
+ logging.debug('Device Activation Stage "%s" for device %s' % (NM_DEVICE_STAGE_STRINGS[stage], device))
+
+ def state_change_sig_handler(self, state):
+ self._nm_state = state
+ self._schedule_icon_update(immediate=True)
+
+ def device_activating_sig_handler(self, device):
+ self._active_device = device
+
+ def device_now_active_sig_handler(self, device, ssid=None):
+ if not self._devices.has_key(device):
+ return
+ self._active_device = device
+ self._devices[device].set_active(True, ssid)
+ self._schedule_icon_update(immediate=True)
+
+ def device_no_longer_active_sig_handler(self, device):
+ if not self._devices.has_key(device):
+ return
+ if self._active_device == device:
+ self._active_device = None
+ self._devices[device].set_active(False)
+ self._schedule_icon_update(immediate=True)
+
+ def name_owner_changed_sig_handler(self, name, old, new):
+ if name != NM_SERVICE:
+ return
+ if (old and len(old)) and (not new and not len(new)):
+ # NM went away
+ self._nm_present = False
+ self._schedule_icon_update(immediate=True)
+ for op in self._devices.keys():
+ del self._devices[op]
+ self._devices = {}
+ self._active_device = None
+ self._nm_state = NM_STATE_UNKNOWN
+ elif (not old and not len(old)) and (new and len(new)):
+ # NM started up
+ self._nm_present = True
+ self._get_nm_state()
+ self._get_initial_devices()
+
+ def device_added_sig_handler(self, device):
+ self._add_device(device)
+
+ def device_removed_sig_handler(self, device):
+ self._remove_device(device)
+
+ def wireless_network_appeared_sig_handler(self, device, network):
+ if not self._devices.has_key(device):
+ return
+ self._devices[device].network_appeared(network)
+
+ def wireless_network_disappeared_sig_handler(self, device, network):
+ if not self._devices.has_key(device):
+ return
+ self._devices[device].network_disappeared(network)
+
+ def wireless_device_strength_changed_sig_handler(self, device, strength):
+ if not self._devices.has_key(device):
+ return
+ self._devices[device].set_strength(strength)
+
+ def wireless_network_strength_changed_sig_handler(self, device, network, strength):
+ if not self._devices.has_key(device):
+ return
+ net = self._devices[device].get_network(network)
+ if net:
+ net.set_strength(strength)
+
+ def device_carrier_on_sig_handler(self, device):
+ if not self._devices.has_key(device):
+ return
+ self._devices[device].set_carrier(True)
+
+ def device_carrier_off_sig_handler(self, device):
+ if not self._devices.has_key(device):
+ return
+ self._devices[device].set_carrier(False)
+
+ def run(self):
+ loop = gobject.MainLoop()
+ try:
+ loop.run()
+ except KeyboardInterrupt:
+ pass
diff --git a/services/nm/nminfo.py b/services/nm/nminfo.py
index a86ec1a..f512a8b 100644
--- a/services/nm/nminfo.py
+++ b/services/nm/nminfo.py
@@ -26,65 +26,65 @@ import logging
import nmclient
try:
- from sugar import env
+ from sugar import env
except ImportError:
- pass
+ pass
NM_INFO_IFACE='org.freedesktop.NetworkManagerInfo'
NM_INFO_PATH='/org/freedesktop/NetworkManagerInfo'
class NoNetworks(dbus.DBusException):
- def __init__(self):
- dbus.DBusException.__init__(self)
- self._dbus_error_name = NM_INFO_IFACE + '.NoNetworks'
+ def __init__(self):
+ dbus.DBusException.__init__(self)
+ self._dbus_error_name = NM_INFO_IFACE + '.NoNetworks'
class CanceledKeyRequestError(dbus.DBusException):
- def __init__(self):
- dbus.DBusException.__init__(self)
- self._dbus_error_name = NM_INFO_IFACE + '.CanceledError'
+ def __init__(self):
+ dbus.DBusException.__init__(self)
+ self._dbus_error_name = NM_INFO_IFACE + '.CanceledError'
class NetworkInvalidError(Exception):
- pass
+ pass
class NMConfig(ConfigParser.ConfigParser):
- def get_bool(self, section, name):
- opt = self.get(section, name)
- if type(opt) == type(""):
- if opt.lower() == 'yes' or opt.lower() == 'true':
- return True
- elif opt.lower() == 'no' or opt.lower() == 'false':
- return False
- raise ValueError("Invalid format for %s/%s. Should be one of [yes, no, true, false]." % (section, name))
-
- def get_list(self, section, name):
- opt = self.get(section, name)
- if type(opt) == type(""):
- if not len(opt):
- return []
- try:
- return opt.split()
- except Exception:
- pass
- raise ValueError("Invalid format for %s/%s. Should be a space-separate list." % (section, name))
-
- def get_int(self, section, name):
- opt = self.get(section, name)
- try:
- return int(opt)
- except Exception:
- pass
- raise ValueError("Invalid format for %s/%s. Should be a valid integer." % (section, name))
-
- def get_float(self, section, name):
- opt = self.get(section, name)
- try:
- return float(opt)
- except Exception:
- pass
- raise ValueError("Invalid format for %s/%s. Should be a valid float." % (section, name))
+ def get_bool(self, section, name):
+ opt = self.get(section, name)
+ if type(opt) == type(""):
+ if opt.lower() == 'yes' or opt.lower() == 'true':
+ return True
+ elif opt.lower() == 'no' or opt.lower() == 'false':
+ return False
+ raise ValueError("Invalid format for %s/%s. Should be one of [yes, no, true, false]." % (section, name))
+
+ def get_list(self, section, name):
+ opt = self.get(section, name)
+ if type(opt) == type(""):
+ if not len(opt):
+ return []
+ try:
+ return opt.split()
+ except Exception:
+ pass
+ raise ValueError("Invalid format for %s/%s. Should be a space-separate list." % (section, name))
+
+ def get_int(self, section, name):
+ opt = self.get(section, name)
+ try:
+ return int(opt)
+ except Exception:
+ pass
+ raise ValueError("Invalid format for %s/%s. Should be a valid integer." % (section, name))
+
+ def get_float(self, section, name):
+ opt = self.get(section, name)
+ try:
+ return float(opt)
+ except Exception:
+ pass
+ raise ValueError("Invalid format for %s/%s. Should be a valid float." % (section, name))
IW_AUTH_CIPHER_NONE = 0x00000001
@@ -102,366 +102,366 @@ NETWORK_TYPE_INVALID = 2
class Security(object):
- def __init__(self, we_cipher):
- self._we_cipher = we_cipher
-
- def read_from_config(self, cfg, name):
- pass
-
- def read_from_args(self, args):
- pass
-
- def new_from_config(cfg, name):
- security = None
- try:
- we_cipher = cfg.get_int(name, "we_cipher")
- if we_cipher == IW_AUTH_CIPHER_NONE:
- security = Security(we_cipher)
- elif we_cipher == IW_AUTH_CIPHER_WEP40 or we_cipher == IW_AUTH_CIPHER_WEP104:
- security = WEPSecurity(we_cipher)
- else:
- # FIXME: find a way to make WPA config option matrix not
- # make you want to throw up
- raise ValueError("Unsupported security combo")
- security.read_from_config(cfg, name)
- except (ConfigParser.NoOptionError, ValueError), e:
- return None
- return security
- new_from_config = staticmethod(new_from_config)
-
- def new_from_args(we_cipher, args):
- security = None
- try:
- if we_cipher == IW_AUTH_CIPHER_NONE:
- security = Security(we_cipher)
- elif we_cipher == IW_AUTH_CIPHER_WEP40 or we_cipher == IW_AUTH_CIPHER_WEP104:
- security = WEPSecurity(we_cipher)
- else:
- # FIXME: find a way to make WPA config option matrix not
- # make you want to throw up
- raise ValueError("Unsupported security combo")
- security.read_from_args(args)
- except ValueError, e:
- logging.debug("Error reading security information: %s" % e)
- del security
- return None
- return security
- new_from_args = staticmethod(new_from_args)
-
- def get_properties(self):
- return [dbus.Int32(self._we_cipher)]
-
- def write_to_config(self, section, config):
- config.set(section, "we_cipher", self._we_cipher)
+ def __init__(self, we_cipher):
+ self._we_cipher = we_cipher
+
+ def read_from_config(self, cfg, name):
+ pass
+
+ def read_from_args(self, args):
+ pass
+
+ def new_from_config(cfg, name):
+ security = None
+ try:
+ we_cipher = cfg.get_int(name, "we_cipher")
+ if we_cipher == IW_AUTH_CIPHER_NONE:
+ security = Security(we_cipher)
+ elif we_cipher == IW_AUTH_CIPHER_WEP40 or we_cipher == IW_AUTH_CIPHER_WEP104:
+ security = WEPSecurity(we_cipher)
+ else:
+ # FIXME: find a way to make WPA config option matrix not
+ # make you want to throw up
+ raise ValueError("Unsupported security combo")
+ security.read_from_config(cfg, name)
+ except (ConfigParser.NoOptionError, ValueError), e:
+ return None
+ return security
+ new_from_config = staticmethod(new_from_config)
+
+ def new_from_args(we_cipher, args):
+ security = None
+ try:
+ if we_cipher == IW_AUTH_CIPHER_NONE:
+ security = Security(we_cipher)
+ elif we_cipher == IW_AUTH_CIPHER_WEP40 or we_cipher == IW_AUTH_CIPHER_WEP104:
+ security = WEPSecurity(we_cipher)
+ else:
+ # FIXME: find a way to make WPA config option matrix not
+ # make you want to throw up
+ raise ValueError("Unsupported security combo")
+ security.read_from_args(args)
+ except ValueError, e:
+ logging.debug("Error reading security information: %s" % e)
+ del security
+ return None
+ return security
+ new_from_args = staticmethod(new_from_args)
+
+ def get_properties(self):
+ return [dbus.Int32(self._we_cipher)]
+
+ def write_to_config(self, section, config):
+ config.set(section, "we_cipher", self._we_cipher)
class WEPSecurity(Security):
- def read_from_args(self, args):
- if len(args) != 2:
- raise ValueError("not enough arguments")
- key = args[0]
- auth_alg = args[1]
- if isinstance(key, unicode):
- key = key.encode()
- if not isinstance(key, str):
- raise ValueError("wrong argument type for key")
- if not isinstance(auth_alg, int):
- raise ValueError("wrong argument type for auth_alg")
- self._key = key
- self._auth_alg = auth_alg
-
- def read_from_config(self, cfg, name):
- # Key should be a hex encoded string
- self._key = cfg.get(name, "key")
- if self._we_cipher == IW_AUTH_CIPHER_WEP40 and len(self._key) != 10:
- raise ValueError("Key length not right for 40-bit WEP")
- if self._we_cipher == IW_AUTH_CIPHER_WEP104 and len(self._key) != 26:
- raise ValueError("Key length not right for 104-bit WEP")
-
- try:
- a = binascii.a2b_hex(self._key)
- except TypeError:
- raise ValueError("Key was not a hexadecimal string.")
-
- self._auth_alg = cfg.get_int(name, "auth_alg")
- if self._auth_alg != IW_AUTH_ALG_OPEN_SYSTEM and self._auth_alg != IW_AUTH_ALG_SHARED_KEY:
- raise ValueError("Invalid authentication algorithm %d" % self._auth_alg)
-
- def get_properties(self):
- args = Security.get_properties(self)
- args.append(dbus.String(self._key))
- args.append(dbus.Int32(self._auth_alg))
- return args
-
- def write_to_config(self, section, config):
- Security.write_to_config(self, section, config)
- config.set(section, "key", self._key)
- config.set(section, "auth_alg", self._auth_alg)
+ def read_from_args(self, args):
+ if len(args) != 2:
+ raise ValueError("not enough arguments")
+ key = args[0]
+ auth_alg = args[1]
+ if isinstance(key, unicode):
+ key = key.encode()
+ if not isinstance(key, str):
+ raise ValueError("wrong argument type for key")
+ if not isinstance(auth_alg, int):
+ raise ValueError("wrong argument type for auth_alg")
+ self._key = key
+ self._auth_alg = auth_alg
+
+ def read_from_config(self, cfg, name):
+ # Key should be a hex encoded string
+ self._key = cfg.get(name, "key")
+ if self._we_cipher == IW_AUTH_CIPHER_WEP40 and len(self._key) != 10:
+ raise ValueError("Key length not right for 40-bit WEP")
+ if self._we_cipher == IW_AUTH_CIPHER_WEP104 and len(self._key) != 26:
+ raise ValueError("Key length not right for 104-bit WEP")
+
+ try:
+ a = binascii.a2b_hex(self._key)
+ except TypeError:
+ raise ValueError("Key was not a hexadecimal string.")
+
+ self._auth_alg = cfg.get_int(name, "auth_alg")
+ if self._auth_alg != IW_AUTH_ALG_OPEN_SYSTEM and self._auth_alg != IW_AUTH_ALG_SHARED_KEY:
+ raise ValueError("Invalid authentication algorithm %d" % self._auth_alg)
+
+ def get_properties(self):
+ args = Security.get_properties(self)
+ args.append(dbus.String(self._key))
+ args.append(dbus.Int32(self._auth_alg))
+ return args
+
+ def write_to_config(self, section, config):
+ Security.write_to_config(self, section, config)
+ config.set(section, "key", self._key)
+ config.set(section, "auth_alg", self._auth_alg)
class Network:
- def __init__(self, ssid):
- self.ssid = ssid
- self.timestamp = int(time.time())
- self.bssids = []
- self.we_cipher = 0
- self._security = None
-
- def get_properties(self):
- bssid_list = dbus.Array([], signature="s")
- for item in self.bssids:
- bssid_list.append(dbus.String(item))
- args = [dbus.String(self.ssid), dbus.Int32(self.timestamp), dbus.Boolean(True), bssid_list]
- args += self._security.get_properties()
- return tuple(args)
-
- def get_security(self):
- return self._security.get_properties()
-
- def set_security(self, security):
- self._security = security
-
- def read_from_args(self, auto, bssid, we_cipher, args):
- if auto == False:
- self.timestamp = int(time.time())
- if not bssid in self.bssids:
- self.bssids.append(bssid)
-
- self._security = Security.new_from_args(we_cipher, args)
- if not self._security:
- raise NetworkInvalidError("Invalid security information")
-
- def read_from_config(self, config):
- try:
- self.timestamp = config.get_int(self.ssid, "timestamp")
- except (ConfigParser.NoOptionError, ValueError), e:
- raise NetworkInvalidError(e)
-
- self._security = Security.new_from_config(config, self.ssid)
- if not self._security:
- raise NetworkInvalidError(e)
-
- # The following don't need to be present
- try:
- self.bssids = config.get_list(self.ssid, "bssids")
- except (ConfigParser.NoOptionError, ValueError), e:
- pass
-
- def write_to_config(self, config):
- try:
- config.add_section(self.ssid)
- config.set(self.ssid, "timestamp", self.timestamp)
- if len(self.bssids) > 0:
- opt = " "
- opt.join(self.bssids)
- config.set(self.ssid, "bssids", opt)
- self._security.write_to_config(self.ssid, config)
- except Exception, e:
- logging.debug("Error writing '%s': %s" % (self.ssid, e))
+ def __init__(self, ssid):
+ self.ssid = ssid
+ self.timestamp = int(time.time())
+ self.bssids = []
+ self.we_cipher = 0
+ self._security = None
+
+ def get_properties(self):
+ bssid_list = dbus.Array([], signature="s")
+ for item in self.bssids:
+ bssid_list.append(dbus.String(item))
+ args = [dbus.String(self.ssid), dbus.Int32(self.timestamp), dbus.Boolean(True), bssid_list]
+ args += self._security.get_properties()
+ return tuple(args)
+
+ def get_security(self):
+ return self._security.get_properties()
+
+ def set_security(self, security):
+ self._security = security
+
+ def read_from_args(self, auto, bssid, we_cipher, args):
+ if auto == False:
+ self.timestamp = int(time.time())
+ if not bssid in self.bssids:
+ self.bssids.append(bssid)
+
+ self._security = Security.new_from_args(we_cipher, args)
+ if not self._security:
+ raise NetworkInvalidError("Invalid security information")
+
+ def read_from_config(self, config):
+ try:
+ self.timestamp = config.get_int(self.ssid, "timestamp")
+ except (ConfigParser.NoOptionError, ValueError), e:
+ raise NetworkInvalidError(e)
+
+ self._security = Security.new_from_config(config, self.ssid)
+ if not self._security:
+ raise NetworkInvalidError(e)
+
+ # The following don't need to be present
+ try:
+ self.bssids = config.get_list(self.ssid, "bssids")
+ except (ConfigParser.NoOptionError, ValueError), e:
+ pass
+
+ def write_to_config(self, config):
+ try:
+ config.add_section(self.ssid)
+ config.set(self.ssid, "timestamp", self.timestamp)
+ if len(self.bssids) > 0:
+ opt = " "
+ opt.join(self.bssids)
+ config.set(self.ssid, "bssids", opt)
+ self._security.write_to_config(self.ssid, config)
+ except Exception, e:
+ logging.debug("Error writing '%s': %s" % (self.ssid, e))
class NotFoundError(dbus.DBusException):
- pass
+ pass
class UnsupportedError(dbus.DBusException):
- pass
+ pass
class NMInfoDBusServiceHelper(dbus.service.Object):
- def __init__(self, parent):
- self._parent = parent
- bus = dbus.SystemBus()
-
- # If NMI is already around, don't grab the NMI service
- bus_object = bus.get_object('org.freedesktop.DBus', '/org/freedesktop/DBus')
- name = None
- try:
- name = bus_object.GetNameOwner("org.freedesktop.NetworkManagerInfo", \
- dbus_interface='org.freedesktop.DBus')
- except dbus.DBusException:
- pass
- if name:
- logging.debug("NMI service already owned by %s, won't claim it." % name)
- raise RuntimeError
-
- bus_name = dbus.service.BusName(NM_INFO_IFACE, bus=bus)
- dbus.service.Object.__init__(self, bus_name, NM_INFO_PATH)
-
- @dbus.service.method(NM_INFO_IFACE, in_signature='i', out_signature='as')
- def getNetworks(self, net_type):
- ssids = self._parent.get_networks(net_type)
- if len(ssids) > 0:
- return dbus.Array(ssids)
-
- raise NoNetworks()
-
- @dbus.service.method(NM_INFO_IFACE, in_signature='si', async_callbacks=('async_cb', 'async_err_cb'))
- def getNetworkProperties(self, ssid, net_type, async_cb, async_err_cb):
- self._parent.get_network_properties(ssid, net_type, async_cb, async_err_cb)
-
- @dbus.service.method(NM_INFO_IFACE)
- def updateNetworkInfo(self, ssid, bauto, bssid, cipher, *args):
- self._parent.update_network_info(ssid, bauto, bssid, cipher, args)
-
- @dbus.service.method(NM_INFO_IFACE, async_callbacks=('async_cb', 'async_err_cb'))
- def getKeyForNetwork(self, dev_path, net_path, ssid, attempt, new_key, async_cb, async_err_cb):
- self._parent.get_key_for_network(dev_path, net_path, ssid,
- attempt, new_key, async_cb, async_err_cb)
-
- @dbus.service.method(NM_INFO_IFACE)
- def cancelGetKeyForNetwork(self):
- self._parent.cancel_get_key_for_network()
+ def __init__(self, parent):
+ self._parent = parent
+ bus = dbus.SystemBus()
+
+ # If NMI is already around, don't grab the NMI service
+ bus_object = bus.get_object('org.freedesktop.DBus', '/org/freedesktop/DBus')
+ name = None
+ try:
+ name = bus_object.GetNameOwner("org.freedesktop.NetworkManagerInfo", \
+ dbus_interface='org.freedesktop.DBus')
+ except dbus.DBusException:
+ pass
+ if name:
+ logging.debug("NMI service already owned by %s, won't claim it." % name)
+ raise RuntimeError
+
+ bus_name = dbus.service.BusName(NM_INFO_IFACE, bus=bus)
+ dbus.service.Object.__init__(self, bus_name, NM_INFO_PATH)
+
+ @dbus.service.method(NM_INFO_IFACE, in_signature='i', out_signature='as')
+ def getNetworks(self, net_type):
+ ssids = self._parent.get_networks(net_type)
+ if len(ssids) > 0:
+ return dbus.Array(ssids)
+
+ raise NoNetworks()
+
+ @dbus.service.method(NM_INFO_IFACE, in_signature='si', async_callbacks=('async_cb', 'async_err_cb'))
+ def getNetworkProperties(self, ssid, net_type, async_cb, async_err_cb):
+ self._parent.get_network_properties(ssid, net_type, async_cb, async_err_cb)
+
+ @dbus.service.method(NM_INFO_IFACE)
+ def updateNetworkInfo(self, ssid, bauto, bssid, cipher, *args):
+ self._parent.update_network_info(ssid, bauto, bssid, cipher, args)
+
+ @dbus.service.method(NM_INFO_IFACE, async_callbacks=('async_cb', 'async_err_cb'))
+ def getKeyForNetwork(self, dev_path, net_path, ssid, attempt, new_key, async_cb, async_err_cb):
+ self._parent.get_key_for_network(dev_path, net_path, ssid,
+ attempt, new_key, async_cb, async_err_cb)
+
+ @dbus.service.method(NM_INFO_IFACE)
+ def cancelGetKeyForNetwork(self):
+ self._parent.cancel_get_key_for_network()
class NMInfo(object):
- def __init__(self, client):
- try:
- profile_path = env.get_profile_path()
- except NameError:
- home = os.path.expanduser("~")
- profile_path = os.path.join(home, ".sugar", "default")
- self._cfg_file = os.path.join(profile_path, "nm", "networks.cfg")
- self._nmclient = client
- self._allowed_networks = self._read_config()
- self._dbus_helper = NMInfoDBusServiceHelper(self)
-
- def save_config(self):
- self._write_config(self._allowed_networks)
-
- def _read_config(self):
- if not os.path.exists(os.path.dirname(self._cfg_file)):
- os.makedirs(os.path.dirname(self._cfg_file), 0755)
- if not os.path.exists(self._cfg_file):
- self._write_config({})
- return {}
-
- config = NMConfig()
- config.read(self._cfg_file)
- networks = {}
- for name in config.sections():
- if not isinstance(name, unicode):
- name = unicode(name)
- net = Network(name)
- try:
- net.read_from_config(config)
- networks[name] = net
- except NetworkInvalidError, e:
- logging.debug("Error: invalid stored network config: %s" % e)
- del net
- del config
- return networks
-
- def _write_config(self, networks):
- fp = open(self._cfg_file, 'w')
- config = NMConfig()
- for net in networks.values():
- net.write_to_config(config)
- config.write(fp)
- fp.close()
- del config
-
- def get_networks(self, net_type):
- if net_type != NETWORK_TYPE_ALLOWED:
- raise ValueError("Bad network type")
- nets = []
- for net in self._allowed_networks.values():
- nets.append(net.ssid)
- logging.debug("Returning networks: %s" % nets)
- return nets
-
- def get_network_properties(self, ssid, net_type, async_cb, async_err_cb):
- if not isinstance(ssid, unicode):
- async_err_cb(ValueError("Invalid arguments; ssid must be unicode."))
- if net_type != NETWORK_TYPE_ALLOWED:
- async_err_cb(ValueError("Bad network type"))
- if not self._allowed_networks.has_key(ssid):
- async_err_cb(NotFoundError("Network '%s' not found." % ssid))
- network = self._allowed_networks[ssid]
- props = network.get_properties()
-
- # DBus workaround: the normal method return handler wraps
- # the returned arguments in a tuple and then converts that to a
- # struct, but NetworkManager expects a plain list of arguments.
- # It turns out that the async callback method return code _doesn't_
- # wrap the returned arguments in a tuple, so as a workaround use
- # the async callback stuff here even though we're not doing it
- # asynchronously.
- async_cb(*props)
-
- def update_network_info(self, ssid, auto, bssid, we_cipher, args):
- if not isinstance(ssid, unicode):
- raise ValueError("Invalid arguments; ssid must be unicode.")
- if self._allowed_networks.has_key(ssid):
- del self._allowed_networks[ssid]
- net = Network(ssid)
- try:
- net.read_from_args(auto, bssid, we_cipher, args)
- logging.debug("Updated network information for '%s'." % ssid)
- self._allowed_networks[ssid] = net
- self.save_config()
- except NetworkInvalidError, e:
- logging.debug("Error updating network information: %s" % e)
- del net
-
- def get_key_for_network(self, dev_op, net_op, ssid, attempt, new_key, async_cb, async_err_cb):
- if not isinstance(ssid, unicode):
- raise ValueError("Invalid arguments; ssid must be unicode.")
- if self._allowed_networks.has_key(ssid) and not new_key:
- # We've got the info already
- net = self._allowed_networks[ssid]
- async_cb(tuple(net.get_security()))
- return
-
- # Otherwise, ask the user for it
- net = None
- dev = self._nmclient.get_device(dev_op)
- if not dev:
- async_err_cb(NotFoundError("Device was unknown."))
- return
-
- if dev.get_type() == nmclient.DEVICE_TYPE_802_3_ETHERNET:
- # We don't support wired 802.1x yet...
- async_err_cb(UnsupportedError("Device type is unsupported by NMI."))
- return
-
- net = dev.get_network(net_op)
- if not net:
- async_err_cb(NotFoundError("Network was unknown."))
- return
-
- self._nmclient.get_key_for_network(net, async_cb, async_err_cb)
-
- def get_key_for_network_cb(self, net, key, auth_alg, async_cb, async_err_cb, canceled=False):
- """
- Called by the NMClient when the Wireless Network Key dialog
- is closed.
- """
- if canceled:
- e = CanceledKeyRequestError("Request was canceled.")
- # key dialog dialog was canceled; send the error back to NM
- async_err_cb(e)
- return
-
- if not key or not auth_alg:
- # no key returned, *** BUG ***; the key dialog
- # should always return either a key + auth_alg, or a
- #cancel error
- raise RuntimeError("No key or auth alg given! Bug!")
-
- we_cipher = None
- if len(key) == 26:
- we_cipher = IW_AUTH_CIPHER_WEP104
- elif len(key) == 10:
- we_cipher = IW_AUTH_CIPHER_WEP40
- else:
- raise RuntimeError("Invalid key length!")
-
- # Stuff the returned key and auth algorithm into a security object
- # and return it to NetworkManager
- sec = Security.new_from_args(we_cipher, (key, auth_alg))
- if not sec:
- raise RuntimeError("Invalid security arguments.")
- props = sec.get_properties()
- a = tuple(props)
- async_cb(*a)
-
- def cancel_get_key_for_network(self):
- # Tell the NMClient to close the key request dialog
- self._nmclient.cancel_get_key_for_network()
+ def __init__(self, client):
+ try:
+ profile_path = env.get_profile_path()
+ except NameError:
+ home = os.path.expanduser("~")
+ profile_path = os.path.join(home, ".sugar", "default")
+ self._cfg_file = os.path.join(profile_path, "nm", "networks.cfg")
+ self._nmclient = client
+ self._allowed_networks = self._read_config()
+ self._dbus_helper = NMInfoDBusServiceHelper(self)
+
+ def save_config(self):
+ self._write_config(self._allowed_networks)
+
+ def _read_config(self):
+ if not os.path.exists(os.path.dirname(self._cfg_file)):
+ os.makedirs(os.path.dirname(self._cfg_file), 0755)
+ if not os.path.exists(self._cfg_file):
+ self._write_config({})
+ return {}
+
+ config = NMConfig()
+ config.read(self._cfg_file)
+ networks = {}
+ for name in config.sections():
+ if not isinstance(name, unicode):
+ name = unicode(name)
+ net = Network(name)
+ try:
+ net.read_from_config(config)
+ networks[name] = net
+ except NetworkInvalidError, e:
+ logging.debug("Error: invalid stored network config: %s" % e)
+ del net
+ del config
+ return networks
+
+ def _write_config(self, networks):
+ fp = open(self._cfg_file, 'w')
+ config = NMConfig()
+ for net in networks.values():
+ net.write_to_config(config)
+ config.write(fp)
+ fp.close()
+ del config
+
+ def get_networks(self, net_type):
+ if net_type != NETWORK_TYPE_ALLOWED:
+ raise ValueError("Bad network type")
+ nets = []
+ for net in self._allowed_networks.values():
+ nets.append(net.ssid)
+ logging.debug("Returning networks: %s" % nets)
+ return nets
+
+ def get_network_properties(self, ssid, net_type, async_cb, async_err_cb):
+ if not isinstance(ssid, unicode):
+ async_err_cb(ValueError("Invalid arguments; ssid must be unicode."))
+ if net_type != NETWORK_TYPE_ALLOWED:
+ async_err_cb(ValueError("Bad network type"))
+ if not self._allowed_networks.has_key(ssid):
+ async_err_cb(NotFoundError("Network '%s' not found." % ssid))
+ network = self._allowed_networks[ssid]
+ props = network.get_properties()
+
+ # DBus workaround: the normal method return handler wraps
+ # the returned arguments in a tuple and then converts that to a
+ # struct, but NetworkManager expects a plain list of arguments.
+ # It turns out that the async callback method return code _doesn't_
+ # wrap the returned arguments in a tuple, so as a workaround use
+ # the async callback stuff here even though we're not doing it
+ # asynchronously.
+ async_cb(*props)
+
+ def update_network_info(self, ssid, auto, bssid, we_cipher, args):
+ if not isinstance(ssid, unicode):
+ raise ValueError("Invalid arguments; ssid must be unicode.")
+ if self._allowed_networks.has_key(ssid):
+ del self._allowed_networks[ssid]
+ net = Network(ssid)
+ try:
+ net.read_from_args(auto, bssid, we_cipher, args)
+ logging.debug("Updated network information for '%s'." % ssid)
+ self._allowed_networks[ssid] = net
+ self.save_config()
+ except NetworkInvalidError, e:
+ logging.debug("Error updating network information: %s" % e)
+ del net
+
+ def get_key_for_network(self, dev_op, net_op, ssid, attempt, new_key, async_cb, async_err_cb):
+ if not isinstance(ssid, unicode):
+ raise ValueError("Invalid arguments; ssid must be unicode.")
+ if self._allowed_networks.has_key(ssid) and not new_key:
+ # We've got the info already
+ net = self._allowed_networks[ssid]
+ async_cb(tuple(net.get_security()))
+ return
+
+ # Otherwise, ask the user for it
+ net = None
+ dev = self._nmclient.get_device(dev_op)
+ if not dev:
+ async_err_cb(NotFoundError("Device was unknown."))
+ return
+
+ if dev.get_type() == nmclient.DEVICE_TYPE_802_3_ETHERNET:
+ # We don't support wired 802.1x yet...
+ async_err_cb(UnsupportedError("Device type is unsupported by NMI."))
+ return
+
+ net = dev.get_network(net_op)
+ if not net:
+ async_err_cb(NotFoundError("Network was unknown."))
+ return
+
+ self._nmclient.get_key_for_network(net, async_cb, async_err_cb)
+
+ def get_key_for_network_cb(self, net, key, auth_alg, async_cb, async_err_cb, canceled=False):
+ """
+ Called by the NMClient when the Wireless Network Key dialog
+ is closed.
+ """
+ if canceled:
+ e = CanceledKeyRequestError("Request was canceled.")
+ # key dialog dialog was canceled; send the error back to NM
+ async_err_cb(e)
+ return
+
+ if not key or not auth_alg:
+ # no key returned, *** BUG ***; the key dialog
+ # should always return either a key + auth_alg, or a
+ #cancel error
+ raise RuntimeError("No key or auth alg given! Bug!")
+
+ we_cipher = None
+ if len(key) == 26:
+ we_cipher = IW_AUTH_CIPHER_WEP104
+ elif len(key) == 10:
+ we_cipher = IW_AUTH_CIPHER_WEP40
+ else:
+ raise RuntimeError("Invalid key length!")
+
+ # Stuff the returned key and auth algorithm into a security object
+ # and return it to NetworkManager
+ sec = Security.new_from_args(we_cipher, (key, auth_alg))
+ if not sec:
+ raise RuntimeError("Invalid security arguments.")
+ props = sec.get_properties()
+ a = tuple(props)
+ async_cb(*a)
+
+ def cancel_get_key_for_network(self):
+ # Tell the NMClient to close the key request dialog
+ self._nmclient.cancel_get_key_for_network()
diff --git a/services/nm/wepkeydialog.py b/services/nm/wepkeydialog.py
index 40c8a0b..fc35ee1 100644
--- a/services/nm/wepkeydialog.py
+++ b/services/nm/wepkeydialog.py
@@ -22,60 +22,60 @@ IW_AUTH_ALG_OPEN_SYSTEM = 0x00000001
IW_AUTH_ALG_SHARED_KEY = 0x00000002
class WEPKeyDialog(gtk.Dialog):
- def __init__(self, net, async_cb, async_err_cb):
- gtk.Dialog.__init__(self)
- self.set_title("Wireless Key Required")
+ def __init__(self, net, async_cb, async_err_cb):
+ gtk.Dialog.__init__(self)
+ self.set_title("Wireless Key Required")
- self._net = net
- self._async_cb = async_cb
- self._async_err_cb = async_err_cb
+ self._net = net
+ self._async_cb = async_cb
+ self._async_err_cb = async_err_cb
- self.set_has_separator(False)
+ self.set_has_separator(False)
- label = gtk.Label("A wireless encryption key is required for\n" \
- " the wireless network '%s'." % net.get_ssid())
- self.vbox.pack_start(label)
+ label = gtk.Label("A wireless encryption key is required for\n" \
+ " the wireless network '%s'." % net.get_ssid())
+ self.vbox.pack_start(label)
- self._entry = gtk.Entry()
- self._entry.props.visibility = False
- self._entry.connect('changed', self._entry_changed_cb)
- self.vbox.pack_start(self._entry)
- self.vbox.show_all()
+ self._entry = gtk.Entry()
+ self._entry.props.visibility = False
+ self._entry.connect('changed', self._entry_changed_cb)
+ self.vbox.pack_start(self._entry)
+ self.vbox.show_all()
- self.add_buttons(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
- gtk.STOCK_OK, gtk.RESPONSE_OK)
+ self.add_buttons(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
+ gtk.STOCK_OK, gtk.RESPONSE_OK)
- self.set_default_response(gtk.RESPONSE_OK)
- self._update_response_sensitivity()
+ self.set_default_response(gtk.RESPONSE_OK)
+ self._update_response_sensitivity()
- def get_key(self):
- return self._entry.get_text()
+ def get_key(self):
+ return self._entry.get_text()
- def get_auth_alg(self):
- return IW_AUTH_ALG_OPEN_SYSTEM
+ def get_auth_alg(self):
+ return IW_AUTH_ALG_OPEN_SYSTEM
- def get_network(self):
- return self._net
+ def get_network(self):
+ return self._net
- def get_callbacks(self):
- return (self._async_cb, self._async_err_cb)
+ def get_callbacks(self):
+ return (self._async_cb, self._async_err_cb)
- def _entry_changed_cb(self, entry):
- self._update_response_sensitivity()
+ def _entry_changed_cb(self, entry):
+ self._update_response_sensitivity()
- def _update_response_sensitivity(self):
- key = self.get_key()
+ def _update_response_sensitivity(self):
+ key = self.get_key()
- is_hex = True
- for c in key:
- if not 'a' <= c <= 'f' and not '0' <= c <= '9':
- is_hex = False
+ is_hex = True
+ for c in key:
+ if not 'a' <= c <= 'f' and not '0' <= c <= '9':
+ is_hex = False
- valid_len = (len(key) == 10 or len(key) == 26)
- self.set_response_sensitive(gtk.RESPONSE_OK, is_hex and valid_len)
+ valid_len = (len(key) == 10 or len(key) == 26)
+ self.set_response_sensitive(gtk.RESPONSE_OK, is_hex and valid_len)
if __name__ == "__main__":
- dialog = WEPKeyDialog()
- dialog.run()
+ dialog = WEPKeyDialog()
+ dialog.run()
- print dialog.get_key()
+ print dialog.get_key()
diff --git a/services/presence/Activity.py b/services/presence/Activity.py
index 065fb49..031c036 100644
--- a/services/presence/Activity.py
+++ b/services/presence/Activity.py
@@ -22,155 +22,155 @@ ACTIVITY_DBUS_INTERFACE = "org.laptop.Presence.Activity"
class ActivityDBusHelper(dbus.service.Object):
- def __init__(self, parent, bus_name, object_path):
- self._parent = parent
- self._bus_name = bus_name
- self._object_path = object_path
- dbus.service.Object.__init__(self, bus_name, self._object_path)
-
- @dbus.service.method(ACTIVITY_DBUS_INTERFACE,
- in_signature="s", out_signature="ao")
- def getServicesOfType(self, stype):
- ret = []
- for serv in self._parent.get_services_of_type(stype):
- ret.append(serv.object_path())
- return ret
-
- @dbus.service.method(ACTIVITY_DBUS_INTERFACE,
- in_signature="", out_signature="ao")
- def getServices(self):
- ret = []
- for serv in self._parent.get_services():
- ret.append(serv.object_path())
- return ret
-
- @dbus.service.method(ACTIVITY_DBUS_INTERFACE,
- in_signature="", out_signature="s")
- def getId(self):
- return self._parent.get_id()
-
- @dbus.service.method(ACTIVITY_DBUS_INTERFACE,
- in_signature="", out_signature="s")
- def getColor(self):
- return self._parent.get_color()
-
- @dbus.service.method(ACTIVITY_DBUS_INTERFACE,
- in_signature="", out_signature="ao")
- def getJoinedBuddies(self):
- ret = []
- for buddy in self._parent.get_joined_buddies():
- ret.append(buddy.object_path())
- return ret
-
- @dbus.service.signal(ACTIVITY_DBUS_INTERFACE,
- signature="o")
- def ServiceAppeared(self, object_path):
- pass
-
- @dbus.service.signal(ACTIVITY_DBUS_INTERFACE,
- signature="o")
- def ServiceDisappeared(self, object_path):
- pass
-
- @dbus.service.signal(ACTIVITY_DBUS_INTERFACE,
- signature="o")
- def BuddyJoined(self, object_path):
- pass
-
- @dbus.service.signal(ACTIVITY_DBUS_INTERFACE,
- signature="o")
- def BuddyLeft(self, object_path):
- pass
+ def __init__(self, parent, bus_name, object_path):
+ self._parent = parent
+ self._bus_name = bus_name
+ self._object_path = object_path
+ dbus.service.Object.__init__(self, bus_name, self._object_path)
+
+ @dbus.service.method(ACTIVITY_DBUS_INTERFACE,
+ in_signature="s", out_signature="ao")
+ def getServicesOfType(self, stype):
+ ret = []
+ for serv in self._parent.get_services_of_type(stype):
+ ret.append(serv.object_path())
+ return ret
+
+ @dbus.service.method(ACTIVITY_DBUS_INTERFACE,
+ in_signature="", out_signature="ao")
+ def getServices(self):
+ ret = []
+ for serv in self._parent.get_services():
+ ret.append(serv.object_path())
+ return ret
+
+ @dbus.service.method(ACTIVITY_DBUS_INTERFACE,
+ in_signature="", out_signature="s")
+ def getId(self):
+ return self._parent.get_id()
+
+ @dbus.service.method(ACTIVITY_DBUS_INTERFACE,
+ in_signature="", out_signature="s")
+ def getColor(self):
+ return self._parent.get_color()
+
+ @dbus.service.method(ACTIVITY_DBUS_INTERFACE,
+ in_signature="", out_signature="ao")
+ def getJoinedBuddies(self):
+ ret = []
+ for buddy in self._parent.get_joined_buddies():
+ ret.append(buddy.object_path())
+ return ret
+
+ @dbus.service.signal(ACTIVITY_DBUS_INTERFACE,
+ signature="o")
+ def ServiceAppeared(self, object_path):
+ pass
+
+ @dbus.service.signal(ACTIVITY_DBUS_INTERFACE,
+ signature="o")
+ def ServiceDisappeared(self, object_path):
+ pass
+
+ @dbus.service.signal(ACTIVITY_DBUS_INTERFACE,
+ signature="o")
+ def BuddyJoined(self, object_path):
+ pass
+
+ @dbus.service.signal(ACTIVITY_DBUS_INTERFACE,
+ signature="o")
+ def BuddyLeft(self, object_path):
+ pass
class Activity(object):
- def __init__(self, bus_name, object_id, initial_service):
- if not initial_service.get_activity_id():
- raise ValueError("Service must have a valid Activity ID")
- self._activity_id = initial_service.get_activity_id()
-
- self._buddies = []
- self._services = {} # service type -> list of Services
- self._color = None
- self._valid = False
-
- self._object_id = object_id
- self._object_path = "/org/laptop/Presence/Activities/%d" % self._object_id
- self._dbus_helper = ActivityDBusHelper(self, bus_name, self._object_path)
-
- self.add_service(initial_service)
-
- def object_path(self):
- return dbus.ObjectPath(self._object_path)
-
- def is_valid(self):
- """An activity is only valid when it's color is available."""
- return self._valid
-
- def get_id(self):
- return self._activity_id
-
- def get_color(self):
- return self._color
-
- def get_services(self):
- ret = []
- for serv_list in self._services.values():
- for service in serv_list:
- if service not in ret:
- ret.append(service)
- return ret
-
- def get_services_of_type(self, stype):
- if self._services.has_key(stype):
- return self._services[stype]
- return []
-
- def get_joined_buddies(self):
- buddies = []
- for serv_list in self._services.values():
- for serv in serv_list:
- owner = serv.get_owner()
- if owner and not owner in buddies and owner.is_valid():
- buddies.append(owner)
- return buddies
-
- def add_service(self, service):
- stype = service.get_type()
- if not self._services.has_key(stype):
- self._services[stype] = []
-
- if not self._color:
- color = service.get_one_property('color')
- if color:
- self._color = color
- self._valid = True
-
- # Send out the BuddyJoined signal if this is the first
- # service from the buddy that we've seen
- buddies = self.get_joined_buddies()
- serv_owner = service.get_owner()
- if serv_owner and serv_owner not in buddies and serv_owner.is_valid():
- self._dbus_helper.BuddyJoined(serv_owner.object_path())
- serv_owner.add_activity(self)
-
- if not service in self._services[stype]:
- self._services[stype].append(service)
- self._dbus_helper.ServiceAppeared(service.object_path())
-
- def remove_service(self, service):
- stype = service.get_type()
- if not self._services.has_key(stype):
- return
- self._services[stype].remove(service)
- self._dbus_helper.ServiceDisappeared(service.object_path())
- if len(self._services[stype]) == 0:
- del self._services[stype]
-
- # Send out the BuddyLeft signal if this is the last
- # service from the buddy
- buddies = self.get_joined_buddies()
- serv_owner = service.get_owner()
- if serv_owner and serv_owner not in buddies and serv_owner.is_valid():
- serv_owner.remove_activity(self)
- self._dbus_helper.BuddyLeft(serv_owner.object_path())
+ def __init__(self, bus_name, object_id, initial_service):
+ if not initial_service.get_activity_id():
+ raise ValueError("Service must have a valid Activity ID")
+ self._activity_id = initial_service.get_activity_id()
+
+ self._buddies = []
+ self._services = {} # service type -> list of Services
+ self._color = None
+ self._valid = False
+
+ self._object_id = object_id
+ self._object_path = "/org/laptop/Presence/Activities/%d" % self._object_id
+ self._dbus_helper = ActivityDBusHelper(self, bus_name, self._object_path)
+
+ self.add_service(initial_service)
+
+ def object_path(self):
+ return dbus.ObjectPath(self._object_path)
+
+ def is_valid(self):
+ """An activity is only valid when it's color is available."""
+ return self._valid
+
+ def get_id(self):
+ return self._activity_id
+
+ def get_color(self):
+ return self._color
+
+ def get_services(self):
+ ret = []
+ for serv_list in self._services.values():
+ for service in serv_list:
+ if service not in ret:
+ ret.append(service)
+ return ret
+
+ def get_services_of_type(self, stype):
+ if self._services.has_key(stype):
+ return self._services[stype]
+ return []
+
+ def get_joined_buddies(self):
+ buddies = []
+ for serv_list in self._services.values():
+ for serv in serv_list:
+ owner = serv.get_owner()
+ if owner and not owner in buddies and owner.is_valid():
+ buddies.append(owner)
+ return buddies
+
+ def add_service(self, service):
+ stype = service.get_type()
+ if not self._services.has_key(stype):
+ self._services[stype] = []
+
+ if not self._color:
+ color = service.get_one_property('color')
+ if color:
+ self._color = color
+ self._valid = True
+
+ # Send out the BuddyJoined signal if this is the first
+ # service from the buddy that we've seen
+ buddies = self.get_joined_buddies()
+ serv_owner = service.get_owner()
+ if serv_owner and serv_owner not in buddies and serv_owner.is_valid():
+ self._dbus_helper.BuddyJoined(serv_owner.object_path())
+ serv_owner.add_activity(self)
+
+ if not service in self._services[stype]:
+ self._services[stype].append(service)
+ self._dbus_helper.ServiceAppeared(service.object_path())
+
+ def remove_service(self, service):
+ stype = service.get_type()
+ if not self._services.has_key(stype):
+ return
+ self._services[stype].remove(service)
+ self._dbus_helper.ServiceDisappeared(service.object_path())
+ if len(self._services[stype]) == 0:
+ del self._services[stype]
+
+ # Send out the BuddyLeft signal if this is the last
+ # service from the buddy
+ buddies = self.get_joined_buddies()
+ serv_owner = service.get_owner()
+ if serv_owner and serv_owner not in buddies and serv_owner.is_valid():
+ serv_owner.remove_activity(self)
+ self._dbus_helper.BuddyLeft(serv_owner.object_path())
diff --git a/services/presence/Buddy.py b/services/presence/Buddy.py
index a49b46a..31d8fe1 100644
--- a/services/presence/Buddy.py
+++ b/services/presence/Buddy.py
@@ -30,433 +30,433 @@ _BUDDY_KEY_COLOR = 'color'
_BUDDY_KEY_CURACT = 'curact'
class NotFoundError(Exception):
- pass
+ pass
class BuddyDBusHelper(dbus.service.Object):
- def __init__(self, parent, bus_name, object_path):
- self._parent = parent
- self._bus_name = bus_name
- self._object_path = object_path
- dbus.service.Object.__init__(self, bus_name, self._object_path)
-
- @dbus.service.signal(BUDDY_DBUS_INTERFACE,
- signature="o")
- def ServiceAppeared(self, object_path):
- pass
-
- @dbus.service.signal(BUDDY_DBUS_INTERFACE,
- signature="o")
- def ServiceDisappeared(self, object_path):
- pass
-
- @dbus.service.signal(BUDDY_DBUS_INTERFACE,
- signature="")
- def Disappeared(self):
- pass
-
- @dbus.service.signal(BUDDY_DBUS_INTERFACE,
- signature="ao")
- def CurrentActivityChanged(self, activities):
- pass
-
- @dbus.service.signal(BUDDY_DBUS_INTERFACE,
- signature="")
- def IconChanged(self):
- pass
-
- @dbus.service.signal(BUDDY_DBUS_INTERFACE,
- signature="o")
- def JoinedActivity(self, object_path):
- pass
-
- @dbus.service.signal(BUDDY_DBUS_INTERFACE,
- signature="o")
- def LeftActivity(self, object_path):
- pass
-
- @dbus.service.signal(BUDDY_DBUS_INTERFACE,
- signature="as")
- def PropertyChanged(self, prop_list):
- pass
-
- @dbus.service.method(BUDDY_DBUS_INTERFACE,
- in_signature="", out_signature="ay")
- def getIcon(self):
- icon = self._parent.get_icon()
- if not icon:
- return ""
- return icon
-
- @dbus.service.method(BUDDY_DBUS_INTERFACE,
- in_signature="so", out_signature="o")
- def getServiceOfType(self, stype, activity_op):
- activity = None
- # "/" is the placeholder for None
- if activity_op != "/":
- for act in self._parent.get_joined_activities():
- if act.object_path() == activity_op:
- activity = act
- if not activity:
- raise NotFoundError("Not found")
-
- service = self._parent.get_service_of_type(stype, activity)
- if not service:
- raise NotFoundError("Not found")
- return service.object_path()
-
- @dbus.service.method(BUDDY_DBUS_INTERFACE,
- in_signature="", out_signature="ao")
- def getJoinedActivities(self):
- acts = []
- for act in self._parent.get_joined_activities():
- acts.append(act.object_path())
- return acts
-
- @dbus.service.method(BUDDY_DBUS_INTERFACE,
- in_signature="", out_signature="a{sv}")
- def getProperties(self):
- props = {}
- props['name'] = self._parent.get_name()
- addr = self._parent.get_address()
- if addr:
- props['ip4_address'] = addr
- props['owner'] = self._parent.is_owner()
- color = self._parent.get_color()
- if color:
- props[_BUDDY_KEY_COLOR] = self._parent.get_color()
- return props
-
- @dbus.service.method(BUDDY_DBUS_INTERFACE,
- in_signature="", out_signature="o")
- def getCurrentActivity(self):
- activity = self._parent.get_current_activity()
- if not activity:
- raise NotFoundError()
- return activity.object_path()
+ def __init__(self, parent, bus_name, object_path):
+ self._parent = parent
+ self._bus_name = bus_name
+ self._object_path = object_path
+ dbus.service.Object.__init__(self, bus_name, self._object_path)
+
+ @dbus.service.signal(BUDDY_DBUS_INTERFACE,
+ signature="o")
+ def ServiceAppeared(self, object_path):
+ pass
+
+ @dbus.service.signal(BUDDY_DBUS_INTERFACE,
+ signature="o")
+ def ServiceDisappeared(self, object_path):
+ pass
+
+ @dbus.service.signal(BUDDY_DBUS_INTERFACE,
+ signature="")
+ def Disappeared(self):
+ pass
+
+ @dbus.service.signal(BUDDY_DBUS_INTERFACE,
+ signature="ao")
+ def CurrentActivityChanged(self, activities):
+ pass
+
+ @dbus.service.signal(BUDDY_DBUS_INTERFACE,
+ signature="")
+ def IconChanged(self):
+ pass
+
+ @dbus.service.signal(BUDDY_DBUS_INTERFACE,
+ signature="o")
+ def JoinedActivity(self, object_path):
+ pass
+
+ @dbus.service.signal(BUDDY_DBUS_INTERFACE,
+ signature="o")
+ def LeftActivity(self, object_path):
+ pass
+
+ @dbus.service.signal(BUDDY_DBUS_INTERFACE,
+ signature="as")
+ def PropertyChanged(self, prop_list):
+ pass
+
+ @dbus.service.method(BUDDY_DBUS_INTERFACE,
+ in_signature="", out_signature="ay")
+ def getIcon(self):
+ icon = self._parent.get_icon()
+ if not icon:
+ return ""
+ return icon
+
+ @dbus.service.method(BUDDY_DBUS_INTERFACE,
+ in_signature="so", out_signature="o")
+ def getServiceOfType(self, stype, activity_op):
+ activity = None
+ # "/" is the placeholder for None
+ if activity_op != "/":
+ for act in self._parent.get_joined_activities():
+ if act.object_path() == activity_op:
+ activity = act
+ if not activity:
+ raise NotFoundError("Not found")
+
+ service = self._parent.get_service_of_type(stype, activity)
+ if not service:
+ raise NotFoundError("Not found")
+ return service.object_path()
+
+ @dbus.service.method(BUDDY_DBUS_INTERFACE,
+ in_signature="", out_signature="ao")
+ def getJoinedActivities(self):
+ acts = []
+ for act in self._parent.get_joined_activities():
+ acts.append(act.object_path())
+ return acts
+
+ @dbus.service.method(BUDDY_DBUS_INTERFACE,
+ in_signature="", out_signature="a{sv}")
+ def getProperties(self):
+ props = {}
+ props['name'] = self._parent.get_name()
+ addr = self._parent.get_address()
+ if addr:
+ props['ip4_address'] = addr
+ props['owner'] = self._parent.is_owner()
+ color = self._parent.get_color()
+ if color:
+ props[_BUDDY_KEY_COLOR] = self._parent.get_color()
+ return props
+
+ @dbus.service.method(BUDDY_DBUS_INTERFACE,
+ in_signature="", out_signature="o")
+ def getCurrentActivity(self):
+ activity = self._parent.get_current_activity()
+ if not activity:
+ raise NotFoundError()
+ return activity.object_path()
class Buddy(object):
- """Represents another person on the network and keeps track of the
- activities and resources they make available for sharing."""
-
- def __init__(self, bus_name, object_id, service, icon_cache):
- if not bus_name:
- raise ValueError("DBus bus name must be valid")
- if not object_id or not isinstance(object_id, int):
- raise ValueError("object id must be a valid number")
- # Normal Buddy objects must be created with a valid service,
- # owner objects do not
- if not isinstance(self, Owner):
- if not isinstance(service, Service.Service):
- raise ValueError("service must be a valid service object")
-
- self._services = {}
- self._activities = {}
-
- self._icon_cache = icon_cache
-
- self._nick_name = None
- self._address = None
- if service is not None:
- self._nick_name = service.get_name()
- self._address = service.get_source_address()
- self._color = None
- self._current_activity = None
- self._valid = False
- self._icon = None
- self._icon_tries = 0
-
- self._object_id = object_id
- self._object_path = BUDDY_DBUS_OBJECT_PATH + str(self._object_id)
- self._dbus_helper = BuddyDBusHelper(self, bus_name, self._object_path)
-
- self._buddy_presence_service = None
- if service is not None:
- self.add_service(service)
-
- def object_path(self):
- return dbus.ObjectPath(self._object_path)
-
- def _request_buddy_icon_cb(self, result_status, response, user_data):
- """Callback when icon request has completed."""
- from sugar.p2p import network
- icon = response
- service = user_data
- if result_status == network.RESULT_SUCCESS:
- if icon and len(icon):
- icon = base64.b64decode(icon)
- self._set_icon(icon)
- self._icon_cache.add_icon(icon)
-
- if (result_status == network.RESULT_FAILED or not icon) and self._icon_tries < 3:
- self._icon_tries = self._icon_tries + 1
- if self._icon_tries >= 3:
- logging.debug("Failed to retrieve buddy icon for '%s'." % self._nick_name)
- gobject.timeout_add(1000, self._get_buddy_icon, service, True)
- return False
-
- def _get_buddy_icon(self, service, retry=False):
- """Get the buddy's icon. Check the cache first, if its
- not there get the icon from the buddy over the network."""
- if retry != True:
- # Only hit the cache once
- icon_hash = service.get_one_property('icon-hash')
- if icon_hash is not None:
- icon = self._icon_cache.get_icon(icon_hash)
- if icon:
- logging.debug("%s: icon cache hit for %s." % (self._nick_name, icon_hash))
- self._set_icon(icon)
- return False
- logging.debug("%s: icon cache miss, fetching icon from buddy..." % self._nick_name)
-
- from sugar.p2p import Stream
- buddy_stream = Stream.Stream.new_from_service(service, start_reader=False)
- writer = buddy_stream.new_writer(service)
- success = writer.custom_request("get_buddy_icon", self._request_buddy_icon_cb, service)
- if not success:
- del writer, buddy_stream
- gobject.timeout_add(1000, self._get_buddy_icon, service, True)
- return False
-
- def _get_service_key(self, service):
- return (service.get_type(), service.get_activity_id())
-
- def add_service(self, service):
- """Adds a new service to this buddy's service list, returning
- True if the service was successfully added, and False if it was not."""
- if service.get_name() != self._nick_name:
- logging.error("Service and buddy nick names doesn't match: " \
- "%s %s" % (service.get_name(), self._nick_name))
- return False
-
- source_addr = service.get_source_address()
- if source_addr != self._address:
- logging.error("Service source and buddy address doesn't " \
- "match: %s %s" % (source_addr, self._address))
- return False
- return self._internal_add_service(service)
-
- def _internal_add_service(self, service):
- service_key = self._get_service_key(service)
- if service_key in self._services.keys():
- logging.error("Service already known: %s %s" % (service_key[0],
- service_key[1]))
- return False
-
- if service.get_type() == PRESENCE_SERVICE_TYPE and self._buddy_presence_service:
- # already have a presence service for this buddy
- logging.debug("!!! Tried to add a buddy presence service when " \
- "one already existed.")
- return False
-
- logging.debug("Buddy %s added service type %s id %s" % (self._nick_name,
- service.get_type(), service.get_activity_id()))
- self._services[service_key] = service
- service.set_owner(self)
-
- if service.get_type() == PRESENCE_SERVICE_TYPE:
- self._buddy_presence_service = service
- # A buddy isn't valid until its official presence
- # service has been found and resolved
- self._valid = True
- self._get_buddy_icon(service)
- self._color = service.get_one_property(_BUDDY_KEY_COLOR)
- self._current_activity = service.get_one_property(_BUDDY_KEY_CURACT)
- # Monitor further buddy property changes, like current activity
- # and color
- service.connect('property-changed',
- self.__buddy_presence_service_property_changed_cb)
-
- if self._valid:
- self._dbus_helper.ServiceAppeared(service.object_path())
- return True
-
- def __buddy_presence_service_property_changed_cb(self, service, keys):
- if _BUDDY_KEY_COLOR in keys:
- new_color = service.get_one_property(_BUDDY_KEY_COLOR)
- if new_color and self._color != new_color:
- self._color = new_color
- self._dbus_helper.PropertyChanged([_BUDDY_KEY_COLOR])
- if _BUDDY_KEY_CURACT in keys:
- # Three cases here:
- # 1) Buddy didn't publish a 'curact' key at all; we do nothing
- # 2) Buddy published a blank/zero-length 'curact' key; we send
- # a current-activity-changed signal for no activity
- # 3) Buddy published a non-zero-length 'curact' key; we send
- # a current-activity-changed signal if we know about the
- # activity already, if not we postpone until the activity
- # is found on the network and added to the buddy
- new_curact = service.get_one_property(_BUDDY_KEY_CURACT)
- if new_curact and self._current_activity != new_curact:
- if not len(new_curact):
- new_curact = None
- self._current_activity = new_curact
- if self._activities.has_key(self._current_activity):
- # Case (3) above, valid activity id
- activity = self._activities[self._current_activity]
- if activity.is_valid():
- self._dbus_helper.CurrentActivityChanged([activity.object_path()])
- elif not self._current_activity:
- # Case (2) above, no current activity
- self._dbus_helper.CurrentActivityChanged([])
-
- def __find_service_by_activity_id(self, actid):
- for serv in self._services.values():
- if serv.get_activity_id() == actid:
- return serv
- return None
-
- def add_activity(self, activity):
- if activity in self._activities.values():
- return
- actid = activity.get_id()
- if not self.__find_service_by_activity_id(actid):
- raise RuntimeError("Tried to add activity for which we had no service")
- self._activities[actid] = activity
- if activity.is_valid():
- self._dbus_helper.JoinedActivity(activity.object_path())
-
- # If when we received a current activity update from the buddy,
- # but didn't know about that activity yet, and now we do know about
- # it, we need to send out the changed activity signal
- if actid == self._current_activity:
- self._dbus_helper.CurrentActivityChanged([activity.object_path()])
-
- def remove_service(self, service):
- """Remove a service from a buddy; ie, the activity was closed
- or the buddy went away."""
- if service.get_source_address() != self._address:
- return
- if service.get_name() != self._nick_name:
- return
-
- if service.get_type() == PRESENCE_SERVICE_TYPE \
- and self._buddy_presence_service \
- and service != self._buddy_presence_service:
- logging.debug("!!! Tried to remove a spurious buddy presence service.")
- return
-
- service_key = self._get_service_key(service)
- if self._services.has_key(service_key):
- if self._valid:
- self._dbus_helper.ServiceDisappeared(service.object_path())
- del self._services[service_key]
-
- if service.get_type() == PRESENCE_SERVICE_TYPE:
- self._valid = False
- self._dbus_helper.Disappeared()
-
- def remove_activity(self, activity):
- actid = activity.get_id()
- if not self._activities.has_key(actid):
- return
- del self._activities[actid]
- if activity.is_valid():
- self._dbus_helper.LeftActivity(activity.object_path())
-
- # If we just removed the buddy's current activity,
- # send out a signal
- if actid == self._current_activity:
- self._current_activity = None
- self._dbus_helper.CurrentActivityChanged([])
-
- def get_joined_activities(self):
- acts = []
- for act in self._activities.values():
- if act.is_valid():
- acts.append(act)
- return acts
-
- def get_service_of_type(self, stype, activity=None):
- """Return a service of a certain type, or None if the buddy
- doesn't provide that service."""
- if not stype:
- raise RuntimeError("Need to specify a service type.")
-
- if activity and not activity.is_valid():
- raise RuntimeError("Activity is not yet valid.")
-
- if activity:
- key = (stype, activity.get_id())
- else:
- key = (stype, None)
- if self._services.has_key(key):
- return self._services[key]
- return None
-
- def is_valid(self):
- """Return whether the buddy is valid or not. A buddy is
- not valid until its official presence service has been found
- and successfully resolved."""
- return self._valid
-
- def get_icon(self):
- """Return the buddies icon, if any."""
- return self._icon
-
- def get_address(self):
- return self._address
-
- def get_name(self):
- return self._nick_name
-
- def get_color(self):
- return self._color
-
- def get_current_activity(self):
- if not self._current_activity:
- return None
- if not self._activities.has_key(self._current_activity):
- return None
- return self._activities[self._current_activity]
-
- def _set_icon(self, icon):
- """Can only set icon for other buddies. The Owner
- takes care of setting it's own icon."""
- if icon != self._icon:
- self._icon = icon
- self._dbus_helper.IconChanged()
-
- def is_owner(self):
- return False
+ """Represents another person on the network and keeps track of the
+ activities and resources they make available for sharing."""
+
+ def __init__(self, bus_name, object_id, service, icon_cache):
+ if not bus_name:
+ raise ValueError("DBus bus name must be valid")
+ if not object_id or not isinstance(object_id, int):
+ raise ValueError("object id must be a valid number")
+ # Normal Buddy objects must be created with a valid service,
+ # owner objects do not
+ if not isinstance(self, Owner):
+ if not isinstance(service, Service.Service):
+ raise ValueError("service must be a valid service object")
+
+ self._services = {}
+ self._activities = {}
+
+ self._icon_cache = icon_cache
+
+ self._nick_name = None
+ self._address = None
+ if service is not None:
+ self._nick_name = service.get_name()
+ self._address = service.get_source_address()
+ self._color = None
+ self._current_activity = None
+ self._valid = False
+ self._icon = None
+ self._icon_tries = 0
+
+ self._object_id = object_id
+ self._object_path = BUDDY_DBUS_OBJECT_PATH + str(self._object_id)
+ self._dbus_helper = BuddyDBusHelper(self, bus_name, self._object_path)
+
+ self._buddy_presence_service = None
+ if service is not None:
+ self.add_service(service)
+
+ def object_path(self):
+ return dbus.ObjectPath(self._object_path)
+
+ def _request_buddy_icon_cb(self, result_status, response, user_data):
+ """Callback when icon request has completed."""
+ from sugar.p2p import network
+ icon = response
+ service = user_data
+ if result_status == network.RESULT_SUCCESS:
+ if icon and len(icon):
+ icon = base64.b64decode(icon)
+ self._set_icon(icon)
+ self._icon_cache.add_icon(icon)
+
+ if (result_status == network.RESULT_FAILED or not icon) and self._icon_tries < 3:
+ self._icon_tries = self._icon_tries + 1
+ if self._icon_tries >= 3:
+ logging.debug("Failed to retrieve buddy icon for '%s'." % self._nick_name)
+ gobject.timeout_add(1000, self._get_buddy_icon, service, True)
+ return False
+
+ def _get_buddy_icon(self, service, retry=False):
+ """Get the buddy's icon. Check the cache first, if its
+ not there get the icon from the buddy over the network."""
+ if retry != True:
+ # Only hit the cache once
+ icon_hash = service.get_one_property('icon-hash')
+ if icon_hash is not None:
+ icon = self._icon_cache.get_icon(icon_hash)
+ if icon:
+ logging.debug("%s: icon cache hit for %s." % (self._nick_name, icon_hash))
+ self._set_icon(icon)
+ return False
+ logging.debug("%s: icon cache miss, fetching icon from buddy..." % self._nick_name)
+
+ from sugar.p2p import Stream
+ buddy_stream = Stream.Stream.new_from_service(service, start_reader=False)
+ writer = buddy_stream.new_writer(service)
+ success = writer.custom_request("get_buddy_icon", self._request_buddy_icon_cb, service)
+ if not success:
+ del writer, buddy_stream
+ gobject.timeout_add(1000, self._get_buddy_icon, service, True)
+ return False
+
+ def _get_service_key(self, service):
+ return (service.get_type(), service.get_activity_id())
+
+ def add_service(self, service):
+ """Adds a new service to this buddy's service list, returning
+ True if the service was successfully added, and False if it was not."""
+ if service.get_name() != self._nick_name:
+ logging.error("Service and buddy nick names doesn't match: " \
+ "%s %s" % (service.get_name(), self._nick_name))
+ return False
+
+ source_addr = service.get_source_address()
+ if source_addr != self._address:
+ logging.error("Service source and buddy address doesn't " \
+ "match: %s %s" % (source_addr, self._address))
+ return False
+ return self._internal_add_service(service)
+
+ def _internal_add_service(self, service):
+ service_key = self._get_service_key(service)
+ if service_key in self._services.keys():
+ logging.error("Service already known: %s %s" % (service_key[0],
+ service_key[1]))
+ return False
+
+ if service.get_type() == PRESENCE_SERVICE_TYPE and self._buddy_presence_service:
+ # already have a presence service for this buddy
+ logging.debug("!!! Tried to add a buddy presence service when " \
+ "one already existed.")
+ return False
+
+ logging.debug("Buddy %s added service type %s id %s" % (self._nick_name,
+ service.get_type(), service.get_activity_id()))
+ self._services[service_key] = service
+ service.set_owner(self)
+
+ if service.get_type() == PRESENCE_SERVICE_TYPE:
+ self._buddy_presence_service = service
+ # A buddy isn't valid until its official presence
+ # service has been found and resolved
+ self._valid = True
+ self._get_buddy_icon(service)
+ self._color = service.get_one_property(_BUDDY_KEY_COLOR)
+ self._current_activity = service.get_one_property(_BUDDY_KEY_CURACT)
+ # Monitor further buddy property changes, like current activity
+ # and color
+ service.connect('property-changed',
+ self.__buddy_presence_service_property_changed_cb)
+
+ if self._valid:
+ self._dbus_helper.ServiceAppeared(service.object_path())
+ return True
+
+ def __buddy_presence_service_property_changed_cb(self, service, keys):
+ if _BUDDY_KEY_COLOR in keys:
+ new_color = service.get_one_property(_BUDDY_KEY_COLOR)
+ if new_color and self._color != new_color:
+ self._color = new_color
+ self._dbus_helper.PropertyChanged([_BUDDY_KEY_COLOR])
+ if _BUDDY_KEY_CURACT in keys:
+ # Three cases here:
+ # 1) Buddy didn't publish a 'curact' key at all; we do nothing
+ # 2) Buddy published a blank/zero-length 'curact' key; we send
+ # a current-activity-changed signal for no activity
+ # 3) Buddy published a non-zero-length 'curact' key; we send
+ # a current-activity-changed signal if we know about the
+ # activity already, if not we postpone until the activity
+ # is found on the network and added to the buddy
+ new_curact = service.get_one_property(_BUDDY_KEY_CURACT)
+ if new_curact and self._current_activity != new_curact:
+ if not len(new_curact):
+ new_curact = None
+ self._current_activity = new_curact
+ if self._activities.has_key(self._current_activity):
+ # Case (3) above, valid activity id
+ activity = self._activities[self._current_activity]
+ if activity.is_valid():
+ self._dbus_helper.CurrentActivityChanged([activity.object_path()])
+ elif not self._current_activity:
+ # Case (2) above, no current activity
+ self._dbus_helper.CurrentActivityChanged([])
+
+ def __find_service_by_activity_id(self, actid):
+ for serv in self._services.values():
+ if serv.get_activity_id() == actid:
+ return serv
+ return None
+
+ def add_activity(self, activity):
+ if activity in self._activities.values():
+ return
+ actid = activity.get_id()
+ if not self.__find_service_by_activity_id(actid):
+ raise RuntimeError("Tried to add activity for which we had no service")
+ self._activities[actid] = activity
+ if activity.is_valid():
+ self._dbus_helper.JoinedActivity(activity.object_path())
+
+ # If when we received a current activity update from the buddy,
+ # but didn't know about that activity yet, and now we do know about
+ # it, we need to send out the changed activity signal
+ if actid == self._current_activity:
+ self._dbus_helper.CurrentActivityChanged([activity.object_path()])
+
+ def remove_service(self, service):
+ """Remove a service from a buddy; ie, the activity was closed
+ or the buddy went away."""
+ if service.get_source_address() != self._address:
+ return
+ if service.get_name() != self._nick_name:
+ return
+
+ if service.get_type() == PRESENCE_SERVICE_TYPE \
+ and self._buddy_presence_service \
+ and service != self._buddy_presence_service:
+ logging.debug("!!! Tried to remove a spurious buddy presence service.")
+ return
+
+ service_key = self._get_service_key(service)
+ if self._services.has_key(service_key):
+ if self._valid:
+ self._dbus_helper.ServiceDisappeared(service.object_path())
+ del self._services[service_key]
+
+ if service.get_type() == PRESENCE_SERVICE_TYPE:
+ self._valid = False
+ self._dbus_helper.Disappeared()
+
+ def remove_activity(self, activity):
+ actid = activity.get_id()
+ if not self._activities.has_key(actid):
+ return
+ del self._activities[actid]
+ if activity.is_valid():
+ self._dbus_helper.LeftActivity(activity.object_path())
+
+ # If we just removed the buddy's current activity,
+ # send out a signal
+ if actid == self._current_activity:
+ self._current_activity = None
+ self._dbus_helper.CurrentActivityChanged([])
+
+ def get_joined_activities(self):
+ acts = []
+ for act in self._activities.values():
+ if act.is_valid():
+ acts.append(act)
+ return acts
+
+ def get_service_of_type(self, stype, activity=None):
+ """Return a service of a certain type, or None if the buddy
+ doesn't provide that service."""
+ if not stype:
+ raise RuntimeError("Need to specify a service type.")
+
+ if activity and not activity.is_valid():
+ raise RuntimeError("Activity is not yet valid.")
+
+ if activity:
+ key = (stype, activity.get_id())
+ else:
+ key = (stype, None)
+ if self._services.has_key(key):
+ return self._services[key]
+ return None
+
+ def is_valid(self):
+ """Return whether the buddy is valid or not. A buddy is
+ not valid until its official presence service has been found
+ and successfully resolved."""
+ return self._valid
+
+ def get_icon(self):
+ """Return the buddies icon, if any."""
+ return self._icon
+
+ def get_address(self):
+ return self._address
+
+ def get_name(self):
+ return self._nick_name
+
+ def get_color(self):
+ return self._color
+
+ def get_current_activity(self):
+ if not self._current_activity:
+ return None
+ if not self._activities.has_key(self._current_activity):
+ return None
+ return self._activities[self._current_activity]
+
+ def _set_icon(self, icon):
+ """Can only set icon for other buddies. The Owner
+ takes care of setting it's own icon."""
+ if icon != self._icon:
+ self._icon = icon
+ self._dbus_helper.IconChanged()
+
+ def is_owner(self):
+ return False
class Owner(Buddy):
- """Class representing the owner of the machine. This is the client
- portion of the Owner, paired with the server portion in Owner.py."""
- def __init__(self, ps, bus_name, object_id, icon_cache):
- Buddy.__init__(self, bus_name, object_id, None, icon_cache)
- self._nick_name = profile.get_nick_name()
- self._color = profile.get_color()
- self._ps = ps
-
- def add_service(self, service):
- """Adds a new service to this buddy's service list, returning
- True if the service was successfully added, and False if it was not."""
- if service.get_name() != self._nick_name:
- logging.error("Service and buddy nick names doesn't match: " \
- "%s %s" % (service.get_name(), self._nick_name))
- return False
-
- # The Owner initially doesn't have an address, so the first
- # service added to the Owner determines the owner's address
- source_addr = service.get_source_address()
- if self._address is None and service.is_local():
- self._address = source_addr
- self._dbus_helper.PropertyChanged(['ip4_address'])
-
- # The owner bypasses address checks and only cares if
- # avahi says the service is a local service
- if not service.is_local():
- logging.error("Cannot add remote service to owner object.")
- return False
-
- logging.debug("Adding owner service %s.%s at %s:%d." % (service.get_name(),
- service.get_type(), service.get_source_address(),
- service.get_port()))
- return self._internal_add_service(service)
-
- def is_owner(self):
- return True
+ """Class representing the owner of the machine. This is the client
+ portion of the Owner, paired with the server portion in Owner.py."""
+ def __init__(self, ps, bus_name, object_id, icon_cache):
+ Buddy.__init__(self, bus_name, object_id, None, icon_cache)
+ self._nick_name = profile.get_nick_name()
+ self._color = profile.get_color()
+ self._ps = ps
+
+ def add_service(self, service):
+ """Adds a new service to this buddy's service list, returning
+ True if the service was successfully added, and False if it was not."""
+ if service.get_name() != self._nick_name:
+ logging.error("Service and buddy nick names doesn't match: " \
+ "%s %s" % (service.get_name(), self._nick_name))
+ return False
+
+ # The Owner initially doesn't have an address, so the first
+ # service added to the Owner determines the owner's address
+ source_addr = service.get_source_address()
+ if self._address is None and service.is_local():
+ self._address = source_addr
+ self._dbus_helper.PropertyChanged(['ip4_address'])
+
+ # The owner bypasses address checks and only cares if
+ # avahi says the service is a local service
+ if not service.is_local():
+ logging.error("Cannot add remote service to owner object.")
+ return False
+
+ logging.debug("Adding owner service %s.%s at %s:%d." % (service.get_name(),
+ service.get_type(), service.get_source_address(),
+ service.get_port()))
+ return self._internal_add_service(service)
+
+ def is_owner(self):
+ return True
#################################################################
@@ -468,62 +468,62 @@ import Service
__objid_seq = 0
def _next_objid():
- global __objid_seq
- __objid_seq = __objid_seq + 1
- return __objid_seq
+ global __objid_seq
+ __objid_seq = __objid_seq + 1
+ return __objid_seq
class BuddyTestCase(unittest.TestCase):
- _DEF_NAME = u"Tommy"
- _DEF_STYPE = unicode(PRESENCE_SERVICE_TYPE)
- _DEF_DOMAIN = u"local"
- _DEF_ADDRESS = u"1.1.1.1"
- _DEF_PORT = 1234
-
- def __init__(self, name):
- self._bus = dbus.SessionBus()
- self._bus_name = dbus.service.BusName('org.laptop.Presence', bus=self._bus)
- unittest.TestCase.__init__(self, name)
-
- def __del__(self):
- del self._bus_name
- del self._bus
-
- def _test_init_fail(self, service, fail_msg):
- """Test something we expect to fail."""
- try:
- objid = _next_objid()
- buddy = Buddy(self._bus_name, objid, service, owner=False)
- except ValueError, exc:
- pass
- else:
- self.fail("expected a ValueError for %s." % fail_msg)
-
- def testService(self):
- service = None
- self._test_init_fail(service, "invalid service")
-
- def testGoodInit(self):
- objid = _next_objid()
- service = Service.Service(self._bus_name, objid, self._DEF_NAME, self._DEF_STYPE, self._DEF_DOMAIN,
- self._DEF_ADDRESS, self._DEF_PORT)
- objid = _next_objid()
- buddy = Buddy(self._bus_name, objid, service)
- assert buddy.get_name() == self._DEF_NAME, "buddy name wasn't correct after init."
- assert buddy.get_address() == self._DEF_ADDRESS, "buddy address wasn't correct after init."
- assert buddy.object_path() == BUDDY_DBUS_OBJECT_PATH + str(objid)
-
- def addToSuite(suite):
- suite.addTest(BuddyTestCase("testService"))
- suite.addTest(BuddyTestCase("testGoodInit"))
- addToSuite = staticmethod(addToSuite)
+ _DEF_NAME = u"Tommy"
+ _DEF_STYPE = unicode(PRESENCE_SERVICE_TYPE)
+ _DEF_DOMAIN = u"local"
+ _DEF_ADDRESS = u"1.1.1.1"
+ _DEF_PORT = 1234
+
+ def __init__(self, name):
+ self._bus = dbus.SessionBus()
+ self._bus_name = dbus.service.BusName('org.laptop.Presence', bus=self._bus)
+ unittest.TestCase.__init__(self, name)
+
+ def __del__(self):
+ del self._bus_name
+ del self._bus
+
+ def _test_init_fail(self, service, fail_msg):
+ """Test something we expect to fail."""
+ try:
+ objid = _next_objid()
+ buddy = Buddy(self._bus_name, objid, service, owner=False)
+ except ValueError, exc:
+ pass
+ else:
+ self.fail("expected a ValueError for %s." % fail_msg)
+
+ def testService(self):
+ service = None
+ self._test_init_fail(service, "invalid service")
+
+ def testGoodInit(self):
+ objid = _next_objid()
+ service = Service.Service(self._bus_name, objid, self._DEF_NAME, self._DEF_STYPE, self._DEF_DOMAIN,
+ self._DEF_ADDRESS, self._DEF_PORT)
+ objid = _next_objid()
+ buddy = Buddy(self._bus_name, objid, service)
+ assert buddy.get_name() == self._DEF_NAME, "buddy name wasn't correct after init."
+ assert buddy.get_address() == self._DEF_ADDRESS, "buddy address wasn't correct after init."
+ assert buddy.object_path() == BUDDY_DBUS_OBJECT_PATH + str(objid)
+
+ def addToSuite(suite):
+ suite.addTest(BuddyTestCase("testService"))
+ suite.addTest(BuddyTestCase("testGoodInit"))
+ addToSuite = staticmethod(addToSuite)
def main():
- suite = unittest.TestSuite()
- BuddyTestCase.addToSuite(suite)
- runner = unittest.TextTestRunner()
- runner.run(suite)
+ suite = unittest.TestSuite()
+ BuddyTestCase.addToSuite(suite)
+ runner = unittest.TextTestRunner()
+ runner.run(suite)
if __name__ == "__main__":
- main()
+ main()
diff --git a/services/presence/BuddyIconCache.py b/services/presence/BuddyIconCache.py
index 643116f..7f9952a 100644
--- a/services/presence/BuddyIconCache.py
+++ b/services/presence/BuddyIconCache.py
@@ -19,59 +19,59 @@ from sugar import env
from sugar import util
class BuddyIconCache(object):
- """Caches icons on disk and finds them based on md5 hash."""
- def __init__(self):
- ppath = env.get_profile_path()
- self._cachepath = os.path.join(ppath, "cache", "buddy-icons")
- if not os.path.exists(self._cachepath):
- os.makedirs(self._cachepath)
+ """Caches icons on disk and finds them based on md5 hash."""
+ def __init__(self):
+ ppath = env.get_profile_path()
+ self._cachepath = os.path.join(ppath, "cache", "buddy-icons")
+ if not os.path.exists(self._cachepath):
+ os.makedirs(self._cachepath)
- self._cache = {}
+ self._cache = {}
- # Read all cached icons and their sums
- for fname in os.listdir(self._cachepath):
- m = md5.new()
- data = self._get_icon_data(fname)
- if len(data) == 0:
- continue
- m.update(data)
- printable_hash = util.printable_hash(m.digest())
- self._cache[printable_hash] = fname
- del m
+ # Read all cached icons and their sums
+ for fname in os.listdir(self._cachepath):
+ m = md5.new()
+ data = self._get_icon_data(fname)
+ if len(data) == 0:
+ continue
+ m.update(data)
+ printable_hash = util.printable_hash(m.digest())
+ self._cache[printable_hash] = fname
+ del m
- def _get_icon_data(self, fname):
- fd = open(os.path.join(self._cachepath, fname), "r")
- data = fd.read()
- fd.close()
- del fd
- return data
+ def _get_icon_data(self, fname):
+ fd = open(os.path.join(self._cachepath, fname), "r")
+ data = fd.read()
+ fd.close()
+ del fd
+ return data
- def get_icon(self, printable_hash):
- if not isinstance(printable_hash, unicode):
- raise RuntimeError("printable_hash must be a unicode string.")
- try:
- fname = self._cache[printable_hash]
- return self._get_icon_data(fname)
- except KeyError:
- pass
- return None
+ def get_icon(self, printable_hash):
+ if not isinstance(printable_hash, unicode):
+ raise RuntimeError("printable_hash must be a unicode string.")
+ try:
+ fname = self._cache[printable_hash]
+ return self._get_icon_data(fname)
+ except KeyError:
+ pass
+ return None
- def add_icon(self, icon_data):
- if len(icon_data) == 0:
- return
+ def add_icon(self, icon_data):
+ if len(icon_data) == 0:
+ return
- m = md5.new()
- m.update(icon_data)
- printable_hash = util.printable_hash(m.digest())
- if self._cache.has_key(printable_hash):
- del m
- return
+ m = md5.new()
+ m.update(icon_data)
+ printable_hash = util.printable_hash(m.digest())
+ if self._cache.has_key(printable_hash):
+ del m
+ return
- # Write the icon to disk and add an entry to our cache for it
- m.update(time.asctime())
- fname = util.printable_hash(m.digest())
- fd = open(os.path.join(self._cachepath, fname), "w")
- fd.write(icon_data)
- fd.close()
- self._cache[printable_hash] = fname
- del m
+ # Write the icon to disk and add an entry to our cache for it
+ m.update(time.asctime())
+ fname = util.printable_hash(m.digest())
+ fd = open(os.path.join(self._cachepath, fname), "w")
+ fd.write(icon_data)
+ fd.close()
+ self._cache[printable_hash] = fname
+ del m
diff --git a/services/presence/PresenceService.py b/services/presence/PresenceService.py
index 6399a7b..5f8c7a4 100644
--- a/services/presence/PresenceService.py
+++ b/services/presence/PresenceService.py
@@ -30,103 +30,103 @@ _SA_UNRESOLVED = 0
_SA_RESOLVE_PENDING = 1
_SA_RESOLVED = 2
class ServiceAdv(object):
- """Wrapper class to track services from Avahi."""
- def __init__(self, interface, protocol, name, stype, domain, local):
- self._interface = interface
- self._protocol = protocol
- if not isinstance(name, unicode):
- raise ValueError("service advertisement name must be unicode.")
- self._name = name
- if not isinstance(stype, unicode):
- raise ValueError("service advertisement type must be unicode.")
- self._stype = stype
- if not isinstance(domain, unicode):
- raise ValueError("service advertisement domain must be unicode.")
- self._domain = domain
- self._service = None
- if not isinstance(local, bool):
- raise ValueError("local must be a bool.")
- self._local = local
- self._state = _SA_UNRESOLVED
- self._resolver = None
- self._resolv_tries = 0
-
- def __del__(self):
- if self._resolver:
- del self._resolver
-
- def interface(self):
- return self._interface
- def protocol(self):
- return self._protocol
- def name(self):
- return self._name
- def stype(self):
- return self._stype
- def domain(self):
- return self._domain
- def is_local(self):
- return self._local
- def resolv_tries(self):
- return self._resolv_tries
- def inc_resolv_tries(self):
- self._resolv_tries += 1
- def service(self):
- return self._service
- def set_service(self, service):
- if not isinstance(service, Service.Service):
- raise ValueError("must be a valid service.")
- if service != self._service:
- self._service = service
- def resolver(self):
- return self._resolver
- def set_resolver(self, resolver):
- if resolver and not isinstance(resolver, dbus.Interface):
- raise ValueError("'resolver' must be a valid dbus object")
- if not resolver and self._resolver:
- del self._resolver
- self._resolver = resolver
- def state(self):
- return self._state
- def set_state(self, state):
- if state == _SA_RESOLVE_PENDING:
- if self._state == _SA_RESOLVED:
- raise ValueError("Can't reset to resolve pending from resolved.")
- if state == _SA_UNRESOLVED:
- self._resolv_tries = 0
- self._state = state
+ """Wrapper class to track services from Avahi."""
+ def __init__(self, interface, protocol, name, stype, domain, local):
+ self._interface = interface
+ self._protocol = protocol
+ if not isinstance(name, unicode):
+ raise ValueError("service advertisement name must be unicode.")
+ self._name = name
+ if not isinstance(stype, unicode):
+ raise ValueError("service advertisement type must be unicode.")
+ self._stype = stype
+ if not isinstance(domain, unicode):
+ raise ValueError("service advertisement domain must be unicode.")
+ self._domain = domain
+ self._service = None
+ if not isinstance(local, bool):
+ raise ValueError("local must be a bool.")
+ self._local = local
+ self._state = _SA_UNRESOLVED
+ self._resolver = None
+ self._resolv_tries = 0
+
+ def __del__(self):
+ if self._resolver:
+ del self._resolver
+
+ def interface(self):
+ return self._interface
+ def protocol(self):
+ return self._protocol
+ def name(self):
+ return self._name
+ def stype(self):
+ return self._stype
+ def domain(self):
+ return self._domain
+ def is_local(self):
+ return self._local
+ def resolv_tries(self):
+ return self._resolv_tries
+ def inc_resolv_tries(self):
+ self._resolv_tries += 1
+ def service(self):
+ return self._service
+ def set_service(self, service):
+ if not isinstance(service, Service.Service):
+ raise ValueError("must be a valid service.")
+ if service != self._service:
+ self._service = service
+ def resolver(self):
+ return self._resolver
+ def set_resolver(self, resolver):
+ if resolver and not isinstance(resolver, dbus.Interface):
+ raise ValueError("'resolver' must be a valid dbus object")
+ if not resolver and self._resolver:
+ del self._resolver
+ self._resolver = resolver
+ def state(self):
+ return self._state
+ def set_state(self, state):
+ if state == _SA_RESOLVE_PENDING:
+ if self._state == _SA_RESOLVED:
+ raise ValueError("Can't reset to resolve pending from resolved.")
+ if state == _SA_UNRESOLVED:
+ self._resolv_tries = 0
+ self._state = state
class RegisteredServiceType(object):
- def __init__(self, stype):
- self._stype = stype
- self._refcount = 1
+ def __init__(self, stype):
+ self._stype = stype
+ self._refcount = 1
- def get_type(self):
- return self._stype
+ def get_type(self):
+ return self._stype
- def ref(self):
- self._refcount += 1
+ def ref(self):
+ self._refcount += 1
- def unref(self):
- self._refcount -= 1
- return self._refcount
+ def unref(self):
+ self._refcount -= 1
+ return self._refcount
def _txt_to_dict(txt):
- """Convert an avahi-returned TXT record formatted
- as nested arrays of integers (from dbus) into a dict
- of key/value string pairs."""
- prop_dict = {}
- props = avahi.txt_array_to_string_array(txt)
- for item in props:
- key = value = None
- if '=' not in item:
- # No = means a boolean value of true
- key = item
- value = True
- else:
- (key, value) = item.split('=', 1)
- prop_dict[key] = value
- return prop_dict
+ """Convert an avahi-returned TXT record formatted
+ as nested arrays of integers (from dbus) into a dict
+ of key/value string pairs."""
+ prop_dict = {}
+ props = avahi.txt_array_to_string_array(txt)
+ for item in props:
+ key = value = None
+ if '=' not in item:
+ # No = means a boolean value of true
+ key = item
+ value = True
+ else:
+ (key, value) = item.split('=', 1)
+ prop_dict[key] = value
+ return prop_dict
_PRESENCE_SERVICE = "org.laptop.Presence"
@@ -134,731 +134,731 @@ _PRESENCE_DBUS_INTERFACE = "org.laptop.Presence"
_PRESENCE_OBJECT_PATH = "/org/laptop/Presence"
class NotFoundError(Exception):
- pass
+ pass
class PresenceServiceDBusHelper(dbus.service.Object):
- def __init__(self, parent, bus_name):
- self._parent = parent
- self._bus_name = bus_name
- dbus.service.Object.__init__(self, bus_name, _PRESENCE_OBJECT_PATH)
-
- @dbus.service.signal(_PRESENCE_DBUS_INTERFACE,
- signature="o")
- def BuddyAppeared(self, object_path):
- pass
-
- @dbus.service.signal(_PRESENCE_DBUS_INTERFACE,
- signature="o")
- def BuddyDisappeared(self, object_path):
- pass
-
- @dbus.service.signal(_PRESENCE_DBUS_INTERFACE,
- signature="o")
- def ServiceAppeared(self, object_path):
- pass
-
- @dbus.service.signal(_PRESENCE_DBUS_INTERFACE,
- signature="o")
- def ServiceDisappeared(self, object_path):
- pass
-
- @dbus.service.signal(_PRESENCE_DBUS_INTERFACE,
- signature="o")
- def ActivityAppeared(self, object_path):
- pass
-
- @dbus.service.signal(_PRESENCE_DBUS_INTERFACE,
- signature="o")
- def ActivityDisappeared(self, object_path):
- pass
-
- @dbus.service.method(_PRESENCE_DBUS_INTERFACE,
- in_signature="", out_signature="ao")
- def getServices(self):
- ret = []
- for serv in self._parent.get_services():
- ret.append(serv.object_path())
- return ret
-
- @dbus.service.method(_PRESENCE_DBUS_INTERFACE,
- in_signature="s", out_signature="ao")
- def getServicesOfType(self, stype):
- ret = []
- for serv in self._parent.get_services_of_type(stype):
- ret.append(serv.object_path())
- return ret
-
- @dbus.service.method(_PRESENCE_DBUS_INTERFACE,
- in_signature="", out_signature="ao")
- def getActivities(self):
- ret = []
- for act in self._parent.get_activities():
- ret.append(act.object_path())
- return ret
-
- @dbus.service.method(_PRESENCE_DBUS_INTERFACE,
- in_signature="s", out_signature="o")
- def getActivity(self, actid):
- act = self._parent.get_activity(actid)
- if not act:
- raise NotFoundError("Not found")
- return act.object_path()
-
- @dbus.service.method(_PRESENCE_DBUS_INTERFACE,
- in_signature="", out_signature="ao")
- def getBuddies(self):
- ret = []
- for buddy in self._parent.get_buddies():
- ret.append(buddy.object_path())
- return ret
-
- @dbus.service.method(_PRESENCE_DBUS_INTERFACE,
- in_signature="s", out_signature="o")
- def getBuddyByName(self, name):
- buddy = self._parent.get_buddy_by_name(name)
- if not buddy:
- raise NotFoundError("Not found")
- return buddy.object_path()
-
- @dbus.service.method(_PRESENCE_DBUS_INTERFACE,
- in_signature="s", out_signature="o")
- def getBuddyByAddress(self, addr):
- buddy = self._parent.get_buddy_by_address(addr)
- if not buddy:
- raise NotFoundError("Not found")
- return buddy.object_path()
-
- @dbus.service.method(_PRESENCE_DBUS_INTERFACE,
- in_signature="", out_signature="o")
- def getOwner(self):
- owner = self._parent.get_owner()
- if not owner:
- raise NotFoundError("Not found")
- return owner.object_path()
-
- @dbus.service.method(_PRESENCE_DBUS_INTERFACE,
- in_signature="os", out_signature="o",
- sender_keyword="sender")
- def joinActivity(self, activity_op, stype, sender):
- found_activity = None
- acts = self._parent.get_activities()
- for act in acts:
- if act.object_path() == activity_op:
- found_activity = act
- break
- if not found_activity:
- raise NotFoundError("The activity %s was not found." % activity_op)
- return self._parent.join_activity(found_activity, stype, sender)
-
- @dbus.service.method(_PRESENCE_DBUS_INTERFACE,
- in_signature="ssa{ss}sis", out_signature="o",
- sender_keyword="sender")
- def shareActivity(self, activity_id, stype, properties, address, port,
- domain, sender=None):
- if not len(address):
- address = None
- service = self._parent.share_activity(activity_id, stype, properties, address,
- port, domain, sender)
- return service.object_path()
-
- @dbus.service.method(_PRESENCE_DBUS_INTERFACE,
- in_signature="ssa{ss}sis", out_signature="o",
- sender_keyword="sender")
- def registerService(self, name, stype, properties, address, port, domain,
- sender=None):
- if not len(address):
- address = None
- service = self._parent.register_service(name, stype, properties, address,
- port, domain, sender)
- return service.object_path()
-
- @dbus.service.method(_PRESENCE_DBUS_INTERFACE,
- in_signature="o", out_signature="",
- sender_keyword="sender")
- def unregisterService(self, service_op, sender):
- found_serv = None
- services = self._parent.get_services()
- for serv in services:
- if serv.object_path() == service_op:
- found_serv = serv
- break
- if not found_serv:
- raise NotFoundError("The service %s was not found." % service_op)
- return self._parent.unregister_service(found_serv, sender)
-
- @dbus.service.method(_PRESENCE_DBUS_INTERFACE,
- in_signature="s", out_signature="")
- def registerServiceType(self, stype):
- self._parent.register_service_type(stype)
-
- @dbus.service.method(_PRESENCE_DBUS_INTERFACE,
- in_signature="s", out_signature="")
- def unregisterServiceType(self, stype):
- self._parent.unregister_service_type(stype)
-
- @dbus.service.method(_PRESENCE_DBUS_INTERFACE)
- def start(self):
- self._parent.start()
+ def __init__(self, parent, bus_name):
+ self._parent = parent
+ self._bus_name = bus_name
+ dbus.service.Object.__init__(self, bus_name, _PRESENCE_OBJECT_PATH)
+
+ @dbus.service.signal(_PRESENCE_DBUS_INTERFACE,
+ signature="o")
+ def BuddyAppeared(self, object_path):
+ pass
+
+ @dbus.service.signal(_PRESENCE_DBUS_INTERFACE,
+ signature="o")
+ def BuddyDisappeared(self, object_path):
+ pass
+
+ @dbus.service.signal(_PRESENCE_DBUS_INTERFACE,
+ signature="o")
+ def ServiceAppeared(self, object_path):
+ pass
+
+ @dbus.service.signal(_PRESENCE_DBUS_INTERFACE,
+ signature="o")
+ def ServiceDisappeared(self, object_path):
+ pass
+
+ @dbus.service.signal(_PRESENCE_DBUS_INTERFACE,
+ signature="o")
+ def ActivityAppeared(self, object_path):
+ pass
+
+ @dbus.service.signal(_PRESENCE_DBUS_INTERFACE,
+ signature="o")
+ def ActivityDisappeared(self, object_path):
+ pass
+
+ @dbus.service.method(_PRESENCE_DBUS_INTERFACE,
+ in_signature="", out_signature="ao")
+ def getServices(self):
+ ret = []
+ for serv in self._parent.get_services():
+ ret.append(serv.object_path())
+ return ret
+
+ @dbus.service.method(_PRESENCE_DBUS_INTERFACE,
+ in_signature="s", out_signature="ao")
+ def getServicesOfType(self, stype):
+ ret = []
+ for serv in self._parent.get_services_of_type(stype):
+ ret.append(serv.object_path())
+ return ret
+
+ @dbus.service.method(_PRESENCE_DBUS_INTERFACE,
+ in_signature="", out_signature="ao")
+ def getActivities(self):
+ ret = []
+ for act in self._parent.get_activities():
+ ret.append(act.object_path())
+ return ret
+
+ @dbus.service.method(_PRESENCE_DBUS_INTERFACE,
+ in_signature="s", out_signature="o")
+ def getActivity(self, actid):
+ act = self._parent.get_activity(actid)
+ if not act:
+ raise NotFoundError("Not found")
+ return act.object_path()
+
+ @dbus.service.method(_PRESENCE_DBUS_INTERFACE,
+ in_signature="", out_signature="ao")
+ def getBuddies(self):
+ ret = []
+ for buddy in self._parent.get_buddies():
+ ret.append(buddy.object_path())
+ return ret
+
+ @dbus.service.method(_PRESENCE_DBUS_INTERFACE,
+ in_signature="s", out_signature="o")
+ def getBuddyByName(self, name):
+ buddy = self._parent.get_buddy_by_name(name)
+ if not buddy:
+ raise NotFoundError("Not found")
+ return buddy.object_path()
+
+ @dbus.service.method(_PRESENCE_DBUS_INTERFACE,
+ in_signature="s", out_signature="o")
+ def getBuddyByAddress(self, addr):
+ buddy = self._parent.get_buddy_by_address(addr)
+ if not buddy:
+ raise NotFoundError("Not found")
+ return buddy.object_path()
+
+ @dbus.service.method(_PRESENCE_DBUS_INTERFACE,
+ in_signature="", out_signature="o")
+ def getOwner(self):
+ owner = self._parent.get_owner()
+ if not owner:
+ raise NotFoundError("Not found")
+ return owner.object_path()
+
+ @dbus.service.method(_PRESENCE_DBUS_INTERFACE,
+ in_signature="os", out_signature="o",
+ sender_keyword="sender")
+ def joinActivity(self, activity_op, stype, sender):
+ found_activity = None
+ acts = self._parent.get_activities()
+ for act in acts:
+ if act.object_path() == activity_op:
+ found_activity = act
+ break
+ if not found_activity:
+ raise NotFoundError("The activity %s was not found." % activity_op)
+ return self._parent.join_activity(found_activity, stype, sender)
+
+ @dbus.service.method(_PRESENCE_DBUS_INTERFACE,
+ in_signature="ssa{ss}sis", out_signature="o",
+ sender_keyword="sender")
+ def shareActivity(self, activity_id, stype, properties, address, port,
+ domain, sender=None):
+ if not len(address):
+ address = None
+ service = self._parent.share_activity(activity_id, stype, properties, address,
+ port, domain, sender)
+ return service.object_path()
+
+ @dbus.service.method(_PRESENCE_DBUS_INTERFACE,
+ in_signature="ssa{ss}sis", out_signature="o",
+ sender_keyword="sender")
+ def registerService(self, name, stype, properties, address, port, domain,
+ sender=None):
+ if not len(address):
+ address = None
+ service = self._parent.register_service(name, stype, properties, address,
+ port, domain, sender)
+ return service.object_path()
+
+ @dbus.service.method(_PRESENCE_DBUS_INTERFACE,
+ in_signature="o", out_signature="",
+ sender_keyword="sender")
+ def unregisterService(self, service_op, sender):
+ found_serv = None
+ services = self._parent.get_services()
+ for serv in services:
+ if serv.object_path() == service_op:
+ found_serv = serv
+ break
+ if not found_serv:
+ raise NotFoundError("The service %s was not found." % service_op)
+ return self._parent.unregister_service(found_serv, sender)
+
+ @dbus.service.method(_PRESENCE_DBUS_INTERFACE,
+ in_signature="s", out_signature="")
+ def registerServiceType(self, stype):
+ self._parent.register_service_type(stype)
+
+ @dbus.service.method(_PRESENCE_DBUS_INTERFACE,
+ in_signature="s", out_signature="")
+ def unregisterServiceType(self, stype):
+ self._parent.unregister_service_type(stype)
+
+ @dbus.service.method(_PRESENCE_DBUS_INTERFACE)
+ def start(self):
+ self._parent.start()
class PresenceService(object):
- def __init__(self):
- # interface -> IP address: interfaces we've gotten events on so far
- self._started = False
- self._local_addrs = {}
-
- self._next_object_id = 0
-
- self._buddies = {} # nick -> Buddy
- self._services = {} # (name, type) -> Service
- self._activities = {} # activity id -> Activity
-
- # Keep track of stuff we're already browsing
- self._service_type_browsers = {}
- self._service_browsers = {}
-
- # Resolved service list
- self._service_advs = []
-
- # Service types we care about resolving
- self._registered_service_types = []
-
- # Set up the dbus service we provide
- self._session_bus = dbus.SessionBus()
- self._bus_name = dbus.service.BusName(_PRESENCE_SERVICE, bus=self._session_bus)
- self._dbus_helper = PresenceServiceDBusHelper(self, self._bus_name)
-
- self._icon_cache = BuddyIconCache.BuddyIconCache()
-
- # Our owner object
- if profile.get_nick_name():
- objid = self._get_next_object_id()
- self._owner = Buddy.Owner(self, self._bus_name,
- objid, self._icon_cache)
- self._buddies[self._owner.get_name()] = self._owner
- else:
- self._owner = None
-
- def start(self):
- if self._started:
- return
- self._started = True
-
- # Connect to Avahi for mDNS stuff
- self._system_bus = dbus.SystemBus()
- self._mdns_service = dbus.Interface(self._system_bus.get_object(avahi.DBUS_NAME,
- avahi.DBUS_PATH_SERVER), avahi.DBUS_INTERFACE_SERVER)
-
- # Always browse .local
- self._new_domain_cb(avahi.IF_UNSPEC, avahi.PROTO_INET, "local")
-
- # Connect to Avahi and start looking for stuff
- domain_browser = self._mdns_service.DomainBrowserNew(avahi.IF_UNSPEC, avahi.PROTO_INET,
- "", avahi.DOMAIN_BROWSER_BROWSE, dbus.UInt32(0))
- db = dbus.Interface(self._system_bus.get_object(avahi.DBUS_NAME, domain_browser), avahi.DBUS_INTERFACE_DOMAIN_BROWSER)
- db.connect_to_signal('ItemNew', self._new_domain_cb_glue)
-
- def _get_next_object_id(self):
- """Increment and return the object ID counter."""
- self._next_object_id = self._next_object_id + 1
- return self._next_object_id
-
- def get_services(self):
- return self._services.values()
-
- def get_services_of_type(self, stype):
- ret = []
- for serv in self._services.values():
- if serv.get_type() == stype:
- ret.append(serv)
- return ret
-
- def get_activities(self):
- # Only return valid activities
- ret = []
- for act in self._activities.values():
- if act.is_valid():
- ret.append(act)
- return ret
-
- def get_activity(self, actid):
- if self._activities.has_key(actid):
- act = self._activities[actid]
- if act.is_valid():
- return act
- return None
-
- def get_buddies(self):
- buddies = []
- for buddy in self._buddies.values():
- if buddy.is_valid():
- buddies.append(buddy)
- return buddies
-
- def get_buddy_by_name(self, name):
- if self._buddies.has_key(name):
- if self._buddies[name].is_valid():
- return self._buddies[name]
- return None
-
- def get_buddy_by_address(self, address):
- for buddy in self._buddies.values():
- if buddy.get_address() == address and buddy.is_valid():
- return buddy
- return None
-
- def get_owner(self):
- return self._owner
-
- def _find_service_adv(self, interface=None, protocol=None, name=None,
- stype=None, domain=None, local=None):
- """Search a list of service advertisements for ones matching
- certain criteria."""
- adv_list = []
- for adv in self._service_advs:
- if interface and adv.interface() != interface:
- continue
- if protocol and adv.protocol() != protocol:
- continue
- if name and adv.name() != name:
- continue
- if stype and adv.stype() != stype:
- continue
- if domain and adv.domain() != domain:
- continue
- if local is not None and adv.is_local() != local:
- continue
- adv_list.append(adv)
- return adv_list
-
- def _find_registered_service_type(self, stype):
- for item in self._registered_service_types:
- if item.get_type() == stype:
- return item
- return None
-
- def _handle_new_service_for_buddy(self, service, local):
- """Deal with a new discovered service object."""
- # Once a service is resolved, we match it up to an existing buddy,
- # or create a new Buddy if this is the first service known about the buddy
- buddy_was_valid = False
- name = service.get_name()
- buddy = None
- try:
- buddy = self._buddies[name]
- buddy_was_valid = buddy.is_valid()
- service_added = buddy.add_service(service)
- if service_added:
- self._dbus_helper.ServiceAppeared(service.object_path())
- except KeyError:
- source_addr = service.get_source_address()
- objid = self._get_next_object_id()
- buddy = Buddy.Buddy(self._bus_name, objid, service, self._icon_cache)
- self._buddies[name] = buddy
- self._dbus_helper.ServiceAppeared(service.object_path())
- if not buddy_was_valid and buddy.is_valid():
- self._dbus_helper.BuddyAppeared(buddy.object_path())
- return buddy
-
- def _handle_new_activity_service(self, service):
- # If the serivce is an activity service, merge it into our activities list
- actid = service.get_activity_id()
- if not actid:
- return
- activity = None
- was_valid = False
- if not self._activities.has_key(actid):
- objid = self._get_next_object_id()
- activity = Activity.Activity(self._bus_name, objid, service)
- self._activities[actid] = activity
- else:
- activity = self._activities[actid]
- was_valid = activity.is_valid()
-
- if activity:
- activity.add_service(service)
-
- # Add the activity to its buddy
- # FIXME: use something other than name to attribute to buddy
- try:
- buddy = self._buddies[service.get_name()]
- buddy.add_activity(activity)
- except KeyError:
- pass
-
- if not was_valid and activity.is_valid():
- self._dbus_helper.ActivityAppeared(activity.object_path())
-
- def _handle_remove_activity_service(self, service):
- actid = service.get_activity_id()
- if not actid:
- return
- if not self._activities.has_key(actid):
- return
-
- activity = self._activities[actid]
-
- activity.remove_service(service)
- if len(activity.get_services()) == 0:
- # Remove the activity from its buddy
- # FIXME: use something other than name to attribute to buddy
- try:
- buddy = self._buddies[service.get_name()]
- buddy.remove_activity(activity)
- except KeyError:
- pass
-
- # Kill the activity
- self._dbus_helper.ActivityDisappeared(activity.object_path())
- del self._activities[actid]
-
- def _service_resolved_cb(self, adv, interface, protocol, full_name,
- stype, domain, host, aprotocol, address, port, txt, flags,
- updated):
- """When the service discovery finally gets here, we've got enough
- information about the service to assign it to a buddy."""
- if updated == False:
- logging.debug("Resolved service '%s' type '%s' domain '%s' to " \
- " %s:%s" % (full_name, stype, domain, address, port))
-
- if not adv in self._service_advs:
- return False
- if adv.state() != _SA_RESOLVED:
- return False
-
- # See if we know about this service already
- service = None
- key = (full_name, stype)
- props = _txt_to_dict(txt)
- if not self._services.has_key(key):
- objid = self._get_next_object_id()
- service = Service.Service(self._bus_name, objid, name=full_name,
- stype=stype, domain=domain, address=address, port=port,
- properties=props, source_address=address)
- self._services[key] = service
- else:
- # Already tracking this service; either:
- # a) we were the one that shared it in the first place,
- # and therefore the source address would not have
- # been set yet
- # b) the service has been updated
- service = self._services[key]
- if not service.get_source_address():
- service.set_source_address(address)
- if not service.get_address():
- service.set_address(address)
-
- adv.set_service(service)
-
- if service and updated:
- service.set_properties(props, from_network=True)
- return False
-
- # Merge the service into our buddy and activity lists, if needed
- buddy = self._handle_new_service_for_buddy(service, adv.is_local())
- if buddy and service.get_activity_id():
- self._handle_new_activity_service(service)
-
- return False
-
- def _service_resolved_cb_glue(self, adv, interface, protocol, name,
- stype, domain, host, aprotocol, address, port, txt, flags):
- # Avahi doesn't flag updates to existing services, so we have
- # to determine that here
- updated = False
- if adv.state() == _SA_RESOLVED:
- updated = True
-
- adv.set_state(_SA_RESOLVED)
- gobject.idle_add(self._service_resolved_cb, adv, interface,
- protocol, name, stype, domain, host, aprotocol, address,
- port, txt, flags, updated)
-
- def _service_resolved_failure_cb(self, adv, err):
- retried = False
- adv.set_resolver(None)
- if adv.stype() == Buddy.PRESENCE_SERVICE_TYPE:
- # Retry the presence service type a few times
- if adv.resolv_tries() < 4:
- adv.set_state(_SA_RESOLVE_PENDING)
- gobject.timeout_add(250, self._resolve_service, adv)
- retried = True
- logging.error("Retrying resolution of service %s.%s: %s" % (adv.name(),
- adv.stype(), err))
-
- if not retried:
- logging.error("Error resolving service %s.%s: %s" % (adv.name(),
- adv.stype(), err))
- adv.set_state(_SA_UNRESOLVED)
-
- def _resolve_service(self, adv):
- """Resolve and lookup a ZeroConf service to obtain its address and TXT records."""
- # Ask avahi to resolve this particular service
- path = self._mdns_service.ServiceResolverNew(dbus.Int32(adv.interface()),
- dbus.Int32(adv.protocol()), adv.name(), adv.stype(), adv.domain(),
- avahi.PROTO_INET, dbus.UInt32(0))
- resolver = dbus.Interface(self._system_bus.get_object(avahi.DBUS_NAME, path),
- avahi.DBUS_INTERFACE_SERVICE_RESOLVER)
- resolver.connect_to_signal('Found', lambda *args: self._service_resolved_cb_glue(adv, *args))
- resolver.connect_to_signal('Failure', lambda *args: self._service_resolved_failure_cb(adv, *args))
- adv.inc_resolv_tries()
- adv.set_resolver(resolver)
- return False
-
- def _service_appeared_cb(self, interface, protocol, full_name, stype, domain, flags):
- local = flags & avahi.LOOKUP_RESULT_OUR_OWN > 0
- adv_list = self._find_service_adv(interface=interface, protocol=protocol,
- name=full_name, stype=stype, domain=domain, local=local)
- adv = None
- if not adv_list:
- adv = ServiceAdv(interface=interface, protocol=protocol, name=full_name,
- stype=stype, domain=domain, local=local)
- self._service_advs.append(adv)
- else:
- adv = adv_list[0]
-
- # Decompose service name if we can
- (actid, buddy_name) = Service.decompose_service_name(full_name)
-
- # If we care about the service right now, resolve it
- resolve = False
- item = self._find_registered_service_type(stype)
- if actid is not None or item is not None:
- resolve = True
- if resolve and adv.state() == _SA_UNRESOLVED:
- logging.debug("Found '%s' (%d) of type '%s' in domain" \
- " '%s' on %i.%i; will resolve." % (full_name, flags, stype,
- domain, interface, protocol))
- adv.set_state(_SA_RESOLVE_PENDING)
- gobject.idle_add(self._resolve_service, adv)
-
- return False
-
- def _service_appeared_cb_glue(self, interface, protocol, name, stype, domain, flags):
- gobject.idle_add(self._service_appeared_cb, interface, protocol, name, stype, domain, flags)
-
- def _service_disappeared_cb(self, interface, protocol, full_name, stype, domain, flags):
- local = flags & avahi.LOOKUP_RESULT_OUR_OWN > 0
- # If it's an unresolved service, remove it from our unresolved list
- adv_list = self._find_service_adv(interface=interface, protocol=protocol,
- name=full_name, stype=stype, domain=domain, local=local)
- if not adv_list:
- return False
-
- # Get the service object; if none, we have nothing left to do
- adv = adv_list[0]
- service = adv.service()
- self._service_advs.remove(adv)
- del adv
- if not service:
- return False
-
- logging.debug("Service %s.%s in domain %s on %i.%i disappeared." % (full_name,
- stype, domain, interface, protocol))
-
- self._dbus_helper.ServiceDisappeared(service.object_path())
- self._handle_remove_activity_service(service)
-
- # Decompose service name if we can
- (actid, buddy_name) = Service.decompose_service_name(full_name)
-
- # Remove the service from the buddy
- try:
- buddy = self._buddies[buddy_name]
- except KeyError:
- pass
- else:
- buddy.remove_service(service)
- if not buddy.is_valid():
- self._dbus_helper.BuddyDisappeared(buddy.object_path())
- del self._buddies[buddy_name]
- key = (service.get_full_name(), service.get_type())
- del self._services[key]
- return False
-
- def _service_disappeared_cb_glue(self, interface, protocol, name, stype, domain, flags):
- gobject.idle_add(self._service_disappeared_cb, interface, protocol, name, stype, domain, flags)
-
- def _new_service_type_cb(self, interface, protocol, stype, domain, flags):
- # Are we already browsing this domain for this type?
- if self._service_browsers.has_key((interface, protocol, stype, domain)):
- return
-
- # Start browsing for all services of this type in this domain
- try:
- s_browser = self._mdns_service.ServiceBrowserNew(interface,
- protocol, stype, domain, dbus.UInt32(0))
- browser_obj = dbus.Interface(self._system_bus.get_object(avahi.DBUS_NAME, s_browser),
- avahi.DBUS_INTERFACE_SERVICE_BROWSER)
- browser_obj.connect_to_signal('ItemNew', self._service_appeared_cb_glue)
- browser_obj.connect_to_signal('ItemRemove', self._service_disappeared_cb_glue)
-
- self._service_browsers[(interface, protocol, stype, domain)] = browser_obj
- except dbus.DBusException:
- logging.debug("Error browsing service type '%s'" % stype)
- return False
-
- def _new_service_type_cb_glue(self, interface, protocol, stype, domain, flags):
- if len(stype) > 0:
- gobject.idle_add(self._new_service_type_cb, interface, protocol,
- stype, domain, flags)
-
- def _new_domain_cb(self, interface, protocol, domain, flags=0):
- """Callback from Avahi when a new domain has been found. Start
- browsing the new domain."""
- # Only use .local for now...
- if domain != "local":
- return
-
- # Are we already browsing this domain?
- if self._service_type_browsers.has_key((interface, protocol, domain)):
- return
-
- # Start browsing this domain for the services its members offer
- try:
- st_browser = self._mdns_service.ServiceTypeBrowserNew(interface, protocol, domain, dbus.UInt32(0))
- browser_obj = dbus.Interface(self._system_bus.get_object(avahi.DBUS_NAME, st_browser),
- avahi.DBUS_INTERFACE_SERVICE_TYPE_BROWSER)
- except dbus.DBusException, exc:
- str_exc = str(exc)
- logging.error("got exception %s while attempting to browse domain %s on %i.%i" % (str_exc, domain, interface, protocol))
- if str_exc.find("The name org.freedesktop.Avahi was not provided by any .service files") >= 0:
- raise Exception("Avahi does not appear to be running. '%s'" % str_exc)
- else:
- raise exc
- logging.debug("Browsing domain '%s' on %i.%i ..." % (domain, interface, protocol))
- browser_obj.connect_to_signal('ItemNew', self._new_service_type_cb_glue)
- self._service_type_browsers[(interface, protocol, domain)] = browser_obj
- return False
-
- def _new_domain_cb_glue(self, interface, protocol, domain, flags=0):
- gobject.idle_add(self._new_domain_cb, interface, protocol, domain, flags)
-
- def join_activity(self, activity, stype, sender):
- services = activity.get_services_of_type(stype)
- if not len(services):
- raise NotFoundError("The service type %s was not present within " \
- "the activity %s" % (stype, activity.object_path()))
- act_service = services[0]
- props = act_service.get_properties()
- color = activity.get_color()
- if color:
- props['color'] = color
- return self._share_activity(activity.get_id(), stype, properties,
- act_service.get_address(), act_service.get_port(),
- act_service.get_domain(), sender)
-
- def share_activity(self, activity_id, stype, properties=None, address=None,
- port=-1, domain=u"local", sender=None):
- """Convenience function to share an activity with other buddies."""
- if not util.validate_activity_id(activity_id):
- raise ValueError("invalid activity id")
- owner_nick = self._owner.get_name()
- real_name = Service.compose_service_name(owner_nick, activity_id)
- if address and not isinstance(address, unicode):
- raise ValueError("address must be a unicode string.")
- if address == None and stype.endswith('_udp'):
- # Use random currently unassigned multicast address
- address = u"232.%d.%d.%d" % (random.randint(0, 254), random.randint(1, 254),
- random.randint(1, 254))
- properties['address'] = address
- properties['port'] = port
- if port and port != -1 and (not isinstance(port, int) or port <= 1024 or port >= 65535):
- raise ValueError("port must be a number between 1024 and 65535")
-
- color = self._owner.get_color()
- if color:
- properties['color'] = color
-
- logging.debug('Share activity %s, type %s, address %s, port %d, " \
- "properties %s' % (activity_id, stype, address, port,
- properties))
- return self.register_service(real_name, stype, properties, address,
- port, domain, sender)
-
- def register_service(self, name, stype, properties={}, address=None,
- port=-1, domain=u"local", sender=None):
- """Register a new service, advertising it to other Buddies on the network."""
- # Refuse to register if we can't get the dbus connection this request
- # came from for some reason
- if not sender:
- raise RuntimeError("Service registration request must have a sender.")
-
- (actid, person_name) = Service.decompose_service_name(name)
- if self.get_owner() and person_name != self.get_owner().get_name():
- raise RuntimeError("Tried to register a service that didn't have" \
- " Owner nick as the service name!")
- if not domain or not len(domain):
- domain = u"local"
- if not port or port == -1:
- port = random.randint(4000, 65000)
-
- objid = self._get_next_object_id()
- service = Service.Service(self._bus_name, objid, name=name,
- stype=stype, domain=domain, address=address, port=port,
- properties=properties, source_address=None,
- local_publisher=sender)
- self._services[(name, stype)] = service
- self.register_service_type(stype)
- service.register(self._system_bus, self._mdns_service)
- return service
-
- def unregister_service(self, service, sender=None):
- service.unregister(sender)
-
- def register_service_type(self, stype):
- """Requests that the Presence service look for and recognize
- a certain mDNS service types."""
- if not isinstance(stype, unicode):
- raise ValueError("service type must be a unicode string.")
-
- # If we've already registered it as a service type, ref it and return
- item = self._find_registered_service_type(stype)
- if item is not None:
- item.ref()
- return
-
- # Otherwise track this type now
- obj = RegisteredServiceType(stype)
- self._registered_service_types.append(obj)
-
- # Find unresolved services that match the service type
- # we're now interested in, and resolve them
- resolv_list = []
-
- # Find services of this type
- resolv_list = self._find_service_adv(stype=stype)
- # Request resolution for them if they aren't in-process already
- for adv in resolv_list:
- if adv.state() == _SA_UNRESOLVED:
- adv.set_state(_SA_RESOLVE_PENDING)
- gobject.idle_add(self._resolve_service, adv)
-
- def unregister_service_type(self, stype):
- """Stop tracking a certain mDNS service."""
- if not isinstance(stype, unicode):
- raise ValueError("service type must be a unicode string.")
-
- # if it was found, unref it and possibly remove it
- item = self._find_registered_service_type(stype)
- if not item:
- return
- if item.unref() <= 0:
- self._registered_service_types.remove(item)
- del item
+ def __init__(self):
+ # interface -> IP address: interfaces we've gotten events on so far
+ self._started = False
+ self._local_addrs = {}
+
+ self._next_object_id = 0
+
+ self._buddies = {} # nick -> Buddy
+ self._services = {} # (name, type) -> Service
+ self._activities = {} # activity id -> Activity
+
+ # Keep track of stuff we're already browsing
+ self._service_type_browsers = {}
+ self._service_browsers = {}
+
+ # Resolved service list
+ self._service_advs = []
+
+ # Service types we care about resolving
+ self._registered_service_types = []
+
+ # Set up the dbus service we provide
+ self._session_bus = dbus.SessionBus()
+ self._bus_name = dbus.service.BusName(_PRESENCE_SERVICE, bus=self._session_bus)
+ self._dbus_helper = PresenceServiceDBusHelper(self, self._bus_name)
+
+ self._icon_cache = BuddyIconCache.BuddyIconCache()
+
+ # Our owner object
+ if profile.get_nick_name():
+ objid = self._get_next_object_id()
+ self._owner = Buddy.Owner(self, self._bus_name,
+ objid, self._icon_cache)
+ self._buddies[self._owner.get_name()] = self._owner
+ else:
+ self._owner = None
+
+ def start(self):
+ if self._started:
+ return
+ self._started = True
+
+ # Connect to Avahi for mDNS stuff
+ self._system_bus = dbus.SystemBus()
+ self._mdns_service = dbus.Interface(self._system_bus.get_object(avahi.DBUS_NAME,
+ avahi.DBUS_PATH_SERVER), avahi.DBUS_INTERFACE_SERVER)
+
+ # Always browse .local
+ self._new_domain_cb(avahi.IF_UNSPEC, avahi.PROTO_INET, "local")
+
+ # Connect to Avahi and start looking for stuff
+ domain_browser = self._mdns_service.DomainBrowserNew(avahi.IF_UNSPEC, avahi.PROTO_INET,
+ "", avahi.DOMAIN_BROWSER_BROWSE, dbus.UInt32(0))
+ db = dbus.Interface(self._system_bus.get_object(avahi.DBUS_NAME, domain_browser), avahi.DBUS_INTERFACE_DOMAIN_BROWSER)
+ db.connect_to_signal('ItemNew', self._new_domain_cb_glue)
+
+ def _get_next_object_id(self):
+ """Increment and return the object ID counter."""
+ self._next_object_id = self._next_object_id + 1
+ return self._next_object_id
+
+ def get_services(self):
+ return self._services.values()
+
+ def get_services_of_type(self, stype):
+ ret = []
+ for serv in self._services.values():
+ if serv.get_type() == stype:
+ ret.append(serv)
+ return ret
+
+ def get_activities(self):
+ # Only return valid activities
+ ret = []
+ for act in self._activities.values():
+ if act.is_valid():
+ ret.append(act)
+ return ret
+
+ def get_activity(self, actid):
+ if self._activities.has_key(actid):
+ act = self._activities[actid]
+ if act.is_valid():
+ return act
+ return None
+
+ def get_buddies(self):
+ buddies = []
+ for buddy in self._buddies.values():
+ if buddy.is_valid():
+ buddies.append(buddy)
+ return buddies
+
+ def get_buddy_by_name(self, name):
+ if self._buddies.has_key(name):
+ if self._buddies[name].is_valid():
+ return self._buddies[name]
+ return None
+
+ def get_buddy_by_address(self, address):
+ for buddy in self._buddies.values():
+ if buddy.get_address() == address and buddy.is_valid():
+ return buddy
+ return None
+
+ def get_owner(self):
+ return self._owner
+
+ def _find_service_adv(self, interface=None, protocol=None, name=None,
+ stype=None, domain=None, local=None):
+ """Search a list of service advertisements for ones matching
+ certain criteria."""
+ adv_list = []
+ for adv in self._service_advs:
+ if interface and adv.interface() != interface:
+ continue
+ if protocol and adv.protocol() != protocol:
+ continue
+ if name and adv.name() != name:
+ continue
+ if stype and adv.stype() != stype:
+ continue
+ if domain and adv.domain() != domain:
+ continue
+ if local is not None and adv.is_local() != local:
+ continue
+ adv_list.append(adv)
+ return adv_list
+
+ def _find_registered_service_type(self, stype):
+ for item in self._registered_service_types:
+ if item.get_type() == stype:
+ return item
+ return None
+
+ def _handle_new_service_for_buddy(self, service, local):
+ """Deal with a new discovered service object."""
+ # Once a service is resolved, we match it up to an existing buddy,
+ # or create a new Buddy if this is the first service known about the buddy
+ buddy_was_valid = False
+ name = service.get_name()
+ buddy = None
+ try:
+ buddy = self._buddies[name]
+ buddy_was_valid = buddy.is_valid()
+ service_added = buddy.add_service(service)
+ if service_added:
+ self._dbus_helper.ServiceAppeared(service.object_path())
+ except KeyError:
+ source_addr = service.get_source_address()
+ objid = self._get_next_object_id()
+ buddy = Buddy.Buddy(self._bus_name, objid, service, self._icon_cache)
+ self._buddies[name] = buddy
+ self._dbus_helper.ServiceAppeared(service.object_path())
+ if not buddy_was_valid and buddy.is_valid():
+ self._dbus_helper.BuddyAppeared(buddy.object_path())
+ return buddy
+
+ def _handle_new_activity_service(self, service):
+ # If the serivce is an activity service, merge it into our activities list
+ actid = service.get_activity_id()
+ if not actid:
+ return
+ activity = None
+ was_valid = False
+ if not self._activities.has_key(actid):
+ objid = self._get_next_object_id()
+ activity = Activity.Activity(self._bus_name, objid, service)
+ self._activities[actid] = activity
+ else:
+ activity = self._activities[actid]
+ was_valid = activity.is_valid()
+
+ if activity:
+ activity.add_service(service)
+
+ # Add the activity to its buddy
+ # FIXME: use something other than name to attribute to buddy
+ try:
+ buddy = self._buddies[service.get_name()]
+ buddy.add_activity(activity)
+ except KeyError:
+ pass
+
+ if not was_valid and activity.is_valid():
+ self._dbus_helper.ActivityAppeared(activity.object_path())
+
+ def _handle_remove_activity_service(self, service):
+ actid = service.get_activity_id()
+ if not actid:
+ return
+ if not self._activities.has_key(actid):
+ return
+
+ activity = self._activities[actid]
+
+ activity.remove_service(service)
+ if len(activity.get_services()) == 0:
+ # Remove the activity from its buddy
+ # FIXME: use something other than name to attribute to buddy
+ try:
+ buddy = self._buddies[service.get_name()]
+ buddy.remove_activity(activity)
+ except KeyError:
+ pass
+
+ # Kill the activity
+ self._dbus_helper.ActivityDisappeared(activity.object_path())
+ del self._activities[actid]
+
+ def _service_resolved_cb(self, adv, interface, protocol, full_name,
+ stype, domain, host, aprotocol, address, port, txt, flags,
+ updated):
+ """When the service discovery finally gets here, we've got enough
+ information about the service to assign it to a buddy."""
+ if updated == False:
+ logging.debug("Resolved service '%s' type '%s' domain '%s' to " \
+ " %s:%s" % (full_name, stype, domain, address, port))
+
+ if not adv in self._service_advs:
+ return False
+ if adv.state() != _SA_RESOLVED:
+ return False
+
+ # See if we know about this service already
+ service = None
+ key = (full_name, stype)
+ props = _txt_to_dict(txt)
+ if not self._services.has_key(key):
+ objid = self._get_next_object_id()
+ service = Service.Service(self._bus_name, objid, name=full_name,
+ stype=stype, domain=domain, address=address, port=port,
+ properties=props, source_address=address)
+ self._services[key] = service
+ else:
+ # Already tracking this service; either:
+ # a) we were the one that shared it in the first place,
+ # and therefore the source address would not have
+ # been set yet
+ # b) the service has been updated
+ service = self._services[key]
+ if not service.get_source_address():
+ service.set_source_address(address)
+ if not service.get_address():
+ service.set_address(address)
+
+ adv.set_service(service)
+
+ if service and updated:
+ service.set_properties(props, from_network=True)
+ return False
+
+ # Merge the service into our buddy and activity lists, if needed
+ buddy = self._handle_new_service_for_buddy(service, adv.is_local())
+ if buddy and service.get_activity_id():
+ self._handle_new_activity_service(service)
+
+ return False
+
+ def _service_resolved_cb_glue(self, adv, interface, protocol, name,
+ stype, domain, host, aprotocol, address, port, txt, flags):
+ # Avahi doesn't flag updates to existing services, so we have
+ # to determine that here
+ updated = False
+ if adv.state() == _SA_RESOLVED:
+ updated = True
+
+ adv.set_state(_SA_RESOLVED)
+ gobject.idle_add(self._service_resolved_cb, adv, interface,
+ protocol, name, stype, domain, host, aprotocol, address,
+ port, txt, flags, updated)
+
+ def _service_resolved_failure_cb(self, adv, err):
+ retried = False
+ adv.set_resolver(None)
+ if adv.stype() == Buddy.PRESENCE_SERVICE_TYPE:
+ # Retry the presence service type a few times
+ if adv.resolv_tries() < 4:
+ adv.set_state(_SA_RESOLVE_PENDING)
+ gobject.timeout_add(250, self._resolve_service, adv)
+ retried = True
+ logging.error("Retrying resolution of service %s.%s: %s" % (adv.name(),
+ adv.stype(), err))
+
+ if not retried:
+ logging.error("Error resolving service %s.%s: %s" % (adv.name(),
+ adv.stype(), err))
+ adv.set_state(_SA_UNRESOLVED)
+
+ def _resolve_service(self, adv):
+ """Resolve and lookup a ZeroConf service to obtain its address and TXT records."""
+ # Ask avahi to resolve this particular service
+ path = self._mdns_service.ServiceResolverNew(dbus.Int32(adv.interface()),
+ dbus.Int32(adv.protocol()), adv.name(), adv.stype(), adv.domain(),
+ avahi.PROTO_INET, dbus.UInt32(0))
+ resolver = dbus.Interface(self._system_bus.get_object(avahi.DBUS_NAME, path),
+ avahi.DBUS_INTERFACE_SERVICE_RESOLVER)
+ resolver.connect_to_signal('Found', lambda *args: self._service_resolved_cb_glue(adv, *args))
+ resolver.connect_to_signal('Failure', lambda *args: self._service_resolved_failure_cb(adv, *args))
+ adv.inc_resolv_tries()
+ adv.set_resolver(resolver)
+ return False
+
+ def _service_appeared_cb(self, interface, protocol, full_name, stype, domain, flags):
+ local = flags & avahi.LOOKUP_RESULT_OUR_OWN > 0
+ adv_list = self._find_service_adv(interface=interface, protocol=protocol,
+ name=full_name, stype=stype, domain=domain, local=local)
+ adv = None
+ if not adv_list:
+ adv = ServiceAdv(interface=interface, protocol=protocol, name=full_name,
+ stype=stype, domain=domain, local=local)
+ self._service_advs.append(adv)
+ else:
+ adv = adv_list[0]
+
+ # Decompose service name if we can
+ (actid, buddy_name) = Service.decompose_service_name(full_name)
+
+ # If we care about the service right now, resolve it
+ resolve = False
+ item = self._find_registered_service_type(stype)
+ if actid is not None or item is not None:
+ resolve = True
+ if resolve and adv.state() == _SA_UNRESOLVED:
+ logging.debug("Found '%s' (%d) of type '%s' in domain" \
+ " '%s' on %i.%i; will resolve." % (full_name, flags, stype,
+ domain, interface, protocol))
+ adv.set_state(_SA_RESOLVE_PENDING)
+ gobject.idle_add(self._resolve_service, adv)
+
+ return False
+
+ def _service_appeared_cb_glue(self, interface, protocol, name, stype, domain, flags):
+ gobject.idle_add(self._service_appeared_cb, interface, protocol, name, stype, domain, flags)
+
+ def _service_disappeared_cb(self, interface, protocol, full_name, stype, domain, flags):
+ local = flags & avahi.LOOKUP_RESULT_OUR_OWN > 0
+ # If it's an unresolved service, remove it from our unresolved list
+ adv_list = self._find_service_adv(interface=interface, protocol=protocol,
+ name=full_name, stype=stype, domain=domain, local=local)
+ if not adv_list:
+ return False
+
+ # Get the service object; if none, we have nothing left to do
+ adv = adv_list[0]
+ service = adv.service()
+ self._service_advs.remove(adv)
+ del adv
+ if not service:
+ return False
+
+ logging.debug("Service %s.%s in domain %s on %i.%i disappeared." % (full_name,
+ stype, domain, interface, protocol))
+
+ self._dbus_helper.ServiceDisappeared(service.object_path())
+ self._handle_remove_activity_service(service)
+
+ # Decompose service name if we can
+ (actid, buddy_name) = Service.decompose_service_name(full_name)
+
+ # Remove the service from the buddy
+ try:
+ buddy = self._buddies[buddy_name]
+ except KeyError:
+ pass
+ else:
+ buddy.remove_service(service)
+ if not buddy.is_valid():
+ self._dbus_helper.BuddyDisappeared(buddy.object_path())
+ del self._buddies[buddy_name]
+ key = (service.get_full_name(), service.get_type())
+ del self._services[key]
+ return False
+
+ def _service_disappeared_cb_glue(self, interface, protocol, name, stype, domain, flags):
+ gobject.idle_add(self._service_disappeared_cb, interface, protocol, name, stype, domain, flags)
+
+ def _new_service_type_cb(self, interface, protocol, stype, domain, flags):
+ # Are we already browsing this domain for this type?
+ if self._service_browsers.has_key((interface, protocol, stype, domain)):
+ return
+
+ # Start browsing for all services of this type in this domain
+ try:
+ s_browser = self._mdns_service.ServiceBrowserNew(interface,
+ protocol, stype, domain, dbus.UInt32(0))
+ browser_obj = dbus.Interface(self._system_bus.get_object(avahi.DBUS_NAME, s_browser),
+ avahi.DBUS_INTERFACE_SERVICE_BROWSER)
+ browser_obj.connect_to_signal('ItemNew', self._service_appeared_cb_glue)
+ browser_obj.connect_to_signal('ItemRemove', self._service_disappeared_cb_glue)
+
+ self._service_browsers[(interface, protocol, stype, domain)] = browser_obj
+ except dbus.DBusException:
+ logging.debug("Error browsing service type '%s'" % stype)
+ return False
+
+ def _new_service_type_cb_glue(self, interface, protocol, stype, domain, flags):
+ if len(stype) > 0:
+ gobject.idle_add(self._new_service_type_cb, interface, protocol,
+ stype, domain, flags)
+
+ def _new_domain_cb(self, interface, protocol, domain, flags=0):
+ """Callback from Avahi when a new domain has been found. Start
+ browsing the new domain."""
+ # Only use .local for now...
+ if domain != "local":
+ return
+
+ # Are we already browsing this domain?
+ if self._service_type_browsers.has_key((interface, protocol, domain)):
+ return
+
+ # Start browsing this domain for the services its members offer
+ try:
+ st_browser = self._mdns_service.ServiceTypeBrowserNew(interface, protocol, domain, dbus.UInt32(0))
+ browser_obj = dbus.Interface(self._system_bus.get_object(avahi.DBUS_NAME, st_browser),
+ avahi.DBUS_INTERFACE_SERVICE_TYPE_BROWSER)
+ except dbus.DBusException, exc:
+ str_exc = str(exc)
+ logging.error("got exception %s while attempting to browse domain %s on %i.%i" % (str_exc, domain, interface, protocol))
+ if str_exc.find("The name org.freedesktop.Avahi was not provided by any .service files") >= 0:
+ raise Exception("Avahi does not appear to be running. '%s'" % str_exc)
+ else:
+ raise exc
+ logging.debug("Browsing domain '%s' on %i.%i ..." % (domain, interface, protocol))
+ browser_obj.connect_to_signal('ItemNew', self._new_service_type_cb_glue)
+ self._service_type_browsers[(interface, protocol, domain)] = browser_obj
+ return False
+
+ def _new_domain_cb_glue(self, interface, protocol, domain, flags=0):
+ gobject.idle_add(self._new_domain_cb, interface, protocol, domain, flags)
+
+ def join_activity(self, activity, stype, sender):
+ services = activity.get_services_of_type(stype)
+ if not len(services):
+ raise NotFoundError("The service type %s was not present within " \
+ "the activity %s" % (stype, activity.object_path()))
+ act_service = services[0]
+ props = act_service.get_properties()
+ color = activity.get_color()
+ if color:
+ props['color'] = color
+ return self._share_activity(activity.get_id(), stype, properties,
+ act_service.get_address(), act_service.get_port(),
+ act_service.get_domain(), sender)
+
+ def share_activity(self, activity_id, stype, properties=None, address=None,
+ port=-1, domain=u"local", sender=None):
+ """Convenience function to share an activity with other buddies."""
+ if not util.validate_activity_id(activity_id):
+ raise ValueError("invalid activity id")
+ owner_nick = self._owner.get_name()
+ real_name = Service.compose_service_name(owner_nick, activity_id)
+ if address and not isinstance(address, unicode):
+ raise ValueError("address must be a unicode string.")
+ if address == None and stype.endswith('_udp'):
+ # Use random currently unassigned multicast address
+ address = u"232.%d.%d.%d" % (random.randint(0, 254), random.randint(1, 254),
+ random.randint(1, 254))
+ properties['address'] = address
+ properties['port'] = port
+ if port and port != -1 and (not isinstance(port, int) or port <= 1024 or port >= 65535):
+ raise ValueError("port must be a number between 1024 and 65535")
+
+ color = self._owner.get_color()
+ if color:
+ properties['color'] = color
+
+ logging.debug('Share activity %s, type %s, address %s, port %d, " \
+ "properties %s' % (activity_id, stype, address, port,
+ properties))
+ return self.register_service(real_name, stype, properties, address,
+ port, domain, sender)
+
+ def register_service(self, name, stype, properties={}, address=None,
+ port=-1, domain=u"local", sender=None):
+ """Register a new service, advertising it to other Buddies on the network."""
+ # Refuse to register if we can't get the dbus connection this request
+ # came from for some reason
+ if not sender:
+ raise RuntimeError("Service registration request must have a sender.")
+
+ (actid, person_name) = Service.decompose_service_name(name)
+ if self.get_owner() and person_name != self.get_owner().get_name():
+ raise RuntimeError("Tried to register a service that didn't have" \
+ " Owner nick as the service name!")
+ if not domain or not len(domain):
+ domain = u"local"
+ if not port or port == -1:
+ port = random.randint(4000, 65000)
+
+ objid = self._get_next_object_id()
+ service = Service.Service(self._bus_name, objid, name=name,
+ stype=stype, domain=domain, address=address, port=port,
+ properties=properties, source_address=None,
+ local_publisher=sender)
+ self._services[(name, stype)] = service
+ self.register_service_type(stype)
+ service.register(self._system_bus, self._mdns_service)
+ return service
+
+ def unregister_service(self, service, sender=None):
+ service.unregister(sender)
+
+ def register_service_type(self, stype):
+ """Requests that the Presence service look for and recognize
+ a certain mDNS service types."""
+ if not isinstance(stype, unicode):
+ raise ValueError("service type must be a unicode string.")
+
+ # If we've already registered it as a service type, ref it and return
+ item = self._find_registered_service_type(stype)
+ if item is not None:
+ item.ref()
+ return
+
+ # Otherwise track this type now
+ obj = RegisteredServiceType(stype)
+ self._registered_service_types.append(obj)
+
+ # Find unresolved services that match the service type
+ # we're now interested in, and resolve them
+ resolv_list = []
+
+ # Find services of this type
+ resolv_list = self._find_service_adv(stype=stype)
+ # Request resolution for them if they aren't in-process already
+ for adv in resolv_list:
+ if adv.state() == _SA_UNRESOLVED:
+ adv.set_state(_SA_RESOLVE_PENDING)
+ gobject.idle_add(self._resolve_service, adv)
+
+ def unregister_service_type(self, stype):
+ """Stop tracking a certain mDNS service."""
+ if not isinstance(stype, unicode):
+ raise ValueError("service type must be a unicode string.")
+
+ # if it was found, unref it and possibly remove it
+ item = self._find_registered_service_type(stype)
+ if not item:
+ return
+ if item.unref() <= 0:
+ self._registered_service_types.remove(item)
+ del item
def main():
- from sugar import TracebackUtils
- loop = gobject.MainLoop()
- ps = PresenceService()
- tbh = TracebackUtils.TracebackHelper()
- try:
- loop.run()
- except KeyboardInterrupt:
- print 'Ctrl+C pressed, exiting...'
+ from sugar import TracebackUtils
+ loop = gobject.MainLoop()
+ ps = PresenceService()
+ tbh = TracebackUtils.TracebackHelper()
+ try:
+ loop.run()
+ except KeyboardInterrupt:
+ print 'Ctrl+C pressed, exiting...'
- del tbh
+ del tbh
if __name__ == "__main__":
- main()
+ main()
diff --git a/services/presence/Service.py b/services/presence/Service.py
index bb41f88..5072ed5 100644
--- a/services/presence/Service.py
+++ b/services/presence/Service.py
@@ -24,61 +24,61 @@ import logging
import gobject
def compose_service_name(name, activity_id):
- if isinstance(name, str):
- name = unicode(name)
- if not name:
- raise ValueError("name must be a valid string.")
- if not activity_id:
- return name
- if not isinstance(name, unicode):
- raise ValueError("name must be in unicode.")
- composed = "%s [%s]" % (name, activity_id)
- return composed
+ if isinstance(name, str):
+ name = unicode(name)
+ if not name:
+ raise ValueError("name must be a valid string.")
+ if not activity_id:
+ return name
+ if not isinstance(name, unicode):
+ raise ValueError("name must be in unicode.")
+ composed = "%s [%s]" % (name, activity_id)
+ return composed
def decompose_service_name(name):
- """Break a service name into the name and activity ID, if we can."""
- if not isinstance(name, unicode):
- raise ValueError("name must be a valid unicode string.")
- name_len = len(name)
- if name_len < util.ACTIVITY_ID_LEN + 5:
- return (None, name)
- # check for activity id end marker
- if name[name_len - 1] != "]":
- return (None, name)
- start = name_len - 1 - util.ACTIVITY_ID_LEN
- end = name_len - 1
- # check for activity id start marker
- if name[start - 1] != "[" or name[start - 2] != " ":
- return (None, name)
- activity_id = name[start:end]
- if not util.validate_activity_id(activity_id):
- return (None, name)
- return (activity_id, name[:start - 2])
+ """Break a service name into the name and activity ID, if we can."""
+ if not isinstance(name, unicode):
+ raise ValueError("name must be a valid unicode string.")
+ name_len = len(name)
+ if name_len < util.ACTIVITY_ID_LEN + 5:
+ return (None, name)
+ # check for activity id end marker
+ if name[name_len - 1] != "]":
+ return (None, name)
+ start = name_len - 1 - util.ACTIVITY_ID_LEN
+ end = name_len - 1
+ # check for activity id start marker
+ if name[start - 1] != "[" or name[start - 2] != " ":
+ return (None, name)
+ activity_id = name[start:end]
+ if not util.validate_activity_id(activity_id):
+ return (None, name)
+ return (activity_id, name[:start - 2])
def _one_dict_differs(dict1, dict2):
- diff_keys = []
- for key, value in dict1.items():
- if not dict2.has_key(key) or dict2[key] != value:
- diff_keys.append(key)
- return diff_keys
+ diff_keys = []
+ for key, value in dict1.items():
+ if not dict2.has_key(key) or dict2[key] != value:
+ diff_keys.append(key)
+ return diff_keys
def _dicts_differ(dict1, dict2):
- diff_keys = []
- diff1 = _one_dict_differs(dict1, dict2)
- diff2 = _one_dict_differs(dict2, dict1)
- for key in diff2:
- if key not in diff1:
- diff_keys.append(key)
- diff_keys += diff1
- return diff_keys
+ diff_keys = []
+ diff1 = _one_dict_differs(dict1, dict2)
+ diff2 = _one_dict_differs(dict2, dict1)
+ for key in diff2:
+ if key not in diff1:
+ diff_keys.append(key)
+ diff_keys += diff1
+ return diff_keys
def _convert_properties_to_dbus_byte_array(props):
- # Ensure properties are converted to ByteArray types
- # because python sometimes can't figure that out
- info = dbus.Array([], signature="aay")
- for k, v in props.items():
- info.append(dbus.types.ByteArray("%s=%s" % (k, v)))
- return info
+ # Ensure properties are converted to ByteArray types
+ # because python sometimes can't figure that out
+ info = dbus.Array([], signature="aay")
+ for k, v in props.items():
+ info.append(dbus.types.ByteArray("%s=%s" % (k, v)))
+ return info
_ACTIVITY_ID_TAG = "ActivityID"
@@ -86,360 +86,360 @@ SERVICE_DBUS_INTERFACE = "org.laptop.Presence.Service"
SERVICE_DBUS_OBJECT_PATH = "/org/laptop/Presence/Services/"
class ServiceDBusHelper(dbus.service.Object):
- """Handle dbus requests and signals for Service objects"""
- def __init__(self, parent, bus_name, object_path):
- self._parent = parent
- self._bus_name = bus_name
- self._object_path = object_path
- dbus.service.Object.__init__(self, bus_name, self._object_path)
-
- @dbus.service.signal(SERVICE_DBUS_INTERFACE,
- signature="as")
- def PublishedValueChanged(self, keylist):
- pass
-
- @dbus.service.method(SERVICE_DBUS_INTERFACE,
- in_signature="", out_signature="a{sv}")
- def getProperties(self):
- """Return service properties."""
- pary = {}
- pary['name'] = self._parent.get_name()
- pary['type'] = self._parent.get_type()
- pary['domain'] = self._parent.get_domain()
- actid = self._parent.get_activity_id()
- if actid:
- pary['activityId'] = actid
- port = self._parent.get_port()
- if port:
- pary['port'] = self._parent.get_port()
- addr = self._parent.get_address()
- if addr:
- pary['address'] = addr
- source_addr = self._parent.get_source_address()
- if source_addr:
- pary['sourceAddress'] = source_addr
- return pary
-
- @dbus.service.method(SERVICE_DBUS_INTERFACE,
- in_signature="s")
- def getPublishedValue(self, key):
- """Return the value belonging to the requested key from the
- service's TXT records."""
- val = self._parent.get_one_property(key)
- if not val:
- raise KeyError("Value was not found.")
- return val
-
- @dbus.service.method(SERVICE_DBUS_INTERFACE,
- in_signature="", out_signature="a{sv}")
- def getPublishedValues(self):
- pary = {}
- props = self._parent.get_properties()
- for key, value in props.items():
- pary[key] = str(value)
- return dbus.Dictionary(pary)
-
- @dbus.service.method(SERVICE_DBUS_INTERFACE,
- sender_keyword="sender")
- def setPublishedValue(self, key, value, sender):
- self._parent.set_property(key, value, sender)
-
- @dbus.service.method(SERVICE_DBUS_INTERFACE,
- in_signature="a{sv}", sender_keyword="sender")
- def setPublishedValues(self, values, sender):
- if not self._parent.is_local():
- raise ValueError("Service was not not registered by requesting process!")
- self._parent.set_properties(values, sender)
+ """Handle dbus requests and signals for Service objects"""
+ def __init__(self, parent, bus_name, object_path):
+ self._parent = parent
+ self._bus_name = bus_name
+ self._object_path = object_path
+ dbus.service.Object.__init__(self, bus_name, self._object_path)
+
+ @dbus.service.signal(SERVICE_DBUS_INTERFACE,
+ signature="as")
+ def PublishedValueChanged(self, keylist):
+ pass
+
+ @dbus.service.method(SERVICE_DBUS_INTERFACE,
+ in_signature="", out_signature="a{sv}")
+ def getProperties(self):
+ """Return service properties."""
+ pary = {}
+ pary['name'] = self._parent.get_name()
+ pary['type'] = self._parent.get_type()
+ pary['domain'] = self._parent.get_domain()
+ actid = self._parent.get_activity_id()
+ if actid:
+ pary['activityId'] = actid
+ port = self._parent.get_port()
+ if port:
+ pary['port'] = self._parent.get_port()
+ addr = self._parent.get_address()
+ if addr:
+ pary['address'] = addr
+ source_addr = self._parent.get_source_address()
+ if source_addr:
+ pary['sourceAddress'] = source_addr
+ return pary
+
+ @dbus.service.method(SERVICE_DBUS_INTERFACE,
+ in_signature="s")
+ def getPublishedValue(self, key):
+ """Return the value belonging to the requested key from the
+ service's TXT records."""
+ val = self._parent.get_one_property(key)
+ if not val:
+ raise KeyError("Value was not found.")
+ return val
+
+ @dbus.service.method(SERVICE_DBUS_INTERFACE,
+ in_signature="", out_signature="a{sv}")
+ def getPublishedValues(self):
+ pary = {}
+ props = self._parent.get_properties()
+ for key, value in props.items():
+ pary[key] = str(value)
+ return dbus.Dictionary(pary)
+
+ @dbus.service.method(SERVICE_DBUS_INTERFACE,
+ sender_keyword="sender")
+ def setPublishedValue(self, key, value, sender):
+ self._parent.set_property(key, value, sender)
+
+ @dbus.service.method(SERVICE_DBUS_INTERFACE,
+ in_signature="a{sv}", sender_keyword="sender")
+ def setPublishedValues(self, values, sender):
+ if not self._parent.is_local():
+ raise ValueError("Service was not not registered by requesting process!")
+ self._parent.set_properties(values, sender)
class Service(gobject.GObject):
- """Encapsulates information about a specific ZeroConf/mDNS
- service as advertised on the network."""
-
- __gsignals__ = {
- 'property-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT]))
- }
-
- def __init__(self, bus_name, object_id, name, stype, domain=u"local",
- address=None, port=-1, properties=None, source_address=None,
- local_publisher=None):
- gobject.GObject.__init__(self)
- if not bus_name:
- raise ValueError("DBus bus name must be valid")
- if not object_id or not isinstance(object_id, int):
- raise ValueError("object id must be a valid number")
-
- # Validate immutable options
- if name and not isinstance(name, unicode):
- raise ValueError("name must be unicode.")
- if not name or not len(name):
- raise ValueError("must specify a valid service name.")
-
- if stype and not isinstance(stype, unicode):
- raise ValueError("service type must be in unicode.")
- if not stype or not len(stype):
- raise ValueError("must specify a valid service type.")
- if not stype.endswith("._tcp") and not stype.endswith("._udp"):
- raise ValueError("must specify a TCP or UDP service type.")
-
- if not isinstance(domain, unicode):
- raise ValueError("domain must be in unicode.")
- if domain and domain != "local":
- raise ValueError("must use the 'local' domain (for now).")
-
- # ID of the D-Bus connection that published this service, if any.
- # We only let the local publisher modify the service.
- self._local_publisher = local_publisher
-
- self._avahi_entry_group = None
-
- (actid, real_name) = decompose_service_name(name)
- self._name = real_name
- self._full_name = name
- self._stype = stype
- self._domain = domain
- self._port = -1
- self.set_port(port)
- self._properties = {}
- self._dbus_helper = None
- self._internal_set_properties(properties)
-
- # Source address is the unicast source IP
- self._source_address = None
- if source_address is not None:
- self.set_source_address(source_address)
-
- # Address is the published address, could be multicast or unicast
- self._address = None
- if self._properties.has_key('address'):
- self.set_address(self._properties['address'])
- elif address is not None:
- self.set_address(address)
- self._properties['address'] = address
-
- # Ensure that an ActivityID tag, if given, matches
- # what we expect from the service type
- if self._properties.has_key(_ACTIVITY_ID_TAG):
- prop_actid = self._properties[_ACTIVITY_ID_TAG]
- if (prop_actid and not actid) or (prop_actid != actid):
- raise ValueError("ActivityID property specified, but the " \
- "service names's activity ID didn't match it: %s," \
- " %s" % (prop_actid, actid))
- self._activity_id = actid
- if actid and not self._properties.has_key(_ACTIVITY_ID_TAG):
- self._properties[_ACTIVITY_ID_TAG] = actid
-
- self._owner = None
-
- # register ourselves with dbus
- self._object_id = object_id
- self._object_path = SERVICE_DBUS_OBJECT_PATH + str(self._object_id)
- self._dbus_helper = ServiceDBusHelper(self, bus_name, self._object_path)
-
- def object_path(self):
- return dbus.ObjectPath(self._object_path)
-
- def get_owner(self):
- return self._owner
-
- def set_owner(self, owner):
- if self._owner is not None:
- raise RuntimeError("Can only set a service's owner once")
- self._owner = owner
-
- def is_local(self):
- if self._local_publisher is not None:
- return True
- return False
-
- def get_name(self):
- """Return the service's name, usually that of the
- buddy who provides it."""
- return self._name
-
- def get_full_name(self):
- return self._full_name
-
- def get_one_property(self, key):
- """Return one property of the service, or None
- if the property was not found. Cannot distinguish
- between lack of a property, and a property value that
- actually is None."""
- if key in self._properties.keys():
- return self._properties[key]
- return None
-
- def get_properties(self):
- """Return a python dictionary of all the service's
- properties."""
- return self._properties
-
- def __emit_properties_changed_signal(self, keys):
- if self._dbus_helper:
- self._dbus_helper.PublishedValueChanged(keys)
- self.emit('property-changed', keys)
-
- def set_property(self, key, value, sender=None):
- """Set one service property"""
- if not self._local_publisher:
- raise ValueError("Service was not not registered by requesting process!")
- if sender is not None and self._local_publisher != sender:
- raise ValueError("Service was not not registered by requesting process!")
-
- if not isinstance(key, unicode):
- raise ValueError("Key must be a unicode string.")
- if not isinstance(value, unicode) and not isinstance(value, bool):
- raise ValueError("Key must be a unicode string or a boolean.")
-
- # Ignore setting the key to it's current value
- if self._properties.has_key(key):
- if self._properties[key] == value:
- return
-
- # Blank value means remove key
- remove = False
- if isinstance(value, unicode) and len(value) == 0:
- remove = True
- if isinstance(value, bool) and value == False:
- remove = True
-
- if remove:
- # If the key wasn't present, return without error
- if self._properties.has_key(key):
- del self._properties[key]
- else:
- # Otherwise set it
- if isinstance(value, bool):
- value = ""
- self._properties[key] = value
-
- # if the service is locally published already, update the TXT records
- if self._local_publisher and self._avahi_entry_group:
- self.__internal_update_avahi_properties()
-
- self.__emit_properties_changed_signal([key])
-
- def set_properties(self, properties, sender=None, from_network=False):
- """Set all service properties in one call"""
- if sender is not None and self._local_publisher != sender:
- raise ValueError("Service was not not registered by requesting process!")
-
- self._internal_set_properties(properties, from_network)
-
- def _internal_set_properties(self, properties, from_network=False):
- """Set the service's properties from either an Avahi
- TXT record (a list of lists of integers), or a
- python dictionary."""
- if not isinstance (properties, dict):
- raise ValueError("Properties must be a dictionary.")
-
- # Make sure the properties are actually different
- diff_keys = _dicts_differ(self._properties, properties)
- if len(diff_keys) == 0:
- return
-
- self._properties = {}
- # Set key/value pairs on internal property list
- for key, value in properties.items():
- if len(key) == 0:
- continue
- tmp_key = key
- tmp_val = value
- if not isinstance(tmp_key, unicode):
- tmp_key = unicode(tmp_key)
- if not isinstance(tmp_val, unicode):
- tmp_val = unicode(tmp_val)
- self._properties[tmp_key] = tmp_val
-
- # if the service is locally published already, update the TXT records
- if self._local_publisher and self._avahi_entry_group and not from_network:
- self.__internal_update_avahi_properties()
-
- self.__emit_properties_changed_signal(diff_keys)
-
- def __internal_update_avahi_properties(self):
- info = _convert_properties_to_dbus_byte_array(self._properties)
- self._avahi_entry_group.UpdateServiceTxt(avahi.IF_UNSPEC,
- avahi.PROTO_UNSPEC, 0,
- dbus.String(self._full_name), dbus.String(self._stype),
- dbus.String(self._domain), info)
-
- def get_type(self):
- """Return the service's service type."""
- return self._stype
-
- def get_activity_id(self):
- """Return the activity ID this service is associated with, if any."""
- return self._activity_id
-
- def get_port(self):
- return self._port
-
- def set_port(self, port):
- if not isinstance(port, int) or (port <= 1024 and port > 65536):
- raise ValueError("must specify a valid port number between 1024 and 65536.")
- self._port = port
-
- def get_source_address(self):
- return self._source_address
-
- def set_source_address(self, address):
- if not address or not isinstance(address, unicode):
- raise ValueError("address must be unicode")
- self._source_address = address
-
- def get_address(self):
- return self._address
-
- def set_address(self, address):
- if not address or not isinstance(address, unicode):
- raise ValueError("address must be a unicode string")
- self._address = address
- self._properties['address'] = address
-
- def get_domain(self):
- """Return the ZeroConf/mDNS domain the service was found in."""
- return self._domain
-
- def register(self, system_bus, avahi_service):
- if self._avahi_entry_group is not None:
- raise RuntimeError("Service already registered!")
-
- obj = system_bus.get_object(avahi.DBUS_NAME, avahi_service.EntryGroupNew())
- self._avahi_entry_group = dbus.Interface(obj, avahi.DBUS_INTERFACE_ENTRY_GROUP)
-
- info = _convert_properties_to_dbus_byte_array(self._properties)
- logging.debug("Will register service with name='%s', stype='%s'," \
- " domain='%s', address='%s', port=%d, info='%s'" % (self._full_name,
- self._stype, self._domain, self._address, self._port, info))
-
- self._avahi_entry_group.AddService(avahi.IF_UNSPEC, avahi.PROTO_UNSPEC, 0,
- dbus.String(self._full_name), dbus.String(self._stype),
- dbus.String(self._domain), dbus.String(""), # let Avahi figure the 'host' out
- dbus.UInt16(self._port), info)
-
- self._avahi_entry_group.connect_to_signal('StateChanged', self.__entry_group_changed_cb)
- self._avahi_entry_group.Commit()
-
- def __entry_group_changed_cb(self, state, error):
- pass
-# logging.debug("** %s.%s Entry group changed: state %s, error %s" % (self._full_name, self._stype, state, error))
-
- def unregister(self, sender):
- # Refuse to unregister if we can't get the dbus connection this request
- # came from for some reason
- if not sender:
- raise RuntimeError("Service registration request must have a sender.")
- if not self._local_publisher:
- raise ValueError("Service was not a local service provided by this laptop!")
- if sender is not None and self._local_publisher != sender:
- raise ValueError("Service was not registered by requesting process!")
- if not self._avahi_entry_group:
- raise ValueError("Service was not registered by requesting process!")
- self._avahi_entry_group.Free()
- del self._avahi_entry_group
- self._avahi_entry_group = None
+ """Encapsulates information about a specific ZeroConf/mDNS
+ service as advertised on the network."""
+
+ __gsignals__ = {
+ 'property-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT]))
+ }
+
+ def __init__(self, bus_name, object_id, name, stype, domain=u"local",
+ address=None, port=-1, properties=None, source_address=None,
+ local_publisher=None):
+ gobject.GObject.__init__(self)
+ if not bus_name:
+ raise ValueError("DBus bus name must be valid")
+ if not object_id or not isinstance(object_id, int):
+ raise ValueError("object id must be a valid number")
+
+ # Validate immutable options
+ if name and not isinstance(name, unicode):
+ raise ValueError("name must be unicode.")
+ if not name or not len(name):
+ raise ValueError("must specify a valid service name.")
+
+ if stype and not isinstance(stype, unicode):
+ raise ValueError("service type must be in unicode.")
+ if not stype or not len(stype):
+ raise ValueError("must specify a valid service type.")
+ if not stype.endswith("._tcp") and not stype.endswith("._udp"):
+ raise ValueError("must specify a TCP or UDP service type.")
+
+ if not isinstance(domain, unicode):
+ raise ValueError("domain must be in unicode.")
+ if domain and domain != "local":
+ raise ValueError("must use the 'local' domain (for now).")
+
+ # ID of the D-Bus connection that published this service, if any.
+ # We only let the local publisher modify the service.
+ self._local_publisher = local_publisher
+
+ self._avahi_entry_group = None
+
+ (actid, real_name) = decompose_service_name(name)
+ self._name = real_name
+ self._full_name = name
+ self._stype = stype
+ self._domain = domain
+ self._port = -1
+ self.set_port(port)
+ self._properties = {}
+ self._dbus_helper = None
+ self._internal_set_properties(properties)
+
+ # Source address is the unicast source IP
+ self._source_address = None
+ if source_address is not None:
+ self.set_source_address(source_address)
+
+ # Address is the published address, could be multicast or unicast
+ self._address = None
+ if self._properties.has_key('address'):
+ self.set_address(self._properties['address'])
+ elif address is not None:
+ self.set_address(address)
+ self._properties['address'] = address
+
+ # Ensure that an ActivityID tag, if given, matches
+ # what we expect from the service type
+ if self._properties.has_key(_ACTIVITY_ID_TAG):
+ prop_actid = self._properties[_ACTIVITY_ID_TAG]
+ if (prop_actid and not actid) or (prop_actid != actid):
+ raise ValueError("ActivityID property specified, but the " \
+ "service names's activity ID didn't match it: %s," \
+ " %s" % (prop_actid, actid))
+ self._activity_id = actid
+ if actid and not self._properties.has_key(_ACTIVITY_ID_TAG):
+ self._properties[_ACTIVITY_ID_TAG] = actid
+
+ self._owner = None
+
+ # register ourselves with dbus
+ self._object_id = object_id
+ self._object_path = SERVICE_DBUS_OBJECT_PATH + str(self._object_id)
+ self._dbus_helper = ServiceDBusHelper(self, bus_name, self._object_path)
+
+ def object_path(self):
+ return dbus.ObjectPath(self._object_path)
+
+ def get_owner(self):
+ return self._owner
+
+ def set_owner(self, owner):
+ if self._owner is not None:
+ raise RuntimeError("Can only set a service's owner once")
+ self._owner = owner
+
+ def is_local(self):
+ if self._local_publisher is not None:
+ return True
+ return False
+
+ def get_name(self):
+ """Return the service's name, usually that of the
+ buddy who provides it."""
+ return self._name
+
+ def get_full_name(self):
+ return self._full_name
+
+ def get_one_property(self, key):
+ """Return one property of the service, or None
+ if the property was not found. Cannot distinguish
+ between lack of a property, and a property value that
+ actually is None."""
+ if key in self._properties.keys():
+ return self._properties[key]
+ return None
+
+ def get_properties(self):
+ """Return a python dictionary of all the service's
+ properties."""
+ return self._properties
+
+ def __emit_properties_changed_signal(self, keys):
+ if self._dbus_helper:
+ self._dbus_helper.PublishedValueChanged(keys)
+ self.emit('property-changed', keys)
+
+ def set_property(self, key, value, sender=None):
+ """Set one service property"""
+ if not self._local_publisher:
+ raise ValueError("Service was not not registered by requesting process!")
+ if sender is not None and self._local_publisher != sender:
+ raise ValueError("Service was not not registered by requesting process!")
+
+ if not isinstance(key, unicode):
+ raise ValueError("Key must be a unicode string.")
+ if not isinstance(value, unicode) and not isinstance(value, bool):
+ raise ValueError("Key must be a unicode string or a boolean.")
+
+ # Ignore setting the key to it's current value
+ if self._properties.has_key(key):
+ if self._properties[key] == value:
+ return
+
+ # Blank value means remove key
+ remove = False
+ if isinstance(value, unicode) and len(value) == 0:
+ remove = True
+ if isinstance(value, bool) and value == False:
+ remove = True
+
+ if remove:
+ # If the key wasn't present, return without error
+ if self._properties.has_key(key):
+ del self._properties[key]
+ else:
+ # Otherwise set it
+ if isinstance(value, bool):
+ value = ""
+ self._properties[key] = value
+
+ # if the service is locally published already, update the TXT records
+ if self._local_publisher and self._avahi_entry_group:
+ self.__internal_update_avahi_properties()
+
+ self.__emit_properties_changed_signal([key])
+
+ def set_properties(self, properties, sender=None, from_network=False):
+ """Set all service properties in one call"""
+ if sender is not None and self._local_publisher != sender:
+ raise ValueError("Service was not not registered by requesting process!")
+
+ self._internal_set_properties(properties, from_network)
+
+ def _internal_set_properties(self, properties, from_network=False):
+ """Set the service's properties from either an Avahi
+ TXT record (a list of lists of integers), or a
+ python dictionary."""
+ if not isinstance (properties, dict):
+ raise ValueError("Properties must be a dictionary.")
+
+ # Make sure the properties are actually different
+ diff_keys = _dicts_differ(self._properties, properties)
+ if len(diff_keys) == 0:
+ return
+
+ self._properties = {}
+ # Set key/value pairs on internal property list
+ for key, value in properties.items():
+ if len(key) == 0:
+ continue
+ tmp_key = key
+ tmp_val = value
+ if not isinstance(tmp_key, unicode):
+ tmp_key = unicode(tmp_key)
+ if not isinstance(tmp_val, unicode):
+ tmp_val = unicode(tmp_val)
+ self._properties[tmp_key] = tmp_val
+
+ # if the service is locally published already, update the TXT records
+ if self._local_publisher and self._avahi_entry_group and not from_network:
+ self.__internal_update_avahi_properties()
+
+ self.__emit_properties_changed_signal(diff_keys)
+
+ def __internal_update_avahi_properties(self):
+ info = _convert_properties_to_dbus_byte_array(self._properties)
+ self._avahi_entry_group.UpdateServiceTxt(avahi.IF_UNSPEC,
+ avahi.PROTO_UNSPEC, 0,
+ dbus.String(self._full_name), dbus.String(self._stype),
+ dbus.String(self._domain), info)
+
+ def get_type(self):
+ """Return the service's service type."""
+ return self._stype
+
+ def get_activity_id(self):
+ """Return the activity ID this service is associated with, if any."""
+ return self._activity_id
+
+ def get_port(self):
+ return self._port
+
+ def set_port(self, port):
+ if not isinstance(port, int) or (port <= 1024 and port > 65536):
+ raise ValueError("must specify a valid port number between 1024 and 65536.")
+ self._port = port
+
+ def get_source_address(self):
+ return self._source_address
+
+ def set_source_address(self, address):
+ if not address or not isinstance(address, unicode):
+ raise ValueError("address must be unicode")
+ self._source_address = address
+
+ def get_address(self):
+ return self._address
+
+ def set_address(self, address):
+ if not address or not isinstance(address, unicode):
+ raise ValueError("address must be a unicode string")
+ self._address = address
+ self._properties['address'] = address
+
+ def get_domain(self):
+ """Return the ZeroConf/mDNS domain the service was found in."""
+ return self._domain
+
+ def register(self, system_bus, avahi_service):
+ if self._avahi_entry_group is not None:
+ raise RuntimeError("Service already registered!")
+
+ obj = system_bus.get_object(avahi.DBUS_NAME, avahi_service.EntryGroupNew())
+ self._avahi_entry_group = dbus.Interface(obj, avahi.DBUS_INTERFACE_ENTRY_GROUP)
+
+ info = _convert_properties_to_dbus_byte_array(self._properties)
+ logging.debug("Will register service with name='%s', stype='%s'," \
+ " domain='%s', address='%s', port=%d, info='%s'" % (self._full_name,
+ self._stype, self._domain, self._address, self._port, info))
+
+ self._avahi_entry_group.AddService(avahi.IF_UNSPEC, avahi.PROTO_UNSPEC, 0,
+ dbus.String(self._full_name), dbus.String(self._stype),
+ dbus.String(self._domain), dbus.String(""), # let Avahi figure the 'host' out
+ dbus.UInt16(self._port), info)
+
+ self._avahi_entry_group.connect_to_signal('StateChanged', self.__entry_group_changed_cb)
+ self._avahi_entry_group.Commit()
+
+ def __entry_group_changed_cb(self, state, error):
+ pass
+# logging.debug("** %s.%s Entry group changed: state %s, error %s" % (self._full_name, self._stype, state, error))
+
+ def unregister(self, sender):
+ # Refuse to unregister if we can't get the dbus connection this request
+ # came from for some reason
+ if not sender:
+ raise RuntimeError("Service registration request must have a sender.")
+ if not self._local_publisher:
+ raise ValueError("Service was not a local service provided by this laptop!")
+ if sender is not None and self._local_publisher != sender:
+ raise ValueError("Service was not registered by requesting process!")
+ if not self._avahi_entry_group:
+ raise ValueError("Service was not registered by requesting process!")
+ self._avahi_entry_group.Free()
+ del self._avahi_entry_group
+ self._avahi_entry_group = None
#################################################################
@@ -450,153 +450,153 @@ import unittest
__objid_seq = 0
def _next_objid():
- global __objid_seq
- __objid_seq = __objid_seq + 1
- return __objid_seq
+ global __objid_seq
+ __objid_seq = __objid_seq + 1
+ return __objid_seq
class ServiceTestCase(unittest.TestCase):
- _DEF_NAME = u"foobar"
- _DEF_STYPE = u"_foo._bar._tcp"
- _DEF_DOMAIN = u"local"
- _DEF_ADDRESS = u"1.1.1.1"
- _DEF_PORT = 1234
- _DEF_PROPS = {'foobar': 'baz'}
- _STR_TEST_ARGS = [None, 0, [], {}]
-
- def __init__(self, name):
- self._bus = dbus.SessionBus()
- self._bus_name = dbus.service.BusName('org.laptop.Presence', bus=self._bus)
- unittest.TestCase.__init__(self, name)
-
- def __del__(self):
- del self._bus_name
- del self._bus
-
- def _test_init_fail(self, name, stype, domain, address, port, properties, fail_msg):
- """Test something we expect to fail."""
- try:
- objid = _next_objid()
- service = Service(self._bus_name, objid, name, stype, domain, address,
- port, properties)
- except ValueError, exc:
- pass
- else:
- self.fail("expected a ValueError for %s." % fail_msg)
-
- def testName(self):
- for item in self._STR_TEST_ARGS:
- self._test_init_fail(item, self._DEF_STYPE, self._DEF_DOMAIN, self._DEF_ADDRESS,
- self._DEF_PORT, self._DEF_PROPS, "invalid name")
-
- def testType(self):
- for item in self._STR_TEST_ARGS:
- self._test_init_fail(self._DEF_NAME, item, self._DEF_DOMAIN, self._DEF_ADDRESS,
- self._DEF_PORT, self._DEF_PROPS, "invalid service type")
- self._test_init_fail(self._DEF_NAME, u"_bork._foobar", self._DEF_DOMAIN, self._DEF_ADDRESS,
- self._DEF_PORT, self._DEF_PROPS, "invalid service type")
-
- def testDomain(self):
- for item in self._STR_TEST_ARGS:
- self._test_init_fail(self._DEF_NAME, self._DEF_STYPE, item, self._DEF_ADDRESS,
- self._DEF_PORT, self._DEF_PROPS, "invalid domain")
- # Only accept local for now
- self._test_init_fail(self._DEF_NAME, self._DEF_STYPE, u"foobar", self._DEF_ADDRESS,
- self._DEF_PORT, self._DEF_PROPS, "invalid domain")
- # Make sure "" works
- objid = _next_objid()
- service = Service(self._bus_name, objid, self._DEF_NAME, self._DEF_STYPE, u"",
- self._DEF_ADDRESS, self._DEF_PORT, self._DEF_PROPS)
- assert service, "Empty domain was not accepted!"
-
- def testAddress(self):
- self._test_init_fail(self._DEF_NAME, self._DEF_STYPE, self._DEF_DOMAIN, [],
- self._DEF_PORT, self._DEF_PROPS, "invalid address")
- self._test_init_fail(self._DEF_NAME, self._DEF_STYPE, self._DEF_DOMAIN, {},
- self._DEF_PORT, self._DEF_PROPS, "invalid address")
- self._test_init_fail(self._DEF_NAME, self._DEF_STYPE, self._DEF_DOMAIN, 1234,
- self._DEF_PORT, self._DEF_PROPS, "invalid address")
-
- def testPort(self):
- self._test_init_fail(self._DEF_NAME, self._DEF_STYPE, self._DEF_DOMAIN, self._DEF_ADDRESS,
- [], self._DEF_PROPS, "invalid port")
- self._test_init_fail(self._DEF_NAME, self._DEF_STYPE, self._DEF_DOMAIN, self._DEF_ADDRESS,
- {}, self._DEF_PROPS, "invalid port")
- self._test_init_fail(self._DEF_NAME, self._DEF_STYPE, self._DEF_DOMAIN, self._DEF_ADDRESS,
- "adf", self._DEF_PROPS, "invalid port")
-
- def testGoodInit(self):
- objid = _next_objid()
- service = Service(self._bus_name, objid, self._DEF_NAME, self._DEF_STYPE, self._DEF_DOMAIN,
- self._DEF_ADDRESS, self._DEF_PORT, self._DEF_PROPS)
- assert service.get_name() == self._DEF_NAME, "service name wasn't correct after init."
- assert service.get_type() == self._DEF_STYPE, "service type wasn't correct after init."
- assert service.get_domain() == "local", "service domain wasn't correct after init."
- assert service.get_address() == self._DEF_ADDRESS, "service address wasn't correct after init."
- assert service.get_port() == self._DEF_PORT, "service port wasn't correct after init."
- assert service.object_path() == SERVICE_DBUS_OBJECT_PATH + str(objid)
- value = service.get_one_property('foobar')
- assert value and value == 'baz', "service property wasn't correct after init."
-
- def testAvahiProperties(self):
- props = [[111, 114, 103, 46, 102, 114, 101, 101, 100, 101, 115, 107, 116, 111, 112, 46, 65, 118, 97, 104, 105, 46, 99, 111, 111, 107, 105, 101, 61, 50, 54, 48, 49, 53, 52, 51, 57, 53, 50]]
- key = "org.freedesktop.Avahi.cookie"
- expected_value = "2601543952"
- objid = _next_objid()
- service = Service(self._bus_name, objid, self._DEF_NAME, self._DEF_STYPE, self._DEF_DOMAIN,
- self._DEF_ADDRESS, self._DEF_PORT, props)
- value = service.get_one_property(key)
- assert value and value == expected_value, "service properties weren't correct after init."
- value = service.get_one_property('bork')
- assert not value, "service properties weren't correct after init."
-
- def testBoolProperty(self):
- props = [[111, 114, 103, 46, 102, 114, 101, 101, 100, 101, 115, 107, 116, 111, 112, 46, 65, 118, 97, 104, 105, 46, 99, 111, 111, 107, 105, 101]]
- key = "org.freedesktop.Avahi.cookie"
- expected_value = True
- objid = _next_objid()
- service = Service(self._bus_name, objid, self._DEF_NAME, self._DEF_STYPE, self._DEF_DOMAIN, self._DEF_ADDRESS,
- self._DEF_PORT, props)
- value = service.get_one_property(key)
- assert value is not None and value == expected_value, "service properties weren't correct after init."
-
- def testActivityService(self):
- # Valid group service type, non-multicast address
- actid = "4569a71b80805aa96a847f7ac1c407327b3ec2b4"
- name = compose_service_name("Tommy", actid)
-
- # Valid activity service name, None address
- objid = _next_objid()
- service = Service(self._bus_name, objid, name, self._DEF_STYPE, self._DEF_DOMAIN, None,
- self._DEF_PORT, self._DEF_PROPS)
- assert service.get_address() == None, "address was not None as expected!"
- assert service.get_activity_id() == actid, "activity id was different than expected!"
-
- # Valid activity service name and multicast address, ensure it works
- mc_addr = u"224.0.0.34"
- objid = _next_objid()
- service = Service(self._bus_name, objid, name, self._DEF_STYPE, self._DEF_DOMAIN, mc_addr,
- self._DEF_PORT, self._DEF_PROPS)
- assert service.get_address() == mc_addr, "address was not expected address!"
-
- def addToSuite(suite):
- suite.addTest(ServiceTestCase("testName"))
- suite.addTest(ServiceTestCase("testType"))
- suite.addTest(ServiceTestCase("testDomain"))
- suite.addTest(ServiceTestCase("testAddress"))
- suite.addTest(ServiceTestCase("testPort"))
- suite.addTest(ServiceTestCase("testGoodInit"))
- suite.addTest(ServiceTestCase("testAvahiProperties"))
- suite.addTest(ServiceTestCase("testBoolProperty"))
- suite.addTest(ServiceTestCase("testActivityService"))
- addToSuite = staticmethod(addToSuite)
+ _DEF_NAME = u"foobar"
+ _DEF_STYPE = u"_foo._bar._tcp"
+ _DEF_DOMAIN = u"local"
+ _DEF_ADDRESS = u"1.1.1.1"
+ _DEF_PORT = 1234
+ _DEF_PROPS = {'foobar': 'baz'}
+ _STR_TEST_ARGS = [None, 0, [], {}]
+
+ def __init__(self, name):
+ self._bus = dbus.SessionBus()
+ self._bus_name = dbus.service.BusName('org.laptop.Presence', bus=self._bus)
+ unittest.TestCase.__init__(self, name)
+
+ def __del__(self):
+ del self._bus_name
+ del self._bus
+
+ def _test_init_fail(self, name, stype, domain, address, port, properties, fail_msg):
+ """Test something we expect to fail."""
+ try:
+ objid = _next_objid()
+ service = Service(self._bus_name, objid, name, stype, domain, address,
+ port, properties)
+ except ValueError, exc:
+ pass
+ else:
+ self.fail("expected a ValueError for %s." % fail_msg)
+
+ def testName(self):
+ for item in self._STR_TEST_ARGS:
+ self._test_init_fail(item, self._DEF_STYPE, self._DEF_DOMAIN, self._DEF_ADDRESS,
+ self._DEF_PORT, self._DEF_PROPS, "invalid name")
+
+ def testType(self):
+ for item in self._STR_TEST_ARGS:
+ self._test_init_fail(self._DEF_NAME, item, self._DEF_DOMAIN, self._DEF_ADDRESS,
+ self._DEF_PORT, self._DEF_PROPS, "invalid service type")
+ self._test_init_fail(self._DEF_NAME, u"_bork._foobar", self._DEF_DOMAIN, self._DEF_ADDRESS,
+ self._DEF_PORT, self._DEF_PROPS, "invalid service type")
+
+ def testDomain(self):
+ for item in self._STR_TEST_ARGS:
+ self._test_init_fail(self._DEF_NAME, self._DEF_STYPE, item, self._DEF_ADDRESS,
+ self._DEF_PORT, self._DEF_PROPS, "invalid domain")
+ # Only accept local for now
+ self._test_init_fail(self._DEF_NAME, self._DEF_STYPE, u"foobar", self._DEF_ADDRESS,
+ self._DEF_PORT, self._DEF_PROPS, "invalid domain")
+ # Make sure "" works
+ objid = _next_objid()
+ service = Service(self._bus_name, objid, self._DEF_NAME, self._DEF_STYPE, u"",
+ self._DEF_ADDRESS, self._DEF_PORT, self._DEF_PROPS)
+ assert service, "Empty domain was not accepted!"
+
+ def testAddress(self):
+ self._test_init_fail(self._DEF_NAME, self._DEF_STYPE, self._DEF_DOMAIN, [],
+ self._DEF_PORT, self._DEF_PROPS, "invalid address")
+ self._test_init_fail(self._DEF_NAME, self._DEF_STYPE, self._DEF_DOMAIN, {},
+ self._DEF_PORT, self._DEF_PROPS, "invalid address")
+ self._test_init_fail(self._DEF_NAME, self._DEF_STYPE, self._DEF_DOMAIN, 1234,
+ self._DEF_PORT, self._DEF_PROPS, "invalid address")
+
+ def testPort(self):
+ self._test_init_fail(self._DEF_NAME, self._DEF_STYPE, self._DEF_DOMAIN, self._DEF_ADDRESS,
+ [], self._DEF_PROPS, "invalid port")
+ self._test_init_fail(self._DEF_NAME, self._DEF_STYPE, self._DEF_DOMAIN, self._DEF_ADDRESS,
+ {}, self._DEF_PROPS, "invalid port")
+ self._test_init_fail(self._DEF_NAME, self._DEF_STYPE, self._DEF_DOMAIN, self._DEF_ADDRESS,
+ "adf", self._DEF_PROPS, "invalid port")
+
+ def testGoodInit(self):
+ objid = _next_objid()
+ service = Service(self._bus_name, objid, self._DEF_NAME, self._DEF_STYPE, self._DEF_DOMAIN,
+ self._DEF_ADDRESS, self._DEF_PORT, self._DEF_PROPS)
+ assert service.get_name() == self._DEF_NAME, "service name wasn't correct after init."
+ assert service.get_type() == self._DEF_STYPE, "service type wasn't correct after init."
+ assert service.get_domain() == "local", "service domain wasn't correct after init."
+ assert service.get_address() == self._DEF_ADDRESS, "service address wasn't correct after init."
+ assert service.get_port() == self._DEF_PORT, "service port wasn't correct after init."
+ assert service.object_path() == SERVICE_DBUS_OBJECT_PATH + str(objid)
+ value = service.get_one_property('foobar')
+ assert value and value == 'baz', "service property wasn't correct after init."
+
+ def testAvahiProperties(self):
+ props = [[111, 114, 103, 46, 102, 114, 101, 101, 100, 101, 115, 107, 116, 111, 112, 46, 65, 118, 97, 104, 105, 46, 99, 111, 111, 107, 105, 101, 61, 50, 54, 48, 49, 53, 52, 51, 57, 53, 50]]
+ key = "org.freedesktop.Avahi.cookie"
+ expected_value = "2601543952"
+ objid = _next_objid()
+ service = Service(self._bus_name, objid, self._DEF_NAME, self._DEF_STYPE, self._DEF_DOMAIN,
+ self._DEF_ADDRESS, self._DEF_PORT, props)
+ value = service.get_one_property(key)
+ assert value and value == expected_value, "service properties weren't correct after init."
+ value = service.get_one_property('bork')
+ assert not value, "service properties weren't correct after init."
+
+ def testBoolProperty(self):
+ props = [[111, 114, 103, 46, 102, 114, 101, 101, 100, 101, 115, 107, 116, 111, 112, 46, 65, 118, 97, 104, 105, 46, 99, 111, 111, 107, 105, 101]]
+ key = "org.freedesktop.Avahi.cookie"
+ expected_value = True
+ objid = _next_objid()
+ service = Service(self._bus_name, objid, self._DEF_NAME, self._DEF_STYPE, self._DEF_DOMAIN, self._DEF_ADDRESS,
+ self._DEF_PORT, props)
+ value = service.get_one_property(key)
+ assert value is not None and value == expected_value, "service properties weren't correct after init."
+
+ def testActivityService(self):
+ # Valid group service type, non-multicast address
+ actid = "4569a71b80805aa96a847f7ac1c407327b3ec2b4"
+ name = compose_service_name("Tommy", actid)
+
+ # Valid activity service name, None address
+ objid = _next_objid()
+ service = Service(self._bus_name, objid, name, self._DEF_STYPE, self._DEF_DOMAIN, None,
+ self._DEF_PORT, self._DEF_PROPS)
+ assert service.get_address() == None, "address was not None as expected!"
+ assert service.get_activity_id() == actid, "activity id was different than expected!"
+
+ # Valid activity service name and multicast address, ensure it works
+ mc_addr = u"224.0.0.34"
+ objid = _next_objid()
+ service = Service(self._bus_name, objid, name, self._DEF_STYPE, self._DEF_DOMAIN, mc_addr,
+ self._DEF_PORT, self._DEF_PROPS)
+ assert service.get_address() == mc_addr, "address was not expected address!"
+
+ def addToSuite(suite):
+ suite.addTest(ServiceTestCase("testName"))
+ suite.addTest(ServiceTestCase("testType"))
+ suite.addTest(ServiceTestCase("testDomain"))
+ suite.addTest(ServiceTestCase("testAddress"))
+ suite.addTest(ServiceTestCase("testPort"))
+ suite.addTest(ServiceTestCase("testGoodInit"))
+ suite.addTest(ServiceTestCase("testAvahiProperties"))
+ suite.addTest(ServiceTestCase("testBoolProperty"))
+ suite.addTest(ServiceTestCase("testActivityService"))
+ addToSuite = staticmethod(addToSuite)
def main():
- suite = unittest.TestSuite()
- ServiceTestCase.addToSuite(suite)
- runner = unittest.TextTestRunner()
- runner.run(suite)
+ suite = unittest.TestSuite()
+ ServiceTestCase.addToSuite(suite)
+ runner = unittest.TextTestRunner()
+ runner.run(suite)
if __name__ == "__main__":
- main()
+ main()
diff --git a/shell/console/console.py b/shell/console/console.py
index 565b973..c105e85 100755
--- a/shell/console/console.py
+++ b/shell/console/console.py
@@ -27,7 +27,7 @@ logviewer_widget = logviewer.Interface().widget
logviewer_widget.show()
# Terminal interface
-terminal_widget = terminal.Interface().widget
+terminal_widget = terminal.Interface().widget
terminal_widget.show()
# Notebook
diff --git a/shell/console/logviewer.py b/shell/console/logviewer.py
index fb589a2..b93f05e 100644
--- a/shell/console/logviewer.py
+++ b/shell/console/logviewer.py
@@ -26,76 +26,76 @@ import gobject
from sugar import env
class LogBuffer(gtk.TextBuffer):
- def __init__(self, logfile):
- gtk.TextBuffer.__init__(self)
+ def __init__(self, logfile):
+ gtk.TextBuffer.__init__(self)
- self._logfile = logfile
- self._pos = 0
+ self._logfile = logfile
+ self._pos = 0
- self.update()
+ self.update()
- def update(self):
- f = open(self._logfile, 'r')
+ def update(self):
+ f = open(self._logfile, 'r')
- f.seek(self._pos)
- self.insert(self.get_end_iter(), f.read())
- self._pos = f.tell()
+ f.seek(self._pos)
+ self.insert(self.get_end_iter(), f.read())
+ self._pos = f.tell()
- f.close()
+ f.close()
- return True
+ return True
class LogView(gtk.ScrolledWindow):
- def __init__(self, model):
- gtk.ScrolledWindow.__init__(self)
+ def __init__(self, model):
+ gtk.ScrolledWindow.__init__(self)
- self.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+ self.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
- textview = gtk.TextView(model)
- textview.set_wrap_mode(gtk.WRAP_WORD)
- textview.set_editable(False)
+ textview = gtk.TextView(model)
+ textview.set_wrap_mode(gtk.WRAP_WORD)
+ textview.set_editable(False)
- self.add(textview)
- textview.show()
+ self.add(textview)
+ textview.show()
class MultiLogView(gtk.Notebook):
- def __init__(self, path):
- gtk.Notebook.__init__(self)
+ def __init__(self, path):
+ gtk.Notebook.__init__(self)
- self._logs_path = path
- self._pages = {}
+ self._logs_path = path
+ self._pages = {}
- self._update()
+ self._update()
- gobject.timeout_add(1000, self._update)
+ gobject.timeout_add(1000, self._update)
- def _add_page(self, logfile):
- full_log_path = os.path.join(self._logs_path, logfile)
- model = LogBuffer(full_log_path)
+ def _add_page(self, logfile):
+ full_log_path = os.path.join(self._logs_path, logfile)
+ model = LogBuffer(full_log_path)
- view = LogView(model)
- self.append_page(view, gtk.Label(logfile))
- view.show()
+ view = LogView(model)
+ self.append_page(view, gtk.Label(logfile))
+ view.show()
- self._pages[logfile] = model
+ self._pages[logfile] = model
- def _update(self):
- if not os.path.isdir(self._logs_path):
- return True
+ def _update(self):
+ if not os.path.isdir(self._logs_path):
+ return True
- for logfile in os.listdir(self._logs_path):
- if self._pages.has_key(logfile):
- self._pages[logfile].update()
- else:
- self._add_page(logfile)
+ for logfile in os.listdir(self._logs_path):
+ if self._pages.has_key(logfile):
+ self._pages[logfile].update()
+ else:
+ self._add_page(logfile)
- return True
+ return True
class Interface:
- def __init__(self):
- path = os.path.join(env.get_profile_path(), 'logs')
- viewer = MultiLogView(path)
- viewer.show()
- self.widget = viewer
- \ No newline at end of file
+ def __init__(self):
+ path = os.path.join(env.get_profile_path(), 'logs')
+ viewer = MultiLogView(path)
+ viewer.show()
+ self.widget = viewer
+ \ No newline at end of file
diff --git a/shell/console/memphis.py b/shell/console/memphis.py
index 4513987..5e4e8a2 100644
--- a/shell/console/memphis.py
+++ b/shell/console/memphis.py
@@ -8,175 +8,175 @@ import plugin
from procmem import proc
try:
- import gtk
- import gtk.gdk
- import gobject
+ import gtk
+ import gtk.gdk
+ import gobject
except:
- sys.exit(1)
+ sys.exit(1)
class Interface:
-
- store_data_types = []
- store_data_types_details = []
-
- def __init__(self):
-
- # Our GtkTree (Treeview)
- self.treeview = gtk.TreeView()
- self.widget = self.treeview
-
- # Loading plugins
- self.plg = plugin.Plugin()
-
- # TOP data types (columns)
- self.store_data_types = []
-
- for plg in self.plg.list:
- plg_data = plg.INTERNALS
-
- # Give plugin object to plugin
- plg.INTERNALS['Plg'] = self.plg
-
- # Creating a store model and loading process data to Treeview
- # self.store_data_types, ex [int, str, str, str, int,...]
- #self.store = gtk.TreeStore(*self.store_data_types)
- self.data = Data(self.treeview, self.plg.list)
-
+
+ store_data_types = []
+ store_data_types_details = []
+
+ def __init__(self):
+
+ # Our GtkTree (Treeview)
+ self.treeview = gtk.TreeView()
+ self.widget = self.treeview
+
+ # Loading plugins
+ self.plg = plugin.Plugin()
+
+ # TOP data types (columns)
+ self.store_data_types = []
+
+ for plg in self.plg.list:
+ plg_data = plg.INTERNALS
+
+ # Give plugin object to plugin
+ plg.INTERNALS['Plg'] = self.plg
+
+ # Creating a store model and loading process data to Treeview
+ # self.store_data_types, ex [int, str, str, str, int,...]
+ #self.store = gtk.TreeStore(*self.store_data_types)
+ self.data = Data(self.treeview, self.plg.list)
+
class Data:
- treeview = None
- last_col_index = 0
-
- store_data_cols = []
- store_data_types = []
- store_data_types_details = []
-
- def __init__(self, treeview, plg_list):
-
- # Top data types
- self.plg_list = plg_list
-
- for plg in self.plg_list:
-
- if plg.INTERNALS['top_data'] != None:
- last_dt = len(self.store_data_types)
-
- if last_dt > 0:
- last_dt -= 1
-
- len_dt = len(plg.INTERNALS['top_data'])
-
- self.store_data_types_details.append({"plugin": plg, "init": last_dt, "end": last_dt + len_dt})
-
- for dt in plg.INTERNALS['top_data']:
- self.store_data_types.append(dt)
-
- for col in plg.INTERNALS['top_cols']:
- self.store_data_cols.append(col)
-
- # Set global treeview
- self.treeview = treeview
-
- # Basic columns
- index = 0
- for column_name in self.store_data_cols:
- self.add_column(column_name, index)
- index += 1
-
- self.store = gtk.TreeStore(*self.store_data_types)
- treeview.set_model(self.store)
-
- # Update information every 1 second
- gobject.timeout_add(500, self.load_data, treeview)
-
- # Add a new column to the main treeview
- def add_column(self, column_name, index):
- cell = gtk.CellRendererText()
- col_tv = gtk.TreeViewColumn(column_name, cell, text=index)
- col_tv.set_resizable(True)
- col_tv.connect('clicked', self.sort_column_clicked)
- col_tv.set_property('clickable', True)
-
- self.treeview.append_column(col_tv)
-
- # Set the last column index added
- self.last_col_index = index
-
- # Sorting
- def sort_column_clicked(self, TreeViewColumn):
- cols = self.treeview.get_columns()
-
- # Searching column index
- index = 0
- for col in cols:
- if col == TreeViewColumn:
- break
-
- index += 1
-
- self.store.set_sort_column_id(index, gtk.SORT_DESCENDING)
-
- def load_data(self, treeview):
- self.store.clear()
-
- # Getting procfs data
- self.procdata = proc.ProcInfo()
- self.process_list = []
-
- pids = []
- screen = wnck.screen_get_default()
- windows = screen.get_windows()
-
- current_pid = os.getpid()
-
- for win in windows:
- pid = int(win.get_pid())
- if current_pid != pid:
- pids.append(pid)
-
- self.process_list = set(pids)
-
- # Sort rows using pid
- #self.process_list.sort(key=operator.itemgetter('pid'))
- self.process_iter = []
-
- for pid in self.process_list:
- pi = self.build_row(self.store, None, self.procdata, pid)
- self.process_iter.append(pi)
-
- treeview.set_rules_hint(True)
- treeview.expand_all()
-
- return True
-
- def build_row(self, store, parent_iter, proc_data, pid):
- data = []
-
- pinfo = proc_data.MemoryInfo(pid)
-
- # Look for plugins that need to update the top data treeview
- for plg in self.plg_list:
- plg_data = []
-
- if plg.INTERNALS['top_data'] != None:
- # data = [xxx, yyy,zzz,...]
- plg_data = plg.info.plg_on_top_data_refresh(plg, pinfo)
-
- for field in plg_data:
- data.append(field)
-
- pi = self.insert_row(store, parent_iter, data)
-
- return pi
-
- # Insert a Row in our TreeView
- def insert_row(self, store, parent, row_data):
- iter = store.insert_after(parent, None)
-
- index = 0
-
- for data in row_data:
- store.set_value(iter, index , data)
- index += 1
-
- return iter
+ treeview = None
+ last_col_index = 0
+
+ store_data_cols = []
+ store_data_types = []
+ store_data_types_details = []
+
+ def __init__(self, treeview, plg_list):
+
+ # Top data types
+ self.plg_list = plg_list
+
+ for plg in self.plg_list:
+
+ if plg.INTERNALS['top_data'] != None:
+ last_dt = len(self.store_data_types)
+
+ if last_dt > 0:
+ last_dt -= 1
+
+ len_dt = len(plg.INTERNALS['top_data'])
+
+ self.store_data_types_details.append({"plugin": plg, "init": last_dt, "end": last_dt + len_dt})
+
+ for dt in plg.INTERNALS['top_data']:
+ self.store_data_types.append(dt)
+
+ for col in plg.INTERNALS['top_cols']:
+ self.store_data_cols.append(col)
+
+ # Set global treeview
+ self.treeview = treeview
+
+ # Basic columns
+ index = 0
+ for column_name in self.store_data_cols:
+ self.add_column(column_name, index)
+ index += 1
+
+ self.store = gtk.TreeStore(*self.store_data_types)
+ treeview.set_model(self.store)
+
+ # Update information every 1 second
+ gobject.timeout_add(500, self.load_data, treeview)
+
+ # Add a new column to the main treeview
+ def add_column(self, column_name, index):
+ cell = gtk.CellRendererText()
+ col_tv = gtk.TreeViewColumn(column_name, cell, text=index)
+ col_tv.set_resizable(True)
+ col_tv.connect('clicked', self.sort_column_clicked)
+ col_tv.set_property('clickable', True)
+
+ self.treeview.append_column(col_tv)
+
+ # Set the last column index added
+ self.last_col_index = index
+
+ # Sorting
+ def sort_column_clicked(self, TreeViewColumn):
+ cols = self.treeview.get_columns()
+
+ # Searching column index
+ index = 0
+ for col in cols:
+ if col == TreeViewColumn:
+ break
+
+ index += 1
+
+ self.store.set_sort_column_id(index, gtk.SORT_DESCENDING)
+
+ def load_data(self, treeview):
+ self.store.clear()
+
+ # Getting procfs data
+ self.procdata = proc.ProcInfo()
+ self.process_list = []
+
+ pids = []
+ screen = wnck.screen_get_default()
+ windows = screen.get_windows()
+
+ current_pid = os.getpid()
+
+ for win in windows:
+ pid = int(win.get_pid())
+ if current_pid != pid:
+ pids.append(pid)
+
+ self.process_list = set(pids)
+
+ # Sort rows using pid
+ #self.process_list.sort(key=operator.itemgetter('pid'))
+ self.process_iter = []
+
+ for pid in self.process_list:
+ pi = self.build_row(self.store, None, self.procdata, pid)
+ self.process_iter.append(pi)
+
+ treeview.set_rules_hint(True)
+ treeview.expand_all()
+
+ return True
+
+ def build_row(self, store, parent_iter, proc_data, pid):
+ data = []
+
+ pinfo = proc_data.MemoryInfo(pid)
+
+ # Look for plugins that need to update the top data treeview
+ for plg in self.plg_list:
+ plg_data = []
+
+ if plg.INTERNALS['top_data'] != None:
+ # data = [xxx, yyy,zzz,...]
+ plg_data = plg.info.plg_on_top_data_refresh(plg, pinfo)
+
+ for field in plg_data:
+ data.append(field)
+
+ pi = self.insert_row(store, parent_iter, data)
+
+ return pi
+
+ # Insert a Row in our TreeView
+ def insert_row(self, store, parent, row_data):
+ iter = store.insert_after(parent, None)
+
+ index = 0
+
+ for data in row_data:
+ store.set_value(iter, index , data)
+ index += 1
+
+ return iter
diff --git a/shell/console/plugin.py b/shell/console/plugin.py
index 5ad5ba2..62ed947 100755
--- a/shell/console/plugin.py
+++ b/shell/console/plugin.py
@@ -9,42 +9,42 @@ from procmem import proc, proc_smaps, analysis
class Plugin:
- # Plugin list
- list = []
- proc = proc.ProcInfo()
-
- internal_plugin = "memphis_init"
- plg_path = os.path.dirname(os.path.abspath(__file__)) + "/plugins"
-
- # Frequency timer, managed by main program
- freq_timer = 0
-
- def __init__(self):
-
- sys.path.insert(0, self.plg_path)
-
- # Including memphis plugin
- self.list.append(__import__(self.internal_plugin))
-
- if os.path.isdir(self.plg_path):
- # around dir entries
- for plg in os.listdir(self.plg_path):
-
- if plg == self.internal_plugin:
- continue
-
- if os.path.isdir(self.plg_path + "/" + plg):
- p = __import__(plg)
- self.list.append(__import__(plg))
-
- # Parse /proc/PID/smaps information
- def proc_get_smaps(self, pid):
- return proc_smaps.ProcSmaps(pid)
-
- # Parse /proc/PID/maps information
- def proc_get_maps(self, pid):
- return proc_smaps.ProcMaps(pid)
+ # Plugin list
+ list = []
+ proc = proc.ProcInfo()
+
+ internal_plugin = "memphis_init"
+ plg_path = os.path.dirname(os.path.abspath(__file__)) + "/plugins"
+
+ # Frequency timer, managed by main program
+ freq_timer = 0
+
+ def __init__(self):
+
+ sys.path.insert(0, self.plg_path)
+
+ # Including memphis plugin
+ self.list.append(__import__(self.internal_plugin))
+
+ if os.path.isdir(self.plg_path):
+ # around dir entries
+ for plg in os.listdir(self.plg_path):
+
+ if plg == self.internal_plugin:
+ continue
+
+ if os.path.isdir(self.plg_path + "/" + plg):
+ p = __import__(plg)
+ self.list.append(__import__(plg))
+
+ # Parse /proc/PID/smaps information
+ def proc_get_smaps(self, pid):
+ return proc_smaps.ProcSmaps(pid)
+
+ # Parse /proc/PID/maps information
+ def proc_get_maps(self, pid):
+ return proc_smaps.ProcMaps(pid)
- def proc_analysis(self, pid):
- return analysis.Analysis(pid)
- \ No newline at end of file
+ def proc_analysis(self, pid):
+ return analysis.Analysis(pid)
+ \ No newline at end of file
diff --git a/shell/console/plugins/clean_size/__init__.py b/shell/console/plugins/clean_size/__init__.py
index fed740c..75ce1d1 100644
--- a/shell/console/plugins/clean_size/__init__.py
+++ b/shell/console/plugins/clean_size/__init__.py
@@ -2,15 +2,15 @@
import info
INTERNALS = {
- # Basic information
- 'PLGNAME': "Clean Size",
- 'TABNAME': None,
- 'AUTHOR': "Eduardo Silva",
- 'DESC': "Print the approx real memory usage",
+ # Basic information
+ 'PLGNAME': "Clean Size",
+ 'TABNAME': None,
+ 'AUTHOR': "Eduardo Silva",
+ 'DESC': "Print the approx real memory usage",
- # Plugin API
- 'Plg': None, # Plugin object
+ # Plugin API
+ 'Plg': None, # Plugin object
- 'top_data': [int], # Top data types needed by memphis core plugin
- 'top_cols': ["Approx Real Usage (kb)"]
- }
+ 'top_data': [int], # Top data types needed by memphis core plugin
+ 'top_cols': ["Approx Real Usage (kb)"]
+ }
diff --git a/shell/console/plugins/clean_size/info.py b/shell/console/plugins/clean_size/info.py
index e223ea5..25ed044 100644
--- a/shell/console/plugins/clean_size/info.py
+++ b/shell/console/plugins/clean_size/info.py
@@ -7,9 +7,9 @@
############################################################
def plg_on_top_data_refresh(self, pinfo):
-
- # Get clean size
- maps = self.INTERNALS['Plg'].proc_get_maps(pinfo['pid'])
+
+ # Get clean size
+ maps = self.INTERNALS['Plg'].proc_get_maps(pinfo['pid'])
- size = (maps.clean_size/1024)
- return [size]
+ size = (maps.clean_size/1024)
+ return [size]
diff --git a/shell/console/plugins/cpu/__init__.py b/shell/console/plugins/cpu/__init__.py
index 3ec6135..e22a413 100644
--- a/shell/console/plugins/cpu/__init__.py
+++ b/shell/console/plugins/cpu/__init__.py
@@ -2,20 +2,20 @@ import os
import info
INTERNALS = {
- 'PLGNAME': "cpu",
- 'TABNAME': None,
- 'AUTHOR': "Eduardo Silva",
- 'DESC': "Print CPU usage",
+ 'PLGNAME': "cpu",
+ 'TABNAME': None,
+ 'AUTHOR': "Eduardo Silva",
+ 'DESC': "Print CPU usage",
- # Plugin API
- 'Plg': None, # Plugin object
- 'current_plg': None, # Current plugin object
- 'current_page': None, # Current page number
+ # Plugin API
+ 'Plg': None, # Plugin object
+ 'current_plg': None, # Current plugin object
+ 'current_page': None, # Current page number
- # Top process view requirements
- 'top_data': [int], # Top data types needed by memphis core plugin
- 'top_cols': ["%CPU "] # Column names
- }
+ # Top process view requirements
+ 'top_data': [int], # Top data types needed by memphis core plugin
+ 'top_cols': ["%CPU "] # Column names
+ }
# Get CPU frequency
cpu_hz = os.sysconf(2)
diff --git a/shell/console/plugins/cpu/info.py b/shell/console/plugins/cpu/info.py
index b8b715e..9cb1ad4 100644
--- a/shell/console/plugins/cpu/info.py
+++ b/shell/console/plugins/cpu/info.py
@@ -7,42 +7,42 @@
############################################################
def plg_on_top_data_refresh(self, pinfo):
- PI = self.INTERNALS['Plg'].proc
-
- pid = pinfo['pid']
-
- # Get JIFFIES CPU usage
- used_jiffies = pinfo['utime'] + pinfo['stime']
- last_ujiffies = get_pid_ujiffies(self, pid)
-
- cpu_usage = PI.get_CPU_usage(self.cpu_hz, used_jiffies, pinfo['start_time'])
+ PI = self.INTERNALS['Plg'].proc
+
+ pid = pinfo['pid']
+
+ # Get JIFFIES CPU usage
+ used_jiffies = pinfo['utime'] + pinfo['stime']
+ last_ujiffies = get_pid_ujiffies(self, pid)
+
+ cpu_usage = PI.get_CPU_usage(self.cpu_hz, used_jiffies, pinfo['start_time'])
- # Get PERCENT CPU usage
- if last_ujiffies == 0.0:
- pcpu = 0.0
- set_pid_ujiffies(self, pid, cpu_usage['used_jiffies'])
- data = [int(pcpu)]
- return data
-
- used_jiffies = cpu_usage['used_jiffies'] - last_ujiffies
+ # Get PERCENT CPU usage
+ if last_ujiffies == 0.0:
+ pcpu = 0.0
+ set_pid_ujiffies(self, pid, cpu_usage['used_jiffies'])
+ data = [int(pcpu)]
+ return data
+
+ used_jiffies = cpu_usage['used_jiffies'] - last_ujiffies
- # Available jiffies are
- avail_jiffies = (500/1000.0)*self.cpu_hz # 500 = 0.5 second
- pcpu = ((used_jiffies*100)/avail_jiffies)
-
- set_pid_ujiffies(self, pid, cpu_usage['used_jiffies'])
-
- data = [int(pcpu)]
- return data
+ # Available jiffies are
+ avail_jiffies = (500/1000.0)*self.cpu_hz # 500 = 0.5 second
+ pcpu = ((used_jiffies*100)/avail_jiffies)
+
+ set_pid_ujiffies(self, pid, cpu_usage['used_jiffies'])
+
+ data = [int(pcpu)]
+ return data
def get_pid_ujiffies(self, pid):
-
- if pid in self.pids_ujiffies:
- return self.pids_ujiffies[pid]
- else:
- set_pid_ujiffies(self, pid, 0)
- return self.pids_ujiffies[pid]
+
+ if pid in self.pids_ujiffies:
+ return self.pids_ujiffies[pid]
+ else:
+ set_pid_ujiffies(self, pid, 0)
+ return self.pids_ujiffies[pid]
def set_pid_ujiffies(self, pid, ujiffies):
- self.pids_ujiffies[pid] = ujiffies
+ self.pids_ujiffies[pid] = ujiffies
diff --git a/shell/console/plugins/dirty_size/__init__.py b/shell/console/plugins/dirty_size/__init__.py
index 2661db8..f8e9e0a 100644
--- a/shell/console/plugins/dirty_size/__init__.py
+++ b/shell/console/plugins/dirty_size/__init__.py
@@ -3,15 +3,15 @@ import info
INTERNALS = {
- # Basic information
- 'PLGNAME': "Dirty Size",
- 'TABNAME': None, # No tabbed plugin
- 'AUTHOR': "Eduardo Silva",
- 'DESC': "Get dirty size memory usage",
+ # Basic information
+ 'PLGNAME': "Dirty Size",
+ 'TABNAME': None, # No tabbed plugin
+ 'AUTHOR': "Eduardo Silva",
+ 'DESC': "Get dirty size memory usage",
- # Plugin API
- 'Plg': None, # Plugin object
+ # Plugin API
+ 'Plg': None, # Plugin object
- 'top_data': [int], # Top data types needed by memphis core plugin
- 'top_cols': ["PDRSS (kb)"]
- }
+ 'top_data': [int], # Top data types needed by memphis core plugin
+ 'top_cols': ["PDRSS (kb)"]
+ }
diff --git a/shell/console/plugins/dirty_size/info.py b/shell/console/plugins/dirty_size/info.py
index 631d86a..54a2e7e 100644
--- a/shell/console/plugins/dirty_size/info.py
+++ b/shell/console/plugins/dirty_size/info.py
@@ -9,12 +9,12 @@
def plg_on_top_data_refresh(self, ppinfo):
- dirty_sizes = get_dirty(self, ppinfo['pid'])
-
- # memhis need an array
- return [dirty_sizes['private']]
+ dirty_sizes = get_dirty(self, ppinfo['pid'])
+
+ # memhis need an array
+ return [dirty_sizes['private']]
def get_dirty(pself, pid):
- ProcAnalysis = pself.INTERNALS['Plg'].proc_analysis(pid)
+ ProcAnalysis = pself.INTERNALS['Plg'].proc_analysis(pid)
- return ProcAnalysis.DirtyRSS()
+ return ProcAnalysis.DirtyRSS()
diff --git a/shell/console/plugins/memphis_init/__init__.py b/shell/console/plugins/memphis_init/__init__.py
index c13ce2e..f5ada7e 100644
--- a/shell/console/plugins/memphis_init/__init__.py
+++ b/shell/console/plugins/memphis_init/__init__.py
@@ -1,15 +1,15 @@
import info
INTERNALS = {
- 'PLGNAME': "memphis",
- 'TABNAME': None,
- 'AUTHOR': "Eduardo Silva",
- 'DESC': "Print basic process information",
+ 'PLGNAME': "memphis",
+ 'TABNAME': None,
+ 'AUTHOR': "Eduardo Silva",
+ 'DESC': "Print basic process information",
- # Plugin API
- 'Plg': None, # Plugin object
+ # Plugin API
+ 'Plg': None, # Plugin object
- # Top process view requirements
- 'top_data': [int, str, str], # Top data types needed by memphis core plugin
- 'top_cols': ["PID", "Process Name", "Status"] # Column names
- }
+ # Top process view requirements
+ 'top_data': [int, str, str], # Top data types needed by memphis core plugin
+ 'top_cols': ["PID", "Process Name", "Status"] # Column names
+ }
diff --git a/shell/console/plugins/memphis_init/info.py b/shell/console/plugins/memphis_init/info.py
index 94d2d43..6e524c7 100644
--- a/shell/console/plugins/memphis_init/info.py
+++ b/shell/console/plugins/memphis_init/info.py
@@ -8,6 +8,6 @@
def plg_on_top_data_refresh(self, ppinfo):
- data = [ppinfo['pid'], ppinfo['name'], ppinfo['state_name']]
-
- return data
+ data = [ppinfo['pid'], ppinfo['name'], ppinfo['state_name']]
+
+ return data
diff --git a/shell/console/procmem/analysis.py b/shell/console/procmem/analysis.py
index a468acd..d2a247a 100644
--- a/shell/console/procmem/analysis.py
+++ b/shell/console/procmem/analysis.py
@@ -1,30 +1,30 @@
import proc, proc_smaps
class Analysis:
-
- pid = 0
-
- def __init__(self, pid):
- self.pid = pid
-
- def DirtyRSS(self):
- smaps = proc_smaps.ProcSmaps(self.pid)
- dirty = []
+
+ pid = 0
+
+ def __init__(self, pid):
+ self.pid = pid
+
+ def DirtyRSS(self):
+ smaps = proc_smaps.ProcSmaps(self.pid)
+ dirty = []
- private = 0
- shared = 0
-
- for map in smaps.mappings:
- private += map.private_dirty
- shared += map.shared_dirty
+ private = 0
+ shared = 0
+
+ for map in smaps.mappings:
+ private += map.private_dirty
+ shared += map.shared_dirty
- dirty = {"private": int(private), "shared": int(shared)}
+ dirty = {"private": int(private), "shared": int(shared)}
- return dirty
-
- def ApproxRealMemoryUsage(self):
- maps = proc_smaps.ProcMaps(self.pid)
- size = (maps.clean_size/1024)
+ return dirty
+
+ def ApproxRealMemoryUsage(self):
+ maps = proc_smaps.ProcMaps(self.pid)
+ size = (maps.clean_size/1024)
- return size
- \ No newline at end of file
+ return size
+ \ No newline at end of file
diff --git a/shell/console/procmem/proc.py b/shell/console/procmem/proc.py
index af0a656..729aa13 100644
--- a/shell/console/procmem/proc.py
+++ b/shell/console/procmem/proc.py
@@ -5,96 +5,96 @@ import string
class ProcInfo:
- dir_path = "/proc/" # Our cute Proc File System
- status_file = "status"
- stat_file = "stat"
-
- proc_list = [] # Our PID list :D
- proc_info = [] #
-
- def __init__(self):
- self.proc_list = self.Get_PID_List()
-
- # Returns Process List
- def Get_PID_List(self):
- list = []
-
- # Exists our procfs ?
- if os.path.isdir(self.dir_path):
- # around dir entries
- for f in os.listdir(self.dir_path):
- if os.path.isdir(self.dir_path+f) & str.isdigit(f):
- list.append(int(f))
+ dir_path = "/proc/" # Our cute Proc File System
+ status_file = "status"
+ stat_file = "stat"
+
+ proc_list = [] # Our PID list :D
+ proc_info = [] #
+
+ def __init__(self):
+ self.proc_list = self.Get_PID_List()
+
+ # Returns Process List
+ def Get_PID_List(self):
+ list = []
+
+ # Exists our procfs ?
+ if os.path.isdir(self.dir_path):
+ # around dir entries
+ for f in os.listdir(self.dir_path):
+ if os.path.isdir(self.dir_path+f) & str.isdigit(f):
+ list.append(int(f))
- return list
-
- def MemoryInfo(self, pid):
- # Path
- pidfile = self.dir_path + str(pid) + "/stat"
- try:
- infile = open(pidfile, "r")
- except:
- print "Error trying " + pidfile
- return None
+ return list
+
+ def MemoryInfo(self, pid):
+ # Path
+ pidfile = self.dir_path + str(pid) + "/stat"
+ try:
+ infile = open(pidfile, "r")
+ except:
+ print "Error trying " + pidfile
+ return None
- # Parsing data , check 'man 5 proc' for details
- data = infile.read().split()
+ # Parsing data , check 'man 5 proc' for details
+ data = infile.read().split()
- infile.close()
-
- state_dic = {
- 'R': 'Running',
- 'S': 'Sleeping',
- 'D': 'Disk sleep',
- 'Z': 'Zombie',
- 'T': 'Traced/Stopped',
- 'W': 'Paging'
- }
+ infile.close()
+
+ state_dic = {
+ 'R': 'Running',
+ 'S': 'Sleeping',
+ 'D': 'Disk sleep',
+ 'Z': 'Zombie',
+ 'T': 'Traced/Stopped',
+ 'W': 'Paging'
+ }
- # user and group owners
- pidstat = os.stat(pidfile)
-
- info = {
- 'pid': int(data[0]), # Process ID
- 'name': data[1].strip('()'), # Process name
- 'state': data[2], # Process State, ex: R|S|D|Z|T|W
- 'state_name': state_dic[data[2]], # Process State name, ex: Running, sleeping, Zombie, etc
- 'ppid': int(data[3]), # Parent process ID
- 'utime': int(data[13]), # Used jiffies in user mode
- 'stime': int(data[14]), # Used jiffies in kernel mode
- 'start_time': int(data[21]), # Process time from system boot (jiffies)
- 'vsize': int(data[22]), # Virtual memory size used (bytes)
- 'rss': int(data[23])*4, # Resident Set Size (bytes)
- 'user_id': pidstat.st_uid, # process owner
- 'group_id': pidstat.st_gid # owner group
- }
-
- return info
-
+ # user and group owners
+ pidstat = os.stat(pidfile)
+
+ info = {
+ 'pid': int(data[0]), # Process ID
+ 'name': data[1].strip('()'), # Process name
+ 'state': data[2], # Process State, ex: R|S|D|Z|T|W
+ 'state_name': state_dic[data[2]], # Process State name, ex: Running, sleeping, Zombie, etc
+ 'ppid': int(data[3]), # Parent process ID
+ 'utime': int(data[13]), # Used jiffies in user mode
+ 'stime': int(data[14]), # Used jiffies in kernel mode
+ 'start_time': int(data[21]), # Process time from system boot (jiffies)
+ 'vsize': int(data[22]), # Virtual memory size used (bytes)
+ 'rss': int(data[23])*4, # Resident Set Size (bytes)
+ 'user_id': pidstat.st_uid, # process owner
+ 'group_id': pidstat.st_gid # owner group
+ }
+
+ return info
+
- # Returns the CPU usage expressed in Jiffies
- def get_CPU_usage(self, cpu_hz, used_jiffies, start_time):
-
- # Uptime info
- uptime_file = self.dir_path + "/uptime"
- try:
- infile = file(uptime_file, "r")
- except:
- print "Error trying uptime file"
- return None
-
- uptime_line = infile.readline()
- uptime = string.split(uptime_line, " ",2)
-
- infile.close()
-
- # System uptime, from /proc/uptime
- uptime = float(uptime[0])
-
- # Jiffies
- avail_jiffies = (uptime * cpu_hz) - start_time
-
- cpu_usage = {'used_jiffies': used_jiffies, 'avail_jiffies': avail_jiffies}
+ # Returns the CPU usage expressed in Jiffies
+ def get_CPU_usage(self, cpu_hz, used_jiffies, start_time):
+
+ # Uptime info
+ uptime_file = self.dir_path + "/uptime"
+ try:
+ infile = file(uptime_file, "r")
+ except:
+ print "Error trying uptime file"
+ return None
+
+ uptime_line = infile.readline()
+ uptime = string.split(uptime_line, " ",2)
+
+ infile.close()
+
+ # System uptime, from /proc/uptime
+ uptime = float(uptime[0])
+
+ # Jiffies
+ avail_jiffies = (uptime * cpu_hz) - start_time
+
+ cpu_usage = {'used_jiffies': used_jiffies, 'avail_jiffies': avail_jiffies}
- return cpu_usage
+ return cpu_usage
diff --git a/shell/console/procmem/proc_smaps.py b/shell/console/procmem/proc_smaps.py
index 84bef43..9416c52 100644
--- a/shell/console/procmem/proc_smaps.py
+++ b/shell/console/procmem/proc_smaps.py
@@ -9,121 +9,121 @@ import os
# Parse the /proc/PID/smaps file
class ProcSmaps:
- mappings = [] # Devices information
-
- def __init__(self, pid):
-
- smapfile = "/proc/%s/smaps" % pid
- self.mappings = []
-
- # Coded by Federico Mena (script)
- try:
- infile = open(smapfile, "r")
- input = infile.read()
- infile.close()
- except:
- print "Error trying " + smapfile
- return
-
- lines = input.splitlines()
+ mappings = [] # Devices information
+
+ def __init__(self, pid):
+
+ smapfile = "/proc/%s/smaps" % pid
+ self.mappings = []
+
+ # Coded by Federico Mena (script)
+ try:
+ infile = open(smapfile, "r")
+ input = infile.read()
+ infile.close()
+ except:
+ print "Error trying " + smapfile
+ return
+
+ lines = input.splitlines()
- num_lines = len (lines)
- line_idx = 0
-
- # 08065000-08067000 rw-p 0001c000 03:01 147613 /opt/gnome/bin/evolution-2.6
- # Size: 8 kB
- # Rss: 8 kB
- # Shared_Clean: 0 kB
- # Shared_Dirty: 0 kB
- # Private_Clean: 8 kB
- # Private_Dirty: 0 kB
-
- while num_lines > 0:
- fields = lines[line_idx].split (" ", 5)
- if len (fields) == 6:
- (offsets, permissions, bin_permissions, device, inode, name) = fields
- else:
- (offsets, permissions, bin_permissions, device, inode) = fields
- name = ""
-
- size = self.parse_smaps_size_line (lines[line_idx + 1])
- rss = self.parse_smaps_size_line (lines[line_idx + 2])
- shared_clean = self.parse_smaps_size_line (lines[line_idx + 3])
- shared_dirty = self.parse_smaps_size_line (lines[line_idx + 4])
- private_clean = self.parse_smaps_size_line (lines[line_idx + 5])
- private_dirty = self.parse_smaps_size_line (lines[line_idx + 6])
- name = name.strip ()
+ num_lines = len (lines)
+ line_idx = 0
+
+ # 08065000-08067000 rw-p 0001c000 03:01 147613 /opt/gnome/bin/evolution-2.6
+ # Size: 8 kB
+ # Rss: 8 kB
+ # Shared_Clean: 0 kB
+ # Shared_Dirty: 0 kB
+ # Private_Clean: 8 kB
+ # Private_Dirty: 0 kB
+
+ while num_lines > 0:
+ fields = lines[line_idx].split (" ", 5)
+ if len (fields) == 6:
+ (offsets, permissions, bin_permissions, device, inode, name) = fields
+ else:
+ (offsets, permissions, bin_permissions, device, inode) = fields
+ name = ""
+
+ size = self.parse_smaps_size_line (lines[line_idx + 1])
+ rss = self.parse_smaps_size_line (lines[line_idx + 2])
+ shared_clean = self.parse_smaps_size_line (lines[line_idx + 3])
+ shared_dirty = self.parse_smaps_size_line (lines[line_idx + 4])
+ private_clean = self.parse_smaps_size_line (lines[line_idx + 5])
+ private_dirty = self.parse_smaps_size_line (lines[line_idx + 6])
+ name = name.strip ()
- mapping = Mapping (size, rss, shared_clean, shared_dirty, private_clean, private_dirty, permissions, name)
- self.mappings.append (mapping)
+ mapping = Mapping (size, rss, shared_clean, shared_dirty, private_clean, private_dirty, permissions, name)
+ self.mappings.append (mapping)
- num_lines -= 7
- line_idx += 7
+ num_lines -= 7
+ line_idx += 7
- # Parses a line of the form "foo: 42 kB" and returns an integer for the "42" field
- def parse_smaps_size_line (self, line):
- # Rss: 8 kB
- fields = line.split ()
- return int(fields[1])
+ # Parses a line of the form "foo: 42 kB" and returns an integer for the "42" field
+ def parse_smaps_size_line (self, line):
+ # Rss: 8 kB
+ fields = line.split ()
+ return int(fields[1])
class Mapping:
- def __init__ (self, size, rss, shared_clean, shared_dirty, private_clean, private_dirty, permissions, name):
- self.size = size
- self.rss = rss
- self.shared_clean = shared_clean
- self.shared_dirty = shared_dirty
- self.private_clean = private_clean
- self.private_dirty = private_dirty
- self.permissions = permissions
- self.name = name
+ def __init__ (self, size, rss, shared_clean, shared_dirty, private_clean, private_dirty, permissions, name):
+ self.size = size
+ self.rss = rss
+ self.shared_clean = shared_clean
+ self.shared_dirty = shared_dirty
+ self.private_clean = private_clean
+ self.private_dirty = private_dirty
+ self.permissions = permissions
+ self.name = name
# Parse /proc/PID/maps file to get the clean memory usage by process,
# we avoid lines with backed-files
class ProcMaps:
-
- clean_size = 0
-
- def __init__(self, pid):
- mapfile = "/proc/%s/maps" % pid
+
+ clean_size = 0
+
+ def __init__(self, pid):
+ mapfile = "/proc/%s/maps" % pid
- try:
- infile = open(mapfile, "r")
- except:
- print "Error trying " + mapfile
- return None
-
- sum = 0
- to_data_do = {
- "[anon]": self.parse_size_line,
- "[heap]": self.parse_size_line
- }
-
- for line in infile:
- arr = line.split()
-
- # Just parse writable mapped areas
- if arr[1][1] != "w":
- continue
-
- if len(arr) == 6:
- # if we got a backed-file we skip this info
- if os.path.isfile(arr[5]):
- continue
- else:
- line_size = to_data_do.get(arr[5], self.skip)(line)
- sum += line_size
- else:
- line_size = self.parse_size_line(line)
- sum += line_size
-
- infile.close()
- self.clean_size = sum
-
- def skip(self, line):
- return 0
-
- # Parse a maps line and return the mapped size
- def parse_size_line(self, line):
- start, end = line.split()[0].split('-')
- size = int(end, 16) - int(start, 16)
- return size
+ try:
+ infile = open(mapfile, "r")
+ except:
+ print "Error trying " + mapfile
+ return None
+
+ sum = 0
+ to_data_do = {
+ "[anon]": self.parse_size_line,
+ "[heap]": self.parse_size_line
+ }
+
+ for line in infile:
+ arr = line.split()
+
+ # Just parse writable mapped areas
+ if arr[1][1] != "w":
+ continue
+
+ if len(arr) == 6:
+ # if we got a backed-file we skip this info
+ if os.path.isfile(arr[5]):
+ continue
+ else:
+ line_size = to_data_do.get(arr[5], self.skip)(line)
+ sum += line_size
+ else:
+ line_size = self.parse_size_line(line)
+ sum += line_size
+
+ infile.close()
+ self.clean_size = sum
+
+ def skip(self, line):
+ return 0
+
+ # Parse a maps line and return the mapped size
+ def parse_size_line(self, line):
+ start, end = line.split()[0].split('-')
+ size = int(end, 16) - int(start, 16)
+ return size
diff --git a/shell/console/terminal.py b/shell/console/terminal.py
index 6a92661..038c36d 100644
--- a/shell/console/terminal.py
+++ b/shell/console/terminal.py
@@ -3,141 +3,141 @@ import vte
import pango
class Terminal(gtk.HBox):
- def __init__(self):
- gtk.HBox.__init__(self, False, 4)
-
- self._vte = vte.Terminal()
- self._configure_vte()
- self._vte.set_size(30, 5)
- self._vte.set_size_request(200, 450)
- self._vte.show()
- self.pack_start(self._vte)
-
- self._scrollbar = gtk.VScrollbar(self._vte.get_adjustment())
- self._scrollbar.show()
- self.pack_start(self._scrollbar, False, False, 0)
-
- self._vte.connect("child-exited", lambda term: term.fork_command())
-
- self._vte.fork_command()
-
- def _configure_vte(self):
- self._vte.set_font(pango.FontDescription('Monospace 10'))
- self._vte.set_colors(gtk.gdk.color_parse ('#AAAAAA'),
- gtk.gdk.color_parse ('#000000'),
- [])
- self._vte.set_cursor_blinks(False)
- self._vte.set_audible_bell(False)
- self._vte.set_scrollback_lines(100)
- self._vte.set_allow_bold(True)
- self._vte.set_scroll_on_keystroke(False)
- self._vte.set_scroll_on_output(False)
- self._vte.set_emulation('xterm')
- self._vte.set_visible_bell(False)
-
- def on_gconf_notification(self, client, cnxn_id, entry, what):
- self.reconfigure_vte()
-
- def on_vte_button_press(self, term, event):
- if event.button == 3:
- self.do_popup(event)
- return True
-
- def on_vte_popup_menu(self, term):
- pass
+ def __init__(self):
+ gtk.HBox.__init__(self, False, 4)
+
+ self._vte = vte.Terminal()
+ self._configure_vte()
+ self._vte.set_size(30, 5)
+ self._vte.set_size_request(200, 450)
+ self._vte.show()
+ self.pack_start(self._vte)
+
+ self._scrollbar = gtk.VScrollbar(self._vte.get_adjustment())
+ self._scrollbar.show()
+ self.pack_start(self._scrollbar, False, False, 0)
+
+ self._vte.connect("child-exited", lambda term: term.fork_command())
+
+ self._vte.fork_command()
+
+ def _configure_vte(self):
+ self._vte.set_font(pango.FontDescription('Monospace 10'))
+ self._vte.set_colors(gtk.gdk.color_parse ('#AAAAAA'),
+ gtk.gdk.color_parse ('#000000'),
+ [])
+ self._vte.set_cursor_blinks(False)
+ self._vte.set_audible_bell(False)
+ self._vte.set_scrollback_lines(100)
+ self._vte.set_allow_bold(True)
+ self._vte.set_scroll_on_keystroke(False)
+ self._vte.set_scroll_on_output(False)
+ self._vte.set_emulation('xterm')
+ self._vte.set_visible_bell(False)
+
+ def on_gconf_notification(self, client, cnxn_id, entry, what):
+ self.reconfigure_vte()
+
+ def on_vte_button_press(self, term, event):
+ if event.button == 3:
+ self.do_popup(event)
+ return True
+
+ def on_vte_popup_menu(self, term):
+ pass
class Multiple:
-
- page_number = 0
-
- def __init__(self):
- self.notebook = gtk.Notebook()
- self.add_new_terminal()
-
- open_terminal = gtk.Button('Open a new terminal')
- open_terminal.connect("clicked", self.add_new_terminal)
- open_terminal.show()
-
- self.notebook.show()
-
- self.main_vbox = gtk.VBox(False, 3)
- self.main_vbox.pack_start(open_terminal, True, True, 2)
- self.main_vbox.pack_start(self.notebook, True, True, 2)
-
- self.main_vbox.show_all()
-
- # Remove a page from the notebook
- def close_terminal(self, button, child):
- page = self.notebook.page_num(child)
-
- if page != -1:
- self.notebook.remove_page(page)
-
-
- pages = self.notebook.get_n_pages()
- if pages <= 0:
- self.page_number = 0
- self.add_new_terminal()
-
- # Need to refresh the widget --
- # This forces the widget to redraw itself.
- self.notebook.queue_draw_area(0, 0, -1, -1)
-
- def add_icon_to_button(self, button):
- iconBox = gtk.HBox(False, 0)
- image = gtk.Image()
- image.set_from_stock(gtk.STOCK_CLOSE, gtk.ICON_SIZE_MENU)
- gtk.Button.set_relief(button, gtk.RELIEF_NONE)
-
- settings = gtk.Widget.get_settings (button)
- (w,h) = gtk.icon_size_lookup_for_settings (settings, gtk.ICON_SIZE_MENU)
- gtk.Widget.set_size_request (button, w + 4, h + 4)
- image.show()
- iconBox.pack_start(image, True, False, 0)
- button.add(iconBox)
- iconBox.show()
-
- def add_new_terminal(self, *arguments, **keywords):
- self.page_number += 1
-
- terminal = Terminal()
- terminal.show()
-
- eventBox = self.create_custom_tab("Term %d" % self.page_number, terminal)
- self.notebook.append_page(terminal, eventBox)
-
- # Set the new page
- pages = gtk.Notebook.get_n_pages(self.notebook)
- self.notebook.set_current_page(pages - 1)
- return True
-
- def create_custom_tab(self, text, child):
- eventBox = gtk.EventBox()
- tabBox = gtk.HBox(False, 2)
- tabLabel = gtk.Label(text)
-
- tabButton = gtk.Button()
- tabButton.connect('clicked', self.close_terminal, child)
-
- # Add a picture on a button
- self.add_icon_to_button(tabButton)
- iconBox = gtk.HBox(False, 0)
-
- eventBox.show()
- tabButton.show()
- tabLabel.show()
-
- tabBox.pack_start(tabLabel, False)
- tabBox.pack_start(tabButton, False)
-
- tabBox.show_all()
- eventBox.add(tabBox)
-
- return eventBox
+
+ page_number = 0
+
+ def __init__(self):
+ self.notebook = gtk.Notebook()
+ self.add_new_terminal()
+
+ open_terminal = gtk.Button('Open a new terminal')
+ open_terminal.connect("clicked", self.add_new_terminal)
+ open_terminal.show()
+
+ self.notebook.show()
+
+ self.main_vbox = gtk.VBox(False, 3)
+ self.main_vbox.pack_start(open_terminal, True, True, 2)
+ self.main_vbox.pack_start(self.notebook, True, True, 2)
+
+ self.main_vbox.show_all()
+
+ # Remove a page from the notebook
+ def close_terminal(self, button, child):
+ page = self.notebook.page_num(child)
+
+ if page != -1:
+ self.notebook.remove_page(page)
+
+
+ pages = self.notebook.get_n_pages()
+ if pages <= 0:
+ self.page_number = 0
+ self.add_new_terminal()
+
+ # Need to refresh the widget --
+ # This forces the widget to redraw itself.
+ self.notebook.queue_draw_area(0, 0, -1, -1)
+
+ def add_icon_to_button(self, button):
+ iconBox = gtk.HBox(False, 0)
+ image = gtk.Image()
+ image.set_from_stock(gtk.STOCK_CLOSE, gtk.ICON_SIZE_MENU)
+ gtk.Button.set_relief(button, gtk.RELIEF_NONE)
+
+ settings = gtk.Widget.get_settings (button)
+ (w,h) = gtk.icon_size_lookup_for_settings (settings, gtk.ICON_SIZE_MENU)
+ gtk.Widget.set_size_request (button, w + 4, h + 4)
+ image.show()
+ iconBox.pack_start(image, True, False, 0)
+ button.add(iconBox)
+ iconBox.show()
+
+ def add_new_terminal(self, *arguments, **keywords):
+ self.page_number += 1
+
+ terminal = Terminal()
+ terminal.show()
+
+ eventBox = self.create_custom_tab("Term %d" % self.page_number, terminal)
+ self.notebook.append_page(terminal, eventBox)
+
+ # Set the new page
+ pages = gtk.Notebook.get_n_pages(self.notebook)
+ self.notebook.set_current_page(pages - 1)
+ return True
+
+ def create_custom_tab(self, text, child):
+ eventBox = gtk.EventBox()
+ tabBox = gtk.HBox(False, 2)
+ tabLabel = gtk.Label(text)
+
+ tabButton = gtk.Button()
+ tabButton.connect('clicked', self.close_terminal, child)
+
+ # Add a picture on a button
+ self.add_icon_to_button(tabButton)
+ iconBox = gtk.HBox(False, 0)
+
+ eventBox.show()
+ tabButton.show()
+ tabLabel.show()
+
+ tabBox.pack_start(tabLabel, False)
+ tabBox.pack_start(tabButton, False)
+
+ tabBox.show_all()
+ eventBox.add(tabBox)
+
+ return eventBox
class Interface:
- def __init__(self):
- multiple = Multiple()
- self.widget = multiple.main_vbox
- \ No newline at end of file
+ def __init__(self):
+ multiple = Multiple()
+ self.widget = multiple.main_vbox
+ \ No newline at end of file
diff --git a/shell/model/BuddyModel.py b/shell/model/BuddyModel.py
index 651e911..8e175e7 100644
--- a/shell/model/BuddyModel.py
+++ b/shell/model/BuddyModel.py
@@ -21,122 +21,122 @@ import gobject
_NOT_PRESENT_COLOR = "#888888,#BBBBBB"
class BuddyModel(gobject.GObject):
- __gsignals__ = {
- 'appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([])),
- 'disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([])),
- 'color-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT])),
- 'icon-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([])),
- 'current-activity-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT]))
- }
-
- def __init__(self, name=None, buddy=None):
- if name and buddy:
- raise RuntimeError("Must specify only _one_ of name or buddy.")
-
- gobject.GObject.__init__(self)
-
- self._ba_handler = None
- self._pc_handler = None
- self._dis_handler = None
- self._bic_handler = None
- self._cac_handler = None
-
- self._pservice = PresenceService.get_instance()
-
- self._buddy = None
-
- # If given just a name, try to get the buddy from the PS first
- if not buddy:
- self._name = name
- # FIXME: use public key, not name
- buddy = self._pservice.get_buddy_by_name(self._name)
-
- # If successful, copy properties from the PS buddy object
- if buddy:
- self.__update_buddy(buddy)
- else:
- # Otherwise, connect to the PS's buddy-appeared signal and
- # wait for the buddy to appear
- self._ba_handler = self._pservice.connect('buddy-appeared',
- self.__buddy_appeared_cb)
- self._name = name
- # Set color to 'inactive'/'disconnected'
- self.__set_color_from_string(_NOT_PRESENT_COLOR)
-
- def __set_color_from_string(self, color_string):
- self._color = IconColor(color_string)
-
- def get_name(self):
- return self._name
-
- def get_color(self):
- return self._color
-
- def get_buddy(self):
- return self._buddy
-
- def is_present(self):
- if self._buddy:
- return True
- return False
-
- def get_current_activity(self):
- if self._buddy:
- return self._buddy.get_current_activity()
- return None
-
- def __update_buddy(self, buddy):
- if not buddy:
- raise ValueError("Buddy cannot be None.")
-
- self._buddy = buddy
- self._name = self._buddy.get_name()
- self.__set_color_from_string(self._buddy.get_color())
-
- self._pc_handler = self._buddy.connect('property-changed', self.__buddy_property_changed_cb)
- self._dis_handler = self._buddy.connect('disappeared', self.__buddy_disappeared_cb)
- self._bic_handler = self._buddy.connect('icon-changed', self.__buddy_icon_changed_cb)
- self._cac_handler = self._buddy.connect('current-activity-changed', self.__buddy_current_activity_changed_cb)
-
- def __buddy_appeared_cb(self, pservice, buddy):
- # FIXME: use public key rather than buddy name
- if self._buddy or buddy.get_name() != self._name:
- return
-
- if self._ba_handler:
- # Once we have the buddy, we no longer need to
- # monitor buddy-appeared events
- self._pservice.disconnect(self._ba_handler)
- self._ba_handler = None
-
- self.__update_buddy(buddy)
- self.emit('appeared')
-
- def __buddy_property_changed_cb(self, buddy, keys):
- if not self._buddy:
- return
- if 'color' in keys:
- self.__set_color_from_string(self._buddy.get_color())
- self.emit('color-changed', self.get_color())
-
- def __buddy_disappeared_cb(self, buddy):
- if buddy != self._buddy:
- return
- self._buddy.disconnect(self._pc_handler)
- self._buddy.disconnect(self._dis_handler)
- self._buddy.disconnect(self._bic_handler)
- self._buddy.disconnect(self._cac_handler)
- self.__set_color_from_string(_NOT_PRESENT_COLOR)
- self.emit('disappeared')
- self._buddy = None
-
- def __buddy_icon_changed_cb(self, buddy):
- self.emit('icon-changed')
-
- def __buddy_current_activity_changed_cb(self, buddy, activity=None):
- if not self._buddy:
- return
- self.emit('current-activity-changed', activity)
+ __gsignals__ = {
+ 'appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([])),
+ 'disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([])),
+ 'color-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT])),
+ 'icon-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([])),
+ 'current-activity-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT]))
+ }
+
+ def __init__(self, name=None, buddy=None):
+ if name and buddy:
+ raise RuntimeError("Must specify only _one_ of name or buddy.")
+
+ gobject.GObject.__init__(self)
+
+ self._ba_handler = None
+ self._pc_handler = None
+ self._dis_handler = None
+ self._bic_handler = None
+ self._cac_handler = None
+
+ self._pservice = PresenceService.get_instance()
+
+ self._buddy = None
+
+ # If given just a name, try to get the buddy from the PS first
+ if not buddy:
+ self._name = name
+ # FIXME: use public key, not name
+ buddy = self._pservice.get_buddy_by_name(self._name)
+
+ # If successful, copy properties from the PS buddy object
+ if buddy:
+ self.__update_buddy(buddy)
+ else:
+ # Otherwise, connect to the PS's buddy-appeared signal and
+ # wait for the buddy to appear
+ self._ba_handler = self._pservice.connect('buddy-appeared',
+ self.__buddy_appeared_cb)
+ self._name = name
+ # Set color to 'inactive'/'disconnected'
+ self.__set_color_from_string(_NOT_PRESENT_COLOR)
+
+ def __set_color_from_string(self, color_string):
+ self._color = IconColor(color_string)
+
+ def get_name(self):
+ return self._name
+
+ def get_color(self):
+ return self._color
+
+ def get_buddy(self):
+ return self._buddy
+
+ def is_present(self):
+ if self._buddy:
+ return True
+ return False
+
+ def get_current_activity(self):
+ if self._buddy:
+ return self._buddy.get_current_activity()
+ return None
+
+ def __update_buddy(self, buddy):
+ if not buddy:
+ raise ValueError("Buddy cannot be None.")
+
+ self._buddy = buddy
+ self._name = self._buddy.get_name()
+ self.__set_color_from_string(self._buddy.get_color())
+
+ self._pc_handler = self._buddy.connect('property-changed', self.__buddy_property_changed_cb)
+ self._dis_handler = self._buddy.connect('disappeared', self.__buddy_disappeared_cb)
+ self._bic_handler = self._buddy.connect('icon-changed', self.__buddy_icon_changed_cb)
+ self._cac_handler = self._buddy.connect('current-activity-changed', self.__buddy_current_activity_changed_cb)
+
+ def __buddy_appeared_cb(self, pservice, buddy):
+ # FIXME: use public key rather than buddy name
+ if self._buddy or buddy.get_name() != self._name:
+ return
+
+ if self._ba_handler:
+ # Once we have the buddy, we no longer need to
+ # monitor buddy-appeared events
+ self._pservice.disconnect(self._ba_handler)
+ self._ba_handler = None
+
+ self.__update_buddy(buddy)
+ self.emit('appeared')
+
+ def __buddy_property_changed_cb(self, buddy, keys):
+ if not self._buddy:
+ return
+ if 'color' in keys:
+ self.__set_color_from_string(self._buddy.get_color())
+ self.emit('color-changed', self.get_color())
+
+ def __buddy_disappeared_cb(self, buddy):
+ if buddy != self._buddy:
+ return
+ self._buddy.disconnect(self._pc_handler)
+ self._buddy.disconnect(self._dis_handler)
+ self._buddy.disconnect(self._bic_handler)
+ self._buddy.disconnect(self._cac_handler)
+ self.__set_color_from_string(_NOT_PRESENT_COLOR)
+ self.emit('disappeared')
+ self._buddy = None
+
+ def __buddy_icon_changed_cb(self, buddy):
+ self.emit('icon-changed')
+
+ def __buddy_current_activity_changed_cb(self, buddy, activity=None):
+ if not self._buddy:
+ return
+ self.emit('current-activity-changed', activity)
diff --git a/shell/model/Friends.py b/shell/model/Friends.py
index ab1935b..36c443f 100644
--- a/shell/model/Friends.py
+++ b/shell/model/Friends.py
@@ -24,61 +24,61 @@ from sugar import env
import logging
class Friends(gobject.GObject):
- __gsignals__ = {
- 'friend-added': (gobject.SIGNAL_RUN_FIRST,
- gobject.TYPE_NONE, ([object])),
- 'friend-removed': (gobject.SIGNAL_RUN_FIRST,
- gobject.TYPE_NONE, ([str])),
- }
-
- def __init__(self):
- gobject.GObject.__init__(self)
-
- self._friends = {}
- self._path = os.path.join(env.get_profile_path(), 'friends')
-
- self.load()
-
- def has_buddy(self, buddy):
- return self._friends.has_key(buddy.get_name())
-
- def add_friend(self, buddy_info):
- self._friends[buddy_info.get_name()] = buddy_info
- self.emit('friend-added', buddy_info)
-
- def make_friend(self, buddy):
- if not self.has_buddy(buddy):
- self.add_friend(BuddyModel(buddy=buddy))
- self.save()
-
- def remove(self, buddy_info):
- del self._friends[buddy_info.get_name()]
- self.save()
- self.emit('friend-removed', buddy_info.get_name())
-
- def __iter__(self):
- return self._friends.values().__iter__()
-
- def load(self):
- cp = ConfigParser()
-
- try:
- success = cp.read([self._path])
- if success:
- for name in cp.sections():
- buddy = BuddyModel(name)
- self.add_friend(buddy)
- except Exception, exc:
- logging.error("Error parsing friends file: %s" % exc)
-
- def save(self):
- cp = ConfigParser()
-
- for friend in self:
- section = friend.get_name()
- cp.add_section(section)
- cp.set(section, 'color', friend.get_color().to_string())
-
- fileobject = open(self._path, 'w')
- cp.write(fileobject)
- fileobject.close()
+ __gsignals__ = {
+ 'friend-added': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([object])),
+ 'friend-removed': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([str])),
+ }
+
+ def __init__(self):
+ gobject.GObject.__init__(self)
+
+ self._friends = {}
+ self._path = os.path.join(env.get_profile_path(), 'friends')
+
+ self.load()
+
+ def has_buddy(self, buddy):
+ return self._friends.has_key(buddy.get_name())
+
+ def add_friend(self, buddy_info):
+ self._friends[buddy_info.get_name()] = buddy_info
+ self.emit('friend-added', buddy_info)
+
+ def make_friend(self, buddy):
+ if not self.has_buddy(buddy):
+ self.add_friend(BuddyModel(buddy=buddy))
+ self.save()
+
+ def remove(self, buddy_info):
+ del self._friends[buddy_info.get_name()]
+ self.save()
+ self.emit('friend-removed', buddy_info.get_name())
+
+ def __iter__(self):
+ return self._friends.values().__iter__()
+
+ def load(self):
+ cp = ConfigParser()
+
+ try:
+ success = cp.read([self._path])
+ if success:
+ for name in cp.sections():
+ buddy = BuddyModel(name)
+ self.add_friend(buddy)
+ except Exception, exc:
+ logging.error("Error parsing friends file: %s" % exc)
+
+ def save(self):
+ cp = ConfigParser()
+
+ for friend in self:
+ section = friend.get_name()
+ cp.add_section(section)
+ cp.set(section, 'color', friend.get_color().to_string())
+
+ fileobject = open(self._path, 'w')
+ cp.write(fileobject)
+ fileobject.close()
diff --git a/shell/model/Invites.py b/shell/model/Invites.py
index bc947a9..7bc0af0 100644
--- a/shell/model/Invites.py
+++ b/shell/model/Invites.py
@@ -17,38 +17,38 @@
import gobject
class Invite:
- def __init__(self, issuer, bundle_id, activity_id):
- self._issuer = issuer
- self._activity_id = activity_id
- self._bundle_id = bundle_id
+ def __init__(self, issuer, bundle_id, activity_id):
+ self._issuer = issuer
+ self._activity_id = activity_id
+ self._bundle_id = bundle_id
- def get_activity_id(self):
- return self._activity_id
+ def get_activity_id(self):
+ return self._activity_id
- def get_bundle_id(self):
- return self._bundle_id
+ def get_bundle_id(self):
+ return self._bundle_id
class Invites(gobject.GObject):
- __gsignals__ = {
- 'invite-added': (gobject.SIGNAL_RUN_FIRST,
- gobject.TYPE_NONE, ([object])),
- 'invite-removed': (gobject.SIGNAL_RUN_FIRST,
- gobject.TYPE_NONE, ([object])),
- }
+ __gsignals__ = {
+ 'invite-added': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([object])),
+ 'invite-removed': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([object])),
+ }
- def __init__(self):
- gobject.GObject.__init__(self)
+ def __init__(self):
+ gobject.GObject.__init__(self)
- self._list = []
+ self._list = []
- def add_invite(self, issuer, bundle_id, activity_id):
- invite = Invite(issuer, bundle_id, activity_id)
- self._list.append(invite)
- self.emit('invite-added', invite)
+ def add_invite(self, issuer, bundle_id, activity_id):
+ invite = Invite(issuer, bundle_id, activity_id)
+ self._list.append(invite)
+ self.emit('invite-added', invite)
- def remove_invite(self, invite):
- self._list.remove(invite)
- self.emit('invite-removed', invite)
+ def remove_invite(self, invite):
+ self._list.remove(invite)
+ self.emit('invite-removed', invite)
- def __iter__(self):
- return self._list.__iter__()
+ def __iter__(self):
+ return self._list.__iter__()
diff --git a/shell/model/MeshModel.py b/shell/model/MeshModel.py
index 0ecf2b8..5ab36e9 100644
--- a/shell/model/MeshModel.py
+++ b/shell/model/MeshModel.py
@@ -21,137 +21,137 @@ from sugar.presence import PresenceService
from model.BuddyModel import BuddyModel
class ActivityModel:
- def __init__(self, activity, bundle, service):
- self._service = service
- self._activity = activity
-
- def get_id(self):
- return self._activity.get_id()
-
- def get_icon_name(self):
- return bundle.get_icon()
-
- def get_color(self):
- return IconColor(self._activity.get_color())
-
- def get_service(self):
- return self._service
+ def __init__(self, activity, bundle, service):
+ self._service = service
+ self._activity = activity
+
+ def get_id(self):
+ return self._activity.get_id()
+
+ def get_icon_name(self):
+ return bundle.get_icon()
+
+ def get_color(self):
+ return IconColor(self._activity.get_color())
+
+ def get_service(self):
+ return self._service
class MeshModel(gobject.GObject):
- __gsignals__ = {
- 'activity-added': (gobject.SIGNAL_RUN_FIRST,
- gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])),
- 'activity-removed': (gobject.SIGNAL_RUN_FIRST,
- gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])),
- 'buddy-added': (gobject.SIGNAL_RUN_FIRST,
- gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])),
- 'buddy-moved': (gobject.SIGNAL_RUN_FIRST,
- gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT,
- gobject.TYPE_PYOBJECT])),
- 'buddy-removed': (gobject.SIGNAL_RUN_FIRST,
- gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT]))
- }
-
- def __init__(self, bundle_registry):
- gobject.GObject.__init__(self)
-
- self._activities = {}
- self._buddies = {}
- self._bundle_registry = bundle_registry
-
- self._pservice = PresenceService.get_instance()
- self._pservice.connect("service-appeared",
- self._service_appeared_cb)
- self._pservice.connect('activity-disappeared',
- self._activity_disappeared_cb)
- self._pservice.connect("buddy-appeared",
- self._buddy_appeared_cb)
- self._pservice.connect("buddy-disappeared",
- self._buddy_disappeared_cb)
-
- # Add any buddies the PS knows about already
- for buddy in self._pservice.get_buddies():
- self._buddy_appeared_cb(self._pservice, buddy)
-
- for service in self._pservice.get_services():
- self._check_service(service)
-
- def get_activities(self):
- return self._activities.values()
-
- def get_buddies(self):
- return self._buddies.values()
-
- def _buddy_activity_changed_cb(self, buddy, cur_activity):
- if not self._buddies.has_key(buddy.get_name()):
- return
- buddy_model = self._buddies[buddy.get_name()]
- if cur_activity == None:
- self.emit('buddy-moved', buddy_model, None)
- else:
- self._notify_buddy_change(buddy_model, cur_activity)
-
- def _notify_buddy_change(self, buddy_model, cur_activity):
- if self._activities.has_key(cur_activity.get_id()):
- activity_model = self._activities[cur_activity.get_id()]
- self.emit('buddy-moved', buddy_model, activity_model)
-
- def _buddy_appeared_cb(self, pservice, buddy):
- model = BuddyModel(buddy=buddy)
- if self._buddies.has_key(model.get_name()):
- del model
- return
-
- model.connect('current-activity-changed',
- self._buddy_activity_changed_cb)
- self._buddies[model.get_name()] = model
- self.emit('buddy-added', model)
-
- cur_activity = buddy.get_current_activity()
- if cur_activity:
- self._notify_buddy_change(model, cur_activity)
-
- def _buddy_disappeared_cb(self, pservice, buddy):
- if not self._buddies.has_key(buddy.get_name()):
- return
- self.emit('buddy-removed', buddy)
- del self._buddies[buddy.get_name()]
-
- def _service_appeared_cb(self, pservice, service):
- self._check_service(service)
-
- def _check_service(self, service):
- if self._bundle_registry.get_bundle(service.get_type()) != None:
- activity_id = service.get_activity_id()
- if not self.has_activity(activity_id):
- activity = self._pservice.get_activity(activity_id)
- if activity != None:
- self.add_activity(activity, service)
-
- def has_activity(self, activity_id):
- return self._activities.has_key(activity_id)
-
- def get_activity(self, activity_id):
- if self.has_activity(activity_id):
- return self._activities[activity_id]
- else:
- return None
-
- def add_activity(self, activity, service):
- bundle = self._bundle_registry.get_bundle(service.get_type())
- model = ActivityModel(activity, bundle, service)
- self._activities[model.get_id()] = model
- self.emit('activity-added', model)
-
- for buddy in self._pservice.get_buddies():
- cur_activity = buddy.get_current_activity()
- name = buddy.get_name()
- if cur_activity == activity and self._buddies.has_key(name):
- buddy_model = self._buddies[name]
- self.emit('buddy-moved', buddy_model, model)
-
- def _activity_disappeared_cb(self, pservice, activity):
- if self._activities.has_key(activity.get_id()):
- activity_model = self._activities[activity.get_id()]
- self.emit('activity-removed', activity_model)
- del self._activities[activity.get_id()]
+ __gsignals__ = {
+ 'activity-added': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])),
+ 'activity-removed': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])),
+ 'buddy-added': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])),
+ 'buddy-moved': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT,
+ gobject.TYPE_PYOBJECT])),
+ 'buddy-removed': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT]))
+ }
+
+ def __init__(self, bundle_registry):
+ gobject.GObject.__init__(self)
+
+ self._activities = {}
+ self._buddies = {}
+ self._bundle_registry = bundle_registry
+
+ self._pservice = PresenceService.get_instance()
+ self._pservice.connect("service-appeared",
+ self._service_appeared_cb)
+ self._pservice.connect('activity-disappeared',
+ self._activity_disappeared_cb)
+ self._pservice.connect("buddy-appeared",
+ self._buddy_appeared_cb)
+ self._pservice.connect("buddy-disappeared",
+ self._buddy_disappeared_cb)
+
+ # Add any buddies the PS knows about already
+ for buddy in self._pservice.get_buddies():
+ self._buddy_appeared_cb(self._pservice, buddy)
+
+ for service in self._pservice.get_services():
+ self._check_service(service)
+
+ def get_activities(self):
+ return self._activities.values()
+
+ def get_buddies(self):
+ return self._buddies.values()
+
+ def _buddy_activity_changed_cb(self, buddy, cur_activity):
+ if not self._buddies.has_key(buddy.get_name()):
+ return
+ buddy_model = self._buddies[buddy.get_name()]
+ if cur_activity == None:
+ self.emit('buddy-moved', buddy_model, None)
+ else:
+ self._notify_buddy_change(buddy_model, cur_activity)
+
+ def _notify_buddy_change(self, buddy_model, cur_activity):
+ if self._activities.has_key(cur_activity.get_id()):
+ activity_model = self._activities[cur_activity.get_id()]
+ self.emit('buddy-moved', buddy_model, activity_model)
+
+ def _buddy_appeared_cb(self, pservice, buddy):
+ model = BuddyModel(buddy=buddy)
+ if self._buddies.has_key(model.get_name()):
+ del model
+ return
+
+ model.connect('current-activity-changed',
+ self._buddy_activity_changed_cb)
+ self._buddies[model.get_name()] = model
+ self.emit('buddy-added', model)
+
+ cur_activity = buddy.get_current_activity()
+ if cur_activity:
+ self._notify_buddy_change(model, cur_activity)
+
+ def _buddy_disappeared_cb(self, pservice, buddy):
+ if not self._buddies.has_key(buddy.get_name()):
+ return
+ self.emit('buddy-removed', buddy)
+ del self._buddies[buddy.get_name()]
+
+ def _service_appeared_cb(self, pservice, service):
+ self._check_service(service)
+
+ def _check_service(self, service):
+ if self._bundle_registry.get_bundle(service.get_type()) != None:
+ activity_id = service.get_activity_id()
+ if not self.has_activity(activity_id):
+ activity = self._pservice.get_activity(activity_id)
+ if activity != None:
+ self.add_activity(activity, service)
+
+ def has_activity(self, activity_id):
+ return self._activities.has_key(activity_id)
+
+ def get_activity(self, activity_id):
+ if self.has_activity(activity_id):
+ return self._activities[activity_id]
+ else:
+ return None
+
+ def add_activity(self, activity, service):
+ bundle = self._bundle_registry.get_bundle(service.get_type())
+ model = ActivityModel(activity, bundle, service)
+ self._activities[model.get_id()] = model
+ self.emit('activity-added', model)
+
+ for buddy in self._pservice.get_buddies():
+ cur_activity = buddy.get_current_activity()
+ name = buddy.get_name()
+ if cur_activity == activity and self._buddies.has_key(name):
+ buddy_model = self._buddies[name]
+ self.emit('buddy-moved', buddy_model, model)
+
+ def _activity_disappeared_cb(self, pservice, activity):
+ if self._activities.has_key(activity.get_id()):
+ activity_model = self._activities[activity.get_id()]
+ self.emit('activity-removed', activity_model)
+ del self._activities[activity.get_id()]
diff --git a/shell/model/Owner.py b/shell/model/Owner.py
index 7d83ab2..49386a9 100644
--- a/shell/model/Owner.py
+++ b/shell/model/Owner.py
@@ -31,90 +31,90 @@ from model.Invites import Invites
PRESENCE_SERVICE_TYPE = "_presence_olpc._tcp"
class ShellOwner(object):
- """Class representing the owner of this machine/instance. This class
- runs in the shell and serves up the buddy icon and other stuff. It's the
- server portion of the Owner, paired with the client portion in Buddy.py."""
- def __init__(self):
- self._nick = profile.get_nick_name()
- user_dir = env.get_profile_path()
-
- self._icon = None
- self._icon_hash = ""
- for fname in os.listdir(user_dir):
- if not fname.startswith("buddy-icon."):
- continue
- fd = open(os.path.join(user_dir, fname), "r")
- self._icon = fd.read()
- if self._icon:
- # Get the icon's hash
- import md5, binascii
- digest = md5.new(self._icon).digest()
- self._icon_hash = util.printable_hash(digest)
- fd.close()
- break
-
- self._pservice = PresenceService.get_instance()
-
- self._invites = Invites()
-
- self._last_activity_update = time.time()
- self._pending_activity_update_timer = None
- self._pending_activity_update = None
-
- def get_invites(self):
- return self._invites
-
- def get_name(self):
- return self._nick
-
- def announce(self):
- # Create and announce our presence
- color = profile.get_color()
- props = {'color': color.to_string(), 'icon-hash': self._icon_hash}
- self._service = self._pservice.register_service(self._nick,
- PRESENCE_SERVICE_TYPE, properties=props)
- logging.debug("Owner '%s' using port %d" % (self._nick, self._service.get_port()))
- self._icon_stream = Stream.Stream.new_from_service(self._service)
- self._icon_stream.register_reader_handler(self._handle_buddy_icon_request, "get_buddy_icon")
- self._icon_stream.register_reader_handler(self._handle_invite, "invite")
-
- def _handle_buddy_icon_request(self):
- """XMLRPC method, return the owner's icon encoded with base64."""
- if self._icon:
- return base64.b64encode(self._icon)
- return ""
-
- def _handle_invite(self, issuer, bundle_id, activity_id):
- """XMLRPC method, called when the owner is invited to an activity."""
- self._invites.add_invite(issuer, bundle_id, activity_id)
- return ''
-
- def __update_advertised_current_activity_cb(self):
- self._last_activity_update = time.time()
- self._pending_activity_update_timer = None
- if self._pending_activity_update:
- logging.debug("*** Updating current activity to %s" % self._pending_activity_update)
- self._service.set_published_value('curact', dbus.String(self._pending_activity_update))
- return False
-
- def set_current_activity(self, activity_id):
- """Update our presence service with the latest activity, but no
- more frequently than every 30 seconds"""
- self._pending_activity_update = activity_id
- # If there's no pending update, we must not have updated it in the
- # last 30 seconds (except for the initial update, hence we also check
- # for the last update)
- if not self._pending_activity_update_timer or time.time() - self._last_activity_update > 30:
- self.__update_advertised_current_activity_cb()
- return
-
- # If we have a pending update already, we have nothing left to do
- if self._pending_activity_update_timer:
- return
-
- # Otherwise, we start a timer to update the activity at the next
- # interval, which should be 30 seconds from the last update, or if that
- # is in the past already, then now
- next = 30 - max(30, time.time() - self._last_activity_update)
- self._pending_activity_update_timer = gobject.timeout_add(next * 1000,
- self.__update_advertised_current_activity_cb)
+ """Class representing the owner of this machine/instance. This class
+ runs in the shell and serves up the buddy icon and other stuff. It's the
+ server portion of the Owner, paired with the client portion in Buddy.py."""
+ def __init__(self):
+ self._nick = profile.get_nick_name()
+ user_dir = env.get_profile_path()
+
+ self._icon = None
+ self._icon_hash = ""
+ for fname in os.listdir(user_dir):
+ if not fname.startswith("buddy-icon."):
+ continue
+ fd = open(os.path.join(user_dir, fname), "r")
+ self._icon = fd.read()
+ if self._icon:
+ # Get the icon's hash
+ import md5, binascii
+ digest = md5.new(self._icon).digest()
+ self._icon_hash = util.printable_hash(digest)
+ fd.close()
+ break
+
+ self._pservice = PresenceService.get_instance()
+
+ self._invites = Invites()
+
+ self._last_activity_update = time.time()
+ self._pending_activity_update_timer = None
+ self._pending_activity_update = None
+
+ def get_invites(self):
+ return self._invites
+
+ def get_name(self):
+ return self._nick
+
+ def announce(self):
+ # Create and announce our presence
+ color = profile.get_color()
+ props = {'color': color.to_string(), 'icon-hash': self._icon_hash}
+ self._service = self._pservice.register_service(self._nick,
+ PRESENCE_SERVICE_TYPE, properties=props)
+ logging.debug("Owner '%s' using port %d" % (self._nick, self._service.get_port()))
+ self._icon_stream = Stream.Stream.new_from_service(self._service)
+ self._icon_stream.register_reader_handler(self._handle_buddy_icon_request, "get_buddy_icon")
+ self._icon_stream.register_reader_handler(self._handle_invite, "invite")
+
+ def _handle_buddy_icon_request(self):
+ """XMLRPC method, return the owner's icon encoded with base64."""
+ if self._icon:
+ return base64.b64encode(self._icon)
+ return ""
+
+ def _handle_invite(self, issuer, bundle_id, activity_id):
+ """XMLRPC method, called when the owner is invited to an activity."""
+ self._invites.add_invite(issuer, bundle_id, activity_id)
+ return ''
+
+ def __update_advertised_current_activity_cb(self):
+ self._last_activity_update = time.time()
+ self._pending_activity_update_timer = None
+ if self._pending_activity_update:
+ logging.debug("*** Updating current activity to %s" % self._pending_activity_update)
+ self._service.set_published_value('curact', dbus.String(self._pending_activity_update))
+ return False
+
+ def set_current_activity(self, activity_id):
+ """Update our presence service with the latest activity, but no
+ more frequently than every 30 seconds"""
+ self._pending_activity_update = activity_id
+ # If there's no pending update, we must not have updated it in the
+ # last 30 seconds (except for the initial update, hence we also check
+ # for the last update)
+ if not self._pending_activity_update_timer or time.time() - self._last_activity_update > 30:
+ self.__update_advertised_current_activity_cb()
+ return
+
+ # If we have a pending update already, we have nothing left to do
+ if self._pending_activity_update_timer:
+ return
+
+ # Otherwise, we start a timer to update the activity at the next
+ # interval, which should be 30 seconds from the last update, or if that
+ # is in the past already, then now
+ next = 30 - max(30, time.time() - self._last_activity_update)
+ self._pending_activity_update_timer = gobject.timeout_add(next * 1000,
+ self.__update_advertised_current_activity_cb)
diff --git a/shell/model/ShellModel.py b/shell/model/ShellModel.py
index d2d6e9d..95ed344 100644
--- a/shell/model/ShellModel.py
+++ b/shell/model/ShellModel.py
@@ -24,45 +24,45 @@ from model.Owner import ShellOwner
from sugar import env
class ShellModel:
- def __init__(self):
- self._current_activity = None
+ def __init__(self):
+ self._current_activity = None
- self._bundle_registry = BundleRegistry()
+ self._bundle_registry = BundleRegistry()
- PresenceService.start()
- self._pservice = PresenceService.get_instance()
+ PresenceService.start()
+ self._pservice = PresenceService.get_instance()
- self._owner = ShellOwner()
- self._owner.announce()
+ self._owner = ShellOwner()
+ self._owner.announce()
- self._friends = Friends()
- self._mesh = MeshModel(self._bundle_registry)
+ self._friends = Friends()
+ self._mesh = MeshModel(self._bundle_registry)
- path = os.path.expanduser('~/Activities')
- self._bundle_registry.add_search_path(path)
+ path = os.path.expanduser('~/Activities')
+ self._bundle_registry.add_search_path(path)
- for path in env.get_data_dirs():
- bundles_path = os.path.join(path, 'activities')
- self._bundle_registry.add_search_path(bundles_path)
+ for path in env.get_data_dirs():
+ bundles_path = os.path.join(path, 'activities')
+ self._bundle_registry.add_search_path(bundles_path)
- def get_bundle_registry(self):
- return self._bundle_registry
+ def get_bundle_registry(self):
+ return self._bundle_registry
- def get_mesh(self):
- return self._mesh
+ def get_mesh(self):
+ return self._mesh
- def get_friends(self):
- return self._friends
+ def get_friends(self):
+ return self._friends
- def get_invites(self):
- return self._owner.get_invites()
+ def get_invites(self):
+ return self._owner.get_invites()
- def get_owner(self):
- return self._owner
+ def get_owner(self):
+ return self._owner
- def set_current_activity(self, activity_id):
- self._current_activity = activity_id
- self._owner.set_current_activity(activity_id)
+ def set_current_activity(self, activity_id):
+ self._current_activity = activity_id
+ self._owner.set_current_activity(activity_id)
- def get_current_activity(self):
- return self._current_activity
+ def get_current_activity(self):
+ return self._current_activity
diff --git a/shell/view/ActivityHost.py b/shell/view/ActivityHost.py
index a7e177d..f87b65b 100644
--- a/shell/view/ActivityHost.py
+++ b/shell/view/ActivityHost.py
@@ -27,122 +27,122 @@ from sugar.chat import ActivityChat
import OverlayWindow
class ActivityChatWindow(gtk.Window):
- def __init__(self, gdk_window, chat_widget):
- gtk.Window.__init__(self)
+ def __init__(self, gdk_window, chat_widget):
+ gtk.Window.__init__(self)
- self.realize()
- self.set_decorated(False)
- self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
- self.window.set_accept_focus(True)
- self.window.set_transient_for(gdk_window)
- self.set_position(gtk.WIN_POS_CENTER_ALWAYS)
- self.set_default_size(600, 450)
+ self.realize()
+ self.set_decorated(False)
+ self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
+ self.window.set_accept_focus(True)
+ self.window.set_transient_for(gdk_window)
+ self.set_position(gtk.WIN_POS_CENTER_ALWAYS)
+ self.set_default_size(600, 450)
- self.add(chat_widget)
+ self.add(chat_widget)
class ActivityHost:
- def __init__(self, shell_model, window):
- self._window = window
- self._xid = window.get_xid()
- self._pservice = PresenceService.get_instance()
-
- bus = dbus.SessionBus()
- proxy_obj = bus.get_object(Activity.get_service_name(self._xid),
- Activity.get_object_path(self._xid))
-
- self._activity = dbus.Interface(proxy_obj, Activity.ACTIVITY_INTERFACE)
- self._id = self._activity.get_id()
- self._type = self._activity.get_type()
- self._gdk_window = gtk.gdk.window_foreign_new(self._xid)
-
- registry = shell_model.get_bundle_registry()
- info = registry.get_bundle(self._type)
- self._icon_name = info.get_icon()
-
- try:
- self._overlay_window = OverlayWindow.OverlayWindow(self._gdk_window)
- win = self._overlay_window.window
- except RuntimeError:
- self._overlay_window = None
- win = self._gdk_window
-
- self._chat_widget = ActivityChat.ActivityChat(self)
- self._chat_window = ActivityChatWindow(win, self._chat_widget)
-
- self._frame_was_visible = False
-
- def get_id(self):
- return self._id
-
- def get_title(self):
- return self._window.get_name()
-
- def get_xid(self):
- return self._xid
-
- def get_icon_name(self):
- return self._icon_name
-
- def get_icon_color(self):
- activity = self._pservice.get_activity(self._id)
- if activity != None:
- return IconColor(activity.get_color())
- else:
- return profile.get_color()
-
- def share(self):
- self._activity.share()
- self._chat_widget.share()
-
- def invite(self, buddy):
- if not self.get_shared():
- self.share()
-
- issuer = self._pservice.get_owner().get_name()
- service = buddy.get_service_of_type("_presence_olpc._tcp")
- stream = Stream.Stream.new_from_service(service, start_reader=False)
- writer = stream.new_writer(service)
- writer.custom_request("invite", None, None, issuer,
- self._type, self._id)
-
- def get_shared(self):
- return self._activity.get_shared()
-
- def get_type(self):
- return self._type
-
- def present(self):
- self._window.activate(gtk.get_current_event_time())
-
- def close(self):
- self._window.close(gtk.get_current_event_time())
-
- def show_dialog(self, dialog):
- dialog.show()
- dialog.window.set_transient_for(self._gdk_window)
-
- def chat_show(self, frame_was_visible):
- if self._overlay_window:
- self._overlay_window.show_all()
- self._chat_window.show_all()
- self._frame_was_visible = frame_was_visible
-
- def chat_hide(self):
- self._chat_window.hide()
- if self._overlay_window:
- self._overlay_window.hide()
- wasvis = self._frame_was_visible
- self._frame_was_visible = False
- return wasvis
-
- def is_chat_visible(self):
- return self._chat_window.get_property('visible')
-
- def set_active(self, active):
- if not active:
- self.chat_hide()
- self._frame_was_visible = False
-
- def destroy(self):
- self._chat_window.destroy()
- self._frame_was_visible = False
+ def __init__(self, shell_model, window):
+ self._window = window
+ self._xid = window.get_xid()
+ self._pservice = PresenceService.get_instance()
+
+ bus = dbus.SessionBus()
+ proxy_obj = bus.get_object(Activity.get_service_name(self._xid),
+ Activity.get_object_path(self._xid))
+
+ self._activity = dbus.Interface(proxy_obj, Activity.ACTIVITY_INTERFACE)
+ self._id = self._activity.get_id()
+ self._type = self._activity.get_type()
+ self._gdk_window = gtk.gdk.window_foreign_new(self._xid)
+
+ registry = shell_model.get_bundle_registry()
+ info = registry.get_bundle(self._type)
+ self._icon_name = info.get_icon()
+
+ try:
+ self._overlay_window = OverlayWindow.OverlayWindow(self._gdk_window)
+ win = self._overlay_window.window
+ except RuntimeError:
+ self._overlay_window = None
+ win = self._gdk_window
+
+ self._chat_widget = ActivityChat.ActivityChat(self)
+ self._chat_window = ActivityChatWindow(win, self._chat_widget)
+
+ self._frame_was_visible = False
+
+ def get_id(self):
+ return self._id
+
+ def get_title(self):
+ return self._window.get_name()
+
+ def get_xid(self):
+ return self._xid
+
+ def get_icon_name(self):
+ return self._icon_name
+
+ def get_icon_color(self):
+ activity = self._pservice.get_activity(self._id)
+ if activity != None:
+ return IconColor(activity.get_color())
+ else:
+ return profile.get_color()
+
+ def share(self):
+ self._activity.share()
+ self._chat_widget.share()
+
+ def invite(self, buddy):
+ if not self.get_shared():
+ self.share()
+
+ issuer = self._pservice.get_owner().get_name()
+ service = buddy.get_service_of_type("_presence_olpc._tcp")
+ stream = Stream.Stream.new_from_service(service, start_reader=False)
+ writer = stream.new_writer(service)
+ writer.custom_request("invite", None, None, issuer,
+ self._type, self._id)
+
+ def get_shared(self):
+ return self._activity.get_shared()
+
+ def get_type(self):
+ return self._type
+
+ def present(self):
+ self._window.activate(gtk.get_current_event_time())
+
+ def close(self):
+ self._window.close(gtk.get_current_event_time())
+
+ def show_dialog(self, dialog):
+ dialog.show()
+ dialog.window.set_transient_for(self._gdk_window)
+
+ def chat_show(self, frame_was_visible):
+ if self._overlay_window:
+ self._overlay_window.show_all()
+ self._chat_window.show_all()
+ self._frame_was_visible = frame_was_visible
+
+ def chat_hide(self):
+ self._chat_window.hide()
+ if self._overlay_window:
+ self._overlay_window.hide()
+ wasvis = self._frame_was_visible
+ self._frame_was_visible = False
+ return wasvis
+
+ def is_chat_visible(self):
+ return self._chat_window.get_property('visible')
+
+ def set_active(self, active):
+ if not active:
+ self.chat_hide()
+ self._frame_was_visible = False
+
+ def destroy(self):
+ self._chat_window.destroy()
+ self._frame_was_visible = False
diff --git a/shell/view/BuddyIcon.py b/shell/view/BuddyIcon.py
index f8f1013..38f8277 100644
--- a/shell/view/BuddyIcon.py
+++ b/shell/view/BuddyIcon.py
@@ -18,41 +18,41 @@ from sugar.graphics.menuicon import MenuIcon
from view.BuddyMenu import BuddyMenu
class BuddyIcon(MenuIcon):
- def __init__(self, shell, menu_shell, buddy):
- MenuIcon.__init__(self, menu_shell, icon_name='stock-buddy',
- color=buddy.get_color())
-
- self._shell = shell
- self._buddy = buddy
- self._buddy.connect('appeared', self._buddy_presence_change_cb)
- self._buddy.connect('disappeared', self._buddy_presence_change_cb)
- self._buddy.connect('color-changed', self._buddy_presence_change_cb)
-
- def _buddy_presence_change_cb(self, buddy, color=None):
- # Update the icon's color when the buddy comes and goes
- self.set_property('color', buddy.get_color())
-
- def set_popup_distance(self, distance):
- self._popup_distance = distance
-
- def create_menu(self):
- menu = BuddyMenu(self._shell, self._buddy)
- menu.connect('action', self._popup_action_cb)
- return menu
-
- def _popup_action_cb(self, popup, action):
- self.popdown()
-
- friends = self._shell.get_model().get_friends()
- if action == BuddyMenu.ACTION_REMOVE_FRIEND:
- friends.remove(self._buddy)
-
- ps_buddy = self._buddy.get_buddy()
- if ps_buddy == None:
- return
-
- if action == BuddyMenu.ACTION_INVITE:
- activity = self._shell.get_current_activity()
- activity.invite(ps_buddy)
- elif action == BuddyMenu.ACTION_MAKE_FRIEND:
- friends.make_friend(ps_buddy)
+ def __init__(self, shell, menu_shell, buddy):
+ MenuIcon.__init__(self, menu_shell, icon_name='stock-buddy',
+ color=buddy.get_color())
+
+ self._shell = shell
+ self._buddy = buddy
+ self._buddy.connect('appeared', self._buddy_presence_change_cb)
+ self._buddy.connect('disappeared', self._buddy_presence_change_cb)
+ self._buddy.connect('color-changed', self._buddy_presence_change_cb)
+
+ def _buddy_presence_change_cb(self, buddy, color=None):
+ # Update the icon's color when the buddy comes and goes
+ self.set_property('color', buddy.get_color())
+
+ def set_popup_distance(self, distance):
+ self._popup_distance = distance
+
+ def create_menu(self):
+ menu = BuddyMenu(self._shell, self._buddy)
+ menu.connect('action', self._popup_action_cb)
+ return menu
+
+ def _popup_action_cb(self, popup, action):
+ self.popdown()
+
+ friends = self._shell.get_model().get_friends()
+ if action == BuddyMenu.ACTION_REMOVE_FRIEND:
+ friends.remove(self._buddy)
+
+ ps_buddy = self._buddy.get_buddy()
+ if ps_buddy == None:
+ return
+
+ if action == BuddyMenu.ACTION_INVITE:
+ activity = self._shell.get_current_activity()
+ activity.invite(ps_buddy)
+ elif action == BuddyMenu.ACTION_MAKE_FRIEND:
+ friends.make_friend(ps_buddy)
diff --git a/shell/view/BuddyMenu.py b/shell/view/BuddyMenu.py
index f330234..069aa6a 100644
--- a/shell/view/BuddyMenu.py
+++ b/shell/view/BuddyMenu.py
@@ -25,73 +25,73 @@ from sugar.presence import PresenceService
_ICON_SIZE = 75
class BuddyMenu(Menu):
- ACTION_MAKE_FRIEND = 0
- ACTION_INVITE = 1
- ACTION_REMOVE_FRIEND = 2
-
- def __init__(self, shell, buddy):
- self._buddy = buddy
- self._shell = shell
-
- icon_item = None
- pixbuf = self._get_buddy_icon_pixbuf()
- if pixbuf:
- scaled_pixbuf = pixbuf.scale_simple(_ICON_SIZE, _ICON_SIZE,
- gtk.gdk.INTERP_BILINEAR)
- del pixbuf
- icon_item = hippo.CanvasImage(pixbuf=scaled_pixbuf)
-
- Menu.__init__(self, buddy.get_name(), icon_item)
-
- self._buddy.connect('icon-changed', self.__buddy_icon_changed_cb)
-
- owner = shell.get_model().get_owner()
- if buddy.get_name() != owner.get_name():
- self._add_actions()
-
- def _get_buddy_icon_pixbuf(self):
- buddy_object = self._buddy.get_buddy()
- if not buddy_object:
- return None
-
- pixbuf = None
- icon_data = buddy_object.get_icon()
- icon_data_string = ""
- for item in icon_data:
- if item < 0:
- item = item + 128
- icon_data_string += chr(item)
- pbl = gtk.gdk.PixbufLoader()
- pbl.write(icon_data_string)
- try:
- pbl.close()
- pixbuf = pbl.get_pixbuf()
- except gobject.GError:
- pass
- del pbl
- return pixbuf
-
- def _add_actions(self):
- shell_model = self._shell.get_model()
- pservice = PresenceService.get_instance()
-
- friends = shell_model.get_friends()
- if friends.has_buddy(self._buddy):
- icon = CanvasIcon(icon_name='stock-remove')
- self.add_action(icon, BuddyMenu.ACTION_REMOVE_FRIEND)
- else:
- icon = CanvasIcon(icon_name='stock-add')
- self.add_action(icon, BuddyMenu.ACTION_MAKE_FRIEND)
-
- activity_id = shell_model.get_current_activity()
- if activity_id != None:
- activity_ps = pservice.get_activity(activity_id)
-
- # FIXME check that the buddy is not in the activity already
-
- icon = CanvasIcon(icon_name='stock-invite')
- self.add_action(icon, BuddyMenu.ACTION_INVITE)
-
- def __buddy_icon_changed_cb(self, buddy):
- pass
+ ACTION_MAKE_FRIEND = 0
+ ACTION_INVITE = 1
+ ACTION_REMOVE_FRIEND = 2
+
+ def __init__(self, shell, buddy):
+ self._buddy = buddy
+ self._shell = shell
+
+ icon_item = None
+ pixbuf = self._get_buddy_icon_pixbuf()
+ if pixbuf:
+ scaled_pixbuf = pixbuf.scale_simple(_ICON_SIZE, _ICON_SIZE,
+ gtk.gdk.INTERP_BILINEAR)
+ del pixbuf
+ icon_item = hippo.CanvasImage(pixbuf=scaled_pixbuf)
+
+ Menu.__init__(self, buddy.get_name(), icon_item)
+
+ self._buddy.connect('icon-changed', self.__buddy_icon_changed_cb)
+
+ owner = shell.get_model().get_owner()
+ if buddy.get_name() != owner.get_name():
+ self._add_actions()
+
+ def _get_buddy_icon_pixbuf(self):
+ buddy_object = self._buddy.get_buddy()
+ if not buddy_object:
+ return None
+
+ pixbuf = None
+ icon_data = buddy_object.get_icon()
+ icon_data_string = ""
+ for item in icon_data:
+ if item < 0:
+ item = item + 128
+ icon_data_string += chr(item)
+ pbl = gtk.gdk.PixbufLoader()
+ pbl.write(icon_data_string)
+ try:
+ pbl.close()
+ pixbuf = pbl.get_pixbuf()
+ except gobject.GError:
+ pass
+ del pbl
+ return pixbuf
+
+ def _add_actions(self):
+ shell_model = self._shell.get_model()
+ pservice = PresenceService.get_instance()
+
+ friends = shell_model.get_friends()
+ if friends.has_buddy(self._buddy):
+ icon = CanvasIcon(icon_name='stock-remove')
+ self.add_action(icon, BuddyMenu.ACTION_REMOVE_FRIEND)
+ else:
+ icon = CanvasIcon(icon_name='stock-add')
+ self.add_action(icon, BuddyMenu.ACTION_MAKE_FRIEND)
+
+ activity_id = shell_model.get_current_activity()
+ if activity_id != None:
+ activity_ps = pservice.get_activity(activity_id)
+
+ # FIXME check that the buddy is not in the activity already
+
+ icon = CanvasIcon(icon_name='stock-invite')
+ self.add_action(icon, BuddyMenu.ACTION_INVITE)
+
+ def __buddy_icon_changed_cb(self, buddy):
+ pass
diff --git a/shell/view/ClipboardIcon.py b/shell/view/ClipboardIcon.py
index 429fc99..41f3e09 100644
--- a/shell/view/ClipboardIcon.py
+++ b/shell/view/ClipboardIcon.py
@@ -5,34 +5,34 @@ from sugar.clipboard import ClipboardService
class ClipboardIcon(MenuIcon):
- def __init__(self, menu_shell, name, file_name):
- MenuIcon.__init__(self, menu_shell, icon_name='activity-xbook')
- self._name = name
- self._file_name = file_name
- self._percent = 0
- self.connect('activated', self._icon_activated_cb)
- self._menu = None
-
- def create_menu(self):
- self._menu = ClipboardMenu(self._name, self._percent)
- self._menu.connect('action', self._popup_action_cb)
- return self._menu
+ def __init__(self, menu_shell, name, file_name):
+ MenuIcon.__init__(self, menu_shell, icon_name='activity-xbook')
+ self._name = name
+ self._file_name = file_name
+ self._percent = 0
+ self.connect('activated', self._icon_activated_cb)
+ self._menu = None
+
+ def create_menu(self):
+ self._menu = ClipboardMenu(self._name, self._percent)
+ self._menu.connect('action', self._popup_action_cb)
+ return self._menu
- def set_percent(self, percent):
- self._percent = percent
- if self._menu:
- self._menu.set_percent(percent)
+ def set_percent(self, percent):
+ self._percent = percent
+ if self._menu:
+ self._menu.set_percent(percent)
- def _icon_activated_cb(self, icon):
- if self._percent == 100:
- activity = ActivityFactory.create("org.laptop.sugar.Xbook")
- activity.execute("open_document", [self._file_name])
+ def _icon_activated_cb(self, icon):
+ if self._percent == 100:
+ activity = ActivityFactory.create("org.laptop.sugar.Xbook")
+ activity.execute("open_document", [self._file_name])
- def _popup_action_cb(self, popup, action):
- self.popdown()
-
- if action == ClipboardMenu.ACTION_STOP_DOWNLOAD:
- raise "Stopping downloads still not implemented."
- elif action == ClipboardMenu.ACTION_DELETE:
- cb_service = ClipboardService.get_instance()
- cb_service.delete_object(self._file_name)
+ def _popup_action_cb(self, popup, action):
+ self.popdown()
+
+ if action == ClipboardMenu.ACTION_STOP_DOWNLOAD:
+ raise "Stopping downloads still not implemented."
+ elif action == ClipboardMenu.ACTION_DELETE:
+ cb_service = ClipboardService.get_instance()
+ cb_service.delete_object(self._file_name)
diff --git a/shell/view/ClipboardMenu.py b/shell/view/ClipboardMenu.py
index 44ca798..625c897 100644
--- a/shell/view/ClipboardMenu.py
+++ b/shell/view/ClipboardMenu.py
@@ -9,48 +9,48 @@ from sugar.graphics import style
class ClipboardMenuItem(ClipboardBubble):
- def __init__(self, percent = 0, stylesheet="clipboard.Bubble"):
- ClipboardBubble.__init__(self, percent = percent)
- style.apply_stylesheet(self, stylesheet)
+ def __init__(self, percent = 0, stylesheet="clipboard.Bubble"):
+ ClipboardBubble.__init__(self, percent = percent)
+ style.apply_stylesheet(self, stylesheet)
class ClipboardMenu(Menu):
- ACTION_DELETE = 0
- ACTION_SHARE = 1
- ACTION_STOP_DOWNLOAD = 2
-
- def __init__(self, name, percent):
- Menu.__init__(self, name)
-
- self._progress_bar = ClipboardMenuItem(percent)
- self._root.append(self._progress_bar)
-
- #icon = CanvasIcon(icon_name='stock-share-mesh')
- #self.add_action(icon, ClipboardMenu.ACTION_SHARE)
-
- self._remove_icon = None
- self._stop_icon = None
-
- self._create_icons(percent)
-
- def _create_icons(self, percent):
- if percent == 100:
- if not self._remove_icon:
- self._remove_icon = CanvasIcon(icon_name='stock-remove')
- self.add_action(self._remove_icon, ClipboardMenu.ACTION_DELETE)
-
- if self._stop_icon:
- self.remove_action(self._stop_icon)
- self._stop_icon = None
- else:
- if not self._stop_icon:
- self._stop_icon = CanvasIcon(icon_name='stock-close')
- self.add_action(self._stop_icon, ClipboardMenu.ACTION_STOP_DOWNLOAD)
+ ACTION_DELETE = 0
+ ACTION_SHARE = 1
+ ACTION_STOP_DOWNLOAD = 2
+
+ def __init__(self, name, percent):
+ Menu.__init__(self, name)
+
+ self._progress_bar = ClipboardMenuItem(percent)
+ self._root.append(self._progress_bar)
+
+ #icon = CanvasIcon(icon_name='stock-share-mesh')
+ #self.add_action(icon, ClipboardMenu.ACTION_SHARE)
+
+ self._remove_icon = None
+ self._stop_icon = None
+
+ self._create_icons(percent)
+
+ def _create_icons(self, percent):
+ if percent == 100:
+ if not self._remove_icon:
+ self._remove_icon = CanvasIcon(icon_name='stock-remove')
+ self.add_action(self._remove_icon, ClipboardMenu.ACTION_DELETE)
+
+ if self._stop_icon:
+ self.remove_action(self._stop_icon)
+ self._stop_icon = None
+ else:
+ if not self._stop_icon:
+ self._stop_icon = CanvasIcon(icon_name='stock-close')
+ self.add_action(self._stop_icon, ClipboardMenu.ACTION_STOP_DOWNLOAD)
- if self._remove_icon:
- self.remove_action(self._remove_icon)
- self._remove_icon = None
-
- def set_percent(self, percent):
- self._progress_bar.set_property('percent', percent)
- self._create_icons(percent)
+ if self._remove_icon:
+ self.remove_action(self._remove_icon)
+ self._remove_icon = None
+
+ def set_percent(self, percent):
+ self._progress_bar.set_property('percent', percent)
+ self._create_icons(percent)
diff --git a/shell/view/FirstTimeDialog.py b/shell/view/FirstTimeDialog.py
index 267a661..0ae82ef 100644
--- a/shell/view/FirstTimeDialog.py
+++ b/shell/view/FirstTimeDialog.py
@@ -24,47 +24,47 @@ from sugar.graphics.iconcolor import IconColor
from sugar import env
class FirstTimeDialog(gtk.Dialog):
- def __init__(self):
- gtk.Dialog.__init__(self)
+ def __init__(self):
+ gtk.Dialog.__init__(self)
- label = gtk.Label(_('Nick Name:'))
- label.set_alignment(0.0, 0.5)
- self.vbox.pack_start(label)
- label.show()
+ label = gtk.Label(_('Nick Name:'))
+ label.set_alignment(0.0, 0.5)
+ self.vbox.pack_start(label)
+ label.show()
- self._entry = gtk.Entry()
- self._entry.connect('changed', self._entry_changed_cb)
- self._entry.connect('activate', self._entry_activated_cb)
- self.vbox.pack_start(self._entry)
- self._entry.show()
+ self._entry = gtk.Entry()
+ self._entry.connect('changed', self._entry_changed_cb)
+ self._entry.connect('activate', self._entry_activated_cb)
+ self.vbox.pack_start(self._entry)
+ self._entry.show()
- self._ok = gtk.Button(None, gtk.STOCK_OK)
- self._ok.set_sensitive(False)
- self.vbox.pack_start(self._ok)
- self._ok.connect('clicked', self._ok_button_clicked_cb)
- self._ok.show()
+ self._ok = gtk.Button(None, gtk.STOCK_OK)
+ self._ok.set_sensitive(False)
+ self.vbox.pack_start(self._ok)
+ self._ok.connect('clicked', self._ok_button_clicked_cb)
+ self._ok.show()
- def _entry_changed_cb(self, entry):
- valid = (len(entry.get_text()) > 0)
- self._ok.set_sensitive(valid)
+ def _entry_changed_cb(self, entry):
+ valid = (len(entry.get_text()) > 0)
+ self._ok.set_sensitive(valid)
- def _entry_activated_cb(self, entry):
- self._create_buddy_section()
-
- def _ok_button_clicked_cb(self, button):
- self._create_buddy_section()
-
- def _create_buddy_section(self):
- cp = ConfigParser()
+ def _entry_activated_cb(self, entry):
+ self._create_buddy_section()
+
+ def _ok_button_clicked_cb(self, button):
+ self._create_buddy_section()
+
+ def _create_buddy_section(self):
+ cp = ConfigParser()
- section = 'Buddy'
- cp.add_section(section)
- cp.set(section, 'NickName', self._entry.get_text())
- cp.set(section, 'Color', IconColor().to_string())
+ section = 'Buddy'
+ cp.add_section(section)
+ cp.set(section, 'NickName', self._entry.get_text())
+ cp.set(section, 'Color', IconColor().to_string())
- config_path = os.path.join(env.get_profile_path(), 'config')
- fileobject = open(config_path, 'w')
- cp.write(fileobject)
- fileobject.close()
+ config_path = os.path.join(env.get_profile_path(), 'config')
+ fileobject = open(config_path, 'w')
+ cp.write(fileobject)
+ fileobject.close()
- self.destroy()
+ self.destroy()
diff --git a/shell/view/OverlayWindow.py b/shell/view/OverlayWindow.py
index 93719a7..7980a1d 100644
--- a/shell/view/OverlayWindow.py
+++ b/shell/view/OverlayWindow.py
@@ -19,32 +19,32 @@ import cairo
class OverlayWindow(gtk.Window):
- def __init__(self, lower_window):
- gtk.Window.__init__(self)
-
- colormap = self.get_screen().get_rgba_colormap()
- colormap=None
- if not colormap:
- raise RuntimeError("The window manager doesn't support compositing.")
- self.set_colormap(colormap)
-
- self.realize()
-
- self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
- self.window.set_accept_focus(False)
- self.window.set_transient_for(lower_window)
-
- self.set_decorated(False)
- self.set_position(gtk.WIN_POS_CENTER_ALWAYS)
- self.set_default_size(gtk.gdk.screen_width(), gtk.gdk.screen_height())
- self.set_app_paintable(True)
-
- self.connect('expose-event', self._expose_cb)
-
- def _expose_cb(self, widget, event):
- cr = widget.window.cairo_create()
- cr.set_source_rgba(0.0, 0.0, 0.0, 0.4) # Transparent
- cr.set_operator(cairo.OPERATOR_SOURCE)
- cr.paint()
- return False
+ def __init__(self, lower_window):
+ gtk.Window.__init__(self)
+
+ colormap = self.get_screen().get_rgba_colormap()
+ colormap=None
+ if not colormap:
+ raise RuntimeError("The window manager doesn't support compositing.")
+ self.set_colormap(colormap)
+
+ self.realize()
+
+ self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
+ self.window.set_accept_focus(False)
+ self.window.set_transient_for(lower_window)
+
+ self.set_decorated(False)
+ self.set_position(gtk.WIN_POS_CENTER_ALWAYS)
+ self.set_default_size(gtk.gdk.screen_width(), gtk.gdk.screen_height())
+ self.set_app_paintable(True)
+
+ self.connect('expose-event', self._expose_cb)
+
+ def _expose_cb(self, widget, event):
+ cr = widget.window.cairo_create()
+ cr.set_source_rgba(0.0, 0.0, 0.0, 0.4) # Transparent
+ cr.set_operator(cairo.OPERATOR_SOURCE)
+ cr.paint()
+ return False
diff --git a/shell/view/Shell.py b/shell/view/Shell.py
index 585f480..9166cef 100644
--- a/shell/view/Shell.py
+++ b/shell/view/Shell.py
@@ -31,206 +31,206 @@ from _sugar import KeyGrabber
import sugar
class Shell(gobject.GObject):
- __gsignals__ = {
- 'activity-opened': (gobject.SIGNAL_RUN_FIRST,
- gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])),
- 'activity-changed': (gobject.SIGNAL_RUN_FIRST,
- gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])),
- 'activity-closed': (gobject.SIGNAL_RUN_FIRST,
- gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT]))
- }
-
- def __init__(self, model):
- gobject.GObject.__init__(self)
-
- self._model = model
- self._hosts = {}
- self._screen = wnck.screen_get_default()
- self._current_host = None
-
- style.load_stylesheet(view.stylesheet)
-
- self._dcon_manager = DCONManager()
-
- self._key_grabber = KeyGrabber()
- self._key_grabber.connect('key-pressed',
- self.__global_key_pressed_cb)
- self._key_grabber.connect('key-released',
- self.__global_key_released_cb)
- self._key_grabber.grab('F1')
- self._key_grabber.grab('F2')
- self._key_grabber.grab('F3')
- self._key_grabber.grab('F4')
- self._key_grabber.grab('F5')
- self._key_grabber.grab('F6')
- self._key_grabber.grab('F7')
- self._key_grabber.grab('F8')
- self._key_grabber.grab('0xDC') # Camera key
- self._key_grabber.grab('0xE0') # Overlay key
- self._key_grabber.grab('0x93') # Frame key
-
- # For non-OLPC machines
- self._key_grabber.grab('<shft><alt>F9')
- self._key_grabber.grab('<shft><alt>F10')
- self._key_grabber.grab('<shft><alt>F11')
-
- self._home_window = HomeWindow(self)
- self._home_window.show()
- self.set_zoom_level(sugar.ZOOM_HOME)
-
- self._screen.connect('window-opened', self.__window_opened_cb)
- self._screen.connect('window-closed', self.__window_closed_cb)
- self._screen.connect('active-window-changed',
- self.__active_window_changed_cb)
-
- self._frame = Frame(self)
- self._frame.show_and_hide(3)
-
- def _open_terminal_cb(self):
- self.start_activity('org.sugar.Terminal')
- return False
-
- def __global_key_pressed_cb(self, grabber, key):
- if key == 'F1':
- self.set_zoom_level(sugar.ZOOM_MESH)
- elif key == 'F2':
- self.set_zoom_level(sugar.ZOOM_FRIENDS)
- elif key == 'F3':
- self.set_zoom_level(sugar.ZOOM_HOME)
- elif key == 'F4':
- self.set_zoom_level(sugar.ZOOM_ACTIVITY)
- elif key == 'F5':
- self._dcon_manager.decrease_brightness()
- elif key == 'F6':
- self._dcon_manager.increase_brightness()
- elif key == 'F7':
- self._dcon_manager.set_mode(DCONManager.COLOR_MODE)
- elif key == 'F8':
- self._dcon_manager.set_mode(DCONManager.BLACK_AND_WHITE_MODE)
- elif key == '<shft><alt>F9':
- self._frame.notify_key_press()
- elif key == '<shft><alt>F10':
- self.toggle_chat_visibility()
- elif key == '<shft><alt>F11':
- gobject.idle_add(self._open_terminal_cb)
- elif key == '0xDC': # Camera key
- pass
- elif key == '0xE0': # Overlay key
- self.toggle_chat_visibility()
- elif key == '0x93': # Frame key
- self._frame.notify_key_press()
-
- def __global_key_released_cb(self, grabber, key):
- if key == '<shft><alt>F9':
- self._frame.notify_key_release()
- elif key == '0x93':
- self._frame.notify_key_release()
-
- def __window_opened_cb(self, screen, window):
- if window.get_window_type() == wnck.WINDOW_NORMAL:
- activity_host = ActivityHost(self.get_model(), window)
- self._hosts[activity_host.get_xid()] = activity_host
- self.emit('activity-opened', activity_host)
-
- def __active_window_changed_cb(self, screen):
- window = screen.get_active_window()
- if not window or window.get_window_type() != wnck.WINDOW_NORMAL:
- return
- if not self._hosts.has_key(window.get_xid()):
- return
-
- activity_host = self._hosts[window.get_xid()]
- current = self._model.get_current_activity()
- if activity_host.get_id() == current:
- return
-
- self._set_current_activity(activity_host)
-
- def __window_closed_cb(self, screen, window):
- if window.get_window_type() != wnck.WINDOW_NORMAL:
- return
-
- if not self._hosts.has_key(window.get_xid()):
- return
-
- host = self._hosts[window.get_xid()]
- host.destroy()
-
- self.emit('activity-closed', host)
- del self._hosts[window.get_xid()]
-
- if len(self._hosts) == 0:
- self._set_current_activity(None)
-
- def _set_current_activity(self, host):
- if host:
- self._model.set_current_activity(host.get_id())
- else:
- self._model.set_current_activity(None)
-
- if self._current_host:
- self._current_host.set_active(False)
-
- self._current_host = host
-
- if self._current_host:
- self._current_host.set_active(True)
-
- self.emit('activity-changed', host)
-
- def get_model(self):
- return self._model
-
- def join_activity(self, bundle_id, activity_id):
- pservice = PresenceService.get_instance()
-
- activity = self._get_activity(activity_id)
- if activity:
- activity.present()
- else:
- activity_ps = pservice.get_activity(activity_id)
-
- if activity_ps:
- activity = ActivityFactory.create(bundle_id)
- activity.join(activity_ps.object_path())
- else:
- logging.error('Cannot start activity.')
-
- def start_activity(self, activity_type):
- activity = ActivityFactory.create(activity_type)
- activity.execute('test', [])
- return activity
-
- def set_zoom_level(self, level):
- if level == sugar.ZOOM_ACTIVITY:
- self._screen.toggle_showing_desktop(False)
- else:
- self._screen.toggle_showing_desktop(True)
- self._home_window.set_zoom_level(level)
-
- def get_current_activity(self):
- activity_id = self._model.get_current_activity()
- if activity_id:
- return self._get_activity(activity_id)
- else:
- return None
-
- def _get_activity(self, activity_id):
- for host in self._hosts.values():
- if host.get_id() == activity_id:
- return host
- return None
-
- def toggle_chat_visibility(self):
- act = self.get_current_activity()
- if not act:
- return
- is_visible = self._frame.is_visible()
- if act.is_chat_visible():
- frame_was_visible = act.chat_hide()
- if not frame_was_visible:
- self._frame.do_slide_out()
- else:
- if not is_visible:
- self._frame.do_slide_in()
- act.chat_show(is_visible)
+ __gsignals__ = {
+ 'activity-opened': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])),
+ 'activity-changed': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])),
+ 'activity-closed': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT]))
+ }
+
+ def __init__(self, model):
+ gobject.GObject.__init__(self)
+
+ self._model = model
+ self._hosts = {}
+ self._screen = wnck.screen_get_default()
+ self._current_host = None
+
+ style.load_stylesheet(view.stylesheet)
+
+ self._dcon_manager = DCONManager()
+
+ self._key_grabber = KeyGrabber()
+ self._key_grabber.connect('key-pressed',
+ self.__global_key_pressed_cb)
+ self._key_grabber.connect('key-released',
+ self.__global_key_released_cb)
+ self._key_grabber.grab('F1')
+ self._key_grabber.grab('F2')
+ self._key_grabber.grab('F3')
+ self._key_grabber.grab('F4')
+ self._key_grabber.grab('F5')
+ self._key_grabber.grab('F6')
+ self._key_grabber.grab('F7')
+ self._key_grabber.grab('F8')
+ self._key_grabber.grab('0xDC') # Camera key
+ self._key_grabber.grab('0xE0') # Overlay key
+ self._key_grabber.grab('0x93') # Frame key
+
+ # For non-OLPC machines
+ self._key_grabber.grab('<shft><alt>F9')
+ self._key_grabber.grab('<shft><alt>F10')
+ self._key_grabber.grab('<shft><alt>F11')
+
+ self._home_window = HomeWindow(self)
+ self._home_window.show()
+ self.set_zoom_level(sugar.ZOOM_HOME)
+
+ self._screen.connect('window-opened', self.__window_opened_cb)
+ self._screen.connect('window-closed', self.__window_closed_cb)
+ self._screen.connect('active-window-changed',
+ self.__active_window_changed_cb)
+
+ self._frame = Frame(self)
+ self._frame.show_and_hide(3)
+
+ def _open_terminal_cb(self):
+ self.start_activity('org.sugar.Terminal')
+ return False
+
+ def __global_key_pressed_cb(self, grabber, key):
+ if key == 'F1':
+ self.set_zoom_level(sugar.ZOOM_MESH)
+ elif key == 'F2':
+ self.set_zoom_level(sugar.ZOOM_FRIENDS)
+ elif key == 'F3':
+ self.set_zoom_level(sugar.ZOOM_HOME)
+ elif key == 'F4':
+ self.set_zoom_level(sugar.ZOOM_ACTIVITY)
+ elif key == 'F5':
+ self._dcon_manager.decrease_brightness()
+ elif key == 'F6':
+ self._dcon_manager.increase_brightness()
+ elif key == 'F7':
+ self._dcon_manager.set_mode(DCONManager.COLOR_MODE)
+ elif key == 'F8':
+ self._dcon_manager.set_mode(DCONManager.BLACK_AND_WHITE_MODE)
+ elif key == '<shft><alt>F9':
+ self._frame.notify_key_press()
+ elif key == '<shft><alt>F10':
+ self.toggle_chat_visibility()
+ elif key == '<shft><alt>F11':
+ gobject.idle_add(self._open_terminal_cb)
+ elif key == '0xDC': # Camera key
+ pass
+ elif key == '0xE0': # Overlay key
+ self.toggle_chat_visibility()
+ elif key == '0x93': # Frame key
+ self._frame.notify_key_press()
+
+ def __global_key_released_cb(self, grabber, key):
+ if key == '<shft><alt>F9':
+ self._frame.notify_key_release()
+ elif key == '0x93':
+ self._frame.notify_key_release()
+
+ def __window_opened_cb(self, screen, window):
+ if window.get_window_type() == wnck.WINDOW_NORMAL:
+ activity_host = ActivityHost(self.get_model(), window)
+ self._hosts[activity_host.get_xid()] = activity_host
+ self.emit('activity-opened', activity_host)
+
+ def __active_window_changed_cb(self, screen):
+ window = screen.get_active_window()
+ if not window or window.get_window_type() != wnck.WINDOW_NORMAL:
+ return
+ if not self._hosts.has_key(window.get_xid()):
+ return
+
+ activity_host = self._hosts[window.get_xid()]
+ current = self._model.get_current_activity()
+ if activity_host.get_id() == current:
+ return
+
+ self._set_current_activity(activity_host)
+
+ def __window_closed_cb(self, screen, window):
+ if window.get_window_type() != wnck.WINDOW_NORMAL:
+ return
+
+ if not self._hosts.has_key(window.get_xid()):
+ return
+
+ host = self._hosts[window.get_xid()]
+ host.destroy()
+
+ self.emit('activity-closed', host)
+ del self._hosts[window.get_xid()]
+
+ if len(self._hosts) == 0:
+ self._set_current_activity(None)
+
+ def _set_current_activity(self, host):
+ if host:
+ self._model.set_current_activity(host.get_id())
+ else:
+ self._model.set_current_activity(None)
+
+ if self._current_host:
+ self._current_host.set_active(False)
+
+ self._current_host = host
+
+ if self._current_host:
+ self._current_host.set_active(True)
+
+ self.emit('activity-changed', host)
+
+ def get_model(self):
+ return self._model
+
+ def join_activity(self, bundle_id, activity_id):
+ pservice = PresenceService.get_instance()
+
+ activity = self._get_activity(activity_id)
+ if activity:
+ activity.present()
+ else:
+ activity_ps = pservice.get_activity(activity_id)
+
+ if activity_ps:
+ activity = ActivityFactory.create(bundle_id)
+ activity.join(activity_ps.object_path())
+ else:
+ logging.error('Cannot start activity.')
+
+ def start_activity(self, activity_type):
+ activity = ActivityFactory.create(activity_type)
+ activity.execute('test', [])
+ return activity
+
+ def set_zoom_level(self, level):
+ if level == sugar.ZOOM_ACTIVITY:
+ self._screen.toggle_showing_desktop(False)
+ else:
+ self._screen.toggle_showing_desktop(True)
+ self._home_window.set_zoom_level(level)
+
+ def get_current_activity(self):
+ activity_id = self._model.get_current_activity()
+ if activity_id:
+ return self._get_activity(activity_id)
+ else:
+ return None
+
+ def _get_activity(self, activity_id):
+ for host in self._hosts.values():
+ if host.get_id() == activity_id:
+ return host
+ return None
+
+ def toggle_chat_visibility(self):
+ act = self.get_current_activity()
+ if not act:
+ return
+ is_visible = self._frame.is_visible()
+ if act.is_chat_visible():
+ frame_was_visible = act.chat_hide()
+ if not frame_was_visible:
+ self._frame.do_slide_out()
+ else:
+ if not is_visible:
+ self._frame.do_slide_in()
+ act.chat_show(is_visible)
diff --git a/shell/view/dconmanager.py b/shell/view/dconmanager.py
index 2cf40b5..2db626a 100644
--- a/shell/view/dconmanager.py
+++ b/shell/view/dconmanager.py
@@ -21,23 +21,23 @@ DCON_MANAGER_SERVICE = 'org.laptop.DCONManager'
DCON_MANAGER_OBJECT_PATH = '/org/laptop/DCONManager'
class DCONManager(object):
- COLOR_MODE = 0
- BLACK_AND_WHITE_MODE = 1
+ COLOR_MODE = 0
+ BLACK_AND_WHITE_MODE = 1
- def __init__(self):
- bus = dbus.SystemBus()
- proxy = bus.get_object(DCON_MANAGER_SERVICE, DCON_MANAGER_OBJECT_PATH)
- self._service = dbus.Interface(proxy, DCON_MANAGER_INTERFACE)
+ def __init__(self):
+ bus = dbus.SystemBus()
+ proxy = bus.get_object(DCON_MANAGER_SERVICE, DCON_MANAGER_OBJECT_PATH)
+ self._service = dbus.Interface(proxy, DCON_MANAGER_INTERFACE)
- def set_mode(self, mode):
- self._service.set_mode(mode)
+ def set_mode(self, mode):
+ self._service.set_mode(mode)
- def increase_brightness(self):
- level = self._service.get_backlight_level()
- if level >= 0:
- self._service.set_backlight_level(level + 1)
+ def increase_brightness(self):
+ level = self._service.get_backlight_level()
+ if level >= 0:
+ self._service.set_backlight_level(level + 1)
- def decrease_brightness(self):
- level = self._service.get_backlight_level()
- if level >= 0:
- self._service.set_backlight_level(level - 1)
+ def decrease_brightness(self):
+ level = self._service.get_backlight_level()
+ if level >= 0:
+ self._service.set_backlight_level(level - 1)
diff --git a/shell/view/frame/ActivitiesBox.py b/shell/view/frame/ActivitiesBox.py
index 2e3a75a..aa96585 100644
--- a/shell/view/frame/ActivitiesBox.py
+++ b/shell/view/frame/ActivitiesBox.py
@@ -22,80 +22,80 @@ from sugar.presence import PresenceService
from sugar.graphics import style
class ActivityItem(CanvasIcon):
- def __init__(self, activity):
- icon_name = activity.get_icon()
- CanvasIcon.__init__(self, icon_name=icon_name)
- style.apply_stylesheet(self, 'frame.ActivityIcon')
- self._activity = activity
+ def __init__(self, activity):
+ icon_name = activity.get_icon()
+ CanvasIcon.__init__(self, icon_name=icon_name)
+ style.apply_stylesheet(self, 'frame.ActivityIcon')
+ self._activity = activity
- def get_bundle_id(self):
- return self._activity.get_service_name()
+ def get_bundle_id(self):
+ return self._activity.get_service_name()
class InviteItem(CanvasIcon):
- def __init__(self, activity, invite):
- CanvasIcon.__init__(self, icon_name=activity.get_icon())
+ def __init__(self, activity, invite):
+ CanvasIcon.__init__(self, icon_name=activity.get_icon())
- style.apply_stylesheet(self, 'frame.ActivityIcon')
- self.props.color = activity.get_color()
+ style.apply_stylesheet(self, 'frame.ActivityIcon')
+ self.props.color = activity.get_color()
- self._invite = invite
+ self._invite = invite
- def get_activity_id(self):
- return self._invite.get_activity_id()
+ def get_activity_id(self):
+ return self._invite.get_activity_id()
- def get_bundle_id(self):
- return self._invite.get_bundle_id()
+ def get_bundle_id(self):
+ return self._invite.get_bundle_id()
- def get_invite(self):
- return self._invite
+ def get_invite(self):
+ return self._invite
class ActivitiesBox(hippo.CanvasBox):
- def __init__(self, shell):
- hippo.CanvasBox.__init__(self, orientation=hippo.ORIENTATION_HORIZONTAL)
-
- self._shell = shell
- self._shell_model = self._shell.get_model()
- self._invite_to_item = {}
- self._invites = self._shell_model.get_invites()
-
- for bundle in self._shell_model.get_bundle_registry():
- if bundle.get_show_launcher():
- self.add_activity(bundle)
-
- for invite in self._invites:
- self.add_invite(invite)
- self._invites.connect('invite-added', self._invite_added_cb)
- self._invites.connect('invite-removed', self._invite_removed_cb)
-
- def _activity_clicked_cb(self, icon):
- self._shell.start_activity(icon.get_bundle_id())
-
- def _invite_clicked_cb(self, icon):
- self._invites.remove_invite(icon.get_invite())
- self._shell.join_activity(icon.get_bundle_id(),
- icon.get_activity_id())
-
- def _invite_added_cb(self, invites, invite):
- self.add_invite(invite)
-
- def _invite_removed_cb(self, invites, invite):
- self.remove_invite(invite)
-
- def add_activity(self, activity):
- item = ActivityItem(activity)
- item.connect('activated', self._activity_clicked_cb)
- self.append(item, 0)
-
- def add_invite(self, invite):
- mesh = self._shell_model.get_mesh()
- activity = mesh.get_activity(invite.get_activity_id())
- if activity:
- item = InviteItem(activity, invite)
- item.connect('activated', self._invite_clicked_cb)
- self.append(item, 0)
-
- self._invite_to_item[invite] = item
-
- def remove_invite(self, invite):
- self.remove(self._invite_to_item[invite])
- del self._invite_to_item[invite]
+ def __init__(self, shell):
+ hippo.CanvasBox.__init__(self, orientation=hippo.ORIENTATION_HORIZONTAL)
+
+ self._shell = shell
+ self._shell_model = self._shell.get_model()
+ self._invite_to_item = {}
+ self._invites = self._shell_model.get_invites()
+
+ for bundle in self._shell_model.get_bundle_registry():
+ if bundle.get_show_launcher():
+ self.add_activity(bundle)
+
+ for invite in self._invites:
+ self.add_invite(invite)
+ self._invites.connect('invite-added', self._invite_added_cb)
+ self._invites.connect('invite-removed', self._invite_removed_cb)
+
+ def _activity_clicked_cb(self, icon):
+ self._shell.start_activity(icon.get_bundle_id())
+
+ def _invite_clicked_cb(self, icon):
+ self._invites.remove_invite(icon.get_invite())
+ self._shell.join_activity(icon.get_bundle_id(),
+ icon.get_activity_id())
+
+ def _invite_added_cb(self, invites, invite):
+ self.add_invite(invite)
+
+ def _invite_removed_cb(self, invites, invite):
+ self.remove_invite(invite)
+
+ def add_activity(self, activity):
+ item = ActivityItem(activity)
+ item.connect('activated', self._activity_clicked_cb)
+ self.append(item, 0)
+
+ def add_invite(self, invite):
+ mesh = self._shell_model.get_mesh()
+ activity = mesh.get_activity(invite.get_activity_id())
+ if activity:
+ item = InviteItem(activity, invite)
+ item.connect('activated', self._invite_clicked_cb)
+ self.append(item, 0)
+
+ self._invite_to_item[invite] = item
+
+ def remove_invite(self, invite):
+ self.remove(self._invite_to_item[invite])
+ del self._invite_to_item[invite]
diff --git a/shell/view/frame/ClipboardBox.py b/shell/view/frame/ClipboardBox.py
index 849c7e0..82dccb6 100644
--- a/shell/view/frame/ClipboardBox.py
+++ b/shell/view/frame/ClipboardBox.py
@@ -7,36 +7,36 @@ from view.ClipboardIcon import ClipboardIcon
from sugar.clipboard import ClipboardService
class ClipboardBox(hippo.CanvasBox):
-
- def __init__(self, frame, menu_shell):
- hippo.CanvasBox.__init__(self)
- self._frame = frame
- self._menu_shell = menu_shell
- self._icons = {}
-
- cb_service = ClipboardService.get_instance()
- cb_service.connect('object-added', self._object_added_cb)
- cb_service.connect('object-deleted', self._object_deleted_cb)
- cb_service.connect('object-state-changed', self._object_state_changed_cb)
+
+ def __init__(self, frame, menu_shell):
+ hippo.CanvasBox.__init__(self)
+ self._frame = frame
+ self._menu_shell = menu_shell
+ self._icons = {}
+
+ cb_service = ClipboardService.get_instance()
+ cb_service.connect('object-added', self._object_added_cb)
+ cb_service.connect('object-deleted', self._object_deleted_cb)
+ cb_service.connect('object-state-changed', self._object_state_changed_cb)
- def _object_added_cb(self, cb_service, name, mimeType, fileName):
- icon = ClipboardIcon(self._menu_shell, name, fileName)
- style.apply_stylesheet(icon, 'frame.BuddyIcon')
- self.append(icon)
- self._icons[fileName] = icon
-
- if not self._frame.is_visible():
- self._frame.show_and_hide(0.1)
-
- logging.debug('ClipboardBox: ' + fileName + ' was added.')
+ def _object_added_cb(self, cb_service, name, mimeType, fileName):
+ icon = ClipboardIcon(self._menu_shell, name, fileName)
+ style.apply_stylesheet(icon, 'frame.BuddyIcon')
+ self.append(icon)
+ self._icons[fileName] = icon
+
+ if not self._frame.is_visible():
+ self._frame.show_and_hide(0.1)
+
+ logging.debug('ClipboardBox: ' + fileName + ' was added.')
- def _object_deleted_cb(self, cb_service, fileName):
- icon = self._icons[fileName]
- self.remove(icon)
- del self._icons[fileName]
- logging.debug('ClipboardBox: ' + fileName + ' was deleted.')
+ def _object_deleted_cb(self, cb_service, fileName):
+ icon = self._icons[fileName]
+ self.remove(icon)
+ del self._icons[fileName]
+ logging.debug('ClipboardBox: ' + fileName + ' was deleted.')
- def _object_state_changed_cb(self, cb_service, fileName, percent):
- icon = self._icons[fileName]
- icon.set_percent(percent)
- logging.debug('ClipboardBox: ' + fileName + ' state was changed.')
+ def _object_state_changed_cb(self, cb_service, fileName, percent):
+ icon = self._icons[fileName]
+ icon.set_percent(percent)
+ logging.debug('ClipboardBox: ' + fileName + ' state was changed.')
diff --git a/shell/view/frame/Frame.py b/shell/view/frame/Frame.py
index 37f28cb..c865219 100644
--- a/shell/view/frame/Frame.py
+++ b/shell/view/frame/Frame.py
@@ -32,268 +32,268 @@ from sugar.graphics.grid import Grid
from sugar.graphics.menushell import MenuShell
class EventFrame(gobject.GObject):
- __gsignals__ = {
- 'enter-edge': (gobject.SIGNAL_RUN_FIRST,
- gobject.TYPE_NONE, ([])),
- 'enter-corner': (gobject.SIGNAL_RUN_FIRST,
- gobject.TYPE_NONE, ([])),
- 'leave': (gobject.SIGNAL_RUN_FIRST,
- gobject.TYPE_NONE, ([]))
- }
-
- HOVER_NONE = 0
- HOVER_CORNER = 1
- HOVER_EDGE = 2
-
- def __init__(self):
- gobject.GObject.__init__(self)
-
- self._windows = []
- self._hover = EventFrame.HOVER_NONE
- self._active = False
-
- invisible = self._create_invisible(0, 0, gtk.gdk.screen_width(), 1)
- self._windows.append(invisible)
-
- invisible = self._create_invisible(0, 0, 1, gtk.gdk.screen_height())
- self._windows.append(invisible)
-
- invisible = self._create_invisible(gtk.gdk.screen_width() - 1, 0,
- gtk.gdk.screen_width(),
- gtk.gdk.screen_height())
- self._windows.append(invisible)
-
- invisible = self._create_invisible(0, gtk.gdk.screen_height() - 1,
- gtk.gdk.screen_width(),
- gtk.gdk.screen_height())
- self._windows.append(invisible)
-
- screen = wnck.screen_get_default()
- screen.connect('active-window-changed',
- self._active_window_changed_cb)
-
- def _create_invisible(self, x, y, width, height):
- invisible = gtk.Invisible()
- invisible.connect('motion-notify-event', self._motion_notify_cb)
- invisible.connect('enter-notify-event', self._enter_notify_cb)
- invisible.connect('leave-notify-event', self._leave_notify_cb)
-
- invisible.realize()
- invisible.window.set_events(gtk.gdk.POINTER_MOTION_MASK |
- gtk.gdk.ENTER_NOTIFY_MASK |
- gtk.gdk.LEAVE_NOTIFY_MASK)
- invisible.window.move_resize(x, y, width, height)
-
- return invisible
-
- def _enter_notify_cb(self, widget, event):
- self._notify_enter(event.x, event.y)
-
- def _motion_notify_cb(self, widget, event):
- self._notify_enter(event.x, event.y)
-
- def _notify_enter(self, x, y):
- screen_w = gtk.gdk.screen_width()
- screen_h = gtk.gdk.screen_height()
-
- if (x == 0 and y == 0) or \
- (x == 0 and y == screen_h - 1) or \
- (x == screen_w - 1 and y == 0) or \
- (x == screen_w - 1 and y == screen_h - 1):
- if self._hover != EventFrame.HOVER_CORNER:
- self._hover = EventFrame.HOVER_CORNER
- self.emit('enter-corner')
- else:
- if self._hover != EventFrame.HOVER_EDGE:
- self._hover = EventFrame.HOVER_EDGE
- self.emit('enter-edge')
-
- def _leave_notify_cb(self, widget, event):
- self._hover = EventFrame.HOVER_NONE
- if self._active:
- self.emit('leave')
-
- def show(self):
- self._active = True
- for window in self._windows:
- window.show()
-
- def hide(self):
- self._active = False
- for window in self._windows:
- window.hide()
-
- def _active_window_changed_cb(self, screen):
- for window in self._windows:
- window.window.raise_()
+ __gsignals__ = {
+ 'enter-edge': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([])),
+ 'enter-corner': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([])),
+ 'leave': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([]))
+ }
+
+ HOVER_NONE = 0
+ HOVER_CORNER = 1
+ HOVER_EDGE = 2
+
+ def __init__(self):
+ gobject.GObject.__init__(self)
+
+ self._windows = []
+ self._hover = EventFrame.HOVER_NONE
+ self._active = False
+
+ invisible = self._create_invisible(0, 0, gtk.gdk.screen_width(), 1)
+ self._windows.append(invisible)
+
+ invisible = self._create_invisible(0, 0, 1, gtk.gdk.screen_height())
+ self._windows.append(invisible)
+
+ invisible = self._create_invisible(gtk.gdk.screen_width() - 1, 0,
+ gtk.gdk.screen_width(),
+ gtk.gdk.screen_height())
+ self._windows.append(invisible)
+
+ invisible = self._create_invisible(0, gtk.gdk.screen_height() - 1,
+ gtk.gdk.screen_width(),
+ gtk.gdk.screen_height())
+ self._windows.append(invisible)
+
+ screen = wnck.screen_get_default()
+ screen.connect('active-window-changed',
+ self._active_window_changed_cb)
+
+ def _create_invisible(self, x, y, width, height):
+ invisible = gtk.Invisible()
+ invisible.connect('motion-notify-event', self._motion_notify_cb)
+ invisible.connect('enter-notify-event', self._enter_notify_cb)
+ invisible.connect('leave-notify-event', self._leave_notify_cb)
+
+ invisible.realize()
+ invisible.window.set_events(gtk.gdk.POINTER_MOTION_MASK |
+ gtk.gdk.ENTER_NOTIFY_MASK |
+ gtk.gdk.LEAVE_NOTIFY_MASK)
+ invisible.window.move_resize(x, y, width, height)
+
+ return invisible
+
+ def _enter_notify_cb(self, widget, event):
+ self._notify_enter(event.x, event.y)
+
+ def _motion_notify_cb(self, widget, event):
+ self._notify_enter(event.x, event.y)
+
+ def _notify_enter(self, x, y):
+ screen_w = gtk.gdk.screen_width()
+ screen_h = gtk.gdk.screen_height()
+
+ if (x == 0 and y == 0) or \
+ (x == 0 and y == screen_h - 1) or \
+ (x == screen_w - 1 and y == 0) or \
+ (x == screen_w - 1 and y == screen_h - 1):
+ if self._hover != EventFrame.HOVER_CORNER:
+ self._hover = EventFrame.HOVER_CORNER
+ self.emit('enter-corner')
+ else:
+ if self._hover != EventFrame.HOVER_EDGE:
+ self._hover = EventFrame.HOVER_EDGE
+ self.emit('enter-edge')
+
+ def _leave_notify_cb(self, widget, event):
+ self._hover = EventFrame.HOVER_NONE
+ if self._active:
+ self.emit('leave')
+
+ def show(self):
+ self._active = True
+ for window in self._windows:
+ window.show()
+
+ def hide(self):
+ self._active = False
+ for window in self._windows:
+ window.hide()
+
+ def _active_window_changed_cb(self, screen):
+ for window in self._windows:
+ window.window.raise_()
class Frame:
- INACTIVE = 0
- TEMPORARY = 1
- STICKY = 2
- HIDE_ON_LEAVE = 3
- AUTOMATIC = 4
+ INACTIVE = 0
+ TEMPORARY = 1
+ STICKY = 2
+ HIDE_ON_LEAVE = 3
+ AUTOMATIC = 4
- def __init__(self, shell):
- self._windows = []
- self._active_menus = 0
- self._shell = shell
- self._mode = Frame.INACTIVE
+ def __init__(self, shell):
+ self._windows = []
+ self._active_menus = 0
+ self._shell = shell
+ self._mode = Frame.INACTIVE
- self._timeline = Timeline(self)
- self._timeline.add_tag('slide_in', 6, 12)
- self._timeline.add_tag('before_slide_out', 36, 36)
- self._timeline.add_tag('slide_out', 37, 42)
+ self._timeline = Timeline(self)
+ self._timeline.add_tag('slide_in', 6, 12)
+ self._timeline.add_tag('before_slide_out', 36, 36)
+ self._timeline.add_tag('slide_out', 37, 42)
- self._event_frame = EventFrame()
- self._event_frame.connect('enter-edge', self._enter_edge_cb)
- self._event_frame.connect('enter-corner', self._enter_corner_cb)
- self._event_frame.connect('leave', self._event_frame_leave_cb)
- self._event_frame.show()
+ self._event_frame = EventFrame()
+ self._event_frame.connect('enter-edge', self._enter_edge_cb)
+ self._event_frame.connect('enter-corner', self._enter_corner_cb)
+ self._event_frame.connect('leave', self._event_frame_leave_cb)
+ self._event_frame.show()
- grid = Grid()
+ grid = Grid()
- # Top panel
- [menu_shell, root] = self._create_panel(grid, 0, 0, 16, 1)
- menu_shell.set_position(MenuShell.BOTTOM)
+ # Top panel
+ [menu_shell, root] = self._create_panel(grid, 0, 0, 16, 1)
+ menu_shell.set_position(MenuShell.BOTTOM)
- box = ZoomBox(self._shell, menu_shell)
+ box = ZoomBox(self._shell, menu_shell)
- [x, y] = grid.point(1, 0)
- root.append(box, hippo.PACK_FIXED)
- root.move(box, x, y)
+ [x, y] = grid.point(1, 0)
+ root.append(box, hippo.PACK_FIXED)
+ root.move(box, x, y)
- tray = NotificationTray()
- tray_box = hippo.CanvasBox(box_width=grid.dimension(1),
- box_height=grid.dimension(1),
- xalign=hippo.ALIGNMENT_END)
+ tray = NotificationTray()
+ tray_box = hippo.CanvasBox(box_width=grid.dimension(1),
+ box_height=grid.dimension(1),
+ xalign=hippo.ALIGNMENT_END)
- tray_widget = hippo.CanvasWidget()
- tray_widget.props.widget = tray
- tray_box.append(tray_widget, gtk.EXPAND)
+ tray_widget = hippo.CanvasWidget()
+ tray_widget.props.widget = tray
+ tray_box.append(tray_widget, gtk.EXPAND)
- [x, y] = grid.point(13, 0)
- root.append(tray_box, hippo.PACK_FIXED)
- root.move(tray_box, x, y)
+ [x, y] = grid.point(13, 0)
+ root.append(tray_box, hippo.PACK_FIXED)
+ root.move(tray_box, x, y)
- box = OverlayBox(self._shell)
+ box = OverlayBox(self._shell)
- [x, y] = grid.point(14, 0)
- root.append(box, hippo.PACK_FIXED)
- root.move(box, x, y)
+ [x, y] = grid.point(14, 0)
+ root.append(box, hippo.PACK_FIXED)
+ root.move(box, x, y)
- shutdown_icon = ShutdownIcon(menu_shell)
+ shutdown_icon = ShutdownIcon(menu_shell)
- [x, y] = grid.point(12, 0)
- root.append(shutdown_icon, hippo.PACK_FIXED)
- root.move(shutdown_icon, x, y)
+ [x, y] = grid.point(12, 0)
+ root.append(shutdown_icon, hippo.PACK_FIXED)
+ root.move(shutdown_icon, x, y)
- # Bottom panel
- [menu_shell, root] = self._create_panel(grid, 0, 11, 16, 1)
- menu_shell.set_position(MenuShell.TOP)
+ # Bottom panel
+ [menu_shell, root] = self._create_panel(grid, 0, 11, 16, 1)
+ menu_shell.set_position(MenuShell.TOP)
- box = ActivitiesBox(self._shell)
- root.append(box, hippo.PACK_FIXED)
+ box = ActivitiesBox(self._shell)
+ root.append(box, hippo.PACK_FIXED)
- [x, y] = grid.point(1, 0)
- root.move(box, x, y)
+ [x, y] = grid.point(1, 0)
+ root.move(box, x, y)
- # Right panel
- [menu_shell, root] = self._create_panel(grid, 15, 1, 1, 10)
- menu_shell.set_position(MenuShell.LEFT)
+ # Right panel
+ [menu_shell, root] = self._create_panel(grid, 15, 1, 1, 10)
+ menu_shell.set_position(MenuShell.LEFT)
- box = FriendsBox(self._shell, menu_shell)
- root.append(box)
+ box = FriendsBox(self._shell, menu_shell)
+ root.append(box)
- # Left panel
- [menu_shell, root] = self._create_panel(grid, 0, 1, 1, 10)
+ # Left panel
+ [menu_shell, root] = self._create_panel(grid, 0, 1, 1, 10)
- box = ClipboardBox(self, menu_shell)
- root.append(box)
+ box = ClipboardBox(self, menu_shell)
+ root.append(box)
- def _create_panel(self, grid, x, y, width, height):
- panel = PanelWindow()
+ def _create_panel(self, grid, x, y, width, height):
+ panel = PanelWindow()
- panel.connect('enter-notify-event', self._enter_notify_cb)
- panel.connect('leave-notify-event', self._leave_notify_cb)
+ panel.connect('enter-notify-event', self._enter_notify_cb)
+ panel.connect('leave-notify-event', self._leave_notify_cb)
- menu_shell = panel.get_menu_shell()
- menu_shell.connect('activated', self._menu_shell_activated_cb)
- menu_shell.connect('deactivated', self._menu_shell_deactivated_cb)
+ menu_shell = panel.get_menu_shell()
+ menu_shell.connect('activated', self._menu_shell_activated_cb)
+ menu_shell.connect('deactivated', self._menu_shell_deactivated_cb)
- [x, y, width, height] = grid.rectangle(x, y, width, height)
+ [x, y, width, height] = grid.rectangle(x, y, width, height)
- panel.move(x, y)
- panel.resize(width, height)
+ panel.move(x, y)
+ panel.resize(width, height)
- self._windows.append(panel)
+ self._windows.append(panel)
- return [panel.get_menu_shell(), panel.get_root()]
+ return [panel.get_menu_shell(), panel.get_root()]
- def _menu_shell_activated_cb(self, menu_shell):
- self._active_menus += 1
- self._timeline.goto('slide_in', True)
+ def _menu_shell_activated_cb(self, menu_shell):
+ self._active_menus += 1
+ self._timeline.goto('slide_in', True)
- def _menu_shell_deactivated_cb(self, menu_shell):
- self._active_menus -= 1
- if self._mode != Frame.STICKY:
- self._timeline.play('before_slide_out', 'slide_out')
+ def _menu_shell_deactivated_cb(self, menu_shell):
+ self._active_menus -= 1
+ if self._mode != Frame.STICKY:
+ self._timeline.play('before_slide_out', 'slide_out')
- def _enter_notify_cb(self, window, event):
- self._timeline.goto('slide_in', True)
+ def _enter_notify_cb(self, window, event):
+ self._timeline.goto('slide_in', True)
- def _leave_notify_cb(self, window, event):
- # FIXME for some reason every click cause also a leave-notify
- if event.state == gtk.gdk.BUTTON1_MASK:
- return
+ def _leave_notify_cb(self, window, event):
+ # FIXME for some reason every click cause also a leave-notify
+ if event.state == gtk.gdk.BUTTON1_MASK:
+ return
- if self._active_menus == 0 and \
- (self._mode == Frame.HIDE_ON_LEAVE or \
- self._mode == Frame.AUTOMATIC):
- self._timeline.play('before_slide_out', 'slide_out')
+ if self._active_menus == 0 and \
+ (self._mode == Frame.HIDE_ON_LEAVE or \
+ self._mode == Frame.AUTOMATIC):
+ self._timeline.play('before_slide_out', 'slide_out')
- def _enter_edge_cb(self, event_frame):
- self._mode = Frame.HIDE_ON_LEAVE
- self._timeline.play(None, 'slide_in')
+ def _enter_edge_cb(self, event_frame):
+ self._mode = Frame.HIDE_ON_LEAVE
+ self._timeline.play(None, 'slide_in')
- def _enter_corner_cb(self, event_frame):
- self._mode = Frame.HIDE_ON_LEAVE
- self._timeline.play('slide_in', 'slide_in')
+ def _enter_corner_cb(self, event_frame):
+ self._mode = Frame.HIDE_ON_LEAVE
+ self._timeline.play('slide_in', 'slide_in')
- def _event_frame_leave_cb(self, event_frame):
- if self._mode != Frame.STICKY:
- self._timeline.goto('slide_out', True)
+ def _event_frame_leave_cb(self, event_frame):
+ if self._mode != Frame.STICKY:
+ self._timeline.goto('slide_out', True)
- def show_and_hide(self, seconds):
- self._mode = Frame.AUTOMATIC
- self._timeline.play()
+ def show_and_hide(self, seconds):
+ self._mode = Frame.AUTOMATIC
+ self._timeline.play()
- def notify_key_press(self):
- if self._timeline.on_tag('slide_in'):
- self._timeline.play('before_slide_out', 'slide_out')
- elif self._timeline.on_tag('before_slide_out'):
- self._mode = Frame.TEMPORARY
- else:
- self._mode = Frame.STICKY
- self._timeline.play('slide_in', 'slide_in')
+ def notify_key_press(self):
+ if self._timeline.on_tag('slide_in'):
+ self._timeline.play('before_slide_out', 'slide_out')
+ elif self._timeline.on_tag('before_slide_out'):
+ self._mode = Frame.TEMPORARY
+ else:
+ self._mode = Frame.STICKY
+ self._timeline.play('slide_in', 'slide_in')
- def notify_key_release(self):
- if self._mode == Frame.TEMPORARY:
- self._timeline.play('before_slide_out', 'slide_out')
+ def notify_key_release(self):
+ if self._mode == Frame.TEMPORARY:
+ self._timeline.play('before_slide_out', 'slide_out')
- def do_slide_in(self, current=0, n_frames=0):
- if not self._windows[0].props.visible:
- for panel in self._windows:
- panel.show()
- self._event_frame.hide()
+ def do_slide_in(self, current=0, n_frames=0):
+ if not self._windows[0].props.visible:
+ for panel in self._windows:
+ panel.show()
+ self._event_frame.hide()
- def do_slide_out(self, current=0, n_frames=0):
- if self._windows[0].props.visible:
- for panel in self._windows:
- panel.hide()
- self._event_frame.show()
+ def do_slide_out(self, current=0, n_frames=0):
+ if self._windows[0].props.visible:
+ for panel in self._windows:
+ panel.hide()
+ self._event_frame.show()
- def is_visible(self):
- if self._windows[0].props.visible:
- return True
- return False
+ def is_visible(self):
+ if self._windows[0].props.visible:
+ return True
+ return False
diff --git a/shell/view/frame/FriendsBox.py b/shell/view/frame/FriendsBox.py
index 14f1290..cdc07ad 100644
--- a/shell/view/frame/FriendsBox.py
+++ b/shell/view/frame/FriendsBox.py
@@ -24,85 +24,85 @@ from view.BuddyIcon import BuddyIcon
from model.BuddyModel import BuddyModel
class FriendsBox(hippo.CanvasBox):
- def __init__(self, shell, menu_shell):
- hippo.CanvasBox.__init__(self)
- self._shell = shell
- self._menu_shell = menu_shell
- self._activity_ps = None
- self._joined_hid = -1
- self._left_hid = -1
- self._buddies = {}
-
- self._pservice = PresenceService.get_instance()
- self._pservice.connect('activity-appeared',
- self.__activity_appeared_cb)
-
- # Add initial activities the PS knows about
- for activity in self._pservice.get_activities():
- self.__activity_appeared_cb(self._pservice, activity)
-
- shell.connect('activity-changed', self.__activity_changed_cb)
-
- def add_buddy(self, buddy):
- if self._buddies.has_key(buddy.get_name()):
- return
-
- model = BuddyModel(buddy=buddy)
- icon = BuddyIcon(self._shell, self._menu_shell, model)
- style.apply_stylesheet(icon, 'frame.BuddyIcon')
- self.append(icon)
-
- self._buddies[buddy.get_name()] = icon
-
- def remove_buddy(self, buddy):
- if not self._buddies.has_key(buddy.get_name()):
- return
-
- self.remove(self._buddies[buddy.get_name()])
-
- def clear(self):
- for item in self.get_children():
- self.remove(item)
- self._buddies = {}
-
- def __activity_appeared_cb(self, pservice, activity_ps):
- activity = self._shell.get_current_activity()
- if activity and activity_ps.get_id() == activity.get_id():
- self._set_activity_ps(activity_ps)
-
- def _set_activity_ps(self, activity_ps):
- if self._activity_ps == activity_ps:
- return
-
- if self._joined_hid > 0:
- self._activity_ps.disconnect(self._joined_hid)
- self._joined_hid = -1
- if self._left_hid > 0:
- self._activity_ps.disconnect(self._left_hid)
- self._left_hid = -1
-
- self._activity_ps = activity_ps
-
- self.clear()
-
- if activity_ps != None:
- for buddy in activity_ps.get_joined_buddies():
- self.add_buddy(buddy)
-
- self._joined_hid = activity_ps.connect(
- 'buddy-joined', self.__buddy_joined_cb)
- self._left_hid = activity_ps.connect(
- 'buddy-left', self.__buddy_left_cb)
-
- def __activity_changed_cb(self, group, activity):
- if activity:
- ps = self._pservice.get_activity(activity.get_id())
- self._set_activity_ps(ps)
- else:
- self._set_activity_ps(None)
-
- def __buddy_joined_cb(self, activity, buddy):
- self.add_buddy(buddy)
-
- def __buddy_left_cb(self, activity, buddy):
- self.remove_buddy(buddy)
+ def __init__(self, shell, menu_shell):
+ hippo.CanvasBox.__init__(self)
+ self._shell = shell
+ self._menu_shell = menu_shell
+ self._activity_ps = None
+ self._joined_hid = -1
+ self._left_hid = -1
+ self._buddies = {}
+
+ self._pservice = PresenceService.get_instance()
+ self._pservice.connect('activity-appeared',
+ self.__activity_appeared_cb)
+
+ # Add initial activities the PS knows about
+ for activity in self._pservice.get_activities():
+ self.__activity_appeared_cb(self._pservice, activity)
+
+ shell.connect('activity-changed', self.__activity_changed_cb)
+
+ def add_buddy(self, buddy):
+ if self._buddies.has_key(buddy.get_name()):
+ return
+
+ model = BuddyModel(buddy=buddy)
+ icon = BuddyIcon(self._shell, self._menu_shell, model)
+ style.apply_stylesheet(icon, 'frame.BuddyIcon')
+ self.append(icon)
+
+ self._buddies[buddy.get_name()] = icon
+
+ def remove_buddy(self, buddy):
+ if not self._buddies.has_key(buddy.get_name()):
+ return
+
+ self.remove(self._buddies[buddy.get_name()])
+
+ def clear(self):
+ for item in self.get_children():
+ self.remove(item)
+ self._buddies = {}
+
+ def __activity_appeared_cb(self, pservice, activity_ps):
+ activity = self._shell.get_current_activity()
+ if activity and activity_ps.get_id() == activity.get_id():
+ self._set_activity_ps(activity_ps)
+
+ def _set_activity_ps(self, activity_ps):
+ if self._activity_ps == activity_ps:
+ return
+
+ if self._joined_hid > 0:
+ self._activity_ps.disconnect(self._joined_hid)
+ self._joined_hid = -1
+ if self._left_hid > 0:
+ self._activity_ps.disconnect(self._left_hid)
+ self._left_hid = -1
+
+ self._activity_ps = activity_ps
+
+ self.clear()
+
+ if activity_ps != None:
+ for buddy in activity_ps.get_joined_buddies():
+ self.add_buddy(buddy)
+
+ self._joined_hid = activity_ps.connect(
+ 'buddy-joined', self.__buddy_joined_cb)
+ self._left_hid = activity_ps.connect(
+ 'buddy-left', self.__buddy_left_cb)
+
+ def __activity_changed_cb(self, group, activity):
+ if activity:
+ ps = self._pservice.get_activity(activity.get_id())
+ self._set_activity_ps(ps)
+ else:
+ self._set_activity_ps(None)
+
+ def __buddy_joined_cb(self, activity, buddy):
+ self.add_buddy(buddy)
+
+ def __buddy_left_cb(self, activity, buddy):
+ self.remove_buddy(buddy)
diff --git a/shell/view/frame/PanelWindow.py b/shell/view/frame/PanelWindow.py
index 14e72b1..8fd8145 100644
--- a/shell/view/frame/PanelWindow.py
+++ b/shell/view/frame/PanelWindow.py
@@ -20,28 +20,28 @@ import hippo
from sugar.graphics.menushell import MenuShell
class PanelWindow(gtk.Window):
- def __init__(self):
- gtk.Window.__init__(self)
+ def __init__(self):
+ gtk.Window.__init__(self)
- self.set_decorated(False)
- self.connect('realize', self._realize_cb)
+ self.set_decorated(False)
+ self.connect('realize', self._realize_cb)
- canvas = hippo.Canvas()
+ canvas = hippo.Canvas()
- self._bg = hippo.CanvasBox(background_color=0x414141ff)
- canvas.set_root(self._bg)
+ self._bg = hippo.CanvasBox(background_color=0x414141ff)
+ canvas.set_root(self._bg)
- self.add(canvas)
- canvas.show()
+ self.add(canvas)
+ canvas.show()
- self._menu_shell = MenuShell(canvas)
+ self._menu_shell = MenuShell(canvas)
- def get_menu_shell(self):
- return self._menu_shell
+ def get_menu_shell(self):
+ return self._menu_shell
- def get_root(self):
- return self._bg
+ def get_root(self):
+ return self._bg
- def _realize_cb(self, widget):
- self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
- self.window.set_accept_focus(False)
+ def _realize_cb(self, widget):
+ self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
+ self.window.set_accept_focus(False)
diff --git a/shell/view/frame/ZoomBox.py b/shell/view/frame/ZoomBox.py
index 45c76cd..ed7e0a1 100644
--- a/shell/view/frame/ZoomBox.py
+++ b/shell/view/frame/ZoomBox.py
@@ -23,98 +23,98 @@ from sugar.graphics import style
import sugar
class ActivityMenu(Menu):
- ACTION_SHARE = 1
- ACTION_CLOSE = 2
+ ACTION_SHARE = 1
+ ACTION_CLOSE = 2
- def __init__(self, activity_host):
- Menu.__init__(self, activity_host.get_title())
+ def __init__(self, activity_host):
+ Menu.__init__(self, activity_host.get_title())
- if not activity_host.get_shared():
- self._add_mesh_action()
+ if not activity_host.get_shared():
+ self._add_mesh_action()
- self._add_close_action()
+ self._add_close_action()
- def _add_mesh_action(self):
- icon = CanvasIcon(icon_name='stock-share-mesh')
- self.add_action(icon, ActivityMenu.ACTION_SHARE)
+ def _add_mesh_action(self):
+ icon = CanvasIcon(icon_name='stock-share-mesh')
+ self.add_action(icon, ActivityMenu.ACTION_SHARE)
- def _add_close_action(self):
- icon = CanvasIcon(icon_name='stock-close')
- self.add_action(icon, ActivityMenu.ACTION_CLOSE)
+ def _add_close_action(self):
+ icon = CanvasIcon(icon_name='stock-close')
+ self.add_action(icon, ActivityMenu.ACTION_CLOSE)
class ActivityIcon(MenuIcon):
- def __init__(self, shell, menu_shell, activity_host):
- self._shell = shell
- self._activity_host = activity_host
+ def __init__(self, shell, menu_shell, activity_host):
+ self._shell = shell
+ self._activity_host = activity_host
- icon_name = activity_host.get_icon_name()
- icon_color = activity_host.get_icon_color()
+ icon_name = activity_host.get_icon_name()
+ icon_color = activity_host.get_icon_color()
- MenuIcon.__init__(self, menu_shell, icon_name=icon_name,
- color=icon_color)
+ MenuIcon.__init__(self, menu_shell, icon_name=icon_name,
+ color=icon_color)
- def create_menu(self):
- menu = ActivityMenu(self._activity_host)
- menu.connect('action', self._action_cb)
- return menu
+ def create_menu(self):
+ menu = ActivityMenu(self._activity_host)
+ menu.connect('action', self._action_cb)
+ return menu
- def _action_cb(self, menu, action):
- self.popdown()
+ def _action_cb(self, menu, action):
+ self.popdown()
- activity = self._shell.get_current_activity()
- if activity == None:
- return
+ activity = self._shell.get_current_activity()
+ if activity == None:
+ return
- if action == ActivityMenu.ACTION_SHARE:
- activity.share()
- if action == ActivityMenu.ACTION_CLOSE:
- activity.close()
+ if action == ActivityMenu.ACTION_SHARE:
+ activity.share()
+ if action == ActivityMenu.ACTION_CLOSE:
+ activity.close()
class ZoomBox(hippo.CanvasBox):
- def __init__(self, shell, menu_shell):
- hippo.CanvasBox.__init__(self, orientation=hippo.ORIENTATION_HORIZONTAL)
-
- self._shell = shell
- self._menu_shell = menu_shell
- self._activity_icon = None
-
- icon = CanvasIcon(icon_name='stock-zoom-mesh')
- style.apply_stylesheet(icon, 'frame.ZoomIcon')
- icon.connect('activated', self._level_clicked_cb, sugar.ZOOM_MESH)
- self.append(icon)
-
- icon = CanvasIcon(icon_name='stock-zoom-friends')
- style.apply_stylesheet(icon, 'frame.ZoomIcon')
- icon.connect('activated', self._level_clicked_cb, sugar.ZOOM_FRIENDS)
- self.append(icon)
-
- icon = CanvasIcon(icon_name='stock-zoom-home')
- style.apply_stylesheet(icon, 'frame.ZoomIcon')
- icon.connect('activated', self._level_clicked_cb, sugar.ZOOM_HOME)
- self.append(icon)
-
- icon = CanvasIcon(icon_name='stock-zoom-activity')
- style.apply_stylesheet(icon, 'frame.ZoomIcon')
- icon.connect('activated', self._level_clicked_cb, sugar.ZOOM_ACTIVITY)
- self.append(icon)
-
- shell.connect('activity-changed', self._activity_changed_cb)
- self._set_current_activity(shell.get_current_activity())
-
- def _set_current_activity(self, activity):
- if self._activity_icon:
- self.remove(self._activity_icon)
-
- if activity:
- icon = ActivityIcon(self._shell, self._menu_shell, activity)
- style.apply_stylesheet(icon, 'frame.ZoomIcon')
- self.append(icon, 0)
- self._activity_icon = icon
- else:
- self._activity_icon = None
-
- def _activity_changed_cb(self, shell_model, activity):
- self._set_current_activity(activity)
-
- def _level_clicked_cb(self, item, level):
- self._shell.set_zoom_level(level)
+ def __init__(self, shell, menu_shell):
+ hippo.CanvasBox.__init__(self, orientation=hippo.ORIENTATION_HORIZONTAL)
+
+ self._shell = shell
+ self._menu_shell = menu_shell
+ self._activity_icon = None
+
+ icon = CanvasIcon(icon_name='stock-zoom-mesh')
+ style.apply_stylesheet(icon, 'frame.ZoomIcon')
+ icon.connect('activated', self._level_clicked_cb, sugar.ZOOM_MESH)
+ self.append(icon)
+
+ icon = CanvasIcon(icon_name='stock-zoom-friends')
+ style.apply_stylesheet(icon, 'frame.ZoomIcon')
+ icon.connect('activated', self._level_clicked_cb, sugar.ZOOM_FRIENDS)
+ self.append(icon)
+
+ icon = CanvasIcon(icon_name='stock-zoom-home')
+ style.apply_stylesheet(icon, 'frame.ZoomIcon')
+ icon.connect('activated', self._level_clicked_cb, sugar.ZOOM_HOME)
+ self.append(icon)
+
+ icon = CanvasIcon(icon_name='stock-zoom-activity')
+ style.apply_stylesheet(icon, 'frame.ZoomIcon')
+ icon.connect('activated', self._level_clicked_cb, sugar.ZOOM_ACTIVITY)
+ self.append(icon)
+
+ shell.connect('activity-changed', self._activity_changed_cb)
+ self._set_current_activity(shell.get_current_activity())
+
+ def _set_current_activity(self, activity):
+ if self._activity_icon:
+ self.remove(self._activity_icon)
+
+ if activity:
+ icon = ActivityIcon(self._shell, self._menu_shell, activity)
+ style.apply_stylesheet(icon, 'frame.ZoomIcon')
+ self.append(icon, 0)
+ self._activity_icon = icon
+ else:
+ self._activity_icon = None
+
+ def _activity_changed_cb(self, shell_model, activity):
+ self._set_current_activity(activity)
+
+ def _level_clicked_cb(self, item, level):
+ self._shell.set_zoom_level(level)
diff --git a/shell/view/frame/notificationtray.py b/shell/view/frame/notificationtray.py
index 5fa5123..b304868 100644
--- a/shell/view/frame/notificationtray.py
+++ b/shell/view/frame/notificationtray.py
@@ -3,16 +3,16 @@ import gtk
from _sugar import TrayManager
class NotificationTray(gtk.HBox):
- def __init__(self):
- gtk.HBox.__init__(self)
+ def __init__(self):
+ gtk.HBox.__init__(self)
- self._manager = TrayManager()
- self._manager.connect('tray-icon-added', self._icon_added_cb)
- self._manager.connect('tray-icon-removed', self._icon_removed_cb)
- self._manager.manage_screen(gtk.gdk.screen_get_default())
+ self._manager = TrayManager()
+ self._manager.connect('tray-icon-added', self._icon_added_cb)
+ self._manager.connect('tray-icon-removed', self._icon_removed_cb)
+ self._manager.manage_screen(gtk.gdk.screen_get_default())
- def _icon_added_cb(self, manager, icon):
- self.pack_start(icon, False)
+ def _icon_added_cb(self, manager, icon):
+ self.pack_start(icon, False)
- def _icon_removed_cb(self, manager, icon):
- icon.destroy()
+ def _icon_removed_cb(self, manager, icon):
+ icon.destroy()
diff --git a/shell/view/frame/overlaybox.py b/shell/view/frame/overlaybox.py
index eaa1e5d..406173a 100644
--- a/shell/view/frame/overlaybox.py
+++ b/shell/view/frame/overlaybox.py
@@ -4,15 +4,15 @@ from sugar.graphics import style
from sugar.graphics.canvasicon import CanvasIcon
class OverlayBox(hippo.CanvasBox):
- def __init__(self, shell):
- hippo.CanvasBox.__init__(self, orientation=hippo.ORIENTATION_HORIZONTAL)
+ def __init__(self, shell):
+ hippo.CanvasBox.__init__(self, orientation=hippo.ORIENTATION_HORIZONTAL)
- self._shell = shell
+ self._shell = shell
- icon = CanvasIcon(icon_name='stock-chat')
- style.apply_stylesheet(icon, 'frame.OverlayIcon')
- icon.connect('activated', self._overlay_clicked_cb)
- self.append(icon)
+ icon = CanvasIcon(icon_name='stock-chat')
+ style.apply_stylesheet(icon, 'frame.OverlayIcon')
+ icon.connect('activated', self._overlay_clicked_cb)
+ self.append(icon)
- def _overlay_clicked_cb(self, item):
- self._shell.toggle_chat_visibility()
+ def _overlay_clicked_cb(self, item):
+ self._shell.toggle_chat_visibility()
diff --git a/shell/view/frame/shutdownicon.py b/shell/view/frame/shutdownicon.py
index 520ba20..5814f72 100644
--- a/shell/view/frame/shutdownicon.py
+++ b/shell/view/frame/shutdownicon.py
@@ -21,24 +21,24 @@ from sugar.graphics.menu import Menu
from sugar.graphics import style
class ShutdownIcon(MenuIcon):
- ACTION_SHUTDOWN = 2
+ ACTION_SHUTDOWN = 2
- def __init__(self, menu_shell):
- MenuIcon.__init__(self, menu_shell, icon_name='stock-close')
- style.apply_stylesheet(self, 'menu.ActionIcon')
+ def __init__(self, menu_shell):
+ MenuIcon.__init__(self, menu_shell, icon_name='stock-close')
+ style.apply_stylesheet(self, 'menu.ActionIcon')
- def create_menu(self):
- menu = Menu()
- menu.add_item('Shut Down', ShutdownIcon.ACTION_SHUTDOWN)
- menu.connect('action', self._action_cb)
- return menu
+ def create_menu(self):
+ menu = Menu()
+ menu.add_item('Shut Down', ShutdownIcon.ACTION_SHUTDOWN)
+ menu.connect('action', self._action_cb)
+ return menu
- def _action_cb(self, menu, action):
- self.popdown()
+ def _action_cb(self, menu, action):
+ self.popdown()
- if action == ShutdownIcon.ACTION_SHUTDOWN:
- bus = dbus.SystemBus()
- proxy = bus.get_object('org.freedesktop.Hal',
- '/org/freedesktop/Hal/devices/computer')
- mgr = dbus.Interface(proxy, 'org.freedesktop.Hal.Device.SystemPowerManagement')
- mgr.Shutdown()
+ if action == ShutdownIcon.ACTION_SHUTDOWN:
+ bus = dbus.SystemBus()
+ proxy = bus.get_object('org.freedesktop.Hal',
+ '/org/freedesktop/Hal/devices/computer')
+ mgr = dbus.Interface(proxy, 'org.freedesktop.Hal.Device.SystemPowerManagement')
+ mgr.Shutdown()
diff --git a/shell/view/home/FriendView.py b/shell/view/home/FriendView.py
index 2b5cf7c..6d24f76 100644
--- a/shell/view/home/FriendView.py
+++ b/shell/view/home/FriendView.py
@@ -23,67 +23,67 @@ from sugar.graphics import style
from sugar.presence import PresenceService
class FriendView(hippo.CanvasBox):
- def __init__(self, shell, menu_shell, buddy, **kwargs):
- hippo.CanvasBox.__init__(self, **kwargs)
+ def __init__(self, shell, menu_shell, buddy, **kwargs):
+ hippo.CanvasBox.__init__(self, **kwargs)
- self._pservice = PresenceService.get_instance()
+ self._pservice = PresenceService.get_instance()
- self._buddy = buddy
- self._buddy_icon = BuddyIcon(shell, menu_shell, buddy)
- style.apply_stylesheet(self._buddy_icon, 'friends.FriendIcon')
- self.append(self._buddy_icon)
+ self._buddy = buddy
+ self._buddy_icon = BuddyIcon(shell, menu_shell, buddy)
+ style.apply_stylesheet(self._buddy_icon, 'friends.FriendIcon')
+ self.append(self._buddy_icon)
- self._activity_icon = CanvasIcon()
- style.apply_stylesheet(self._activity_icon, 'friends.ActivityIcon')
- self._activity_icon_visible = False
+ self._activity_icon = CanvasIcon()
+ style.apply_stylesheet(self._activity_icon, 'friends.ActivityIcon')
+ self._activity_icon_visible = False
- if self._buddy.is_present():
- self._buddy_appeared_cb(buddy)
+ if self._buddy.is_present():
+ self._buddy_appeared_cb(buddy)
- self._buddy.connect('current-activity-changed', self._buddy_activity_changed_cb)
- self._buddy.connect('appeared', self._buddy_appeared_cb)
- self._buddy.connect('disappeared', self._buddy_disappeared_cb)
- self._buddy.connect('color-changed', self._buddy_color_changed_cb)
+ self._buddy.connect('current-activity-changed', self._buddy_activity_changed_cb)
+ self._buddy.connect('appeared', self._buddy_appeared_cb)
+ self._buddy.connect('disappeared', self._buddy_disappeared_cb)
+ self._buddy.connect('color-changed', self._buddy_color_changed_cb)
- def _get_new_icon_name(self, activity):
- # FIXME: do something better here; we probably need to use "flagship"
- # services like mDNS where activities default services are marked
- # somehow.
- activity_registry = shell.get_model().get_bundle_registry()
- for serv in activity.get_services():
- bundle = activity_registry.get_bundle(serv.get_type())
- if bundle:
- return bundle.get_icon()
- return None
+ def _get_new_icon_name(self, activity):
+ # FIXME: do something better here; we probably need to use "flagship"
+ # services like mDNS where activities default services are marked
+ # somehow.
+ activity_registry = shell.get_model().get_bundle_registry()
+ for serv in activity.get_services():
+ bundle = activity_registry.get_bundle(serv.get_type())
+ if bundle:
+ return bundle.get_icon()
+ return None
- def _remove_activity_icon(self):
- if self._activity_icon_visible:
- self.remove(self._activity_icon)
- self._activity_icon_visible = False
+ def _remove_activity_icon(self):
+ if self._activity_icon_visible:
+ self.remove(self._activity_icon)
+ self._activity_icon_visible = False
- def _buddy_activity_changed_cb(self, buddy, activity=None):
- if not activity:
- self._remove_activity_icon()
- return
+ def _buddy_activity_changed_cb(self, buddy, activity=None):
+ if not activity:
+ self._remove_activity_icon()
+ return
- # FIXME: use some sort of "unknown activity" icon rather
- # than hiding the icon?
- name = self._get_new_icon_name(activity)
- if name:
- self._activity_icon.props.icon_name = name
- self._activity_icon.props.color = buddy.get_color()
- if not self._activity_icon_visible:
- self.append(self._activity_icon, hippo.PACK_EXPAND)
- self._activity_icon_visible = True
- else:
- self._remove_activity_icon()
+ # FIXME: use some sort of "unknown activity" icon rather
+ # than hiding the icon?
+ name = self._get_new_icon_name(activity)
+ if name:
+ self._activity_icon.props.icon_name = name
+ self._activity_icon.props.color = buddy.get_color()
+ if not self._activity_icon_visible:
+ self.append(self._activity_icon, hippo.PACK_EXPAND)
+ self._activity_icon_visible = True
+ else:
+ self._remove_activity_icon()
- def _buddy_appeared_cb(self, buddy):
- activity = self._buddy.get_current_activity()
- self._buddy_activity_changed_cb(buddy, activity)
+ def _buddy_appeared_cb(self, buddy):
+ activity = self._buddy.get_current_activity()
+ self._buddy_activity_changed_cb(buddy, activity)
- def _buddy_disappeared_cb(self, buddy):
- self._buddy_activity_changed_cb(buddy, None)
+ def _buddy_disappeared_cb(self, buddy):
+ self._buddy_activity_changed_cb(buddy, None)
- def _buddy_color_changed_cb(self, buddy, color):
- self._activity_icon.props.color = buddy.get_color()
+ def _buddy_color_changed_cb(self, buddy, color):
+ self._activity_icon.props.color = buddy.get_color()
diff --git a/shell/view/home/FriendsBox.py b/shell/view/home/FriendsBox.py
index 28a745e..ec4aad6 100644
--- a/shell/view/home/FriendsBox.py
+++ b/shell/view/home/FriendsBox.py
@@ -25,42 +25,42 @@ from view.home.MyIcon import MyIcon
from view.home.FriendView import FriendView
class FriendsBox(SpreadBox, hippo.CanvasItem):
- __gtype_name__ = 'SugarFriendsBox'
- def __init__(self, shell, menu_shell):
- SpreadBox.__init__(self, background_color=0xe2e2e2ff)
+ __gtype_name__ = 'SugarFriendsBox'
+ def __init__(self, shell, menu_shell):
+ SpreadBox.__init__(self, background_color=0xe2e2e2ff)
- self._shell = shell
- self._menu_shell = menu_shell
- self._friends = {}
+ self._shell = shell
+ self._menu_shell = menu_shell
+ self._friends = {}
- self._my_icon = MyIcon()
- style.apply_stylesheet(self._my_icon, 'friends.MyIcon')
- self.append(self._my_icon, hippo.PACK_FIXED)
+ self._my_icon = MyIcon()
+ style.apply_stylesheet(self._my_icon, 'friends.MyIcon')
+ self.append(self._my_icon, hippo.PACK_FIXED)
- friends = self._shell.get_model().get_friends()
+ friends = self._shell.get_model().get_friends()
- for friend in friends:
- self.add_friend(friend)
+ for friend in friends:
+ self.add_friend(friend)
- friends.connect('friend-added', self._friend_added_cb)
- friends.connect('friend-removed', self._friend_removed_cb)
+ friends.connect('friend-added', self._friend_added_cb)
+ friends.connect('friend-removed', self._friend_removed_cb)
- def add_friend(self, buddy_info):
- icon = FriendView(self._shell, self._menu_shell, buddy_info)
- self.add_item(icon)
+ def add_friend(self, buddy_info):
+ icon = FriendView(self._shell, self._menu_shell, buddy_info)
+ self.add_item(icon)
- self._friends[buddy_info.get_name()] = icon
+ self._friends[buddy_info.get_name()] = icon
- def _friend_added_cb(self, data_model, buddy_info):
- self.add_friend(buddy_info)
+ def _friend_added_cb(self, data_model, buddy_info):
+ self.add_friend(buddy_info)
- def _friend_removed_cb(self, data_model, name):
- self.remove_item(self._friends[name])
- del self._friends[name]
+ def _friend_removed_cb(self, data_model, name):
+ self.remove_item(self._friends[name])
+ del self._friends[name]
- def do_allocate(self, width, height):
- SpreadBox.do_allocate(self, width, height)
+ def do_allocate(self, width, height):
+ SpreadBox.do_allocate(self, width, height)
- [icon_width, icon_height] = self._my_icon.get_allocation()
- self.move(self._my_icon, (width - icon_width) / 2,
- (height - icon_height) / 2)
+ [icon_width, icon_height] = self._my_icon.get_allocation()
+ self.move(self._my_icon, (width - icon_width) / 2,
+ (height - icon_height) / 2)
diff --git a/shell/view/home/HomeBox.py b/shell/view/home/HomeBox.py
index 146056b..a24402d 100644
--- a/shell/view/home/HomeBox.py
+++ b/shell/view/home/HomeBox.py
@@ -22,24 +22,24 @@ from sugar.graphics.grid import Grid
from sugar.graphics import style
class HomeBox(hippo.CanvasBox, hippo.CanvasItem):
- __gtype_name__ = 'SugarHomeBox'
+ __gtype_name__ = 'SugarHomeBox'
- def __init__(self, shell):
- hippo.CanvasBox.__init__(self, background_color=0xe2e2e2ff,
- yalign=2)
+ def __init__(self, shell):
+ hippo.CanvasBox.__init__(self, background_color=0xe2e2e2ff,
+ yalign=2)
- grid = Grid()
- donut = ActivitiesDonut(shell, box_width=grid.dimension(7),
- box_height=grid.dimension(7))
- self.append(donut)
+ grid = Grid()
+ donut = ActivitiesDonut(shell, box_width=grid.dimension(7),
+ box_height=grid.dimension(7))
+ self.append(donut)
- self._my_icon = MyIcon()
- style.apply_stylesheet(self._my_icon, 'home.MyIcon')
- self.append(self._my_icon, hippo.PACK_FIXED)
+ self._my_icon = MyIcon()
+ style.apply_stylesheet(self._my_icon, 'home.MyIcon')
+ self.append(self._my_icon, hippo.PACK_FIXED)
- def do_allocate(self, width, height):
- hippo.CanvasBox.do_allocate(self, width, height)
+ def do_allocate(self, width, height):
+ hippo.CanvasBox.do_allocate(self, width, height)
- [icon_width, icon_height] = self._my_icon.get_allocation()
- self.move(self._my_icon, (width - icon_width) / 2,
- (height - icon_height) / 2)
+ [icon_width, icon_height] = self._my_icon.get_allocation()
+ self.move(self._my_icon, (width - icon_width) / 2,
+ (height - icon_height) / 2)
diff --git a/shell/view/home/HomeWindow.py b/shell/view/home/HomeWindow.py
index e07c7d0..b450b8c 100644
--- a/shell/view/home/HomeWindow.py
+++ b/shell/view/home/HomeWindow.py
@@ -25,45 +25,45 @@ from view.home.HomeBox import HomeBox
from view.home.FriendsBox import FriendsBox
class HomeWindow(gtk.Window):
- def __init__(self, shell):
- gtk.Window.__init__(self)
- self._shell = shell
+ def __init__(self, shell):
+ gtk.Window.__init__(self)
+ self._shell = shell
- self.set_default_size(gtk.gdk.screen_width(),
- gtk.gdk.screen_height())
+ self.set_default_size(gtk.gdk.screen_width(),
+ gtk.gdk.screen_height())
- self.realize()
- self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DESKTOP)
+ self.realize()
+ self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DESKTOP)
- self._nb = gtk.Notebook()
- self._nb.set_show_border(False)
- self._nb.set_show_tabs(False)
+ self._nb = gtk.Notebook()
+ self._nb.set_show_border(False)
+ self._nb.set_show_tabs(False)
- self.add(self._nb)
- self._nb.show()
+ self.add(self._nb)
+ self._nb.show()
- canvas = hippo.Canvas()
- box = HomeBox(shell)
- canvas.set_root(box)
- self._nb.append_page(canvas)
- canvas.show()
+ canvas = hippo.Canvas()
+ box = HomeBox(shell)
+ canvas.set_root(box)
+ self._nb.append_page(canvas)
+ canvas.show()
- canvas = hippo.Canvas()
- box = FriendsBox(shell, MenuShell(canvas))
- canvas.set_root(box)
- self._nb.append_page(canvas)
- canvas.show()
+ canvas = hippo.Canvas()
+ box = FriendsBox(shell, MenuShell(canvas))
+ canvas.set_root(box)
+ self._nb.append_page(canvas)
+ canvas.show()
- canvas = hippo.Canvas()
- box = MeshBox(shell, MenuShell(canvas))
- canvas.set_root(box)
- self._nb.append_page(canvas)
- canvas.show()
+ canvas = hippo.Canvas()
+ box = MeshBox(shell, MenuShell(canvas))
+ canvas.set_root(box)
+ self._nb.append_page(canvas)
+ canvas.show()
- def set_zoom_level(self, level):
- if level == sugar.ZOOM_HOME:
- self._nb.set_current_page(0)
- elif level == sugar.ZOOM_FRIENDS:
- self._nb.set_current_page(1)
- elif level == sugar.ZOOM_MESH:
- self._nb.set_current_page(2)
+ def set_zoom_level(self, level):
+ if level == sugar.ZOOM_HOME:
+ self._nb.set_current_page(0)
+ elif level == sugar.ZOOM_FRIENDS:
+ self._nb.set_current_page(1)
+ elif level == sugar.ZOOM_MESH:
+ self._nb.set_current_page(2)
diff --git a/shell/view/home/MeshBox.py b/shell/view/home/MeshBox.py
index 1c61d1a..5ea4aef 100644
--- a/shell/view/home/MeshBox.py
+++ b/shell/view/home/MeshBox.py
@@ -25,116 +25,116 @@ from sugar.graphics.canvasicon import CanvasIcon
from view.BuddyIcon import BuddyIcon
class ActivityView(SnowflakeBox):
- def __init__(self, shell, menu_shell, model):
- SnowflakeBox.__init__(self)
+ def __init__(self, shell, menu_shell, model):
+ SnowflakeBox.__init__(self)
- self._shell = shell
- self._model = model
- self._icons = {}
+ self._shell = shell
+ self._model = model
+ self._icons = {}
- icon = CanvasIcon(icon_name=model.get_icon_name(),
- color=model.get_color(), size=80)
- icon.connect('activated', self._clicked_cb)
- self.append(icon, hippo.PACK_FIXED)
- self.set_root(icon)
+ icon = CanvasIcon(icon_name=model.get_icon_name(),
+ color=model.get_color(), size=80)
+ icon.connect('activated', self._clicked_cb)
+ self.append(icon, hippo.PACK_FIXED)
+ self.set_root(icon)
- def has_buddy_icon(self, name):
- return self._icons.has_key(name)
+ def has_buddy_icon(self, name):
+ return self._icons.has_key(name)
- def add_buddy_icon(self, name, icon):
- self._icons[name] = icon
- self.append(icon, hippo.PACK_FIXED)
+ def add_buddy_icon(self, name, icon):
+ self._icons[name] = icon
+ self.append(icon, hippo.PACK_FIXED)
- def remove_buddy_icon(self, name):
- icon = self._icons[name]
- self.remove(icon)
- del self._icons[name]
+ def remove_buddy_icon(self, name):
+ icon = self._icons[name]
+ self.remove(icon)
+ del self._icons[name]
- def _clicked_cb(self, item):
- bundle_id = self._model.get_service().get_type()
- self._shell.join_activity(bundle_id, self._model.get_id())
+ def _clicked_cb(self, item):
+ bundle_id = self._model.get_service().get_type()
+ self._shell.join_activity(bundle_id, self._model.get_id())
class MeshBox(SpreadBox):
- def __init__(self, shell, menu_shell):
- SpreadBox.__init__(self, background_color=0xe2e2e2ff)
+ def __init__(self, shell, menu_shell):
+ SpreadBox.__init__(self, background_color=0xe2e2e2ff)
- self._shell = shell
- self._menu_shell = menu_shell
- self._model = shell.get_model().get_mesh()
- self._buddies = {}
- self._activities = {}
- self._buddy_to_activity = {}
+ self._shell = shell
+ self._menu_shell = menu_shell
+ self._model = shell.get_model().get_mesh()
+ self._buddies = {}
+ self._activities = {}
+ self._buddy_to_activity = {}
- for buddy_model in self._model.get_buddies():
- self._add_alone_buddy(buddy_model)
+ for buddy_model in self._model.get_buddies():
+ self._add_alone_buddy(buddy_model)
- self._model.connect('buddy-added', self._buddy_added_cb)
- self._model.connect('buddy-removed', self._buddy_removed_cb)
- self._model.connect('buddy-moved', self._buddy_moved_cb)
+ self._model.connect('buddy-added', self._buddy_added_cb)
+ self._model.connect('buddy-removed', self._buddy_removed_cb)
+ self._model.connect('buddy-moved', self._buddy_moved_cb)
- for activity_model in self._model.get_activities():
- self._add_activity(activity_model)
+ for activity_model in self._model.get_activities():
+ self._add_activity(activity_model)
- self._model.connect('activity-added', self._activity_added_cb)
- self._model.connect('activity-removed', self._activity_removed_cb)
+ self._model.connect('activity-added', self._activity_added_cb)
+ self._model.connect('activity-removed', self._activity_removed_cb)
- def _buddy_added_cb(self, model, buddy_model):
- self._add_alone_buddy(buddy_model)
+ def _buddy_added_cb(self, model, buddy_model):
+ self._add_alone_buddy(buddy_model)
- def _buddy_removed_cb(self, model, buddy_model):
- self._remove_buddy(buddy_model)
+ def _buddy_removed_cb(self, model, buddy_model):
+ self._remove_buddy(buddy_model)
- def _buddy_moved_cb(self, model, buddy_model, activity_model):
- self._move_buddy(buddy_model, activity_model)
+ def _buddy_moved_cb(self, model, buddy_model, activity_model):
+ self._move_buddy(buddy_model, activity_model)
- def _activity_added_cb(self, model, activity_model):
- self._add_activity(activity_model)
+ def _activity_added_cb(self, model, activity_model):
+ self._add_activity(activity_model)
- def _activity_removed_cb(self, model, activity_model):
- self._remove_activity(activity_model)
+ def _activity_removed_cb(self, model, activity_model):
+ self._remove_activity(activity_model)
- def _add_alone_buddy(self, buddy_model):
- icon = BuddyIcon(self._shell, self._menu_shell, buddy_model)
- icon.props.size = 80
- self.add_item(icon)
+ def _add_alone_buddy(self, buddy_model):
+ icon = BuddyIcon(self._shell, self._menu_shell, buddy_model)
+ icon.props.size = 80
+ self.add_item(icon)
- self._buddies[buddy_model.get_name()] = icon
+ self._buddies[buddy_model.get_name()] = icon
- def _remove_alone_buddy(self, buddy_model):
- icon = self._buddies[buddy_model.get_name()]
- self.remove_item(icon)
- del self._buddies[buddy_model.get_name()]
+ def _remove_alone_buddy(self, buddy_model):
+ icon = self._buddies[buddy_model.get_name()]
+ self.remove_item(icon)
+ del self._buddies[buddy_model.get_name()]
- def _remove_buddy(self, buddy_model):
- name = buddy_model.get_name()
- if self._buddies.has_key(name):
- self._remove_alone_buddy(buddy_model)
- else:
- for activity in self._activities.values():
- if activity.has_buddy_icon(name):
- activity.remove_buddy_icon(name)
+ def _remove_buddy(self, buddy_model):
+ name = buddy_model.get_name()
+ if self._buddies.has_key(name):
+ self._remove_alone_buddy(buddy_model)
+ else:
+ for activity in self._activities.values():
+ if activity.has_buddy_icon(name):
+ activity.remove_buddy_icon(name)
- def _move_buddy(self, buddy_model, activity_model):
- name = buddy_model.get_name()
+ def _move_buddy(self, buddy_model, activity_model):
+ name = buddy_model.get_name()
- self._remove_buddy(buddy_model)
+ self._remove_buddy(buddy_model)
- if activity_model == None:
- self._add_alone_buddy(buddy_model)
- else:
- activity = self._activities[activity_model.get_id()]
+ if activity_model == None:
+ self._add_alone_buddy(buddy_model)
+ else:
+ activity = self._activities[activity_model.get_id()]
- icon = BuddyIcon(self._shell, self._menu_shell, buddy_model)
- icon.props.size = 60
- activity.add_buddy_icon(buddy_model.get_name(), icon)
+ icon = BuddyIcon(self._shell, self._menu_shell, buddy_model)
+ icon.props.size = 60
+ activity.add_buddy_icon(buddy_model.get_name(), icon)
- def _add_activity(self, activity_model):
- icon = ActivityView(self._shell, self._menu_shell, activity_model)
- self.add_item(icon)
+ def _add_activity(self, activity_model):
+ icon = ActivityView(self._shell, self._menu_shell, activity_model)
+ self.add_item(icon)
- self._activities[activity_model.get_id()] = icon
+ self._activities[activity_model.get_id()] = icon
- def _remove_activity(self, activity_model):
- icon = self._activities[activity_model.get_id()]
- self.remove_item(icon)
- del self._activities[activity_model.get_id()]
+ def _remove_activity(self, activity_model):
+ icon = self._activities[activity_model.get_id()]
+ self.remove_item(icon)
+ del self._activities[activity_model.get_id()]
diff --git a/shell/view/home/MyIcon.py b/shell/view/home/MyIcon.py
index df59317..80e3a04 100644
--- a/shell/view/home/MyIcon.py
+++ b/shell/view/home/MyIcon.py
@@ -18,6 +18,6 @@ from sugar.graphics.canvasicon import CanvasIcon
from sugar import profile
class MyIcon(CanvasIcon):
- def __init__(self):
- CanvasIcon.__init__(self, icon_name='stock-buddy',
- color=profile.get_color())
+ def __init__(self):
+ CanvasIcon.__init__(self, icon_name='stock-buddy',
+ color=profile.get_color())
diff --git a/shell/view/home/activitiesdonut.py b/shell/view/home/activitiesdonut.py
index f7d24fc..74f3bbb 100644
--- a/shell/view/home/activitiesdonut.py
+++ b/shell/view/home/activitiesdonut.py
@@ -21,100 +21,100 @@ from sugar.graphics.canvasicon import CanvasIcon
from sugar.graphics import style
class ActivitiesDonut(hippo.CanvasBox, hippo.CanvasItem):
- __gtype_name__ = 'SugarActivitiesDonut'
- def __init__(self, shell, **kwargs):
- hippo.CanvasBox.__init__(self, **kwargs)
+ __gtype_name__ = 'SugarActivitiesDonut'
+ def __init__(self, shell, **kwargs):
+ hippo.CanvasBox.__init__(self, **kwargs)
- self._activities = {}
+ self._activities = {}
- shell.connect('activity_opened', self.__activity_opened_cb)
- shell.connect('activity_closed', self.__activity_closed_cb)
+ shell.connect('activity_opened', self.__activity_opened_cb)
+ shell.connect('activity_closed', self.__activity_closed_cb)
- def __activity_opened_cb(self, model, activity):
- self._add_activity(activity)
+ def __activity_opened_cb(self, model, activity):
+ self._add_activity(activity)
- def __activity_closed_cb(self, model, activity):
- self._remove_activity(activity)
-
- def _remove_activity(self, activity):
- icon = self._activities[activity.get_id()]
- self.remove(icon)
- del self._activities[activity.get_id()]
+ def __activity_closed_cb(self, model, activity):
+ self._remove_activity(activity)
+
+ def _remove_activity(self, activity):
+ icon = self._activities[activity.get_id()]
+ self.remove(icon)
+ del self._activities[activity.get_id()]
- def _add_activity(self, activity):
- icon_name = activity.get_icon_name()
- icon_color = activity.get_icon_color()
+ def _add_activity(self, activity):
+ icon_name = activity.get_icon_name()
+ icon_color = activity.get_icon_color()
- icon = CanvasIcon(icon_name=icon_name, color=icon_color)
- style.apply_stylesheet(icon, 'ring.ActivityIcon')
- icon.connect('activated', self.__activity_icon_clicked_cb, activity)
- self.append(icon, hippo.PACK_FIXED)
+ icon = CanvasIcon(icon_name=icon_name, color=icon_color)
+ style.apply_stylesheet(icon, 'ring.ActivityIcon')
+ icon.connect('activated', self.__activity_icon_clicked_cb, activity)
+ self.append(icon, hippo.PACK_FIXED)
- self._activities[activity.get_id()] = icon
+ self._activities[activity.get_id()] = icon
- self.emit_paint_needed(0, 0, -1, -1)
+ self.emit_paint_needed(0, 0, -1, -1)
- def __activity_icon_clicked_cb(self, item, activity):
- activity.present()
+ def __activity_icon_clicked_cb(self, item, activity):
+ activity.present()
- def _get_angles(self, index):
- angle = 2 * math.pi / 8
- return [index * angle, (index + 1) * angle]
+ def _get_angles(self, index):
+ angle = 2 * math.pi / 8
+ return [index * angle, (index + 1) * angle]
- def _get_radius(self):
- [width, height] = self.get_allocation()
- return min(width, height) / 2
+ def _get_radius(self):
+ [width, height] = self.get_allocation()
+ return min(width, height) / 2
- def _get_inner_radius(self):
- return self._get_radius() * 0.5
+ def _get_inner_radius(self):
+ return self._get_radius() * 0.5
- def do_paint_below_children(self, cr, damaged_box):
- [width, height] = self.get_allocation()
+ def do_paint_below_children(self, cr, damaged_box):
+ [width, height] = self.get_allocation()
- cr.translate(width / 2, height / 2)
+ cr.translate(width / 2, height / 2)
- radius = self._get_radius()
+ radius = self._get_radius()
- cr.set_source_rgb(0xf1 / 255.0, 0xf1 / 255.0, 0xf1 / 255.0)
- cr.arc(0, 0, radius, 0, 2 * math.pi)
- cr.fill()
+ cr.set_source_rgb(0xf1 / 255.0, 0xf1 / 255.0, 0xf1 / 255.0)
+ cr.arc(0, 0, radius, 0, 2 * math.pi)
+ cr.fill()
- angle_end = 0
- for i in range(0, len(self._activities)):
- [angle_start, angle_end] = self._get_angles(i)
+ angle_end = 0
+ for i in range(0, len(self._activities)):
+ [angle_start, angle_end] = self._get_angles(i)
- cr.new_path()
- cr.move_to(0, 0)
- cr.line_to(radius * math.cos(angle_start),
- radius * math.sin(angle_start))
- cr.arc(0, 0, radius, angle_start, angle_end)
- cr.line_to(0, 0)
+ cr.new_path()
+ cr.move_to(0, 0)
+ cr.line_to(radius * math.cos(angle_start),
+ radius * math.sin(angle_start))
+ cr.arc(0, 0, radius, angle_start, angle_end)
+ cr.line_to(0, 0)
- cr.set_source_rgb(0xe2 / 255.0, 0xe2 / 255.0, 0xe2 / 255.0)
- cr.set_line_width(4)
- cr.stroke_preserve()
+ cr.set_source_rgb(0xe2 / 255.0, 0xe2 / 255.0, 0xe2 / 255.0)
+ cr.set_line_width(4)
+ cr.stroke_preserve()
- cr.set_source_rgb(1, 1, 1)
- cr.fill()
+ cr.set_source_rgb(1, 1, 1)
+ cr.fill()
- cr.set_source_rgb(0xe2 / 255.0, 0xe2 / 255.0, 0xe2 / 255.0)
- cr.arc(0, 0, self._get_inner_radius(), 0, 2 * math.pi)
- cr.fill()
+ cr.set_source_rgb(0xe2 / 255.0, 0xe2 / 255.0, 0xe2 / 255.0)
+ cr.arc(0, 0, self._get_inner_radius(), 0, 2 * math.pi)
+ cr.fill()
- def do_allocate(self, width, height):
- hippo.CanvasBox.do_allocate(self, width, height)
+ def do_allocate(self, width, height):
+ hippo.CanvasBox.do_allocate(self, width, height)
- radius = (self._get_inner_radius() + self._get_radius()) / 2
+ radius = (self._get_inner_radius() + self._get_radius()) / 2
- i = 0
- for icon in self._activities.values():
- [angle_start, angle_end] = self._get_angles(i)
- angle = angle_start + (angle_end - angle_start) / 2
+ i = 0
+ for icon in self._activities.values():
+ [angle_start, angle_end] = self._get_angles(i)
+ angle = angle_start + (angle_end - angle_start) / 2
- [icon_width, icon_height] = icon.get_allocation()
+ [icon_width, icon_height] = icon.get_allocation()
- x = int(radius * math.cos(angle)) - icon_width / 2
- y = int(radius * math.sin(angle)) - icon_height / 2
- self.move(icon, x + width / 2, y + height / 2)
+ x = int(radius * math.cos(angle)) - icon_width / 2
+ y = int(radius * math.sin(angle)) - icon_height / 2
+ self.move(icon, x + width / 2, y + height / 2)
- i += 1
+ i += 1
diff --git a/shell/view/stylesheet.py b/shell/view/stylesheet.py
index 1870f9c..5b1c4c6 100644
--- a/shell/view/stylesheet.py
+++ b/shell/view/stylesheet.py
@@ -21,59 +21,59 @@ from sugar.graphics.iconcolor import IconColor
from sugar.graphics import style
frame_ActivityIcon = {
- 'color' : IconColor('white'),
- 'size' : style.standard_icon_size
+ 'color' : IconColor('white'),
+ 'size' : style.standard_icon_size
}
frame_ShutdownIcon = {
- 'size' : style.standard_icon_size
+ 'size' : style.standard_icon_size
}
frame_OverlayIcon = {
- 'size' : style.standard_icon_size
+ 'size' : style.standard_icon_size
}
frame_ZoomIcon = {
- 'size' : style.standard_icon_size
+ 'size' : style.standard_icon_size
}
frame_BuddyIcon = {
- 'size' : style.standard_icon_size
+ 'size' : style.standard_icon_size
}
home_MyIcon = {
- 'size' : style.xlarge_icon_size
+ 'size' : style.xlarge_icon_size
}
ring_ActivityIcon = {
- 'size' : style.medium_icon_size
+ 'size' : style.medium_icon_size
}
friends_MyIcon = {
- 'size' : style.large_icon_size
+ 'size' : style.large_icon_size
}
friends_FriendIcon = {
- 'size' : style.large_icon_size
+ 'size' : style.large_icon_size
}
friends_ActivityIcon = {
- 'size' : style.standard_icon_size
+ 'size' : style.standard_icon_size
}
clipboard_bubble = {
- 'fill-color' : 0x646464FF,
- 'stroke-color' : 0x646464FF,
- 'progress-color': 0x333333FF,
- 'spacing' : style.space_unit,
- 'padding' : style.space_unit * 1.5
+ 'fill-color' : 0x646464FF,
+ 'stroke-color' : 0x646464FF,
+ 'progress-color': 0x333333FF,
+ 'spacing' : style.space_unit,
+ 'padding' : style.space_unit * 1.5
}
clipboard_menu_item_title = {
- 'xalign': hippo.ALIGNMENT_START,
- 'padding-left': 5,
- 'color' : 0xFFFFFFFF,
- 'font' : style.get_font_description('Bold', 1.2)
+ 'xalign': hippo.ALIGNMENT_START,
+ 'padding-left': 5,
+ 'color' : 0xFFFFFFFF,
+ 'font' : style.get_font_description('Bold', 1.2)
}
style.register_stylesheet("clipboard.Bubble", clipboard_bubble)
diff --git a/sugar/TracebackUtils.py b/sugar/TracebackUtils.py
index 86e28f9..940381e 100644
--- a/sugar/TracebackUtils.py
+++ b/sugar/TracebackUtils.py
@@ -22,33 +22,33 @@ import signal
haveThreadframe = True
try:
- import threadframe
+ import threadframe
except ImportError:
- haveThreadframe = False
+ haveThreadframe = False
class TracebackHelper(object):
- def __init__(self):
- fname = "%s-%d" % (os.path.basename(sys.argv[0]), os.getpid())
- self._fpath = os.path.join("/tmp", fname)
- print "Tracebacks will be written to %s on SIGUSR1" % self._fpath
- signal.signal(signal.SIGUSR1, self._handler)
+ def __init__(self):
+ fname = "%s-%d" % (os.path.basename(sys.argv[0]), os.getpid())
+ self._fpath = os.path.join("/tmp", fname)
+ print "Tracebacks will be written to %s on SIGUSR1" % self._fpath
+ signal.signal(signal.SIGUSR1, self._handler)
- def __del__(self):
- try:
- os.remove(self._fpath)
- except OSError:
- pass
+ def __del__(self):
+ try:
+ os.remove(self._fpath)
+ except OSError:
+ pass
- def _handler(self, signum, pframe):
- f = open(self._fpath, "a")
- if not haveThreadframe:
- f.write("Threadframe not installed. No traceback available.\n")
- else:
- frames = threadframe.dict()
- for thread_id, frame in frames.iteritems():
- f.write(('-' * 79) + '\n')
- f.write('[Thread %s] %d' % (thread_id, sys.getrefcount(frame)) + '\n')
- traceback.print_stack(frame, limit=None, file=f)
- f.write("\n")
- f.write('\n')
- f.close()
+ def _handler(self, signum, pframe):
+ f = open(self._fpath, "a")
+ if not haveThreadframe:
+ f.write("Threadframe not installed. No traceback available.\n")
+ else:
+ frames = threadframe.dict()
+ for thread_id, frame in frames.iteritems():
+ f.write(('-' * 79) + '\n')
+ f.write('[Thread %s] %d' % (thread_id, sys.getrefcount(frame)) + '\n')
+ traceback.print_stack(frame, limit=None, file=f)
+ f.write("\n")
+ f.write('\n')
+ f.close()
diff --git a/sugar/activity/Activity.py b/sugar/activity/Activity.py
index 2f27303..215ee85 100644
--- a/sugar/activity/Activity.py
+++ b/sugar/activity/Activity.py
@@ -32,133 +32,133 @@ ACTIVITY_SERVICE_PATH = "/org/laptop/Activity"
ACTIVITY_INTERFACE = "org.laptop.Activity"
def get_service_name(xid):
- return ACTIVITY_SERVICE_NAME + '%d' % xid
+ return ACTIVITY_SERVICE_NAME + '%d' % xid
def get_object_path(xid):
- return ACTIVITY_SERVICE_PATH + "/%s" % xid
+ return ACTIVITY_SERVICE_PATH + "/%s" % xid
class ActivityDbusService(dbus.service.Object):
- """Base dbus service object that each Activity uses to export dbus methods.
-
- The dbus service is separate from the actual Activity object so that we can
- tightly control what stuff passes through the dbus python bindings."""
-
- def start(self, pservice, activity):
- self._activity = activity
- self._pservice = pservice
-
- @dbus.service.method(ACTIVITY_INTERFACE)
- def share(self):
- """Called by the shell to request the activity to share itself on the network."""
- self._activity.share()
-
- @dbus.service.method(ACTIVITY_INTERFACE)
- def join(self, activity_ps_path):
- """Join the activity specified by its presence service path"""
- activity_ps = self._pservice.get(activity_ps_path)
- return self._activity.join(activity_ps)
-
- @dbus.service.method(ACTIVITY_INTERFACE)
- def get_id(self):
- """Get the activity identifier"""
- return self._activity.get_id()
-
- @dbus.service.method(ACTIVITY_INTERFACE)
- def get_type(self):
- """Get the activity type"""
- return self._activity.get_type()
-
- @dbus.service.method(ACTIVITY_INTERFACE)
- def get_shared(self):
- """Returns True if the activity is shared on the mesh."""
- return self._activity.get_shared()
-
- @dbus.service.method(ACTIVITY_INTERFACE,
- in_signature="sas", out_signature="")
- def execute(self, command, args):
- self._activity.execute(command, args)
+ """Base dbus service object that each Activity uses to export dbus methods.
+
+ The dbus service is separate from the actual Activity object so that we can
+ tightly control what stuff passes through the dbus python bindings."""
+
+ def start(self, pservice, activity):
+ self._activity = activity
+ self._pservice = pservice
+
+ @dbus.service.method(ACTIVITY_INTERFACE)
+ def share(self):
+ """Called by the shell to request the activity to share itself on the network."""
+ self._activity.share()
+
+ @dbus.service.method(ACTIVITY_INTERFACE)
+ def join(self, activity_ps_path):
+ """Join the activity specified by its presence service path"""
+ activity_ps = self._pservice.get(activity_ps_path)
+ return self._activity.join(activity_ps)
+
+ @dbus.service.method(ACTIVITY_INTERFACE)
+ def get_id(self):
+ """Get the activity identifier"""
+ return self._activity.get_id()
+
+ @dbus.service.method(ACTIVITY_INTERFACE)
+ def get_type(self):
+ """Get the activity type"""
+ return self._activity.get_type()
+
+ @dbus.service.method(ACTIVITY_INTERFACE)
+ def get_shared(self):
+ """Returns True if the activity is shared on the mesh."""
+ return self._activity.get_shared()
+
+ @dbus.service.method(ACTIVITY_INTERFACE,
+ in_signature="sas", out_signature="")
+ def execute(self, command, args):
+ self._activity.execute(command, args)
class Activity(gtk.Window):
- """Base Activity class that all other Activities derive from."""
-
- def __init__(self):
- gtk.Window.__init__(self)
-
- self.connect('destroy', self.__destroy_cb)
-
- self._shared = False
- self._activity_id = None
- self._default_type = None
- self._service = None
- self._pservice = PresenceService()
-
- self.present()
-
- group = gtk.Window()
- group.realize()
- self.window.set_group(group.window)
-
- bus = dbus.SessionBus()
- xid = self.window.xid
-
- bus_name = dbus.service.BusName(get_service_name(xid), bus=bus)
- self._bus = ActivityDbusService(bus_name, get_object_path(xid))
- self._bus.start(self._pservice, self)
-
- def set_type(self, activity_type):
- """Sets the activity type."""
- self._activity_type = activity_type
- self._default_type = activity.get_default_type(activity_type)
-
- def get_type(self):
- """Gets the activity type."""
- return self._activity_type
-
- def get_default_type(self):
- return self._default_type
-
- def get_shared(self):
- """Returns TRUE if the activity is shared on the mesh."""
- return self._shared
-
- def get_id(self):
- """Get the unique activity identifier."""
- if self._activity_id == None:
- self._activity_id = sugar.util.unique_id()
- return self._activity_id
-
- def join(self, activity_ps):
- """Join an activity shared on the network."""
- self._shared = True
- self._activity_id = activity_ps.get_id()
-
- # Publish the default service, it's a copy of
- # one of those we found on the network.
- services = activity_ps.get_services_of_type(self._default_type)
- if len(services) > 0:
- service = services[0]
- addr = service.get_address()
- port = service.get_port()
- properties = service.get_published_values()
- self._service = self._pservice.share_activity(
- self, self._default_type, properties, addr, port)
- else:
- logging.error('Cannot join the activity')
-
- def share(self):
- """Share the activity on the network."""
- logging.debug('Share activity %s on the network.' % self.get_id())
-
- self._service = self._pservice.share_activity(self, self._default_type)
- self._shared = True
-
- def execute(self, command, args):
- """Execute the given command with args"""
- pass
-
- def __destroy_cb(self, window):
- if self._bus:
- del self._bus
- self._bus = None
- if self._service:
- self._pservice.unregister_service(self._service)
+ """Base Activity class that all other Activities derive from."""
+
+ def __init__(self):
+ gtk.Window.__init__(self)
+
+ self.connect('destroy', self.__destroy_cb)
+
+ self._shared = False
+ self._activity_id = None
+ self._default_type = None
+ self._service = None
+ self._pservice = PresenceService()
+
+ self.present()
+
+ group = gtk.Window()
+ group.realize()
+ self.window.set_group(group.window)
+
+ bus = dbus.SessionBus()
+ xid = self.window.xid
+
+ bus_name = dbus.service.BusName(get_service_name(xid), bus=bus)
+ self._bus = ActivityDbusService(bus_name, get_object_path(xid))
+ self._bus.start(self._pservice, self)
+
+ def set_type(self, activity_type):
+ """Sets the activity type."""
+ self._activity_type = activity_type
+ self._default_type = activity.get_default_type(activity_type)
+
+ def get_type(self):
+ """Gets the activity type."""
+ return self._activity_type
+
+ def get_default_type(self):
+ return self._default_type
+
+ def get_shared(self):
+ """Returns TRUE if the activity is shared on the mesh."""
+ return self._shared
+
+ def get_id(self):
+ """Get the unique activity identifier."""
+ if self._activity_id == None:
+ self._activity_id = sugar.util.unique_id()
+ return self._activity_id
+
+ def join(self, activity_ps):
+ """Join an activity shared on the network."""
+ self._shared = True
+ self._activity_id = activity_ps.get_id()
+
+ # Publish the default service, it's a copy of
+ # one of those we found on the network.
+ services = activity_ps.get_services_of_type(self._default_type)
+ if len(services) > 0:
+ service = services[0]
+ addr = service.get_address()
+ port = service.get_port()
+ properties = service.get_published_values()
+ self._service = self._pservice.share_activity(
+ self, self._default_type, properties, addr, port)
+ else:
+ logging.error('Cannot join the activity')
+
+ def share(self):
+ """Share the activity on the network."""
+ logging.debug('Share activity %s on the network.' % self.get_id())
+
+ self._service = self._pservice.share_activity(self, self._default_type)
+ self._shared = True
+
+ def execute(self, command, args):
+ """Execute the given command with args"""
+ pass
+
+ def __destroy_cb(self, window):
+ if self._bus:
+ del self._bus
+ self._bus = None
+ if self._service:
+ self._pservice.unregister_service(self._service)
diff --git a/sugar/activity/ActivityFactory.py b/sugar/activity/ActivityFactory.py
index 66eba74..ee131ef 100644
--- a/sugar/activity/ActivityFactory.py
+++ b/sugar/activity/ActivityFactory.py
@@ -27,72 +27,72 @@ from sugar.presence.PresenceService import PresenceService
from sugar.activity import Activity
def get_path(activity_name):
- """Returns the activity path"""
- return '/' + activity_name.replace('.', '/')
+ """Returns the activity path"""
+ return '/' + activity_name.replace('.', '/')
class ActivityFactory(dbus.service.Object):
- """Dbus service that takes care of creating new instances of an activity"""
+ """Dbus service that takes care of creating new instances of an activity"""
- def __init__(self, activity_type, activity_class):
- self._activity_type = activity_type
- self._activities = []
+ def __init__(self, activity_type, activity_class):
+ self._activity_type = activity_type
+ self._activities = []
- splitted_module = activity_class.rsplit('.', 1)
- module_name = splitted_module[0]
- class_name = splitted_module[1]
+ splitted_module = activity_class.rsplit('.', 1)
+ module_name = splitted_module[0]
+ class_name = splitted_module[1]
- module = __import__(module_name)
- for comp in module_name.split('.')[1:]:
- module = getattr(module, comp)
- if hasattr(module, 'start'):
- module.start()
+ module = __import__(module_name)
+ for comp in module_name.split('.')[1:]:
+ module = getattr(module, comp)
+ if hasattr(module, 'start'):
+ module.start()
- self._module = module
- self._constructor = getattr(module, class_name)
-
- bus = dbus.SessionBus()
- factory = activity_type
- bus_name = dbus.service.BusName(factory, bus = bus)
- dbus.service.Object.__init__(self, bus_name, get_path(factory))
+ self._module = module
+ self._constructor = getattr(module, class_name)
+
+ bus = dbus.SessionBus()
+ factory = activity_type
+ bus_name = dbus.service.BusName(factory, bus = bus)
+ dbus.service.Object.__init__(self, bus_name, get_path(factory))
- @dbus.service.method("com.redhat.Sugar.ActivityFactory")
- def create(self):
- activity = self._constructor()
- activity.set_type(self._activity_type)
+ @dbus.service.method("com.redhat.Sugar.ActivityFactory")
+ def create(self):
+ activity = self._constructor()
+ activity.set_type(self._activity_type)
- self._activities.append(activity)
- activity.connect('destroy', self._activity_destroy_cb)
+ self._activities.append(activity)
+ activity.connect('destroy', self._activity_destroy_cb)
- return activity.window.xid
+ return activity.window.xid
- def _activity_destroy_cb(self, activity):
- self._activities.remove(activity)
+ def _activity_destroy_cb(self, activity):
+ self._activities.remove(activity)
- if hasattr(self._module, 'stop'):
- self._module.stop()
+ if hasattr(self._module, 'stop'):
+ self._module.stop()
- if len(self._activities) == 0:
- gtk.main_quit()
+ if len(self._activities) == 0:
+ gtk.main_quit()
def create(activity_name):
- """Create a new activity from his name."""
- bus = dbus.SessionBus()
+ """Create a new activity from his name."""
+ bus = dbus.SessionBus()
- factory_name = activity_name
- factory_path = get_path(factory_name)
+ factory_name = activity_name
+ factory_path = get_path(factory_name)
- proxy_obj = bus.get_object(factory_name, factory_path)
- factory = dbus.Interface(proxy_obj, "com.redhat.Sugar.ActivityFactory")
+ proxy_obj = bus.get_object(factory_name, factory_path)
+ factory = dbus.Interface(proxy_obj, "com.redhat.Sugar.ActivityFactory")
- xid = factory.create()
+ xid = factory.create()
- bus = dbus.SessionBus()
- proxy_obj = bus.get_object(Activity.get_service_name(xid),
- Activity.get_object_path(xid))
- activity = dbus.Interface(proxy_obj, Activity.ACTIVITY_INTERFACE)
+ bus = dbus.SessionBus()
+ proxy_obj = bus.get_object(Activity.get_service_name(xid),
+ Activity.get_object_path(xid))
+ activity = dbus.Interface(proxy_obj, Activity.ACTIVITY_INTERFACE)
- return activity
+ return activity
def register_factory(name, activity_class):
- """Register the activity factory."""
- factory = ActivityFactory(name, activity_class)
+ """Register the activity factory."""
+ factory = ActivityFactory(name, activity_class)
diff --git a/sugar/activity/__init__.py b/sugar/activity/__init__.py
index 959c0a1..1e606d5 100644
--- a/sugar/activity/__init__.py
+++ b/sugar/activity/__init__.py
@@ -9,10 +9,10 @@ sizes = 'gtk-large-toolbar=%d, %d' % (grid.dimension(1), grid.dimension(1))
settings.set_string_property('gtk-icon-sizes', sizes, '')
def get_default_type(activity_type):
- """Get the activity default type.
+ """Get the activity default type.
- It's the type of the main network service which tracks presence
+ It's the type of the main network service which tracks presence
and provides info about the activity, for example the title."""
- splitted_id = activity_type.split('.')
- splitted_id.reverse()
- return '_' + '_'.join(splitted_id) + '._udp'
+ splitted_id = activity_type.split('.')
+ splitted_id.reverse()
+ return '_' + '_'.join(splitted_id) + '._udp'
diff --git a/sugar/activity/bundle.py b/sugar/activity/bundle.py
index f9263a3..00d2d52 100644
--- a/sugar/activity/bundle.py
+++ b/sugar/activity/bundle.py
@@ -4,83 +4,83 @@ import os
from ConfigParser import ConfigParser
class Bundle:
- """Info about an activity bundle. Wraps the activity.info file."""
- def __init__(self, path):
- self._name = None
- self._icon = None
- self._service_name = None
- self._show_launcher = True
- self._valid = True
- self._path = path
- self._activity_version = 0
-
- info_path = os.path.join(path, 'activity', 'activity.info')
- if os.path.isfile(info_path):
- self._parse_info(info_path)
- else:
- self._valid = False
-
- def _parse_info(self, info_path):
- cp = ConfigParser()
- cp.read([info_path])
-
- section = 'Activity'
-
- if cp.has_option(section, 'service_name'):
- self._service_name = cp.get(section, 'service_name')
- else:
- self._valid = False
- logging.error('%s must specify a service name' % self._path)
-
- if cp.has_option(section, 'name'):
- self._name = cp.get(section, 'name')
- else:
- self._valid = False
- logging.error('%s must specify a name' % self._path)
-
- if cp.has_option(section, 'exec'):
- self._exec = cp.get(section, 'exec')
- else:
- self._valid = False
- logging.error('%s must specify an exec' % self._path)
-
- if cp.has_option(section, 'show_launcher'):
- if cp.get(section, 'show_launcher') == 'no':
- self._show_launcher = False
-
- if cp.has_option(section, 'icon'):
- self._icon = cp.get(section, 'icon')
-
- if cp.has_option(section, 'activity_version'):
- self._activity_version = int(cp.get(section, 'activity_version'))
-
- def is_valid(self):
- return self._valid
-
- def get_path(self):
- """Get the activity bundle path."""
- return self._path
-
- def get_name(self):
- """Get the activity user visible name."""
- return self._name
-
- def get_service_name(self):
- """Get the activity service name"""
- return self._service_name
-
- def get_icon(self):
- """Get the activity icon name"""
- return self._icon
-
- def get_activity_version(self):
- """Get the activity version"""
- return self._activity_version
-
- def get_exec(self):
- """Get the command to execute to launch the activity factory"""
- return self._exec
-
- def get_show_launcher(self):
- """Get whether there should be a visible launcher for the activity"""
- return self._show_launcher
+ """Info about an activity bundle. Wraps the activity.info file."""
+ def __init__(self, path):
+ self._name = None
+ self._icon = None
+ self._service_name = None
+ self._show_launcher = True
+ self._valid = True
+ self._path = path
+ self._activity_version = 0
+
+ info_path = os.path.join(path, 'activity', 'activity.info')
+ if os.path.isfile(info_path):
+ self._parse_info(info_path)
+ else:
+ self._valid = False
+
+ def _parse_info(self, info_path):
+ cp = ConfigParser()
+ cp.read([info_path])
+
+ section = 'Activity'
+
+ if cp.has_option(section, 'service_name'):
+ self._service_name = cp.get(section, 'service_name')
+ else:
+ self._valid = False
+ logging.error('%s must specify a service name' % self._path)
+
+ if cp.has_option(section, 'name'):
+ self._name = cp.get(section, 'name')
+ else:
+ self._valid = False
+ logging.error('%s must specify a name' % self._path)
+
+ if cp.has_option(section, 'exec'):
+ self._exec = cp.get(section, 'exec')
+ else:
+ self._valid = False
+ logging.error('%s must specify an exec' % self._path)
+
+ if cp.has_option(section, 'show_launcher'):
+ if cp.get(section, 'show_launcher') == 'no':
+ self._show_launcher = False
+
+ if cp.has_option(section, 'icon'):
+ self._icon = cp.get(section, 'icon')
+
+ if cp.has_option(section, 'activity_version'):
+ self._activity_version = int(cp.get(section, 'activity_version'))
+
+ def is_valid(self):
+ return self._valid
+
+ def get_path(self):
+ """Get the activity bundle path."""
+ return self._path
+
+ def get_name(self):
+ """Get the activity user visible name."""
+ return self._name
+
+ def get_service_name(self):
+ """Get the activity service name"""
+ return self._service_name
+
+ def get_icon(self):
+ """Get the activity icon name"""
+ return self._icon
+
+ def get_activity_version(self):
+ """Get the activity version"""
+ return self._activity_version
+
+ def get_exec(self):
+ """Get the command to execute to launch the activity factory"""
+ return self._exec
+
+ def get_show_launcher(self):
+ """Get whether there should be a visible launcher for the activity"""
+ return self._show_launcher
diff --git a/sugar/activity/bundlebuilder.py b/sugar/activity/bundlebuilder.py
index c313523..4ab4f7d 100644
--- a/sugar/activity/bundlebuilder.py
+++ b/sugar/activity/bundlebuilder.py
@@ -25,71 +25,71 @@ import shutil
from sugar.activity.bundle import Bundle
class _SvnFileList(list):
- def __init__(self):
- f = os.popen('svn list -R')
- for line in f.readlines():
- filename = line.strip()
- if os.path.isfile(filename):
- self.append(filename)
- f.close()
+ def __init__(self):
+ f = os.popen('svn list -R')
+ for line in f.readlines():
+ filename = line.strip()
+ if os.path.isfile(filename):
+ self.append(filename)
+ f.close()
class _GitFileList(list):
- def __init__(self):
- f = os.popen('git-ls-files')
- for line in f.readlines():
- filename = line.strip()
- if not filename.startswith('.'):
- self.append(filename)
- f.close()
+ def __init__(self):
+ f = os.popen('git-ls-files')
+ for line in f.readlines():
+ filename = line.strip()
+ if not filename.startswith('.'):
+ self.append(filename)
+ f.close()
def _extract_bundle(source_file, dest_dir):
- if not os.path.exists(dest_dir):
- os.mkdir(dest_dir)
+ if not os.path.exists(dest_dir):
+ os.mkdir(dest_dir)
- zf = zipfile.ZipFile(source_file)
+ zf = zipfile.ZipFile(source_file)
- for i, name in enumerate(zf.namelist()):
- path = os.path.join(dest_dir, name)
-
- if not os.path.exists(os.path.dirname(path)):
- os.makedirs(os.path.dirname(path))
+ for i, name in enumerate(zf.namelist()):
+ path = os.path.join(dest_dir, name)
+
+ if not os.path.exists(os.path.dirname(path)):
+ os.makedirs(os.path.dirname(path))
- outfile = open(path, 'wb')
- outfile.write(zf.read(name))
- outfile.flush()
- outfile.close()
+ outfile = open(path, 'wb')
+ outfile.write(zf.read(name))
+ outfile.flush()
+ outfile.close()
def _get_source_path():
- return os.getcwd()
+ return os.getcwd()
def _get_activities_path():
- path = os.path.expanduser('~/Activities')
- if not os.path.isdir(path):
- os.mkdir(path)
- return path
+ path = os.path.expanduser('~/Activities')
+ if not os.path.isdir(path):
+ os.mkdir(path)
+ return path
def _get_bundle_dir():
- bundle_name = os.path.basename(_get_source_path())
- return bundle_name + '.activity'
+ bundle_name = os.path.basename(_get_source_path())
+ return bundle_name + '.activity'
def _get_install_dir(prefix):
- return os.path.join(prefix, 'share/activities')
+ return os.path.join(prefix, 'share/activities')
def _get_bundle_path():
- return os.path.join(_get_activities_path(), _get_bundle_dir())
+ return os.path.join(_get_activities_path(), _get_bundle_dir())
def _get_package_name():
- bundle = Bundle(_get_source_path())
- zipname = '%s-%d.xo' % (bundle.get_name(), bundle.get_activity_version())
- return zipname
+ bundle = Bundle(_get_source_path())
+ zipname = '%s-%d.xo' % (bundle.get_name(), bundle.get_activity_version())
+ return zipname
def _delete_backups(arg, dirname, names):
- for name in names:
- if name.endswith('~') or name.endswith('pyc'):
- os.remove(os.path.join(dirname, name))
+ for name in names:
+ if name.endswith('~') or name.endswith('pyc'):
+ os.remove(os.path.join(dirname, name))
def cmd_help():
- print 'Usage: \n\
+ print 'Usage: \n\
setup.py dev - setup for development \n\
setup.py dist - create a bundle package \n\
setup.py install - install the bundle \n\
@@ -98,59 +98,59 @@ setup.py help - print this message \n\
'
def cmd_dev():
- bundle_path = get_bundle_path()
- try:
- os.symlink(_get_source_path(), bundle_path)
- except OSError:
- if os.path.islink(bundle_path):
- print 'ERROR - The bundle has been already setup for development.'
- else:
- print 'ERROR - A bundle with the same name is already installed.'
+ bundle_path = get_bundle_path()
+ try:
+ os.symlink(_get_source_path(), bundle_path)
+ except OSError:
+ if os.path.islink(bundle_path):
+ print 'ERROR - The bundle has been already setup for development.'
+ else:
+ print 'ERROR - A bundle with the same name is already installed.'
def cmd_dist():
- if os.path.isdir('.git'):
- file_list = _GitFileList()
- elif os.path.isdir('.svn'):
- file_list = _SvnFileList()
- else:
- print 'ERROR - The command works only with git or svn repositories.'
-
- zipname = _get_package_name()
- bundle_zip = zipfile.ZipFile(zipname, 'w', zipfile.ZIP_DEFLATED)
-
- for filename in file_list:
- arcname = os.path.join(_get_bundle_dir(), filename)
- bundle_zip.write(filename, arcname)
-
- bundle_zip.close()
+ if os.path.isdir('.git'):
+ file_list = _GitFileList()
+ elif os.path.isdir('.svn'):
+ file_list = _SvnFileList()
+ else:
+ print 'ERROR - The command works only with git or svn repositories.'
+
+ zipname = _get_package_name()
+ bundle_zip = zipfile.ZipFile(zipname, 'w', zipfile.ZIP_DEFLATED)
+
+ for filename in file_list:
+ arcname = os.path.join(_get_bundle_dir(), filename)
+ bundle_zip.write(filename, arcname)
+
+ bundle_zip.close()
def cmd_install(prefix):
- cmd_dist()
- cmd_uninstall(prefix)
- _extract_bundle(_get_package_name(), _get_install_dir(prefix))
+ cmd_dist()
+ cmd_uninstall(prefix)
+ _extract_bundle(_get_package_name(), _get_install_dir(prefix))
def cmd_uninstall(prefix):
- path = os.path.join(_get_install_dir(prefix), _get_bundle_dir())
- if os.path.isdir(path):
- shutil.rmtree(path)
+ path = os.path.join(_get_install_dir(prefix), _get_bundle_dir())
+ if os.path.isdir(path):
+ shutil.rmtree(path)
def cmd_clean():
- os.path.walk('.', delete_backups, None)
+ os.path.walk('.', delete_backups, None)
def start():
- if len(sys.argv) < 2:
- cmd_help()
- elif sys.argv[1] == 'build':
- pass
- elif sys.argv[1] == 'dev':
- cmd_dev()
- elif sys.argv[1] == 'dist':
- cmd_dist()
- elif sys.argv[1] == 'install' and len(sys.argv) == 3:
- cmd_install(sys.argv[2])
- elif sys.argv[1] == 'uninstall' and len(sys.argv) == 3:
- cmd_uninstall(sys.argv[2])
- elif sys.argv[1] == 'clean':
- cmd_clean()
- else:
- cmd_help()
+ if len(sys.argv) < 2:
+ cmd_help()
+ elif sys.argv[1] == 'build':
+ pass
+ elif sys.argv[1] == 'dev':
+ cmd_dev()
+ elif sys.argv[1] == 'dist':
+ cmd_dist()
+ elif sys.argv[1] == 'install' and len(sys.argv) == 3:
+ cmd_install(sys.argv[2])
+ elif sys.argv[1] == 'uninstall' and len(sys.argv) == 3:
+ cmd_uninstall(sys.argv[2])
+ elif sys.argv[1] == 'clean':
+ cmd_clean()
+ else:
+ cmd_help()
diff --git a/sugar/activity/bundleregistry.py b/sugar/activity/bundleregistry.py
index f9adbca..aa7d70a 100644
--- a/sugar/activity/bundleregistry.py
+++ b/sugar/activity/bundleregistry.py
@@ -6,51 +6,51 @@ from sugar import env
from sugar import util
class _ServiceManager(object):
- def __init__(self):
- self._path = env.get_user_service_dir()
+ def __init__(self):
+ self._path = env.get_user_service_dir()
- def add(self, bundle):
- name = bundle.get_service_name()
+ def add(self, bundle):
+ name = bundle.get_service_name()
- # FIXME evil hack. Probably need to fix Exec spec
- full_exec = env.get_shell_bin_dir() + '/' + bundle.get_exec()
- full_exec += ' ' + bundle.get_path()
+ # FIXME evil hack. Probably need to fix Exec spec
+ full_exec = env.get_shell_bin_dir() + '/' + bundle.get_exec()
+ full_exec += ' ' + bundle.get_path()
- util.write_service(name, full_exec, self._path)
+ util.write_service(name, full_exec, self._path)
class BundleRegistry:
- """Service that tracks the available activity bundles"""
-
- def __init__(self):
- self._bundles = {}
- self._search_path = []
- self._service_manager = _ServiceManager()
-
- def get_bundle(self, service_name):
- """Returns an bundle given his service name"""
- if self._bundles.has_key(service_name):
- return self._bundles[service_name]
- else:
- return None
-
- def add_search_path(self, path):
- """Add a directory to the bundles search path"""
- self._search_path.append(path)
- self._scan_directory(path)
-
- def __iter__(self):
- return self._bundles.values().__iter__()
-
- def _scan_directory(self, path):
- if os.path.isdir(path):
- for f in os.listdir(path):
- bundle_dir = os.path.join(path, f)
- if os.path.isdir(bundle_dir) and \
- bundle_dir.endswith('.activity'):
- self._add_bundle(bundle_dir)
-
- def _add_bundle(self, bundle_path):
- bundle = Bundle(bundle_path)
- if bundle.is_valid():
- self._bundles[bundle.get_service_name()] = bundle
- self._service_manager.add(bundle)
+ """Service that tracks the available activity bundles"""
+
+ def __init__(self):
+ self._bundles = {}
+ self._search_path = []
+ self._service_manager = _ServiceManager()
+
+ def get_bundle(self, service_name):
+ """Returns an bundle given his service name"""
+ if self._bundles.has_key(service_name):
+ return self._bundles[service_name]
+ else:
+ return None
+
+ def add_search_path(self, path):
+ """Add a directory to the bundles search path"""
+ self._search_path.append(path)
+ self._scan_directory(path)
+
+ def __iter__(self):
+ return self._bundles.values().__iter__()
+
+ def _scan_directory(self, path):
+ if os.path.isdir(path):
+ for f in os.listdir(path):
+ bundle_dir = os.path.join(path, f)
+ if os.path.isdir(bundle_dir) and \
+ bundle_dir.endswith('.activity'):
+ self._add_bundle(bundle_dir)
+
+ def _add_bundle(self, bundle_path):
+ bundle = Bundle(bundle_path)
+ if bundle.is_valid():
+ self._bundles[bundle.get_service_name()] = bundle
+ self._service_manager.add(bundle)
diff --git a/sugar/chat/ActivityChat.py b/sugar/chat/ActivityChat.py
index 1892672..ecba9af 100644
--- a/sugar/chat/ActivityChat.py
+++ b/sugar/chat/ActivityChat.py
@@ -20,48 +20,48 @@ import logging
from sugar.chat.GroupChat import GroupChat
class ActivityChat(GroupChat):
- SERVICE_TYPE = "_olpc_activity_chat._udp"
+ SERVICE_TYPE = "_olpc_activity_chat._udp"
- def __init__(self, activity):
- GroupChat.__init__(self)
- self._chat_service = None
+ def __init__(self, activity):
+ GroupChat.__init__(self)
+ self._chat_service = None
- self.connect('destroy', self._destroy_cb)
+ self.connect('destroy', self._destroy_cb)
- self._activity = activity
- self._pservice.register_service_type(ActivityChat.SERVICE_TYPE)
- self._pservice.connect('service-appeared', self._service_appeared_cb)
+ self._activity = activity
+ self._pservice.register_service_type(ActivityChat.SERVICE_TYPE)
+ self._pservice.connect('service-appeared', self._service_appeared_cb)
- # Find an existing activity chat to latch onto
- ps_activity = self._pservice.get_activity(activity.get_id())
- if ps_activity is not None:
- services = ps_activity.get_services_of_type(ActivityChat.SERVICE_TYPE)
- if len(services) > 0:
- self._service_appeared_cb(self._pservice, services[0])
+ # Find an existing activity chat to latch onto
+ ps_activity = self._pservice.get_activity(activity.get_id())
+ if ps_activity is not None:
+ services = ps_activity.get_services_of_type(ActivityChat.SERVICE_TYPE)
+ if len(services) > 0:
+ self._service_appeared_cb(self._pservice, services[0])
- def _service_appeared_cb(self, pservice, service):
- if service.get_activity_id() != self._activity.get_id():
- return
- if service.get_type() != ActivityChat.SERVICE_TYPE:
- return
- if self._chat_service:
- return
+ def _service_appeared_cb(self, pservice, service):
+ if service.get_activity_id() != self._activity.get_id():
+ return
+ if service.get_type() != ActivityChat.SERVICE_TYPE:
+ return
+ if self._chat_service:
+ return
- logging.debug('Activity chat service appeared, setup the stream.')
- # Ok, there's an existing chat service that we copy
- # parameters and such from
- addr = service.get_address()
- port = service.get_port()
- self._chat_service = self._pservice.share_activity(self._activity,
- stype=ActivityChat.SERVICE_TYPE, address=addr, port=port)
- self._setup_stream(self._chat_service)
+ logging.debug('Activity chat service appeared, setup the stream.')
+ # Ok, there's an existing chat service that we copy
+ # parameters and such from
+ addr = service.get_address()
+ port = service.get_port()
+ self._chat_service = self._pservice.share_activity(self._activity,
+ stype=ActivityChat.SERVICE_TYPE, address=addr, port=port)
+ self._setup_stream(self._chat_service)
- def share(self):
- """Only called when we share the activity this chat is tied to."""
- self._chat_service = self._pservice.share_activity(self._activity,
- stype=ActivityChat.SERVICE_TYPE)
- self._setup_stream(self._chat_service)
+ def share(self):
+ """Only called when we share the activity this chat is tied to."""
+ self._chat_service = self._pservice.share_activity(self._activity,
+ stype=ActivityChat.SERVICE_TYPE)
+ self._setup_stream(self._chat_service)
- def _destroy_cb(self, widget):
- if self._chat_service:
- self._pservice.unregister_service(self._chat_service)
+ def _destroy_cb(self, widget):
+ if self._chat_service:
+ self._pservice.unregister_service(self._chat_service)
diff --git a/sugar/chat/Chat.py b/sugar/chat/Chat.py
index eb1b4da..aae6450 100644
--- a/sugar/chat/Chat.py
+++ b/sugar/chat/Chat.py
@@ -37,244 +37,244 @@ import richtext
PANGO_SCALE = 1024 # Where is this defined?
class Chat(gtk.VBox):
- SERVICE_TYPE = "_olpc_chat._tcp"
- SERVICE_PORT = 6100
-
- TEXT_MODE = 0
- SKETCH_MODE = 1
-
- def __init__(self):
- gtk.VBox.__init__(self, False, 6)
-
- self._pservice = PresenceService.get_instance()
-
- self._stream_writer = None
- self.set_border_width(12)
-
- chat_vbox = gtk.VBox()
- chat_vbox.set_spacing(6)
-
- self._chat_sw = gtk.ScrolledWindow()
- self._chat_sw.set_shadow_type(gtk.SHADOW_IN)
- self._chat_sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
- self._chat_view = richtext.RichTextView()
- self._chat_view.connect("link-clicked", self.__link_clicked_cb)
- self._chat_view.set_editable(False)
- self._chat_view.set_cursor_visible(False)
- self._chat_view.set_pixels_above_lines(7)
- self._chat_view.set_left_margin(5)
- self._chat_sw.add(self._chat_view)
- self._chat_view.show()
- chat_vbox.pack_start(self._chat_sw)
- self._chat_sw.show()
-
- self.pack_start(chat_vbox)
- chat_vbox.show()
-
- self._mode = Chat.TEXT_MODE
- self._editor = ChatEditor(self, ChatEditor.TEXT_MODE)
-
- toolbar = ChatToolbar(self._editor)
- self.pack_start(toolbar, False)
- toolbar.show()
-
- self.pack_start(self._editor, False)
- self._editor.show()
-
- self.connect("key-press-event", self.__key_press_event_cb)
-
- def __key_press_event_cb(self, window, event):
- if event.keyval == gtk.keysyms.s and \
- event.state & gtk.gdk.CONTROL_MASK:
- if self.get_mode() == Chat.SKETCH_MODE:
- self.set_mode(Chat.TEXT_MODE)
- elif self.get_mode() == Chat.TEXT_MODE:
- self.set_mode(Chat.SKETCH_MODE)
-
- def get_mode(self):
- return self._mode
-
- def set_mode(self, mode):
- self._mode = mode
- if self._mode == Chat.TEXT_MODE:
- self._editor.set_mode(ChatEditor.TEXT_MODE)
- elif self._mode == Chat.SKETCH_MODE:
- self._editor.set_mode(ChatEditor.SKETCH_MODE)
-
- def __get_browser_shell(self):
- bus = dbus.SessionBus()
- proxy_obj = bus.get_object('com.redhat.Sugar.Browser', '/com/redhat/Sugar/Browser')
- self._browser_shell = dbus.Interface(proxy_obj, 'com.redhat.Sugar.BrowserShell')
-
- def __link_clicked_cb(self, view, address):
- self.__get_browser_shell().open_browser(address)
-
- def _scroll_chat_view_to_bottom(self):
- # Only scroll to bottom if the view is already close to the bottom
- vadj = self._chat_sw.get_vadjustment()
- if vadj.value + vadj.page_size > vadj.upper * 0.8:
- vadj.value = vadj.upper - vadj.page_size
- self._chat_sw.set_vadjustment(vadj)
-
- def _message_inserted(self):
- gobject.idle_add(self._scroll_chat_view_to_bottom)
-
- def _insert_buddy(self, buf, buddy):
- # Stuff in the buddy icon, if we have one for this buddy
- icon = buddy.get_icon_pixbuf()
- if icon:
- rise = int(icon.get_height() / 4) * -1
-
- hash_string = "%s-%s" % (buddy.get_name(), buddy.get_ip4_address())
- sha_hash = sha.new()
- sha_hash.update(hash_string)
- tagname = "buddyicon-%s" % sha_hash.hexdigest()
-
- if not buf.get_tag_table().lookup(tagname):
- buf.create_tag(tagname, rise=(rise * PANGO_SCALE))
-
- aniter = buf.get_end_iter()
- buf.insert_pixbuf(aniter, icon)
- aniter.backward_char()
- enditer = buf.get_end_iter()
- buf.apply_tag_by_name(tagname, aniter, enditer)
-
- # Stick in the buddy's nickname
- if not buf.get_tag_table().lookup("nickname"):
- buf.create_tag("nickname", weight=pango.WEIGHT_BOLD)
- aniter = buf.get_end_iter()
- offset = aniter.get_offset()
- buf.insert(aniter, " " + buddy.get_name() + ": ")
- enditer = buf.get_iter_at_offset(offset)
- buf.apply_tag_by_name("nickname", aniter, enditer)
-
- def _insert_rich_message(self, buddy, msg):
- msg = Emoticons.get_instance().replace(msg)
-
- buf = self._chat_view.get_buffer()
- self._insert_buddy(buf, buddy)
-
- serializer = richtext.RichTextSerializer()
- serializer.deserialize(msg, buf)
- aniter = buf.get_end_iter()
- buf.insert(aniter, "\n")
-
- self._message_inserted()
-
- def _insert_sketch(self, buddy, svgdata):
- """Insert a sketch object into the chat buffer."""
- pbl = gtk.gdk.PixbufLoader("svg")
- pbl.write(svgdata)
- pbl.close()
- pbuf = pbl.get_pixbuf()
-
- buf = self._chat_view.get_buffer()
-
- self._insert_buddy(buf, buddy)
-
- rise = int(pbuf.get_height() / 3) * -1
- sha_hash = sha.new()
- sha_hash.update(svgdata)
- tagname = "sketch-%s" % sha_hash.hexdigest()
- if not buf.get_tag_table().lookup(tagname):
- buf.create_tag(tagname, rise=(rise * PANGO_SCALE))
-
- aniter = buf.get_end_iter()
- buf.insert_pixbuf(aniter, pbuf)
- aniter.backward_char()
- enditer = buf.get_end_iter()
- buf.apply_tag_by_name(tagname, aniter, enditer)
- aniter = buf.get_end_iter()
- buf.insert(aniter, "\n")
-
- self._message_inserted()
-
- def _get_first_richtext_chunk(self, msg):
- """Scan the message for the first richtext-tagged chunk and return it."""
- rt_last = -1
- tag_rt_start = "<richtext>"
- tag_rt_end = "</richtext>"
- rt_first = msg.find(tag_rt_start)
- length = -1
- if rt_first >= 0:
- length = len(msg)
- rt_last = msg.find(tag_rt_end, rt_first)
- if rt_first >= 0 and rt_last >= (rt_first + len(tag_rt_start)) and length > 0:
- return msg[rt_first:rt_last + len(tag_rt_end)]
- return None
-
- def _get_first_sketch_chunk(self, msg):
- """Scan the message for the first SVG-tagged chunk and return it."""
- svg_last = -1
- tag_svg_start = "<svg"
- tag_svg_end = "</svg>"
- desc_start = msg.find("<?xml version='1.0' encoding='UTF-8'?>")
- if desc_start < 0:
- return None
- ignore = msg.find("<!DOCTYPE svg")
- if ignore < 0:
- return None
- svg_first = msg.find(tag_svg_start)
- length = -1
- if svg_first >= 0:
- length = len(msg)
- svg_last = msg.find(tag_svg_end, svg_first)
- if svg_first >= 0 and svg_last >= (svg_first + len(tag_svg_start)) and length > 0:
- return msg[desc_start:svg_last + len(tag_svg_end)]
- return None
-
- def recv_message(self, message):
- """Insert a remote chat message into the chat buffer."""
- [nick, msg] = Chat.deserialize_message(message)
- buddy = self._pservice.get_buddy_by_name(nick)
- if not buddy:
- logging.error('The buddy %s is not present.' % (nick))
- return
-
- # FIXME a better way to compare buddies?
- owner = self._pservice.get_owner()
- if buddy.get_name() == owner.get_name():
- return
-
- chunk = self._get_first_richtext_chunk(msg)
- if chunk:
- self._insert_rich_message(buddy, chunk)
- return
-
- chunk = self._get_first_sketch_chunk(msg)
- if chunk:
- self._insert_sketch(buddy, chunk)
- return
-
- def set_stream_writer(self, stream_writer):
- self._stream_writer = stream_writer
-
- def send_sketch(self, svgdata):
- if not svgdata or not len(svgdata):
- return
- if self._stream_writer:
- self._stream_writer.write(self.serialize_message(svgdata))
- owner = self._pservice.get_owner()
- if owner:
- self._insert_sketch(owner, svgdata)
-
- def send_text_message(self, text):
- """Send a chat message and insert it into the local buffer."""
- if len(text) <= 0:
- return
- if self._stream_writer:
- self._stream_writer.write(self.serialize_message(text))
- else:
- logging.warning("Cannot send message, there is no stream writer")
- owner = self._pservice.get_owner()
- if owner:
- self._insert_rich_message(owner, text)
-
- def serialize_message(self, message):
- owner = self._pservice.get_owner()
- return owner.get_name() + '||' + message
-
- def deserialize_message(message):
- return message.split('||', 1)
-
- deserialize_message = staticmethod(deserialize_message)
+ SERVICE_TYPE = "_olpc_chat._tcp"
+ SERVICE_PORT = 6100
+
+ TEXT_MODE = 0
+ SKETCH_MODE = 1
+
+ def __init__(self):
+ gtk.VBox.__init__(self, False, 6)
+
+ self._pservice = PresenceService.get_instance()
+
+ self._stream_writer = None
+ self.set_border_width(12)
+
+ chat_vbox = gtk.VBox()
+ chat_vbox.set_spacing(6)
+
+ self._chat_sw = gtk.ScrolledWindow()
+ self._chat_sw.set_shadow_type(gtk.SHADOW_IN)
+ self._chat_sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
+ self._chat_view = richtext.RichTextView()
+ self._chat_view.connect("link-clicked", self.__link_clicked_cb)
+ self._chat_view.set_editable(False)
+ self._chat_view.set_cursor_visible(False)
+ self._chat_view.set_pixels_above_lines(7)
+ self._chat_view.set_left_margin(5)
+ self._chat_sw.add(self._chat_view)
+ self._chat_view.show()
+ chat_vbox.pack_start(self._chat_sw)
+ self._chat_sw.show()
+
+ self.pack_start(chat_vbox)
+ chat_vbox.show()
+
+ self._mode = Chat.TEXT_MODE
+ self._editor = ChatEditor(self, ChatEditor.TEXT_MODE)
+
+ toolbar = ChatToolbar(self._editor)
+ self.pack_start(toolbar, False)
+ toolbar.show()
+
+ self.pack_start(self._editor, False)
+ self._editor.show()
+
+ self.connect("key-press-event", self.__key_press_event_cb)
+
+ def __key_press_event_cb(self, window, event):
+ if event.keyval == gtk.keysyms.s and \
+ event.state & gtk.gdk.CONTROL_MASK:
+ if self.get_mode() == Chat.SKETCH_MODE:
+ self.set_mode(Chat.TEXT_MODE)
+ elif self.get_mode() == Chat.TEXT_MODE:
+ self.set_mode(Chat.SKETCH_MODE)
+
+ def get_mode(self):
+ return self._mode
+
+ def set_mode(self, mode):
+ self._mode = mode
+ if self._mode == Chat.TEXT_MODE:
+ self._editor.set_mode(ChatEditor.TEXT_MODE)
+ elif self._mode == Chat.SKETCH_MODE:
+ self._editor.set_mode(ChatEditor.SKETCH_MODE)
+
+ def __get_browser_shell(self):
+ bus = dbus.SessionBus()
+ proxy_obj = bus.get_object('com.redhat.Sugar.Browser', '/com/redhat/Sugar/Browser')
+ self._browser_shell = dbus.Interface(proxy_obj, 'com.redhat.Sugar.BrowserShell')
+
+ def __link_clicked_cb(self, view, address):
+ self.__get_browser_shell().open_browser(address)
+
+ def _scroll_chat_view_to_bottom(self):
+ # Only scroll to bottom if the view is already close to the bottom
+ vadj = self._chat_sw.get_vadjustment()
+ if vadj.value + vadj.page_size > vadj.upper * 0.8:
+ vadj.value = vadj.upper - vadj.page_size
+ self._chat_sw.set_vadjustment(vadj)
+
+ def _message_inserted(self):
+ gobject.idle_add(self._scroll_chat_view_to_bottom)
+
+ def _insert_buddy(self, buf, buddy):
+ # Stuff in the buddy icon, if we have one for this buddy
+ icon = buddy.get_icon_pixbuf()
+ if icon:
+ rise = int(icon.get_height() / 4) * -1
+
+ hash_string = "%s-%s" % (buddy.get_name(), buddy.get_ip4_address())
+ sha_hash = sha.new()
+ sha_hash.update(hash_string)
+ tagname = "buddyicon-%s" % sha_hash.hexdigest()
+
+ if not buf.get_tag_table().lookup(tagname):
+ buf.create_tag(tagname, rise=(rise * PANGO_SCALE))
+
+ aniter = buf.get_end_iter()
+ buf.insert_pixbuf(aniter, icon)
+ aniter.backward_char()
+ enditer = buf.get_end_iter()
+ buf.apply_tag_by_name(tagname, aniter, enditer)
+
+ # Stick in the buddy's nickname
+ if not buf.get_tag_table().lookup("nickname"):
+ buf.create_tag("nickname", weight=pango.WEIGHT_BOLD)
+ aniter = buf.get_end_iter()
+ offset = aniter.get_offset()
+ buf.insert(aniter, " " + buddy.get_name() + ": ")
+ enditer = buf.get_iter_at_offset(offset)
+ buf.apply_tag_by_name("nickname", aniter, enditer)
+
+ def _insert_rich_message(self, buddy, msg):
+ msg = Emoticons.get_instance().replace(msg)
+
+ buf = self._chat_view.get_buffer()
+ self._insert_buddy(buf, buddy)
+
+ serializer = richtext.RichTextSerializer()
+ serializer.deserialize(msg, buf)
+ aniter = buf.get_end_iter()
+ buf.insert(aniter, "\n")
+
+ self._message_inserted()
+
+ def _insert_sketch(self, buddy, svgdata):
+ """Insert a sketch object into the chat buffer."""
+ pbl = gtk.gdk.PixbufLoader("svg")
+ pbl.write(svgdata)
+ pbl.close()
+ pbuf = pbl.get_pixbuf()
+
+ buf = self._chat_view.get_buffer()
+
+ self._insert_buddy(buf, buddy)
+
+ rise = int(pbuf.get_height() / 3) * -1
+ sha_hash = sha.new()
+ sha_hash.update(svgdata)
+ tagname = "sketch-%s" % sha_hash.hexdigest()
+ if not buf.get_tag_table().lookup(tagname):
+ buf.create_tag(tagname, rise=(rise * PANGO_SCALE))
+
+ aniter = buf.get_end_iter()
+ buf.insert_pixbuf(aniter, pbuf)
+ aniter.backward_char()
+ enditer = buf.get_end_iter()
+ buf.apply_tag_by_name(tagname, aniter, enditer)
+ aniter = buf.get_end_iter()
+ buf.insert(aniter, "\n")
+
+ self._message_inserted()
+
+ def _get_first_richtext_chunk(self, msg):
+ """Scan the message for the first richtext-tagged chunk and return it."""
+ rt_last = -1
+ tag_rt_start = "<richtext>"
+ tag_rt_end = "</richtext>"
+ rt_first = msg.find(tag_rt_start)
+ length = -1
+ if rt_first >= 0:
+ length = len(msg)
+ rt_last = msg.find(tag_rt_end, rt_first)
+ if rt_first >= 0 and rt_last >= (rt_first + len(tag_rt_start)) and length > 0:
+ return msg[rt_first:rt_last + len(tag_rt_end)]
+ return None
+
+ def _get_first_sketch_chunk(self, msg):
+ """Scan the message for the first SVG-tagged chunk and return it."""
+ svg_last = -1
+ tag_svg_start = "<svg"
+ tag_svg_end = "</svg>"
+ desc_start = msg.find("<?xml version='1.0' encoding='UTF-8'?>")
+ if desc_start < 0:
+ return None
+ ignore = msg.find("<!DOCTYPE svg")
+ if ignore < 0:
+ return None
+ svg_first = msg.find(tag_svg_start)
+ length = -1
+ if svg_first >= 0:
+ length = len(msg)
+ svg_last = msg.find(tag_svg_end, svg_first)
+ if svg_first >= 0 and svg_last >= (svg_first + len(tag_svg_start)) and length > 0:
+ return msg[desc_start:svg_last + len(tag_svg_end)]
+ return None
+
+ def recv_message(self, message):
+ """Insert a remote chat message into the chat buffer."""
+ [nick, msg] = Chat.deserialize_message(message)
+ buddy = self._pservice.get_buddy_by_name(nick)
+ if not buddy:
+ logging.error('The buddy %s is not present.' % (nick))
+ return
+
+ # FIXME a better way to compare buddies?
+ owner = self._pservice.get_owner()
+ if buddy.get_name() == owner.get_name():
+ return
+
+ chunk = self._get_first_richtext_chunk(msg)
+ if chunk:
+ self._insert_rich_message(buddy, chunk)
+ return
+
+ chunk = self._get_first_sketch_chunk(msg)
+ if chunk:
+ self._insert_sketch(buddy, chunk)
+ return
+
+ def set_stream_writer(self, stream_writer):
+ self._stream_writer = stream_writer
+
+ def send_sketch(self, svgdata):
+ if not svgdata or not len(svgdata):
+ return
+ if self._stream_writer:
+ self._stream_writer.write(self.serialize_message(svgdata))
+ owner = self._pservice.get_owner()
+ if owner:
+ self._insert_sketch(owner, svgdata)
+
+ def send_text_message(self, text):
+ """Send a chat message and insert it into the local buffer."""
+ if len(text) <= 0:
+ return
+ if self._stream_writer:
+ self._stream_writer.write(self.serialize_message(text))
+ else:
+ logging.warning("Cannot send message, there is no stream writer")
+ owner = self._pservice.get_owner()
+ if owner:
+ self._insert_rich_message(owner, text)
+
+ def serialize_message(self, message):
+ owner = self._pservice.get_owner()
+ return owner.get_name() + '||' + message
+
+ def deserialize_message(message):
+ return message.split('||', 1)
+
+ deserialize_message = staticmethod(deserialize_message)
diff --git a/sugar/chat/ChatEditor.py b/sugar/chat/ChatEditor.py
index 4ee16ce..ee36688 100644
--- a/sugar/chat/ChatEditor.py
+++ b/sugar/chat/ChatEditor.py
@@ -22,83 +22,83 @@ from sugar.chat.sketchpad.SketchPad import SketchPad
import richtext
class ChatEditor(gtk.HBox):
- TEXT_MODE = 0
- SKETCH_MODE = 1
+ TEXT_MODE = 0
+ SKETCH_MODE = 1
- def __init__(self, chat, mode):
- gtk.HBox.__init__(self, False, 6)
+ def __init__(self, chat, mode):
+ gtk.HBox.__init__(self, False, 6)
- self._chat = chat
+ self._chat = chat
- self._notebook = gtk.Notebook()
- self._notebook.set_show_tabs(False)
- self._notebook.set_show_border(False)
- self._notebook.set_size_request(-1, 70)
-
- chat_view_sw = gtk.ScrolledWindow()
- chat_view_sw.set_shadow_type(gtk.SHADOW_IN)
- chat_view_sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
- self._text_view = richtext.RichTextView()
- self._text_view.connect("key-press-event", self.__key_press_event_cb)
- chat_view_sw.add(self._text_view)
- self._text_view.show()
-
- self._notebook.append_page(chat_view_sw)
- chat_view_sw.show()
-
- self._sketchpad = SketchPad()
- self._notebook.append_page(self._sketchpad)
- self._sketchpad.show()
-
- self.pack_start(self._notebook)
- self._notebook.show()
-
- send_button = gtk.Button(_("Send"))
- send_button.set_size_request(60, -1)
- send_button.connect('clicked', self.__send_button_clicked_cb)
- self.pack_start(send_button, False, True)
- send_button.show()
-
- self.set_mode(mode)
+ self._notebook = gtk.Notebook()
+ self._notebook.set_show_tabs(False)
+ self._notebook.set_show_border(False)
+ self._notebook.set_size_request(-1, 70)
+
+ chat_view_sw = gtk.ScrolledWindow()
+ chat_view_sw.set_shadow_type(gtk.SHADOW_IN)
+ chat_view_sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+ self._text_view = richtext.RichTextView()
+ self._text_view.connect("key-press-event", self.__key_press_event_cb)
+ chat_view_sw.add(self._text_view)
+ self._text_view.show()
+
+ self._notebook.append_page(chat_view_sw)
+ chat_view_sw.show()
+
+ self._sketchpad = SketchPad()
+ self._notebook.append_page(self._sketchpad)
+ self._sketchpad.show()
+
+ self.pack_start(self._notebook)
+ self._notebook.show()
+
+ send_button = gtk.Button(_("Send"))
+ send_button.set_size_request(60, -1)
+ send_button.connect('clicked', self.__send_button_clicked_cb)
+ self.pack_start(send_button, False, True)
+ send_button.show()
+
+ self.set_mode(mode)
- def set_color(self, color):
- self._sketchpad.set_color(color)
-
- def get_buffer(self):
- return self._text_view.get_buffer()
+ def set_color(self, color):
+ self._sketchpad.set_color(color)
+
+ def get_buffer(self):
+ return self._text_view.get_buffer()
- def set_mode(self, mode):
- self._mode = mode
- if self._mode == ChatEditor.SKETCH_MODE:
- self._notebook.set_current_page(1)
- elif self._mode == ChatEditor.TEXT_MODE:
- self._notebook.set_current_page(0)
+ def set_mode(self, mode):
+ self._mode = mode
+ if self._mode == ChatEditor.SKETCH_MODE:
+ self._notebook.set_current_page(1)
+ elif self._mode == ChatEditor.TEXT_MODE:
+ self._notebook.set_current_page(0)
- def __send_button_clicked_cb(self, button):
- self._send()
+ def __send_button_clicked_cb(self, button):
+ self._send()
- def _send(self):
- if self._mode == ChatEditor.SKETCH_MODE:
- self._send_sketch()
- elif self._mode == ChatEditor.TEXT_MODE:
- self._send_text()
+ def _send(self):
+ if self._mode == ChatEditor.SKETCH_MODE:
+ self._send_sketch()
+ elif self._mode == ChatEditor.TEXT_MODE:
+ self._send_text()
- def _send_sketch(self):
- self._chat.send_sketch(self._sketchpad.to_svg())
- self._sketchpad.clear()
+ def _send_sketch(self):
+ self._chat.send_sketch(self._sketchpad.to_svg())
+ self._sketchpad.clear()
- def _send_text(self):
- buf = self._text_view.get_buffer()
- text = buf.get_text(buf.get_start_iter(), buf.get_end_iter())
- if len(text.strip()) > 0:
- serializer = richtext.RichTextSerializer()
- text = serializer.serialize(buf)
- self._chat.send_text_message(text)
+ def _send_text(self):
+ buf = self._text_view.get_buffer()
+ text = buf.get_text(buf.get_start_iter(), buf.get_end_iter())
+ if len(text.strip()) > 0:
+ serializer = richtext.RichTextSerializer()
+ text = serializer.serialize(buf)
+ self._chat.send_text_message(text)
- buf.set_text("")
- buf.place_cursor(buf.get_start_iter())
-
- def __key_press_event_cb(self, text_view, event):
- if event.keyval == gtk.keysyms.Return:
- self._send()
- return True
+ buf.set_text("")
+ buf.place_cursor(buf.get_start_iter())
+
+ def __key_press_event_cb(self, text_view, event):
+ if event.keyval == gtk.keysyms.Return:
+ self._send()
+ return True
diff --git a/sugar/chat/ChatToolbar.py b/sugar/chat/ChatToolbar.py
index 8e88a68..d633138 100644
--- a/sugar/chat/ChatToolbar.py
+++ b/sugar/chat/ChatToolbar.py
@@ -22,129 +22,129 @@ from sugar.chat.sketchpad.Toolbox import Toolbox
import richtext
class ChatToolbar(gtk.HBox):
- def __init__(self, editor):
- gtk.HBox.__init__(self, False, 24)
-
- self._editor = editor
- self._emt_popup = None
-
- spring = gtk.Label('')
- self.pack_start(spring, True)
- spring.show()
-
- toolbox = richtext.RichTextToolbox(editor.get_buffer())
- self.pack_start(toolbox, False)
- toolbox.show()
-
- item = gtk.Button()
- item.unset_flags(gtk.CAN_FOCUS)
-
- e_hbox = gtk.HBox(False, 6)
-
- e_image = gtk.Image()
- e_image.set_from_icon_name('stock_smiley-1', gtk.ICON_SIZE_SMALL_TOOLBAR)
- e_hbox.pack_start(e_image)
- e_image.show()
-
- arrow = gtk.Arrow(gtk.ARROW_DOWN, gtk.SHADOW_NONE)
- e_hbox.pack_start(arrow)
- arrow.show()
-
- item.set_image(e_hbox)
- item.connect("clicked", self.__emoticons_button_clicked_cb)
- toolbox.pack_start(item, False)
- item.show()
-
-# separator = gtk.SeparatorToolItem()
-# toolbar.insert(separator, -1)
-# separator.show()
-
-# item = gtk.MenuToolButton(None, "Links")
-# item.set_menu(gtk.Menu())
-# item.connect("show-menu", self.__show_link_menu_cb)
-# toolbar.insert(item, -1)
-# item.show()
-
- toolbox = Toolbox()
- toolbox.connect('color-selected', self._color_selected)
- self.pack_start(toolbox, False)
- toolbox.show()
-
- spring = gtk.Label('')
- self.pack_start(spring, True)
- spring.show()
-
- def _color_selected(self, toolbox, color):
- self._editor.set_color(color)
-
- def __link_activate_cb(self, item, link):
- buf = self._editor.get_buffer()
- buf.append_link(link['title'], link['address'])
-
- def __show_link_menu_cb(self, button):
- menu = gtk.Menu()
-
- links = self.__get_browser_shell().get_links()
-
- for link in links:
- item = gtk.MenuItem(link['title'], False)
- item.connect("activate", self.__link_activate_cb, link)
- menu.append(item)
- item.show()
-
- button.set_menu(menu)
-
- def _create_emoticons_popup(self):
- model = gtk.ListStore(gtk.gdk.Pixbuf, str)
-
- for name in Emoticons.get_instance().get_all():
- icon_theme = gtk.icon_theme_get_default()
- try:
- pixbuf = icon_theme.load_icon(name, 16, 0)
- model.append([pixbuf, name])
- except gobject.GError:
- pass
-
- icon_view = gtk.IconView(model)
- icon_view.connect('selection-changed', self.__emoticon_selection_changed_cb)
- icon_view.set_pixbuf_column(0)
- icon_view.set_selection_mode(gtk.SELECTION_SINGLE)
-
- frame = gtk.Frame()
- frame.set_shadow_type(gtk.SHADOW_ETCHED_IN)
- frame.add(icon_view)
- icon_view.show()
-
- window = gtk.Window(gtk.WINDOW_POPUP)
- window.add(frame)
- frame.show()
-
- return window
-
- def __emoticon_selection_changed_cb(self, icon_view):
- items = icon_view.get_selected_items()
- if items:
- model = icon_view.get_model()
- icon_name = model[items[0]][1]
- self._editor.get_buffer().append_icon(icon_name)
- self._emt_popup.hide()
-
- def __emoticons_button_clicked_cb(self, button):
- # FIXME grabs...
- if not self._emt_popup:
- self._emt_popup = self._create_emoticons_popup()
-
- if self._emt_popup.get_property('visible'):
- self._emt_popup.hide()
- else:
- width = 180
- height = 130
-
- self._emt_popup.set_default_size(width, height)
-
- [x, y] = button.window.get_origin()
- x += button.allocation.x
- y += button.allocation.y - height
- self._emt_popup.move(x, y)
-
- self._emt_popup.show()
+ def __init__(self, editor):
+ gtk.HBox.__init__(self, False, 24)
+
+ self._editor = editor
+ self._emt_popup = None
+
+ spring = gtk.Label('')
+ self.pack_start(spring, True)
+ spring.show()
+
+ toolbox = richtext.RichTextToolbox(editor.get_buffer())
+ self.pack_start(toolbox, False)
+ toolbox.show()
+
+ item = gtk.Button()
+ item.unset_flags(gtk.CAN_FOCUS)
+
+ e_hbox = gtk.HBox(False, 6)
+
+ e_image = gtk.Image()
+ e_image.set_from_icon_name('stock_smiley-1', gtk.ICON_SIZE_SMALL_TOOLBAR)
+ e_hbox.pack_start(e_image)
+ e_image.show()
+
+ arrow = gtk.Arrow(gtk.ARROW_DOWN, gtk.SHADOW_NONE)
+ e_hbox.pack_start(arrow)
+ arrow.show()
+
+ item.set_image(e_hbox)
+ item.connect("clicked", self.__emoticons_button_clicked_cb)
+ toolbox.pack_start(item, False)
+ item.show()
+
+# separator = gtk.SeparatorToolItem()
+# toolbar.insert(separator, -1)
+# separator.show()
+
+# item = gtk.MenuToolButton(None, "Links")
+# item.set_menu(gtk.Menu())
+# item.connect("show-menu", self.__show_link_menu_cb)
+# toolbar.insert(item, -1)
+# item.show()
+
+ toolbox = Toolbox()
+ toolbox.connect('color-selected', self._color_selected)
+ self.pack_start(toolbox, False)
+ toolbox.show()
+
+ spring = gtk.Label('')
+ self.pack_start(spring, True)
+ spring.show()
+
+ def _color_selected(self, toolbox, color):
+ self._editor.set_color(color)
+
+ def __link_activate_cb(self, item, link):
+ buf = self._editor.get_buffer()
+ buf.append_link(link['title'], link['address'])
+
+ def __show_link_menu_cb(self, button):
+ menu = gtk.Menu()
+
+ links = self.__get_browser_shell().get_links()
+
+ for link in links:
+ item = gtk.MenuItem(link['title'], False)
+ item.connect("activate", self.__link_activate_cb, link)
+ menu.append(item)
+ item.show()
+
+ button.set_menu(menu)
+
+ def _create_emoticons_popup(self):
+ model = gtk.ListStore(gtk.gdk.Pixbuf, str)
+
+ for name in Emoticons.get_instance().get_all():
+ icon_theme = gtk.icon_theme_get_default()
+ try:
+ pixbuf = icon_theme.load_icon(name, 16, 0)
+ model.append([pixbuf, name])
+ except gobject.GError:
+ pass
+
+ icon_view = gtk.IconView(model)
+ icon_view.connect('selection-changed', self.__emoticon_selection_changed_cb)
+ icon_view.set_pixbuf_column(0)
+ icon_view.set_selection_mode(gtk.SELECTION_SINGLE)
+
+ frame = gtk.Frame()
+ frame.set_shadow_type(gtk.SHADOW_ETCHED_IN)
+ frame.add(icon_view)
+ icon_view.show()
+
+ window = gtk.Window(gtk.WINDOW_POPUP)
+ window.add(frame)
+ frame.show()
+
+ return window
+
+ def __emoticon_selection_changed_cb(self, icon_view):
+ items = icon_view.get_selected_items()
+ if items:
+ model = icon_view.get_model()
+ icon_name = model[items[0]][1]
+ self._editor.get_buffer().append_icon(icon_name)
+ self._emt_popup.hide()
+
+ def __emoticons_button_clicked_cb(self, button):
+ # FIXME grabs...
+ if not self._emt_popup:
+ self._emt_popup = self._create_emoticons_popup()
+
+ if self._emt_popup.get_property('visible'):
+ self._emt_popup.hide()
+ else:
+ width = 180
+ height = 130
+
+ self._emt_popup.set_default_size(width, height)
+
+ [x, y] = button.window.get_origin()
+ x += button.allocation.x
+ y += button.allocation.y - height
+ self._emt_popup.move(x, y)
+
+ self._emt_popup.show()
diff --git a/sugar/chat/Emoticons.py b/sugar/chat/Emoticons.py
index 3f0e09e..33e53eb 100644
--- a/sugar/chat/Emoticons.py
+++ b/sugar/chat/Emoticons.py
@@ -15,70 +15,70 @@
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.
-emoticons_table = [ \
-[ 'stock_smiley-10', [ ':P', ':p' ] ], \
-[ 'stock_smiley-19', None ], \
-[ 'stock_smiley-2', None ], \
-[ 'stock_smiley-11', None ], \
-[ 'stock_smiley-1', [ ':)' ] ], \
-[ 'stock_smiley-3', None ], \
-[ 'stock_smiley-12', None ], \
-[ 'stock_smiley-20', None ], \
-[ 'stock_smiley-4', [ ':(' ] ], \
-[ 'stock_smiley-13', None ], \
-[ 'stock_smiley-21', None ], \
-[ 'stock_smiley-5', None ], \
-[ 'stock_smiley-14', None ], \
-[ 'stock_smiley-22', None ], \
-[ 'stock_smiley-6', None ], \
-[ 'stock_smiley-15', None ], \
-[ 'stock_smiley-23', None ], \
-[ 'stock_smiley-7', None ], \
-[ 'stock_smiley-16', None ], \
-[ 'stock_smiley-24', None ], \
-[ 'stock_smiley-8', None ], \
-[ 'stock_smiley-17', None ], \
-[ 'stock_smiley-25', None ], \
-[ 'stock_smiley-9', None ], \
-[ 'stock_smiley-18', None ], \
-[ 'stock_smiley-26', None ], \
+emoticons_table = [ \
+[ 'stock_smiley-10', [ ':P', ':p' ] ], \
+[ 'stock_smiley-19', None ], \
+[ 'stock_smiley-2', None ], \
+[ 'stock_smiley-11', None ], \
+[ 'stock_smiley-1', [ ':)' ] ], \
+[ 'stock_smiley-3', None ], \
+[ 'stock_smiley-12', None ], \
+[ 'stock_smiley-20', None ], \
+[ 'stock_smiley-4', [ ':(' ] ], \
+[ 'stock_smiley-13', None ], \
+[ 'stock_smiley-21', None ], \
+[ 'stock_smiley-5', None ], \
+[ 'stock_smiley-14', None ], \
+[ 'stock_smiley-22', None ], \
+[ 'stock_smiley-6', None ], \
+[ 'stock_smiley-15', None ], \
+[ 'stock_smiley-23', None ], \
+[ 'stock_smiley-7', None ], \
+[ 'stock_smiley-16', None ], \
+[ 'stock_smiley-24', None ], \
+[ 'stock_smiley-8', None ], \
+[ 'stock_smiley-17', None ], \
+[ 'stock_smiley-25', None ], \
+[ 'stock_smiley-9', None ], \
+[ 'stock_smiley-18', None ], \
+[ 'stock_smiley-26', None ], \
]
class Emoticons:
- instance = None
+ instance = None
- def get_instance():
- if not Emoticons.instance:
- Emoticons.instance = Emoticons()
- return Emoticons.instance
+ def get_instance():
+ if not Emoticons.instance:
+ Emoticons.instance = Emoticons()
+ return Emoticons.instance
- get_instance = staticmethod(get_instance)
+ get_instance = staticmethod(get_instance)
- def __init__(self):
- self._table = {}
+ def __init__(self):
+ self._table = {}
- for emoticon in emoticons_table:
- [ name, text_emts ] = emoticon
- self.add(name, text_emts)
-
- def add(self, icon_name, text=None):
- self._table[icon_name] = text
-
- def get_all(self):
- return self._table.keys()
-
- """Replace emoticons text with the icon name.
-
- Parse the provided text to find emoticons (in
- textual form) and replace them with their xml
- representation in the form:
- <icon name="$EMOTICON_ICON_NAME"/>
- """
- def replace(self, text):
- for icon_name in self._table.keys():
- text_emts = self._table[icon_name]
- if text_emts:
- for emoticon_text in text_emts:
- xml = '<icon name="' + icon_name + '"/>'
- text = text.replace(emoticon_text, xml)
- return text
+ for emoticon in emoticons_table:
+ [ name, text_emts ] = emoticon
+ self.add(name, text_emts)
+
+ def add(self, icon_name, text=None):
+ self._table[icon_name] = text
+
+ def get_all(self):
+ return self._table.keys()
+
+ """Replace emoticons text with the icon name.
+
+ Parse the provided text to find emoticons (in
+ textual form) and replace them with their xml
+ representation in the form:
+ <icon name="$EMOTICON_ICON_NAME"/>
+ """
+ def replace(self, text):
+ for icon_name in self._table.keys():
+ text_emts = self._table[icon_name]
+ if text_emts:
+ for emoticon_text in text_emts:
+ xml = '<icon name="' + icon_name + '"/>'
+ text = text.replace(emoticon_text, xml)
+ return text
diff --git a/sugar/chat/GroupChat.py b/sugar/chat/GroupChat.py
index d7580da..a1c6b65 100644
--- a/sugar/chat/GroupChat.py
+++ b/sugar/chat/GroupChat.py
@@ -23,15 +23,15 @@ from sugar.presence.PresenceService import PresenceService
import sugar.env
class GroupChat(Chat):
- def __init__(self):
- Chat.__init__(self)
- self._group_stream = None
+ def __init__(self):
+ Chat.__init__(self)
+ self._group_stream = None
- def _setup_stream(self, service):
- self._group_stream = Stream.new_from_service(service)
- self._group_stream.set_data_listener(self._group_recv_message)
- self._stream_writer = self._group_stream.new_writer()
+ def _setup_stream(self, service):
+ self._group_stream = Stream.new_from_service(service)
+ self._group_stream.set_data_listener(self._group_recv_message)
+ self._stream_writer = self._group_stream.new_writer()
- def _group_recv_message(self, address, msg):
- logging.debug('Group chat received from %s message %s' % (address, msg))
- self.recv_message(msg)
+ def _group_recv_message(self, address, msg):
+ logging.debug('Group chat received from %s message %s' % (address, msg))
+ self.recv_message(msg)
diff --git a/sugar/chat/richtext.py b/sugar/chat/richtext.py
index 7a6f179..ebd8b1c 100644
--- a/sugar/chat/richtext.py
+++ b/sugar/chat/richtext.py
@@ -21,431 +21,431 @@ import pango
import xml.sax
class RichTextView(gtk.TextView):
-
- __gsignals__ = {
- 'link-clicked': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_STRING]))
- }
-
- def __init__(self):
- gtk.TextView.__init__(self, RichTextBuffer())
- self.connect("motion-notify-event", self.__motion_notify_cb)
- self.connect("button-press-event", self.__button_press_cb)
- self.__hover_link = False
-
- def _set_hover_link(self, hover_link):
- if hover_link != self.__hover_link:
- self.__hover_link = hover_link
- display = self.get_toplevel().get_display()
- child_window = self.get_window(gtk.TEXT_WINDOW_TEXT)
-
- if hover_link:
- cursor = gtk.gdk.Cursor(display, gtk.gdk.HAND2)
- else:
- cursor = gtk.gdk.Cursor(display, gtk.gdk.XTERM)
-
- child_window.set_cursor(cursor)
- gtk.gdk.flush()
-
- def __iter_is_link(self, it):
- item = self.get_buffer().get_tag_table().lookup("link")
- if item:
- return it.has_tag(item)
- return False
-
- def __get_event_iter(self, event):
- return self.get_iter_at_location(int(event.x), int(event.y))
-
- def __motion_notify_cb(self, widget, event):
- if event.is_hint:
- event.window.get_pointer();
-
- it = self.__get_event_iter(event)
- if it:
- hover_link = self.__iter_is_link(it)
- else:
- hover_link = False
-
- self._set_hover_link(hover_link)
-
- def __button_press_cb(self, widget, event):
- it = self.__get_event_iter(event)
- if it and self.__iter_is_link(it):
- buf = self.get_buffer()
- address_tag = buf.get_tag_table().lookup("object-id")
-
- address_end = it.copy()
- address_end.backward_to_tag_toggle(address_tag)
-
- address_start = address_end.copy()
- address_start.backward_to_tag_toggle(address_tag)
-
- address = buf.get_text(address_start, address_end)
- self.emit("link-clicked", address)
+
+ __gsignals__ = {
+ 'link-clicked': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_STRING]))
+ }
+
+ def __init__(self):
+ gtk.TextView.__init__(self, RichTextBuffer())
+ self.connect("motion-notify-event", self.__motion_notify_cb)
+ self.connect("button-press-event", self.__button_press_cb)
+ self.__hover_link = False
+
+ def _set_hover_link(self, hover_link):
+ if hover_link != self.__hover_link:
+ self.__hover_link = hover_link
+ display = self.get_toplevel().get_display()
+ child_window = self.get_window(gtk.TEXT_WINDOW_TEXT)
+
+ if hover_link:
+ cursor = gtk.gdk.Cursor(display, gtk.gdk.HAND2)
+ else:
+ cursor = gtk.gdk.Cursor(display, gtk.gdk.XTERM)
+
+ child_window.set_cursor(cursor)
+ gtk.gdk.flush()
+
+ def __iter_is_link(self, it):
+ item = self.get_buffer().get_tag_table().lookup("link")
+ if item:
+ return it.has_tag(item)
+ return False
+
+ def __get_event_iter(self, event):
+ return self.get_iter_at_location(int(event.x), int(event.y))
+
+ def __motion_notify_cb(self, widget, event):
+ if event.is_hint:
+ event.window.get_pointer();
+
+ it = self.__get_event_iter(event)
+ if it:
+ hover_link = self.__iter_is_link(it)
+ else:
+ hover_link = False
+
+ self._set_hover_link(hover_link)
+
+ def __button_press_cb(self, widget, event):
+ it = self.__get_event_iter(event)
+ if it and self.__iter_is_link(it):
+ buf = self.get_buffer()
+ address_tag = buf.get_tag_table().lookup("object-id")
+
+ address_end = it.copy()
+ address_end.backward_to_tag_toggle(address_tag)
+
+ address_start = address_end.copy()
+ address_start.backward_to_tag_toggle(address_tag)
+
+ address = buf.get_text(address_start, address_end)
+ self.emit("link-clicked", address)
class RichTextBuffer(gtk.TextBuffer):
- def __init__(self):
- gtk.TextBuffer.__init__(self)
-
- self.connect_after("insert-text", self.__insert_text_cb)
-
- self.__create_tags()
- self.active_tags = []
-
- def append_link(self, title, address):
- it = self.get_iter_at_mark(self.get_insert())
- self.insert_with_tags_by_name(it, address, "link", "object-id")
- self.insert_with_tags_by_name(it, title, "link")
-
- def append_icon(self, name, it = None):
- if not it:
- it = self.get_iter_at_mark(self.get_insert())
-
- self.insert_with_tags_by_name(it, name, "icon", "object-id")
- icon_theme = gtk.icon_theme_get_default()
- try:
- pixbuf = icon_theme.load_icon(name, 16, 0)
- self.insert_pixbuf(it, pixbuf)
- except gobject.GError:
- pass
-
- def apply_tag(self, tag_name):
- self.active_tags.append(tag_name)
-
- bounds = self.get_selection_bounds()
- if bounds:
- [start, end] = bounds
- self.apply_tag_by_name(tag_name, start, end)
-
- def unapply_tag(self, tag_name):
- self.active_tags.remove(tag_name)
-
- bounds = self.get_selection_bounds()
- if bounds:
- [start, end] = bounds
- self.remove_tag_by_name(tag_name, start, end)
-
- def __create_tags(self):
- tag = self.create_tag("icon")
-
- tag = self.create_tag("link")
- tag.set_property("underline", pango.UNDERLINE_SINGLE)
- tag.set_property("foreground", "#0000FF")
-
- tag = self.create_tag("object-id")
- tag.set_property("invisible", True)
-
- tag = self.create_tag("bold")
- tag.set_property("weight", pango.WEIGHT_BOLD)
-
- tag = self.create_tag("italic")
- tag.set_property("style", pango.STYLE_ITALIC)
-
- tag = self.create_tag("font-size-xx-small")
- tag.set_property("scale", pango.SCALE_XX_SMALL)
-
- tag = self.create_tag("font-size-x-small")
- tag.set_property("scale", pango.SCALE_X_SMALL)
-
- tag = self.create_tag("font-size-small")
- tag.set_property("scale", pango.SCALE_SMALL)
-
- tag = self.create_tag("font-size-large")
- tag.set_property("scale", pango.SCALE_LARGE)
-
- tag = self.create_tag("font-size-x-large")
- tag.set_property("scale", pango.SCALE_X_LARGE)
-
- tag = self.create_tag("font-size-xx-large")
- tag.set_property("scale", pango.SCALE_XX_LARGE)
-
- def __insert_text_cb(self, widget, pos, text, length):
- for tag in self.active_tags:
- pos_end = pos.copy()
- pos_end.backward_chars(length)
- self.apply_tag_by_name(tag, pos, pos_end)
-
+ def __init__(self):
+ gtk.TextBuffer.__init__(self)
+
+ self.connect_after("insert-text", self.__insert_text_cb)
+
+ self.__create_tags()
+ self.active_tags = []
+
+ def append_link(self, title, address):
+ it = self.get_iter_at_mark(self.get_insert())
+ self.insert_with_tags_by_name(it, address, "link", "object-id")
+ self.insert_with_tags_by_name(it, title, "link")
+
+ def append_icon(self, name, it = None):
+ if not it:
+ it = self.get_iter_at_mark(self.get_insert())
+
+ self.insert_with_tags_by_name(it, name, "icon", "object-id")
+ icon_theme = gtk.icon_theme_get_default()
+ try:
+ pixbuf = icon_theme.load_icon(name, 16, 0)
+ self.insert_pixbuf(it, pixbuf)
+ except gobject.GError:
+ pass
+
+ def apply_tag(self, tag_name):
+ self.active_tags.append(tag_name)
+
+ bounds = self.get_selection_bounds()
+ if bounds:
+ [start, end] = bounds
+ self.apply_tag_by_name(tag_name, start, end)
+
+ def unapply_tag(self, tag_name):
+ self.active_tags.remove(tag_name)
+
+ bounds = self.get_selection_bounds()
+ if bounds:
+ [start, end] = bounds
+ self.remove_tag_by_name(tag_name, start, end)
+
+ def __create_tags(self):
+ tag = self.create_tag("icon")
+
+ tag = self.create_tag("link")
+ tag.set_property("underline", pango.UNDERLINE_SINGLE)
+ tag.set_property("foreground", "#0000FF")
+
+ tag = self.create_tag("object-id")
+ tag.set_property("invisible", True)
+
+ tag = self.create_tag("bold")
+ tag.set_property("weight", pango.WEIGHT_BOLD)
+
+ tag = self.create_tag("italic")
+ tag.set_property("style", pango.STYLE_ITALIC)
+
+ tag = self.create_tag("font-size-xx-small")
+ tag.set_property("scale", pango.SCALE_XX_SMALL)
+
+ tag = self.create_tag("font-size-x-small")
+ tag.set_property("scale", pango.SCALE_X_SMALL)
+
+ tag = self.create_tag("font-size-small")
+ tag.set_property("scale", pango.SCALE_SMALL)
+
+ tag = self.create_tag("font-size-large")
+ tag.set_property("scale", pango.SCALE_LARGE)
+
+ tag = self.create_tag("font-size-x-large")
+ tag.set_property("scale", pango.SCALE_X_LARGE)
+
+ tag = self.create_tag("font-size-xx-large")
+ tag.set_property("scale", pango.SCALE_XX_LARGE)
+
+ def __insert_text_cb(self, widget, pos, text, length):
+ for tag in self.active_tags:
+ pos_end = pos.copy()
+ pos_end.backward_chars(length)
+ self.apply_tag_by_name(tag, pos, pos_end)
+
class RichTextToolbox(gtk.HBox):
- def __init__(self, buf):
- gtk.HBox.__init__(self, False, 6)
-
- self.buf = buf
-
- self._font_size = "normal"
- self._font_scales = [ "xx-small", "x-small", "small", \
- "normal", \
- "large", "x-large", "xx-large" ]
-
- image = gtk.Image()
- image.set_from_stock(gtk.STOCK_BOLD, gtk.ICON_SIZE_SMALL_TOOLBAR)
-
- item = gtk.ToggleButton()
- item.set_image(image)
- item.connect("toggled", self.__toggle_style_cb, "bold")
- item.unset_flags(gtk.CAN_FOCUS)
- self.pack_start(item, False)
- item.show()
-
- image.show()
-
- image = gtk.Image()
- image.set_from_stock(gtk.STOCK_ITALIC, gtk.ICON_SIZE_SMALL_TOOLBAR)
-
- item = gtk.ToggleButton()
- item.set_image(image)
- item.unset_flags(gtk.CAN_FOCUS)
- item.connect("toggled", self.__toggle_style_cb, "italic")
- self.pack_start(item, False)
- item.show()
-
- image = gtk.Image()
- image.set_from_stock(gtk.STOCK_GO_UP, gtk.ICON_SIZE_SMALL_TOOLBAR)
-
- self._font_size_up = gtk.Button()
- self._font_size_up.set_image(image)
- self._font_size_up.unset_flags(gtk.CAN_FOCUS)
- self._font_size_up.connect("clicked", self.__font_size_up_cb)
- self.pack_start(self._font_size_up, False)
- self._font_size_up.show()
-
- image.show()
-
- image = gtk.Image()
- image.set_from_stock(gtk.STOCK_GO_DOWN, gtk.ICON_SIZE_SMALL_TOOLBAR)
-
- self._font_size_down = gtk.Button()
- self._font_size_down.set_image(image)
- self._font_size_down.unset_flags(gtk.CAN_FOCUS)
- self._font_size_down.connect("clicked", self.__font_size_down_cb)
- self.pack_start(self._font_size_down, False)
- self._font_size_down.show()
-
- image.show()
-
- def _get_font_size_index(self):
- return self._font_scales.index(self._font_size);
-
- def __toggle_style_cb(self, toggle, tag_name):
- if toggle.get_active():
- self.buf.apply_tag(tag_name)
- else:
- self.buf.unapply_tag(tag_name)
-
- def _set_font_size(self, font_size):
- if self._font_size != "normal":
- self.buf.unapply_tag("font-size-" + self._font_size)
- if font_size != "normal":
- self.buf.apply_tag("font-size-" + font_size)
-
- self._font_size = font_size
-
- can_up = self._get_font_size_index() < len(self._font_scales) - 1
- can_down = self._get_font_size_index() > 0
- self._font_size_up.set_sensitive(can_up)
- self._font_size_down.set_sensitive(can_down)
-
- def __font_size_up_cb(self, button):
- index = self._get_font_size_index()
- if index + 1 < len(self._font_scales):
- self._set_font_size(self._font_scales[index + 1])
-
- def __font_size_down_cb(self, button):
- index = self._get_font_size_index()
- if index > 0:
- self._set_font_size(self._font_scales[index - 1])
-
+ def __init__(self, buf):
+ gtk.HBox.__init__(self, False, 6)
+
+ self.buf = buf
+
+ self._font_size = "normal"
+ self._font_scales = [ "xx-small", "x-small", "small", \
+ "normal", \
+ "large", "x-large", "xx-large" ]
+
+ image = gtk.Image()
+ image.set_from_stock(gtk.STOCK_BOLD, gtk.ICON_SIZE_SMALL_TOOLBAR)
+
+ item = gtk.ToggleButton()
+ item.set_image(image)
+ item.connect("toggled", self.__toggle_style_cb, "bold")
+ item.unset_flags(gtk.CAN_FOCUS)
+ self.pack_start(item, False)
+ item.show()
+
+ image.show()
+
+ image = gtk.Image()
+ image.set_from_stock(gtk.STOCK_ITALIC, gtk.ICON_SIZE_SMALL_TOOLBAR)
+
+ item = gtk.ToggleButton()
+ item.set_image(image)
+ item.unset_flags(gtk.CAN_FOCUS)
+ item.connect("toggled", self.__toggle_style_cb, "italic")
+ self.pack_start(item, False)
+ item.show()
+
+ image = gtk.Image()
+ image.set_from_stock(gtk.STOCK_GO_UP, gtk.ICON_SIZE_SMALL_TOOLBAR)
+
+ self._font_size_up = gtk.Button()
+ self._font_size_up.set_image(image)
+ self._font_size_up.unset_flags(gtk.CAN_FOCUS)
+ self._font_size_up.connect("clicked", self.__font_size_up_cb)
+ self.pack_start(self._font_size_up, False)
+ self._font_size_up.show()
+
+ image.show()
+
+ image = gtk.Image()
+ image.set_from_stock(gtk.STOCK_GO_DOWN, gtk.ICON_SIZE_SMALL_TOOLBAR)
+
+ self._font_size_down = gtk.Button()
+ self._font_size_down.set_image(image)
+ self._font_size_down.unset_flags(gtk.CAN_FOCUS)
+ self._font_size_down.connect("clicked", self.__font_size_down_cb)
+ self.pack_start(self._font_size_down, False)
+ self._font_size_down.show()
+
+ image.show()
+
+ def _get_font_size_index(self):
+ return self._font_scales.index(self._font_size);
+
+ def __toggle_style_cb(self, toggle, tag_name):
+ if toggle.get_active():
+ self.buf.apply_tag(tag_name)
+ else:
+ self.buf.unapply_tag(tag_name)
+
+ def _set_font_size(self, font_size):
+ if self._font_size != "normal":
+ self.buf.unapply_tag("font-size-" + self._font_size)
+ if font_size != "normal":
+ self.buf.apply_tag("font-size-" + font_size)
+
+ self._font_size = font_size
+
+ can_up = self._get_font_size_index() < len(self._font_scales) - 1
+ can_down = self._get_font_size_index() > 0
+ self._font_size_up.set_sensitive(can_up)
+ self._font_size_down.set_sensitive(can_down)
+
+ def __font_size_up_cb(self, button):
+ index = self._get_font_size_index()
+ if index + 1 < len(self._font_scales):
+ self._set_font_size(self._font_scales[index + 1])
+
+ def __font_size_down_cb(self, button):
+ index = self._get_font_size_index()
+ if index > 0:
+ self._set_font_size(self._font_scales[index - 1])
+
class RichTextHandler(xml.sax.handler.ContentHandler):
- def __init__(self, serializer, buf):
- xml.sax.handler.ContentHandler.__init__(self)
- self.buf = buf
- self.serializer = serializer
- self.tags = []
- self._in_richtext = False
- self._done = False
-
- def startElement(self, name, attrs):
- # Look for, and only start parsing after 'richtext'
- if not self._in_richtext and name == "richtext":
- self._in_richtext = True
- if not self._in_richtext:
- return
-
- if name != "richtext":
- tag = self.serializer.deserialize_element(name, attrs)
- self.tags.append(tag)
- if name == "link":
- self.href = attrs['href']
- elif name == "icon":
- self.buf.append_icon(attrs['name'], self.buf.get_end_iter())
+ def __init__(self, serializer, buf):
+ xml.sax.handler.ContentHandler.__init__(self)
+ self.buf = buf
+ self.serializer = serializer
+ self.tags = []
+ self._in_richtext = False
+ self._done = False
+
+ def startElement(self, name, attrs):
+ # Look for, and only start parsing after 'richtext'
+ if not self._in_richtext and name == "richtext":
+ self._in_richtext = True
+ if not self._in_richtext:
+ return
+
+ if name != "richtext":
+ tag = self.serializer.deserialize_element(name, attrs)
+ self.tags.append(tag)
+ if name == "link":
+ self.href = attrs['href']
+ elif name == "icon":
+ self.buf.append_icon(attrs['name'], self.buf.get_end_iter())
- def characters(self, data):
- start_it = it = self.buf.get_end_iter()
- mark = self.buf.create_mark(None, start_it, True)
- self.buf.insert(it, data)
- start_it = self.buf.get_iter_at_mark(mark)
-
- for tag in self.tags:
- self.buf.apply_tag_by_name(tag, start_it, it)
- if tag == "link":
- self.buf.insert_with_tags_by_name(start_it, self.href,
- "link", "object-id")
-
- def endElement(self, name):
- if not self._done and self._in_richtext:
- if name != "richtext":
- self.tags.pop()
- if name == "richtext":
- self._done = True
- self._in_richtext = False
+ def characters(self, data):
+ start_it = it = self.buf.get_end_iter()
+ mark = self.buf.create_mark(None, start_it, True)
+ self.buf.insert(it, data)
+ start_it = self.buf.get_iter_at_mark(mark)
+
+ for tag in self.tags:
+ self.buf.apply_tag_by_name(tag, start_it, it)
+ if tag == "link":
+ self.buf.insert_with_tags_by_name(start_it, self.href,
+ "link", "object-id")
+
+ def endElement(self, name):
+ if not self._done and self._in_richtext:
+ if name != "richtext":
+ self.tags.pop()
+ if name == "richtext":
+ self._done = True
+ self._in_richtext = False
class RichTextSerializer:
- def __init__(self):
- self._open_tags = []
-
- def deserialize_element(self, el_name, attributes):
- if el_name == "bold":
- return "bold"
- elif el_name == "italic":
- return "italic"
- elif el_name == "font":
- return "font-size-" + attributes["size"]
- elif el_name == "link":
- return "link"
- elif el_name == "icon":
- return "icon"
- else:
- return None
-
- def _parse_object_id(self, it):
- object_id_tag = self.buf.get_tag_table().lookup("object-id")
- end = it.copy()
- end.forward_to_tag_toggle(object_id_tag)
- return self.buf.get_text(it, end)
-
- def serialize_tag_start(self, tag, it):
- name = tag.get_property("name")
- if name == "bold":
- return "<bold>"
- elif name == "italic":
- return "<italic>"
- elif name == "link":
- address = self._parse_object_id(it)
- return "<link " + "href=\"" + address + "\">"
- elif name == "icon":
- name = self._parse_object_id(it)
- return "<icon " + "name=\"" + name + "\"/>"
- elif name == "object-id":
- return ""
- elif name.startswith("font-size-"):
- tag_name = name.replace("font-size-", "", 1)
- return "<font size=\"" + tag_name + "\">"
- else:
- return "<unknown>"
-
- def serialize_tag_end(self, tag):
- name = tag.get_property("name")
- if name == "bold":
- return "</bold>"
- elif name == "italic":
- return "</italic>"
- elif name == "link":
- return "</link>"
- elif name == "icon":
- return ""
- elif name == "object-id":
- return ""
- elif name.startswith("font-size-"):
- return "</font>"
- else:
- return "</unknown>"
-
- def serialize(self, buf):
- self.buf = buf
-
- res = "<richtext>"
-
- next_it = buf.get_start_iter()
- while not next_it.is_end():
- it = next_it.copy()
- if not next_it.forward_to_tag_toggle(None):
- next_it = buf.get_end_iter()
-
- tags_to_reopen = []
-
- for tag in it.get_toggled_tags(False):
- while 1:
- open_tag = self._open_tags.pop()
- res += self.serialize_tag_end(tag)
- if open_tag == tag:
- break
- tags_to_reopen.append(open_tag)
-
- for tag in tags_to_reopen:
- self._open_tags.append(tag)
- res += self.serialize_tag_start(tag, it)
-
- for tag in it.get_toggled_tags(True):
- self._open_tags.append(tag)
- res += self.serialize_tag_start(tag, it)
-
- res += buf.get_text(it, next_it, False)
-
- if next_it.is_end():
- self._open_tags.reverse()
- for tag in self._open_tags:
- res += self.serialize_tag_end(tag)
-
- res += "</richtext>"
-
- return res
-
- def deserialize(self, xml_string, buf):
- parser = xml.sax.make_parser()
- handler = RichTextHandler(self, buf)
- parser.setContentHandler(handler)
- parser.feed(xml_string)
- parser.close()
+ def __init__(self):
+ self._open_tags = []
+
+ def deserialize_element(self, el_name, attributes):
+ if el_name == "bold":
+ return "bold"
+ elif el_name == "italic":
+ return "italic"
+ elif el_name == "font":
+ return "font-size-" + attributes["size"]
+ elif el_name == "link":
+ return "link"
+ elif el_name == "icon":
+ return "icon"
+ else:
+ return None
+
+ def _parse_object_id(self, it):
+ object_id_tag = self.buf.get_tag_table().lookup("object-id")
+ end = it.copy()
+ end.forward_to_tag_toggle(object_id_tag)
+ return self.buf.get_text(it, end)
+
+ def serialize_tag_start(self, tag, it):
+ name = tag.get_property("name")
+ if name == "bold":
+ return "<bold>"
+ elif name == "italic":
+ return "<italic>"
+ elif name == "link":
+ address = self._parse_object_id(it)
+ return "<link " + "href=\"" + address + "\">"
+ elif name == "icon":
+ name = self._parse_object_id(it)
+ return "<icon " + "name=\"" + name + "\"/>"
+ elif name == "object-id":
+ return ""
+ elif name.startswith("font-size-"):
+ tag_name = name.replace("font-size-", "", 1)
+ return "<font size=\"" + tag_name + "\">"
+ else:
+ return "<unknown>"
+
+ def serialize_tag_end(self, tag):
+ name = tag.get_property("name")
+ if name == "bold":
+ return "</bold>"
+ elif name == "italic":
+ return "</italic>"
+ elif name == "link":
+ return "</link>"
+ elif name == "icon":
+ return ""
+ elif name == "object-id":
+ return ""
+ elif name.startswith("font-size-"):
+ return "</font>"
+ else:
+ return "</unknown>"
+
+ def serialize(self, buf):
+ self.buf = buf
+
+ res = "<richtext>"
+
+ next_it = buf.get_start_iter()
+ while not next_it.is_end():
+ it = next_it.copy()
+ if not next_it.forward_to_tag_toggle(None):
+ next_it = buf.get_end_iter()
+
+ tags_to_reopen = []
+
+ for tag in it.get_toggled_tags(False):
+ while 1:
+ open_tag = self._open_tags.pop()
+ res += self.serialize_tag_end(tag)
+ if open_tag == tag:
+ break
+ tags_to_reopen.append(open_tag)
+
+ for tag in tags_to_reopen:
+ self._open_tags.append(tag)
+ res += self.serialize_tag_start(tag, it)
+
+ for tag in it.get_toggled_tags(True):
+ self._open_tags.append(tag)
+ res += self.serialize_tag_start(tag, it)
+
+ res += buf.get_text(it, next_it, False)
+
+ if next_it.is_end():
+ self._open_tags.reverse()
+ for tag in self._open_tags:
+ res += self.serialize_tag_end(tag)
+
+ res += "</richtext>"
+
+ return res
+
+ def deserialize(self, xml_string, buf):
+ parser = xml.sax.make_parser()
+ handler = RichTextHandler(self, buf)
+ parser.setContentHandler(handler)
+ parser.feed(xml_string)
+ parser.close()
def test_quit(w, rb):
- print RichTextSerializer().serialize(rb)
- gtk.main_quit()
-
+ print RichTextSerializer().serialize(rb)
+ gtk.main_quit()
+
def link_clicked(v, address):
- print "Link clicked " + address
+ print "Link clicked " + address
if __name__ == "__main__":
- window = gtk.Window()
- window.set_default_size(400, 300)
-
- vbox = gtk.VBox()
-
- view = RichTextView()
- view.connect("link-clicked", link_clicked)
- vbox.pack_start(view)
- view.show()
-
- rich_buf = view.get_buffer()
-
- test_xml = "<richtext>"
-
- test_xml += "<bold><italic>Test</italic>one</bold>\n"
- test_xml += "<bold><italic>Test two</italic></bold>"
- test_xml += "<font size=\"xx-small\">Test three</font>"
- test_xml += "<link href=\"http://www.gnome.org\">Test link</link>"
- test_xml += "<icon name=\"stock_help-chat\"/>"
- test_xml += "</richtext>"
-
- RichTextSerializer().deserialize(test_xml, rich_buf)
-
- toolbar = RichTextToolbar(rich_buf)
- vbox.pack_start(toolbar, False)
- toolbar.show()
-
- window.add(vbox)
- vbox.show()
-
- window.show()
-
- window.connect("destroy", test_quit, rich_buf)
-
- gtk.main()
+ window = gtk.Window()
+ window.set_default_size(400, 300)
+
+ vbox = gtk.VBox()
+
+ view = RichTextView()
+ view.connect("link-clicked", link_clicked)
+ vbox.pack_start(view)
+ view.show()
+
+ rich_buf = view.get_buffer()
+
+ test_xml = "<richtext>"
+
+ test_xml += "<bold><italic>Test</italic>one</bold>\n"
+ test_xml += "<bold><italic>Test two</italic></bold>"
+ test_xml += "<font size=\"xx-small\">Test three</font>"
+ test_xml += "<link href=\"http://www.gnome.org\">Test link</link>"
+ test_xml += "<icon name=\"stock_help-chat\"/>"
+ test_xml += "</richtext>"
+
+ RichTextSerializer().deserialize(test_xml, rich_buf)
+
+ toolbar = RichTextToolbar(rich_buf)
+ vbox.pack_start(toolbar, False)
+ toolbar.show()
+
+ window.add(vbox)
+ vbox.show()
+
+ window.show()
+
+ window.connect("destroy", test_quit, rich_buf)
+
+ gtk.main()
diff --git a/sugar/chat/sketchpad/Sketch.py b/sugar/chat/sketchpad/Sketch.py
index 0ddfb3c..ac0a865 100644
--- a/sugar/chat/sketchpad/Sketch.py
+++ b/sugar/chat/sketchpad/Sketch.py
@@ -18,37 +18,37 @@
from SVGdraw import path
class Sketch:
- def __init__(self, rgb):
- self._points = []
- self._rgb = (float(rgb[0]), float(rgb[1]), float(rgb[2]))
-
- def add_point(self, x, y):
- self._points.append((x, y))
+ def __init__(self, rgb):
+ self._points = []
+ self._rgb = (float(rgb[0]), float(rgb[1]), float(rgb[2]))
+
+ def add_point(self, x, y):
+ self._points.append((x, y))
- def get_points(self):
- return self._points
-
- def draw(self, ctx):
- start = True
- for (x, y) in self._points:
- if start:
- ctx.move_to(x, y)
- start = False
- else:
- ctx.line_to(x, y)
- ctx.set_source_rgb(self._rgb[0], self._rgb[1], self._rgb[2])
- ctx.stroke()
-
- def draw_to_svg(self):
- i = 0
- for (x, y) in self._points:
- coords = str(x) + ' ' + str(y) + ' '
- if i == 0:
- path_data = 'M ' + coords
- elif i == 1:
- path_data += 'L ' + coords
- else:
- path_data += coords
- i += 1
- color = "#%02X%02X%02X" % (255 * self._rgb[0], 255 * self._rgb[1], 255 * self._rgb[2])
- return path(path_data, fill = 'none', stroke = color)
+ def get_points(self):
+ return self._points
+
+ def draw(self, ctx):
+ start = True
+ for (x, y) in self._points:
+ if start:
+ ctx.move_to(x, y)
+ start = False
+ else:
+ ctx.line_to(x, y)
+ ctx.set_source_rgb(self._rgb[0], self._rgb[1], self._rgb[2])
+ ctx.stroke()
+
+ def draw_to_svg(self):
+ i = 0
+ for (x, y) in self._points:
+ coords = str(x) + ' ' + str(y) + ' '
+ if i == 0:
+ path_data = 'M ' + coords
+ elif i == 1:
+ path_data += 'L ' + coords
+ else:
+ path_data += coords
+ i += 1
+ color = "#%02X%02X%02X" % (255 * self._rgb[0], 255 * self._rgb[1], 255 * self._rgb[2])
+ return path(path_data, fill = 'none', stroke = color)
diff --git a/sugar/chat/sketchpad/SketchPad.py b/sugar/chat/sketchpad/SketchPad.py
index 33327f0..e15e435 100644
--- a/sugar/chat/sketchpad/SketchPad.py
+++ b/sugar/chat/sketchpad/SketchPad.py
@@ -23,101 +23,101 @@ from SVGdraw import drawing
from SVGdraw import svg
class SketchPad(gtk.DrawingArea):
- __gsignals__ = {
- 'new-user-sketch':(gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT]))
- }
+ __gsignals__ = {
+ 'new-user-sketch':(gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT]))
+ }
- def __init__(self, bgcolor=(0.6, 1, 0.4)):
- gtk.DrawingArea.__init__(self)
+ def __init__(self, bgcolor=(0.6, 1, 0.4)):
+ gtk.DrawingArea.__init__(self)
- self._active_sketch = None
- self._rgb = (0.0, 0.0, 0.0)
- self._bgcolor = bgcolor
- self._sketches = []
+ self._active_sketch = None
+ self._rgb = (0.0, 0.0, 0.0)
+ self._bgcolor = bgcolor
+ self._sketches = []
- self.add_events(gtk.gdk.BUTTON_PRESS_MASK |
- gtk.gdk.BUTTON_RELEASE_MASK |
- gtk.gdk.BUTTON1_MOTION_MASK)
- self.connect("button-press-event", self._button_press_cb)
- self.connect("button-release-event", self._button_release_cb)
- self.connect("motion-notify-event", self._motion_notify_cb)
- self.connect('expose_event', self.expose)
-
- def clear(self):
- self._sketches = []
- self.window.invalidate_rect(None, False)
+ self.add_events(gtk.gdk.BUTTON_PRESS_MASK |
+ gtk.gdk.BUTTON_RELEASE_MASK |
+ gtk.gdk.BUTTON1_MOTION_MASK)
+ self.connect("button-press-event", self._button_press_cb)
+ self.connect("button-release-event", self._button_release_cb)
+ self.connect("motion-notify-event", self._motion_notify_cb)
+ self.connect('expose_event', self.expose)
+
+ def clear(self):
+ self._sketches = []
+ self.window.invalidate_rect(None, False)
- def expose(self, widget, event):
- """Draw the background of the sketchpad."""
- rect = self.get_allocation()
- ctx = widget.window.cairo_create()
-
- ctx.set_source_rgb(self._bgcolor[0], self._bgcolor[1], self._bgcolor[2])
- ctx.rectangle(0, 0, rect.width, rect.height)
- ctx.fill_preserve()
-
- ctx.set_source_rgb(0, 0.3, 0.2)
- ctx.stroke()
-
- for sketch in self._sketches:
- sketch.draw(ctx)
-
- return False
+ def expose(self, widget, event):
+ """Draw the background of the sketchpad."""
+ rect = self.get_allocation()
+ ctx = widget.window.cairo_create()
+
+ ctx.set_source_rgb(self._bgcolor[0], self._bgcolor[1], self._bgcolor[2])
+ ctx.rectangle(0, 0, rect.width, rect.height)
+ ctx.fill_preserve()
+
+ ctx.set_source_rgb(0, 0.3, 0.2)
+ ctx.stroke()
+
+ for sketch in self._sketches:
+ sketch.draw(ctx)
+
+ return False
- def set_color(self, color):
- """Sets the current drawing color of the sketchpad.
- color agument should be 3-item tuple of rgb values between 0 and 1."""
- self._rgb = color
+ def set_color(self, color):
+ """Sets the current drawing color of the sketchpad.
+ color agument should be 3-item tuple of rgb values between 0 and 1."""
+ self._rgb = color
- def add_sketch(self, sketch):
- """Add a sketch to the the pad. Mostly for subclasses and clients."""
- self._sketches.append(sketch)
- self.window.invalidate_rect(None, False)
+ def add_sketch(self, sketch):
+ """Add a sketch to the the pad. Mostly for subclasses and clients."""
+ self._sketches.append(sketch)
+ self.window.invalidate_rect(None, False)
- def add_point(self, event):
- if not self._active_sketch:
- return
- self._active_sketch.add_point(event.x, event.y)
- self.window.invalidate_rect(None, False)
-
- def _button_press_cb(self, widget, event):
- self._active_sketch = Sketch(self._rgb)
- self._sketches.append(self._active_sketch)
- self.add_point(event)
-
- def _button_release_cb(self, widget, event):
- self.add_point(event)
- self.emit('new-user-sketch', self._active_sketch)
- self._active_sketch = None
-
- def _motion_notify_cb(self, widget, event):
- self.add_point(event)
-
- def to_svg(self):
- """Return a string containing an SVG representation of this sketch."""
- d = drawing()
- s = svg()
- for sketch in self._sketches:
- s.addElement(sketch.draw_to_svg())
- d.setSVG(s)
- return d.toXml()
+ def add_point(self, event):
+ if not self._active_sketch:
+ return
+ self._active_sketch.add_point(event.x, event.y)
+ self.window.invalidate_rect(None, False)
+
+ def _button_press_cb(self, widget, event):
+ self._active_sketch = Sketch(self._rgb)
+ self._sketches.append(self._active_sketch)
+ self.add_point(event)
+
+ def _button_release_cb(self, widget, event):
+ self.add_point(event)
+ self.emit('new-user-sketch', self._active_sketch)
+ self._active_sketch = None
+
+ def _motion_notify_cb(self, widget, event):
+ self.add_point(event)
+
+ def to_svg(self):
+ """Return a string containing an SVG representation of this sketch."""
+ d = drawing()
+ s = svg()
+ for sketch in self._sketches:
+ s.addElement(sketch.draw_to_svg())
+ d.setSVG(s)
+ return d.toXml()
def test_quit(w, skpad):
- print skpad.to_svg()
- gtk.main_quit()
+ print skpad.to_svg()
+ gtk.main_quit()
if __name__ == "__main__":
- window = gtk.Window()
- window.set_default_size(400, 300)
- window.connect("destroy", lambda w: gtk.main_quit())
+ window = gtk.Window()
+ window.set_default_size(400, 300)
+ window.connect("destroy", lambda w: gtk.main_quit())
- sketchpad = SketchPad()
- window.add(sketchpad)
- sketchpad.show()
-
- window.show()
-
- window.connect("destroy", test_quit, sketchpad)
+ sketchpad = SketchPad()
+ window.add(sketchpad)
+ sketchpad.show()
+
+ window.show()
+
+ window.connect("destroy", test_quit, sketchpad)
- gtk.main()
+ gtk.main()
diff --git a/sugar/chat/sketchpad/Toolbox.py b/sugar/chat/sketchpad/Toolbox.py
index 0ae4e29..b142f98 100644
--- a/sugar/chat/sketchpad/Toolbox.py
+++ b/sugar/chat/sketchpad/Toolbox.py
@@ -19,59 +19,59 @@ import gtk
import gobject
class ColorButton(gtk.RadioButton):
- def __init__(self, group, rgb):
- gtk.RadioButton.__init__(self, group)
-
- self._rgb = rgb
-
- self.set_mode(False)
- self.set_relief(gtk.RELIEF_NONE)
-
- drawing_area = gtk.DrawingArea()
- drawing_area.set_size_request(24, 24)
- drawing_area.connect_after('expose_event', self.expose)
- self.add(drawing_area)
- drawing_area.show()
+ def __init__(self, group, rgb):
+ gtk.RadioButton.__init__(self, group)
+
+ self._rgb = rgb
+
+ self.set_mode(False)
+ self.set_relief(gtk.RELIEF_NONE)
+
+ drawing_area = gtk.DrawingArea()
+ drawing_area.set_size_request(24, 24)
+ drawing_area.connect_after('expose_event', self.expose)
+ self.add(drawing_area)
+ drawing_area.show()
- def color(self):
- return self._rgb
+ def color(self):
+ return self._rgb
- def expose(self, widget, event):
- rect = widget.get_allocation()
- ctx = widget.window.cairo_create()
+ def expose(self, widget, event):
+ rect = widget.get_allocation()
+ ctx = widget.window.cairo_create()
- ctx.set_source_rgb(self._rgb[0], self._rgb[1] , self._rgb[2])
- ctx.rectangle(4, 4, rect.width - 8, rect.height - 8)
- ctx.fill()
-
- return False
+ ctx.set_source_rgb(self._rgb[0], self._rgb[1] , self._rgb[2])
+ ctx.rectangle(4, 4, rect.width - 8, rect.height - 8)
+ ctx.fill()
+
+ return False
class Toolbox(gtk.HBox):
- __gsignals__ = {
- 'color-selected': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT]))
- }
+ __gsignals__ = {
+ 'color-selected': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT]))
+ }
- def __init__(self):
- gtk.HBox.__init__(self, False, 6)
-
- self._colors_group = None
-
- self._add_color([0, 0, 0])
- self._add_color([1, 0, 0])
- self._add_color([0, 1, 0])
- self._add_color([0, 0, 1])
-
- def _add_color(self, rgb):
- color = ColorButton(self._colors_group, rgb)
- color.unset_flags(gtk.CAN_FOCUS)
- color.connect('clicked', self.__color_clicked_cb, rgb)
- self.pack_start(color, False)
+ def __init__(self):
+ gtk.HBox.__init__(self, False, 6)
+
+ self._colors_group = None
+
+ self._add_color([0, 0, 0])
+ self._add_color([1, 0, 0])
+ self._add_color([0, 1, 0])
+ self._add_color([0, 0, 1])
+
+ def _add_color(self, rgb):
+ color = ColorButton(self._colors_group, rgb)
+ color.unset_flags(gtk.CAN_FOCUS)
+ color.connect('clicked', self.__color_clicked_cb, rgb)
+ self.pack_start(color, False)
- if self._colors_group == None:
- self._colors_group = color
+ if self._colors_group == None:
+ self._colors_group = color
- color.show()
+ color.show()
- def __color_clicked_cb(self, button, rgb):
- self.emit("color-selected", button.color())
+ def __color_clicked_cb(self, button, rgb):
+ self.emit("color-selected", button.color())
diff --git a/sugar/clipboard/ClipboardService.py b/sugar/clipboard/ClipboardService.py
index 7c9dd1f..254d6b2 100644
--- a/sugar/clipboard/ClipboardService.py
+++ b/sugar/clipboard/ClipboardService.py
@@ -7,69 +7,69 @@ DBUS_PATH = "/org/laptop/Clipboard"
class ClipboardService(gobject.GObject):
- __gsignals__ = {
- 'object-added': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([str, str, str])),
- 'object-deleted': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([str])),
- 'object-state-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([str, int])),
- }
-
- def __init__(self):
- gobject.GObject.__init__(self)
-
- self._dbus_service = None
- bus = dbus.SessionBus()
- bus.add_signal_receiver(self._name_owner_changed_cb,
- signal_name="NameOwnerChanged",
- dbus_interface="org.freedesktop.DBus")
- # Try to register to ClipboardService, if we fail, we'll try later.
- try:
- self._connect_clipboard_signals()
- except dbus.DBusException, exception:
- pass
-
- def _connect_clipboard_signals(self):
- bus = dbus.SessionBus()
- proxy_obj = bus.get_object(DBUS_SERVICE, DBUS_PATH)
- self._dbus_service = dbus.Interface(proxy_obj, DBUS_SERVICE)
- self._dbus_service.connect_to_signal('object_added',
- self._object_added_cb)
- self._dbus_service.connect_to_signal('object_deleted',
- self._object_deleted_cb)
- self._dbus_service.connect_to_signal('object_state_changed',
- self._object_state_changed_cb)
+ __gsignals__ = {
+ 'object-added': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([str, str, str])),
+ 'object-deleted': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([str])),
+ 'object-state-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([str, int])),
+ }
+
+ def __init__(self):
+ gobject.GObject.__init__(self)
+
+ self._dbus_service = None
+ bus = dbus.SessionBus()
+ bus.add_signal_receiver(self._name_owner_changed_cb,
+ signal_name="NameOwnerChanged",
+ dbus_interface="org.freedesktop.DBus")
+ # Try to register to ClipboardService, if we fail, we'll try later.
+ try:
+ self._connect_clipboard_signals()
+ except dbus.DBusException, exception:
+ pass
+
+ def _connect_clipboard_signals(self):
+ bus = dbus.SessionBus()
+ proxy_obj = bus.get_object(DBUS_SERVICE, DBUS_PATH)
+ self._dbus_service = dbus.Interface(proxy_obj, DBUS_SERVICE)
+ self._dbus_service.connect_to_signal('object_added',
+ self._object_added_cb)
+ self._dbus_service.connect_to_signal('object_deleted',
+ self._object_deleted_cb)
+ self._dbus_service.connect_to_signal('object_state_changed',
+ self._object_state_changed_cb)
- def _name_owner_changed_cb(self, name, old, new):
- if name != DBUS_SERVICE:
- return
-
- if (not old and not len(old)) and (new and len(new)):
- # ClipboardService started up
- self._connect_clipboard_signals()
-
- def _object_added_cb(self, name, mimeType, fileName):
- self.emit('object-added', name, mimeType, fileName)
+ def _name_owner_changed_cb(self, name, old, new):
+ if name != DBUS_SERVICE:
+ return
+
+ if (not old and not len(old)) and (new and len(new)):
+ # ClipboardService started up
+ self._connect_clipboard_signals()
+
+ def _object_added_cb(self, name, mimeType, fileName):
+ self.emit('object-added', name, mimeType, fileName)
- def _object_deleted_cb(self, fileName):
- self.emit('object-deleted', fileName)
+ def _object_deleted_cb(self, fileName):
+ self.emit('object-deleted', fileName)
- def _object_state_changed_cb(self, fileName, percent):
- self.emit('object-state-changed', fileName, percent)
-
- def add_object(self, name, mimeType, fileName):
- self._dbus_service.add_object(name, mimeType, fileName)
+ def _object_state_changed_cb(self, fileName, percent):
+ self.emit('object-state-changed', fileName, percent)
+
+ def add_object(self, name, mimeType, fileName):
+ self._dbus_service.add_object(name, mimeType, fileName)
- def delete_object(self, fileName):
- self._dbus_service.delete_object(fileName)
-
- def set_object_state(self, fileName, percent):
- self._dbus_service.set_object_state(fileName, percent)
+ def delete_object(self, fileName):
+ self._dbus_service.delete_object(fileName)
+
+ def set_object_state(self, fileName, percent):
+ self._dbus_service.set_object_state(fileName, percent)
_clipboard_service = None
def get_instance():
- global _clipboard_service
- if not _clipboard_service:
- _clipboard_service = ClipboardService()
- return _clipboard_service
+ global _clipboard_service
+ if not _clipboard_service:
+ _clipboard_service = ClipboardService()
+ return _clipboard_service
diff --git a/sugar/emulator.py b/sugar/emulator.py
index 638029e..b37dae6 100644
--- a/sugar/emulator.py
+++ b/sugar/emulator.py
@@ -24,108 +24,108 @@ import gobject
from sugar import env
def get_display_number():
- """Find a free display number trying to connect to 6000+ ports"""
- retries = 20
- display_number = 1
- display_is_free = False
-
- while not display_is_free and retries > 0:
- s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- try:
- s.connect(('127.0.0.1', 6000 + display_number))
- s.close()
-
- display_number += 1
- retries -= 1
- except:
- display_is_free = True
-
- if display_is_free:
- return display_number
- else:
- logging.error('Cannot find a free display.')
- sys.exit(0)
+ """Find a free display number trying to connect to 6000+ ports"""
+ retries = 20
+ display_number = 1
+ display_is_free = False
+
+ while not display_is_free and retries > 0:
+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ try:
+ s.connect(('127.0.0.1', 6000 + display_number))
+ s.close()
+
+ display_number += 1
+ retries -= 1
+ except:
+ display_is_free = True
+
+ if display_is_free:
+ return display_number
+ else:
+ logging.error('Cannot find a free display.')
+ sys.exit(0)
class Process:
- """Object representing one of the session processes"""
-
- def __init__(self, command):
- self._command = command
-
- def get_name(self):
- return self._command
-
- def start(self, standard_output=False):
- args = self._command.split()
- flags = gobject.SPAWN_SEARCH_PATH
- result = gobject.spawn_async(args, flags=flags,
- standard_output=standard_output)
- self.pid = result[0]
- self._stdout = result[2]
+ """Object representing one of the session processes"""
+
+ def __init__(self, command):
+ self._command = command
+
+ def get_name(self):
+ return self._command
+
+ def start(self, standard_output=False):
+ args = self._command.split()
+ flags = gobject.SPAWN_SEARCH_PATH
+ result = gobject.spawn_async(args, flags=flags,
+ standard_output=standard_output)
+ self.pid = result[0]
+ self._stdout = result[2]
class MatchboxProcess(Process):
- def __init__(self):
- kbd_config = os.path.join(env.get_data_dir(), 'kbdconfig')
- options = '-kbdconfig %s ' % kbd_config
+ def __init__(self):
+ kbd_config = os.path.join(env.get_data_dir(), 'kbdconfig')
+ options = '-kbdconfig %s ' % kbd_config
- options += '-use_titlebar no '
- options += '-theme olpc '
+ options += '-use_titlebar no '
+ options += '-theme olpc '
- command = 'matchbox-window-manager %s ' % options
- Process.__init__(self, command)
-
- def get_name(self):
- return 'Matchbox'
+ command = 'matchbox-window-manager %s ' % options
+ Process.__init__(self, command)
+
+ def get_name(self):
+ return 'Matchbox'
class XephyrProcess(Process):
- def __init__(self, fullscreen):
- self._display = get_display_number()
- cmd = 'Xephyr :%d -ac ' % (self._display)
- if fullscreen:
- cmd += '-fullscreen '
- else:
- cmd += '-screen 800x600 '
- Process.__init__(self, cmd)
-
- def get_name(self):
- return 'Xephyr'
-
- def start(self):
- Process.start(self)
- os.environ['DISPLAY'] = ":%d" % (self._display)
- os.environ['SUGAR_XEPHYR_PID'] = '%d' % self.pid
+ def __init__(self, fullscreen):
+ self._display = get_display_number()
+ cmd = 'Xephyr :%d -ac ' % (self._display)
+ if fullscreen:
+ cmd += '-fullscreen '
+ else:
+ cmd += '-screen 800x600 '
+ Process.__init__(self, cmd)
+
+ def get_name(self):
+ return 'Xephyr'
+
+ def start(self):
+ Process.start(self)
+ os.environ['DISPLAY'] = ":%d" % (self._display)
+ os.environ['SUGAR_XEPHYR_PID'] = '%d' % self.pid
class XnestProcess(Process):
- def __init__(self):
- self._display = get_display_number()
- cmd = 'Xnest :%d -ac -geometry 800x600' % (self._display)
- Process.__init__(self, cmd)
-
- def get_name(self):
- return 'Xnest'
-
- def start(self):
- Process.start(self)
- os.environ['DISPLAY'] = ":%d" % (self._display)
+ def __init__(self):
+ self._display = get_display_number()
+ cmd = 'Xnest :%d -ac -geometry 800x600' % (self._display)
+ Process.__init__(self, cmd)
+
+ def get_name(self):
+ return 'Xnest'
+
+ def start(self):
+ Process.start(self)
+ os.environ['DISPLAY'] = ":%d" % (self._display)
class Emulator(object):
- """The OLPC emulator"""
- def __init__(self, fullscreen):
- self._fullscreen = fullscreen
-
- def start(self):
- try:
- process = XephyrProcess(self._fullscreen)
- process.start()
- except:
- try:
- process = XnestProcess()
- process.start()
- except:
- print 'Cannot run the emulator. You need to install \
- Xephyr or Xnest.'
- sys.exit(0)
-
- process = MatchboxProcess()
- process.start()
+ """The OLPC emulator"""
+ def __init__(self, fullscreen):
+ self._fullscreen = fullscreen
+
+ def start(self):
+ try:
+ process = XephyrProcess(self._fullscreen)
+ process.start()
+ except:
+ try:
+ process = XnestProcess()
+ process.start()
+ except:
+ print 'Cannot run the emulator. You need to install \
+ Xephyr or Xnest.'
+ sys.exit(0)
+
+ process = MatchboxProcess()
+ process.start()
diff --git a/sugar/env.py b/sugar/env.py
index 7c63731..391c7cd 100644
--- a/sugar/env.py
+++ b/sugar/env.py
@@ -20,43 +20,43 @@ import sys
import pwd
try:
- from sugar.__uninstalled__ import *
+ from sugar.__uninstalled__ import *
except ImportError:
- from sugar.__installed__ import *
+ from sugar.__installed__ import *
def get_profile_path():
- if os.environ.has_key('SUGAR_PROFILE'):
- profile_id = os.environ['SUGAR_PROFILE']
- else:
- profile_id = 'default'
+ if os.environ.has_key('SUGAR_PROFILE'):
+ profile_id = os.environ['SUGAR_PROFILE']
+ else:
+ profile_id = 'default'
- path = os.path.join(os.path.expanduser('~/.sugar'), profile_id)
- if not os.path.isdir(path):
- try:
- os.makedirs(path)
- except OSError, exc:
- print "Could not create user directory."
+ path = os.path.join(os.path.expanduser('~/.sugar'), profile_id)
+ if not os.path.isdir(path):
+ try:
+ os.makedirs(path)
+ except OSError, exc:
+ print "Could not create user directory."
- return path
+ return path
def get_data_dir():
- return sugar_data_dir
+ return sugar_data_dir
def get_services_dir():
- return sugar_services_dir
+ return sugar_services_dir
def get_shell_bin_dir():
- return sugar_shell_bin_dir
+ return sugar_shell_bin_dir
# http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
def get_data_dirs():
- if os.environ.has_key('XDG_DATA_DIRS'):
- return os.environ['XDG_DATA_DIRS'].split(':')
- else:
- return [ '/usr/local/share/', '/usr/share/' ]
+ if os.environ.has_key('XDG_DATA_DIRS'):
+ return os.environ['XDG_DATA_DIRS'].split(':')
+ else:
+ return [ '/usr/local/share/', '/usr/share/' ]
def get_user_service_dir():
- service_dir = os.path.expanduser('~/.local/share/dbus-1/services')
- if not os.path.isdir(service_dir):
- os.makedirs(service_dir)
- return service_dir
+ service_dir = os.path.expanduser('~/.local/share/dbus-1/services')
+ if not os.path.isdir(service_dir):
+ os.makedirs(service_dir)
+ return service_dir
diff --git a/sugar/graphics/ClipboardBubble.py b/sugar/graphics/ClipboardBubble.py
index b94fc26..1947fd5 100644
--- a/sugar/graphics/ClipboardBubble.py
+++ b/sugar/graphics/ClipboardBubble.py
@@ -24,108 +24,108 @@ import gtk
import hippo
class ClipboardBubble(hippo.CanvasBox, hippo.CanvasItem):
- __gtype_name__ = 'ClipboardBubble'
-
- __gproperties__ = {
- 'fill-color': (object, None, None,
- gobject.PARAM_READWRITE),
- 'stroke-color': (object, None, None,
- gobject.PARAM_READWRITE),
- 'progress-color': (object, None, None,
- gobject.PARAM_READWRITE),
- 'percent' : (object, None, None,
- gobject.PARAM_READWRITE),
- }
-
- def __init__(self, **kwargs):
- self._stroke_color = 0xFFFFFFFF
- self._fill_color = 0xFFFFFFFF
- self._progress_color = 0x000000FF
- self._percent = 0
- self._radius = 8
-
- hippo.CanvasBox.__init__(self, **kwargs)
-
- def do_set_property(self, pspec, value):
- if pspec.name == 'fill-color':
- self._fill_color = value
- self.emit_paint_needed(0, 0, -1, -1)
- elif pspec.name == 'stroke-color':
- self._stroke_color = value
- self.emit_paint_needed(0, 0, -1, -1)
- elif pspec.name == 'progress-color':
- self._progress_color = value
- self.emit_paint_needed(0, 0, -1, -1)
- elif pspec.name == 'percent':
- self._percent = value
- self.emit_paint_needed(0, 0, -1, -1)
-
- def do_get_property(self, pspec):
- if pspec.name == 'fill-color':
- return self._fill_color
- elif pspec.name == 'stroke-color':
- return self._stroke_color
- elif pspec.name == 'progress-color':
- return self._progress_color
- elif pspec.name == 'percent':
- return self._percent
-
- def _int_to_rgb(self, int_color):
- red = (int_color >> 24) & 0x000000FF
- green = (int_color >> 16) & 0x000000FF
- blue = (int_color >> 8) & 0x000000FF
- alpha = int_color & 0x000000FF
- return (red / 255.0, green / 255.0, blue / 255.0)
-
- def do_paint_below_children(self, cr, damaged_box):
- [width, height] = self.get_allocation()
-
- line_width = 3.0
- x = line_width
- y = line_width
- width -= line_width * 2
- height -= line_width * 2
-
- self._paint_ellipse(cr, x, y, width, height, self._fill_color)
-
- color = self._int_to_rgb(self._stroke_color)
- cr.set_source_rgb(*color)
- cr.set_line_width(line_width)
- cr.stroke();
-
- self._paint_progress_bar(cr, x, y, width, height, line_width)
-
- def _paint_progress_bar(self, cr, x, y, width, height, line_width):
- prog_x = x + line_width
- prog_y = y + line_width
- prog_width = (width - (line_width * 2)) * (self._percent / 100.0)
- prog_height = (height - (line_width * 2))
-
- self._paint_ellipse(cr, prog_x, prog_y, width, height, self._progress_color)
-
- def _paint_ellipse(self, cr, x, y, width, height, fill_color):
- cr.move_to(x + self._radius, y)
- cr.arc(x + width - self._radius,
- y + self._radius,
- self._radius,
- math.pi * 1.5,
- math.pi * 2)
- cr.arc(x + width - self._radius,
- x + height - self._radius,
- self._radius,
- 0,
- math.pi * 0.5)
- cr.arc(x + self._radius,
- y + height - self._radius,
- self._radius,
- math.pi * 0.5,
- math.pi)
- cr.arc(x + self._radius,
- y + self._radius,
- self._radius,
- math.pi,
- math.pi * 1.5);
-
- color = self._int_to_rgb(fill_color)
- cr.set_source_rgb(*color)
- cr.fill_preserve();
+ __gtype_name__ = 'ClipboardBubble'
+
+ __gproperties__ = {
+ 'fill-color': (object, None, None,
+ gobject.PARAM_READWRITE),
+ 'stroke-color': (object, None, None,
+ gobject.PARAM_READWRITE),
+ 'progress-color': (object, None, None,
+ gobject.PARAM_READWRITE),
+ 'percent' : (object, None, None,
+ gobject.PARAM_READWRITE),
+ }
+
+ def __init__(self, **kwargs):
+ self._stroke_color = 0xFFFFFFFF
+ self._fill_color = 0xFFFFFFFF
+ self._progress_color = 0x000000FF
+ self._percent = 0
+ self._radius = 8
+
+ hippo.CanvasBox.__init__(self, **kwargs)
+
+ def do_set_property(self, pspec, value):
+ if pspec.name == 'fill-color':
+ self._fill_color = value
+ self.emit_paint_needed(0, 0, -1, -1)
+ elif pspec.name == 'stroke-color':
+ self._stroke_color = value
+ self.emit_paint_needed(0, 0, -1, -1)
+ elif pspec.name == 'progress-color':
+ self._progress_color = value
+ self.emit_paint_needed(0, 0, -1, -1)
+ elif pspec.name == 'percent':
+ self._percent = value
+ self.emit_paint_needed(0, 0, -1, -1)
+
+ def do_get_property(self, pspec):
+ if pspec.name == 'fill-color':
+ return self._fill_color
+ elif pspec.name == 'stroke-color':
+ return self._stroke_color
+ elif pspec.name == 'progress-color':
+ return self._progress_color
+ elif pspec.name == 'percent':
+ return self._percent
+
+ def _int_to_rgb(self, int_color):
+ red = (int_color >> 24) & 0x000000FF
+ green = (int_color >> 16) & 0x000000FF
+ blue = (int_color >> 8) & 0x000000FF
+ alpha = int_color & 0x000000FF
+ return (red / 255.0, green / 255.0, blue / 255.0)
+
+ def do_paint_below_children(self, cr, damaged_box):
+ [width, height] = self.get_allocation()
+
+ line_width = 3.0
+ x = line_width
+ y = line_width
+ width -= line_width * 2
+ height -= line_width * 2
+
+ self._paint_ellipse(cr, x, y, width, height, self._fill_color)
+
+ color = self._int_to_rgb(self._stroke_color)
+ cr.set_source_rgb(*color)
+ cr.set_line_width(line_width)
+ cr.stroke();
+
+ self._paint_progress_bar(cr, x, y, width, height, line_width)
+
+ def _paint_progress_bar(self, cr, x, y, width, height, line_width):
+ prog_x = x + line_width
+ prog_y = y + line_width
+ prog_width = (width - (line_width * 2)) * (self._percent / 100.0)
+ prog_height = (height - (line_width * 2))
+
+ self._paint_ellipse(cr, prog_x, prog_y, width, height, self._progress_color)
+
+ def _paint_ellipse(self, cr, x, y, width, height, fill_color):
+ cr.move_to(x + self._radius, y)
+ cr.arc(x + width - self._radius,
+ y + self._radius,
+ self._radius,
+ math.pi * 1.5,
+ math.pi * 2)
+ cr.arc(x + width - self._radius,
+ x + height - self._radius,
+ self._radius,
+ 0,
+ math.pi * 0.5)
+ cr.arc(x + self._radius,
+ y + height - self._radius,
+ self._radius,
+ math.pi * 0.5,
+ math.pi)
+ cr.arc(x + self._radius,
+ y + self._radius,
+ self._radius,
+ math.pi,
+ math.pi * 1.5);
+
+ color = self._int_to_rgb(fill_color)
+ cr.set_source_rgb(*color)
+ cr.fill_preserve();
diff --git a/sugar/graphics/bubble.py b/sugar/graphics/bubble.py
index f5903a0..5bfe87a 100644
--- a/sugar/graphics/bubble.py
+++ b/sugar/graphics/bubble.py
@@ -22,56 +22,56 @@ import gtk
import hippo
class Bubble(hippo.CanvasBox, hippo.CanvasItem):
- __gtype_name__ = 'SugarBubble'
+ __gtype_name__ = 'SugarBubble'
- __gproperties__ = {
- 'color' : (object, None, None,
- gobject.PARAM_READWRITE),
- }
+ __gproperties__ = {
+ 'color' : (object, None, None,
+ gobject.PARAM_READWRITE),
+ }
- def __init__(self, **kwargs):
- self._color = None
- self._radius = 8
+ def __init__(self, **kwargs):
+ self._color = None
+ self._radius = 8
- hippo.CanvasBox.__init__(self, **kwargs)
+ hippo.CanvasBox.__init__(self, **kwargs)
- def do_set_property(self, pspec, value):
- if pspec.name == 'color':
- self._color = value
- self.emit_paint_needed(0, 0, -1, -1)
+ def do_set_property(self, pspec, value):
+ if pspec.name == 'color':
+ self._color = value
+ self.emit_paint_needed(0, 0, -1, -1)
- def do_get_property(self, pspec):
- if pspec.name == 'color':
- return self._color
+ def do_get_property(self, pspec):
+ if pspec.name == 'color':
+ return self._color
- def _string_to_rgb(self, color_string):
- col = gtk.gdk.color_parse(color_string)
- return (col.red / 65535.0, col.green / 65535.0, col.blue / 65535.0)
+ def _string_to_rgb(self, color_string):
+ col = gtk.gdk.color_parse(color_string)
+ return (col.red / 65535.0, col.green / 65535.0, col.blue / 65535.0)
- def do_paint_below_children(self, cr, damaged_box):
- [width, height] = self.get_allocation()
+ def do_paint_below_children(self, cr, damaged_box):
+ [width, height] = self.get_allocation()
- line_width = 3.0
- x = line_width
- y = line_width
- width -= line_width * 2
- height -= line_width * 2
+ line_width = 3.0
+ x = line_width
+ y = line_width
+ width -= line_width * 2
+ height -= line_width * 2
- cr.move_to(x + self._radius, y);
- cr.arc(x + width - self._radius, y + self._radius,
- self._radius, math.pi * 1.5, math.pi * 2);
- cr.arc(x + width - self._radius, x + height - self._radius,
- self._radius, 0, math.pi * 0.5);
- cr.arc(x + self._radius, y + height - self._radius,
- self._radius, math.pi * 0.5, math.pi);
- cr.arc(x + self._radius, y + self._radius, self._radius,
- math.pi, math.pi * 1.5);
+ cr.move_to(x + self._radius, y);
+ cr.arc(x + width - self._radius, y + self._radius,
+ self._radius, math.pi * 1.5, math.pi * 2);
+ cr.arc(x + width - self._radius, x + height - self._radius,
+ self._radius, 0, math.pi * 0.5);
+ cr.arc(x + self._radius, y + height - self._radius,
+ self._radius, math.pi * 0.5, math.pi);
+ cr.arc(x + self._radius, y + self._radius, self._radius,
+ math.pi, math.pi * 1.5);
- color = self._string_to_rgb(self._color.get_fill_color())
- cr.set_source_rgb(*color)
- cr.fill_preserve();
+ color = self._string_to_rgb(self._color.get_fill_color())
+ cr.set_source_rgb(*color)
+ cr.fill_preserve();
- color = self._string_to_rgb(self._color.get_stroke_color())
- cr.set_source_rgb(*color)
- cr.set_line_width(line_width)
- cr.stroke();
+ color = self._string_to_rgb(self._color.get_stroke_color())
+ cr.set_source_rgb(*color)
+ cr.set_line_width(line_width)
+ cr.stroke();
diff --git a/sugar/graphics/canvasicon.py b/sugar/graphics/canvasicon.py
index da3d8ca..06aff7b 100644
--- a/sugar/graphics/canvasicon.py
+++ b/sugar/graphics/canvasicon.py
@@ -26,133 +26,133 @@ import cairo
from sugar.graphics.iconcolor import IconColor
class _IconCache:
- def __init__(self):
- self._icons = {}
- self._theme = gtk.icon_theme_get_default()
+ def __init__(self):
+ self._icons = {}
+ self._theme = gtk.icon_theme_get_default()
- def _read_icon(self, filename, color):
- icon_file = open(filename, 'r')
+ def _read_icon(self, filename, color):
+ icon_file = open(filename, 'r')
- if color == None:
- return rsvg.Handle(file=filename)
- else:
- data = icon_file.read()
- icon_file.close()
+ if color == None:
+ return rsvg.Handle(file=filename)
+ else:
+ data = icon_file.read()
+ icon_file.close()
- fill = color.get_fill_color()
- stroke = color.get_stroke_color()
-
- entity = '<!ENTITY fill_color "%s">' % fill
- data = re.sub('<!ENTITY fill_color .*>', entity, data)
+ fill = color.get_fill_color()
+ stroke = color.get_stroke_color()
+
+ entity = '<!ENTITY fill_color "%s">' % fill
+ data = re.sub('<!ENTITY fill_color .*>', entity, data)
- entity = '<!ENTITY stroke_color "%s">' % stroke
- data = re.sub('<!ENTITY stroke_color .*>', entity, data)
+ entity = '<!ENTITY stroke_color "%s">' % stroke
+ data = re.sub('<!ENTITY stroke_color .*>', entity, data)
- return rsvg.Handle(data=data)
+ return rsvg.Handle(data=data)
- def get_handle(self, name, color, size):
- info = self._theme.lookup_icon(name, int(size), 0)
+ def get_handle(self, name, color, size):
+ info = self._theme.lookup_icon(name, int(size), 0)
- if color:
- key = (info.get_filename(), color.to_string())
- else:
- key = info.get_filename()
+ if color:
+ key = (info.get_filename(), color.to_string())
+ else:
+ key = info.get_filename()
- if self._icons.has_key(key):
- icon = self._icons[key]
- else:
- icon = self._read_icon(info.get_filename(), color)
- self._icons[key] = icon
- return icon
+ if self._icons.has_key(key):
+ icon = self._icons[key]
+ else:
+ icon = self._read_icon(info.get_filename(), color)
+ self._icons[key] = icon
+ return icon
class CanvasIcon(hippo.CanvasBox, hippo.CanvasItem):
- __gtype_name__ = 'CanvasIcon'
-
- __gproperties__ = {
- 'icon-name': (str, None, None, None,
- gobject.PARAM_READWRITE),
- 'color' : (object, None, None,
- gobject.PARAM_READWRITE),
- 'size' : (int, None, None,
- 0, 1024, 24,
- gobject.PARAM_READWRITE)
- }
-
- _cache = _IconCache()
-
- def __init__(self, **kwargs):
- self._size = 24
- self._color = None
- self._icon_name = None
-
- hippo.CanvasBox.__init__(self, **kwargs)
-
- self._buffer = None
-
- self.connect('button-press-event', self._button_press_event_cb)
-
- def do_set_property(self, pspec, value):
- if pspec.name == 'icon-name':
- self._icon_name = value
- self._buffer = None
- self.emit_paint_needed(0, 0, -1, -1)
- elif pspec.name == 'color':
- self._buffer = None
- self._color = value
- self.emit_paint_needed(0, 0, -1, -1)
- elif pspec.name == 'size':
- self._buffer = None
- self._size = value
- self.emit_request_changed()
-
- def do_get_property(self, pspec):
- if pspec.name == 'size':
- return self._size
- elif pspec.name == 'icon-name':
- return self._icon_name
- elif pspec.name == 'color':
- return self._color
-
- def _get_buffer(self, cr, handle, size):
- if self._buffer == None:
- target = cr.get_target()
- surface = target.create_similar(cairo.CONTENT_COLOR_ALPHA,
- int(size) + 1, int(size) + 1)
-
- dimensions = handle.get_dimension_data()
- scale = float(size) / float(dimensions[0])
-
- ctx = cairo.Context(surface)
- ctx.scale(scale, scale)
- handle.render_cairo(ctx)
- del ctx
-
- self._buffer = surface
- self._buffer_scale = scale
-
- return self._buffer
-
- def do_paint_below_children(self, cr, damaged_box):
- icon_name = self._icon_name
- if icon_name == None:
- icon_name = 'stock-missing'
-
- handle = CanvasIcon._cache.get_handle(
- icon_name, self._color, self._size)
- buf = self._get_buffer(cr, handle, self._size)
-
- [width, height] = self.get_allocation()
- x = (width - self._size) / 2
- y = (height - self._size) / 2
-
- cr.set_source_surface(buf, x, y)
- cr.paint()
-
- def do_get_width_request(self):
- return self._size
-
- def do_get_height_request(self, for_width):
- return self._size
-
- def _button_press_event_cb(self, item, event):
- item.emit_activated()
+ __gtype_name__ = 'CanvasIcon'
+
+ __gproperties__ = {
+ 'icon-name': (str, None, None, None,
+ gobject.PARAM_READWRITE),
+ 'color' : (object, None, None,
+ gobject.PARAM_READWRITE),
+ 'size' : (int, None, None,
+ 0, 1024, 24,
+ gobject.PARAM_READWRITE)
+ }
+
+ _cache = _IconCache()
+
+ def __init__(self, **kwargs):
+ self._size = 24
+ self._color = None
+ self._icon_name = None
+
+ hippo.CanvasBox.__init__(self, **kwargs)
+
+ self._buffer = None
+
+ self.connect('button-press-event', self._button_press_event_cb)
+
+ def do_set_property(self, pspec, value):
+ if pspec.name == 'icon-name':
+ self._icon_name = value
+ self._buffer = None
+ self.emit_paint_needed(0, 0, -1, -1)
+ elif pspec.name == 'color':
+ self._buffer = None
+ self._color = value
+ self.emit_paint_needed(0, 0, -1, -1)
+ elif pspec.name == 'size':
+ self._buffer = None
+ self._size = value
+ self.emit_request_changed()
+
+ def do_get_property(self, pspec):
+ if pspec.name == 'size':
+ return self._size
+ elif pspec.name == 'icon-name':
+ return self._icon_name
+ elif pspec.name == 'color':
+ return self._color
+
+ def _get_buffer(self, cr, handle, size):
+ if self._buffer == None:
+ target = cr.get_target()
+ surface = target.create_similar(cairo.CONTENT_COLOR_ALPHA,
+ int(size) + 1, int(size) + 1)
+
+ dimensions = handle.get_dimension_data()
+ scale = float(size) / float(dimensions[0])
+
+ ctx = cairo.Context(surface)
+ ctx.scale(scale, scale)
+ handle.render_cairo(ctx)
+ del ctx
+
+ self._buffer = surface
+ self._buffer_scale = scale
+
+ return self._buffer
+
+ def do_paint_below_children(self, cr, damaged_box):
+ icon_name = self._icon_name
+ if icon_name == None:
+ icon_name = 'stock-missing'
+
+ handle = CanvasIcon._cache.get_handle(
+ icon_name, self._color, self._size)
+ buf = self._get_buffer(cr, handle, self._size)
+
+ [width, height] = self.get_allocation()
+ x = (width - self._size) / 2
+ y = (height - self._size) / 2
+
+ cr.set_source_surface(buf, x, y)
+ cr.paint()
+
+ def do_get_width_request(self):
+ return self._size
+
+ def do_get_height_request(self, for_width):
+ return self._size
+
+ def _button_press_event_cb(self, item, event):
+ item.emit_activated()
diff --git a/sugar/graphics/grid.py b/sugar/graphics/grid.py
index 350b4ec..cfbdf67 100644
--- a/sugar/graphics/grid.py
+++ b/sugar/graphics/grid.py
@@ -21,19 +21,19 @@ COLS = 16
ROWS = 12
class Grid(object):
- def __init__(self):
- self._factor = gtk.gdk.screen_width() / COLS
+ def __init__(self):
+ self._factor = gtk.gdk.screen_width() / COLS
- def point(self, grid_x, grid_y):
- return [grid_x * self._factor, grid_y * self._factor]
+ def point(self, grid_x, grid_y):
+ return [grid_x * self._factor, grid_y * self._factor]
- def rectangle(self, grid_x, grid_y, grid_w, grid_h):
- return [grid_x * self._factor, grid_y * self._factor,
- grid_w * self._factor, grid_h * self._factor]
+ def rectangle(self, grid_x, grid_y, grid_w, grid_h):
+ return [grid_x * self._factor, grid_y * self._factor,
+ grid_w * self._factor, grid_h * self._factor]
- def dimension(self, grid_dimension):
- return grid_dimension * self._factor
+ def dimension(self, grid_dimension):
+ return grid_dimension * self._factor
- def fit_point(self, x, y):
- return [int(x / self._factor), int(y / self._factor)]
-
+ def fit_point(self, x, y):
+ return [int(x / self._factor), int(y / self._factor)]
+
diff --git a/sugar/graphics/iconcolor.py b/sugar/graphics/iconcolor.py
index d736d54..71dfe18 100644
--- a/sugar/graphics/iconcolor.py
+++ b/sugar/graphics/iconcolor.py
@@ -20,32 +20,32 @@ import random
from sugar.graphics.colors import colors
def _parse_string(color_string):
- if color_string == 'white':
- return ['#ffffff', '#414141']
+ if color_string == 'white':
+ return ['#ffffff', '#414141']
- splitted = color_string.split(',')
- if len(splitted) == 2:
- return [splitted[0], splitted[1]]
- else:
- return None
+ splitted = color_string.split(',')
+ if len(splitted) == 2:
+ return [splitted[0], splitted[1]]
+ else:
+ return None
def is_valid(color_string):
- return (_parse_string(color_string) != None)
+ return (_parse_string(color_string) != None)
class IconColor:
- def __init__(self, color_string=None):
- if color_string == None or not is_valid(color_string):
- n = int(random.random() * (len(colors) - 1))
- [self._stroke, self._fill] = colors[n]
- else:
- [self._stroke, self._fill] = _parse_string(color_string)
+ def __init__(self, color_string=None):
+ if color_string == None or not is_valid(color_string):
+ n = int(random.random() * (len(colors) - 1))
+ [self._stroke, self._fill] = colors[n]
+ else:
+ [self._stroke, self._fill] = _parse_string(color_string)
- def get_stroke_color(self):
- return self._stroke
+ def get_stroke_color(self):
+ return self._stroke
- def get_fill_color(self):
- return self._fill
+ def get_fill_color(self):
+ return self._fill
- def to_string(self):
- return '%s,%s' % (self._stroke, self._fill)
+ def to_string(self):
+ return '%s,%s' % (self._stroke, self._fill)
diff --git a/sugar/graphics/menu.py b/sugar/graphics/menu.py
index 508dbb0..5b68d61 100644
--- a/sugar/graphics/menu.py
+++ b/sugar/graphics/menu.py
@@ -23,85 +23,85 @@ from sugar.graphics.canvasicon import CanvasIcon
from sugar.graphics import style
class Menu(gtk.Window):
- __gsignals__ = {
- 'action': (gobject.SIGNAL_RUN_FIRST,
- gobject.TYPE_NONE, ([int])),
- }
+ __gsignals__ = {
+ 'action': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([int])),
+ }
- def __init__(self, title=None, content_box=None):
- gtk.Window.__init__(self, gtk.WINDOW_POPUP)
+ def __init__(self, title=None, content_box=None):
+ gtk.Window.__init__(self, gtk.WINDOW_POPUP)
- canvas = hippo.Canvas()
- self.add(canvas)
- canvas.show()
+ canvas = hippo.Canvas()
+ self.add(canvas)
+ canvas.show()
- self._root = hippo.CanvasBox()
- style.apply_stylesheet(self._root, 'menu')
- canvas.set_root(self._root)
+ self._root = hippo.CanvasBox()
+ style.apply_stylesheet(self._root, 'menu')
+ canvas.set_root(self._root)
- if title:
- self._title_item = hippo.CanvasText(text=title)
- style.apply_stylesheet(self._title_item, 'menu.Title')
- self._root.append(self._title_item)
- else:
- self._title_item = None
+ if title:
+ self._title_item = hippo.CanvasText(text=title)
+ style.apply_stylesheet(self._title_item, 'menu.Title')
+ self._root.append(self._title_item)
+ else:
+ self._title_item = None
- if content_box:
- separator = self._create_separator()
- self._root.append(separator)
- self._root.append(content_box)
+ if content_box:
+ separator = self._create_separator()
+ self._root.append(separator)
+ self._root.append(content_box)
- self._action_box = None
- self._item_box = None
+ self._action_box = None
+ self._item_box = None
- def _create_separator(self):
- separator = hippo.CanvasBox()
- style.apply_stylesheet(separator, 'menu.Separator')
- return separator
+ def _create_separator(self):
+ separator = hippo.CanvasBox()
+ style.apply_stylesheet(separator, 'menu.Separator')
+ return separator
- def _create_item_box(self):
- if self._title_item:
- separator = self._create_separator()
- self._root.append(separator)
+ def _create_item_box(self):
+ if self._title_item:
+ separator = self._create_separator()
+ self._root.append(separator)
- self._item_box = hippo.CanvasBox(
- orientation=hippo.ORIENTATION_VERTICAL)
- self._root.append(self._item_box)
+ self._item_box = hippo.CanvasBox(
+ orientation=hippo.ORIENTATION_VERTICAL)
+ self._root.append(self._item_box)
- def _create_action_box(self):
- separator = self._create_separator()
- self._root.append(separator)
+ def _create_action_box(self):
+ separator = self._create_separator()
+ self._root.append(separator)
- self._action_box = hippo.CanvasBox(
- orientation=hippo.ORIENTATION_HORIZONTAL)
- self._root.append(self._action_box)
+ self._action_box = hippo.CanvasBox(
+ orientation=hippo.ORIENTATION_HORIZONTAL)
+ self._root.append(self._action_box)
- def add_item(self, label, action_id):
- if not self._item_box:
- self._create_item_box()
+ def add_item(self, label, action_id):
+ if not self._item_box:
+ self._create_item_box()
- text = hippo.CanvasText(text=label)
- style.apply_stylesheet(text, 'menu.Item')
+ text = hippo.CanvasText(text=label)
+ style.apply_stylesheet(text, 'menu.Item')
- # FIXME need a way to make hippo items activable in python
- text.connect('button-press-event', self._item_clicked_cb, action_id)
- #text.connect('activated', self._action_clicked_cb, action_id)
+ # FIXME need a way to make hippo items activable in python
+ text.connect('button-press-event', self._item_clicked_cb, action_id)
+ #text.connect('activated', self._action_clicked_cb, action_id)
- self._item_box.append(text)
+ self._item_box.append(text)
- def add_action(self, icon, action_id):
- if not self._action_box:
- self._create_action_box()
+ def add_action(self, icon, action_id):
+ if not self._action_box:
+ self._create_action_box()
- style.apply_stylesheet(icon, 'menu.ActionIcon')
- icon.connect('activated', self._action_clicked_cb, action_id)
- self._action_box.append(icon)
+ style.apply_stylesheet(icon, 'menu.ActionIcon')
+ icon.connect('activated', self._action_clicked_cb, action_id)
+ self._action_box.append(icon)
- def remove_action(self, icon):
- self._action_box.remove(icon)
+ def remove_action(self, icon):
+ self._action_box.remove(icon)
- def _item_clicked_cb(self, icon, event, action):
- self.emit('action', action)
+ def _item_clicked_cb(self, icon, event, action):
+ self.emit('action', action)
- def _action_clicked_cb(self, icon, action):
- self.emit('action', action)
+ def _action_clicked_cb(self, icon, action):
+ self.emit('action', action)
diff --git a/sugar/graphics/menuicon.py b/sugar/graphics/menuicon.py
index 8c0041e..62d1275 100644
--- a/sugar/graphics/menuicon.py
+++ b/sugar/graphics/menuicon.py
@@ -23,58 +23,58 @@ from sugar.graphics.canvasicon import CanvasIcon
from sugar.graphics.timeline import Timeline
class MenuIcon(CanvasIcon):
- def __init__(self, menu_shell, **kwargs):
- CanvasIcon.__init__(self, **kwargs)
+ def __init__(self, menu_shell, **kwargs):
+ CanvasIcon.__init__(self, **kwargs)
- self._menu_shell = menu_shell
- self._menu = None
- self._hover_menu = False
+ self._menu_shell = menu_shell
+ self._menu = None
+ self._hover_menu = False
- self._timeline = Timeline(self)
- self._timeline.add_tag('popup', 6, 6)
- self._timeline.add_tag('before_popdown', 7, 7)
- self._timeline.add_tag('popdown', 8, 8)
+ self._timeline = Timeline(self)
+ self._timeline.add_tag('popup', 6, 6)
+ self._timeline.add_tag('before_popdown', 7, 7)
+ self._timeline.add_tag('popdown', 8, 8)
- self.connect('motion-notify-event', self._motion_notify_event_cb)
+ self.connect('motion-notify-event', self._motion_notify_event_cb)
- def do_popup(self, current, n_frames):
- if self._menu:
- return
+ def do_popup(self, current, n_frames):
+ if self._menu:
+ return
- self._menu = self.create_menu()
+ self._menu = self.create_menu()
- self._menu.connect('enter-notify-event',
- self._menu_enter_notify_event_cb)
- self._menu.connect('leave-notify-event',
- self._menu_leave_notify_event_cb)
+ self._menu.connect('enter-notify-event',
+ self._menu_enter_notify_event_cb)
+ self._menu.connect('leave-notify-event',
+ self._menu_leave_notify_event_cb)
- [x, y] = self._menu_shell.get_position(self._menu, self)
+ [x, y] = self._menu_shell.get_position(self._menu, self)
- self._menu.move(x, y)
- self._menu.show()
+ self._menu.move(x, y)
+ self._menu.show()
- self._menu_shell.set_active(self)
+ self._menu_shell.set_active(self)
- def do_popdown(self, current, frame):
- if self._menu:
- self._menu.destroy()
- self._menu = None
- self._menu_shell.set_active(None)
+ def do_popdown(self, current, frame):
+ if self._menu:
+ self._menu.destroy()
+ self._menu = None
+ self._menu_shell.set_active(None)
- def popdown(self):
- self._timeline.play('popdown', 'popdown')
+ def popdown(self):
+ self._timeline.play('popdown', 'popdown')
- def _motion_notify_event_cb(self, item, event):
- if event.detail == hippo.MOTION_DETAIL_ENTER:
- self._timeline.play(None, 'popup')
- elif event.detail == hippo.MOTION_DETAIL_LEAVE:
- if not self._hover_menu:
- self._timeline.play('before_popdown', 'popdown')
+ def _motion_notify_event_cb(self, item, event):
+ if event.detail == hippo.MOTION_DETAIL_ENTER:
+ self._timeline.play(None, 'popup')
+ elif event.detail == hippo.MOTION_DETAIL_LEAVE:
+ if not self._hover_menu:
+ self._timeline.play('before_popdown', 'popdown')
- def _menu_enter_notify_event_cb(self, widget, event):
- self._hover_menu = True
- self._timeline.play('popup', 'popup')
+ def _menu_enter_notify_event_cb(self, widget, event):
+ self._hover_menu = True
+ self._timeline.play('popup', 'popup')
- def _menu_leave_notify_event_cb(self, widget, event):
- self._hover_menu = False
- self._timeline.play('popdown', 'popdown')
+ def _menu_leave_notify_event_cb(self, widget, event):
+ self._hover_menu = False
+ self._timeline.play('popdown', 'popdown')
diff --git a/sugar/graphics/menushell.py b/sugar/graphics/menushell.py
index 48183e1..61b98b0 100644
--- a/sugar/graphics/menushell.py
+++ b/sugar/graphics/menushell.py
@@ -19,83 +19,83 @@ import gobject
import gtk
class MenuShell(gobject.GObject):
- __gsignals__ = {
- 'activated': (gobject.SIGNAL_RUN_FIRST,
- gobject.TYPE_NONE, ([])),
- 'deactivated': (gobject.SIGNAL_RUN_FIRST,
- gobject.TYPE_NONE, ([])),
- }
-
- AUTO = 0
- LEFT = 1
- RIGHT = 2
- TOP = 3
- BOTTOM = 4
-
- def __init__(self, parent_canvas):
- gobject.GObject.__init__(self)
-
- self._parent_canvas = parent_canvas
- self._menu_controller = None
- self._position = MenuShell.AUTO
-
- def set_position(self, position):
- self._position = position
-
- def is_active(self):
- return (self._menu_controller != None)
-
- def set_active(self, controller):
- if controller == None:
- self.emit('deactivated')
- else:
- self.emit('activated')
-
- if self._menu_controller:
- self._menu_controller.popdown()
- self._menu_controller = controller
-
- def _get_item_rect(self, item):
- [x, y] = item.get_context().translate_to_widget(item)
-
- [origin_x, origin_y] = self._parent_canvas.window.get_origin()
- x += origin_x
- y += origin_y
-
- [w, h] = item.get_allocation()
-
- return [x, y, w, h]
-
- def get_position(self, menu, item):
- [item_x, item_y, item_w, item_h] = self._get_item_rect(item)
- [menu_w, menu_h] = menu.size_request()
-
- left_x = item_x - menu_w
- left_y = item_y
- right_x = item_x + item_w
- right_y = item_y
- top_x = item_x
- top_y = item_y - menu_h
- bottom_x = item_x
- bottom_y = item_y + item_h
-
- if self._position == MenuShell.LEFT:
- [x, y] = [left_x, left_y]
- elif self._position == MenuShell.RIGHT:
- [x, y] = [right_x, right_y]
- elif self._position == MenuShell.TOP:
- [x, y] = [top_x, top_y]
- elif self._position == MenuShell.BOTTOM:
- [x, y] = [bottom_x, bottom_y]
- elif self._position == MenuShell.AUTO:
- [x, y] = [right_x, right_y]
- if x + menu_w > gtk.gdk.screen_width():
- [x, y] = [left_x, left_y]
-
- x = min(x, gtk.gdk.screen_width() - menu_w)
- x = max(0, x)
-
- y = min(y, gtk.gdk.screen_height() - menu_h)
- y = max(0, y)
-
- return [x, y]
+ __gsignals__ = {
+ 'activated': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([])),
+ 'deactivated': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([])),
+ }
+
+ AUTO = 0
+ LEFT = 1
+ RIGHT = 2
+ TOP = 3
+ BOTTOM = 4
+
+ def __init__(self, parent_canvas):
+ gobject.GObject.__init__(self)
+
+ self._parent_canvas = parent_canvas
+ self._menu_controller = None
+ self._position = MenuShell.AUTO
+
+ def set_position(self, position):
+ self._position = position
+
+ def is_active(self):
+ return (self._menu_controller != None)
+
+ def set_active(self, controller):
+ if controller == None:
+ self.emit('deactivated')
+ else:
+ self.emit('activated')
+
+ if self._menu_controller:
+ self._menu_controller.popdown()
+ self._menu_controller = controller
+
+ def _get_item_rect(self, item):
+ [x, y] = item.get_context().translate_to_widget(item)
+
+ [origin_x, origin_y] = self._parent_canvas.window.get_origin()
+ x += origin_x
+ y += origin_y
+
+ [w, h] = item.get_allocation()
+
+ return [x, y, w, h]
+
+ def get_position(self, menu, item):
+ [item_x, item_y, item_w, item_h] = self._get_item_rect(item)
+ [menu_w, menu_h] = menu.size_request()
+
+ left_x = item_x - menu_w
+ left_y = item_y
+ right_x = item_x + item_w
+ right_y = item_y
+ top_x = item_x
+ top_y = item_y - menu_h
+ bottom_x = item_x
+ bottom_y = item_y + item_h
+
+ if self._position == MenuShell.LEFT:
+ [x, y] = [left_x, left_y]
+ elif self._position == MenuShell.RIGHT:
+ [x, y] = [right_x, right_y]
+ elif self._position == MenuShell.TOP:
+ [x, y] = [top_x, top_y]
+ elif self._position == MenuShell.BOTTOM:
+ [x, y] = [bottom_x, bottom_y]
+ elif self._position == MenuShell.AUTO:
+ [x, y] = [right_x, right_y]
+ if x + menu_w > gtk.gdk.screen_width():
+ [x, y] = [left_x, left_y]
+
+ x = min(x, gtk.gdk.screen_width() - menu_w)
+ x = max(0, x)
+
+ y = min(y, gtk.gdk.screen_height() - menu_h)
+ y = max(0, y)
+
+ return [x, y]
diff --git a/sugar/graphics/snowflakebox.py b/sugar/graphics/snowflakebox.py
index 2af11cd..30f5b05 100644
--- a/sugar/graphics/snowflakebox.py
+++ b/sugar/graphics/snowflakebox.py
@@ -25,72 +25,72 @@ _CHILDREN_FACTOR = 1
_FLAKE_DISTANCE = 6
class SnowflakeBox(hippo.CanvasBox, hippo.CanvasItem):
- __gtype_name__ = 'SugarSnowflakeBox'
- def __init__(self, **kwargs):
- hippo.CanvasBox.__init__(self, **kwargs)
- self._root = None
+ __gtype_name__ = 'SugarSnowflakeBox'
+ def __init__(self, **kwargs):
+ hippo.CanvasBox.__init__(self, **kwargs)
+ self._root = None
- def set_root(self, icon):
- self._root = icon
+ def set_root(self, icon):
+ self._root = icon
- def _get_center(self):
- [width, height] = self.get_allocation()
- return [width / 2, height / 2]
+ def _get_center(self):
+ [width, height] = self.get_allocation()
+ return [width / 2, height / 2]
- def _get_radius(self):
- return _BASE_RADIUS + _CHILDREN_FACTOR * self._get_n_children()
+ def _get_radius(self):
+ return _BASE_RADIUS + _CHILDREN_FACTOR * self._get_n_children()
- def _layout_root(self):
- [width, height] = self._root.get_allocation()
- [cx, cy] = self._get_center()
+ def _layout_root(self):
+ [width, height] = self._root.get_allocation()
+ [cx, cy] = self._get_center()
- x = cx - (width / 2)
- y = cy - (height / 2)
+ x = cx - (width / 2)
+ y = cy - (height / 2)
- self.move(self._root, int(x), int(y))
+ self.move(self._root, int(x), int(y))
- def _get_n_children(self):
- return len(self.get_children()) - 1
+ def _get_n_children(self):
+ return len(self.get_children()) - 1
- def _layout_child(self, child, index):
- r = self._get_radius()
- if (self._get_n_children() > 10):
- r += _FLAKE_DISTANCE * (index % 3)
+ def _layout_child(self, child, index):
+ r = self._get_radius()
+ if (self._get_n_children() > 10):
+ r += _FLAKE_DISTANCE * (index % 3)
- angle = 2 * math.pi * index / self._get_n_children()
+ angle = 2 * math.pi * index / self._get_n_children()
- [width, height] = child.get_allocation()
- [cx, cy] = self._get_center()
+ [width, height] = child.get_allocation()
+ [cx, cy] = self._get_center()
- x = cx + math.cos(angle) * r - (width / 2)
- y = cy + math.sin(angle) * r - (height / 2)
+ x = cx + math.cos(angle) * r - (width / 2)
+ y = cy + math.sin(angle) * r - (height / 2)
- self.move(child, int(x), int(y))
+ self.move(child, int(x), int(y))
- def do_get_width_request(self):
- hippo.CanvasBox.do_get_width_request(self)
+ def do_get_width_request(self):
+ hippo.CanvasBox.do_get_width_request(self)
- max_child_size = 0
- for child in self.get_children():
- width = child.get_width_request()
- height = child.get_height_request(width)
- max_child_size = max (max_child_size, width)
- max_child_size = max (max_child_size, height)
+ max_child_size = 0
+ for child in self.get_children():
+ width = child.get_width_request()
+ height = child.get_height_request(width)
+ max_child_size = max (max_child_size, width)
+ max_child_size = max (max_child_size, height)
- return self._get_radius() * 2 + \
- max_child_size + _FLAKE_DISTANCE * 2
+ return self._get_radius() * 2 + \
+ max_child_size + _FLAKE_DISTANCE * 2
- def do_get_height_request(self, width):
- hippo.CanvasBox.do_get_height_request(self, width)
- return width
+ def do_get_height_request(self, width):
+ hippo.CanvasBox.do_get_height_request(self, width)
+ return width
- def do_allocate(self, width, height):
- hippo.CanvasBox.do_allocate(self, width, height)
+ def do_allocate(self, width, height):
+ hippo.CanvasBox.do_allocate(self, width, height)
- self._layout_root()
+ self._layout_root()
- index = 0
- for child in self.get_children():
- if child != self._root:
- self._layout_child(child, index)
- index += 1
+ index = 0
+ for child in self.get_children():
+ if child != self._root:
+ self._layout_child(child, index)
+ index += 1
diff --git a/sugar/graphics/spreadbox.py b/sugar/graphics/spreadbox.py
index 7d4047d..59dfe9c 100644
--- a/sugar/graphics/spreadbox.py
+++ b/sugar/graphics/spreadbox.py
@@ -25,108 +25,108 @@ _DISTANCE_THRESHOLD = 10.0
_FORCE_CONSTANT = 0.1
class SpreadBox(hippo.CanvasBox, hippo.CanvasItem):
- __gtype_name__ = 'SugarSpreadBox'
+ __gtype_name__ = 'SugarSpreadBox'
- def __init__(self, **kwargs):
- hippo.CanvasBox.__init__(self, **kwargs)
+ def __init__(self, **kwargs):
+ hippo.CanvasBox.__init__(self, **kwargs)
- self._items_to_position = []
- self._stable = False
+ self._items_to_position = []
+ self._stable = False
- def add_item(self, item):
- self._items_to_position.append(item)
- self.append(item, hippo.PACK_FIXED)
+ def add_item(self, item):
+ self._items_to_position.append(item)
+ self.append(item, hippo.PACK_FIXED)
- def remove_item(self, item):
- if self._items_to_position.count(item) > 0:
- self._items_to_position.remove(item)
- self.remove(item)
+ def remove_item(self, item):
+ if self._items_to_position.count(item) > 0:
+ self._items_to_position.remove(item)
+ self.remove(item)
- def _get_item_radius(self, item):
- [width, height] = item.get_request()
- return math.sqrt(width ** 2 + height ** 2) / 2
+ def _get_item_radius(self, item):
+ [width, height] = item.get_request()
+ return math.sqrt(width ** 2 + height ** 2) / 2
- def _get_item_center(self, item):
- [width, height] = item.get_request()
- [x, y] = self.get_position(item)
+ def _get_item_center(self, item):
+ [width, height] = item.get_request()
+ [x, y] = self.get_position(item)
- c_x = int(x + float(width) / 2.0)
- c_y = int(y + float(height) / 2.0)
+ c_x = int(x + float(width) / 2.0)
+ c_y = int(y + float(height) / 2.0)
- return [c_x, c_y]
+ return [c_x, c_y]
- def _get_repulsion(self, icon1, icon2):
- [c1_x, c1_y] = self._get_item_center(icon1)
- [c2_x, c2_y] = self._get_item_center(icon2)
+ def _get_repulsion(self, icon1, icon2):
+ [c1_x, c1_y] = self._get_item_center(icon1)
+ [c2_x, c2_y] = self._get_item_center(icon2)
- a = c2_x - c1_x
- b = c2_y - c1_y
+ a = c2_x - c1_x
+ b = c2_y - c1_y
- r1 = self._get_item_radius(icon1)
- r2 = self._get_item_radius(icon2)
- distance = math.sqrt(a ** 2 + b ** 2) - r1 - r2
+ r1 = self._get_item_radius(icon1)
+ r2 = self._get_item_radius(icon2)
+ distance = math.sqrt(a ** 2 + b ** 2) - r1 - r2
- if distance < _DISTANCE_THRESHOLD:
- f_x = int(math.ceil(-_FORCE_CONSTANT * float(a)))
- f_y = int(math.ceil(-_FORCE_CONSTANT * float(b)))
- else:
- f_x = 0
- f_y = 0
+ if distance < _DISTANCE_THRESHOLD:
+ f_x = int(math.ceil(-_FORCE_CONSTANT * float(a)))
+ f_y = int(math.ceil(-_FORCE_CONSTANT * float(b)))
+ else:
+ f_x = 0
+ f_y = 0
- return [f_x, f_y]
+ return [f_x, f_y]
- def _clamp_position(self, icon, x, y):
- x = max(0, x)
- y = max(0, y)
+ def _clamp_position(self, icon, x, y):
+ x = max(0, x)
+ y = max(0, y)
- [item_w, item_h] = icon.get_request()
- [box_w, box_h] = self.get_allocation()
+ [item_w, item_h] = icon.get_request()
+ [box_w, box_h] = self.get_allocation()
- x = min(box_w - item_w, x)
- y = min(box_h - item_h, y)
+ x = min(box_w - item_w, x)
+ y = min(box_h - item_h, y)
- return [x, y]
+ return [x, y]
- def _spread_icons(self):
- self._stable = True
+ def _spread_icons(self):
+ self._stable = True
- for icon1 in self.get_children():
- vx = 0
- vy = 0
+ for icon1 in self.get_children():
+ vx = 0
+ vy = 0
- for icon2 in self.get_children():
- if icon1 != icon2:
- [f_x, f_y] = self._get_repulsion(icon1, icon2)
- if f_x != 0 or f_y != 0:
- self._stable = False
- vx += f_x
- vy += f_y
+ for icon2 in self.get_children():
+ if icon1 != icon2:
+ [f_x, f_y] = self._get_repulsion(icon1, icon2)
+ if f_x != 0 or f_y != 0:
+ self._stable = False
+ vx += f_x
+ vy += f_y
- if vx != 0 or vy != 0:
- [x, y] = self.get_position(icon1)
- new_x = x + vx
- new_y = y + vy
+ if vx != 0 or vy != 0:
+ [x, y] = self.get_position(icon1)
+ new_x = x + vx
+ new_y = y + vy
- [new_x, new_y] = self._clamp_position(icon1, new_x, new_y)
+ [new_x, new_y] = self._clamp_position(icon1, new_x, new_y)
- self.move(icon1, new_x, new_y)
+ self.move(icon1, new_x, new_y)
- def do_allocate(self, width, height):
- hippo.CanvasBox.do_allocate(self, width, height)
+ def do_allocate(self, width, height):
+ hippo.CanvasBox.do_allocate(self, width, height)
- for item in self._items_to_position:
- [item_w, item_h] = item.get_request()
+ for item in self._items_to_position:
+ [item_w, item_h] = item.get_request()
- x = int(random.random() * width - item_w)
- y = int(random.random() * height - item_h)
+ x = int(random.random() * width - item_w)
+ y = int(random.random() * height - item_h)
- [x, y] = self._clamp_position(item, x, y)
- self.move(item, x, y)
+ [x, y] = self._clamp_position(item, x, y)
+ self.move(item, x, y)
- self._items_to_position = []
+ self._items_to_position = []
- tries = 20
- self._spread_icons()
- while not self._stable and tries > 0:
- self._spread_icons()
- tries -= 1
+ tries = 20
+ self._spread_icons()
+ while not self._stable and tries > 0:
+ self._spread_icons()
+ tries -= 1
diff --git a/sugar/graphics/style.py b/sugar/graphics/style.py
index f0ab3e8..6c4bff3 100644
--- a/sugar/graphics/style.py
+++ b/sugar/graphics/style.py
@@ -31,21 +31,21 @@ large_icon_size = standard_icon_size * 2.0
xlarge_icon_size = standard_icon_size * 3.0
def load_stylesheet(module):
- for objname in dir(module):
- if not objname.startswith('_'):
- obj = getattr(module, objname)
- if isinstance(obj, dict):
- register_stylesheet(objname.replace('_', '.'), obj)
+ for objname in dir(module):
+ if not objname.startswith('_'):
+ obj = getattr(module, objname)
+ if isinstance(obj, dict):
+ register_stylesheet(objname.replace('_', '.'), obj)
def register_stylesheet(name, style):
- _styles[name] = style
+ _styles[name] = style
def apply_stylesheet(item, stylesheet_name):
- if _styles.has_key(stylesheet_name):
- style_sheet = _styles[stylesheet_name]
- for name in style_sheet.keys():
- item.set_property(name, style_sheet[name])
+ if _styles.has_key(stylesheet_name):
+ style_sheet = _styles[stylesheet_name]
+ for name in style_sheet.keys():
+ item.set_property(name, style_sheet[name])
def get_font_description(style, relative_size):
- base_size = 18 * _screen_factor
- return '%s %dpx' % (style, int(base_size * relative_size))
+ base_size = 18 * _screen_factor
+ return '%s %dpx' % (style, int(base_size * relative_size))
diff --git a/sugar/graphics/stylesheet.py b/sugar/graphics/stylesheet.py
index d349733..ae9b4c8 100644
--- a/sugar/graphics/stylesheet.py
+++ b/sugar/graphics/stylesheet.py
@@ -1,31 +1,31 @@
from sugar.graphics import style
menu = {
- 'background_color' : 0x000000FF,
- 'spacing' : style.space_unit,
- 'padding' : style.space_unit
+ 'background_color' : 0x000000FF,
+ 'spacing' : style.space_unit,
+ 'padding' : style.space_unit
}
menu_Title = {
- 'color' : 0xFFFFFFFF,
- 'font' : style.get_font_description('Bold', 1.2)
+ 'color' : 0xFFFFFFFF,
+ 'font' : style.get_font_description('Bold', 1.2)
}
menu_Separator = {
- 'background_color' : 0xFFFFFFFF,
- 'box_height' : style.separator_thickness
+ 'background_color' : 0xFFFFFFFF,
+ 'box_height' : style.separator_thickness
}
menu_ActionIcon = {
- 'size' : style.standard_icon_size
+ 'size' : style.standard_icon_size
}
menu_Item = {
- 'color' : 0xFFFFFFFF,
- 'font' : style.get_font_description('Plain', 1.1)
+ 'color' : 0xFFFFFFFF,
+ 'font' : style.get_font_description('Plain', 1.1)
}
menu_Text = {
- 'color' : 0xFFFFFFFF,
- 'font' : style.get_font_description('Plain', 1.2)
+ 'color' : 0xFFFFFFFF,
+ 'font' : style.get_font_description('Plain', 1.2)
}
diff --git a/sugar/graphics/timeline.py b/sugar/graphics/timeline.py
index 5c40ca5..3944771 100644
--- a/sugar/graphics/timeline.py
+++ b/sugar/graphics/timeline.py
@@ -18,100 +18,100 @@
import gobject
class _Tag:
- def __init__(self, name, start_frame, end_frame):
- self.name = name
- self.start_frame = start_frame
- self.end_frame = end_frame
+ def __init__(self, name, start_frame, end_frame):
+ self.name = name
+ self.start_frame = start_frame
+ self.end_frame = end_frame
class TimelineObserver:
- def __init__(self, observer):
- self._observer = observer
+ def __init__(self, observer):
+ self._observer = observer
- def next_frame(self, tag, current_frame, n_frames):
- try:
- method = getattr(self._observer, 'do_' + tag)
- except AttributeError:
- method = None
+ def next_frame(self, tag, current_frame, n_frames):
+ try:
+ method = getattr(self._observer, 'do_' + tag)
+ except AttributeError:
+ method = None
- if method:
- method(current_frame, n_frames)
+ if method:
+ method(current_frame, n_frames)
class Timeline:
- def __init__(self, observer):
- self._fps = 12
- self._tags = []
- self._name_to_tag = {}
- self._current_frame = 0
- self._timeout_sid = 0
- self._observer = TimelineObserver(observer)
-
- def add_tag(self, name, start_frame, end_frame):
- tag = _Tag(name, start_frame, end_frame)
- self._tags.append(tag)
- self._name_to_tag[name] = tag
-
- def remove_tag(self, name):
- tag = self._tags[name]
- self._tags.remove(tag)
- del self._tags[name]
-
- def _next_frame(self, tag, frame):
- n_frames = tag.start_frame - tag.end_frame
- self._observer.next_frame(tag.name, frame, n_frames)
-
- def goto(self, tag_name, end_frame=False):
- self.pause()
-
- tag = self._name_to_tag[tag_name]
- if end_frame:
- self._current_frame = tag.end_frame
- else:
- self._current_frame = tag.start_frame
-
- self._next_frame(tag, self._current_frame)
-
- def on_tag(self, name):
- tag = self._name_to_tag[name]
- return (tag.start_frame <= self._current_frame and \
- tag.end_frame >= self._current_frame)
-
- def _get_tags_for_frame(self, frame):
- result = []
- for tag in self._tags:
- if tag.start_frame <= frame and tag.end_frame >= frame:
- result.append(tag)
- return result
-
- def _timeout_cb(self, end_frame):
- for tag in self._get_tags_for_frame(self._current_frame):
- cur_frame = self._current_frame - tag.start_frame
- self._next_frame(tag, cur_frame)
-
- if self._current_frame < end_frame:
- self._current_frame += 1
- return True
- else:
- return False
-
- def play(self, start_tag=None, stop_tag=None):
- self.pause()
-
- if start_tag == None:
- start = 0
- else:
- start = self._name_to_tag[start_tag].start_frame
-
- if stop_tag == None:
- end = self._tags[len(self._tags) - 1].end_frame
- else:
- end = self._name_to_tag[stop_tag].end_frame
-
- self._current_frame = start
-
- interval = 1000 / self._fps
- self._timeout_sid = gobject.timeout_add(
- interval, self._timeout_cb, end)
-
- def pause(self):
- if self._timeout_sid > 0:
- gobject.source_remove(self._timeout_sid)
+ def __init__(self, observer):
+ self._fps = 12
+ self._tags = []
+ self._name_to_tag = {}
+ self._current_frame = 0
+ self._timeout_sid = 0
+ self._observer = TimelineObserver(observer)
+
+ def add_tag(self, name, start_frame, end_frame):
+ tag = _Tag(name, start_frame, end_frame)
+ self._tags.append(tag)
+ self._name_to_tag[name] = tag
+
+ def remove_tag(self, name):
+ tag = self._tags[name]
+ self._tags.remove(tag)
+ del self._tags[name]
+
+ def _next_frame(self, tag, frame):
+ n_frames = tag.start_frame - tag.end_frame
+ self._observer.next_frame(tag.name, frame, n_frames)
+
+ def goto(self, tag_name, end_frame=False):
+ self.pause()
+
+ tag = self._name_to_tag[tag_name]
+ if end_frame:
+ self._current_frame = tag.end_frame
+ else:
+ self._current_frame = tag.start_frame
+
+ self._next_frame(tag, self._current_frame)
+
+ def on_tag(self, name):
+ tag = self._name_to_tag[name]
+ return (tag.start_frame <= self._current_frame and \
+ tag.end_frame >= self._current_frame)
+
+ def _get_tags_for_frame(self, frame):
+ result = []
+ for tag in self._tags:
+ if tag.start_frame <= frame and tag.end_frame >= frame:
+ result.append(tag)
+ return result
+
+ def _timeout_cb(self, end_frame):
+ for tag in self._get_tags_for_frame(self._current_frame):
+ cur_frame = self._current_frame - tag.start_frame
+ self._next_frame(tag, cur_frame)
+
+ if self._current_frame < end_frame:
+ self._current_frame += 1
+ return True
+ else:
+ return False
+
+ def play(self, start_tag=None, stop_tag=None):
+ self.pause()
+
+ if start_tag == None:
+ start = 0
+ else:
+ start = self._name_to_tag[start_tag].start_frame
+
+ if stop_tag == None:
+ end = self._tags[len(self._tags) - 1].end_frame
+ else:
+ end = self._name_to_tag[stop_tag].end_frame
+
+ self._current_frame = start
+
+ interval = 1000 / self._fps
+ self._timeout_sid = gobject.timeout_add(
+ interval, self._timeout_cb, end)
+
+ def pause(self):
+ if self._timeout_sid > 0:
+ gobject.source_remove(self._timeout_sid)
diff --git a/sugar/logger.py b/sugar/logger.py
index b4b2e0c..5eb8039 100644
--- a/sugar/logger.py
+++ b/sugar/logger.py
@@ -29,82 +29,82 @@ STDOUT_LEVEL = 1000
STDERR_LEVEL = 2000
class LogWriter:
- def __init__(self, module_id):
- self._module_id = module_id
-
- logs_dir = _get_logs_dir()
- log_path = os.path.join(logs_dir, module_id + '.log')
- self._log_file = open(log_path, 'w')
-
- def write_record(self, record):
- self.write(record.levelno, record.msg)
-
- def write(self, level, msg):
- if level == logging.ERROR:
- level_txt = 'ERROR'
- elif level == logging.WARNING:
- level_txt = 'WARNING'
- elif level == logging.DEBUG:
- level_txt = 'DEBUG'
- elif level == logging.INFO:
- level_txt = 'INFO'
- elif level == STDERR_LEVEL:
- level_txt = 'STDERR'
- elif level == STDOUT_LEVEL:
- level_txt = 'STDOUT'
-
- fmt = "%s - %s\n" % (level_txt, msg)
- fmt = fmt.encode("utf8")
- self._log_file.write(fmt)
- self._log_file.flush()
+ def __init__(self, module_id):
+ self._module_id = module_id
+
+ logs_dir = _get_logs_dir()
+ log_path = os.path.join(logs_dir, module_id + '.log')
+ self._log_file = open(log_path, 'w')
+
+ def write_record(self, record):
+ self.write(record.levelno, record.msg)
+
+ def write(self, level, msg):
+ if level == logging.ERROR:
+ level_txt = 'ERROR'
+ elif level == logging.WARNING:
+ level_txt = 'WARNING'
+ elif level == logging.DEBUG:
+ level_txt = 'DEBUG'
+ elif level == logging.INFO:
+ level_txt = 'INFO'
+ elif level == STDERR_LEVEL:
+ level_txt = 'STDERR'
+ elif level == STDOUT_LEVEL:
+ level_txt = 'STDOUT'
+
+ fmt = "%s - %s\n" % (level_txt, msg)
+ fmt = fmt.encode("utf8")
+ self._log_file.write(fmt)
+ self._log_file.flush()
class Handler(logging.Handler):
- def __init__(self, writer):
- logging.Handler.__init__(self)
+ def __init__(self, writer):
+ logging.Handler.__init__(self)
- self._writer = writer
+ self._writer = writer
- def emit(self, record):
- self._writer.write_record(record)
+ def emit(self, record):
+ self._writer.write_record(record)
class StdoutCatcher:
- def write(self, txt):
- _log_writer.write(STDOUT_LEVEL, txt)
- sys.__stdout__.write(txt)
+ def write(self, txt):
+ _log_writer.write(STDOUT_LEVEL, txt)
+ sys.__stdout__.write(txt)
class StderrCatcher:
- def write(self, txt):
- _log_writer.write(STDERR_LEVEL, txt)
- sys.__stderr__.write(txt)
+ def write(self, txt):
+ _log_writer.write(STDERR_LEVEL, txt)
+ sys.__stderr__.write(txt)
def __exception_handler(typ, exc, tb):
- trace = StringIO()
- traceback.print_exception(typ, exc, tb, None, trace)
- print >> sys.stderr, trace.getvalue()
+ trace = StringIO()
+ traceback.print_exception(typ, exc, tb, None, trace)
+ print >> sys.stderr, trace.getvalue()
- _log_writer.write(logging.ERROR, trace.getvalue())
+ _log_writer.write(logging.ERROR, trace.getvalue())
def _get_logs_dir():
- logs_dir = os.path.join(env.get_profile_path(), 'logs')
- if not os.path.isdir(logs_dir):
- os.makedirs(logs_dir)
- return logs_dir
+ logs_dir = os.path.join(env.get_profile_path(), 'logs')
+ if not os.path.isdir(logs_dir):
+ os.makedirs(logs_dir)
+ return logs_dir
def start(module_id):
- log_writer = LogWriter(module_id)
+ log_writer = LogWriter(module_id)
- root_logger = logging.getLogger('')
- root_logger.setLevel(logging.DEBUG)
- root_logger.addHandler(Handler(log_writer))
+ root_logger = logging.getLogger('')
+ root_logger.setLevel(logging.DEBUG)
+ root_logger.addHandler(Handler(log_writer))
- sys.stdout = StdoutCatcher()
- sys.stderr = StderrCatcher()
+ sys.stdout = StdoutCatcher()
+ sys.stderr = StderrCatcher()
- global _log_writer
- _log_writer = log_writer
- sys.excepthook = __exception_handler
+ global _log_writer
+ _log_writer = log_writer
+ sys.excepthook = __exception_handler
def cleanup():
- logs_dir = _get_logs_dir()
- for f in os.listdir(logs_dir):
- os.remove(os.path.join(logs_dir, f))
+ logs_dir = _get_logs_dir()
+ for f in os.listdir(logs_dir):
+ os.remove(os.path.join(logs_dir, f))
diff --git a/sugar/p2p/MostlyReliablePipe.py b/sugar/p2p/MostlyReliablePipe.py
index 4218181..604eada 100644
--- a/sugar/p2p/MostlyReliablePipe.py
+++ b/sugar/p2p/MostlyReliablePipe.py
@@ -32,952 +32,952 @@ import gobject
def _stringify_sha(sha_hash):
- print_sha = ""
- for char in sha_hash:
- print_sha = print_sha + binascii.b2a_hex(char)
- return print_sha
+ print_sha = ""
+ for char in sha_hash:
+ print_sha = print_sha + binascii.b2a_hex(char)
+ return print_sha
def _sha_data(data):
- sha_hash = sha.new()
- sha_hash.update(data)
- return sha_hash.digest()
+ sha_hash = sha.new()
+ sha_hash.update(data)
+ return sha_hash.digest()
_UDP_DATAGRAM_SIZE = 512
class SegmentBase(object):
- _MAGIC = 0xbaea4304
-
- # 4: magic (0xbaea4304)
- # 1: type
- # 2: segment number
- # 2: total segments
- # 2: message sequence number
- #20: total data sha1
- _HEADER_TEMPLATE = "! IbHHH20s"
- _HEADER_LEN = struct.calcsize(_HEADER_TEMPLATE)
- _MTU = _UDP_DATAGRAM_SIZE - _HEADER_LEN
-
- # Message segment packet types
- _SEGMENT_TYPE_DATA = 0
- _SEGMENT_TYPE_RETRANSMIT = 1
- _SEGMENT_TYPE_ACK = 2
-
- def magic():
- return SegmentBase._MAGIC
- magic = staticmethod(magic)
-
- def header_template():
- return SegmentBase._HEADER_TEMPLATE
- header_template = staticmethod(header_template)
-
- def type_data():
- return SegmentBase._SEGMENT_TYPE_DATA
- type_data = staticmethod(type_data)
-
- def type_retransmit():
- return SegmentBase._SEGMENT_TYPE_RETRANSMIT
- type_retransmit = staticmethod(type_retransmit)
-
- def type_ack():
- return SegmentBase._SEGMENT_TYPE_ACK
- type_ack = staticmethod(type_ack)
-
- def header_len():
- """Return the header size of SegmentBase packets."""
- return SegmentBase._HEADER_LEN
- header_len = staticmethod(header_len)
-
- def mtu():
- """Return the SegmentBase packet MTU."""
- return SegmentBase._MTU
- mtu = staticmethod(mtu)
-
- def __init__(self, segno, total_segs, msg_seq_num, master_sha):
- self._type = None
- self._transmits = 0
- self._last_transmit = 0
- self._data = None
- self._data_len = 0
- self.userdata = None
- self._stime = time.time()
- self._addr = None
-
- # Sanity checks on the message attributes
- if not segno or not isinstance(segno, int):
- raise ValueError("Segment number must be in integer.")
- if segno < 1 or segno > 65535:
- raise ValueError("Segment number must be between 1 and 65535 inclusive.")
- if not total_segs or not isinstance(total_segs, int):
- raise ValueError("Message segment total must be an integer.")
- if total_segs < 1 or total_segs > 65535:
- raise ValueError("Message must have between 1 and 65535 segments inclusive.")
- if segno > total_segs:
- raise ValueError("Segment number cannot be larger than message segment total.")
- if not msg_seq_num or not isinstance(msg_seq_num, int):
- raise ValueError("Message sequnce number must be an integer.")
- if msg_seq_num < 1 or msg_seq_num > 65535:
- raise ValueError("Message sequence number must be between 1 and 65535 inclusive.")
- if not master_sha or not isinstance(master_sha, str) or len(master_sha) != 20:
- raise ValueError("Message SHA1 checksum invalid.")
-
- self._segno = segno
- self._total_segs = total_segs
- self._msg_seq_num = msg_seq_num
- self._master_sha = master_sha
-
- def _validate_address(addr):
- if not addr or not isinstance(addr, tuple):
- raise ValueError("Address must be a tuple.")
- if len(addr) != 2 or not isinstance(addr[0], str) or not isinstance(addr[1], int):
- raise ValueError("Address format was invalid.")
- if addr[1] < 1 or addr[1] > 65535:
- raise ValueError("Address port was invalid.")
- _validate_address = staticmethod(_validate_address)
-
- def new_from_data(addr, data):
- """Static constructor for creation from a packed data stream."""
- SegmentBase._validate_address(addr)
-
- # Verify minimum length
- if not data:
- raise ValueError("Segment data is invalid.")
- data_len = len(data)
- if data_len < SegmentBase.header_len() + 1:
- raise ValueError("Segment is less then minimum required length")
- if data_len > _UDP_DATAGRAM_SIZE:
- raise ValueError("Segment data is larger than allowed.")
- stream = StringIO.StringIO(data)
-
- # Determine and verify the length of included data
- stream.seek(0, 2)
- data_len = stream.tell() - SegmentBase._HEADER_LEN
- stream.seek(0)
-
- if data_len < 1:
- raise ValueError("Segment must have some data.")
- if data_len > SegmentBase._MTU:
- raise ValueError("Data length must not be larger than the MTU (%s)." % SegmentBase._MTU)
-
- # Read the first header attributes
- (magic, seg_type, segno, total_segs, msg_seq_num, master_sha) = struct.unpack(SegmentBase._HEADER_TEMPLATE,
- stream.read(SegmentBase._HEADER_LEN))
-
- # Sanity checks on the message attributes
- if magic != SegmentBase._MAGIC:
- raise ValueError("Segment does not have the correct magic.")
-
- # if the segment is the only one in the message, validate the data
- if segno == 1 and total_segs == 1:
- data_sha = _sha_data(stream.read(data_len))
- if data_sha != master_sha:
- raise ValueError("Single segment message SHA checksums didn't match.")
- stream.seek(SegmentBase._HEADER_LEN)
-
- if seg_type == SegmentBase._SEGMENT_TYPE_DATA:
- segment = DataSegment(segno, total_segs, msg_seq_num, master_sha)
- elif seg_type == SegmentBase._SEGMENT_TYPE_RETRANSMIT:
- segment = RetransmitSegment(segno, total_segs, msg_seq_num, master_sha)
- elif seg_type == SegmentBase._SEGMENT_TYPE_ACK:
- segment = AckSegment(segno, total_segs, msg_seq_num, master_sha)
- else:
- raise ValueError("Segment has invalid type.")
-
- # Segment specific data interpretation
- segment._addr = addr
- segment._unpack_data(stream, data_len)
-
- return segment
- new_from_data = staticmethod(new_from_data)
-
- def stime(self):
- return self._stime
-
- def address(self):
- return self._addr
-
- def segment_number(self):
- return self._segno
-
- def total_segments(self):
- return self._total_segs
-
- def message_sequence_number(self):
- return self._msg_seq_num
-
- def data(self):
- return self._data
-
- def master_sha(self):
- return self._master_sha
-
- def segment_type(self):
- return self._type
-
- def packetize(self):
- """Return a correctly formatted message that can be immediately sent."""
- header = struct.pack(self._HEADER_TEMPLATE, self._MAGIC, self._type,
- self._segno, self._total_segs, self._msg_seq_num, self._master_sha)
- return header + self._data
-
- def transmits(self):
- return self._transmits
-
- def inc_transmits(self):
- self._transmits = self._transmits + 1
- self._last_transmit = time.time()
-
- def last_transmit(self):
- return self._last_transmit
+ _MAGIC = 0xbaea4304
+
+ # 4: magic (0xbaea4304)
+ # 1: type
+ # 2: segment number
+ # 2: total segments
+ # 2: message sequence number
+ #20: total data sha1
+ _HEADER_TEMPLATE = "! IbHHH20s"
+ _HEADER_LEN = struct.calcsize(_HEADER_TEMPLATE)
+ _MTU = _UDP_DATAGRAM_SIZE - _HEADER_LEN
+
+ # Message segment packet types
+ _SEGMENT_TYPE_DATA = 0
+ _SEGMENT_TYPE_RETRANSMIT = 1
+ _SEGMENT_TYPE_ACK = 2
+
+ def magic():
+ return SegmentBase._MAGIC
+ magic = staticmethod(magic)
+
+ def header_template():
+ return SegmentBase._HEADER_TEMPLATE
+ header_template = staticmethod(header_template)
+
+ def type_data():
+ return SegmentBase._SEGMENT_TYPE_DATA
+ type_data = staticmethod(type_data)
+
+ def type_retransmit():
+ return SegmentBase._SEGMENT_TYPE_RETRANSMIT
+ type_retransmit = staticmethod(type_retransmit)
+
+ def type_ack():
+ return SegmentBase._SEGMENT_TYPE_ACK
+ type_ack = staticmethod(type_ack)
+
+ def header_len():
+ """Return the header size of SegmentBase packets."""
+ return SegmentBase._HEADER_LEN
+ header_len = staticmethod(header_len)
+
+ def mtu():
+ """Return the SegmentBase packet MTU."""
+ return SegmentBase._MTU
+ mtu = staticmethod(mtu)
+
+ def __init__(self, segno, total_segs, msg_seq_num, master_sha):
+ self._type = None
+ self._transmits = 0
+ self._last_transmit = 0
+ self._data = None
+ self._data_len = 0
+ self.userdata = None
+ self._stime = time.time()
+ self._addr = None
+
+ # Sanity checks on the message attributes
+ if not segno or not isinstance(segno, int):
+ raise ValueError("Segment number must be in integer.")
+ if segno < 1 or segno > 65535:
+ raise ValueError("Segment number must be between 1 and 65535 inclusive.")
+ if not total_segs or not isinstance(total_segs, int):
+ raise ValueError("Message segment total must be an integer.")
+ if total_segs < 1 or total_segs > 65535:
+ raise ValueError("Message must have between 1 and 65535 segments inclusive.")
+ if segno > total_segs:
+ raise ValueError("Segment number cannot be larger than message segment total.")
+ if not msg_seq_num or not isinstance(msg_seq_num, int):
+ raise ValueError("Message sequnce number must be an integer.")
+ if msg_seq_num < 1 or msg_seq_num > 65535:
+ raise ValueError("Message sequence number must be between 1 and 65535 inclusive.")
+ if not master_sha or not isinstance(master_sha, str) or len(master_sha) != 20:
+ raise ValueError("Message SHA1 checksum invalid.")
+
+ self._segno = segno
+ self._total_segs = total_segs
+ self._msg_seq_num = msg_seq_num
+ self._master_sha = master_sha
+
+ def _validate_address(addr):
+ if not addr or not isinstance(addr, tuple):
+ raise ValueError("Address must be a tuple.")
+ if len(addr) != 2 or not isinstance(addr[0], str) or not isinstance(addr[1], int):
+ raise ValueError("Address format was invalid.")
+ if addr[1] < 1 or addr[1] > 65535:
+ raise ValueError("Address port was invalid.")
+ _validate_address = staticmethod(_validate_address)
+
+ def new_from_data(addr, data):
+ """Static constructor for creation from a packed data stream."""
+ SegmentBase._validate_address(addr)
+
+ # Verify minimum length
+ if not data:
+ raise ValueError("Segment data is invalid.")
+ data_len = len(data)
+ if data_len < SegmentBase.header_len() + 1:
+ raise ValueError("Segment is less then minimum required length")
+ if data_len > _UDP_DATAGRAM_SIZE:
+ raise ValueError("Segment data is larger than allowed.")
+ stream = StringIO.StringIO(data)
+
+ # Determine and verify the length of included data
+ stream.seek(0, 2)
+ data_len = stream.tell() - SegmentBase._HEADER_LEN
+ stream.seek(0)
+
+ if data_len < 1:
+ raise ValueError("Segment must have some data.")
+ if data_len > SegmentBase._MTU:
+ raise ValueError("Data length must not be larger than the MTU (%s)." % SegmentBase._MTU)
+
+ # Read the first header attributes
+ (magic, seg_type, segno, total_segs, msg_seq_num, master_sha) = struct.unpack(SegmentBase._HEADER_TEMPLATE,
+ stream.read(SegmentBase._HEADER_LEN))
+
+ # Sanity checks on the message attributes
+ if magic != SegmentBase._MAGIC:
+ raise ValueError("Segment does not have the correct magic.")
+
+ # if the segment is the only one in the message, validate the data
+ if segno == 1 and total_segs == 1:
+ data_sha = _sha_data(stream.read(data_len))
+ if data_sha != master_sha:
+ raise ValueError("Single segment message SHA checksums didn't match.")
+ stream.seek(SegmentBase._HEADER_LEN)
+
+ if seg_type == SegmentBase._SEGMENT_TYPE_DATA:
+ segment = DataSegment(segno, total_segs, msg_seq_num, master_sha)
+ elif seg_type == SegmentBase._SEGMENT_TYPE_RETRANSMIT:
+ segment = RetransmitSegment(segno, total_segs, msg_seq_num, master_sha)
+ elif seg_type == SegmentBase._SEGMENT_TYPE_ACK:
+ segment = AckSegment(segno, total_segs, msg_seq_num, master_sha)
+ else:
+ raise ValueError("Segment has invalid type.")
+
+ # Segment specific data interpretation
+ segment._addr = addr
+ segment._unpack_data(stream, data_len)
+
+ return segment
+ new_from_data = staticmethod(new_from_data)
+
+ def stime(self):
+ return self._stime
+
+ def address(self):
+ return self._addr
+
+ def segment_number(self):
+ return self._segno
+
+ def total_segments(self):
+ return self._total_segs
+
+ def message_sequence_number(self):
+ return self._msg_seq_num
+
+ def data(self):
+ return self._data
+
+ def master_sha(self):
+ return self._master_sha
+
+ def segment_type(self):
+ return self._type
+
+ def packetize(self):
+ """Return a correctly formatted message that can be immediately sent."""
+ header = struct.pack(self._HEADER_TEMPLATE, self._MAGIC, self._type,
+ self._segno, self._total_segs, self._msg_seq_num, self._master_sha)
+ return header + self._data
+
+ def transmits(self):
+ return self._transmits
+
+ def inc_transmits(self):
+ self._transmits = self._transmits + 1
+ self._last_transmit = time.time()
+
+ def last_transmit(self):
+ return self._last_transmit
class DataSegment(SegmentBase):
- """A message segment that encapsulates random data."""
-
- def __init__(self, segno, total_segs, msg_seq_num, master_sha):
- SegmentBase.__init__(self, segno, total_segs, msg_seq_num, master_sha)
- self._type = SegmentBase._SEGMENT_TYPE_DATA
-
- def _get_template_for_len(length):
- return "! %ds" % length
- _get_template_for_len = staticmethod(_get_template_for_len)
-
- def _unpack_data(self, stream, data_len):
- """Unpack the data stream, called by constructor."""
- self._data_len = data_len
- template = DataSegment._get_template_for_len(self._data_len)
- self._data = struct.unpack(template, stream.read(self._data_len))[0]
-
- def new_from_parts(segno, total_segs, msg_seq_num, master_sha, data):
- """Construct a new message segment from individual attributes."""
- if not data:
- raise ValueError("Must have valid data.")
- segment = DataSegment(segno, total_segs, msg_seq_num, master_sha)
- segment._data_len = len(data)
- template = DataSegment._get_template_for_len(segment._data_len)
- segment._data = struct.pack(template, data)
- return segment
- new_from_parts = staticmethod(new_from_parts)
+ """A message segment that encapsulates random data."""
+
+ def __init__(self, segno, total_segs, msg_seq_num, master_sha):
+ SegmentBase.__init__(self, segno, total_segs, msg_seq_num, master_sha)
+ self._type = SegmentBase._SEGMENT_TYPE_DATA
+
+ def _get_template_for_len(length):
+ return "! %ds" % length
+ _get_template_for_len = staticmethod(_get_template_for_len)
+
+ def _unpack_data(self, stream, data_len):
+ """Unpack the data stream, called by constructor."""
+ self._data_len = data_len
+ template = DataSegment._get_template_for_len(self._data_len)
+ self._data = struct.unpack(template, stream.read(self._data_len))[0]
+
+ def new_from_parts(segno, total_segs, msg_seq_num, master_sha, data):
+ """Construct a new message segment from individual attributes."""
+ if not data:
+ raise ValueError("Must have valid data.")
+ segment = DataSegment(segno, total_segs, msg_seq_num, master_sha)
+ segment._data_len = len(data)
+ template = DataSegment._get_template_for_len(segment._data_len)
+ segment._data = struct.pack(template, data)
+ return segment
+ new_from_parts = staticmethod(new_from_parts)
class RetransmitSegment(SegmentBase):
- """A message segment that encapsulates a retransmission request."""
-
- # Retransmission data format:
- # 2: message sequence number
- # 20: total data sha1
- # 2: segment number
- _RT_DATA_TEMPLATE = "! H20sH"
- _RT_DATA_LEN = struct.calcsize(_RT_DATA_TEMPLATE)
-
- def data_template():
- return RetransmitSegment._RT_DATA_TEMPLATE
- data_template = staticmethod(data_template)
-
- def __init__(self, segno, total_segs, msg_seq_num, master_sha):
- """Should not be called directly."""
- if segno != 1 or total_segs != 1:
- raise ValueError("Retransmission request messages must have only one segment.")
-
- SegmentBase.__init__(self, segno, total_segs, msg_seq_num, master_sha)
- self._type = SegmentBase._SEGMENT_TYPE_RETRANSMIT
-
- def _verify_data(rt_msg_seq_num, rt_master_sha, rt_segment_number):
- # Sanity checks on the message attributes
- if not rt_segment_number or not isinstance(rt_segment_number, int):
- raise ValueError("RT Segment number must be in integer.")
- if rt_segment_number < 1 or rt_segment_number > 65535:
- raise ValueError("RT Segment number must be between 1 and 65535 inclusive.")
- if not rt_msg_seq_num or not isinstance(rt_msg_seq_num, int):
- raise ValueError("RT Message sequnce number must be an integer.")
- if rt_msg_seq_num < 1 or rt_msg_seq_num > 65535:
- raise ValueError("RT Message sequence number must be between 1 and 65535 inclusive.")
- if not rt_master_sha or not isinstance(rt_master_sha, str) or len(rt_master_sha) != 20:
- raise ValueError("RT Message SHA1 checksum invalid.")
- _verify_data = staticmethod(_verify_data)
-
- def _make_rtms_data(rt_msg_seq_num, rt_master_sha, rt_segment_number):
- """Pack retransmission request payload."""
- data = struct.pack(RetransmitSegment._RT_DATA_TEMPLATE, rt_msg_seq_num,
- rt_master_sha, rt_segment_number)
- return (data, _sha_data(data))
- _make_rtms_data = staticmethod(_make_rtms_data)
-
- def new_from_parts(addr, msg_seq_num, rt_msg_seq_num, rt_master_sha, rt_segment_number):
- """Static constructor for creation from individual attributes."""
-
- RetransmitSegment._verify_data(rt_msg_seq_num, rt_master_sha, rt_segment_number)
- (data, data_sha) = RetransmitSegment._make_rtms_data(rt_msg_seq_num,
- rt_master_sha, rt_segment_number)
- segment = RetransmitSegment(1, 1, msg_seq_num, data_sha)
- segment._data_len = RetransmitSegment._RT_DATA_LEN
- segment._data = data
- SegmentBase._validate_address(addr)
- segment._addr = addr
-
- segment._rt_msg_seq_num = rt_msg_seq_num
- segment._rt_master_sha = rt_master_sha
- segment._rt_segment_number = rt_segment_number
- return segment
- new_from_parts = staticmethod(new_from_parts)
-
- def _unpack_data(self, stream, data_len):
- if data_len != self._RT_DATA_LEN:
- raise ValueError("Retransmission request data had invalid length.")
- data = stream.read(data_len)
- (rt_msg_seq_num, rt_master_sha, rt_seg_no) = struct.unpack(self._RT_DATA_TEMPLATE, data)
- RetransmitSegment._verify_data(rt_msg_seq_num, rt_master_sha, rt_seg_no)
-
- self._data = data
- self._data_len = data_len
- self._rt_msg_seq_num = rt_msg_seq_num
- self._rt_master_sha = rt_master_sha
- self._rt_segment_number = rt_seg_no
-
- def rt_msg_seq_num(self):
- return self._rt_msg_seq_num
-
- def rt_master_sha(self):
- return self._rt_master_sha
-
- def rt_segment_number(self):
- return self._rt_segment_number
+ """A message segment that encapsulates a retransmission request."""
+
+ # Retransmission data format:
+ # 2: message sequence number
+ # 20: total data sha1
+ # 2: segment number
+ _RT_DATA_TEMPLATE = "! H20sH"
+ _RT_DATA_LEN = struct.calcsize(_RT_DATA_TEMPLATE)
+
+ def data_template():
+ return RetransmitSegment._RT_DATA_TEMPLATE
+ data_template = staticmethod(data_template)
+
+ def __init__(self, segno, total_segs, msg_seq_num, master_sha):
+ """Should not be called directly."""
+ if segno != 1 or total_segs != 1:
+ raise ValueError("Retransmission request messages must have only one segment.")
+
+ SegmentBase.__init__(self, segno, total_segs, msg_seq_num, master_sha)
+ self._type = SegmentBase._SEGMENT_TYPE_RETRANSMIT
+
+ def _verify_data(rt_msg_seq_num, rt_master_sha, rt_segment_number):
+ # Sanity checks on the message attributes
+ if not rt_segment_number or not isinstance(rt_segment_number, int):
+ raise ValueError("RT Segment number must be in integer.")
+ if rt_segment_number < 1 or rt_segment_number > 65535:
+ raise ValueError("RT Segment number must be between 1 and 65535 inclusive.")
+ if not rt_msg_seq_num or not isinstance(rt_msg_seq_num, int):
+ raise ValueError("RT Message sequnce number must be an integer.")
+ if rt_msg_seq_num < 1 or rt_msg_seq_num > 65535:
+ raise ValueError("RT Message sequence number must be between 1 and 65535 inclusive.")
+ if not rt_master_sha or not isinstance(rt_master_sha, str) or len(rt_master_sha) != 20:
+ raise ValueError("RT Message SHA1 checksum invalid.")
+ _verify_data = staticmethod(_verify_data)
+
+ def _make_rtms_data(rt_msg_seq_num, rt_master_sha, rt_segment_number):
+ """Pack retransmission request payload."""
+ data = struct.pack(RetransmitSegment._RT_DATA_TEMPLATE, rt_msg_seq_num,
+ rt_master_sha, rt_segment_number)
+ return (data, _sha_data(data))
+ _make_rtms_data = staticmethod(_make_rtms_data)
+
+ def new_from_parts(addr, msg_seq_num, rt_msg_seq_num, rt_master_sha, rt_segment_number):
+ """Static constructor for creation from individual attributes."""
+
+ RetransmitSegment._verify_data(rt_msg_seq_num, rt_master_sha, rt_segment_number)
+ (data, data_sha) = RetransmitSegment._make_rtms_data(rt_msg_seq_num,
+ rt_master_sha, rt_segment_number)
+ segment = RetransmitSegment(1, 1, msg_seq_num, data_sha)
+ segment._data_len = RetransmitSegment._RT_DATA_LEN
+ segment._data = data
+ SegmentBase._validate_address(addr)
+ segment._addr = addr
+
+ segment._rt_msg_seq_num = rt_msg_seq_num
+ segment._rt_master_sha = rt_master_sha
+ segment._rt_segment_number = rt_segment_number
+ return segment
+ new_from_parts = staticmethod(new_from_parts)
+
+ def _unpack_data(self, stream, data_len):
+ if data_len != self._RT_DATA_LEN:
+ raise ValueError("Retransmission request data had invalid length.")
+ data = stream.read(data_len)
+ (rt_msg_seq_num, rt_master_sha, rt_seg_no) = struct.unpack(self._RT_DATA_TEMPLATE, data)
+ RetransmitSegment._verify_data(rt_msg_seq_num, rt_master_sha, rt_seg_no)
+
+ self._data = data
+ self._data_len = data_len
+ self._rt_msg_seq_num = rt_msg_seq_num
+ self._rt_master_sha = rt_master_sha
+ self._rt_segment_number = rt_seg_no
+
+ def rt_msg_seq_num(self):
+ return self._rt_msg_seq_num
+
+ def rt_master_sha(self):
+ return self._rt_master_sha
+
+ def rt_segment_number(self):
+ return self._rt_segment_number
class AckSegment(SegmentBase):
- """A message segment that encapsulates a message acknowledgement."""
-
- # Ack data format:
- # 2: acked message sequence number
- # 20: acked message total data sha1
- # 4: acked message source IP address
- _ACK_DATA_TEMPLATE = "! H20s4s"
- _ACK_DATA_LEN = struct.calcsize(_ACK_DATA_TEMPLATE)
-
- def data_template():
- return AckSegment._ACK_DATA_TEMPLATE
- data_template = staticmethod(data_template)
-
- def __init__(self, segno, total_segs, msg_seq_num, master_sha):
- """Should not be called directly."""
- if segno != 1 or total_segs != 1:
- raise ValueError("Acknowledgement messages must have only one segment.")
-
- SegmentBase.__init__(self, segno, total_segs, msg_seq_num, master_sha)
- self._type = SegmentBase._SEGMENT_TYPE_ACK
-
- def _verify_data(ack_msg_seq_num, ack_master_sha, ack_addr):
- # Sanity checks on the message attributes
- if not ack_msg_seq_num or not isinstance(ack_msg_seq_num, int):
- raise ValueError("Ack message sequnce number must be an integer.")
- if ack_msg_seq_num < 1 or ack_msg_seq_num > 65535:
- raise ValueError("Ack message sequence number must be between 1 and 65535 inclusive.")
- if not ack_master_sha or not isinstance(ack_master_sha, str) or len(ack_master_sha) != 20:
- raise ValueError("Ack message SHA1 checksum invalid.")
- if not isinstance(ack_addr, str):
- raise ValueError("Ack message invalid address type.")
- try:
- foo = socket.inet_aton(ack_addr)
- except socket.error:
- raise ValueError("Ack message invalid address.")
- _verify_data = staticmethod(_verify_data)
-
- def _make_ack_data(ack_msg_seq_num, ack_master_sha, ack_addr):
- """Pack an ack payload."""
- addr_data = socket.inet_aton(ack_addr)
- data = struct.pack(AckSegment._ACK_DATA_TEMPLATE, ack_msg_seq_num,
- ack_master_sha, addr_data)
- return (data, _sha_data(data))
- _make_ack_data = staticmethod(_make_ack_data)
-
- def new_from_parts(addr, msg_seq_num, ack_msg_seq_num, ack_master_sha, ack_addr):
- """Static constructor for creation from individual attributes."""
-
- AckSegment._verify_data(ack_msg_seq_num, ack_master_sha, ack_addr)
- (data, data_sha) = AckSegment._make_ack_data(ack_msg_seq_num,
- ack_master_sha, ack_addr)
- segment = AckSegment(1, 1, msg_seq_num, data_sha)
- segment._data_len = AckSegment._ACK_DATA_LEN
- segment._data = data
- SegmentBase._validate_address(addr)
- segment._addr = addr
-
- segment._ack_msg_seq_num = ack_msg_seq_num
- segment._ack_master_sha = ack_master_sha
- segment._ack_addr = ack_addr
- return segment
- new_from_parts = staticmethod(new_from_parts)
-
- def _unpack_data(self, stream, data_len):
- if data_len != self._ACK_DATA_LEN:
- raise ValueError("Ack segment data had invalid length.")
- data = stream.read(data_len)
- (ack_msg_seq_num, ack_master_sha, ack_addr_data) = struct.unpack(self._ACK_DATA_TEMPLATE, data)
- try:
- ack_addr = socket.inet_ntoa(ack_addr_data)
- except socket.error:
- raise ValueError("Ack segment data had invalid address.")
- AckSegment._verify_data(ack_msg_seq_num, ack_master_sha, ack_addr)
-
- self._data = data
- self._data_len = data_len
- self._ack_msg_seq_num = ack_msg_seq_num
- self._ack_master_sha = ack_master_sha
- self._ack_addr = ack_addr
-
- def ack_msg_seq_num(self):
- return self._ack_msg_seq_num
-
- def ack_master_sha(self):
- return self._ack_master_sha
-
- def ack_addr(self):
- return self._ack_addr
+ """A message segment that encapsulates a message acknowledgement."""
+
+ # Ack data format:
+ # 2: acked message sequence number
+ # 20: acked message total data sha1
+ # 4: acked message source IP address
+ _ACK_DATA_TEMPLATE = "! H20s4s"
+ _ACK_DATA_LEN = struct.calcsize(_ACK_DATA_TEMPLATE)
+
+ def data_template():
+ return AckSegment._ACK_DATA_TEMPLATE
+ data_template = staticmethod(data_template)
+
+ def __init__(self, segno, total_segs, msg_seq_num, master_sha):
+ """Should not be called directly."""
+ if segno != 1 or total_segs != 1:
+ raise ValueError("Acknowledgement messages must have only one segment.")
+
+ SegmentBase.__init__(self, segno, total_segs, msg_seq_num, master_sha)
+ self._type = SegmentBase._SEGMENT_TYPE_ACK
+
+ def _verify_data(ack_msg_seq_num, ack_master_sha, ack_addr):
+ # Sanity checks on the message attributes
+ if not ack_msg_seq_num or not isinstance(ack_msg_seq_num, int):
+ raise ValueError("Ack message sequnce number must be an integer.")
+ if ack_msg_seq_num < 1 or ack_msg_seq_num > 65535:
+ raise ValueError("Ack message sequence number must be between 1 and 65535 inclusive.")
+ if not ack_master_sha or not isinstance(ack_master_sha, str) or len(ack_master_sha) != 20:
+ raise ValueError("Ack message SHA1 checksum invalid.")
+ if not isinstance(ack_addr, str):
+ raise ValueError("Ack message invalid address type.")
+ try:
+ foo = socket.inet_aton(ack_addr)
+ except socket.error:
+ raise ValueError("Ack message invalid address.")
+ _verify_data = staticmethod(_verify_data)
+
+ def _make_ack_data(ack_msg_seq_num, ack_master_sha, ack_addr):
+ """Pack an ack payload."""
+ addr_data = socket.inet_aton(ack_addr)
+ data = struct.pack(AckSegment._ACK_DATA_TEMPLATE, ack_msg_seq_num,
+ ack_master_sha, addr_data)
+ return (data, _sha_data(data))
+ _make_ack_data = staticmethod(_make_ack_data)
+
+ def new_from_parts(addr, msg_seq_num, ack_msg_seq_num, ack_master_sha, ack_addr):
+ """Static constructor for creation from individual attributes."""
+
+ AckSegment._verify_data(ack_msg_seq_num, ack_master_sha, ack_addr)
+ (data, data_sha) = AckSegment._make_ack_data(ack_msg_seq_num,
+ ack_master_sha, ack_addr)
+ segment = AckSegment(1, 1, msg_seq_num, data_sha)
+ segment._data_len = AckSegment._ACK_DATA_LEN
+ segment._data = data
+ SegmentBase._validate_address(addr)
+ segment._addr = addr
+
+ segment._ack_msg_seq_num = ack_msg_seq_num
+ segment._ack_master_sha = ack_master_sha
+ segment._ack_addr = ack_addr
+ return segment
+ new_from_parts = staticmethod(new_from_parts)
+
+ def _unpack_data(self, stream, data_len):
+ if data_len != self._ACK_DATA_LEN:
+ raise ValueError("Ack segment data had invalid length.")
+ data = stream.read(data_len)
+ (ack_msg_seq_num, ack_master_sha, ack_addr_data) = struct.unpack(self._ACK_DATA_TEMPLATE, data)
+ try:
+ ack_addr = socket.inet_ntoa(ack_addr_data)
+ except socket.error:
+ raise ValueError("Ack segment data had invalid address.")
+ AckSegment._verify_data(ack_msg_seq_num, ack_master_sha, ack_addr)
+
+ self._data = data
+ self._data_len = data_len
+ self._ack_msg_seq_num = ack_msg_seq_num
+ self._ack_master_sha = ack_master_sha
+ self._ack_addr = ack_addr
+
+ def ack_msg_seq_num(self):
+ return self._ack_msg_seq_num
+
+ def ack_master_sha(self):
+ return self._ack_master_sha
+
+ def ack_addr(self):
+ return self._ack_addr
class Message(object):
- """Tracks an entire message object, which is composed of a number
- of individual segments."""
- def __init__(self, src_addr, msg_seq_num, msg_sha, total_segments):
- self._rt_target = 0
- self._next_rt_time = 0
- self._last_incoming_time = 0
- self._segments = {}
- self._complete = False
- self._dispatched_time = 0
- self._data = None
- self._data_sha = None
- self._src_addr = src_addr
- self._msg_seq_num = msg_seq_num
- self._msg_sha = msg_sha
- self._total_segments = total_segments
- self._rt_tries = {}
- for i in range(1, self._total_segments + 1):
- self._rt_tries[i] = 0
-
- def __del__(self):
- self.clear()
-
- def sha(self):
- return self._msg_sha
-
- def source_address(self):
- return self._src_addr
-
- def clear(self):
- for key in self._segments.keys()[:]:
- del self._segments[key]
- del self._rt_tries[key]
- self._segments = {}
- self._rt_tries = {}
-
- def has_segment(self, segno):
- return self._segments.has_key(segno)
-
- def first_missing(self):
- for i in range(1, self._total_segments + 1):
- if not self._segments.has_key(i):
- return i
- return 0
-
- _DEF_RT_REQUEST_INTERVAL = 0.09 # 70ms (in seconds)
- def update_rt_wait(self, now):
- """now argument should be in seconds."""
- wait = self._DEF_RT_REQUEST_INTERVAL
- if self._last_incoming_time > now - 0.02:
- msg_completeness = float(len(self._segments)) / float(self._total_segments)
- wait = wait + (self._DEF_RT_REQUEST_INTERVAL * (1.0 - msg_completeness))
- self._next_rt_time = now + wait
-
- def add_segment(self, segment):
- if self.complete():
- return
- segno = segment.segment_number()
- if self._segments.has_key(segno):
- return
- self._segments[segno] = segment
- self._rt_tries[segno] = 0
- now = time.time()
- self._last_incoming_time = now
-
- num_segs = len(self._segments)
- if num_segs == self._total_segments:
- self._complete = True
- self._next_rt_time = 0
- self._data = ''
- for seg in self._segments.values():
- self._data = self._data + seg.data()
- self._data_sha = _sha_data(self._data)
- elif segno == num_segs or num_segs == 1:
- # If we're not missing segments, push back retransmit request
- self.update_rt_wait(now)
-
- def get_retransmit_message(self, msg_seq_num, segno):
- if segno < 1 or segno > self._total_segments:
- return None
- seg = RetransmitSegment.new_from_parts(self._src_addr, msg_seq_num,
- self._msg_seq_num, self._msg_sha, segno)
- self._rt_tries[segno] = self._rt_tries[segno] + 1
- self.update_rt_wait(time.time())
- return seg
-
- def complete(self):
- return self._complete
-
- def dispatch_time(self):
- return self._dispatch_time
-
- def set_dispatch_time(self):
- self._dispatch_time = time.time()
-
- def data(self):
- return (self._data, self._data_sha)
-
- def last_incoming_time(self):
- return self._last_incoming_time
-
- def next_rt_time(self):
- return self._next_rt_time
-
- def rt_tries(self, segno):
- if self._rt_tries.has_key(segno):
- return self._rt_tries[segno]
- return 0
+ """Tracks an entire message object, which is composed of a number
+ of individual segments."""
+ def __init__(self, src_addr, msg_seq_num, msg_sha, total_segments):
+ self._rt_target = 0
+ self._next_rt_time = 0
+ self._last_incoming_time = 0
+ self._segments = {}
+ self._complete = False
+ self._dispatched_time = 0
+ self._data = None
+ self._data_sha = None
+ self._src_addr = src_addr
+ self._msg_seq_num = msg_seq_num
+ self._msg_sha = msg_sha
+ self._total_segments = total_segments
+ self._rt_tries = {}
+ for i in range(1, self._total_segments + 1):
+ self._rt_tries[i] = 0
+
+ def __del__(self):
+ self.clear()
+
+ def sha(self):
+ return self._msg_sha
+
+ def source_address(self):
+ return self._src_addr
+
+ def clear(self):
+ for key in self._segments.keys()[:]:
+ del self._segments[key]
+ del self._rt_tries[key]
+ self._segments = {}
+ self._rt_tries = {}
+
+ def has_segment(self, segno):
+ return self._segments.has_key(segno)
+
+ def first_missing(self):
+ for i in range(1, self._total_segments + 1):
+ if not self._segments.has_key(i):
+ return i
+ return 0
+
+ _DEF_RT_REQUEST_INTERVAL = 0.09 # 70ms (in seconds)
+ def update_rt_wait(self, now):
+ """now argument should be in seconds."""
+ wait = self._DEF_RT_REQUEST_INTERVAL
+ if self._last_incoming_time > now - 0.02:
+ msg_completeness = float(len(self._segments)) / float(self._total_segments)
+ wait = wait + (self._DEF_RT_REQUEST_INTERVAL * (1.0 - msg_completeness))
+ self._next_rt_time = now + wait
+
+ def add_segment(self, segment):
+ if self.complete():
+ return
+ segno = segment.segment_number()
+ if self._segments.has_key(segno):
+ return
+ self._segments[segno] = segment
+ self._rt_tries[segno] = 0
+ now = time.time()
+ self._last_incoming_time = now
+
+ num_segs = len(self._segments)
+ if num_segs == self._total_segments:
+ self._complete = True
+ self._next_rt_time = 0
+ self._data = ''
+ for seg in self._segments.values():
+ self._data = self._data + seg.data()
+ self._data_sha = _sha_data(self._data)
+ elif segno == num_segs or num_segs == 1:
+ # If we're not missing segments, push back retransmit request
+ self.update_rt_wait(now)
+
+ def get_retransmit_message(self, msg_seq_num, segno):
+ if segno < 1 or segno > self._total_segments:
+ return None
+ seg = RetransmitSegment.new_from_parts(self._src_addr, msg_seq_num,
+ self._msg_seq_num, self._msg_sha, segno)
+ self._rt_tries[segno] = self._rt_tries[segno] + 1
+ self.update_rt_wait(time.time())
+ return seg
+
+ def complete(self):
+ return self._complete
+
+ def dispatch_time(self):
+ return self._dispatch_time
+
+ def set_dispatch_time(self):
+ self._dispatch_time = time.time()
+
+ def data(self):
+ return (self._data, self._data_sha)
+
+ def last_incoming_time(self):
+ return self._last_incoming_time
+
+ def next_rt_time(self):
+ return self._next_rt_time
+
+ def rt_tries(self, segno):
+ if self._rt_tries.has_key(segno):
+ return self._rt_tries[segno]
+ return 0
def _get_local_interfaces():
- import array
- import struct
- import fcntl
- import socket
+ import array
+ import struct
+ import fcntl
+ import socket
- max_possible = 4
- bytes = max_possible * 32
- SIOCGIFCONF = 0x8912
- names = array.array('B', '\0' * bytes)
+ max_possible = 4
+ bytes = max_possible * 32
+ SIOCGIFCONF = 0x8912
+ names = array.array('B', '\0' * bytes)
- sockfd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- ifreq = struct.pack('iL', bytes, names.buffer_info()[0])
- result = fcntl.ioctl(sockfd.fileno(), SIOCGIFCONF, ifreq)
- sockfd.close()
+ sockfd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ ifreq = struct.pack('iL', bytes, names.buffer_info()[0])
+ result = fcntl.ioctl(sockfd.fileno(), SIOCGIFCONF, ifreq)
+ sockfd.close()
- outbytes = struct.unpack('iL', result)[0]
- namestr = names.tostring()
+ outbytes = struct.unpack('iL', result)[0]
+ namestr = names.tostring()
- return [namestr[i:i+32].split('\0', 1)[0] for i in range(0, outbytes, 32)]
+ return [namestr[i:i+32].split('\0', 1)[0] for i in range(0, outbytes, 32)]
def _get_local_ip_addresses():
- """Call Linux specific bits to retrieve our own IP address."""
- import socket
- import sys
- import fcntl
- import struct
-
- intfs = _get_local_interfaces()
-
- ips = []
- SIOCGIFADDR = 0x8915
- sockfd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- for intf in intfs:
- if intf == "lo":
- continue
- try:
- ifreq = (intf + '\0'*32)[:32]
- result = fcntl.ioctl(sockfd.fileno(), SIOCGIFADDR, ifreq)
- addr = socket.inet_ntoa(result[20:24])
- ips.append(addr)
- except IOError, exc:
- print "Error getting IP address: %s" % exc
- sockfd.close()
- return ips
+ """Call Linux specific bits to retrieve our own IP address."""
+ import socket
+ import sys
+ import fcntl
+ import struct
+
+ intfs = _get_local_interfaces()
+
+ ips = []
+ SIOCGIFADDR = 0x8915
+ sockfd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ for intf in intfs:
+ if intf == "lo":
+ continue
+ try:
+ ifreq = (intf + '\0'*32)[:32]
+ result = fcntl.ioctl(sockfd.fileno(), SIOCGIFADDR, ifreq)
+ addr = socket.inet_ntoa(result[20:24])
+ ips.append(addr)
+ except IOError, exc:
+ print "Error getting IP address: %s" % exc
+ sockfd.close()
+ return ips
class MostlyReliablePipe(object):
- """Implement Mostly-Reliable UDP. We don't actually care about guaranteeing
- delivery or receipt, just a better effort than no effort at all."""
-
- _UDP_MSG_SIZE = SegmentBase.mtu() + SegmentBase.header_len()
- _SEGMENT_TTL = 120 # 2 minutes
-
- def __init__(self, local_addr, remote_addr, port, data_cb, user_data=None):
- self._local_addr = local_addr
- self._remote_addr = remote_addr
- self._port = port
- self._data_cb = data_cb
- self._user_data = user_data
- self._started = False
- self._send_worker = 0
- self._seq_counter = 0
- self._drop_prob = 0
- self._rt_check_worker_id = 0
-
- self._outgoing = []
- self._sent = {}
-
- self._incoming = {} # (message sha, # of segments) -> [segment1, segment2, ...]
- self._dispatched = {}
- self._acks = {} # (message sequence #, master sha, source addr) -> received timestamp
- self._ack_check_worker_id = 0
-
- self._local_ips = _get_local_ip_addresses()
-
- self._setup_listener()
- self._setup_sender()
-
- def __del__(self):
- if self._send_worker > 0:
- gobject.source_remove(self._send_worker)
- self._send_worker = 0
- if self._rt_check_worker_id > 0:
- gobject.source_remove(self._rt_check_worker_id)
- self._rt_check_worker_id = 0
- if self._ack_check_worker_id > 0:
- gobject.source_remove(self._ack_check_worker_id)
- self._ack_check_worker_id = 0
-
- def _setup_sender(self):
- """Setup the send socket for multicast."""
- self._send_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- # Make the socket multicast-aware, and set TTL.
- self._send_sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 20) # Change TTL (=20) to suit
-
- def _setup_listener(self):
- """Set up the listener socket for multicast traffic."""
- # Listener socket
- self._listen_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
-
- # Set some options to make it multicast-friendly
- self._listen_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_TTL, 20)
- self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_LOOP, 1)
-
- def start(self):
- """Let the listener socket start listening for network data."""
- # Set some more multicast options
- self._listen_sock.bind((self._local_addr, self._port))
- self._listen_sock.settimeout(2)
+ """Implement Mostly-Reliable UDP. We don't actually care about guaranteeing
+ delivery or receipt, just a better effort than no effort at all."""
+
+ _UDP_MSG_SIZE = SegmentBase.mtu() + SegmentBase.header_len()
+ _SEGMENT_TTL = 120 # 2 minutes
+
+ def __init__(self, local_addr, remote_addr, port, data_cb, user_data=None):
+ self._local_addr = local_addr
+ self._remote_addr = remote_addr
+ self._port = port
+ self._data_cb = data_cb
+ self._user_data = user_data
+ self._started = False
+ self._send_worker = 0
+ self._seq_counter = 0
+ self._drop_prob = 0
+ self._rt_check_worker_id = 0
+
+ self._outgoing = []
+ self._sent = {}
+
+ self._incoming = {} # (message sha, # of segments) -> [segment1, segment2, ...]
+ self._dispatched = {}
+ self._acks = {} # (message sequence #, master sha, source addr) -> received timestamp
+ self._ack_check_worker_id = 0
+
+ self._local_ips = _get_local_ip_addresses()
+
+ self._setup_listener()
+ self._setup_sender()
+
+ def __del__(self):
+ if self._send_worker > 0:
+ gobject.source_remove(self._send_worker)
+ self._send_worker = 0
+ if self._rt_check_worker_id > 0:
+ gobject.source_remove(self._rt_check_worker_id)
+ self._rt_check_worker_id = 0
+ if self._ack_check_worker_id > 0:
+ gobject.source_remove(self._ack_check_worker_id)
+ self._ack_check_worker_id = 0
+
+ def _setup_sender(self):
+ """Setup the send socket for multicast."""
+ self._send_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ # Make the socket multicast-aware, and set TTL.
+ self._send_sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 20) # Change TTL (=20) to suit
+
+ def _setup_listener(self):
+ """Set up the listener socket for multicast traffic."""
+ # Listener socket
+ self._listen_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+
+ # Set some options to make it multicast-friendly
+ self._listen_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_TTL, 20)
+ self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_LOOP, 1)
+
+ def start(self):
+ """Let the listener socket start listening for network data."""
+ # Set some more multicast options
+ self._listen_sock.bind((self._local_addr, self._port))
+ self._listen_sock.settimeout(2)
# Disable for now to try to fix "cannot assign requested address" errors
-# intf = socket.gethostbyname(socket.gethostname())
-# self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_IF,
-# socket.inet_aton(intf) + socket.inet_aton('0.0.0.0'))
- self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_ADD_MEMBERSHIP,
- socket.inet_aton(self._remote_addr) + socket.inet_aton('0.0.0.0'))
-
- # Watch the listener socket for data
- gobject.io_add_watch(self._listen_sock, gobject.IO_IN, self._handle_incoming_data)
- gobject.timeout_add(self._SEGMENT_TTL * 1000, self._segment_ttl_worker)
- self._rt_check_worker_id = gobject.timeout_add(50, self._retransmit_check_worker)
- self._ack_check_worker_id = gobject.timeout_add(50, self._ack_check_worker)
-
- self._started = True
-
- def _segment_ttl_worker(self):
- """Cull already-sent message segments that are past their TTL."""
- now = time.time()
- for key in self._sent.keys()[:]:
- segment = self._sent[key]
- if segment.stime() < now - self._SEGMENT_TTL:
- if segment.userdata:
- gobject.source_remove(segment.userdata)
- del self._sent[key]
-
- # Cull incomplete incoming segment chains that haven't gotten any data
- # for a long time either
- for msg_key in self._incoming.keys()[:]:
- message = self._incoming[msg_key]
- if message.last_incoming_time() < now - self._SEGMENT_TTL:
- del self._incoming[msg_key]
-
- # Remove already received and dispatched messages after a while
- for msg_key in self._dispatched.keys()[:]:
- message = self._dispatched[msg_key]
- if message.dispatch_time() < now - (self._SEGMENT_TTL*2):
- del self._dispatched[msg_key]
-
- # Remove received acks after a while
- for ack_key in self._acks.keys()[:]:
- ack_time = self._acks[ack_key]
- if ack_time < now - (self._SEGMENT_TTL*2):
- del self._acks[ack_key]
-
- return True
-
- _MAX_SEGMENT_RETRIES = 10
- def _retransmit_request(self, message):
- """Returns true if the message has exceeded it's retry limit."""
- first_missing = message.first_missing()
- if first_missing > 0:
- num_retries = message.rt_tries(first_missing)
- if num_retries > self._MAX_SEGMENT_RETRIES:
- return True
- msg_seq = self._next_msg_seq()
- seg = message.get_retransmit_message(msg_seq, first_missing)
- if seg:
- print "(MRP): Requesting retransmit of %d by %s" % (first_missing, message.source_address())
- self._outgoing.append(seg)
- self._schedule_send_worker()
- return False
-
- def _retransmit_check_worker(self):
- """Periodically check for and send retransmit requests for message
- segments that got lost."""
- try:
- now = time.time()
- for key in self._incoming.keys()[:]:
- message = self._incoming[key]
- if message.complete():
- continue
- next_rt = message.next_rt_time()
- if next_rt == 0 or next_rt > now:
- continue
- if self._retransmit_request(message):
- # Kill the message, too many retries
- print "(MRP): Dropped message %s, exceeded retries." % _stringify_sha(message.sha())
- self._dispatched[key] = message
- message.set_dispatch_time()
- del self._incoming[key]
- except KeyboardInterrupt:
- return False
- return True
-
- def _process_incoming_data(self, segment):
- """Handle a new message segment. First checks if there is only one
- segment to the message, and if the checksum from the header matches
- that computed from the data, dispatches it. Otherwise, it adds the
- new segment to the list of other segments for that message, and
- checks to see if the message is complete. If all segments are present,
- the message is reassembled and dispatched."""
-
- msg_sha = segment.master_sha()
- nsegs = segment.total_segments()
- addr = segment.address()
- segno = segment.segment_number()
-
- msg_seq_num = segment.message_sequence_number()
- msg_key = (addr[0], msg_seq_num, msg_sha, nsegs)
-
- if self._dispatched.has_key(msg_key):
- # We already dispatched this message, this segment is useless
- return
- # First segment in the message
- if not self._incoming.has_key(msg_key):
- self._incoming[msg_key] = Message((addr[0], self._port), msg_seq_num, msg_sha, nsegs)
- # Acknowledge the message if it didn't come from us
- if addr[0] not in self._local_ips:
- ack_key = (msg_seq_num, msg_sha, addr[0])
- if not self._acks.has_key(ack_key):
- self._send_ack_for_message(msg_seq_num, msg_sha, addr[0])
-
- message = self._incoming[msg_key]
- # Look for a dupe, and if so, drop the new segment
- if message.has_segment(segno):
- return
- message.add_segment(segment)
-
- # Dispatch the message if all segments are present and the sha is correct
- if message.complete():
- (msg_data, complete_data_sha) = message.data()
- if msg_sha == complete_data_sha:
- self._data_cb(addr, msg_data, self._user_data)
- self._dispatched[msg_key] = message
- message.set_dispatch_time()
- del self._incoming[msg_key]
- return
-
- def _segment_retransmit_cb(self, key, segment):
- """Add a segment ot the outgoing queue and schedule its transmission."""
- del self._sent[key]
- self._outgoing.append(segment)
- self._schedule_send_worker()
- return False
-
- def _schedule_segment_retransmit(self, key, segment, when, now):
- """Schedule retransmission of a segment if one is not already scheduled."""
- if segment.userdata:
- # Already scheduled for retransmit
- return
-
- if when <= now:
- # Immediate retransmission
- self._segment_retransmit_cb(key, segment)
- else:
- # convert time to milliseconds
- timeout = int((when - now) * 1000)
- segment.userdata = gobject.timeout_add(timeout, self._segment_retransmit_cb,
- key, segment)
-
- _STD_RETRANSMIT_INTERVAL = 0.05 # 50ms (in seconds)
- def _process_retransmit_request(self, segment):
- """Validate and process a retransmission request."""
- key = (segment.rt_msg_seq_num(), segment.rt_master_sha(), segment.rt_segment_number())
- if not self._sent.has_key(key):
- # Either we don't know about the segment, or it was already culled
- return
-
- # Calculate next retransmission time and schedule packet for retransmit
- segment = self._sent[key]
- # only retransmit segments every 150ms or more
- now = time.time()
- next_transmit = max(now, segment.last_transmit() + self._STD_RETRANSMIT_INTERVAL)
- self._schedule_segment_retransmit(key, segment, next_transmit, now)
-
- def _ack_check_worker(self):
- """Periodically check for messages that haven't received an ack
- yet, and retransmit them."""
- try:
- now = time.time()
- for key in self._sent.keys()[:]:
- segment = self._sent[key]
- # We only care about retransmitting the first segment
- # of a message, since if other machines don't have the
- # rest of the segments, they'll issue retransmit requests
- if segment.segment_number() != 1:
- continue
- if segment.last_transmit() > now - 0.150: # 150ms
- # Was just retransmitted recently, wait longer
- # before retransmitting it
- continue
- ack_key = None
- for ip in self._local_ips:
- ack_key = (segment.message_sequence_number(), segment.master_sha(), ip)
- if self._acks.has_key(ack_key):
- break
- ack_key = None
- # If the segment already has been acked, don't send it
- # again unless somebody explicitly requests a retransmit
- if ack_key is not None:
- continue
-
- del self._sent[key]
- self._outgoing.append(segment)
- self._schedule_send_worker()
- except KeyboardInterrupt:
- return False
- return True
-
- def _send_ack_for_message(self, ack_msg_seq_num, ack_msg_sha, ack_addr):
- """Send an ack segment for a message."""
- msg_seq_num = self._next_msg_seq()
- full_remote_addr = (self._remote_addr, self._port)
- ack = AckSegment.new_from_parts(full_remote_addr, msg_seq_num,
- ack_msg_seq_num, ack_msg_sha, ack_addr)
- self._outgoing.append(ack)
- self._schedule_send_worker()
- self._process_incoming_ack(ack)
-
- def _process_incoming_ack(self, segment):
- """Save the ack so that we don't send an ack when we start getting the segments
- the ack was acknowledging."""
- # If the ack is supposed to be for a message we sent, only accept it if
- # we actually sent the message to which it refers
- ack_addr = segment.ack_addr()
- ack_master_sha = segment.ack_master_sha()
- ack_msg_seq_num = segment.ack_msg_seq_num()
- if ack_addr in self._local_ips:
- sent_key = (ack_msg_seq_num, ack_master_sha, 1)
- if not self._sent.has_key(sent_key):
- return
- ack_key = (ack_msg_seq_num, ack_master_sha, ack_addr)
- if not self._acks.has_key(ack_key):
- self._acks[ack_key] = time.time()
-
- def set_drop_probability(self, prob=4):
- """Debugging function to randomly drop incoming packets.
- The prob argument should be an integer between 1 and 10 to drop,
- or 0 to drop none. Higher numbers drop more packets."""
- if not isinstance(prob, int):
- raise ValueError("Drop probability must be an integer.")
- if prob < 1 or prob > 10:
- raise ValueError("Drop probability must be between 1 and 10 inclusive.")
- self._drop_prob = prob
-
- def _handle_incoming_data(self, source, condition):
- """Handle incoming network data by making a message segment out of it
- sending it off to the processing function."""
- if not (condition & gobject.IO_IN):
- return True
- msg = {}
- data, addr = source.recvfrom(self._UDP_MSG_SIZE)
-
- should_drop = False
- p = random.random() * 10.0
- if self._drop_prob > 0 and p <= self._drop_prob:
- should_drop = True
-
- try:
- segment = SegmentBase.new_from_data(addr, data)
- if should_drop:
- print "(MRP): Dropped segment %d." % segment.segment_number()
- else:
- stype = segment.segment_type()
- if stype == SegmentBase.type_data():
- self._process_incoming_data(segment)
- elif stype == SegmentBase.type_retransmit():
- self._process_retransmit_request(segment)
- elif stype == SegmentBase.type_ack():
- self._process_incoming_ack(segment)
- except ValueError, exc:
- print "(MRP): Bad segment: %s" % exc
- return True
-
- def _next_msg_seq(self):
- self._seq_counter = self._seq_counter + 1
- if self._seq_counter > 65535:
- self._seq_counter = 1
- return self._seq_counter
-
- def send(self, data):
- """Break data up into chunks and queue for later transmission."""
- if not self._started:
- raise Exception("Can't send anything until started!")
-
- msg_seq = self._next_msg_seq()
-
- # Pack the data into network byte order
- template = "! %ds" % len(str(data))
- data = struct.pack(template, str(data))
- master_sha = _sha_data(data)
-
- # Split up the data into segments
- left = length = len(data)
- mtu = SegmentBase.mtu()
- nmessages = length / mtu
- if length % mtu > 0:
- nmessages = nmessages + 1
- seg_num = 1
- while left > 0:
- seg = DataSegment.new_from_parts(seg_num, nmessages,
- msg_seq, master_sha, data[:mtu])
- self._outgoing.append(seg)
- seg_num = seg_num + 1
- data = data[mtu:]
- left = left - mtu
- self._schedule_send_worker()
-
- def _schedule_send_worker(self):
- if len(self._outgoing) > 0 and self._send_worker == 0:
- self._send_worker = gobject.timeout_add(50, self._send_worker_cb)
-
- def _send_worker_cb(self):
- """Send all queued segments that have yet to be transmitted."""
- self._send_worker = 0
- nsent = 0
- for segment in self._outgoing:
- packet = segment.packetize()
- segment.inc_transmits()
- addr = (self._remote_addr, self._port)
- if segment.address():
- addr = segment.address()
- self._send_sock.sendto(packet, addr)
- if segment.userdata:
- gobject.source_remove(segment.userdata)
- segment.userdata = None # Retransmission GSource
- key = (segment.message_sequence_number(), segment.master_sha(), segment.segment_number())
- self._sent[key] = segment
- nsent = nsent + 1
- if nsent > 10:
- break
- self._outgoing = self._outgoing[nsent:]
- if len(self._outgoing):
- self._schedule_send_worker()
- return False
+# intf = socket.gethostbyname(socket.gethostname())
+# self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_IF,
+# socket.inet_aton(intf) + socket.inet_aton('0.0.0.0'))
+ self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_ADD_MEMBERSHIP,
+ socket.inet_aton(self._remote_addr) + socket.inet_aton('0.0.0.0'))
+
+ # Watch the listener socket for data
+ gobject.io_add_watch(self._listen_sock, gobject.IO_IN, self._handle_incoming_data)
+ gobject.timeout_add(self._SEGMENT_TTL * 1000, self._segment_ttl_worker)
+ self._rt_check_worker_id = gobject.timeout_add(50, self._retransmit_check_worker)
+ self._ack_check_worker_id = gobject.timeout_add(50, self._ack_check_worker)
+
+ self._started = True
+
+ def _segment_ttl_worker(self):
+ """Cull already-sent message segments that are past their TTL."""
+ now = time.time()
+ for key in self._sent.keys()[:]:
+ segment = self._sent[key]
+ if segment.stime() < now - self._SEGMENT_TTL:
+ if segment.userdata:
+ gobject.source_remove(segment.userdata)
+ del self._sent[key]
+
+ # Cull incomplete incoming segment chains that haven't gotten any data
+ # for a long time either
+ for msg_key in self._incoming.keys()[:]:
+ message = self._incoming[msg_key]
+ if message.last_incoming_time() < now - self._SEGMENT_TTL:
+ del self._incoming[msg_key]
+
+ # Remove already received and dispatched messages after a while
+ for msg_key in self._dispatched.keys()[:]:
+ message = self._dispatched[msg_key]
+ if message.dispatch_time() < now - (self._SEGMENT_TTL*2):
+ del self._dispatched[msg_key]
+
+ # Remove received acks after a while
+ for ack_key in self._acks.keys()[:]:
+ ack_time = self._acks[ack_key]
+ if ack_time < now - (self._SEGMENT_TTL*2):
+ del self._acks[ack_key]
+
+ return True
+
+ _MAX_SEGMENT_RETRIES = 10
+ def _retransmit_request(self, message):
+ """Returns true if the message has exceeded it's retry limit."""
+ first_missing = message.first_missing()
+ if first_missing > 0:
+ num_retries = message.rt_tries(first_missing)
+ if num_retries > self._MAX_SEGMENT_RETRIES:
+ return True
+ msg_seq = self._next_msg_seq()
+ seg = message.get_retransmit_message(msg_seq, first_missing)
+ if seg:
+ print "(MRP): Requesting retransmit of %d by %s" % (first_missing, message.source_address())
+ self._outgoing.append(seg)
+ self._schedule_send_worker()
+ return False
+
+ def _retransmit_check_worker(self):
+ """Periodically check for and send retransmit requests for message
+ segments that got lost."""
+ try:
+ now = time.time()
+ for key in self._incoming.keys()[:]:
+ message = self._incoming[key]
+ if message.complete():
+ continue
+ next_rt = message.next_rt_time()
+ if next_rt == 0 or next_rt > now:
+ continue
+ if self._retransmit_request(message):
+ # Kill the message, too many retries
+ print "(MRP): Dropped message %s, exceeded retries." % _stringify_sha(message.sha())
+ self._dispatched[key] = message
+ message.set_dispatch_time()
+ del self._incoming[key]
+ except KeyboardInterrupt:
+ return False
+ return True
+
+ def _process_incoming_data(self, segment):
+ """Handle a new message segment. First checks if there is only one
+ segment to the message, and if the checksum from the header matches
+ that computed from the data, dispatches it. Otherwise, it adds the
+ new segment to the list of other segments for that message, and
+ checks to see if the message is complete. If all segments are present,
+ the message is reassembled and dispatched."""
+
+ msg_sha = segment.master_sha()
+ nsegs = segment.total_segments()
+ addr = segment.address()
+ segno = segment.segment_number()
+
+ msg_seq_num = segment.message_sequence_number()
+ msg_key = (addr[0], msg_seq_num, msg_sha, nsegs)
+
+ if self._dispatched.has_key(msg_key):
+ # We already dispatched this message, this segment is useless
+ return
+ # First segment in the message
+ if not self._incoming.has_key(msg_key):
+ self._incoming[msg_key] = Message((addr[0], self._port), msg_seq_num, msg_sha, nsegs)
+ # Acknowledge the message if it didn't come from us
+ if addr[0] not in self._local_ips:
+ ack_key = (msg_seq_num, msg_sha, addr[0])
+ if not self._acks.has_key(ack_key):
+ self._send_ack_for_message(msg_seq_num, msg_sha, addr[0])
+
+ message = self._incoming[msg_key]
+ # Look for a dupe, and if so, drop the new segment
+ if message.has_segment(segno):
+ return
+ message.add_segment(segment)
+
+ # Dispatch the message if all segments are present and the sha is correct
+ if message.complete():
+ (msg_data, complete_data_sha) = message.data()
+ if msg_sha == complete_data_sha:
+ self._data_cb(addr, msg_data, self._user_data)
+ self._dispatched[msg_key] = message
+ message.set_dispatch_time()
+ del self._incoming[msg_key]
+ return
+
+ def _segment_retransmit_cb(self, key, segment):
+ """Add a segment ot the outgoing queue and schedule its transmission."""
+ del self._sent[key]
+ self._outgoing.append(segment)
+ self._schedule_send_worker()
+ return False
+
+ def _schedule_segment_retransmit(self, key, segment, when, now):
+ """Schedule retransmission of a segment if one is not already scheduled."""
+ if segment.userdata:
+ # Already scheduled for retransmit
+ return
+
+ if when <= now:
+ # Immediate retransmission
+ self._segment_retransmit_cb(key, segment)
+ else:
+ # convert time to milliseconds
+ timeout = int((when - now) * 1000)
+ segment.userdata = gobject.timeout_add(timeout, self._segment_retransmit_cb,
+ key, segment)
+
+ _STD_RETRANSMIT_INTERVAL = 0.05 # 50ms (in seconds)
+ def _process_retransmit_request(self, segment):
+ """Validate and process a retransmission request."""
+ key = (segment.rt_msg_seq_num(), segment.rt_master_sha(), segment.rt_segment_number())
+ if not self._sent.has_key(key):
+ # Either we don't know about the segment, or it was already culled
+ return
+
+ # Calculate next retransmission time and schedule packet for retransmit
+ segment = self._sent[key]
+ # only retransmit segments every 150ms or more
+ now = time.time()
+ next_transmit = max(now, segment.last_transmit() + self._STD_RETRANSMIT_INTERVAL)
+ self._schedule_segment_retransmit(key, segment, next_transmit, now)
+
+ def _ack_check_worker(self):
+ """Periodically check for messages that haven't received an ack
+ yet, and retransmit them."""
+ try:
+ now = time.time()
+ for key in self._sent.keys()[:]:
+ segment = self._sent[key]
+ # We only care about retransmitting the first segment
+ # of a message, since if other machines don't have the
+ # rest of the segments, they'll issue retransmit requests
+ if segment.segment_number() != 1:
+ continue
+ if segment.last_transmit() > now - 0.150: # 150ms
+ # Was just retransmitted recently, wait longer
+ # before retransmitting it
+ continue
+ ack_key = None
+ for ip in self._local_ips:
+ ack_key = (segment.message_sequence_number(), segment.master_sha(), ip)
+ if self._acks.has_key(ack_key):
+ break
+ ack_key = None
+ # If the segment already has been acked, don't send it
+ # again unless somebody explicitly requests a retransmit
+ if ack_key is not None:
+ continue
+
+ del self._sent[key]
+ self._outgoing.append(segment)
+ self._schedule_send_worker()
+ except KeyboardInterrupt:
+ return False
+ return True
+
+ def _send_ack_for_message(self, ack_msg_seq_num, ack_msg_sha, ack_addr):
+ """Send an ack segment for a message."""
+ msg_seq_num = self._next_msg_seq()
+ full_remote_addr = (self._remote_addr, self._port)
+ ack = AckSegment.new_from_parts(full_remote_addr, msg_seq_num,
+ ack_msg_seq_num, ack_msg_sha, ack_addr)
+ self._outgoing.append(ack)
+ self._schedule_send_worker()
+ self._process_incoming_ack(ack)
+
+ def _process_incoming_ack(self, segment):
+ """Save the ack so that we don't send an ack when we start getting the segments
+ the ack was acknowledging."""
+ # If the ack is supposed to be for a message we sent, only accept it if
+ # we actually sent the message to which it refers
+ ack_addr = segment.ack_addr()
+ ack_master_sha = segment.ack_master_sha()
+ ack_msg_seq_num = segment.ack_msg_seq_num()
+ if ack_addr in self._local_ips:
+ sent_key = (ack_msg_seq_num, ack_master_sha, 1)
+ if not self._sent.has_key(sent_key):
+ return
+ ack_key = (ack_msg_seq_num, ack_master_sha, ack_addr)
+ if not self._acks.has_key(ack_key):
+ self._acks[ack_key] = time.time()
+
+ def set_drop_probability(self, prob=4):
+ """Debugging function to randomly drop incoming packets.
+ The prob argument should be an integer between 1 and 10 to drop,
+ or 0 to drop none. Higher numbers drop more packets."""
+ if not isinstance(prob, int):
+ raise ValueError("Drop probability must be an integer.")
+ if prob < 1 or prob > 10:
+ raise ValueError("Drop probability must be between 1 and 10 inclusive.")
+ self._drop_prob = prob
+
+ def _handle_incoming_data(self, source, condition):
+ """Handle incoming network data by making a message segment out of it
+ sending it off to the processing function."""
+ if not (condition & gobject.IO_IN):
+ return True
+ msg = {}
+ data, addr = source.recvfrom(self._UDP_MSG_SIZE)
+
+ should_drop = False
+ p = random.random() * 10.0
+ if self._drop_prob > 0 and p <= self._drop_prob:
+ should_drop = True
+
+ try:
+ segment = SegmentBase.new_from_data(addr, data)
+ if should_drop:
+ print "(MRP): Dropped segment %d." % segment.segment_number()
+ else:
+ stype = segment.segment_type()
+ if stype == SegmentBase.type_data():
+ self._process_incoming_data(segment)
+ elif stype == SegmentBase.type_retransmit():
+ self._process_retransmit_request(segment)
+ elif stype == SegmentBase.type_ack():
+ self._process_incoming_ack(segment)
+ except ValueError, exc:
+ print "(MRP): Bad segment: %s" % exc
+ return True
+
+ def _next_msg_seq(self):
+ self._seq_counter = self._seq_counter + 1
+ if self._seq_counter > 65535:
+ self._seq_counter = 1
+ return self._seq_counter
+
+ def send(self, data):
+ """Break data up into chunks and queue for later transmission."""
+ if not self._started:
+ raise Exception("Can't send anything until started!")
+
+ msg_seq = self._next_msg_seq()
+
+ # Pack the data into network byte order
+ template = "! %ds" % len(str(data))
+ data = struct.pack(template, str(data))
+ master_sha = _sha_data(data)
+
+ # Split up the data into segments
+ left = length = len(data)
+ mtu = SegmentBase.mtu()
+ nmessages = length / mtu
+ if length % mtu > 0:
+ nmessages = nmessages + 1
+ seg_num = 1
+ while left > 0:
+ seg = DataSegment.new_from_parts(seg_num, nmessages,
+ msg_seq, master_sha, data[:mtu])
+ self._outgoing.append(seg)
+ seg_num = seg_num + 1
+ data = data[mtu:]
+ left = left - mtu
+ self._schedule_send_worker()
+
+ def _schedule_send_worker(self):
+ if len(self._outgoing) > 0 and self._send_worker == 0:
+ self._send_worker = gobject.timeout_add(50, self._send_worker_cb)
+
+ def _send_worker_cb(self):
+ """Send all queued segments that have yet to be transmitted."""
+ self._send_worker = 0
+ nsent = 0
+ for segment in self._outgoing:
+ packet = segment.packetize()
+ segment.inc_transmits()
+ addr = (self._remote_addr, self._port)
+ if segment.address():
+ addr = segment.address()
+ self._send_sock.sendto(packet, addr)
+ if segment.userdata:
+ gobject.source_remove(segment.userdata)
+ segment.userdata = None # Retransmission GSource
+ key = (segment.message_sequence_number(), segment.master_sha(), segment.segment_number())
+ self._sent[key] = segment
+ nsent = nsent + 1
+ if nsent > 10:
+ break
+ self._outgoing = self._outgoing[nsent:]
+ if len(self._outgoing):
+ self._schedule_send_worker()
+ return False
#################################################################
@@ -988,348 +988,348 @@ import unittest
class SegmentBaseTestCase(unittest.TestCase):
- _DEF_SEGNO = 1
- _DEF_TOT_SEGS = 5
- _DEF_MSG_SEQ_NUM = 4556
- _DEF_MASTER_SHA = "12345678901234567890"
- _DEF_SEG_TYPE = 0
+ _DEF_SEGNO = 1
+ _DEF_TOT_SEGS = 5
+ _DEF_MSG_SEQ_NUM = 4556
+ _DEF_MASTER_SHA = "12345678901234567890"
+ _DEF_SEG_TYPE = 0
- _DEF_ADDRESS = ('123.3.2.1', 3333)
- _SEG_MAGIC = 0xbaea4304
+ _DEF_ADDRESS = ('123.3.2.1', 3333)
+ _SEG_MAGIC = 0xbaea4304
class SegmentBaseInitTestCase(SegmentBaseTestCase):
- def _test_init_fail(self, segno, total_segs, msg_seq_num, master_sha, fail_msg):
- try:
- seg = SegmentBase(segno, total_segs, msg_seq_num, master_sha)
- except ValueError, exc:
- pass
- else:
- self.fail("expected a ValueError for %s." % fail_msg)
-
- def testSegmentBase(self):
- assert SegmentBase.magic() == self._SEG_MAGIC, "Segment magic wasn't correct!"
- assert SegmentBase.header_len() > 0, "header size was not greater than zero."
- assert SegmentBase.mtu() > 0, "MTU was not greater than zero."
- assert SegmentBase.mtu() + SegmentBase.header_len() == _UDP_DATAGRAM_SIZE, "MTU + header size didn't equal expected %d." % _UDP_DATAGRAM_SIZE
-
- def testGoodInit(self):
- seg = SegmentBase(self._DEF_SEGNO, self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA)
- assert seg.stime() < time.time(), "segment start time is less than now!"
- assert not seg.address(), "Segment address was not None after init."
- assert seg.segment_number() == self._DEF_SEGNO, "Segment number wasn't correct after init."
- assert seg.total_segments() == self._DEF_TOT_SEGS, "Total segments wasn't correct after init."
- assert seg.message_sequence_number() == self._DEF_MSG_SEQ_NUM, "Message sequence number wasn't correct after init."
- assert seg.master_sha() == self._DEF_MASTER_SHA, "Message master SHA wasn't correct after init."
- assert seg.segment_type() == None, "Segment type was not None after init."
- assert seg.transmits() == 0, "Segment transmits was not 0 after init."
- assert seg.last_transmit() == 0, "Segment last transmit was not 0 after init."
- assert seg.data() == None, "Segment data was not None after init."
-
- def testSegmentNumber(self):
- self._test_init_fail(0, self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid segment number")
- self._test_init_fail(65536, self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid segment number")
- self._test_init_fail(None, self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid segment number")
- self._test_init_fail("", self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid segment number")
-
- def testTotalMessageSegmentNumber(self):
- self._test_init_fail(self._DEF_SEGNO, 0, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid total segments")
- self._test_init_fail(self._DEF_SEGNO, 65536, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid total segments")
- self._test_init_fail(self._DEF_SEGNO, None, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid total segments")
- self._test_init_fail(self._DEF_SEGNO, "", self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid total segments")
-
- def testMessageSequenceNumber(self):
- self._test_init_fail(self._DEF_SEGNO, self._DEF_TOT_SEGS, 0, self._DEF_MASTER_SHA, "invalid message sequence number")
- self._test_init_fail(self._DEF_SEGNO, self._DEF_TOT_SEGS, 65536, self._DEF_MASTER_SHA, "invalid message sequence number")
- self._test_init_fail(self._DEF_SEGNO, self._DEF_TOT_SEGS, None, self._DEF_MASTER_SHA, "invalid message sequence number")
- self._test_init_fail(self._DEF_SEGNO, self._DEF_TOT_SEGS, "", self._DEF_MASTER_SHA, "invalid message sequence number")
-
- def testMasterSHA(self):
- self._test_init_fail(self._DEF_SEGNO, self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, "1" * 19, "invalid SHA1 data hash")
- self._test_init_fail(self._DEF_SEGNO, self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, "1" * 21, "invalid SHA1 data hash")
- self._test_init_fail(self._DEF_SEGNO, self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, None, "invalid SHA1 data hash")
- self._test_init_fail(self._DEF_SEGNO, self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, 1234, "invalid SHA1 data hash")
-
- def _testNewFromDataFail(self, addr, data, fail_msg):
- try:
- seg = SegmentBase.new_from_data(addr, data)
- except ValueError, exc:
- pass
- else:
- self.fail("expected a ValueError about %s." % fail_msg)
-
- def testNewFromDataAddress(self):
- self._testNewFromDataFail(None, None, "bad address")
- self._testNewFromDataFail('', None, "bad address")
- self._testNewFromDataFail((''), None, "bad address")
- self._testNewFromDataFail((1), None, "bad address")
- self._testNewFromDataFail(('', ''), None, "bad address")
- self._testNewFromDataFail((1, 3333), None, "bad address")
- self._testNewFromDataFail(('', 0), None, "bad address")
- self._testNewFromDataFail(('', 65536), None, "bad address")
-
- def testNewFromDataData(self):
- """Only test generic new_from_data() bits, not type-specific ones."""
- self._testNewFromDataFail(self._DEF_ADDRESS, None, "invalid data")
-
- really_short_data = "111"
- self._testNewFromDataFail(self._DEF_ADDRESS, really_short_data, "data too short")
-
- only_header_data = "1" * SegmentBase.header_len()
- self._testNewFromDataFail(self._DEF_ADDRESS, only_header_data, "data too short")
-
- too_much_data = "1" * (_UDP_DATAGRAM_SIZE + 1)
- self._testNewFromDataFail(self._DEF_ADDRESS, too_much_data, "too much data")
-
- header_template = SegmentBase.header_template()
- bad_magic_data = struct.pack(header_template, 0x12345678, self._DEF_SEG_TYPE,
- self._DEF_SEGNO, self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA)
- self._testNewFromDataFail(self._DEF_ADDRESS, bad_magic_data, "invalid magic")
-
- bad_type_data = struct.pack(header_template, self._SEG_MAGIC, -1, self._DEF_SEGNO,
- self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA)
- self._testNewFromDataFail(self._DEF_ADDRESS, bad_type_data, "invalid segment type")
-
- # Test master_sha that doesn't match data's SHA
- header = struct.pack(header_template, self._SEG_MAGIC, self._DEF_SEG_TYPE, 1, 1,
- self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA)
- data = struct.pack("! 15s", "7" * 15)
- self._testNewFromDataFail(self._DEF_ADDRESS, header + data, "single-segment message SHA mismatch")
-
- def addToSuite(suite):
- suite.addTest(SegmentBaseInitTestCase("testGoodInit"))
- suite.addTest(SegmentBaseInitTestCase("testSegmentNumber"))
- suite.addTest(SegmentBaseInitTestCase("testTotalMessageSegmentNumber"))
- suite.addTest(SegmentBaseInitTestCase("testMessageSequenceNumber"))
- suite.addTest(SegmentBaseInitTestCase("testMasterSHA"))
- suite.addTest(SegmentBaseInitTestCase("testNewFromDataAddress"))
- suite.addTest(SegmentBaseInitTestCase("testNewFromDataData"))
- addToSuite = staticmethod(addToSuite)
+ def _test_init_fail(self, segno, total_segs, msg_seq_num, master_sha, fail_msg):
+ try:
+ seg = SegmentBase(segno, total_segs, msg_seq_num, master_sha)
+ except ValueError, exc:
+ pass
+ else:
+ self.fail("expected a ValueError for %s." % fail_msg)
+
+ def testSegmentBase(self):
+ assert SegmentBase.magic() == self._SEG_MAGIC, "Segment magic wasn't correct!"
+ assert SegmentBase.header_len() > 0, "header size was not greater than zero."
+ assert SegmentBase.mtu() > 0, "MTU was not greater than zero."
+ assert SegmentBase.mtu() + SegmentBase.header_len() == _UDP_DATAGRAM_SIZE, "MTU + header size didn't equal expected %d." % _UDP_DATAGRAM_SIZE
+
+ def testGoodInit(self):
+ seg = SegmentBase(self._DEF_SEGNO, self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA)
+ assert seg.stime() < time.time(), "segment start time is less than now!"
+ assert not seg.address(), "Segment address was not None after init."
+ assert seg.segment_number() == self._DEF_SEGNO, "Segment number wasn't correct after init."
+ assert seg.total_segments() == self._DEF_TOT_SEGS, "Total segments wasn't correct after init."
+ assert seg.message_sequence_number() == self._DEF_MSG_SEQ_NUM, "Message sequence number wasn't correct after init."
+ assert seg.master_sha() == self._DEF_MASTER_SHA, "Message master SHA wasn't correct after init."
+ assert seg.segment_type() == None, "Segment type was not None after init."
+ assert seg.transmits() == 0, "Segment transmits was not 0 after init."
+ assert seg.last_transmit() == 0, "Segment last transmit was not 0 after init."
+ assert seg.data() == None, "Segment data was not None after init."
+
+ def testSegmentNumber(self):
+ self._test_init_fail(0, self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid segment number")
+ self._test_init_fail(65536, self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid segment number")
+ self._test_init_fail(None, self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid segment number")
+ self._test_init_fail("", self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid segment number")
+
+ def testTotalMessageSegmentNumber(self):
+ self._test_init_fail(self._DEF_SEGNO, 0, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid total segments")
+ self._test_init_fail(self._DEF_SEGNO, 65536, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid total segments")
+ self._test_init_fail(self._DEF_SEGNO, None, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid total segments")
+ self._test_init_fail(self._DEF_SEGNO, "", self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid total segments")
+
+ def testMessageSequenceNumber(self):
+ self._test_init_fail(self._DEF_SEGNO, self._DEF_TOT_SEGS, 0, self._DEF_MASTER_SHA, "invalid message sequence number")
+ self._test_init_fail(self._DEF_SEGNO, self._DEF_TOT_SEGS, 65536, self._DEF_MASTER_SHA, "invalid message sequence number")
+ self._test_init_fail(self._DEF_SEGNO, self._DEF_TOT_SEGS, None, self._DEF_MASTER_SHA, "invalid message sequence number")
+ self._test_init_fail(self._DEF_SEGNO, self._DEF_TOT_SEGS, "", self._DEF_MASTER_SHA, "invalid message sequence number")
+
+ def testMasterSHA(self):
+ self._test_init_fail(self._DEF_SEGNO, self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, "1" * 19, "invalid SHA1 data hash")
+ self._test_init_fail(self._DEF_SEGNO, self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, "1" * 21, "invalid SHA1 data hash")
+ self._test_init_fail(self._DEF_SEGNO, self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, None, "invalid SHA1 data hash")
+ self._test_init_fail(self._DEF_SEGNO, self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, 1234, "invalid SHA1 data hash")
+
+ def _testNewFromDataFail(self, addr, data, fail_msg):
+ try:
+ seg = SegmentBase.new_from_data(addr, data)
+ except ValueError, exc:
+ pass
+ else:
+ self.fail("expected a ValueError about %s." % fail_msg)
+
+ def testNewFromDataAddress(self):
+ self._testNewFromDataFail(None, None, "bad address")
+ self._testNewFromDataFail('', None, "bad address")
+ self._testNewFromDataFail((''), None, "bad address")
+ self._testNewFromDataFail((1), None, "bad address")
+ self._testNewFromDataFail(('', ''), None, "bad address")
+ self._testNewFromDataFail((1, 3333), None, "bad address")
+ self._testNewFromDataFail(('', 0), None, "bad address")
+ self._testNewFromDataFail(('', 65536), None, "bad address")
+
+ def testNewFromDataData(self):
+ """Only test generic new_from_data() bits, not type-specific ones."""
+ self._testNewFromDataFail(self._DEF_ADDRESS, None, "invalid data")
+
+ really_short_data = "111"
+ self._testNewFromDataFail(self._DEF_ADDRESS, really_short_data, "data too short")
+
+ only_header_data = "1" * SegmentBase.header_len()
+ self._testNewFromDataFail(self._DEF_ADDRESS, only_header_data, "data too short")
+
+ too_much_data = "1" * (_UDP_DATAGRAM_SIZE + 1)
+ self._testNewFromDataFail(self._DEF_ADDRESS, too_much_data, "too much data")
+
+ header_template = SegmentBase.header_template()
+ bad_magic_data = struct.pack(header_template, 0x12345678, self._DEF_SEG_TYPE,
+ self._DEF_SEGNO, self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA)
+ self._testNewFromDataFail(self._DEF_ADDRESS, bad_magic_data, "invalid magic")
+
+ bad_type_data = struct.pack(header_template, self._SEG_MAGIC, -1, self._DEF_SEGNO,
+ self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA)
+ self._testNewFromDataFail(self._DEF_ADDRESS, bad_type_data, "invalid segment type")
+
+ # Test master_sha that doesn't match data's SHA
+ header = struct.pack(header_template, self._SEG_MAGIC, self._DEF_SEG_TYPE, 1, 1,
+ self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA)
+ data = struct.pack("! 15s", "7" * 15)
+ self._testNewFromDataFail(self._DEF_ADDRESS, header + data, "single-segment message SHA mismatch")
+
+ def addToSuite(suite):
+ suite.addTest(SegmentBaseInitTestCase("testGoodInit"))
+ suite.addTest(SegmentBaseInitTestCase("testSegmentNumber"))
+ suite.addTest(SegmentBaseInitTestCase("testTotalMessageSegmentNumber"))
+ suite.addTest(SegmentBaseInitTestCase("testMessageSequenceNumber"))
+ suite.addTest(SegmentBaseInitTestCase("testMasterSHA"))
+ suite.addTest(SegmentBaseInitTestCase("testNewFromDataAddress"))
+ suite.addTest(SegmentBaseInitTestCase("testNewFromDataData"))
+ addToSuite = staticmethod(addToSuite)
class DataSegmentTestCase(SegmentBaseTestCase):
- """Test DataSegment class specific initialization and stuff."""
-
- def testInit(self):
- seg = DataSegment(self._DEF_SEGNO, self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM,
- self._DEF_MASTER_SHA)
- assert seg.segment_type() == SegmentBase.type_data(), "Segment wasn't a data segment."
-
- def testNewFromParts(self):
- try:
- seg = DataSegment.new_from_parts(self._DEF_SEGNO, self._DEF_TOT_SEGS,
- self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, None)
- except ValueError, exc:
- pass
- else:
- self.fail("Expected ValueError about invalid data.")
-
- # Ensure message data is same as we stuff in after object is instantiated
- payload = "How are you today?"
- seg = DataSegment.new_from_parts(self._DEF_SEGNO, self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM,
- self._DEF_MASTER_SHA, payload)
- assert seg.data() == payload, "Data after segment creation didn't match expected."
-
- def testNewFromData(self):
- """Test DataSegment's new_from_data() functionality."""
-
- # Make sure something valid actually works
- header_template = SegmentBase.header_template()
- payload_str = "How are you today?"
- payload = struct.pack("! %ds" % len(payload_str), payload_str)
- payload_sha = _sha_data(payload)
- header = struct.pack(header_template, self._SEG_MAGIC, SegmentBase.type_data(), self._DEF_SEGNO,
- self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, payload_sha)
- seg = SegmentBase.new_from_data(self._DEF_ADDRESS, header + payload)
-
- assert seg.address() == self._DEF_ADDRESS, "Segment address did not match expected."
- assert seg.segment_type() == SegmentBase.type_data(), "Segment type did not match expected."
- assert seg.segment_number() == self._DEF_SEGNO, "Segment number did not match expected."
- assert seg.total_segments() == self._DEF_TOT_SEGS, "Total segments did not match expected."
- assert seg.message_sequence_number() == self._DEF_MSG_SEQ_NUM, "Message sequence number did not match expected."
- assert seg.master_sha() == payload_sha, "Message master SHA did not match expected."
- assert seg.data() == payload, "Segment data did not match expected payload."
-
- def addToSuite(suite):
- suite.addTest(DataSegmentTestCase("testInit"))
- suite.addTest(DataSegmentTestCase("testNewFromParts"))
- suite.addTest(DataSegmentTestCase("testNewFromData"))
- addToSuite = staticmethod(addToSuite)
+ """Test DataSegment class specific initialization and stuff."""
+
+ def testInit(self):
+ seg = DataSegment(self._DEF_SEGNO, self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM,
+ self._DEF_MASTER_SHA)
+ assert seg.segment_type() == SegmentBase.type_data(), "Segment wasn't a data segment."
+
+ def testNewFromParts(self):
+ try:
+ seg = DataSegment.new_from_parts(self._DEF_SEGNO, self._DEF_TOT_SEGS,
+ self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, None)
+ except ValueError, exc:
+ pass
+ else:
+ self.fail("Expected ValueError about invalid data.")
+
+ # Ensure message data is same as we stuff in after object is instantiated
+ payload = "How are you today?"
+ seg = DataSegment.new_from_parts(self._DEF_SEGNO, self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM,
+ self._DEF_MASTER_SHA, payload)
+ assert seg.data() == payload, "Data after segment creation didn't match expected."
+
+ def testNewFromData(self):
+ """Test DataSegment's new_from_data() functionality."""
+
+ # Make sure something valid actually works
+ header_template = SegmentBase.header_template()
+ payload_str = "How are you today?"
+ payload = struct.pack("! %ds" % len(payload_str), payload_str)
+ payload_sha = _sha_data(payload)
+ header = struct.pack(header_template, self._SEG_MAGIC, SegmentBase.type_data(), self._DEF_SEGNO,
+ self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, payload_sha)
+ seg = SegmentBase.new_from_data(self._DEF_ADDRESS, header + payload)
+
+ assert seg.address() == self._DEF_ADDRESS, "Segment address did not match expected."
+ assert seg.segment_type() == SegmentBase.type_data(), "Segment type did not match expected."
+ assert seg.segment_number() == self._DEF_SEGNO, "Segment number did not match expected."
+ assert seg.total_segments() == self._DEF_TOT_SEGS, "Total segments did not match expected."
+ assert seg.message_sequence_number() == self._DEF_MSG_SEQ_NUM, "Message sequence number did not match expected."
+ assert seg.master_sha() == payload_sha, "Message master SHA did not match expected."
+ assert seg.data() == payload, "Segment data did not match expected payload."
+
+ def addToSuite(suite):
+ suite.addTest(DataSegmentTestCase("testInit"))
+ suite.addTest(DataSegmentTestCase("testNewFromParts"))
+ suite.addTest(DataSegmentTestCase("testNewFromData"))
+ addToSuite = staticmethod(addToSuite)
class RetransmitSegmentTestCase(SegmentBaseTestCase):
- """Test RetransmitSegment class specific initialization and stuff."""
-
- def _test_init_fail(self, segno, total_segs, msg_seq_num, master_sha, fail_msg):
- try:
- seg = RetransmitSegment(segno, total_segs, msg_seq_num, master_sha)
- except ValueError, exc:
- pass
- else:
- self.fail("expected a ValueError for %s." % fail_msg)
-
- def testInit(self):
- self._test_init_fail(0, 1, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid segment number")
- self._test_init_fail(2, 1, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid segment number")
- self._test_init_fail(1, 0, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid number of total segments")
- self._test_init_fail(1, 2, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid number of total segments")
-
- # Something that's supposed to work
- seg = RetransmitSegment(1, 1, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA)
- assert seg.segment_type() == SegmentBase.type_retransmit(), "Segment wasn't a retransmit segment."
-
- def _test_new_from_parts_fail(self, msg_seq_num, rt_msg_seq_num, rt_master_sha, rt_segment_number, fail_msg):
- try:
- seg = RetransmitSegment.new_from_parts(self._DEF_ADDRESS, msg_seq_num, rt_msg_seq_num,
- rt_master_sha, rt_segment_number)
- except ValueError, exc:
- pass
- else:
- self.fail("expected a ValueError for %s." % fail_msg)
-
- def testNewFromParts(self):
- """Test RetransmitSegment's new_from_parts() functionality."""
- self._test_new_from_parts_fail(0, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA,
- self._DEF_SEGNO, "invalid message sequence number")
- self._test_new_from_parts_fail(65536, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA,
- self._DEF_SEGNO, "invalid message sequence number")
- self._test_new_from_parts_fail(None, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA,
- self._DEF_SEGNO, "invalid message sequence number")
- self._test_new_from_parts_fail("", self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA,
- self._DEF_SEGNO, "invalid message sequence number")
-
- self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, 0, self._DEF_MASTER_SHA,
- self._DEF_SEGNO, "invalid retransmit message sequence number")
- self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, 65536, self._DEF_MASTER_SHA,
- self._DEF_SEGNO, "invalid retransmit message sequence number")
- self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, None, self._DEF_MASTER_SHA,
- self._DEF_SEGNO, "invalid retransmit message sequence number")
- self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, "", self._DEF_MASTER_SHA,
- self._DEF_SEGNO, "invalid retransmit message sequence number")
-
- self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, self._DEF_MSG_SEQ_NUM, "1" * 19,
- self._DEF_SEGNO, "invalid retransmit message master SHA")
- self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, self._DEF_MSG_SEQ_NUM, "1" * 21,
- self._DEF_SEGNO, "invalid retransmit message master SHA")
- self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, self._DEF_MSG_SEQ_NUM, None,
- self._DEF_SEGNO, "invalid retransmit message master SHA")
- self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, self._DEF_MSG_SEQ_NUM, 1234,
- self._DEF_SEGNO, "invalid retransmit message master SHA")
-
- self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, self._DEF_MSG_SEQ_NUM,
- self._DEF_MASTER_SHA, 0, "invalid retransmit message segment number")
- self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, self._DEF_MSG_SEQ_NUM,
- self._DEF_MASTER_SHA, 65536, "invalid retransmit message segment number")
- self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, self._DEF_MSG_SEQ_NUM,
- self._DEF_MASTER_SHA, None, "invalid retransmit message segment number")
- self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, self._DEF_MSG_SEQ_NUM,
- self._DEF_MASTER_SHA, "", "invalid retransmit message segment number")
-
- # Ensure message data is same as we stuff in after object is instantiated
- seg = RetransmitSegment.new_from_parts(self._DEF_ADDRESS, self._DEF_MSG_SEQ_NUM, self._DEF_MSG_SEQ_NUM,
- self._DEF_MASTER_SHA, self._DEF_SEGNO)
- assert seg.rt_msg_seq_num() == self._DEF_MSG_SEQ_NUM, "RT message sequence number after segment creation didn't match expected."
- assert seg.rt_master_sha() == self._DEF_MASTER_SHA, "RT master SHA after segment creation didn't match expected."
- assert seg.rt_segment_number() == self._DEF_SEGNO, "RT segment number after segment creation didn't match expected."
-
- def _new_from_data(self, rt_msg_seq_num, rt_master_sha, rt_segment_number):
- payload = struct.pack(RetransmitSegment.data_template(), rt_msg_seq_num, rt_master_sha, rt_segment_number)
- payload_sha = _sha_data(payload)
- header_template = SegmentBase.header_template()
- header = struct.pack(header_template, self._SEG_MAGIC, SegmentBase.type_retransmit(), 1, 1,
- self._DEF_MSG_SEQ_NUM, payload_sha)
- return header + payload
-
- def _test_new_from_data_fail(self, rt_msg_seq_num, rt_master_sha, rt_segment_number, fail_msg):
- try:
- packet = self._new_from_data(rt_msg_seq_num, rt_master_sha, rt_segment_number)
- seg = SegmentBase.new_from_data(self._DEF_ADDRESS, packet)
- except ValueError, exc:
- pass
- else:
- self.fail("Expected a ValueError about %s." % fail_msg)
-
- def testNewFromData(self):
- """Test DataSegment's new_from_data() functionality."""
- self._test_new_from_data_fail(0, self._DEF_MASTER_SHA, self._DEF_SEGNO, "invalid RT message sequence number")
- self._test_new_from_data_fail(65536, self._DEF_MASTER_SHA, self._DEF_SEGNO, "invalid RT message sequence number")
-
- self._test_new_from_data_fail(self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, 0, "invalid RT segment number")
- self._test_new_from_data_fail(self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, 65536, "invalid RT segment number")
-
- # Ensure something that should work
- packet = self._new_from_data(self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, self._DEF_SEGNO)
- seg = SegmentBase.new_from_data(self._DEF_ADDRESS, packet)
- assert seg.segment_type() == SegmentBase.type_retransmit(), "Segment wasn't expected type."
- assert seg.rt_msg_seq_num() == self._DEF_MSG_SEQ_NUM, "Segment RT message sequence number didn't match expected."
- assert seg.rt_master_sha() == self._DEF_MASTER_SHA, "Segment RT master SHA didn't match expected."
- assert seg.rt_segment_number() == self._DEF_SEGNO, "Segment RT segment number didn't match expected."
-
- def testPartsToData(self):
- seg = RetransmitSegment.new_from_parts(self._DEF_ADDRESS, self._DEF_MSG_SEQ_NUM, self._DEF_MSG_SEQ_NUM,
- self._DEF_MASTER_SHA, self._DEF_SEGNO)
- new_seg = SegmentBase.new_from_data(self._DEF_ADDRESS, seg.packetize())
- assert new_seg.rt_msg_seq_num() == self._DEF_MSG_SEQ_NUM, "Segment RT message sequence number didn't match expected."
- assert new_seg.rt_master_sha() == self._DEF_MASTER_SHA, "Segment RT master SHA didn't match expected."
- assert new_seg.rt_segment_number() == self._DEF_SEGNO, "Segment RT segment number didn't match expected."
-
- def addToSuite(suite):
- suite.addTest(RetransmitSegmentTestCase("testInit"))
- suite.addTest(RetransmitSegmentTestCase("testNewFromParts"))
- suite.addTest(RetransmitSegmentTestCase("testNewFromData"))
- suite.addTest(RetransmitSegmentTestCase("testPartsToData"))
- addToSuite = staticmethod(addToSuite)
+ """Test RetransmitSegment class specific initialization and stuff."""
+
+ def _test_init_fail(self, segno, total_segs, msg_seq_num, master_sha, fail_msg):
+ try:
+ seg = RetransmitSegment(segno, total_segs, msg_seq_num, master_sha)
+ except ValueError, exc:
+ pass
+ else:
+ self.fail("expected a ValueError for %s." % fail_msg)
+
+ def testInit(self):
+ self._test_init_fail(0, 1, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid segment number")
+ self._test_init_fail(2, 1, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid segment number")
+ self._test_init_fail(1, 0, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid number of total segments")
+ self._test_init_fail(1, 2, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid number of total segments")
+
+ # Something that's supposed to work
+ seg = RetransmitSegment(1, 1, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA)
+ assert seg.segment_type() == SegmentBase.type_retransmit(), "Segment wasn't a retransmit segment."
+
+ def _test_new_from_parts_fail(self, msg_seq_num, rt_msg_seq_num, rt_master_sha, rt_segment_number, fail_msg):
+ try:
+ seg = RetransmitSegment.new_from_parts(self._DEF_ADDRESS, msg_seq_num, rt_msg_seq_num,
+ rt_master_sha, rt_segment_number)
+ except ValueError, exc:
+ pass
+ else:
+ self.fail("expected a ValueError for %s." % fail_msg)
+
+ def testNewFromParts(self):
+ """Test RetransmitSegment's new_from_parts() functionality."""
+ self._test_new_from_parts_fail(0, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA,
+ self._DEF_SEGNO, "invalid message sequence number")
+ self._test_new_from_parts_fail(65536, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA,
+ self._DEF_SEGNO, "invalid message sequence number")
+ self._test_new_from_parts_fail(None, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA,
+ self._DEF_SEGNO, "invalid message sequence number")
+ self._test_new_from_parts_fail("", self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA,
+ self._DEF_SEGNO, "invalid message sequence number")
+
+ self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, 0, self._DEF_MASTER_SHA,
+ self._DEF_SEGNO, "invalid retransmit message sequence number")
+ self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, 65536, self._DEF_MASTER_SHA,
+ self._DEF_SEGNO, "invalid retransmit message sequence number")
+ self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, None, self._DEF_MASTER_SHA,
+ self._DEF_SEGNO, "invalid retransmit message sequence number")
+ self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, "", self._DEF_MASTER_SHA,
+ self._DEF_SEGNO, "invalid retransmit message sequence number")
+
+ self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, self._DEF_MSG_SEQ_NUM, "1" * 19,
+ self._DEF_SEGNO, "invalid retransmit message master SHA")
+ self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, self._DEF_MSG_SEQ_NUM, "1" * 21,
+ self._DEF_SEGNO, "invalid retransmit message master SHA")
+ self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, self._DEF_MSG_SEQ_NUM, None,
+ self._DEF_SEGNO, "invalid retransmit message master SHA")
+ self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, self._DEF_MSG_SEQ_NUM, 1234,
+ self._DEF_SEGNO, "invalid retransmit message master SHA")
+
+ self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, self._DEF_MSG_SEQ_NUM,
+ self._DEF_MASTER_SHA, 0, "invalid retransmit message segment number")
+ self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, self._DEF_MSG_SEQ_NUM,
+ self._DEF_MASTER_SHA, 65536, "invalid retransmit message segment number")
+ self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, self._DEF_MSG_SEQ_NUM,
+ self._DEF_MASTER_SHA, None, "invalid retransmit message segment number")
+ self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, self._DEF_MSG_SEQ_NUM,
+ self._DEF_MASTER_SHA, "", "invalid retransmit message segment number")
+
+ # Ensure message data is same as we stuff in after object is instantiated
+ seg = RetransmitSegment.new_from_parts(self._DEF_ADDRESS, self._DEF_MSG_SEQ_NUM, self._DEF_MSG_SEQ_NUM,
+ self._DEF_MASTER_SHA, self._DEF_SEGNO)
+ assert seg.rt_msg_seq_num() == self._DEF_MSG_SEQ_NUM, "RT message sequence number after segment creation didn't match expected."
+ assert seg.rt_master_sha() == self._DEF_MASTER_SHA, "RT master SHA after segment creation didn't match expected."
+ assert seg.rt_segment_number() == self._DEF_SEGNO, "RT segment number after segment creation didn't match expected."
+
+ def _new_from_data(self, rt_msg_seq_num, rt_master_sha, rt_segment_number):
+ payload = struct.pack(RetransmitSegment.data_template(), rt_msg_seq_num, rt_master_sha, rt_segment_number)
+ payload_sha = _sha_data(payload)
+ header_template = SegmentBase.header_template()
+ header = struct.pack(header_template, self._SEG_MAGIC, SegmentBase.type_retransmit(), 1, 1,
+ self._DEF_MSG_SEQ_NUM, payload_sha)
+ return header + payload
+
+ def _test_new_from_data_fail(self, rt_msg_seq_num, rt_master_sha, rt_segment_number, fail_msg):
+ try:
+ packet = self._new_from_data(rt_msg_seq_num, rt_master_sha, rt_segment_number)
+ seg = SegmentBase.new_from_data(self._DEF_ADDRESS, packet)
+ except ValueError, exc:
+ pass
+ else:
+ self.fail("Expected a ValueError about %s." % fail_msg)
+
+ def testNewFromData(self):
+ """Test DataSegment's new_from_data() functionality."""
+ self._test_new_from_data_fail(0, self._DEF_MASTER_SHA, self._DEF_SEGNO, "invalid RT message sequence number")
+ self._test_new_from_data_fail(65536, self._DEF_MASTER_SHA, self._DEF_SEGNO, "invalid RT message sequence number")
+
+ self._test_new_from_data_fail(self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, 0, "invalid RT segment number")
+ self._test_new_from_data_fail(self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, 65536, "invalid RT segment number")
+
+ # Ensure something that should work
+ packet = self._new_from_data(self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, self._DEF_SEGNO)
+ seg = SegmentBase.new_from_data(self._DEF_ADDRESS, packet)
+ assert seg.segment_type() == SegmentBase.type_retransmit(), "Segment wasn't expected type."
+ assert seg.rt_msg_seq_num() == self._DEF_MSG_SEQ_NUM, "Segment RT message sequence number didn't match expected."
+ assert seg.rt_master_sha() == self._DEF_MASTER_SHA, "Segment RT master SHA didn't match expected."
+ assert seg.rt_segment_number() == self._DEF_SEGNO, "Segment RT segment number didn't match expected."
+
+ def testPartsToData(self):
+ seg = RetransmitSegment.new_from_parts(self._DEF_ADDRESS, self._DEF_MSG_SEQ_NUM, self._DEF_MSG_SEQ_NUM,
+ self._DEF_MASTER_SHA, self._DEF_SEGNO)
+ new_seg = SegmentBase.new_from_data(self._DEF_ADDRESS, seg.packetize())
+ assert new_seg.rt_msg_seq_num() == self._DEF_MSG_SEQ_NUM, "Segment RT message sequence number didn't match expected."
+ assert new_seg.rt_master_sha() == self._DEF_MASTER_SHA, "Segment RT master SHA didn't match expected."
+ assert new_seg.rt_segment_number() == self._DEF_SEGNO, "Segment RT segment number didn't match expected."
+
+ def addToSuite(suite):
+ suite.addTest(RetransmitSegmentTestCase("testInit"))
+ suite.addTest(RetransmitSegmentTestCase("testNewFromParts"))
+ suite.addTest(RetransmitSegmentTestCase("testNewFromData"))
+ suite.addTest(RetransmitSegmentTestCase("testPartsToData"))
+ addToSuite = staticmethod(addToSuite)
class SHAUtilsTestCase(unittest.TestCase):
- def testSHA(self):
- data = "235jklqt3hjwasdv879wfe89723rqjh32tr3hwaejksdvd89udsv89dsgiougjktqjhk23tjht23hjt3qhjewagthjasgdgsd"
- data_sha = _sha_data(data)
- assert len(data_sha) == 20, "SHA wasn't correct size."
- known_sha = "\xee\x9e\xb9\x1d\xe8\x96\x75\xcb\x12\xf1\x25\x22\x0f\x76\xf7\xf3\xc8\x4e\xbf\xcd"
- assert data_sha == known_sha, "SHA didn't match known SHA."
+ def testSHA(self):
+ data = "235jklqt3hjwasdv879wfe89723rqjh32tr3hwaejksdvd89udsv89dsgiougjktqjhk23tjht23hjt3qhjewagthjasgdgsd"
+ data_sha = _sha_data(data)
+ assert len(data_sha) == 20, "SHA wasn't correct size."
+ known_sha = "\xee\x9e\xb9\x1d\xe8\x96\x75\xcb\x12\xf1\x25\x22\x0f\x76\xf7\xf3\xc8\x4e\xbf\xcd"
+ assert data_sha == known_sha, "SHA didn't match known SHA."
- def testStringifySHA(self):
- data = "jlkwjlkaegdjlksgdjklsdgajklganjtwn23n325n23tjwgeajkga nafDA fwqnjlqtjkl23tjk2365jlk235jkl2356jlktjkltewjlktewjklewtjklaggsda"
- data_known_sha = "9650c23db78092a0ffda4577c87ebf36d25c868e"
- assert _stringify_sha(_sha_data(data)) == data_known_sha, "SHA stringify didn't return correct SHA."
- # Do it twice for kicks
- assert _stringify_sha(_sha_data(data)) == data_known_sha, "SHA stringify didn't return correct SHA."
+ def testStringifySHA(self):
+ data = "jlkwjlkaegdjlksgdjklsdgajklganjtwn23n325n23tjwgeajkga nafDA fwqnjlqtjkl23tjk2365jlk235jkl2356jlktjkltewjlktewjklewtjklaggsda"
+ data_known_sha = "9650c23db78092a0ffda4577c87ebf36d25c868e"
+ assert _stringify_sha(_sha_data(data)) == data_known_sha, "SHA stringify didn't return correct SHA."
+ # Do it twice for kicks
+ assert _stringify_sha(_sha_data(data)) == data_known_sha, "SHA stringify didn't return correct SHA."
- def addToSuite(suite):
- suite.addTest(SHAUtilsTestCase("testSHA"))
- suite.addTest(SHAUtilsTestCase("testStringifySHA"))
- addToSuite = staticmethod(addToSuite)
+ def addToSuite(suite):
+ suite.addTest(SHAUtilsTestCase("testSHA"))
+ suite.addTest(SHAUtilsTestCase("testStringifySHA"))
+ addToSuite = staticmethod(addToSuite)
def unit_test():
- suite = unittest.TestSuite()
- SegmentBaseInitTestCase.addToSuite(suite)
- DataSegmentTestCase.addToSuite(suite)
- RetransmitSegmentTestCase.addToSuite(suite)
- SHAUtilsTestCase.addToSuite(suite)
+ suite = unittest.TestSuite()
+ SegmentBaseInitTestCase.addToSuite(suite)
+ DataSegmentTestCase.addToSuite(suite)
+ RetransmitSegmentTestCase.addToSuite(suite)
+ SHAUtilsTestCase.addToSuite(suite)
- runner = unittest.TextTestRunner()
- runner.run(suite)
+ runner = unittest.TextTestRunner()
+ runner.run(suite)
def got_data(addr, data, user_data=None):
- print "Got data from %s, writing to %s." % (addr, user_data)
- fl = open(user_data, "w+")
- fl.write(data)
- fl.close()
+ print "Got data from %s, writing to %s." % (addr, user_data)
+ fl = open(user_data, "w+")
+ fl.write(data)
+ fl.close()
def simple_test():
- import sys
- pipe = MostlyReliablePipe('', '224.0.0.222', 2293, got_data, sys.argv[2])
-# pipe.set_drop_probability(4)
- pipe.start()
- fl = open(sys.argv[1], "r")
- data = fl.read()
- fl.close()
- msg = """The said Eliza, John, and Georgiana were now clustered round their mama in the drawing-room:
+ import sys
+ pipe = MostlyReliablePipe('', '224.0.0.222', 2293, got_data, sys.argv[2])
+# pipe.set_drop_probability(4)
+ pipe.start()
+ fl = open(sys.argv[1], "r")
+ data = fl.read()
+ fl.close()
+ msg = """The said Eliza, John, and Georgiana were now clustered round their mama in the drawing-room:
she lay reclined on a sofa by the fireside, and with her darlings about her (for the time neither
quarrelling nor crying) looked perfectly happy. Me, she had dispensed from joining the group; saying,
'She regretted to be under the necessity of keeping me at a distance; but that until she heard from
@@ -1337,58 +1337,58 @@ Bessie, and could discover by her own observation, that I was endeavouring in go
a more sociable and childlike disposition, a more attractive and sprightly manner -- something lighter,
franker, more natural, as it were -- she really must exclude me from privileges intended only for
contented, happy, little children.'"""
- pipe.send(data)
- try:
- gtk.main()
- except KeyboardInterrupt:
- print 'Ctrl+C pressed, exiting...'
+ pipe.send(data)
+ try:
+ gtk.main()
+ except KeyboardInterrupt:
+ print 'Ctrl+C pressed, exiting...'
def net_test_got_data(addr, data, user_data=None):
- # Don't report data if we are a sender
- if user_data:
- return
- print "%s (%s)" % (data, addr)
+ # Don't report data if we are a sender
+ if user_data:
+ return
+ print "%s (%s)" % (data, addr)
idstamp = 0
def transmit_data(pipe):
- global idstamp
- msg = "Message #%d" % idstamp
- print "Sending '%s'" % msg
- pipe.send(msg)
- idstamp = idstamp + 1
- return True
+ global idstamp
+ msg = "Message #%d" % idstamp
+ print "Sending '%s'" % msg
+ pipe.send(msg)
+ idstamp = idstamp + 1
+ return True
def network_test():
- import sys, os
- send = False
- if len(sys.argv) != 2:
- print "Need one arg, either 'send' or 'recv'"
- os._exit(1)
- if sys.argv[1] == "send":
- send = True
- elif sys.argv[1] == "recv":
- send = False
- else:
- print "Arg should be either 'send' or 'recv'"
- os._exit(1)
-
- pipe = MostlyReliablePipe('', '224.0.0.222', 2293, net_test_got_data, send)
- pipe.start()
- if send:
- gobject.timeout_add(1000, transmit_data, pipe)
- try:
- gtk.main()
- except KeyboardInterrupt:
- print 'Ctrl+C pressed, exiting...'
+ import sys, os
+ send = False
+ if len(sys.argv) != 2:
+ print "Need one arg, either 'send' or 'recv'"
+ os._exit(1)
+ if sys.argv[1] == "send":
+ send = True
+ elif sys.argv[1] == "recv":
+ send = False
+ else:
+ print "Arg should be either 'send' or 'recv'"
+ os._exit(1)
+
+ pipe = MostlyReliablePipe('', '224.0.0.222', 2293, net_test_got_data, send)
+ pipe.start()
+ if send:
+ gobject.timeout_add(1000, transmit_data, pipe)
+ try:
+ gtk.main()
+ except KeyboardInterrupt:
+ print 'Ctrl+C pressed, exiting...'
def main():
-# unit_test()
-# simple_test()
- network_test()
+# unit_test()
+# simple_test()
+ network_test()
if __name__ == "__main__":
- main()
+ main()
diff --git a/sugar/p2p/NotificationListener.py b/sugar/p2p/NotificationListener.py
index f68bbb2..42668ad 100644
--- a/sugar/p2p/NotificationListener.py
+++ b/sugar/p2p/NotificationListener.py
@@ -21,18 +21,18 @@ from sugar.p2p.Notifier import Notifier
from sugar.p2p import network
class NotificationListener:
- def __init__(self, service):
- logging.debug('Start notification listener. Service %s, address %s, port %s' % (service.get_type(), service.get_address(), service.get_port()))
- server = network.GroupServer(service.get_address(),
- service.get_port(),
- self._recv_multicast)
- server.start()
-
- self._listeners = []
-
- def add_listener(self, listener):
- self._listeners.append(listener)
-
- def _recv_multicast(self, msg):
- for listener in self._listeners:
- listener(msg)
+ def __init__(self, service):
+ logging.debug('Start notification listener. Service %s, address %s, port %s' % (service.get_type(), service.get_address(), service.get_port()))
+ server = network.GroupServer(service.get_address(),
+ service.get_port(),
+ self._recv_multicast)
+ server.start()
+
+ self._listeners = []
+
+ def add_listener(self, listener):
+ self._listeners.append(listener)
+
+ def _recv_multicast(self, msg):
+ for listener in self._listeners:
+ listener(msg)
diff --git a/sugar/p2p/Notifier.py b/sugar/p2p/Notifier.py
index f216fda..69d0af6 100644
--- a/sugar/p2p/Notifier.py
+++ b/sugar/p2p/Notifier.py
@@ -18,10 +18,10 @@
from sugar.p2p import network
class Notifier:
- def __init__(self, service):
- address = service.get_address()
- port = service.get_port()
- self._client = network.GroupClient(address, port)
-
- def notify(self, msg):
- self._client.send_msg(msg)
+ def __init__(self, service):
+ address = service.get_address()
+ port = service.get_port()
+ self._client = network.GroupClient(address, port)
+
+ def notify(self, msg):
+ self._client.send_msg(msg)
diff --git a/sugar/p2p/Stream.py b/sugar/p2p/Stream.py
index edb4d1b..b3239b3 100644
--- a/sugar/p2p/Stream.py
+++ b/sugar/p2p/Stream.py
@@ -26,135 +26,135 @@ from MostlyReliablePipe import MostlyReliablePipe
from sugar.presence import Service
def is_multicast_address(address):
- """Simple numerical check for whether an IP4 address
- is in the range for multicast addresses or not."""
- if not address:
- return False
- if address[3] != '.':
- return False
- first = int(float(address[:3]))
- if first >= 224 and first <= 239:
- return True
- return False
+ """Simple numerical check for whether an IP4 address
+ is in the range for multicast addresses or not."""
+ if not address:
+ return False
+ if address[3] != '.':
+ return False
+ first = int(float(address[:3]))
+ if first >= 224 and first <= 239:
+ return True
+ return False
class Stream(object):
- def __init__(self, service):
- if not service.get_port():
- raise ValueError("service must have an address.")
- self._service = service
- self._reader_port = self._service.get_port()
- self._writer_port = self._reader_port
- self._address = self._service.get_address()
- self._callback = None
-
- def new_from_service(service, start_reader=True):
- if is_multicast_address(service.get_address()):
- return MulticastStream(service)
- else:
- return UnicastStream(service, start_reader)
- new_from_service = staticmethod(new_from_service)
-
- def set_data_listener(self, callback):
- self._callback = callback
-
- def _recv(self, address, data):
- if self._callback:
- self._callback(address, data)
+ def __init__(self, service):
+ if not service.get_port():
+ raise ValueError("service must have an address.")
+ self._service = service
+ self._reader_port = self._service.get_port()
+ self._writer_port = self._reader_port
+ self._address = self._service.get_address()
+ self._callback = None
+
+ def new_from_service(service, start_reader=True):
+ if is_multicast_address(service.get_address()):
+ return MulticastStream(service)
+ else:
+ return UnicastStream(service, start_reader)
+ new_from_service = staticmethod(new_from_service)
+
+ def set_data_listener(self, callback):
+ self._callback = callback
+
+ def _recv(self, address, data):
+ if self._callback:
+ self._callback(address, data)
class UnicastStreamWriter(object):
- def __init__(self, stream, service):
- # set up the writer
- self._service = service
- if not service.get_address():
- raise ValueError("service must have a valid address.")
- self._address = self._service.get_address()
- self._port = self._service.get_port()
- self._xmlrpc_addr = "http://%s:%d" % (self._address, self._port)
- self._writer = network.GlibServerProxy(self._xmlrpc_addr)
-
- def write(self, xmlrpc_data):
- """Write some data to the default endpoint of this pipe on the remote server."""
- try:
- self._writer.message(None, None, xmlrpc_data)
- return True
- except (socket.error, xmlrpclib.Fault, xmlrpclib.ProtocolError):
- traceback.print_exc()
- return False
-
- def custom_request(self, method_name, request_cb, user_data, *args):
- """Call a custom XML-RPC method on the remote server."""
- try:
- method = getattr(self._writer, method_name)
- method(request_cb, user_data, *args)
- return True
- except (socket.error, xmlrpclib.Fault, xmlrpclib.ProtocolError):
- traceback.print_exc()
- return False
+ def __init__(self, stream, service):
+ # set up the writer
+ self._service = service
+ if not service.get_address():
+ raise ValueError("service must have a valid address.")
+ self._address = self._service.get_address()
+ self._port = self._service.get_port()
+ self._xmlrpc_addr = "http://%s:%d" % (self._address, self._port)
+ self._writer = network.GlibServerProxy(self._xmlrpc_addr)
+
+ def write(self, xmlrpc_data):
+ """Write some data to the default endpoint of this pipe on the remote server."""
+ try:
+ self._writer.message(None, None, xmlrpc_data)
+ return True
+ except (socket.error, xmlrpclib.Fault, xmlrpclib.ProtocolError):
+ traceback.print_exc()
+ return False
+
+ def custom_request(self, method_name, request_cb, user_data, *args):
+ """Call a custom XML-RPC method on the remote server."""
+ try:
+ method = getattr(self._writer, method_name)
+ method(request_cb, user_data, *args)
+ return True
+ except (socket.error, xmlrpclib.Fault, xmlrpclib.ProtocolError):
+ traceback.print_exc()
+ return False
class UnicastStream(Stream):
- def __init__(self, service, start_reader=True):
- """Initializes the stream. If the 'start_reader' argument is True,
- the stream will initialize and start a new stream reader, if it
- is False, no reader will be created and the caller must call the
- start_reader() method to start the stream reader and be able to
- receive any data from the stream."""
- Stream.__init__(self, service)
- if start_reader:
- self.start_reader()
-
- def start_reader(self):
- """Start the stream's reader, which for UnicastStream objects is
- and XMLRPC server. If there's a port conflict with some other
- service, the reader will try to find another port to use instead.
- Returns the port number used for the reader."""
- # Set up the reader
- self._reader = network.GlibXMLRPCServer(("", self._reader_port))
- self._reader.register_function(self._message, "message")
-
- def _message(self, message):
- """Called by the XMLRPC server when network data arrives."""
- address = network.get_authinfo()
- self._recv(address, message)
- return True
-
- def register_reader_handler(self, handler, name):
- """Register a custom message handler with the reader. This call
- adds a custom XMLRPC method call with the name 'name' to the reader's
- XMLRPC server, which then calls the 'handler' argument back when
- a method call for it arrives over the network."""
- if name == "message":
- raise ValueError("Handler name 'message' is a reserved handler.")
- self._reader.register_function(handler, name)
-
- def new_writer(self, service):
- """Return a new stream writer object."""
- return UnicastStreamWriter(self, service)
+ def __init__(self, service, start_reader=True):
+ """Initializes the stream. If the 'start_reader' argument is True,
+ the stream will initialize and start a new stream reader, if it
+ is False, no reader will be created and the caller must call the
+ start_reader() method to start the stream reader and be able to
+ receive any data from the stream."""
+ Stream.__init__(self, service)
+ if start_reader:
+ self.start_reader()
+
+ def start_reader(self):
+ """Start the stream's reader, which for UnicastStream objects is
+ and XMLRPC server. If there's a port conflict with some other
+ service, the reader will try to find another port to use instead.
+ Returns the port number used for the reader."""
+ # Set up the reader
+ self._reader = network.GlibXMLRPCServer(("", self._reader_port))
+ self._reader.register_function(self._message, "message")
+
+ def _message(self, message):
+ """Called by the XMLRPC server when network data arrives."""
+ address = network.get_authinfo()
+ self._recv(address, message)
+ return True
+
+ def register_reader_handler(self, handler, name):
+ """Register a custom message handler with the reader. This call
+ adds a custom XMLRPC method call with the name 'name' to the reader's
+ XMLRPC server, which then calls the 'handler' argument back when
+ a method call for it arrives over the network."""
+ if name == "message":
+ raise ValueError("Handler name 'message' is a reserved handler.")
+ self._reader.register_function(handler, name)
+
+ def new_writer(self, service):
+ """Return a new stream writer object."""
+ return UnicastStreamWriter(self, service)
class MulticastStream(Stream):
- def __init__(self, service):
- Stream.__init__(self, service)
- self._service = service
- self._internal_start_reader()
-
- def start_reader(self):
- return self._reader_port
-
- def _internal_start_reader(self):
- logging.debug('Start multicast stream, address %s, port %d' % (self._address, self._reader_port))
- if not self._service.get_address():
- raise ValueError("service must have a valid address.")
- self._pipe = MostlyReliablePipe('', self._address, self._reader_port,
- self._recv_data_cb)
- self._pipe.start()
-
- def write(self, data):
- self._pipe.send(data)
-
- def _recv_data_cb(self, address, data, user_data=None):
- self._recv(address[0], data)
-
- def new_writer(self, service=None):
- return self
+ def __init__(self, service):
+ Stream.__init__(self, service)
+ self._service = service
+ self._internal_start_reader()
+
+ def start_reader(self):
+ return self._reader_port
+
+ def _internal_start_reader(self):
+ logging.debug('Start multicast stream, address %s, port %d' % (self._address, self._reader_port))
+ if not self._service.get_address():
+ raise ValueError("service must have a valid address.")
+ self._pipe = MostlyReliablePipe('', self._address, self._reader_port,
+ self._recv_data_cb)
+ self._pipe.start()
+
+ def write(self, data):
+ self._pipe.send(data)
+
+ def _recv_data_cb(self, address, data, user_data=None):
+ self._recv(address[0], data)
+
+ def new_writer(self, service=None):
+ return self
diff --git a/sugar/p2p/network.py b/sugar/p2p/network.py
index 6718669..e5b4e4b 100644
--- a/sugar/p2p/network.py
+++ b/sugar/p2p/network.py
@@ -35,347 +35,347 @@ RESULT_SUCCESS = 1
__authinfos = {}
def _add_authinfo(authinfo):
- __authinfos[threading.currentThread()] = authinfo
+ __authinfos[threading.currentThread()] = authinfo
def get_authinfo():
- return __authinfos.get(threading.currentThread())
+ return __authinfos.get(threading.currentThread())
def _del_authinfo():
- del __authinfos[threading.currentThread()]
+ del __authinfos[threading.currentThread()]
class GlibTCPServer(SocketServer.TCPServer):
- """GlibTCPServer
+ """GlibTCPServer
- Integrate socket accept into glib mainloop.
- """
+ Integrate socket accept into glib mainloop.
+ """
- allow_reuse_address = True
- request_queue_size = 20
+ allow_reuse_address = True
+ request_queue_size = 20
- def __init__(self, server_address, RequestHandlerClass):
- SocketServer.TCPServer.__init__(self, server_address, RequestHandlerClass)
- self.socket.setblocking(0) # Set nonblocking
+ def __init__(self, server_address, RequestHandlerClass):
+ SocketServer.TCPServer.__init__(self, server_address, RequestHandlerClass)
+ self.socket.setblocking(0) # Set nonblocking
- # Watch the listener socket for data
- gobject.io_add_watch(self.socket, gobject.IO_IN, self._handle_accept)
+ # Watch the listener socket for data
+ gobject.io_add_watch(self.socket, gobject.IO_IN, self._handle_accept)
- def _handle_accept(self, source, condition):
- """Process incoming data on the server's socket by doing an accept()
- via handle_request()."""
- if not (condition & gobject.IO_IN):
- return True
- self.handle_request()
- return True
+ def _handle_accept(self, source, condition):
+ """Process incoming data on the server's socket by doing an accept()
+ via handle_request()."""
+ if not (condition & gobject.IO_IN):
+ return True
+ self.handle_request()
+ return True
class GlibXMLRPCRequestHandler(SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
- """ GlibXMLRPCRequestHandler
-
- The stock SimpleXMLRPCRequestHandler and server don't allow any way to pass
- the client's address and/or SSL certificate into the function that actually
- _processes_ the request. So we have to store it in a thread-indexed dict.
- """
-
- def do_POST(self):
- _add_authinfo(self.client_address)
- try:
- SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.do_POST(self)
- except socket.timeout:
- pass
- except socket.error, e:
- print "Error (%s): socket error - '%s'" % (self.client_address, e)
- except:
- print "Error while processing POST:"
- traceback.print_exc()
- _del_authinfo()
+ """ GlibXMLRPCRequestHandler
+
+ The stock SimpleXMLRPCRequestHandler and server don't allow any way to pass
+ the client's address and/or SSL certificate into the function that actually
+ _processes_ the request. So we have to store it in a thread-indexed dict.
+ """
+
+ def do_POST(self):
+ _add_authinfo(self.client_address)
+ try:
+ SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.do_POST(self)
+ except socket.timeout:
+ pass
+ except socket.error, e:
+ print "Error (%s): socket error - '%s'" % (self.client_address, e)
+ except:
+ print "Error while processing POST:"
+ traceback.print_exc()
+ _del_authinfo()
class GlibXMLRPCServer(GlibTCPServer, SimpleXMLRPCServer.SimpleXMLRPCDispatcher):
- """GlibXMLRPCServer
-
- Use nonblocking sockets and handle the accept via glib rather than
- blocking on accept().
- """
-
- def __init__(self, addr, requestHandler=GlibXMLRPCRequestHandler, logRequests=0):
- self.logRequests = logRequests
- SimpleXMLRPCServer.SimpleXMLRPCDispatcher.__init__(self)
- GlibTCPServer.__init__(self, addr, requestHandler)
-
- def _marshaled_dispatch(self, data, dispatch_method = None):
- """Dispatches an XML-RPC method from marshalled (XML) data.
-
- XML-RPC methods are dispatched from the marshalled (XML) data
- using the _dispatch method and the result is returned as
- marshalled data. For backwards compatibility, a dispatch
- function can be provided as an argument (see comment in
- SimpleXMLRPCRequestHandler.do_POST) but overriding the
- existing method through subclassing is the prefered means
- of changing method dispatch behavior.
- """
-
- params, method = xmlrpclib.loads(data)
-
- # generate response
- try:
- if dispatch_method is not None:
- response = dispatch_method(method, params)
- else:
- response = self._dispatch(method, params)
- # wrap response in a singleton tuple
- response = (response,)
- response = xmlrpclib.dumps(response, methodresponse=1)
- except xmlrpclib.Fault, fault:
- response = xmlrpclib.dumps(fault)
- except:
- print "Exception while processing request:"
- traceback.print_exc()
-
- # report exception back to server
- response = xmlrpclib.dumps(
- xmlrpclib.Fault(1, "%s:%s" % (sys.exc_type, sys.exc_value))
- )
-
- return response
+ """GlibXMLRPCServer
+
+ Use nonblocking sockets and handle the accept via glib rather than
+ blocking on accept().
+ """
+
+ def __init__(self, addr, requestHandler=GlibXMLRPCRequestHandler, logRequests=0):
+ self.logRequests = logRequests
+ SimpleXMLRPCServer.SimpleXMLRPCDispatcher.__init__(self)
+ GlibTCPServer.__init__(self, addr, requestHandler)
+
+ def _marshaled_dispatch(self, data, dispatch_method = None):
+ """Dispatches an XML-RPC method from marshalled (XML) data.
+
+ XML-RPC methods are dispatched from the marshalled (XML) data
+ using the _dispatch method and the result is returned as
+ marshalled data. For backwards compatibility, a dispatch
+ function can be provided as an argument (see comment in
+ SimpleXMLRPCRequestHandler.do_POST) but overriding the
+ existing method through subclassing is the prefered means
+ of changing method dispatch behavior.
+ """
+
+ params, method = xmlrpclib.loads(data)
+
+ # generate response
+ try:
+ if dispatch_method is not None:
+ response = dispatch_method(method, params)
+ else:
+ response = self._dispatch(method, params)
+ # wrap response in a singleton tuple
+ response = (response,)
+ response = xmlrpclib.dumps(response, methodresponse=1)
+ except xmlrpclib.Fault, fault:
+ response = xmlrpclib.dumps(fault)
+ except:
+ print "Exception while processing request:"
+ traceback.print_exc()
+
+ # report exception back to server
+ response = xmlrpclib.dumps(
+ xmlrpclib.Fault(1, "%s:%s" % (sys.exc_type, sys.exc_value))
+ )
+
+ return response
class GlibHTTP(httplib.HTTP):
- """Subclass HTTP so we can return it's connection class' socket."""
- def connect(self, host=None, port=None):
- httplib.HTTP.connect(self, host, port)
- self._conn.sock.setblocking(0)
- def get_sock(self):
- return self._conn.sock
+ """Subclass HTTP so we can return it's connection class' socket."""
+ def connect(self, host=None, port=None):
+ httplib.HTTP.connect(self, host, port)
+ self._conn.sock.setblocking(0)
+ def get_sock(self):
+ return self._conn.sock
class GlibXMLRPCTransport(xmlrpclib.Transport):
- """Integrate the request with the glib mainloop rather than blocking."""
- ##
- # Connect to server.
- #
- # @param host Target host.
- # @return A connection handle.
-
- def __init__(self):
- pass
-
- def make_connection(self, host):
- """Use our own connection object so we can get its socket."""
- # create a HTTP connection object from a host descriptor
- host, extra_headers, x509 = self.get_host_info(host)
- return GlibHTTP(host)
-
- ##
- # Send a complete request, and parse the response.
- #
- # @param host Target host.
- # @param handler Target PRC handler.
- # @param request_body XML-RPC request body.
- # @param verbose Debugging flag.
- # @return Parsed response.
-
- def start_request(self, host, handler, request_body, verbose=0, request_cb=None, user_data=None):
- """Do the first half of the request by sending data to the remote
- server. The bottom half bits get run when the remote server's response
- actually comes back."""
- # issue XML-RPC request
-
- h = self.make_connection(host)
- if verbose:
- h.set_debuglevel(1)
-
- self.send_request(h, handler, request_body)
- self.send_host(h, host)
- self.send_user_agent(h)
- self.send_content(h, request_body)
-
- # Schedule a GIOWatch so we don't block waiting for the response
- gobject.io_add_watch(h.get_sock(), gobject.IO_IN, self._finish_request,
- h, host, handler, verbose, request_cb, user_data)
-
- def _finish_request(self, source, condition, h, host, handler, verbose, request_cb, user_data):
- """Parse and return response when the remote server actually returns it."""
- if not (condition & gobject.IO_IN):
- return True
-
- try:
- errcode, errmsg, headers = h.getreply()
- except socket.error, err:
- if err[0] != 104:
- raise socket.error(err)
- else:
- gobject.idle_add(request_cb, RESULT_FAILED, None, user_data)
- return False
-
- if errcode != 200:
- raise xmlrpclib.ProtocolError(host + handler, errcode, errmsg, headers)
- self.verbose = verbose
- response = self._parse_response(h.getfile(), h.get_sock())
- if request_cb:
- if len(response) == 1:
- response = response[0]
- gobject.idle_add(request_cb, RESULT_SUCCESS, response, user_data)
- return False
+ """Integrate the request with the glib mainloop rather than blocking."""
+ ##
+ # Connect to server.
+ #
+ # @param host Target host.
+ # @return A connection handle.
+
+ def __init__(self):
+ pass
+
+ def make_connection(self, host):
+ """Use our own connection object so we can get its socket."""
+ # create a HTTP connection object from a host descriptor
+ host, extra_headers, x509 = self.get_host_info(host)
+ return GlibHTTP(host)
+
+ ##
+ # Send a complete request, and parse the response.
+ #
+ # @param host Target host.
+ # @param handler Target PRC handler.
+ # @param request_body XML-RPC request body.
+ # @param verbose Debugging flag.
+ # @return Parsed response.
+
+ def start_request(self, host, handler, request_body, verbose=0, request_cb=None, user_data=None):
+ """Do the first half of the request by sending data to the remote
+ server. The bottom half bits get run when the remote server's response
+ actually comes back."""
+ # issue XML-RPC request
+
+ h = self.make_connection(host)
+ if verbose:
+ h.set_debuglevel(1)
+
+ self.send_request(h, handler, request_body)
+ self.send_host(h, host)
+ self.send_user_agent(h)
+ self.send_content(h, request_body)
+
+ # Schedule a GIOWatch so we don't block waiting for the response
+ gobject.io_add_watch(h.get_sock(), gobject.IO_IN, self._finish_request,
+ h, host, handler, verbose, request_cb, user_data)
+
+ def _finish_request(self, source, condition, h, host, handler, verbose, request_cb, user_data):
+ """Parse and return response when the remote server actually returns it."""
+ if not (condition & gobject.IO_IN):
+ return True
+
+ try:
+ errcode, errmsg, headers = h.getreply()
+ except socket.error, err:
+ if err[0] != 104:
+ raise socket.error(err)
+ else:
+ gobject.idle_add(request_cb, RESULT_FAILED, None, user_data)
+ return False
+
+ if errcode != 200:
+ raise xmlrpclib.ProtocolError(host + handler, errcode, errmsg, headers)
+ self.verbose = verbose
+ response = self._parse_response(h.getfile(), h.get_sock())
+ if request_cb:
+ if len(response) == 1:
+ response = response[0]
+ gobject.idle_add(request_cb, RESULT_SUCCESS, response, user_data)
+ return False
class _Method:
- """Right, so python people thought it would be funny to make this
- class private to xmlrpclib.py..."""
- # some magic to bind an XML-RPC method to an RPC server.
- # supports "nested" methods (e.g. examples.getStateName)
- def __init__(self, send, name):
- self.__send = send
- self.__name = name
- def __getattr__(self, name):
- return _Method(self.__send, "%s.%s" % (self.__name, name))
- def __call__(self, request_cb, user_data, *args):
- return self.__send(self.__name, request_cb, user_data, args)
+ """Right, so python people thought it would be funny to make this
+ class private to xmlrpclib.py..."""
+ # some magic to bind an XML-RPC method to an RPC server.
+ # supports "nested" methods (e.g. examples.getStateName)
+ def __init__(self, send, name):
+ self.__send = send
+ self.__name = name
+ def __getattr__(self, name):
+ return _Method(self.__send, "%s.%s" % (self.__name, name))
+ def __call__(self, request_cb, user_data, *args):
+ return self.__send(self.__name, request_cb, user_data, args)
class GlibServerProxy(xmlrpclib.ServerProxy):
- """Subclass xmlrpclib.ServerProxy so we can run the XML-RPC request
- in two parts, integrated with the glib mainloop, such that we don't
- block anywhere.
-
- Using this object is somewhat special; it requires more arguments to each
- XML-RPC request call than the normal xmlrpclib.ServerProxy object:
-
- client = GlibServerProxy("http://127.0.0.1:8888")
- user_data = "bar"
- xmlrpc_arg1 = "test"
- xmlrpc_arg2 = "foo"
- client.test(xmlrpc_test_cb, user_data, xmlrpc_arg1, xmlrpc_arg2)
-
- Here, 'xmlrpc_test_cb' is the callback function, which has the following
- signature:
-
- def xmlrpc_test_cb(result_status, response, user_data=None):
- ...
- """
- def __init__(self, uri, encoding=None, verbose=0, allow_none=0):
- self._transport = GlibXMLRPCTransport()
- self._encoding = encoding
- self._verbose = verbose
- self._allow_none = allow_none
- xmlrpclib.ServerProxy.__init__(self, uri, self._transport, encoding, verbose, allow_none)
-
- # get the url
- import urllib
- urltype, uri = urllib.splittype(uri)
- if urltype not in ("http", "https"):
- raise IOError, "unsupported XML-RPC protocol"
- self._host, self._handler = urllib.splithost(uri)
- if not self._handler:
- self._handler = "/RPC2"
-
- def __request(self, methodname, request_cb, user_data, params):
- """Call the method on the remote server. We just start the request here
- and the transport itself takes care of scheduling the response callback
- when the remote server returns the response. We don't want to block anywhere."""
-
- request = xmlrpclib.dumps(params, methodname, encoding=self._encoding,
- allow_none=self._allow_none)
-
- try:
- response = self._transport.start_request(
- self._host,
- self._handler,
- request,
- verbose=self._verbose,
- request_cb=request_cb,
- user_data=user_data
- )
- except socket.error, exc:
- gobject.idle_add(request_cb, RESULT_FAILED, None, user_data)
-
- def __getattr__(self, name):
- # magic method dispatcher
- return _Method(self.__request, name)
+ """Subclass xmlrpclib.ServerProxy so we can run the XML-RPC request
+ in two parts, integrated with the glib mainloop, such that we don't
+ block anywhere.
+
+ Using this object is somewhat special; it requires more arguments to each
+ XML-RPC request call than the normal xmlrpclib.ServerProxy object:
+
+ client = GlibServerProxy("http://127.0.0.1:8888")
+ user_data = "bar"
+ xmlrpc_arg1 = "test"
+ xmlrpc_arg2 = "foo"
+ client.test(xmlrpc_test_cb, user_data, xmlrpc_arg1, xmlrpc_arg2)
+
+ Here, 'xmlrpc_test_cb' is the callback function, which has the following
+ signature:
+
+ def xmlrpc_test_cb(result_status, response, user_data=None):
+ ...
+ """
+ def __init__(self, uri, encoding=None, verbose=0, allow_none=0):
+ self._transport = GlibXMLRPCTransport()
+ self._encoding = encoding
+ self._verbose = verbose
+ self._allow_none = allow_none
+ xmlrpclib.ServerProxy.__init__(self, uri, self._transport, encoding, verbose, allow_none)
+
+ # get the url
+ import urllib
+ urltype, uri = urllib.splittype(uri)
+ if urltype not in ("http", "https"):
+ raise IOError, "unsupported XML-RPC protocol"
+ self._host, self._handler = urllib.splithost(uri)
+ if not self._handler:
+ self._handler = "/RPC2"
+
+ def __request(self, methodname, request_cb, user_data, params):
+ """Call the method on the remote server. We just start the request here
+ and the transport itself takes care of scheduling the response callback
+ when the remote server returns the response. We don't want to block anywhere."""
+
+ request = xmlrpclib.dumps(params, methodname, encoding=self._encoding,
+ allow_none=self._allow_none)
+
+ try:
+ response = self._transport.start_request(
+ self._host,
+ self._handler,
+ request,
+ verbose=self._verbose,
+ request_cb=request_cb,
+ user_data=user_data
+ )
+ except socket.error, exc:
+ gobject.idle_add(request_cb, RESULT_FAILED, None, user_data)
+
+ def __getattr__(self, name):
+ # magic method dispatcher
+ return _Method(self.__request, name)
class GroupServer(object):
- _MAX_MSG_SIZE = 500
+ _MAX_MSG_SIZE = 500
- def __init__(self, address, port, data_cb):
- self._address = address
- self._port = port
- self._data_cb = data_cb
+ def __init__(self, address, port, data_cb):
+ self._address = address
+ self._port = port
+ self._data_cb = data_cb
- self._setup_listener()
+ self._setup_listener()
- def _setup_listener(self):
- # Listener socket
- self._listen_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ def _setup_listener(self):
+ # Listener socket
+ self._listen_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- # Set some options to make it multicast-friendly
- self._listen_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_TTL, 20)
- self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_LOOP, 1)
+ # Set some options to make it multicast-friendly
+ self._listen_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_TTL, 20)
+ self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_LOOP, 1)
- def start(self):
- # Set some more multicast options
- self._listen_sock.bind(('', self._port))
- self._listen_sock.settimeout(2)
- intf = socket.gethostbyname(socket.gethostname())
- self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_IF, socket.inet_aton(intf) + socket.inet_aton('0.0.0.0'))
- self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_ADD_MEMBERSHIP, socket.inet_aton(self._address) + socket.inet_aton('0.0.0.0'))
+ def start(self):
+ # Set some more multicast options
+ self._listen_sock.bind(('', self._port))
+ self._listen_sock.settimeout(2)
+ intf = socket.gethostbyname(socket.gethostname())
+ self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_IF, socket.inet_aton(intf) + socket.inet_aton('0.0.0.0'))
+ self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_ADD_MEMBERSHIP, socket.inet_aton(self._address) + socket.inet_aton('0.0.0.0'))
- # Watch the listener socket for data
- gobject.io_add_watch(self._listen_sock, gobject.IO_IN, self._handle_incoming_data)
+ # Watch the listener socket for data
+ gobject.io_add_watch(self._listen_sock, gobject.IO_IN, self._handle_incoming_data)
- def _handle_incoming_data(self, source, condition):
- if not (condition & gobject.IO_IN):
- return True
- msg = {}
- msg['data'], (msg['addr'], msg['port']) = source.recvfrom(self._MAX_MSG_SIZE)
- if self._data_cb:
- self._data_cb(msg)
- return True
+ def _handle_incoming_data(self, source, condition):
+ if not (condition & gobject.IO_IN):
+ return True
+ msg = {}
+ msg['data'], (msg['addr'], msg['port']) = source.recvfrom(self._MAX_MSG_SIZE)
+ if self._data_cb:
+ self._data_cb(msg)
+ return True
class GroupClient(object):
- _MAX_MSG_SIZE = 500
+ _MAX_MSG_SIZE = 500
- def __init__(self, address, port):
- self._address = address
- self._port = port
+ def __init__(self, address, port):
+ self._address = address
+ self._port = port
- self._send_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- # Make the socket multicast-aware, and set TTL.
- self._send_sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 20) # Change TTL (=20) to suit
+ self._send_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ # Make the socket multicast-aware, and set TTL.
+ self._send_sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 20) # Change TTL (=20) to suit
- def send_msg(self, data):
- self._send_sock.sendto(data, (self._address, self._port))
+ def send_msg(self, data):
+ self._send_sock.sendto(data, (self._address, self._port))
class Test(object):
- def test(self, arg1):
- print "Request got %s" % arg1
- return "success"
+ def test(self, arg1):
+ print "Request got %s" % arg1
+ return "success"
def xmlrpc_test_cb(response, user_data=None):
- print "Response was %s, user_data was %s" % (response, user_data)
- import gtk
- gtk.main_quit()
+ print "Response was %s, user_data was %s" % (response, user_data)
+ import gtk
+ gtk.main_quit()
def xmlrpc_test():
- client = GlibServerProxy("http://127.0.0.1:8888")
- client.test(xmlrpc_test_cb, "bar", "test data")
+ client = GlibServerProxy("http://127.0.0.1:8888")
+ client.test(xmlrpc_test_cb, "bar", "test data")
def main():
- import gtk
- server = GlibXMLRPCServer(("", 8888))
- inst = Test()
- server.register_instance(inst)
-
- gobject.idle_add(xmlrpc_test)
-
- try:
- gtk.main()
- except KeyboardInterrupt:
- print 'Ctrl+C pressed, exiting...'
- print "Done."
+ import gtk
+ server = GlibXMLRPCServer(("", 8888))
+ inst = Test()
+ server.register_instance(inst)
+
+ gobject.idle_add(xmlrpc_test)
+
+ try:
+ gtk.main()
+ except KeyboardInterrupt:
+ print 'Ctrl+C pressed, exiting...'
+ print "Done."
if __name__ == "__main__":
- main()
+ main()
diff --git a/sugar/presence/Activity.py b/sugar/presence/Activity.py
index e267d83..06c8a00 100644
--- a/sugar/presence/Activity.py
+++ b/sugar/presence/Activity.py
@@ -20,98 +20,98 @@ import dbus
class Activity(gobject.GObject):
- __gsignals__ = {
- 'buddy-joined': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT])),
- 'buddy-left': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT])),
- 'service-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT])),
- 'service-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT]))
- }
-
- _PRESENCE_SERVICE = "org.laptop.Presence"
- _ACTIVITY_DBUS_INTERFACE = "org.laptop.Presence.Activity"
-
- def __init__(self, bus, new_obj_cb, del_obj_cb, object_path):
- gobject.GObject.__init__(self)
- self._object_path = object_path
- self._ps_new_object = new_obj_cb
- self._ps_del_object = del_obj_cb
- bobj = bus.get_object(self._PRESENCE_SERVICE, object_path)
- self._activity = dbus.Interface(bobj, self._ACTIVITY_DBUS_INTERFACE)
- self._activity.connect_to_signal('BuddyJoined', self._buddy_joined_cb)
- self._activity.connect_to_signal('BuddyLeft', self._buddy_left_cb)
- self._activity.connect_to_signal('ServiceAppeared', self._service_appeared_cb)
- self._activity.connect_to_signal('ServiceDisappeared', self._service_disappeared_cb)
-
- self._id = None
- self._color = None
-
- def object_path(self):
- return self._object_path
-
- def _emit_buddy_joined_signal(self, object_path):
- self.emit('buddy-joined', self._ps_new_object(object_path))
- return False
-
- def _buddy_joined_cb(self, object_path):
- gobject.idle_add(self._emit_buddy_joined_signal, object_path)
-
- def _emit_buddy_left_signal(self, object_path):
- self.emit('buddy-left', self._ps_new_object(object_path))
- return False
-
- def _buddy_left_cb(self, object_path):
- gobject.idle_add(self._emit_buddy_left_signal, object_path)
-
- def _emit_service_appeared_signal(self, object_path):
- self.emit('service-appeared', self._ps_new_object(object_path))
- return False
-
- def _service_appeared_cb(self, object_path):
- gobject.idle_add(self._emit_service_appeared_signal, object_path)
-
- def _emit_service_disappeared_signal(self, object_path):
- self.emit('service-disappeared', self._ps_new_object(object_path))
- return False
-
- def _service_disappeared_cb(self, object_path):
- gobject.idle_add(self._emit_service_disappeared_signal, object_path)
-
- def get_id(self):
- # Cache activity ID, which should never change anyway
- if not self._id:
- self._id = self._activity.getId()
- return self._id
-
- def get_color(self):
- if not self._color:
- self._color = self._activity.getColor()
- return self._color
-
- def get_services(self):
- resp = self._activity.getServices()
- servs = []
- for item in resp:
- servs.append(self._ps_new_object(item))
- return servs
-
- def get_services_of_type(self, stype):
- resp = self._activity.getServicesOfType(stype)
- servs = []
- for item in resp:
- servs.append(self._ps_new_object(item))
- return servs
-
- def get_joined_buddies(self):
- resp = self._activity.getJoinedBuddies()
- buddies = []
- for item in resp:
- buddies.append(self._ps_new_object(item))
- return buddies
-
- def owner_has_joined(self):
- # FIXME
- return False
+ __gsignals__ = {
+ 'buddy-joined': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT])),
+ 'buddy-left': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT])),
+ 'service-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT])),
+ 'service-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT]))
+ }
+
+ _PRESENCE_SERVICE = "org.laptop.Presence"
+ _ACTIVITY_DBUS_INTERFACE = "org.laptop.Presence.Activity"
+
+ def __init__(self, bus, new_obj_cb, del_obj_cb, object_path):
+ gobject.GObject.__init__(self)
+ self._object_path = object_path
+ self._ps_new_object = new_obj_cb
+ self._ps_del_object = del_obj_cb
+ bobj = bus.get_object(self._PRESENCE_SERVICE, object_path)
+ self._activity = dbus.Interface(bobj, self._ACTIVITY_DBUS_INTERFACE)
+ self._activity.connect_to_signal('BuddyJoined', self._buddy_joined_cb)
+ self._activity.connect_to_signal('BuddyLeft', self._buddy_left_cb)
+ self._activity.connect_to_signal('ServiceAppeared', self._service_appeared_cb)
+ self._activity.connect_to_signal('ServiceDisappeared', self._service_disappeared_cb)
+
+ self._id = None
+ self._color = None
+
+ def object_path(self):
+ return self._object_path
+
+ def _emit_buddy_joined_signal(self, object_path):
+ self.emit('buddy-joined', self._ps_new_object(object_path))
+ return False
+
+ def _buddy_joined_cb(self, object_path):
+ gobject.idle_add(self._emit_buddy_joined_signal, object_path)
+
+ def _emit_buddy_left_signal(self, object_path):
+ self.emit('buddy-left', self._ps_new_object(object_path))
+ return False
+
+ def _buddy_left_cb(self, object_path):
+ gobject.idle_add(self._emit_buddy_left_signal, object_path)
+
+ def _emit_service_appeared_signal(self, object_path):
+ self.emit('service-appeared', self._ps_new_object(object_path))
+ return False
+
+ def _service_appeared_cb(self, object_path):
+ gobject.idle_add(self._emit_service_appeared_signal, object_path)
+
+ def _emit_service_disappeared_signal(self, object_path):
+ self.emit('service-disappeared', self._ps_new_object(object_path))
+ return False
+
+ def _service_disappeared_cb(self, object_path):
+ gobject.idle_add(self._emit_service_disappeared_signal, object_path)
+
+ def get_id(self):
+ # Cache activity ID, which should never change anyway
+ if not self._id:
+ self._id = self._activity.getId()
+ return self._id
+
+ def get_color(self):
+ if not self._color:
+ self._color = self._activity.getColor()
+ return self._color
+
+ def get_services(self):
+ resp = self._activity.getServices()
+ servs = []
+ for item in resp:
+ servs.append(self._ps_new_object(item))
+ return servs
+
+ def get_services_of_type(self, stype):
+ resp = self._activity.getServicesOfType(stype)
+ servs = []
+ for item in resp:
+ servs.append(self._ps_new_object(item))
+ return servs
+
+ def get_joined_buddies(self):
+ resp = self._activity.getJoinedBuddies()
+ buddies = []
+ for item in resp:
+ buddies.append(self._ps_new_object(item))
+ return buddies
+
+ def owner_has_joined(self):
+ # FIXME
+ return False
diff --git a/sugar/presence/Buddy.py b/sugar/presence/Buddy.py
index 579592b..740b29b 100644
--- a/sugar/presence/Buddy.py
+++ b/sugar/presence/Buddy.py
@@ -21,173 +21,173 @@ import dbus
class Buddy(gobject.GObject):
- __gsignals__ = {
- 'icon-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([])),
- 'disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([])),
- 'service-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT])),
- 'service-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT])),
- 'joined-activity': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT])),
- 'left-activity': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT])),
- 'property-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT])),
- 'current-activity-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT]))
- }
-
- _PRESENCE_SERVICE = "org.laptop.Presence"
- _BUDDY_DBUS_INTERFACE = "org.laptop.Presence.Buddy"
-
- def __init__(self, bus, new_obj_cb, del_obj_cb, object_path):
- gobject.GObject.__init__(self)
- self._object_path = object_path
- self._ps_new_object = new_obj_cb
- self._ps_del_object = del_obj_cb
- self._properties = {}
- bobj = bus.get_object(self._PRESENCE_SERVICE, object_path)
- self._buddy = dbus.Interface(bobj, self._BUDDY_DBUS_INTERFACE)
- self._buddy.connect_to_signal('IconChanged', self._icon_changed_cb)
- self._buddy.connect_to_signal('ServiceAppeared', self._service_appeared_cb)
- self._buddy.connect_to_signal('ServiceDisappeared', self._service_disappeared_cb)
- self._buddy.connect_to_signal('Disappeared', self._disappeared_cb)
- self._buddy.connect_to_signal('JoinedActivity', self._joined_activity_cb)
- self._buddy.connect_to_signal('LeftActivity', self._left_activity_cb)
- self._buddy.connect_to_signal('PropertyChanged', self._property_changed_cb)
- self._buddy.connect_to_signal('CurrentActivityChanged', self._current_activity_changed_cb)
- self._properties = self._get_properties_helper()
-
- self._current_activity = None
- try:
- self._current_activity = self._buddy.getCurrentActivity()
- except Exception, e:
- pass
-
- def _get_properties_helper(self):
- props = self._buddy.getProperties()
- if not props:
- return {}
- return props
-
- def object_path(self):
- return self._object_path
-
- def _emit_icon_changed_signal(self):
- self.emit('icon-changed')
- return False
-
- def _icon_changed_cb(self):
- gobject.idle_add(self._emit_icon_changed_signal)
-
- def _emit_disappeared_signal(self):
- self.emit('disappeared')
-
- def _disappeared_cb(self):
- gobject.idle_add(self._emit_disappeared_signal)
-
- def _emit_service_appeared_signal(self, object_path):
- self.emit('service-appeared', self._ps_new_object(object_path))
- return False
-
- def _service_appeared_cb(self, object_path):
- gobject.idle_add(self._emit_service_appeared_signal, object_path)
-
- def _emit_service_disappeared_signal(self, object_path):
- self.emit('service-disappeared', self._ps_new_object(object_path))
- return False
-
- def _service_disappeared_cb(self, object_path):
- gobject.idle_add(self._emit_service_disappeared_signal, object_path)
-
- def _emit_joined_activity_signal(self, object_path):
- self.emit('joined-activity', self._ps_new_object(object_path))
- return False
-
- def _joined_activity_cb(self, object_path):
- gobject.idle_add(self._emit_joined_activity_signal, object_path)
-
- def _emit_left_activity_signal(self, object_path):
- self.emit('left-activity', self._ps_new_object(object_path))
- return False
-
- def _left_activity_cb(self, object_path):
- gobject.idle_add(self._emit_left_activity_signal, object_path)
-
- def _handle_property_changed_signal(self, prop_list):
- self._properties = self._get_properties_helper()
- self.emit('property-changed', prop_list)
- return False
-
- def _property_changed_cb(self, prop_list):
- gobject.idle_add(self._handle_property_changed_signal, prop_list)
-
- def _handle_current_activity_changed_signal(self, act_list):
- if len(act_list) == 0:
- self._current_activity = None
- self.emit('current-activity-changed', None)
- else:
- self._current_activity = act_list[0]
- self.emit('current-activity-changed', self._ps_new_object(act_list[0]))
- return False
-
- def _current_activity_changed_cb(self, act_list):
- gobject.idle_add(self._handle_current_activity_changed_signal, act_list)
-
- def get_name(self):
- return self._properties['name']
-
- def get_ip4_address(self):
- return self._properties['ip4_address']
-
- def is_owner(self):
- return self._properties['owner']
-
- def get_color(self):
- return self._properties['color']
-
- def get_icon(self):
- return self._buddy.getIcon()
-
- def get_current_activity(self):
- if not self._current_activity:
- return None
- return self._ps_new_object(self._current_activity)
-
- def get_icon_pixbuf(self):
- icon = self._buddy.getIcon()
- if icon and len(icon):
- pbl = gtk.gdk.PixbufLoader()
- icon_data = ""
- for item in icon:
- if item < 0:
- item = item + 128
- icon_data = icon_data + chr(item)
- pbl.write(icon_data)
- pbl.close()
- return pbl.get_pixbuf()
- else:
- return None
-
- def get_service_of_type(self, stype, activity=None):
- try:
- act_op = "/"
- if activity:
- act_op = activity.object_path()
- object_path = self._buddy.getServiceOfType(stype, act_op)
- except dbus.exceptions.DBusException:
- return None
- return self._ps_new_object(object_path)
-
- def get_joined_activities(self):
- try:
- resp = self._buddy.getJoinedActivities()
- except dbus.exceptions.DBusException:
- return []
- acts = []
- for item in resp:
- acts.append(self._ps_new_object(item))
- return acts
+ __gsignals__ = {
+ 'icon-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([])),
+ 'disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([])),
+ 'service-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT])),
+ 'service-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT])),
+ 'joined-activity': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT])),
+ 'left-activity': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT])),
+ 'property-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT])),
+ 'current-activity-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT]))
+ }
+
+ _PRESENCE_SERVICE = "org.laptop.Presence"
+ _BUDDY_DBUS_INTERFACE = "org.laptop.Presence.Buddy"
+
+ def __init__(self, bus, new_obj_cb, del_obj_cb, object_path):
+ gobject.GObject.__init__(self)
+ self._object_path = object_path
+ self._ps_new_object = new_obj_cb
+ self._ps_del_object = del_obj_cb
+ self._properties = {}
+ bobj = bus.get_object(self._PRESENCE_SERVICE, object_path)
+ self._buddy = dbus.Interface(bobj, self._BUDDY_DBUS_INTERFACE)
+ self._buddy.connect_to_signal('IconChanged', self._icon_changed_cb)
+ self._buddy.connect_to_signal('ServiceAppeared', self._service_appeared_cb)
+ self._buddy.connect_to_signal('ServiceDisappeared', self._service_disappeared_cb)
+ self._buddy.connect_to_signal('Disappeared', self._disappeared_cb)
+ self._buddy.connect_to_signal('JoinedActivity', self._joined_activity_cb)
+ self._buddy.connect_to_signal('LeftActivity', self._left_activity_cb)
+ self._buddy.connect_to_signal('PropertyChanged', self._property_changed_cb)
+ self._buddy.connect_to_signal('CurrentActivityChanged', self._current_activity_changed_cb)
+ self._properties = self._get_properties_helper()
+
+ self._current_activity = None
+ try:
+ self._current_activity = self._buddy.getCurrentActivity()
+ except Exception, e:
+ pass
+
+ def _get_properties_helper(self):
+ props = self._buddy.getProperties()
+ if not props:
+ return {}
+ return props
+
+ def object_path(self):
+ return self._object_path
+
+ def _emit_icon_changed_signal(self):
+ self.emit('icon-changed')
+ return False
+
+ def _icon_changed_cb(self):
+ gobject.idle_add(self._emit_icon_changed_signal)
+
+ def _emit_disappeared_signal(self):
+ self.emit('disappeared')
+
+ def _disappeared_cb(self):
+ gobject.idle_add(self._emit_disappeared_signal)
+
+ def _emit_service_appeared_signal(self, object_path):
+ self.emit('service-appeared', self._ps_new_object(object_path))
+ return False
+
+ def _service_appeared_cb(self, object_path):
+ gobject.idle_add(self._emit_service_appeared_signal, object_path)
+
+ def _emit_service_disappeared_signal(self, object_path):
+ self.emit('service-disappeared', self._ps_new_object(object_path))
+ return False
+
+ def _service_disappeared_cb(self, object_path):
+ gobject.idle_add(self._emit_service_disappeared_signal, object_path)
+
+ def _emit_joined_activity_signal(self, object_path):
+ self.emit('joined-activity', self._ps_new_object(object_path))
+ return False
+
+ def _joined_activity_cb(self, object_path):
+ gobject.idle_add(self._emit_joined_activity_signal, object_path)
+
+ def _emit_left_activity_signal(self, object_path):
+ self.emit('left-activity', self._ps_new_object(object_path))
+ return False
+
+ def _left_activity_cb(self, object_path):
+ gobject.idle_add(self._emit_left_activity_signal, object_path)
+
+ def _handle_property_changed_signal(self, prop_list):
+ self._properties = self._get_properties_helper()
+ self.emit('property-changed', prop_list)
+ return False
+
+ def _property_changed_cb(self, prop_list):
+ gobject.idle_add(self._handle_property_changed_signal, prop_list)
+
+ def _handle_current_activity_changed_signal(self, act_list):
+ if len(act_list) == 0:
+ self._current_activity = None
+ self.emit('current-activity-changed', None)
+ else:
+ self._current_activity = act_list[0]
+ self.emit('current-activity-changed', self._ps_new_object(act_list[0]))
+ return False
+
+ def _current_activity_changed_cb(self, act_list):
+ gobject.idle_add(self._handle_current_activity_changed_signal, act_list)
+
+ def get_name(self):
+ return self._properties['name']
+
+ def get_ip4_address(self):
+ return self._properties['ip4_address']
+
+ def is_owner(self):
+ return self._properties['owner']
+
+ def get_color(self):
+ return self._properties['color']
+
+ def get_icon(self):
+ return self._buddy.getIcon()
+
+ def get_current_activity(self):
+ if not self._current_activity:
+ return None
+ return self._ps_new_object(self._current_activity)
+
+ def get_icon_pixbuf(self):
+ icon = self._buddy.getIcon()
+ if icon and len(icon):
+ pbl = gtk.gdk.PixbufLoader()
+ icon_data = ""
+ for item in icon:
+ if item < 0:
+ item = item + 128
+ icon_data = icon_data + chr(item)
+ pbl.write(icon_data)
+ pbl.close()
+ return pbl.get_pixbuf()
+ else:
+ return None
+
+ def get_service_of_type(self, stype, activity=None):
+ try:
+ act_op = "/"
+ if activity:
+ act_op = activity.object_path()
+ object_path = self._buddy.getServiceOfType(stype, act_op)
+ except dbus.exceptions.DBusException:
+ return None
+ return self._ps_new_object(object_path)
+
+ def get_joined_activities(self):
+ try:
+ resp = self._buddy.getJoinedActivities()
+ except dbus.exceptions.DBusException:
+ return []
+ acts = []
+ for item in resp:
+ acts.append(self._ps_new_object(item))
+ return acts
diff --git a/sugar/presence/PresenceService.py b/sugar/presence/PresenceService.py
index d74b0c5..fd6091e 100644
--- a/sugar/presence/PresenceService.py
+++ b/sugar/presence/PresenceService.py
@@ -20,23 +20,23 @@ import dbus, dbus.glib, gobject
import Buddy, Service, Activity
class ObjectCache(object):
- def __init__(self):
- self._cache = {}
+ def __init__(self):
+ self._cache = {}
- def get(self, object_path):
- try:
- return self._cache[object_path]
- except KeyError:
- return None
+ def get(self, object_path):
+ try:
+ return self._cache[object_path]
+ except KeyError:
+ return None
- def add(self, obj):
- op = obj.object_path()
- if not self._cache.has_key(op):
- self._cache[op] = obj
+ def add(self, obj):
+ op = obj.object_path()
+ if not self._cache.has_key(op):
+ self._cache[op] = obj
- def remove(self, object_path):
- if self._cache.has_key(object_path):
- del self._cache[object_path]
+ def remove(self, object_path):
+ if self._cache.has_key(object_path):
+ del self._cache[object_path]
DBUS_SERVICE = "org.laptop.Presence"
@@ -46,192 +46,192 @@ DBUS_PATH = "/org/laptop/Presence"
class PresenceService(gobject.GObject):
- __gsignals__ = {
- 'buddy-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT])),
- 'buddy-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT])),
- 'service-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT])),
- 'service-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT])),
- 'activity-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT])),
- 'activity-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT]))
- }
-
- _PS_BUDDY_OP = DBUS_PATH + "/Buddies/"
- _PS_SERVICE_OP = DBUS_PATH + "/Services/"
- _PS_ACTIVITY_OP = DBUS_PATH + "/Activities/"
-
-
- def __init__(self):
- gobject.GObject.__init__(self)
- self._objcache = ObjectCache()
- self._bus = dbus.SessionBus()
- self._ps = dbus.Interface(self._bus.get_object(DBUS_SERVICE,
- DBUS_PATH), DBUS_INTERFACE)
- self._ps.connect_to_signal('BuddyAppeared', self._buddy_appeared_cb)
- self._ps.connect_to_signal('BuddyDisappeared', self._buddy_disappeared_cb)
- self._ps.connect_to_signal('ServiceAppeared', self._service_appeared_cb)
- self._ps.connect_to_signal('ServiceDisappeared', self._service_disappeared_cb)
- self._ps.connect_to_signal('ActivityAppeared', self._activity_appeared_cb)
- self._ps.connect_to_signal('ActivityDisappeared', self._activity_disappeared_cb)
-
- def _new_object(self, object_path):
- obj = self._objcache.get(object_path)
- if not obj:
- if object_path.startswith(self._PS_SERVICE_OP):
- obj = Service.Service(self._bus, self._new_object,
- self._del_object, object_path)
- elif object_path.startswith(self._PS_BUDDY_OP):
- obj = Buddy.Buddy(self._bus, self._new_object,
- self._del_object, object_path)
- elif object_path.startswith(self._PS_ACTIVITY_OP):
- obj = Activity.Activity(self._bus, self._new_object,
- self._del_object, object_path)
- else:
- raise RuntimeError("Unknown object type")
- self._objcache.add(obj)
- return obj
-
- def _del_object(self, object_path):
- # FIXME
- pass
-
- def _emit_buddy_appeared_signal(self, object_path):
- self.emit('buddy-appeared', self._new_object(object_path))
- return False
-
- def _buddy_appeared_cb(self, op):
- gobject.idle_add(self._emit_buddy_appeared_signal, op)
-
- def _emit_buddy_disappeared_signal(self, object_path):
- self.emit('buddy-disappeared', self._new_object(object_path))
- return False
-
- def _buddy_disappeared_cb(self, object_path):
- gobject.idle_add(self._emit_buddy_disappeared_signal, object_path)
-
- def _emit_service_appeared_signal(self, object_path):
- self.emit('service-appeared', self._new_object(object_path))
- return False
-
- def _service_appeared_cb(self, object_path):
- gobject.idle_add(self._emit_service_appeared_signal, object_path)
-
- def _emit_service_disappeared_signal(self, object_path):
- self.emit('service-disappeared', self._new_object(object_path))
- return False
-
- def _service_disappeared_cb(self, object_path):
- gobject.idle_add(self._emit_service_disappeared_signal, object_path)
-
- def _emit_activity_appeared_signal(self, object_path):
- self.emit('activity-appeared', self._new_object(object_path))
- return False
-
- def _activity_appeared_cb(self, object_path):
- gobject.idle_add(self._emit_activity_appeared_signal, object_path)
-
- def _emit_activity_disappeared_signal(self, object_path):
- self.emit('activity-disappeared', self._new_object(object_path))
- return False
-
- def _activity_disappeared_cb(self, object_path):
- gobject.idle_add(self._emit_activity_disappeared_signal, object_path)
-
- def get(self, object_path):
- return self._new_object(object_path)
-
- def get_services(self):
- resp = self._ps.getServices()
- servs = []
- for item in resp:
- servs.append(self._new_object(item))
- return servs
-
- def get_services_of_type(self, stype):
- resp = self._ps.getServicesOfType(stype)
- servs = []
- for item in resp:
- servs.append(self._new_object(item))
- return servs
-
- def get_activities(self):
- resp = self._ps.getActivities()
- acts = []
- for item in resp:
- acts.append(self._new_object(item))
- return acts
-
- def get_activity(self, activity_id):
- try:
- act_op = self._ps.getActivity(activity_id)
- except dbus.exceptions.DBusException:
- return None
- return self._new_object(act_op)
-
- def get_buddies(self):
- resp = self._ps.getBuddies()
- buddies = []
- for item in resp:
- buddies.append(self._new_object(item))
- return buddies
-
- def get_buddy_by_name(self, name):
- try:
- buddy_op = self._ps.getBuddyByName(name)
- except dbus.exceptions.DBusException:
- return None
- return self._new_object(buddy_op)
-
- def get_buddy_by_address(self, addr):
- try:
- buddy_op = self._ps.getBuddyByAddress(addr)
- except dbus.exceptions.DBusException:
- return None
- return self._new_object(buddy_op)
-
- def get_owner(self):
- try:
- owner_op = self._ps.getOwner()
- except dbus.exceptions.DBusException:
- return None
- return self._new_object(owner_op)
-
- def share_activity(self, activity, stype, properties={}, address=None, port=-1, domain=u"local"):
- actid = activity.get_id()
- if address == None:
- address = u""
- serv_op = self._ps.shareActivity(actid, stype, properties, address, port, domain)
- return self._new_object(serv_op)
-
- def register_service(self, name, stype, properties={}, address=None, port=-1, domain=u"local"):
- if address == None:
- address = u""
- serv_op = self._ps.registerService(name, stype, properties, address, port, domain)
- return self._new_object(serv_op)
-
- def unregister_service(self, service):
- self._ps.unregisterService(service.object_path())
-
- def register_service_type(self, stype):
- self._ps.registerServiceType(stype)
-
- def unregister_service_type(self, stype):
- self._ps.unregisterServiceType(stype)
+ __gsignals__ = {
+ 'buddy-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT])),
+ 'buddy-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT])),
+ 'service-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT])),
+ 'service-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT])),
+ 'activity-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT])),
+ 'activity-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT]))
+ }
+
+ _PS_BUDDY_OP = DBUS_PATH + "/Buddies/"
+ _PS_SERVICE_OP = DBUS_PATH + "/Services/"
+ _PS_ACTIVITY_OP = DBUS_PATH + "/Activities/"
+
+
+ def __init__(self):
+ gobject.GObject.__init__(self)
+ self._objcache = ObjectCache()
+ self._bus = dbus.SessionBus()
+ self._ps = dbus.Interface(self._bus.get_object(DBUS_SERVICE,
+ DBUS_PATH), DBUS_INTERFACE)
+ self._ps.connect_to_signal('BuddyAppeared', self._buddy_appeared_cb)
+ self._ps.connect_to_signal('BuddyDisappeared', self._buddy_disappeared_cb)
+ self._ps.connect_to_signal('ServiceAppeared', self._service_appeared_cb)
+ self._ps.connect_to_signal('ServiceDisappeared', self._service_disappeared_cb)
+ self._ps.connect_to_signal('ActivityAppeared', self._activity_appeared_cb)
+ self._ps.connect_to_signal('ActivityDisappeared', self._activity_disappeared_cb)
+
+ def _new_object(self, object_path):
+ obj = self._objcache.get(object_path)
+ if not obj:
+ if object_path.startswith(self._PS_SERVICE_OP):
+ obj = Service.Service(self._bus, self._new_object,
+ self._del_object, object_path)
+ elif object_path.startswith(self._PS_BUDDY_OP):
+ obj = Buddy.Buddy(self._bus, self._new_object,
+ self._del_object, object_path)
+ elif object_path.startswith(self._PS_ACTIVITY_OP):
+ obj = Activity.Activity(self._bus, self._new_object,
+ self._del_object, object_path)
+ else:
+ raise RuntimeError("Unknown object type")
+ self._objcache.add(obj)
+ return obj
+
+ def _del_object(self, object_path):
+ # FIXME
+ pass
+
+ def _emit_buddy_appeared_signal(self, object_path):
+ self.emit('buddy-appeared', self._new_object(object_path))
+ return False
+
+ def _buddy_appeared_cb(self, op):
+ gobject.idle_add(self._emit_buddy_appeared_signal, op)
+
+ def _emit_buddy_disappeared_signal(self, object_path):
+ self.emit('buddy-disappeared', self._new_object(object_path))
+ return False
+
+ def _buddy_disappeared_cb(self, object_path):
+ gobject.idle_add(self._emit_buddy_disappeared_signal, object_path)
+
+ def _emit_service_appeared_signal(self, object_path):
+ self.emit('service-appeared', self._new_object(object_path))
+ return False
+
+ def _service_appeared_cb(self, object_path):
+ gobject.idle_add(self._emit_service_appeared_signal, object_path)
+
+ def _emit_service_disappeared_signal(self, object_path):
+ self.emit('service-disappeared', self._new_object(object_path))
+ return False
+
+ def _service_disappeared_cb(self, object_path):
+ gobject.idle_add(self._emit_service_disappeared_signal, object_path)
+
+ def _emit_activity_appeared_signal(self, object_path):
+ self.emit('activity-appeared', self._new_object(object_path))
+ return False
+
+ def _activity_appeared_cb(self, object_path):
+ gobject.idle_add(self._emit_activity_appeared_signal, object_path)
+
+ def _emit_activity_disappeared_signal(self, object_path):
+ self.emit('activity-disappeared', self._new_object(object_path))
+ return False
+
+ def _activity_disappeared_cb(self, object_path):
+ gobject.idle_add(self._emit_activity_disappeared_signal, object_path)
+
+ def get(self, object_path):
+ return self._new_object(object_path)
+
+ def get_services(self):
+ resp = self._ps.getServices()
+ servs = []
+ for item in resp:
+ servs.append(self._new_object(item))
+ return servs
+
+ def get_services_of_type(self, stype):
+ resp = self._ps.getServicesOfType(stype)
+ servs = []
+ for item in resp:
+ servs.append(self._new_object(item))
+ return servs
+
+ def get_activities(self):
+ resp = self._ps.getActivities()
+ acts = []
+ for item in resp:
+ acts.append(self._new_object(item))
+ return acts
+
+ def get_activity(self, activity_id):
+ try:
+ act_op = self._ps.getActivity(activity_id)
+ except dbus.exceptions.DBusException:
+ return None
+ return self._new_object(act_op)
+
+ def get_buddies(self):
+ resp = self._ps.getBuddies()
+ buddies = []
+ for item in resp:
+ buddies.append(self._new_object(item))
+ return buddies
+
+ def get_buddy_by_name(self, name):
+ try:
+ buddy_op = self._ps.getBuddyByName(name)
+ except dbus.exceptions.DBusException:
+ return None
+ return self._new_object(buddy_op)
+
+ def get_buddy_by_address(self, addr):
+ try:
+ buddy_op = self._ps.getBuddyByAddress(addr)
+ except dbus.exceptions.DBusException:
+ return None
+ return self._new_object(buddy_op)
+
+ def get_owner(self):
+ try:
+ owner_op = self._ps.getOwner()
+ except dbus.exceptions.DBusException:
+ return None
+ return self._new_object(owner_op)
+
+ def share_activity(self, activity, stype, properties={}, address=None, port=-1, domain=u"local"):
+ actid = activity.get_id()
+ if address == None:
+ address = u""
+ serv_op = self._ps.shareActivity(actid, stype, properties, address, port, domain)
+ return self._new_object(serv_op)
+
+ def register_service(self, name, stype, properties={}, address=None, port=-1, domain=u"local"):
+ if address == None:
+ address = u""
+ serv_op = self._ps.registerService(name, stype, properties, address, port, domain)
+ return self._new_object(serv_op)
+
+ def unregister_service(self, service):
+ self._ps.unregisterService(service.object_path())
+
+ def register_service_type(self, stype):
+ self._ps.registerServiceType(stype)
+
+ def unregister_service_type(self, stype):
+ self._ps.unregisterServiceType(stype)
_ps = None
def get_instance():
- global _ps
- if not _ps:
- _ps = PresenceService()
- return _ps
+ global _ps
+ if not _ps:
+ _ps = PresenceService()
+ return _ps
def start():
- bus = dbus.SessionBus()
- ps = dbus.Interface(bus.get_object(DBUS_SERVICE, DBUS_PATH), DBUS_INTERFACE)
- ps.start()
+ bus = dbus.SessionBus()
+ ps = dbus.Interface(bus.get_object(DBUS_SERVICE, DBUS_PATH), DBUS_INTERFACE)
+ ps.start()
diff --git a/sugar/presence/Service.py b/sugar/presence/Service.py
index a1ef98a..22b436f 100644
--- a/sugar/presence/Service.py
+++ b/sugar/presence/Service.py
@@ -20,101 +20,101 @@ import dbus
def _one_dict_differs(dict1, dict2):
- diff_keys = []
- for key, value in dict1.items():
- if not dict2.has_key(key) or dict2[key] != value:
- diff_keys.append(key)
- return diff_keys
+ diff_keys = []
+ for key, value in dict1.items():
+ if not dict2.has_key(key) or dict2[key] != value:
+ diff_keys.append(key)
+ return diff_keys
def _dicts_differ(dict1, dict2):
- diff_keys = []
- diff1 = _one_dict_differs(dict1, dict2)
- diff2 = _one_dict_differs(dict2, dict1)
- for key in diff2:
- if key not in diff1:
- diff_keys.append(key)
- diff_keys += diff1
- return diff_keys
+ diff_keys = []
+ diff1 = _one_dict_differs(dict1, dict2)
+ diff2 = _one_dict_differs(dict2, dict1)
+ for key in diff2:
+ if key not in diff1:
+ diff_keys.append(key)
+ diff_keys += diff1
+ return diff_keys
class Service(gobject.GObject):
- _PRESENCE_SERVICE = "org.laptop.Presence"
- _SERVICE_DBUS_INTERFACE = "org.laptop.Presence.Service"
-
- __gsignals__ = {
- 'published-value-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT]))
- }
-
- def __init__(self, bus, new_obj_cb, del_obj_cb, object_path):
- gobject.GObject.__init__(self)
- self._object_path = object_path
- self._ps_new_object = new_obj_cb
- self._ps_del_object = del_obj_cb
- sobj = bus.get_object(self._PRESENCE_SERVICE, object_path)
- self._service = dbus.Interface(sobj, self._SERVICE_DBUS_INTERFACE)
- self._service.connect_to_signal('PropertyChanged', self.__property_changed_cb)
- self._service.connect_to_signal('PublishedValueChanged',
- self.__published_value_changed_cb)
- self._props = self._service.getProperties()
- self._pubvals = self._service.getPublishedValues()
-
- def object_path(self):
- return self._object_path
-
- def __property_changed_cb(self, prop_list):
- self._props = self._service.getProperties()
-
- def get_published_value(self, key):
- return self._pubvals[key]
-
- def get_published_values(self):
- self._pubvals = self._service.getPublishedValues()
- return self._pubvals
-
- def set_published_value(self, key, value):
- if self._pubvals.has_key(key):
- if self._pubvals[key] == value:
- return
- self._pubvals[key] = value
- self._service.setPublishedValue(key, value)
-
- def set_published_values(self, vals):
- self._service.setPublishedValues(vals)
- self._pubvals = vals
-
- def __published_value_changed_cb(self, keys):
- oldvals = self._pubvals
- self.get_published_values()
- diff_keys = _dicts_differ(oldvals, self._pubvals)
- if len(diff_keys) > 0:
- self.emit('published-value-changed', diff_keys)
-
- def get_name(self):
- return self._props['name']
-
- def get_type(self):
- return self._props['type']
-
- def get_domain(self):
- return self._props['domain']
-
- def get_address(self):
- if self._props.has_key('address'):
- return self._props['address']
- return None
-
- def get_activity_id(self):
- if self._props.has_key('activityId'):
- return self._props['activityId']
- return None
-
- def get_port(self):
- if self._props.has_key('port'):
- return self._props['port']
- return None
-
- def get_source_address(self):
- if self._props.has_key('sourceAddress'):
- return self._props['sourceAddress']
- return None
+ _PRESENCE_SERVICE = "org.laptop.Presence"
+ _SERVICE_DBUS_INTERFACE = "org.laptop.Presence.Service"
+
+ __gsignals__ = {
+ 'published-value-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT]))
+ }
+
+ def __init__(self, bus, new_obj_cb, del_obj_cb, object_path):
+ gobject.GObject.__init__(self)
+ self._object_path = object_path
+ self._ps_new_object = new_obj_cb
+ self._ps_del_object = del_obj_cb
+ sobj = bus.get_object(self._PRESENCE_SERVICE, object_path)
+ self._service = dbus.Interface(sobj, self._SERVICE_DBUS_INTERFACE)
+ self._service.connect_to_signal('PropertyChanged', self.__property_changed_cb)
+ self._service.connect_to_signal('PublishedValueChanged',
+ self.__published_value_changed_cb)
+ self._props = self._service.getProperties()
+ self._pubvals = self._service.getPublishedValues()
+
+ def object_path(self):
+ return self._object_path
+
+ def __property_changed_cb(self, prop_list):
+ self._props = self._service.getProperties()
+
+ def get_published_value(self, key):
+ return self._pubvals[key]
+
+ def get_published_values(self):
+ self._pubvals = self._service.getPublishedValues()
+ return self._pubvals
+
+ def set_published_value(self, key, value):
+ if self._pubvals.has_key(key):
+ if self._pubvals[key] == value:
+ return
+ self._pubvals[key] = value
+ self._service.setPublishedValue(key, value)
+
+ def set_published_values(self, vals):
+ self._service.setPublishedValues(vals)
+ self._pubvals = vals
+
+ def __published_value_changed_cb(self, keys):
+ oldvals = self._pubvals
+ self.get_published_values()
+ diff_keys = _dicts_differ(oldvals, self._pubvals)
+ if len(diff_keys) > 0:
+ self.emit('published-value-changed', diff_keys)
+
+ def get_name(self):
+ return self._props['name']
+
+ def get_type(self):
+ return self._props['type']
+
+ def get_domain(self):
+ return self._props['domain']
+
+ def get_address(self):
+ if self._props.has_key('address'):
+ return self._props['address']
+ return None
+
+ def get_activity_id(self):
+ if self._props.has_key('activityId'):
+ return self._props['activityId']
+ return None
+
+ def get_port(self):
+ if self._props.has_key('port'):
+ return self._props['port']
+ return None
+
+ def get_source_address(self):
+ if self._props.has_key('sourceAddress'):
+ return self._props['sourceAddress']
+ return None
diff --git a/sugar/profile.py b/sugar/profile.py
index 5b1c782..f731fba 100644
--- a/sugar/profile.py
+++ b/sugar/profile.py
@@ -21,34 +21,34 @@ from sugar import env
from sugar.graphics.iconcolor import IconColor
class _Profile(object):
- def __init__(self):
- self.name = None
- self.color = None
- self._load()
+ def __init__(self):
+ self.name = None
+ self.color = None
+ self._load()
- def update(self):
- self._load()
+ def update(self):
+ self._load()
- def _load(self):
- cp = ConfigParser()
- config_path = os.path.join(env.get_profile_path(), 'config')
- parsed = cp.read([config_path])
+ def _load(self):
+ cp = ConfigParser()
+ config_path = os.path.join(env.get_profile_path(), 'config')
+ parsed = cp.read([config_path])
- if cp.has_option('Buddy', 'NickName'):
- self.name = cp.get('Buddy', 'NickName')
+ if cp.has_option('Buddy', 'NickName'):
+ self.name = cp.get('Buddy', 'NickName')
- if cp.has_option('Buddy', 'Color'):
- self.color = IconColor(cp.get('Buddy', 'Color'))
+ if cp.has_option('Buddy', 'Color'):
+ self.color = IconColor(cp.get('Buddy', 'Color'))
- del cp
+ del cp
def get_nick_name():
- return _profile.name
+ return _profile.name
def get_color():
- return _profile.color
+ return _profile.color
def update():
- _profile.update()
+ _profile.update()
_profile = _Profile()
diff --git a/sugar/simulator.py b/sugar/simulator.py
index 7a2d24f..c97f364 100644
--- a/sugar/simulator.py
+++ b/sugar/simulator.py
@@ -33,151 +33,151 @@ _PRESENCE_SERVICE_TYPE = "_presence_olpc._tcp"
_activity_refs = {}
class _NameCollection(object):
- def __init__(self):
- self._names = copy.copy(_nick_names)
+ def __init__(self):
+ self._names = copy.copy(_nick_names)
- def get_name(self):
- i = random.randint(0, len(self._names))
- return self._names.pop(i)
+ def get_name(self):
+ i = random.randint(0, len(self._names))
+ return self._names.pop(i)
class _BotService(object):
- def __init__(self, bot):
- self._bot = bot
-
- def announce(self):
- props = { 'color': self._bot.color.to_string() }
- pservice = PresenceService.get_instance()
- self._service = pservice.register_service(self._bot.name,
- _PRESENCE_SERVICE_TYPE, properties=props)
-
- self._stream = Stream.Stream.new_from_service(self._service)
- self._stream.register_reader_handler(
- self._handle_buddy_icon_request, "get_buddy_icon")
- self._stream.register_reader_handler(
- self._handle_invite, "invite")
-
- def _handle_buddy_icon_request(self):
- if self._bot.icon:
- fd = open(self._bot.icon, "r")
- icon_data = fd.read()
- fd.close()
- if icon_data:
- return base64.b64encode(self._icon)
- return ''
-
- def _handle_invite(self, issuer, bundle_id, activity_id):
- return ''
-
- def set_current_activity(self, activity_id):
- self._service.set_published_value('curact', dbus.String(activity_id))
+ def __init__(self, bot):
+ self._bot = bot
+
+ def announce(self):
+ props = { 'color': self._bot.color.to_string() }
+ pservice = PresenceService.get_instance()
+ self._service = pservice.register_service(self._bot.name,
+ _PRESENCE_SERVICE_TYPE, properties=props)
+
+ self._stream = Stream.Stream.new_from_service(self._service)
+ self._stream.register_reader_handler(
+ self._handle_buddy_icon_request, "get_buddy_icon")
+ self._stream.register_reader_handler(
+ self._handle_invite, "invite")
+
+ def _handle_buddy_icon_request(self):
+ if self._bot.icon:
+ fd = open(self._bot.icon, "r")
+ icon_data = fd.read()
+ fd.close()
+ if icon_data:
+ return base64.b64encode(self._icon)
+ return ''
+
+ def _handle_invite(self, issuer, bundle_id, activity_id):
+ return ''
+
+ def set_current_activity(self, activity_id):
+ self._service.set_published_value('curact', dbus.String(activity_id))
class _JoinActivityAction(object):
- def __init__(self, bot, named_ref):
- self._bot = bot
- self._named_ref = named_ref
+ def __init__(self, bot, named_ref):
+ self._bot = bot
+ self._named_ref = named_ref
- def execute(self):
- activity_id = _activity_refs[self._named_ref]
+ def execute(self):
+ activity_id = _activity_refs[self._named_ref]
- pservice = PresenceService.get_instance()
- activity = pservice.get_activity(activity_id)
- service = activity.get_services()[0]
+ pservice = PresenceService.get_instance()
+ activity = pservice.get_activity(activity_id)
+ service = activity.get_services()[0]
- name = "%s [%s]" % (self._bot.name, activity_id)
- properties = { 'title' : service.get_published_value('title'),
- 'color' : service.get_published_value('color') }
+ name = "%s [%s]" % (self._bot.name, activity_id)
+ properties = { 'title' : service.get_published_value('title'),
+ 'color' : service.get_published_value('color') }
- pservice.register_service(name, service.get_type(),
- properties, service.get_address(),
- service.get_port())
+ pservice.register_service(name, service.get_type(),
+ properties, service.get_address(),
+ service.get_port())
- self._bot._service.set_current_activity(activity_id)
+ self._bot._service.set_current_activity(activity_id)
class _ChangeActivityAction(object):
- def __init__(self, bot, named_ref):
- self._bot = bot
- self._named_ref = named_ref
+ def __init__(self, bot, named_ref):
+ self._bot = bot
+ self._named_ref = named_ref
- def execute(self):
- activity_id = _activity_refs[self._named_ref]
- self._bot._service.set_current_activity(activity_id)
+ def execute(self):
+ activity_id = _activity_refs[self._named_ref]
+ self._bot._service.set_current_activity(activity_id)
class _ShareChatAction(object):
- def __init__(self, bot, named_ref, title):
- self._bot = bot
- self._title = title
- self._id = util.unique_id()
+ def __init__(self, bot, named_ref, title):
+ self._bot = bot
+ self._title = title
+ self._id = util.unique_id()
- _activity_refs[named_ref] = self._id
+ _activity_refs[named_ref] = self._id
- def execute(self):
- name = "%s [%s]" % (self._bot.name, self._id)
- stype = '_GroupChatActivity_Sugar_redhat_com._udp'
- properties = { 'title' : self._title,
- 'color' : self._bot.color.to_string() }
- address = u"232.%d.%d.%d" % (random.randint(0, 254),
- random.randint(1, 254),
- random.randint(1, 254))
+ def execute(self):
+ name = "%s [%s]" % (self._bot.name, self._id)
+ stype = '_GroupChatActivity_Sugar_redhat_com._udp'
+ properties = { 'title' : self._title,
+ 'color' : self._bot.color.to_string() }
+ address = u"232.%d.%d.%d" % (random.randint(0, 254),
+ random.randint(1, 254),
+ random.randint(1, 254))
- pservice = PresenceService.get_instance()
- pservice.register_service(name, stype, properties, address)
+ pservice = PresenceService.get_instance()
+ pservice.register_service(name, stype, properties, address)
class _WaitAction(object):
- def __init__(self, bot, seconds):
- self._bot = bot
- self._seconds = seconds
-
- def execute(self):
- self._bot._pause_queue(self._seconds)
+ def __init__(self, bot, seconds):
+ self._bot = bot
+ self._seconds = seconds
+
+ def execute(self):
+ self._bot._pause_queue(self._seconds)
class Bot(object):
- _name_collection = _NameCollection()
+ _name_collection = _NameCollection()
- def __init__(self):
- self.name = Bot._name_collection.get_name()
- self.color = IconColor()
- self.icon = None
+ def __init__(self):
+ self.name = Bot._name_collection.get_name()
+ self.color = IconColor()
+ self.icon = None
- self._queue = []
+ self._queue = []
- def wait(self, seconds):
- action = _WaitAction(self, seconds)
- self._queue.append(action)
+ def wait(self, seconds):
+ action = _WaitAction(self, seconds)
+ self._queue.append(action)
- def share_chat(self, activity_id, title):
- action = _ShareChatAction(self, activity_id, title)
- self._queue.append(action)
+ def share_chat(self, activity_id, title):
+ action = _ShareChatAction(self, activity_id, title)
+ self._queue.append(action)
- def change_activity(self, activity_id):
- action = _ChangeActivityAction(self, activity_id)
- self._queue.append(action)
+ def change_activity(self, activity_id):
+ action = _ChangeActivityAction(self, activity_id)
+ self._queue.append(action)
- def join_activity(self, activity_id):
- action = _JoinActivityAction(self, activity_id)
- self._queue.append(action)
+ def join_activity(self, activity_id):
+ action = _JoinActivityAction(self, activity_id)
+ self._queue.append(action)
- def start(self):
- self._service = _BotService(self)
- self._service.announce()
+ def start(self):
+ self._service = _BotService(self)
+ self._service.announce()
- self._start_queue()
+ self._start_queue()
- def _idle_cb(self):
- self._next_action()
- return True
+ def _idle_cb(self):
+ self._next_action()
+ return True
- def _pause_done_cb(self):
- self._start_queue()
- return False
+ def _pause_done_cb(self):
+ self._start_queue()
+ return False
- def _start_queue(self):
- self._queue_sid = gobject.idle_add(self._idle_cb)
+ def _start_queue(self):
+ self._queue_sid = gobject.idle_add(self._idle_cb)
- def _pause_queue(self, seconds):
- gobject.source_remove(self._queue_sid)
- gobject.timeout_add(int(seconds * 1000), self._pause_done_cb)
+ def _pause_queue(self, seconds):
+ gobject.source_remove(self._queue_sid)
+ gobject.timeout_add(int(seconds * 1000), self._pause_done_cb)
- def _next_action(self):
- if len(self._queue) > 0:
- action = self._queue.pop(0)
- action.execute()
+ def _next_action(self):
+ if len(self._queue) > 0:
+ action = self._queue.pop(0)
+ action.execute()
diff --git a/sugar/util.py b/sugar/util.py
index 108c48e..8ad840d 100644
--- a/sugar/util.py
+++ b/sugar/util.py
@@ -25,50 +25,50 @@ from ConfigParser import ConfigParser
from ConfigParser import NoOptionError
def printable_hash(in_hash):
- """Convert binary hash data into printable characters."""
- printable = ""
- for char in in_hash:
- printable = printable + binascii.b2a_hex(char)
- return printable
+ """Convert binary hash data into printable characters."""
+ printable = ""
+ for char in in_hash:
+ printable = printable + binascii.b2a_hex(char)
+ return printable
def _sha_data(data):
- """sha1 hash some bytes."""
- sha_hash = sha.new()
- sha_hash.update(data)
- return sha_hash.digest()
+ """sha1 hash some bytes."""
+ sha_hash = sha.new()
+ sha_hash.update(data)
+ return sha_hash.digest()
def unique_id(data = ''):
- data_string = "%s%s%s" % (time.time(), random.randint(10000, 100000), data)
- return printable_hash(_sha_data(data_string))
+ data_string = "%s%s%s" % (time.time(), random.randint(10000, 100000), data)
+ return printable_hash(_sha_data(data_string))
ACTIVITY_ID_LEN = 40
def is_hex(s):
- return s.strip(string.hexdigits) == ''
+ return s.strip(string.hexdigits) == ''
def validate_activity_id(actid):
- """Validate an activity ID."""
- if not isinstance(actid, str) and not isinstance(actid, unicode):
- return False
- if len(actid) != ACTIVITY_ID_LEN:
- return False
- if not is_hex(actid):
- return False
- return True
+ """Validate an activity ID."""
+ if not isinstance(actid, str) and not isinstance(actid, unicode):
+ return False
+ if len(actid) != ACTIVITY_ID_LEN:
+ return False
+ if not is_hex(actid):
+ return False
+ return True
class _ServiceParser(ConfigParser):
- def optionxform(self, option):
- return option
+ def optionxform(self, option):
+ return option
def write_service(name, bin, path):
- service_cp = _ServiceParser()
- section = 'D-BUS Service'
- service_cp.add_section(section)
- service_cp.set(section, 'Name', name)
- service_cp.set(section, 'Exec', bin)
+ service_cp = _ServiceParser()
+ section = 'D-BUS Service'
+ service_cp.add_section(section)
+ service_cp.set(section, 'Name', name)
+ service_cp.set(section, 'Exec', bin)
- dest_filename = os.path.join(path, name + '.service')
- fileobject = open(dest_filename, 'w')
- service_cp.write(fileobject)
- fileobject.close()
+ dest_filename = os.path.join(path, name + '.service')
+ fileobject = open(dest_filename, 'w')
+ service_cp.write(fileobject)
+ fileobject.close()
diff --git a/tests/bundle/Test.activity/testactivity.py b/tests/bundle/Test.activity/testactivity.py
index 34cf8b4..ec8032c 100644
--- a/tests/bundle/Test.activity/testactivity.py
+++ b/tests/bundle/Test.activity/testactivity.py
@@ -1,5 +1,5 @@
from sugar.activity.Activity import Activity
class TestActivity(Activity):
- def __init__(self):
- Activity.__init__(self)
+ def __init__(self):
+ Activity.__init__(self)
diff --git a/tests/simulator/demo/others.py b/tests/simulator/demo/others.py
index 7fee290..0b87c0c 100644
--- a/tests/simulator/demo/others.py
+++ b/tests/simulator/demo/others.py
@@ -19,19 +19,19 @@ import random
from sugar.simulator import Bot
for i in range(0, 8):
- bot = Bot()
+ bot = Bot()
- bot.wait(random.randint(10, 20))
- bot.join_activity('giraffes')
- bot.change_activity('giraffes')
+ bot.wait(random.randint(10, 20))
+ bot.join_activity('giraffes')
+ bot.change_activity('giraffes')
- bot.start()
+ bot.start()
for i in range(0, 6):
- bot = Bot()
+ bot = Bot()
- bot.wait(random.randint(10, 20))
- bot.join_activity('nekkhamma')
- bot.change_activity('nekkhamma')
+ bot.wait(random.randint(10, 20))
+ bot.join_activity('nekkhamma')
+ bot.change_activity('nekkhamma')
- bot.start()
+ bot.start()
diff --git a/tests/sketch/sketchactivity.py b/tests/sketch/sketchactivity.py
index 007d96e..31aff35 100644
--- a/tests/sketch/sketchactivity.py
+++ b/tests/sketch/sketchactivity.py
@@ -30,205 +30,205 @@ from sugar.graphics.iconcolor import IconColor
from sugar import profile
class NetworkController(gobject.GObject):
- __gsignals__ = {
- 'new-path':(gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT])),
- }
-
- def __init__(self, parent, ps_owner):
- gobject.GObject.__init__(self)
- self._parent = parent
- self._parent.connect('buddy-joined', self._buddy_joined)
- self._parent.connect('buddy-left', self._buddy_left)
- self._stream = None
- self._stream_writer = None
- self._joined_buddies = {} # IP address -> buddy
- self._ps_owner = ps_owner
-
- def init_stream(self, service):
- self._stream = Stream.new_from_service(service)
- self._stream.set_data_listener(self._recv_message)
- self._stream_writer = self._stream.new_writer()
-
- def _recv_message(self, address, msg):
- # Ignore multicast messages from ourself
- if self._ps_owner and address == self._ps_owner.get_ip4_address():
- return
-
- # Ensure the message comes from somebody in this activity
- if not self._joined_buddies.has_key(address):
- logging.debug("Message from unjoined buddy.")
- return
-
- # Convert the points to an array and send to the sketchpad
- points = []
- msg = msg.strip()
- split_coords = msg.split(" ")
- for item in split_coords:
- x = 0
- y = 0
- try:
- (x, y) = item.split(",")
- x = float(x)
- y = float(y)
- except ValueError:
- continue
- if x < 0 or y < 0:
- continue
- points.append((x, y))
-
- buddy = self._joined_buddies[address]
- self.emit("new-path", buddy, points)
-
- def _buddy_joined(self, widget, activity, buddy, activity_type):
- activity_service = buddy.get_service_of_type(activity_type, activity)
- if not activity_service:
- logging.debug("Buddy Joined, but could not get activity service " \
- "of %s" % activity_type)
- return
-
- address = activity_service.get_source_address()
- port = activity_service.get_port()
- if not address or not port:
- logging.debug("Buddy Joined, but could not get address/port from" \
- " activity service %s" % activity_type)
- return
- if not self._joined_buddies.has_key(address):
- logging.debug("Buddy joined: %s (%s)" % (address, port))
- self._joined_buddies[address] = buddy
-
- def _buddy_left(self, widget, activity, buddy, activity_type):
- buddy_key = None
- for (key, value) in self._joined_buddies.items():
- if value == buddy:
- buddy_key = key
- break
- if buddy_key:
- del self._joined_buddies[buddy_key]
-
- def new_local_sketch(self, path):
- """ Receive an array of point tuples the local user created """
- cmd = ""
- # Convert points into the wire format
- for point in path:
- cmd = cmd + "%d,%d " % (point[0], point[1])
-
- # If there were no points, or we aren't in a shared activity yet,
- # don't send anything
- if not len(cmd) or not self._stream_writer:
- return
-
- # Send the points to other buddies
- self._stream_writer.write(cmd)
+ __gsignals__ = {
+ 'new-path':(gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT])),
+ }
+
+ def __init__(self, parent, ps_owner):
+ gobject.GObject.__init__(self)
+ self._parent = parent
+ self._parent.connect('buddy-joined', self._buddy_joined)
+ self._parent.connect('buddy-left', self._buddy_left)
+ self._stream = None
+ self._stream_writer = None
+ self._joined_buddies = {} # IP address -> buddy
+ self._ps_owner = ps_owner
+
+ def init_stream(self, service):
+ self._stream = Stream.new_from_service(service)
+ self._stream.set_data_listener(self._recv_message)
+ self._stream_writer = self._stream.new_writer()
+
+ def _recv_message(self, address, msg):
+ # Ignore multicast messages from ourself
+ if self._ps_owner and address == self._ps_owner.get_ip4_address():
+ return
+
+ # Ensure the message comes from somebody in this activity
+ if not self._joined_buddies.has_key(address):
+ logging.debug("Message from unjoined buddy.")
+ return
+
+ # Convert the points to an array and send to the sketchpad
+ points = []
+ msg = msg.strip()
+ split_coords = msg.split(" ")
+ for item in split_coords:
+ x = 0
+ y = 0
+ try:
+ (x, y) = item.split(",")
+ x = float(x)
+ y = float(y)
+ except ValueError:
+ continue
+ if x < 0 or y < 0:
+ continue
+ points.append((x, y))
+
+ buddy = self._joined_buddies[address]
+ self.emit("new-path", buddy, points)
+
+ def _buddy_joined(self, widget, activity, buddy, activity_type):
+ activity_service = buddy.get_service_of_type(activity_type, activity)
+ if not activity_service:
+ logging.debug("Buddy Joined, but could not get activity service " \
+ "of %s" % activity_type)
+ return
+
+ address = activity_service.get_source_address()
+ port = activity_service.get_port()
+ if not address or not port:
+ logging.debug("Buddy Joined, but could not get address/port from" \
+ " activity service %s" % activity_type)
+ return
+ if not self._joined_buddies.has_key(address):
+ logging.debug("Buddy joined: %s (%s)" % (address, port))
+ self._joined_buddies[address] = buddy
+
+ def _buddy_left(self, widget, activity, buddy, activity_type):
+ buddy_key = None
+ for (key, value) in self._joined_buddies.items():
+ if value == buddy:
+ buddy_key = key
+ break
+ if buddy_key:
+ del self._joined_buddies[buddy_key]
+
+ def new_local_sketch(self, path):
+ """ Receive an array of point tuples the local user created """
+ cmd = ""
+ # Convert points into the wire format
+ for point in path:
+ cmd = cmd + "%d,%d " % (point[0], point[1])
+
+ # If there were no points, or we aren't in a shared activity yet,
+ # don't send anything
+ if not len(cmd) or not self._stream_writer:
+ return
+
+ # Send the points to other buddies
+ self._stream_writer.write(cmd)
def _html_to_rgb_color(colorstring):
- """ converts #RRGGBB to cairo-suitable floats"""
- colorstring = colorstring.strip()
- while colorstring[0] == '#':
- colorstring = colorstring[1:]
- r = int(colorstring[:2], 16)
- g = int(colorstring[2:4], 16)
- b = int(colorstring[4:6], 16)
- color = ((float(r) / 255.0), (float(g) / 255.0), (float(b) / 255.0))
- return color
+ """ converts #RRGGBB to cairo-suitable floats"""
+ colorstring = colorstring.strip()
+ while colorstring[0] == '#':
+ colorstring = colorstring[1:]
+ r = int(colorstring[:2], 16)
+ g = int(colorstring[2:4], 16)
+ b = int(colorstring[4:6], 16)
+ color = ((float(r) / 255.0), (float(g) / 255.0), (float(b) / 255.0))
+ return color
class SharedSketchPad(SketchPad.SketchPad):
- def __init__(self, net_controller, color):
- SketchPad.SketchPad.__init__(self, bgcolor=(1.0, 0.984313725, 0.560784314))
- self._net_controller = net_controller
- self._user_color = _html_to_rgb_color(color)
- self.set_color(self._user_color)
-
- # Receive notifications when our buddies send us new sketches
- self._net_controller.connect('new-path', self._new_buddy_path)
-
- self.connect('new-user-sketch', self._new_local_sketch_cb)
-
- def _new_buddy_path(self, net_controller, buddy, path):
- """ Called whenever a buddy on the mesh sends us a new sketch path """
- str_color = buddy.get_color()
- if not str_color:
- str_color = "#348798" # FIXME
- color = IconColor(str_color)
- stroke_color = _html_to_rgb_color(color.get_stroke_color())
- sketch = Sketch.Sketch(stroke_color)
- for item in path:
- sketch.add_point(item[0], item[1])
- self.add_sketch(sketch)
-
- def _new_local_sketch_cb(self, widget, sketch):
- """ Send the sketch the user just made to the network """
- self._net_controller.new_local_sketch(sketch.get_points())
+ def __init__(self, net_controller, color):
+ SketchPad.SketchPad.__init__(self, bgcolor=(1.0, 0.984313725, 0.560784314))
+ self._net_controller = net_controller
+ self._user_color = _html_to_rgb_color(color)
+ self.set_color(self._user_color)
+
+ # Receive notifications when our buddies send us new sketches
+ self._net_controller.connect('new-path', self._new_buddy_path)
+
+ self.connect('new-user-sketch', self._new_local_sketch_cb)
+
+ def _new_buddy_path(self, net_controller, buddy, path):
+ """ Called whenever a buddy on the mesh sends us a new sketch path """
+ str_color = buddy.get_color()
+ if not str_color:
+ str_color = "#348798" # FIXME
+ color = IconColor(str_color)
+ stroke_color = _html_to_rgb_color(color.get_stroke_color())
+ sketch = Sketch.Sketch(stroke_color)
+ for item in path:
+ sketch.add_point(item[0], item[1])
+ self.add_sketch(sketch)
+
+ def _new_local_sketch_cb(self, widget, sketch):
+ """ Send the sketch the user just made to the network """
+ self._net_controller.new_local_sketch(sketch.get_points())
class SketchActivity(Activity):
- __gsignals__ = {
- 'buddy-joined':(gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT])),
- 'buddy-left': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT]))
- }
-
- def __init__(self):
- Activity.__init__(self)
- self.connect('destroy', self._cleanup_cb)
-
- self.set_title("Sketch")
-
- self._ps = PresenceService.get_instance()
- self._ps_activity = None
- self._owner = self._ps.get_owner()
-
- self._net_controller = NetworkController(self, self._owner)
- self._sketchpad = SharedSketchPad(self._net_controller,
- profile.get_color().get_stroke_color())
- self.add(self._sketchpad)
- self.show_all()
-
- def get_ps(self):
- return self._ps
-
- def _cleanup_cb(self):
- del self._net_controller
-
- def share(self):
- Activity.share(self)
- self._net_controller.init_stream(self._service)
- self._ps.connect('activity-appeared', self._activity_appeared_cb)
-
- def join(self, activity_ps):
- Activity.join(self, activity_ps)
- self._net_controller.init_stream(self._service)
- self._ps.connect('activity-appeared', self._activity_appeared_cb)
- self._activity_appeared_cb(self._ps, activity_ps)
-
- def _activity_appeared_cb(self, ps, activity):
- # Only care about our own activity
- if activity.get_id() != self.get_id():
- return
-
- # If we already have found our shared activity, do nothing
- if self._ps_activity:
- return
-
- self._ps_activity = activity
-
- # Connect signals to the shared activity so we are notified when
- # buddies join and leave
- self._ps_activity.connect('buddy-joined', self._add_buddy)
- self._ps_activity.connect('buddy-left', self._remove_buddy)
-
- # Get the list of buddies already in this shared activity so we can
- # connect to them
- buddies = self._ps_activity.get_joined_buddies()
- for buddy in buddies:
- self._add_buddy(self._ps_activity, buddy)
-
- def _add_buddy(self, ps_activity, buddy):
- service_type = self._ps_activity
- self.emit('buddy-joined', ps_activity, buddy, self.get_default_type())
-
- def _remove_buddy(self, ps_activity, buddy):
- self.emit('buddy-left', ps_activity, buddy, self.get_default_type())
+ __gsignals__ = {
+ 'buddy-joined':(gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT])),
+ 'buddy-left': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT]))
+ }
+
+ def __init__(self):
+ Activity.__init__(self)
+ self.connect('destroy', self._cleanup_cb)
+
+ self.set_title("Sketch")
+
+ self._ps = PresenceService.get_instance()
+ self._ps_activity = None
+ self._owner = self._ps.get_owner()
+
+ self._net_controller = NetworkController(self, self._owner)
+ self._sketchpad = SharedSketchPad(self._net_controller,
+ profile.get_color().get_stroke_color())
+ self.add(self._sketchpad)
+ self.show_all()
+
+ def get_ps(self):
+ return self._ps
+
+ def _cleanup_cb(self):
+ del self._net_controller
+
+ def share(self):
+ Activity.share(self)
+ self._net_controller.init_stream(self._service)
+ self._ps.connect('activity-appeared', self._activity_appeared_cb)
+
+ def join(self, activity_ps):
+ Activity.join(self, activity_ps)
+ self._net_controller.init_stream(self._service)
+ self._ps.connect('activity-appeared', self._activity_appeared_cb)
+ self._activity_appeared_cb(self._ps, activity_ps)
+
+ def _activity_appeared_cb(self, ps, activity):
+ # Only care about our own activity
+ if activity.get_id() != self.get_id():
+ return
+
+ # If we already have found our shared activity, do nothing
+ if self._ps_activity:
+ return
+
+ self._ps_activity = activity
+
+ # Connect signals to the shared activity so we are notified when
+ # buddies join and leave
+ self._ps_activity.connect('buddy-joined', self._add_buddy)
+ self._ps_activity.connect('buddy-left', self._remove_buddy)
+
+ # Get the list of buddies already in this shared activity so we can
+ # connect to them
+ buddies = self._ps_activity.get_joined_buddies()
+ for buddy in buddies:
+ self._add_buddy(self._ps_activity, buddy)
+
+ def _add_buddy(self, ps_activity, buddy):
+ service_type = self._ps_activity
+ self.emit('buddy-joined', ps_activity, buddy, self.get_default_type())
+
+ def _remove_buddy(self, ps_activity, buddy):
+ self.emit('buddy-left', ps_activity, buddy, self.get_default_type())
diff --git a/tests/test-snowflake-box.py b/tests/test-snowflake-box.py
index 242ba42..d56993b 100755
--- a/tests/test-snowflake-box.py
+++ b/tests/test-snowflake-box.py
@@ -32,17 +32,17 @@ from sugar.graphics.iconcolor import IconColor
from sugar.graphics.canvasicon import CanvasIcon
def _create_snowflake(parent, children):
- color = IconColor()
- icon = CanvasIcon(size=40, color=color,
- icon_name='activity-groupchat')
- parent.append(icon, hippo.PACK_FIXED)
- parent.set_root(icon)
-
- for i in range(0, children):
- color = IconColor()
- icon = CanvasIcon(size=60, color=color,
- icon_name='stock-buddy')
- parent.append(icon, hippo.PACK_FIXED)
+ color = IconColor()
+ icon = CanvasIcon(size=40, color=color,
+ icon_name='activity-groupchat')
+ parent.append(icon, hippo.PACK_FIXED)
+ parent.set_root(icon)
+
+ for i in range(0, children):
+ color = IconColor()
+ icon = CanvasIcon(size=60, color=color,
+ icon_name='stock-buddy')
+ parent.append(icon, hippo.PACK_FIXED)
window = gtk.Window()
window.set_default_size(gtk.gdk.screen_width(), gtk.gdk.screen_height())
diff --git a/tests/test-spread-box.py b/tests/test-spread-box.py
index a5da735..0f138cc 100755
--- a/tests/test-spread-box.py
+++ b/tests/test-spread-box.py
@@ -31,13 +31,13 @@ from sugar.graphics.iconcolor import IconColor
from sugar.graphics.canvasicon import CanvasIcon
def _create_icon():
- color = IconColor()
+ color = IconColor()
- icon = CanvasIcon(size=100, color=color,
- icon_name='stock-buddy')
- box.add_item(icon)
+ icon = CanvasIcon(size=100, color=color,
+ icon_name='stock-buddy')
+ box.add_item(icon)
- return (len(box.get_children()) < 20)
+ return (len(box.get_children()) < 20)
window = gtk.Window()
window.connect("destroy", lambda w: gtk.main_quit())
diff --git a/tests/test-window-manager.py b/tests/test-window-manager.py
index 5a0274b..dff2b98 100644
--- a/tests/test-window-manager.py
+++ b/tests/test-window-manager.py
@@ -27,15 +27,15 @@ session.start()
import gtk
def _show_dialog(window):
- dialog = gtk.Dialog(title='No Unviewed Media',
- parent=window, flags=gtk.DIALOG_MODAL,
- buttons=(gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
- label = gtk.Label('There is no unviewed media to download.')
- dialog.vbox.pack_start(label, True, True, 0)
- label.show()
- response = dialog.run()
- dialog.hide()
- del dialog
+ dialog = gtk.Dialog(title='No Unviewed Media',
+ parent=window, flags=gtk.DIALOG_MODAL,
+ buttons=(gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
+ label = gtk.Label('There is no unviewed media to download.')
+ dialog.vbox.pack_start(label, True, True, 0)
+ label.show()
+ response = dialog.run()
+ dialog.hide()
+ del dialog
window = gtk.Window()
window.show()