Merge branch 'master' of git+ssh://dev.laptop.org/git/sugar

This commit is contained in:
Marco Pesenti Gritti 2007-03-09 11:24:38 +01:00
commit 1d70e212c7
6 changed files with 236 additions and 76 deletions

View File

@ -15,32 +15,118 @@
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import gobject
import dbus, dbus.service import dbus, dbus.service
from sugar import util
from telepathy.interfaces import (CHANNEL_INTERFACE) from telepathy.interfaces import (CHANNEL_INTERFACE)
_ACTIVITY_PATH = "/org/laptop/Sugar/Presence/Activities/" _ACTIVITY_PATH = "/org/laptop/Sugar/Presence/Activities/"
_ACTIVITY_INTERFACE = "org.laptop.Sugar.Presence.Activity" _ACTIVITY_INTERFACE = "org.laptop.Sugar.Presence.Activity"
class Activity(dbus.service.Object): class DBusGObjectMetaclass(gobject.GObjectMeta, dbus.service.InterfaceType): pass
def __init__(self, bus_name, object_id, activity_id, tp): class DBusGObject(dbus.service.Object, gobject.GObject): __metaclass__ = DBusGObjectMetaclass
self._buddies = []
self._color = None
self._valid = False class Activity(DBusGObject):
self._name = None __gtype_name__ = "Activity"
self._activity_id = activity_id
__gsignals__ = {
'validity-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([gobject.TYPE_BOOLEAN]))
}
__gproperties__ = {
'id' : (str, None, None, None,
gobject.PARAM_READWRITE | gobject.PARAM_CONSTRUCT_ONLY),
'name' : (str, None, None, None, gobject.PARAM_READWRITE),
'color' : (str, None, None, None, gobject.PARAM_READWRITE),
'type' : (str, None, None, None, gobject.PARAM_READWRITE),
'valid' : (bool, None, None, False, gobject.PARAM_READABLE),
'local' : (bool, None, None, False,
gobject.PARAM_READWRITE | gobject.PARAM_CONSTRUCT_ONLY),
'joined' : (bool, None, None, False, gobject.PARAM_READABLE)
}
def __init__(self, bus_name, object_id, tp, **kwargs):
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")
if not tp:
raise ValueError("telepathy CM must be valid")
self._object_id = object_id self._object_id = object_id
self._object_path = "/org/laptop/Presence/Activities/%d" % self._object_id self._object_path = _ACTIVITY_PATH + str(self._object_id)
dbus.service.Object.__init__(self, bus_name, self._object_path)
self._buddies = []
self._joined = False
# the telepathy client # the telepathy client
self._tp = tp self._tp = tp
self._activity_text_channel = None self._activity_text_channel = None
self._joined = False self._valid = False
self._id = None
self._local = False
self._type = None
dbus.service.Object.__init__(self, bus_name, self._object_path) if not kwargs.get("id"):
raise ValueError("activity id is required")
if not util.validate_activity_id(kwargs['id']):
raise ValueError("Invalid activity id '%s'" % kwargs['id'])
gobject.GObject.__init__(self, **kwargs)
if self.props.local and not self.props.valid:
raise RuntimeError("local activities require color, type, and name")
def do_get_property(self, pspec):
if pspec.name == "id":
return self._id
elif pspec.name == "name":
return self._name
elif pspec.name == "color":
return self._color
elif pspec.name == "type":
return self._type
elif pspec.name == "valid":
return self._valid
elif pspec.name == "joined":
return self._joined
elif pspec.name == "local":
return self._local
def do_set_property(self, pspec, value):
if pspec.name == "id":
self._id = value
elif pspec.name == "name":
self._name = value
elif pspec.name == "color":
self._color = value
elif pspec.name == "type":
if self._type:
raise RuntimeError("activity type is already set")
self._type = value
elif pspec.name == "joined":
self._joined = value
elif pspec.name == "local":
self._local = value
self._update_validity()
def _update_validity(self):
try:
old_valid = self._valid
if self._color and self._name and self._id and self._type:
self._valid = True
else:
self._valid = False
if old_valid != self._valid:
self.emit("validity-changed", self._valid)
except AttributeError:
self._valid = False
# dbus signals # dbus signals
@dbus.service.signal(_ACTIVITY_INTERFACE, @dbus.service.signal(_ACTIVITY_INTERFACE,
@ -62,12 +148,17 @@ class Activity(dbus.service.Object):
@dbus.service.method(_ACTIVITY_INTERFACE, @dbus.service.method(_ACTIVITY_INTERFACE,
in_signature="", out_signature="s") in_signature="", out_signature="s")
def GetId(self): def GetId(self):
return self.get_id() return self.props.id
@dbus.service.method(_ACTIVITY_INTERFACE, @dbus.service.method(_ACTIVITY_INTERFACE,
in_signature="", out_signature="s") in_signature="", out_signature="s")
def GetColor(self): def GetColor(self):
return self.get_color() return self.props.color
@dbus.service.method(_ACTIVITY_INTERFACE,
in_signature="", out_signature="s")
def GetType(self):
return self.props.type
@dbus.service.method(_ACTIVITY_INTERFACE, @dbus.service.method(_ACTIVITY_INTERFACE,
in_signature="", out_signature="") in_signature="", out_signature="")
@ -77,8 +168,10 @@ class Activity(dbus.service.Object):
@dbus.service.method(_ACTIVITY_INTERFACE, @dbus.service.method(_ACTIVITY_INTERFACE,
in_signature="", out_signature="ao") in_signature="", out_signature="ao")
def GetJoinedBuddies(self): def GetJoinedBuddies(self):
ret = []
for buddy in self._buddies: for buddy in self._buddies:
ret.append(buddy.object_path()) if buddy.props.valid:
ret.append(buddy.object_path())
return ret return ret
@dbus.service.method(_ACTIVITY_INTERFACE, @dbus.service.method(_ACTIVITY_INTERFACE,
@ -89,41 +182,34 @@ class Activity(dbus.service.Object):
@dbus.service.method(_ACTIVITY_INTERFACE, @dbus.service.method(_ACTIVITY_INTERFACE,
in_signature="", out_signature="s") in_signature="", out_signature="s")
def GetName(self): def GetName(self):
return self.get_name() return self.props.name
# methods # methods
def object_path(self): def object_path(self):
return dbus.ObjectPath(self._object_path) 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_joined_buddies(self): def get_joined_buddies(self):
return self._buddies ret = []
for buddy in self._buddies:
def get_name(self): if buddy.props.valid:
return self._name ret.append(buddy)
return ret
def buddy_joined(self, buddy): def buddy_joined(self, buddy):
if buddy not in self._buddies: if buddy not in self._buddies:
self._buddies.append(buddy) self._buddies.append(buddy)
self.BuddyJoined(buddy.object_path()) if self.props.valid:
self.BuddyJoined(buddy.object_path())
def buddy_left(self, buddy): def buddy_left(self, buddy):
if buddy in self._buddies: if buddy in self._buddies:
self._buddies.remove(buddy) self._buddies.remove(buddy)
self.BuddyLeft(buddy.object_path()) if self.props.valid:
self.BuddyLeft(buddy.object_path())
def join(self): def join(self):
if not self._joined: if not self._joined:
self._activity_text_channel = self._tp.join_activity(self._activity_id) self._activity_text_channel = self._tp.join_activity(self.props.id)
self._activity_text_channel[CHANNEL_INTERFACE].connect_to_signal('Closed', self._activity_text_channel_closed_cb) self._activity_text_channel[CHANNEL_INTERFACE].connect_to_signal('Closed', self._activity_text_channel_closed_cb)
self._joined = True self._joined = True

View File

@ -73,9 +73,10 @@ class Buddy(DBusGObject):
self._key = None self._key = None
self._icon = '' self._icon = ''
if not kwargs.get("key"):
raise ValueError("key required")
gobject.GObject.__init__(self, **kwargs) gobject.GObject.__init__(self, **kwargs)
if not self._key:
raise RuntimeError("public key required")
def do_get_property(self, pspec): def do_get_property(self, pspec):
if pspec.name == "key": if pspec.name == "key":
@ -109,8 +110,6 @@ class Buddy(DBusGObject):
elif pspec.name == "current-activity": elif pspec.name == "current-activity":
self._current_activity = value self._current_activity = value
elif pspec.name == "key": elif pspec.name == "key":
if self._key:
raise RuntimeError("key already set")
self._key = value self._key = value
self._update_validity() self._update_validity()
@ -167,25 +166,25 @@ class Buddy(DBusGObject):
return dbus.ObjectPath(self._object_path) return dbus.ObjectPath(self._object_path)
def add_activity(self, activity): def add_activity(self, activity):
actid = activity.get_id() actid = activity.props.id
if self._activities.has_key(actid): if self._activities.has_key(actid):
return return
self._activities[actid] = activity self._activities[actid] = activity
if activity.is_valid(): if activity.props.valid:
self.JoinedActivity(activity.object_path()) self.JoinedActivity(activity.object_path())
def remove_activity(self, activity): def remove_activity(self, activity):
actid = activity.get_id() actid = activity.props.id
if not self._activities.has_key(actid): if not self._activities.has_key(actid):
return return
del self._activities[actid] del self._activities[actid]
if activity.is_valid(): if activity.props.valid:
self.LeftActivity(activity.object_path()) self.LeftActivity(activity.object_path())
def get_joined_activities(self): def get_joined_activities(self):
acts = [] acts = []
for act in self._activities.values(): for act in self._activities.values():
if act.is_valid(): if act.props.valid:
acts.append(act) acts.append(act)
return acts return acts

View File

@ -134,25 +134,38 @@ class PresenceService(dbus.service.Object):
buddy = self._handles_buddies[tp].get(handle) buddy = self._handles_buddies[tp].get(handle)
if buddy: if buddy:
buddy.set_properties(prop) buddy.set_properties(prop)
print "Buddy %s properties updated" % buddy.props.key #print "Buddy %s properties updated" % buddy.props.key
def _new_activity(self, activity_id, tp): def _new_activity(self, activity_id, tp):
objid = self._get_next_object_id() try:
activity = Activity(self._bus_name, objid, activity_id, tp) objid = self._get_next_object_id()
# FIXME : don't do that shit ! activity = Activity(self._bus_name, objid, tp, id=activity_id)
activity._valid = True except Exception, e:
print "Invalid activity: %s" % e
return None
activity.connect("validity-changed", self._activity_validity_changed_cb)
self._activities[activity_id] = activity self._activities[activity_id] = activity
print "new activity", activity_id # FIXME
self.ActivityAppeared(activity.object_path()) # Use values from the network
import random
names = ["Tommy", "Susie", "Jill", "Bryan", "Nathan", "Sophia", "Haley", "Jimmy"]
name = names[random.randint(0, len(names) - 1)]
activity.props.name = "Chat with %s" % name
activity.props.type = "org.laptop.Sugar.Chat"
from sugar.graphics import xocolor
color = xocolor.XoColor().to_string()
activity.props.color = color
return activity return activity
def _remove_activity(self, activity): def _remove_activity(self, activity):
print "remove activity", activity.get_id() print "remove activity", activity.props.id
self.ActivityDisappeared(activity.object_path()) self.ActivityDisappeared(activity.object_path())
del self._activities[activity.get_id()] del self._activities[activity.props.id]
def _contact_activities_changed(self, tp, contact_handle, activities): def _contact_activities_changed(self, tp, contact_handle, activities):
print "------------activities changed-------------" print "------------activities changed-------------"
@ -168,7 +181,7 @@ class PresenceService(dbus.service.Object):
old_activities = set() old_activities = set()
for activity in buddy.get_joined_activities(): for activity in buddy.get_joined_activities():
old_activities.add(activity.get_id()) old_activities.add(activity.props.id)
new_activities = set(activities) new_activities = set(activities)
@ -177,11 +190,12 @@ class PresenceService(dbus.service.Object):
print "buddy", contact_handle, "joined", act print "buddy", contact_handle, "joined", act
activity = self._activities.get(act) activity = self._activities.get(act)
if not activity: if not activity:
# new activity # new activity, can fail
activity = self._new_activity(act, tp) activity = self._new_activity(act, tp)
activity.buddy_joined(buddy) if activity:
buddy.add_activity(activity) activity.buddy_joined(buddy)
buddy.add_activity(activity)
activities_left = old_activities - new_activities activities_left = old_activities - new_activities
for act in activities_left: for act in activities_left:
@ -278,18 +292,24 @@ class PresenceService(dbus.service.Object):
def _share_activity(self, actid, atype, name, properties): def _share_activity(self, actid, atype, name, properties):
objid = self._get_next_object_id() objid = self._get_next_object_id()
# FIXME check which tp client we should use to share the activity # FIXME check which tp client we should use to share the activity
activity = Activity(self._bus_name, objid, actid, self._server_plugin) color = self._owner.props.color
# FIXME : don't do that shit ! activity = Activity(self._bus_name, objid, self._server_plugin,
activity._valid = True id=actid, type=atype, name=name, color=color, local=True)
activity.connect("validity-changed", self._activity_validity_changed_cb)
self._activities[actid] = activity self._activities[actid] = activity
# FIXME set the type, name, properties...
print "new activity", actid
activity.join() activity.join()
self.ActivityAppeared(activity.object_path())
return activity return activity
def _activity_validity_changed_cb(self, activity, valid):
if valid:
self.ActivityAppeared(activity.object_path())
print "New Activity: %s (%s)" % (activity.props.name, activity.props.id)
else:
self.ActivityDisappeared(activity.object_path())
print "Activity disappeared: %s (%s)" % (activity.props.name, activity.props.id)
def main(): def main():
loop = gobject.MainLoop() loop = gobject.MainLoop()

View File

@ -218,9 +218,7 @@ class ServerPlugin(gobject.GObject):
self._conn[CONN_INTERFACE_AVATARS].connect_to_signal('AvatarUpdated', self._avatar_updated_cb) self._conn[CONN_INTERFACE_AVATARS].connect_to_signal('AvatarUpdated', self._avatar_updated_cb)
# FIXME: we need to use PEP to store the nick. We aren't notified when self._conn[CONN_INTERFACE_ALIASING].connect_to_signal('AliasesChanged', self._alias_changed_cb)
# vcards are changed
#self._conn[CONN_INTERFACE_ALIASING].connect_to_signal('AliasesChanged', self._alias_changed_cb)
try: try:
self._set_self_buddy_info() self._set_self_buddy_info()
@ -406,9 +404,8 @@ class ServerPlugin(gobject.GObject):
def _alias_changed_cb(self, aliases): def _alias_changed_cb(self, aliases):
for handle, alias in aliases: for handle, alias in aliases:
nick = self._conn[CONN_INTERFACE_ALIASING].RequestAliases([handle])[0] prop = {'nick': alias}
prop = {'nick': nick} #print "Buddy %s alias changed to %s" % (handle, alias)
print "Buddy %s alias changed to %s" % (handle, nick)
self._properties_changed_cb(handle, prop) self._properties_changed_cb(handle, prop)
def _properties_changed_cb(self, contact, properties): def _properties_changed_cb(self, contact, properties):

View File

@ -14,6 +14,7 @@
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import gobject
import os import os
import random import random
import base64 import base64
@ -30,11 +31,24 @@ from model.Invites import Invites
PRESENCE_SERVICE_TYPE = "_presence_olpc._tcp" PRESENCE_SERVICE_TYPE = "_presence_olpc._tcp"
class ShellOwner(object): class ShellOwner(gobject.GObject):
__gtype_name__ = "ShellOwner"
__gsignals__ = {
'nick-changed' : (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([gobject.TYPE_STRING])),
'color-changed' : (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([gobject.TYPE_PYOBJECT])),
'icon-changed' : (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([gobject.TYPE_PYOBJECT]))
}
"""Class representing the owner of this machine/instance. This class """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 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.""" server portion of the Owner, paired with the client portion in Buddy.py."""
def __init__(self): def __init__(self):
gobject.GObject.__init__(self)
self._nick = profile.get_nick_name() self._nick = profile.get_nick_name()
user_dir = env.get_profile_path() user_dir = env.get_profile_path()
@ -45,12 +59,14 @@ class ShellOwner(object):
continue continue
fd = open(os.path.join(user_dir, fname), "r") fd = open(os.path.join(user_dir, fname), "r")
self._icon = fd.read() 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() fd.close()
if not self._icon:
raise RuntimeError("No buddy icon exists")
# Get the icon's hash
import md5, binascii
digest = md5.new(self._icon).digest()
self._icon_hash = util.printable_hash(digest)
break break
self._pservice = PresenceService.get_instance() self._pservice = PresenceService.get_instance()
@ -60,6 +76,7 @@ class ShellOwner(object):
self._last_activity_update = time.time() self._last_activity_update = time.time()
self._pending_activity_update_timer = None self._pending_activity_update_timer = None
self._pending_activity_update = None self._pending_activity_update = None
self._current_activity = None
def get_invites(self): def get_invites(self):
return self._invites return self._invites
@ -94,6 +111,7 @@ class ShellOwner(object):
self._last_activity_update = time.time() self._last_activity_update = time.time()
self._pending_activity_update_timer = None self._pending_activity_update_timer = None
if self._pending_activity_update: if self._pending_activity_update:
self.emit('current-activity-changed', self._pending_activity_update)
logging.debug("*** Updating current activity to %s" % 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)) self._service.set_published_value('curact', dbus.String(self._pending_activity_update))
return False return False

View File

@ -4,18 +4,58 @@ from sugar.activity import bundleregistry
_DBUS_SERVICE = "org.laptop.Shell" _DBUS_SERVICE = "org.laptop.Shell"
_DBUS_INTERFACE = "org.laptop.Shell" _DBUS_INTERFACE = "org.laptop.Shell"
_DBUS_OWNER_INTERFACE = "org.laptop.Shell.Owner"
_DBUS_PATH = "/org/laptop/Shell" _DBUS_PATH = "/org/laptop/Shell"
class ShellService(dbus.service.Object): class ShellService(dbus.service.Object):
def __init__(self, shellModel): def __init__(self, shell_model):
self._shellModel = shellModel self._shell_model = shell_model
self._owner = self._shell_model.get_owner()
self._owner.connect('nick-changed', self._owner_nick_changed_cb)
self._owner.connect('icon-changed', self._owner_icon_changed_cb)
self._owner.connect('color-changed', self._owner_color_changed_cb)
self._home_model = self._shell_model.get_home()
self._home_model.connect('active-activity-changed', self._cur_activity_changed_cb)
bus = dbus.SessionBus() bus = dbus.SessionBus()
bus_name = dbus.service.BusName(_DBUS_SERVICE, bus=bus) bus_name = dbus.service.BusName(_DBUS_SERVICE, bus=bus)
dbus.service.Object.__init__(self, bus_name, _DBUS_PATH) dbus.service.Object.__init__(self, bus_name, _DBUS_PATH)
@dbus.service.method(_DBUS_INTERFACE, in_signature="s", out_signature="b") @dbus.service.method(_DBUS_INTERFACE, in_signature="s", out_signature="b")
def add_bundle(self, bundle_path): def add_bundle(self, bundle_path):
registry = bundleregistry.get_registry() registry = bundleregistry.get_registry()
return registry.add_bundle(bundle_path) return registry.add_bundle(bundle_path)
@dbus.service.signal(_DBUS_OWNER_INTERFACE, signature="s")
def ColorChanged(self, color):
pass
def _owner_color_changed_cb(self, new_color):
self.ColorChanged(new_color.to_string())
@dbus.service.signal(_DBUS_OWNER_INTERFACE, signature="s")
def NickChanged(self, nick):
pass
def _owner_nick_changed_cb(self, new_nick):
self.NickChanged(new_nick)
@dbus.service.signal(_DBUS_OWNER_INTERFACE, signature="ay")
def IconChanged(self, icon_data):
pass
def _owner_icon_changed_cb(self, new_icon):
self.IconChanged(dbus.ByteArray(new_icon))
@dbus.service.signal(_DBUS_OWNER_INTERFACE, signature="s")
def CurrentActivityChanged(self, activity_id):
pass
def _cur_activity_changed_cb(self, owner, new_activity):
new_id = ""
if new_activity:
new_id = new_activity.get_id()
self.CurrentActivityChanged(new_id)