Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/watchme.py
diff options
context:
space:
mode:
Diffstat (limited to 'watchme.py')
-rw-r--r--watchme.py182
1 files changed, 182 insertions, 0 deletions
diff --git a/watchme.py b/watchme.py
new file mode 100644
index 0000000..38ecd8a
--- /dev/null
+++ b/watchme.py
@@ -0,0 +1,182 @@
+# Copyright (C) 2007, Eduardo Silva <edsiper@gmail.com>.
+# Copyright (C) 2008, One Laptop Per Child
+# Copyright (C) 2009, Ben Schwartz <bens@alum.mit.edu>
+#
+# 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
+
+import os
+
+import logging
+from gettext import gettext
+
+import gtk
+import dbus
+
+from sugar.activity import activity
+import os.path
+
+import telepathy
+import subprocess
+
+import signal
+
+SERVICE = 'org.sugarlabs.WatchMe'
+IFACE = SERVICE
+PATH = '/org/sugarlabs/WatchMe'
+
+class WatchMeActivity(activity.Activity):
+
+ def __init__(self, handle):
+ activity.Activity.__init__(self, handle)
+
+ self._logger = logging.getLogger('watchme-activity')
+ self._logger.debug('Starting the WatchMe activity')
+
+ self.set_title(gettext('WatchMe Activity'))
+
+ self._vncdaemon = None
+ self._vncviewer = None
+
+ if not self._shared_activity: #I am the initiator
+ toolbox = activity.ActivityToolbox(self)
+ activity_toolbar = toolbox.get_activity_toolbar()
+ activity_toolbar.keep.props.visible = False
+
+ self.set_toolbox(toolbox)
+ toolbox.show()
+
+ label = gtk.Label(gettext("If you want people to be able to see everything on your screen, invite them to this activity"))
+
+ self._connected = True
+ # The initiator is "connected" without actually connecting to the VNC
+ # server, because they are looking at the X server.
+ self.connect('shared', self._shared_cb)
+ else: # I am joining
+ #A GUI is not created for a joiner. Hopefully, the vncviewer window
+ #will be the first window created by the activity, and so will get
+ #a working icon, etc.
+ label = gtk.Label(gettext("Please wait while you are connected to the shared session"))
+ self._connected = False
+ if self.get_shared(): #Already joined for some reason
+ self._joined_cb()
+ else:
+ self.connect('joined', self._joined_cb)
+ self.set_canvas(label)
+ self.show_all()
+
+ def _sharing_setup(self):
+ params = {} #could be used in the future to indicate a reflector
+
+ bundle_path = activity.get_bundle_path()
+ port = 5900
+ # Start a VNC daemon at an automatically located free TCP port,
+ # scaling down by a factor of 2 with no blending (for efficiency)
+ # allowing viewers to view only, not control the cursor or keyboard
+ # allowing multiple viewers to join
+ # continue running indefinitely
+ # allow connections only from localhost
+ self._vncdaemon = subprocess.Popen(['x11vnc', #search the PATH
+ '-autoport',str(port),
+ '-viewonly',
+ '-shared',
+ '-forever',
+ '-localhost'], stdout=subprocess.PIPE)
+
+ # When run with -autoport, x11vnc finds an open port, opens it, and
+ # prints a line of the form
+ # PORT=5972
+ # to stdout.
+ x = self._vncdaemon.stdout.readline()
+ success = 'PORT='
+ if x[:len(success)] == success:
+ port = int(x[len(success):])
+ logging.debug('started VNC daemon successfully on port %d' % port)
+ else:
+ self._vncdaemon.terminate()
+ self._vncdaemon.wait()
+ self._logger.error('unable to find an open port!')
+ self.close()
+ return (params, port)
+
+ def _shared_cb(self, activity):
+ self._logger.debug('My activity was shared')
+ self.initiating = True
+ (params, port) = self._sharing_setup()
+
+ self._logger.debug('This is my activity: making a tube...')
+
+ address = ('127.0.0.1', dbus.UInt16(port))
+
+ tubes_chan = self._shared_activity.telepathy_tubes_chan
+ id = tubes_chan[telepathy.CHANNEL_TYPE_TUBES].OfferStreamTube(
+ SERVICE, params, telepathy.SOCKET_ADDRESS_TYPE_IPV4, address,
+ telepathy.SOCKET_ACCESS_CONTROL_LOCALHOST, 0)
+
+ def _joined_cb(self, also_self):
+ tubes_chan = self._shared_activity.telepathy_tubes_chan
+
+ tubes_chan[telepathy.CHANNEL_TYPE_TUBES].connect_to_signal('NewTube',
+ self._new_tube_cb)
+ 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, tube_id, initiator, tube_type, service, params, state):
+ self._logger.debug('New Tube')
+ if ((tube_type == telepathy.TUBE_TYPE_STREAM) and
+ (service == SERVICE) and (not self._connected)):
+ tubes_chan = self._shared_activity.telepathy_tubes_chan
+ iface = tubes_chan[telepathy.CHANNEL_TYPE_TUBES]
+ addr = iface.AcceptStreamTube(tube_id,
+ telepathy.SOCKET_ADDRESS_TYPE_IPV4,
+ telepathy.SOCKET_ACCESS_CONTROL_LOCALHOST, 0)
+
+ port = int(addr[1])
+ # additional properties are available from params
+
+ ## Start a VNC viewer pointed at the appropriate port.
+ #self._vncviewer = subprocess.Popen(['/usr/bin/vncviewer',
+ # 'localhost::%d' % port,
+ # '-ViewOnly',
+ # '-Shared'])
+ import gtkvnc
+ vncwidget = gtkvnc.Display()
+ self.set_canvas(vncwidget)
+ vncwidget.realize() # I don't know what this does
+ vncwidget.open_host('localhost',str(port))
+ self._connected = True
+ self.show_all()
+
+ def can_close(self):
+ #if self._vncviewer is not None:
+ # try:
+ # os.kill(self._vncviewer.pid,signal.SIGTERM)
+ # except:
+ # pass
+ # #self._vncviewer.terminate() #requires python 2.6
+ if self._vncdaemon is not None:
+ try:
+ os.kill(self._vncdaemon.pid,signal.SIGTERM)
+ except:
+ pass
+ #self._vncdaemon.terminate() #requires python 2.6
+ return True
+
+ 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):
+ self._logger.error('ListTubes() failed: %s' % e)