Some more patches to the Connect activity. These make it a proper shared
activity.
From 684f3be93e064d6cd014e41d00df89b8c0092911 Mon Sep 17 00:00:00 2001
From: Simon McVittie <[EMAIL PROTECTED]>
Date: Tue, 8 May 2007 15:12:12 +0100
Subject: [PATCH] gtkui.py: take responsibility for linking up the GLib main loop to dbus-python

---
 gtkui.py |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/gtkui.py b/gtkui.py
index 8dd6edd..9711099 100644
--- a/gtkui.py
+++ b/gtkui.py
@@ -3,6 +3,7 @@ import sys
 import logging
 
 import dbus
+from dbus.mainloop.glib import DBusGMainLoop
 import gtk
 import telepathy
 
@@ -92,5 +93,5 @@ def main():
         pass
 
 if __name__ == '__main__':
+    dbus_main_loop = DBusGMainLoop(set_as_default=True)
     main()
-
-- 
1.5.1.3

From ff890fe93a52fffc6df3b2d954d1959518c655ba Mon Sep 17 00:00:00 2001
From: Simon McVittie <[EMAIL PROTECTED]>
Date: Tue, 8 May 2007 15:14:51 +0100
Subject: [PATCH] client.py: Clean up some unused code. Move responsibility for participant tracking into ConnectGame

---
 client.py |   33 +++------------------------------
 1 files changed, 3 insertions(+), 30 deletions(-)

diff --git a/client.py b/client.py
index 8496481..f625e61 100644
--- a/client.py
+++ b/client.py
@@ -25,20 +25,8 @@ PATH = "/org/freedesktop/Telepathy/Tube/Connect"
 
 ROOM = "[EMAIL PROTECTED]"
 
-dbus_main_loop = DBusGMainLoop(set_as_default=True)
-
-logging.basicConfig()
 _logger = logging.getLogger('connect-activity.client')
 
-def print_dbus_message(msg):
-    print 'got %s' % (msg.__class__.__name__)
-    print '  sender: %r' % msg.get_sender()
-    print '  destination: %r' % msg.get_destination()
-    print '  path: %r' % msg.get_path()
-    print '  interface %r' % msg.get_interface()
-    print '  member %r' % msg.get_member()
-    print '  args: %r' % msg.get_args_list()
-
 def redraw(grid):
     """Utility function to force a redraw of a Gtk widget."""
     grid.window.invalidate_rect(grid.get_allocation(), False)
@@ -56,6 +44,9 @@ class ConnectGame(Object):
     def participant_change_cb(self, added, removed):
         # Initiator is player 1, other player is player 2.
 
+        _logger.debug('adding participants: %r', added)
+        _logger.debug('removing participants: %r', removed)
+
         if self.player_id is None:
             if self.initiator == self.tube.self_handle:
                 self.player_id = 1
@@ -154,9 +145,6 @@ class ConnectClient:
         self.conn = conn
         self.grid = grid
         self.game = None
-        self.tubes_self_handle = 0
-        self.pending_calls = {}
-        self.player_id = 0
 
         event_widget.connect('key-press-event', self.key_press_cb)
 
@@ -185,15 +173,11 @@ class ConnectClient:
         current, lp, rp = map(lambda x: map(int, x),
             text_chan[CHANNEL_INTERFACE_GROUP].GetAllMembers())
         print 'activity members: %r, %r, %r' % (current, lp, rp)
-        self.tubes_self_handle = text_chan[
-            CHANNEL_INTERFACE_GROUP].GetSelfHandle()
         tubes_chan = self.conn.request_channel(
             CHANNEL_TYPE_TUBES, HANDLE_TYPE_ROOM, handle,
             True)
         tubes_chan[CHANNEL_TYPE_TUBES].connect_to_signal('NewTube',
             self.new_tube_cb)
-        tubes_chan[CHANNEL_TYPE_TUBES].connect_to_signal('DBusNamesChanged',
-            self.dbus_names_changed_cb)
         # XXX: this is racy. When we have the Presence Service's
         # initiator/inviter semantics, we won't have this issue though
         tube = self.find_tube(tubes_chan)
