Merge branch 'master' of git+ssh://dev.laptop.org/git/sugar
This commit is contained in:
commit
e92dc1d29f
@ -1 +1 @@
|
||||
SUBDIRS = chat groupchat terminal web
|
||||
SUBDIRS = chat groupchat terminal web sketch
|
||||
|
6
activities/sketch/Makefile.am
Normal file
6
activities/sketch/Makefile.am
Normal file
@ -0,0 +1,6 @@
|
||||
sugardir = $(pkgdatadir)/activities/sketch
|
||||
sugar_PYTHON = \
|
||||
__init__.py \
|
||||
sketchactivity.py
|
||||
|
||||
EXTRA_DIST = sketch.activity
|
0
activities/sketch/__init__.py
Normal file
0
activities/sketch/__init__.py
Normal file
6
activities/sketch/sketch.activity
Normal file
6
activities/sketch/sketch.activity
Normal file
@ -0,0 +1,6 @@
|
||||
[Activity]
|
||||
name = Sketch
|
||||
id = org.laptop.Sketch
|
||||
icon = activity-sketch
|
||||
python_module = sketch.sketchactivity.SketchActivity
|
||||
show_launcher = yes
|
234
activities/sketch/sketchactivity.py
Normal file
234
activities/sketch/sketchactivity.py
Normal file
@ -0,0 +1,234 @@
|
||||
# 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
|
||||
|
||||
import gtk
|
||||
import gobject
|
||||
import os
|
||||
import logging
|
||||
|
||||
from sugar.p2p import MostlyReliablePipe
|
||||
from sugar.p2p.Stream import Stream
|
||||
|
||||
from sugar.presence import PresenceService
|
||||
from sugar.activity.Activity import Activity
|
||||
from sugar.chat.sketchpad import SketchPad
|
||||
from sugar.chat.sketchpad import Sketch
|
||||
from sugar.graphics.iconcolor import IconColor
|
||||
from sugar import profile
|
||||
|
||||
class NetworkController(gobject.GObject):
|
||||
__gsignals__ = {
|
||||
'new-path':(gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT])),
|
||||
}
|
||||
|
||||
def __init__(self, parent, ps_owner):
|
||||
gobject.GObject.__init__(self)
|
||||
self._parent = parent
|
||||
self._parent.connect('buddy-joined', self._buddy_joined)
|
||||
self._parent.connect('buddy-left', self._buddy_left)
|
||||
self._stream = None
|
||||
self._stream_writer = None
|
||||
self._joined_buddies = {} # IP address -> buddy
|
||||
self._ps_owner = ps_owner
|
||||
|
||||
def init_stream(self, service):
|
||||
self._stream = Stream.new_from_service(service)
|
||||
self._stream.set_data_listener(self._recv_message)
|
||||
self._stream_writer = self._stream.new_writer()
|
||||
|
||||
def _recv_message(self, address, msg):
|
||||
# Ignore multicast messages from ourself
|
||||
if self._ps_owner and address == self._ps_owner.get_ip4_address():
|
||||
return
|
||||
|
||||
# Ensure the message comes from somebody in this activity
|
||||
if not self._joined_buddies.has_key(address):
|
||||
logging.debug("Message from unjoined buddy.")
|
||||
return
|
||||
|
||||
# Convert the points to an array and send to the sketchpad
|
||||
points = []
|
||||
msg = msg.strip()
|
||||
split_coords = msg.split(" ")
|
||||
for item in split_coords:
|
||||
x = 0
|
||||
y = 0
|
||||
try:
|
||||
(x, y) = item.split(",")
|
||||
x = float(x)
|
||||
y = float(y)
|
||||
except ValueError:
|
||||
continue
|
||||
if x < 0 or y < 0:
|
||||
continue
|
||||
points.append((x, y))
|
||||
|
||||
buddy = self._joined_buddies[address]
|
||||
self.emit("new-path", buddy, points)
|
||||
|
||||
def _buddy_joined(self, widget, activity, buddy, activity_type):
|
||||
activity_service = buddy.get_service_of_type(activity_type, activity)
|
||||
if not activity_service:
|
||||
logging.debug("Buddy Joined, but could not get activity service " \
|
||||
"of %s" % activity_type)
|
||||
return
|
||||
|
||||
address = activity_service.get_source_address()
|
||||
port = activity_service.get_port()
|
||||
if not address or not port:
|
||||
logging.debug("Buddy Joined, but could not get address/port from" \
|
||||
" activity service %s" % activity_type)
|
||||
return
|
||||
if not self._joined_buddies.has_key(address):
|
||||
logging.debug("Buddy joined: %s (%s)" % (address, port))
|
||||
self._joined_buddies[address] = buddy
|
||||
|
||||
def _buddy_left(self, widget, activity, buddy, activity_type):
|
||||
buddy_key = None
|
||||
for (key, value) in self._joined_buddies.items():
|
||||
if value == buddy:
|
||||
buddy_key = key
|
||||
break
|
||||
if buddy_key:
|
||||
del self._joined_buddies[buddy_key]
|
||||
|
||||
def new_local_sketch(self, path):
|
||||
""" Receive an array of point tuples the local user created """
|
||||
cmd = ""
|
||||
# Convert points into the wire format
|
||||
for point in path:
|
||||
cmd = cmd + "%d,%d " % (point[0], point[1])
|
||||
|
||||
# If there were no points, or we aren't in a shared activity yet,
|
||||
# don't send anything
|
||||
if not len(cmd) or not self._stream_writer:
|
||||
return
|
||||
|
||||
# Send the points to other buddies
|
||||
self._stream_writer.write(cmd)
|
||||
|
||||
def _html_to_rgb_color(colorstring):
|
||||
""" converts #RRGGBB to cairo-suitable floats"""
|
||||
colorstring = colorstring.strip()
|
||||
while colorstring[0] == '#':
|
||||
colorstring = colorstring[1:]
|
||||
r = int(colorstring[:2], 16)
|
||||
g = int(colorstring[2:4], 16)
|
||||
b = int(colorstring[4:6], 16)
|
||||
color = ((float(r) / 255.0), (float(g) / 255.0), (float(b) / 255.0))
|
||||
return color
|
||||
|
||||
|
||||
class SharedSketchPad(SketchPad.SketchPad):
|
||||
def __init__(self, net_controller, color):
|
||||
SketchPad.SketchPad.__init__(self, bgcolor=(1.0, 0.984313725, 0.560784314))
|
||||
self._net_controller = net_controller
|
||||
self._user_color = _html_to_rgb_color(color)
|
||||
self.set_color(self._user_color)
|
||||
|
||||
# Receive notifications when our buddies send us new sketches
|
||||
self._net_controller.connect('new-path', self._new_buddy_path)
|
||||
|
||||
self.connect('new-user-sketch', self._new_local_sketch_cb)
|
||||
|
||||
def _new_buddy_path(self, net_controller, buddy, path):
|
||||
""" Called whenever a buddy on the mesh sends us a new sketch path """
|
||||
str_color = buddy.get_color()
|
||||
if not str_color:
|
||||
str_color = "#348798" # FIXME
|
||||
color = IconColor(str_color)
|
||||
stroke_color = _html_to_rgb_color(color.get_stroke_color())
|
||||
sketch = Sketch.Sketch(stroke_color)
|
||||
for item in path:
|
||||
sketch.add_point(item[0], item[1])
|
||||
self.add_sketch(sketch)
|
||||
|
||||
def _new_local_sketch_cb(self, widget, sketch):
|
||||
""" Send the sketch the user just made to the network """
|
||||
self._net_controller.new_local_sketch(sketch.get_points())
|
||||
|
||||
|
||||
class SketchActivity(Activity):
|
||||
__gsignals__ = {
|
||||
'buddy-joined':(gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT])),
|
||||
'buddy-left': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT]))
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
Activity.__init__(self)
|
||||
self.connect('destroy', self._cleanup_cb)
|
||||
|
||||
self.set_title("Sketch")
|
||||
|
||||
self._ps = PresenceService.get_instance()
|
||||
self._ps_activity = None
|
||||
self._owner = self._ps.get_owner()
|
||||
|
||||
self._net_controller = NetworkController(self, self._owner)
|
||||
self._sketchpad = SharedSketchPad(self._net_controller,
|
||||
profile.get_color().get_stroke_color())
|
||||
self.add(self._sketchpad)
|
||||
self.show_all()
|
||||
|
||||
def get_ps(self):
|
||||
return self._ps
|
||||
|
||||
def _cleanup_cb(self):
|
||||
del self._net_controller
|
||||
|
||||
def share(self):
|
||||
Activity.share(self)
|
||||
self._net_controller.init_stream(self._service)
|
||||
self._ps.connect('activity-appeared', self._activity_appeared_cb)
|
||||
|
||||
def join(self, activity_ps):
|
||||
Activity.join(self, activity_ps)
|
||||
self._net_controller.init_stream(self._service)
|
||||
self._ps.connect('activity-appeared', self._activity_appeared_cb)
|
||||
self._activity_appeared_cb(self._ps, activity_ps)
|
||||
|
||||
def _activity_appeared_cb(self, ps, activity):
|
||||
# Only care about our own activity
|
||||
if activity.get_id() != self.get_id():
|
||||
return
|
||||
|
||||
# If we already have found our shared activity, do nothing
|
||||
if self._ps_activity:
|
||||
return
|
||||
|
||||
self._ps_activity = activity
|
||||
|
||||
# Connect signals to the shared activity so we are notified when
|
||||
# buddies join and leave
|
||||
self._ps_activity.connect('buddy-joined', self._add_buddy)
|
||||
self._ps_activity.connect('buddy-left', self._remove_buddy)
|
||||
|
||||
# Get the list of buddies already in this shared activity so we can
|
||||
# connect to them
|
||||
buddies = self._ps_activity.get_joined_buddies()
|
||||
for buddy in buddies:
|
||||
self._add_buddy(self._ps_activity, buddy)
|
||||
|
||||
def _add_buddy(self, ps_activity, buddy):
|
||||
service_type = self._ps_activity
|
||||
self.emit('buddy-joined', ps_activity, buddy, self.get_default_type())
|
||||
|
||||
def _remove_buddy(self, ps_activity, buddy):
|
||||
self.emit('buddy-left', ps_activity, buddy, self.get_default_type())
|
||||
|
@ -53,6 +53,7 @@ activities/web/Makefile
|
||||
activities/chat/Makefile
|
||||
activities/groupchat/Makefile
|
||||
activities/terminal/Makefile
|
||||
activities/sketch/Makefile
|
||||
lib/Makefile
|
||||
lib/src/Makefile
|
||||
lib/python/Makefile
|
||||
|
Loading…
Reference in New Issue
Block a user