Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMorgan Collett <morgan.collett@collabora.co.uk>2007-06-07 18:26:27 (GMT)
committer Morgan Collett <morgan.collett@collabora.co.uk>2007-06-07 18:26:27 (GMT)
commit01076ff22a8bcefa7155d9f67874e75d72a50bce (patch)
tree2339f9278943ce0c0ba4048d3f816ed9020f1fa5
Initial import
-rw-r--r--.gitignore3
-rw-r--r--activity.py206
-rw-r--r--activity/activity-hellomesh.svg16
-rw-r--r--activity/activity.info7
-rwxr-xr-xsetup.py22
-rw-r--r--tubeconn.py107
6 files changed, 361 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..1912417
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+Connect-*.xo
+*.pyc
+.*.sw[op]
diff --git a/activity.py b/activity.py
new file mode 100644
index 0000000..fb0eebe
--- /dev/null
+++ b/activity.py
@@ -0,0 +1,206 @@
+# Copyright 2007 Collabora Ltd.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+"""HelloMesh Activity: A case study for collaboration using Tubes."""
+
+import dbus
+import hippo
+import gtk
+import pango
+import logging
+import telepathy
+import telepathy.client
+
+from sugar import profile
+from sugar.activity.activity import Activity, ActivityToolbox
+from sugar.graphics import font
+from sugar.graphics.canvasicon import CanvasIcon
+from sugar.graphics.roundbox import RoundBox
+from sugar.graphics.xocolor import XoColor
+from sugar.graphics.units import points_to_pixels as px
+from sugar.presence import presenceservice
+
+# will eventually be imported from telepathy.tubes or something
+from tubeconn import TubeConnection
+
+logger = logging.getLogger('hellomesh-activity')
+
+class HelloMeshActivity(Activity):
+ """HelloMesh Activity as specified in activity.info"""
+ def __init__(self, handle):
+ """Set up the HelloMesh activity."""
+ Activity.__init__(self, handle)
+ self.set_title('HelloMesh Activity')
+
+ # top toolbar with share and close buttons:
+ toolbox = ActivityToolbox(self)
+ self.set_toolbox(toolbox)
+ toolbox.show()
+
+ # Hippo Canvas:
+ hbox = hippo.CanvasBox(spacing=4,
+ orientation=hippo.ORIENTATION_HORIZONTAL)
+
+ self.main_panel = hippo.CanvasBox(spacing=4,
+ orientation=hippo.ORIENTATION_VERTICAL)
+ self.entry = gtk.Entry()
+ self.main_panel.append(hippo.CanvasWidget(widget=self.entry))
+ hbox.append(self.main_panel, hippo.PACK_EXPAND)
+
+ canvas = hippo.Canvas()
+ canvas.set_root(hbox)
+ self.set_canvas(canvas)
+ self.show_all()
+
+ # get the Presence Service
+ self.pservice = presenceservice.get_instance()
+ bus = dbus.Bus()
+ name, path = self.pservice.get_preferred_connection()
+ self.tp_conn_name = name
+ self.tp_conn_path = path
+ self.conn = telepathy.client.Connection(name, path)
+ self.initiating = None
+
+ self.connect('shared', self._shared_cb)
+
+ # Buddy object for you
+ owner = self.pservice.get_owner()
+ self.owner = owner
+
+ if self._shared_activity:
+ # we are joining the activity
+ self.connect('joined', self._joined_cb)
+ self._shared_activity.connect('buddy-joined',
+ self._buddy_joined_cb)
+ self._shared_activity.connect('buddy-left',
+ self._buddy_left_cb)
+ if self.get_shared():
+ # we've already joined
+ self._joined_cb()
+ else:
+ # we are creating the activity
+ pass
+
+ def _shared_cb(self, activity):
+ logger.debug('My activity was shared')
+ self.initiating = True
+ self._setup()
+
+ for buddy in self._shared_activity.get_joined_buddies():
+ pass # XXX
+
+ self._shared_activity.connect('buddy-joined', self._buddy_joined_cb)
+ self._shared_activity.connect('buddy-left', self._buddy_left_cb)
+
+ logger.debug('This is my activity: making a tube...')
+ id = self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].OfferTube(
+ telepathy.TUBE_TYPE_DBUS, SERVICE, {})
+
+ # FIXME: presence service should be tubes-aware and give us more help
+ # with this
+ def _setup(self):
+ if self._shared_activity is None:
+ logger.error('Failed to share or join activity')
+ return
+
+ bus_name, conn_path, channel_paths =\
+ self._shared_activity.get_channels()
+
+ # Work out what our room is called and whether we have Tubes already
+ room = None
+ tubes_chan = None
+ text_chan = None
+ for channel_path in channel_paths:
+ channel = telepathy.client.Channel(bus_name, channel_path)
+ htype, handle = channel.GetHandle()
+ if htype == telepathy.HANDLE_TYPE_ROOM:
+ logger.debug('Found our room: it has handle#%d "%s"',
+ handle, self.conn.InspectHandles(htype, [handle])[0])
+ room = handle
+ ctype = channel.GetChannelType()
+ if ctype == telepathy.CHANNEL_TYPE_TUBES:
+ logger.debug('Found our Tubes channel at %s', channel_path)
+ tubes_chan = channel
+ elif ctype == telepathy.CHANNEL_TYPE_TEXT:
+ logger.debug('Found our Text channel at %s', channel_path)
+ text_chan = channel
+
+ if room is None:
+ logger.error("Presence service didn't create a room")
+ return
+ if text_chan is None:
+ logger.error("Presence service didn't create a text channel")
+ return
+
+ # Make sure we have a Tubes channel - PS doesn't yet provide one
+ if tubes_chan is None:
+ logger.debug("Didn't find our Tubes channel, requesting one...")
+ tubes_chan = self.conn.request_channel(telepathy.CHANNEL_TYPE_TUBES,
+ telepathy.HANDLE_TYPE_ROOM, room, True)
+
+ self.tubes_chan = tubes_chan
+ self.text_chan = text_chan
+
+ tubes_chan[telepathy.CHANNEL_TYPE_TUBES].connect_to_signal('NewTube',
+ self._new_tube_cb)
+
+ def _list_tubes_reply_cb(self, tubes):
+ for tube_info in tubes:
+ self._new_tube_cb(*tube_info)
+
+ def _list_tubes_error_cb(self, e):
+ logger.error('ListTubes() failed: %s', e)
+
+ def _joined_cb(self, activity):
+ if self.game is not None:
+ return
+
+ if not self._shared_activity:
+ return
+
+ for buddy in self._shared_activity.get_joined_buddies():
+ pass # XXX do stuff with buddy
+
+ logger.debug('Joined an existing shared activity')
+ self.initiating = False
+ self._setup()
+
+ logger.debug('This is not my activity: waiting for a tube...')
+ self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].ListTubes(
+ reply_handler=self._list_tubes_reply_cb,
+ error_handler=self._list_tubes_error_cb)
+
+ def _new_tube_cb(self, id, initiator, type, service, params, state):
+ logger.debug('New tube: ID=%d initator=%d type=%d service=%s '
+ 'params=%r state=%d', id, initiator, type, service,
+ params, state)
+
+ #if (self.game is None and type == telepathy.TUBE_TYPE_DBUS and
+ # service == SERVICE):
+ # if state == telepathy.TUBE_STATE_LOCAL_PENDING:
+ # self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].AcceptTube(id)
+
+ # tube_conn = TubeConnection(self.conn,
+ # self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES],
+ # id, group_iface=self.text_chan[telepathy.CHANNEL_INTERFACE_GROUP])
+ # self.game = ConnectGame(tube_conn, self.grid, self.initiating,
+ # self.buddies_panel, self.owner, self._get_buddy, self)
+
+ def _buddy_joined_cb (self, activity, buddy):
+ logger.debug('Buddy %s joined' % buddy.props.nick)
+
+ def _buddy_left_cb (self, activity, buddy):
+ logger.debug('Buddy %s left' % buddy.props.nick)
diff --git a/activity/activity-hellomesh.svg b/activity/activity-hellomesh.svg
new file mode 100644
index 0000000..45ba759
--- /dev/null
+++ b/activity/activity-hellomesh.svg
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 12.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 51448) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
+ <!ENTITY ns_svg "http://www.w3.org/2000/svg">
+ <!ENTITY ns_xlink "http://www.w3.org/1999/xlink">
+ <!ENTITY stroke_color "#020202">
+ <!ENTITY fill_color "#666666">
+]>
+<svg version="1.1" id="Icon" xmlns="&ns_svg;" xmlns:xlink="&ns_xlink;" width="48.92" height="43.846" viewBox="0 0 48.92 43.846"
+ overflow="visible" enable-background="new 0 0 48.92 43.846" xml:space="preserve">
+<path id="Bubble" fill="&fill_color;" stroke="&stroke_color;" stroke-width="3.5" d="M6.348,41.615c0.682,1.151,6.027,0.059,8.246-1.464
+ c2.102-1.432,3.207-2.596,4.336-2.596c1.133,0,12.54,0.92,20.935-5.715c7.225-5.707,9.772-13.788,4.52-21.438
+ c-5.252-7.644-13.831-9.079-20.878-8.56C13.891,2.562,1.309,10.13,1.762,21.533c0.264,6.711,3.357,9.143,4.922,10.702
+ c1.562,1.566,4.545,1.566,2.992,5.589C9.066,39.402,5.838,40.742,6.348,41.615z"/>
+</svg>
+
diff --git a/activity/activity.info b/activity/activity.info
new file mode 100644
index 0000000..cae2946
--- /dev/null
+++ b/activity/activity.info
@@ -0,0 +1,7 @@
+[Activity]
+name = HelloMesh
+service_name = org.laptop.HelloMesh
+class = activity.HelloMeshActivity
+icon = activity-hellomesh
+activity_version = 1
+show_launcher = yes
diff --git a/setup.py b/setup.py
new file mode 100755
index 0000000..fae74b8
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+# Copyright (C) 2006, Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+from sugar.activity import bundlebuilder
+
+bundlebuilder.start()
+
diff --git a/tubeconn.py b/tubeconn.py
new file mode 100644
index 0000000..d1c1403
--- /dev/null
+++ b/tubeconn.py
@@ -0,0 +1,107 @@
+# This should eventually land in telepathy-python, so has the same license:
+
+# Copyright (C) 2007 Collabora Ltd. <http://www.collabora.co.uk/>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+__all__ = ('TubeConnection',)
+__docformat__ = 'reStructuredText'
+
+
+import logging
+
+from dbus.connection import Connection
+
+
+logger = logging.getLogger('telepathy.tubeconn')
+
+
+class TubeConnection(Connection):
+
+ def __new__(cls, conn, tubes_iface, tube_id, address=None,
+ group_iface=None, mainloop=None):
+ if address is None:
+ address = tubes_iface.GetDBusServerAddress(tube_id)
+ self = super(TubeConnection, cls).__new__(cls, address,
+ mainloop=mainloop)
+
+ self._tubes_iface = tubes_iface
+ self.tube_id = tube_id
+ self.participants = {}
+ self.bus_name_to_handle = {}
+ self._mapping_watches = []
+
+ if group_iface is None:
+ method = conn.GetSelfHandle
+ else:
+ method = group_iface.GetSelfHandle
+ method(reply_handler=self._on_get_self_handle_reply,
+ error_handler=self._on_get_self_handle_error)
+
+ return self
+
+ def _on_get_self_handle_reply(self, handle):
+ self.self_handle = handle
+ match = self._tubes_iface.connect_to_signal('DBusNamesChanged',
+ self._on_dbus_names_changed)
+ self._tubes_iface.GetDBusNames(self.tube_id,
+ reply_handler=self._on_get_dbus_names_reply,
+ error_handler=self._on_get_dbus_names_error)
+ self._dbus_names_changed_match = match
+
+ def _on_get_self_handle_error(self, e):
+ logging.basicConfig()
+ logger.error('GetSelfHandle failed: %s', e)
+
+ def close(self):
+ self._dbus_names_changed_match.remove()
+ self._on_dbus_names_changed(self.tube_id, (), self.participants.keys())
+ super(TubeConnection, self).close()
+
+ def _on_get_dbus_names_reply(self, names):
+ self._on_dbus_names_changed(self.tube_id, names, ())
+
+ def _on_get_dbus_names_error(self, e):
+ logging.basicConfig()
+ logger.error('GetDBusNames failed: %s', e)
+
+ def _on_dbus_names_changed(self, tube_id, added, removed):
+ if tube_id == self.tube_id:
+ for handle, bus_name in added:
+ if handle == self.self_handle:
+ # I've just joined - set my unique name
+ self.set_unique_name(bus_name)
+ self.participants[handle] = bus_name
+ self.bus_name_to_handle[bus_name] = handle
+
+ # call the callback while the removed people are still in
+ # participants, so their bus names are available
+ for callback in self._mapping_watches:
+ callback(added, removed)
+
+ for handle in removed:
+ bus_name = self.participants.pop(handle, None)
+ self.bus_name_to_handle.pop(bus_name, None)
+
+ def watch_participants(self, callback):
+ self._mapping_watches.append(callback)
+ if self.participants:
+ # GetDBusNames already returned: fake a participant add event
+ # immediately
+ added = []
+ for k, v in self.participants.iteritems():
+ added.append((k, v))
+ callback(added, [])