@@ -213,17 +197,6 @@ class ConnectClient:
                 SERVICE, {})
             print 'found no tube; created tube %d' % id
 
-    def dbus_names_changed_cb(self, tube_id, added, removed):
-        print 'names changed:'
-
-        if added:
-            added = tuple([(int(x[0]), str(x[1])) for x in added])
-            print '  added: %r' % added
-
-        if removed:
-            removed = tuple([int(x) for x in removed])
-            print '  removed: %r' % removed
-
     def find_tube(self, chan):
         "Find a D-Bus tube in a tubes channel that provides our service."
 
-- 
1.5.1.3

From 099ca5a15aec89ba439abd44028840eac21dd233 Mon Sep 17 00:00:00 2001
From: Simon McVittie <[EMAIL PROTECTED]>
Date: Tue, 8 May 2007 15:29:51 +0100
Subject: [PATCH] activity.py: Hook into Presence Service rather than using ConnectClient

---
 activity.py |  133 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 128 insertions(+), 5 deletions(-)

diff --git a/activity.py b/activity.py
index 57fa836..dc2ca60 100644
--- a/activity.py
+++ b/activity.py
@@ -1,27 +1,150 @@
+import logging
+from gettext import gettext as _
 
 import dbus
+import gtk
 import hippo
 import telepathy
+import telepathy.client
 
-from sugar.activity.activity import Activity
+from sugar.activity.activity import Activity, ActivityToolbox
 from sugar.presence import presenceservice
+import sugar.logger
 
 import gridwidget
 import client
+# will eventually be imported from telepathy.tubes or something
+from tubeconn import TubeConnection
+
+
+logger = logging.getLogger('connect-activity')
+
 
 class ConnectActivity(Activity):
     def __init__(self, handle):
         Activity.__init__(self, handle)
 
-        widget = gridwidget.GridWidget()
-        self.set_canvas(widget)
+        logger.debug('Starting Connect activity...')
+
+        self.set_title(_('Connect Activity'))
+
+        self.grid = gridwidget.GridWidget()
+        self.set_canvas(self.grid)
         self.show_all()
 
         pservice = presenceservice.get_instance()
 
         bus = dbus.Bus()
         name, path = pservice.get_preferred_connection()
-        conn = telepathy.client.Connection(name, path)
+        self.conn = telepathy.client.Connection(name, path)
+
+        self.game = None
+
+        toolbox = ActivityToolbox(self)
+        self.set_toolbox(toolbox)
+        toolbox.show()
+
+        self.connect('shared', self._shared_cb)
+
+        if self._shared_activity:
+            self.connect('joined', self._joined_cb)
+            if self.get_shared():
+                # oh, OK, we've already joined
+                self._joined_cb()
+
+        self.connect('key-press-event', self.key_press_cb)
+
+    def key_press_cb(self, widget, event):
+        if event.keyval in (gtk.keysyms.Escape, gtk.keysyms.q):
+            gtk.main_quit()
+
+        if self.game is not None:
+            self.game.key_press_event(widget, event)
+
+    def _shared_cb(self, activity):
+        logger.debug('My Connect activity was shared')
+        self._setup()
+
+        logger.debug('This is my activity: making a tube...')
+        id = self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].OfferTube(
+            telepathy.TUBE_TYPE_DBUS, client.SERVICE, {})
+
+    # FIXME: presence service should be tubes-aware and give us more help
+    # with this
+    def _setup(self):
+        pservice = presenceservice.get_instance()
+        # There are too many things called Activity.
+        ps_activity = pservice.get_activity(self.get_id())
+        bus_name, conn_path, channel_paths = ps_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
+
+        logger.debug('Joined an existing Connect game')
+        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)
 
