More patches for review: these add a TubesConnection helper, which I'll
eventually move into telepathy-python.

Simon
From 3aba4b1d28757591795f07284474082acddde242 Mon Sep 17 00:00:00 2001
From: Simon McVittie <[EMAIL PROTECTED]>
Date: Mon, 7 May 2007 14:54:57 +0100
Subject: [PATCH] gtkui.py: Configure logging to show all messages

---
 gtkui.py |    6 ++++++
 1 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/gtkui.py b/gtkui.py
index 27e950a..8dd6edd 100644
--- a/gtkui.py
+++ b/gtkui.py
@@ -1,5 +1,6 @@
 
 import sys
+import logging
 
 import dbus
 import gtk
@@ -8,6 +9,11 @@ import telepathy
 import gridwidget
 import client
 
+
+logging.basicConfig()
+logging.getLogger().setLevel(1)
+
+
 def decode(x, sig):
     # XXX: dbus-python ought to do most of the work for this
     if sig == 'b':
-- 
1.5.1.3

From 56c8ceeb2c9e0d4ab938d57df30c4b814fb490f6 Mon Sep 17 00:00:00 2001
From: Simon McVittie <[EMAIL PROTECTED]>
Date: Mon, 7 May 2007 14:56:01 +0100
Subject: [PATCH] tubeconn.py: Add a prototype Tubes connection helper, for eventual inclusion in telepathy-python

---
 tubeconn.py |  104 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 104 insertions(+), 0 deletions(-)
 create mode 100644 tubeconn.py

diff --git a/tubeconn.py b/tubeconn.py
new file mode 100644
index 0000000..0b65056
--- /dev/null
+++ b/tubeconn.py
@@ -0,0 +1,104 @@
+# 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
+try:
+    set()
+except NameError:
+    from sets import Set as set
+
+from dbus import Array
+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._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
+        self._tubes_iface.GetDBusNames(self.tube_id,
+                reply_handler=self._on_get_dbus_names_reply,
+                error_handler=self._on_get_dbus_names_error)
+        match = self._tubes_iface.connect_to_signal('DBusNamesChanged',
+                self._on_dbus_names_changed)
+        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()
+        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
+            for handle in removed:
+                self.participants.pop(handle, None)
+            for callback in self._mapping_watches:
+                callback(added, removed)
+
+    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, [])
-- 
1.5.1.3

From 38ef3e74e2ad624507f7a767e523bfe802b302e5 Mon Sep 17 00:00:00 2001
From: Simon McVittie <[EMAIL PROTECTED]>
Date: Mon, 7 May 2007 14:57:19 +0100
Subject: [PATCH] client.py: Use TubeConnection. Move all game code to ConnectGame

---
 client.py |  106 +++++++++++++++++++++++++++++++++----------------------------
 1 files changed, 57 insertions(+), 49 deletions(-)

diff --git a/client.py b/client.py
index 9f9cfa0..8496481 100644
--- a/client.py
+++ b/client.py
@@ -5,7 +5,6 @@ import gtk
 import telepathy
 
 from dbus import Interface
-from dbus.connection import Connection
 from dbus.mainloop.glib import DBusGMainLoop
 from dbus.service import Object, method, signal
 
@@ -15,6 +14,9 @@ from telepathy.constants import TUBE_TYPE_DBUS, \
         TUBE_STATE_LOCAL_PENDING, TUBE_STATE_REMOTE_PENDING, TUBE_STATE_OPEN, \
         CONNECTION_STATUS_CONNECTED, HANDLE_TYPE_ROOM
 
+# 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"
@@ -42,31 +44,33 @@ def redraw(grid):
     grid.window.invalidate_rect(grid.get_allocation(), False)
 
 class ConnectGame(Object):
-    def __init__(self, tube, grid, self_handle, initiator, dbus_names):
+    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
 
-        # Initiator is player 1, other player is player 2.
+        self.tube.watch_participants(self.participant_change_cb)
 
-        self.self_handle = self_handle
-        self.initiator = initiator
+    def participant_change_cb(self, added, removed):
+        # Initiator is player 1, other player is player 2.
 
-        if initiator == self_handle:
-            self.player_id = 1
-        else:
-            opponent = self.tube.get_object(dbus_names[initiator], PATH)
-            self.opponent = Interface(opponent, IFACE)
-            self.opponent.Hello(reply_handler=self.hello_cb,
-                error_handler=self.error_cb)
-            self.player_id = 2
-
-        # XXX: care about signal sender
-        self.tube.add_signal_receiver(self.insert_cb, 'Insert', IFACE,
-            path=PATH)
-
-        print 'intiator: %d' % initiator
-        print 'self: %d' % self.self_handle
+        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):
@@ -97,11 +101,16 @@ class ConnectGame(Object):
         assert column >= 0
         assert column < 7
 
-    def insert_cb(self, column):
-        #print 'Insert: %r' % args
+    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
@@ -120,6 +129,25 @@ class ConnectGame(Object):
         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):
@@ -142,22 +170,8 @@ class ConnectClient:
         if event.keyval in (gtk.keysyms.Escape, gtk.keysyms.q):
             gtk.main_quit()
 
-        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):
-                redraw(self.grid)
-                self.game.Insert(self.grid.selected_column)
-                self.grid.selected_column = None
+        if self.game is not None:
+            self.game.key_press_event(widget, event)
 
     def status_changed_cb(self, status, reason):
         if status == CONNECTION_STATUS_CONNECTED:
@@ -180,8 +194,8 @@ class ConnectClient:
             self.new_tube_cb)
         tubes_chan[CHANNEL_TYPE_TUBES].connect_to_signal('DBusNamesChanged',
             self.dbus_names_changed_cb)
-        # XXX: this is racy
-        # XXX: try all tubes and use the first one where Hello () -> True
+        # 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)
         self.text_chan = text_chan
         self.tubes_chan = tubes_chan
@@ -222,17 +236,11 @@ class ConnectClient:
 
     def use_tube(self, id, initiator):
         print 'using tube %d' % id
-        addr = self.tubes_chan[CHANNEL_TYPE_TUBES].GetDBusServerAddress(id)
-        assert addr
-        self.dbus_names = dict(
-            self.tubes_chan[CHANNEL_TYPE_TUBES].GetDBusNames(id))
-        print 'names:', pprint.pformat(list(self.dbus_names))
-        assert self.tubes_self_handle in self.dbus_names
 
-        conn = Connection(addr)
+        conn = TubeConnection(self.conn, self.tubes_chan[CHANNEL_TYPE_TUBES],
+            id, group_iface=self.text_chan[CHANNEL_INTERFACE_GROUP])
 
-        self.game = ConnectGame(conn, self.grid, self.tubes_self_handle,
-            initiator, self.dbus_names)
+        self.game = ConnectGame(conn, self.grid, initiator)
 
     def new_tube_cb(self, id, initiator, type, service, parameters, state):
         print 'new tube: %r' % (
-- 
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