-        client.ConnectClient(conn, self, widget)
+        if (self.game is None and type == telepathy.TUBE_TYPE_DBUS and
+            service == client.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 = client.ConnectGame(tube_conn, self.grid, initiator)
-- 
1.5.1.3

From 00d4df40086977506778b7c966ee612d934d71b6 Mon Sep 17 00:00:00 2001
From: Simon McVittie <[EMAIL PROTECTED]>
Date: Tue, 8 May 2007 15:39:50 +0100
Subject: [PATCH] Move ConnectGame to its own file game.py; activity no longer uses client.py
(it's only still here for the benefit of gtkui)
---
 activity.py |    8 ++--
 client.py   |  122 +-------------------------------------------------------
 game.py     |  129 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 134 insertions(+), 125 deletions(-)
 create mode 100644 game.py

diff --git a/activity.py b/activity.py
index dc2ca60..b786dbe 100644
--- a/activity.py
+++ b/activity.py
@@ -12,7 +12,7 @@ from sugar.presence import presenceservice
 import sugar.logger
 
 import gridwidget
-import client
+from game import ConnectGame, SERVICE
 # will eventually be imported from telepathy.tubes or something
 from tubeconn import TubeConnection
 
@@ -67,7 +67,7 @@ class ConnectActivity(Activity):
 
         logger.debug('This is my activity: making a tube...')
         id = self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].OfferTube(
-            telepathy.TUBE_TYPE_DBUS, client.SERVICE, {})
+            telepathy.TUBE_TYPE_DBUS, SERVICE, {})
 
     # FIXME: presence service should be tubes-aware and give us more help
     # with this
@@ -140,11 +140,11 @@ class ConnectActivity(Activity):
                      params, state)
 
         if (self.game is None and type == telepathy.TUBE_TYPE_DBUS and
-            service == client.SERVICE):
+            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 = client.ConnectGame(tube_conn, self.grid, initiator)
+            self.game = ConnectGame(tube_conn, self.grid, initiator)
diff --git a/client.py b/client.py
index f625e61..710e078 100644
--- a/client.py
+++ b/client.py
@@ -1,12 +1,8 @@
 import logging
-import pprint
 
 import gtk
 import telepathy
 
-from dbus import Interface
-from dbus.mainloop.glib import DBusGMainLoop
-from dbus.service import Object, method, signal
 
 from telepathy.interfaces import CHANNEL_TYPE_TUBES, \
         CHANNEL_TYPE_TEXT, CONN_INTERFACE, CHANNEL_INTERFACE_GROUP
@@ -14,131 +10,15 @@ from telepathy.constants import TUBE_TYPE_DBUS, \
         TUBE_STATE_LOCAL_PENDING, TUBE_STATE_REMOTE_PENDING, TUBE_STATE_OPEN, \
         CONNECTION_STATUS_CONNECTED, HANDLE_TYPE_ROOM
 
+from game import ConnectGame, SERVICE
 # will eventually be imported from telepathy.tubes or something
 from tubeconn import TubeConnection
 
 
-# XXX: I'm not convinced this is in the right namespace
-SERVICE = "org.freedesktop.Telepathy.Tube.Connect"
-IFACE = SERVICE
-PATH = "/org/freedesktop/Telepathy/Tube/Connect"
-
 ROOM = "[EMAIL PROTECTED]"
 
 _logger = logging.getLogger('connect-activity.client')
 
-def redraw(grid):
-    """Utility function to force a redraw of a Gtk widget."""
-    grid.window.invalidate_rect(grid.get_allocation(), False)
-
-class ConnectGame(Object):
-    def __init__(self, tube, grid, initiator):
-        super(ConnectGame, self).__init__(tube, PATH)
-        self.tube = tube
-        self.grid = grid
-        self.initiator = initiator
-        self.player_id = None
-
-        self.tube.watch_participants(self.participant_change_cb)
-
-    def participant_change_cb(self, added, removed):
-        # Initiator is player 1, other player is player 2.
-
-        _logger.debug('adding participants: %r', added)
-        _logger.debug('removing participants: %r', removed)
-
-        if self.player_id is None:
-            if self.initiator == self.tube.self_handle:
-                self.player_id = 1
-            else:
-                opponent = self.tube.get_object(
-                    self.tube.participants[self.initiator], PATH)
-                self.opponent = Interface(opponent, IFACE)
-                self.opponent.Hello(reply_handler=self.hello_cb,
-                    error_handler=self.error_cb)
-                self.player_id = 2
-            self.tube.add_signal_receiver(self.insert_cb, 'Insert', IFACE,
-                path=PATH, sender_keyword='sender')
-
-        print 'intiator: %d' % self.initiator
-        print 'self: %d' % self.tube.self_handle
-        print 'player ID: %d' % self.player_id
-
-    def hello_cb(self, success):
-        self.opponent.GetGrid(reply_handler=self.get_grid_cb,
-            error_handler=self.error_cb)
-
-    def get_grid_cb(self, grid):
-        self.grid.grid = grid
-        redraw(self.grid)
-
-    def error_cb(self, e):
-        _logger.error('Error connecting to opponent:\n%s', e)
-
-    @method(dbus_interface=IFACE, in_signature='', out_signature='b')
-    def Hello(self):
-        self.grid.selected_column = 3
-        redraw(self.grid)
-        # XXX: return player ID too, to allow for swapping who goes first in
-        # for second and later games
-        return True
-
-    @method(dbus_interface=IFACE, in_signature='', out_signature='aan')
-    def GetGrid(self):
-        return self.grid.grid
-
-    @signal(dbus_interface=IFACE, signature='n')
-    def Insert(self, column):
-        assert column >= 0
-        assert column < 7
-
-    def insert_cb(self, column, sender=None):
-        _logger.debug('Insert(%d) from %s', column, sender)
-
-        if sender == self.tube.participants[self.tube.self_handle]:
-            _logger.debug('Ignoring Insert signal from myself: %d', column)
-            return
-
-        if self.grid.insert(column, self.get_active_player()):
-            if self.get_active_player() == self.player_id:
-                _logger.debug('It\'s my turn now')
-                # This should always be the case for 2 players, as we only get
-                # this signal when the other player plays.
-                self.grid.selected_column = 3
-            redraw(self.grid)
-
-    def get_active_player(self):
-        count = {}
-
-        for row in self.grid.grid:
-            for player in row:
-                if player != 0:
-                    count[player] = count.get(player, 0) + 1
-
-        if count.get(1, 0) > count.get(2, 0):
-            return 2
-        else:
-            return 1
-
-    def key_press_event(self, widget, event):
-        if self.grid.selected_column is None:
-            return
-
-        if event.keyval in (gtk.keysyms.Left,):
-            if self.grid.selected_column > 0:
-                self.grid.selected_column -= 1
-                redraw(self.grid)
-        elif event.keyval in (gtk.keysyms.Right,):
-            if self.grid.selected_column < 6:
-                self.grid.selected_column += 1
-                redraw(self.grid)
-        elif event.keyval in (gtk.keysyms.Down, gtk.keysyms.space):
-            if self.grid.insert(self.grid.selected_column, self.player_id):
-                _logger.debug('Inserting at %d', self.grid.selected_column)
-                redraw(self.grid)
-                self.Insert(self.grid.selected_column)
-                self.grid.selected_column = None
-
 
 class ConnectClient:
     def __init__(self, conn, event_widget, grid):
diff --git a/game.py b/game.py
new file mode 100644
index 0000000..3ed9e36
--- /dev/null
+++ b/game.py
@@ -0,0 +1,129 @@
+import logging
+
+import gtk
+
+from dbus import Interface
+from dbus.service import Object, method, signal
+
+
+# XXX: I'm not convinced this is in the right namespace
+SERVICE = "org.freedesktop.Telepathy.Tube.Connect"
+IFACE = SERVICE
+PATH = "/org/freedesktop/Telepathy/Tube/Connect"
+
+
+_logger = logging.getLogger('connect-activity.game')
+
+
+def redraw(grid):
+    """Utility function to force a redraw of a Gtk widget."""
+    grid.window.invalidate_rect(grid.get_allocation(), False)
+
+
+class ConnectGame(Object):
+    def __init__(self, tube, grid, initiator):
+        super(ConnectGame, self).__init__(tube, PATH)
+        self.tube = tube
+        self.grid = grid
+        self.initiator = initiator
+        self.player_id = None
+
+        self.tube.watch_participants(self.participant_change_cb)
+
+    def participant_change_cb(self, added, removed):
+        # Initiator is player 1, other player is player 2.
+
+        _logger.debug('adding participants: %r', added)
+        _logger.debug('removing participants: %r', removed)
+
+        if self.player_id is None:
+            if self.initiator == self.tube.self_handle:
+                self.player_id = 1
+            else:
+                opponent = self.tube.get_object(
+                    self.tube.participants[self.initiator], PATH)
+                self.opponent = Interface(opponent, IFACE)
+                self.opponent.Hello(reply_handler=self.hello_cb,
+                    error_handler=self.error_cb)
+                self.player_id = 2
+            self.tube.add_signal_receiver(self.insert_cb, 'Insert', IFACE,
+                path=PATH, sender_keyword='sender')
+
+        print 'intiator: %d' % self.initiator
+        print 'self: %d' % self.tube.self_handle
+        print 'player ID: %d' % self.player_id
+
+    def hello_cb(self, success):
+        self.opponent.GetGrid(reply_handler=self.get_grid_cb,
+            error_handler=self.error_cb)
+
+    def get_grid_cb(self, grid):
+        self.grid.grid = grid
+        redraw(self.grid)
+
+    def error_cb(self, e):
+        _logger.error('Error connecting to opponent:\n%s', e)
+
+    @method(dbus_interface=IFACE, in_signature='', out_signature='b')
+    def Hello(self):
+        self.grid.selected_column = 3
+        redraw(self.grid)
+        # XXX: return player ID too, to allow for swapping who goes first in
+        # for second and later games
+        return True
+
+    @method(dbus_interface=IFACE, in_signature='', out_signature='aan')
+    def GetGrid(self):
+        return self.grid.grid
+
+    @signal(dbus_interface=IFACE, signature='n')
+    def Insert(self, column):
+        assert column >= 0
+        assert column < 7
+
+    def insert_cb(self, column, sender=None):
+        _logger.debug('Insert(%d) from %s', column, sender)
+
+        if sender == self.tube.participants[self.tube.self_handle]:
+            _logger.debug('Ignoring Insert signal from myself: %d', column)
+            return
+
+        if self.grid.insert(column, self.get_active_player()):
+            if self.get_active_player() == self.player_id:
+                _logger.debug('It\'s my turn now')
+                # This should always be the case for 2 players, as we only get
+                # this signal when the other player plays.
+                self.grid.selected_column = 3
+            redraw(self.grid)
+
+    def get_active_player(self):
+        count = {}
+
+        for row in self.grid.grid:
+            for player in row:
+                if player != 0:
+                    count[player] = count.get(player, 0) + 1
+
+        if count.get(1, 0) > count.get(2, 0):
+            return 2
+        else:
+            return 1
+
+    def key_press_event(self, widget, event):
+        if self.grid.selected_column is None:
+            return
+
+        if event.keyval in (gtk.keysyms.Left,):
+            if self.grid.selected_column > 0:
+                self.grid.selected_column -= 1
+                redraw(self.grid)
+        elif event.keyval in (gtk.keysyms.Right,):
+            if self.grid.selected_column < 6:
+                self.grid.selected_column += 1
+                redraw(self.grid)
+        elif event.keyval in (gtk.keysyms.Down, gtk.keysyms.space):
+            if self.grid.insert(self.grid.selected_column, self.player_id):
+                _logger.debug('Inserting at %d', self.grid.selected_column)
+                redraw(self.grid)
+                self.Insert(self.grid.selected_column)
+                self.grid.selected_column = None
-- 
1.5.1.3

Attachment: signature.asc
Description: Digital signature

_______________________________________________
Sugar mailing list
[email protected]
http://mailman.laptop.org/mailman/listinfo/sugar

Reply via email to