Changed all tabs to 4 spaces for python style
This commit is contained in:
+25
-25
@@ -22,33 +22,33 @@ import signal
|
||||
|
||||
haveThreadframe = True
|
||||
try:
|
||||
import threadframe
|
||||
import threadframe
|
||||
except ImportError:
|
||||
haveThreadframe = False
|
||||
haveThreadframe = False
|
||||
|
||||
class TracebackHelper(object):
|
||||
def __init__(self):
|
||||
fname = "%s-%d" % (os.path.basename(sys.argv[0]), os.getpid())
|
||||
self._fpath = os.path.join("/tmp", fname)
|
||||
print "Tracebacks will be written to %s on SIGUSR1" % self._fpath
|
||||
signal.signal(signal.SIGUSR1, self._handler)
|
||||
def __init__(self):
|
||||
fname = "%s-%d" % (os.path.basename(sys.argv[0]), os.getpid())
|
||||
self._fpath = os.path.join("/tmp", fname)
|
||||
print "Tracebacks will be written to %s on SIGUSR1" % self._fpath
|
||||
signal.signal(signal.SIGUSR1, self._handler)
|
||||
|
||||
def __del__(self):
|
||||
try:
|
||||
os.remove(self._fpath)
|
||||
except OSError:
|
||||
pass
|
||||
def __del__(self):
|
||||
try:
|
||||
os.remove(self._fpath)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
def _handler(self, signum, pframe):
|
||||
f = open(self._fpath, "a")
|
||||
if not haveThreadframe:
|
||||
f.write("Threadframe not installed. No traceback available.\n")
|
||||
else:
|
||||
frames = threadframe.dict()
|
||||
for thread_id, frame in frames.iteritems():
|
||||
f.write(('-' * 79) + '\n')
|
||||
f.write('[Thread %s] %d' % (thread_id, sys.getrefcount(frame)) + '\n')
|
||||
traceback.print_stack(frame, limit=None, file=f)
|
||||
f.write("\n")
|
||||
f.write('\n')
|
||||
f.close()
|
||||
def _handler(self, signum, pframe):
|
||||
f = open(self._fpath, "a")
|
||||
if not haveThreadframe:
|
||||
f.write("Threadframe not installed. No traceback available.\n")
|
||||
else:
|
||||
frames = threadframe.dict()
|
||||
for thread_id, frame in frames.iteritems():
|
||||
f.write(('-' * 79) + '\n')
|
||||
f.write('[Thread %s] %d' % (thread_id, sys.getrefcount(frame)) + '\n')
|
||||
traceback.print_stack(frame, limit=None, file=f)
|
||||
f.write("\n")
|
||||
f.write('\n')
|
||||
f.close()
|
||||
|
||||
+100
-100
@@ -32,133 +32,133 @@ ACTIVITY_SERVICE_PATH = "/org/laptop/Activity"
|
||||
ACTIVITY_INTERFACE = "org.laptop.Activity"
|
||||
|
||||
def get_service_name(xid):
|
||||
return ACTIVITY_SERVICE_NAME + '%d' % xid
|
||||
return ACTIVITY_SERVICE_NAME + '%d' % xid
|
||||
|
||||
def get_object_path(xid):
|
||||
return ACTIVITY_SERVICE_PATH + "/%s" % xid
|
||||
return ACTIVITY_SERVICE_PATH + "/%s" % xid
|
||||
|
||||
class ActivityDbusService(dbus.service.Object):
|
||||
"""Base dbus service object that each Activity uses to export dbus methods.
|
||||
|
||||
The dbus service is separate from the actual Activity object so that we can
|
||||
tightly control what stuff passes through the dbus python bindings."""
|
||||
"""Base dbus service object that each Activity uses to export dbus methods.
|
||||
|
||||
The dbus service is separate from the actual Activity object so that we can
|
||||
tightly control what stuff passes through the dbus python bindings."""
|
||||
|
||||
def start(self, pservice, activity):
|
||||
self._activity = activity
|
||||
self._pservice = pservice
|
||||
def start(self, pservice, activity):
|
||||
self._activity = activity
|
||||
self._pservice = pservice
|
||||
|
||||
@dbus.service.method(ACTIVITY_INTERFACE)
|
||||
def share(self):
|
||||
"""Called by the shell to request the activity to share itself on the network."""
|
||||
self._activity.share()
|
||||
@dbus.service.method(ACTIVITY_INTERFACE)
|
||||
def share(self):
|
||||
"""Called by the shell to request the activity to share itself on the network."""
|
||||
self._activity.share()
|
||||
|
||||
@dbus.service.method(ACTIVITY_INTERFACE)
|
||||
def join(self, activity_ps_path):
|
||||
"""Join the activity specified by its presence service path"""
|
||||
activity_ps = self._pservice.get(activity_ps_path)
|
||||
return self._activity.join(activity_ps)
|
||||
@dbus.service.method(ACTIVITY_INTERFACE)
|
||||
def join(self, activity_ps_path):
|
||||
"""Join the activity specified by its presence service path"""
|
||||
activity_ps = self._pservice.get(activity_ps_path)
|
||||
return self._activity.join(activity_ps)
|
||||
|
||||
@dbus.service.method(ACTIVITY_INTERFACE)
|
||||
def get_id(self):
|
||||
"""Get the activity identifier"""
|
||||
return self._activity.get_id()
|
||||
@dbus.service.method(ACTIVITY_INTERFACE)
|
||||
def get_id(self):
|
||||
"""Get the activity identifier"""
|
||||
return self._activity.get_id()
|
||||
|
||||
@dbus.service.method(ACTIVITY_INTERFACE)
|
||||
def get_type(self):
|
||||
"""Get the activity type"""
|
||||
return self._activity.get_type()
|
||||
@dbus.service.method(ACTIVITY_INTERFACE)
|
||||
def get_type(self):
|
||||
"""Get the activity type"""
|
||||
return self._activity.get_type()
|
||||
|
||||
@dbus.service.method(ACTIVITY_INTERFACE)
|
||||
def get_shared(self):
|
||||
"""Returns True if the activity is shared on the mesh."""
|
||||
return self._activity.get_shared()
|
||||
@dbus.service.method(ACTIVITY_INTERFACE)
|
||||
def get_shared(self):
|
||||
"""Returns True if the activity is shared on the mesh."""
|
||||
return self._activity.get_shared()
|
||||
|
||||
@dbus.service.method(ACTIVITY_INTERFACE,
|
||||
in_signature="sas", out_signature="")
|
||||
def execute(self, command, args):
|
||||
self._activity.execute(command, args)
|
||||
@dbus.service.method(ACTIVITY_INTERFACE,
|
||||
in_signature="sas", out_signature="")
|
||||
def execute(self, command, args):
|
||||
self._activity.execute(command, args)
|
||||
|
||||
class Activity(gtk.Window):
|
||||
"""Base Activity class that all other Activities derive from."""
|
||||
"""Base Activity class that all other Activities derive from."""
|
||||
|
||||
def __init__(self):
|
||||
gtk.Window.__init__(self)
|
||||
def __init__(self):
|
||||
gtk.Window.__init__(self)
|
||||
|
||||
self.connect('destroy', self.__destroy_cb)
|
||||
self.connect('destroy', self.__destroy_cb)
|
||||
|
||||
self._shared = False
|
||||
self._activity_id = None
|
||||
self._default_type = None
|
||||
self._service = None
|
||||
self._pservice = PresenceService()
|
||||
self._shared = False
|
||||
self._activity_id = None
|
||||
self._default_type = None
|
||||
self._service = None
|
||||
self._pservice = PresenceService()
|
||||
|
||||
self.present()
|
||||
|
||||
group = gtk.Window()
|
||||
group.realize()
|
||||
self.window.set_group(group.window)
|
||||
self.present()
|
||||
|
||||
group = gtk.Window()
|
||||
group.realize()
|
||||
self.window.set_group(group.window)
|
||||
|
||||
bus = dbus.SessionBus()
|
||||
xid = self.window.xid
|
||||
bus = dbus.SessionBus()
|
||||
xid = self.window.xid
|
||||
|
||||
bus_name = dbus.service.BusName(get_service_name(xid), bus=bus)
|
||||
self._bus = ActivityDbusService(bus_name, get_object_path(xid))
|
||||
self._bus.start(self._pservice, self)
|
||||
bus_name = dbus.service.BusName(get_service_name(xid), bus=bus)
|
||||
self._bus = ActivityDbusService(bus_name, get_object_path(xid))
|
||||
self._bus.start(self._pservice, self)
|
||||
|
||||
def set_type(self, activity_type):
|
||||
"""Sets the activity type."""
|
||||
self._activity_type = activity_type
|
||||
self._default_type = activity.get_default_type(activity_type)
|
||||
def set_type(self, activity_type):
|
||||
"""Sets the activity type."""
|
||||
self._activity_type = activity_type
|
||||
self._default_type = activity.get_default_type(activity_type)
|
||||
|
||||
def get_type(self):
|
||||
"""Gets the activity type."""
|
||||
return self._activity_type
|
||||
def get_type(self):
|
||||
"""Gets the activity type."""
|
||||
return self._activity_type
|
||||
|
||||
def get_default_type(self):
|
||||
return self._default_type
|
||||
def get_default_type(self):
|
||||
return self._default_type
|
||||
|
||||
def get_shared(self):
|
||||
"""Returns TRUE if the activity is shared on the mesh."""
|
||||
return self._shared
|
||||
def get_shared(self):
|
||||
"""Returns TRUE if the activity is shared on the mesh."""
|
||||
return self._shared
|
||||
|
||||
def get_id(self):
|
||||
"""Get the unique activity identifier."""
|
||||
if self._activity_id == None:
|
||||
self._activity_id = sugar.util.unique_id()
|
||||
return self._activity_id
|
||||
def get_id(self):
|
||||
"""Get the unique activity identifier."""
|
||||
if self._activity_id == None:
|
||||
self._activity_id = sugar.util.unique_id()
|
||||
return self._activity_id
|
||||
|
||||
def join(self, activity_ps):
|
||||
"""Join an activity shared on the network."""
|
||||
self._shared = True
|
||||
self._activity_id = activity_ps.get_id()
|
||||
def join(self, activity_ps):
|
||||
"""Join an activity shared on the network."""
|
||||
self._shared = True
|
||||
self._activity_id = activity_ps.get_id()
|
||||
|
||||
# Publish the default service, it's a copy of
|
||||
# one of those we found on the network.
|
||||
services = activity_ps.get_services_of_type(self._default_type)
|
||||
if len(services) > 0:
|
||||
service = services[0]
|
||||
addr = service.get_address()
|
||||
port = service.get_port()
|
||||
properties = service.get_published_values()
|
||||
self._service = self._pservice.share_activity(
|
||||
self, self._default_type, properties, addr, port)
|
||||
else:
|
||||
logging.error('Cannot join the activity')
|
||||
# Publish the default service, it's a copy of
|
||||
# one of those we found on the network.
|
||||
services = activity_ps.get_services_of_type(self._default_type)
|
||||
if len(services) > 0:
|
||||
service = services[0]
|
||||
addr = service.get_address()
|
||||
port = service.get_port()
|
||||
properties = service.get_published_values()
|
||||
self._service = self._pservice.share_activity(
|
||||
self, self._default_type, properties, addr, port)
|
||||
else:
|
||||
logging.error('Cannot join the activity')
|
||||
|
||||
def share(self):
|
||||
"""Share the activity on the network."""
|
||||
logging.debug('Share activity %s on the network.' % self.get_id())
|
||||
def share(self):
|
||||
"""Share the activity on the network."""
|
||||
logging.debug('Share activity %s on the network.' % self.get_id())
|
||||
|
||||
self._service = self._pservice.share_activity(self, self._default_type)
|
||||
self._shared = True
|
||||
self._service = self._pservice.share_activity(self, self._default_type)
|
||||
self._shared = True
|
||||
|
||||
def execute(self, command, args):
|
||||
"""Execute the given command with args"""
|
||||
pass
|
||||
def execute(self, command, args):
|
||||
"""Execute the given command with args"""
|
||||
pass
|
||||
|
||||
def __destroy_cb(self, window):
|
||||
if self._bus:
|
||||
del self._bus
|
||||
self._bus = None
|
||||
if self._service:
|
||||
self._pservice.unregister_service(self._service)
|
||||
def __destroy_cb(self, window):
|
||||
if self._bus:
|
||||
del self._bus
|
||||
self._bus = None
|
||||
if self._service:
|
||||
self._pservice.unregister_service(self._service)
|
||||
|
||||
@@ -27,72 +27,72 @@ from sugar.presence.PresenceService import PresenceService
|
||||
from sugar.activity import Activity
|
||||
|
||||
def get_path(activity_name):
|
||||
"""Returns the activity path"""
|
||||
return '/' + activity_name.replace('.', '/')
|
||||
"""Returns the activity path"""
|
||||
return '/' + activity_name.replace('.', '/')
|
||||
|
||||
class ActivityFactory(dbus.service.Object):
|
||||
"""Dbus service that takes care of creating new instances of an activity"""
|
||||
"""Dbus service that takes care of creating new instances of an activity"""
|
||||
|
||||
def __init__(self, activity_type, activity_class):
|
||||
self._activity_type = activity_type
|
||||
self._activities = []
|
||||
def __init__(self, activity_type, activity_class):
|
||||
self._activity_type = activity_type
|
||||
self._activities = []
|
||||
|
||||
splitted_module = activity_class.rsplit('.', 1)
|
||||
module_name = splitted_module[0]
|
||||
class_name = splitted_module[1]
|
||||
splitted_module = activity_class.rsplit('.', 1)
|
||||
module_name = splitted_module[0]
|
||||
class_name = splitted_module[1]
|
||||
|
||||
module = __import__(module_name)
|
||||
for comp in module_name.split('.')[1:]:
|
||||
module = getattr(module, comp)
|
||||
if hasattr(module, 'start'):
|
||||
module.start()
|
||||
module = __import__(module_name)
|
||||
for comp in module_name.split('.')[1:]:
|
||||
module = getattr(module, comp)
|
||||
if hasattr(module, 'start'):
|
||||
module.start()
|
||||
|
||||
self._module = module
|
||||
self._constructor = getattr(module, class_name)
|
||||
|
||||
bus = dbus.SessionBus()
|
||||
factory = activity_type
|
||||
bus_name = dbus.service.BusName(factory, bus = bus)
|
||||
dbus.service.Object.__init__(self, bus_name, get_path(factory))
|
||||
self._module = module
|
||||
self._constructor = getattr(module, class_name)
|
||||
|
||||
bus = dbus.SessionBus()
|
||||
factory = activity_type
|
||||
bus_name = dbus.service.BusName(factory, bus = bus)
|
||||
dbus.service.Object.__init__(self, bus_name, get_path(factory))
|
||||
|
||||
@dbus.service.method("com.redhat.Sugar.ActivityFactory")
|
||||
def create(self):
|
||||
activity = self._constructor()
|
||||
activity.set_type(self._activity_type)
|
||||
@dbus.service.method("com.redhat.Sugar.ActivityFactory")
|
||||
def create(self):
|
||||
activity = self._constructor()
|
||||
activity.set_type(self._activity_type)
|
||||
|
||||
self._activities.append(activity)
|
||||
activity.connect('destroy', self._activity_destroy_cb)
|
||||
self._activities.append(activity)
|
||||
activity.connect('destroy', self._activity_destroy_cb)
|
||||
|
||||
return activity.window.xid
|
||||
return activity.window.xid
|
||||
|
||||
def _activity_destroy_cb(self, activity):
|
||||
self._activities.remove(activity)
|
||||
def _activity_destroy_cb(self, activity):
|
||||
self._activities.remove(activity)
|
||||
|
||||
if hasattr(self._module, 'stop'):
|
||||
self._module.stop()
|
||||
if hasattr(self._module, 'stop'):
|
||||
self._module.stop()
|
||||
|
||||
if len(self._activities) == 0:
|
||||
gtk.main_quit()
|
||||
if len(self._activities) == 0:
|
||||
gtk.main_quit()
|
||||
|
||||
def create(activity_name):
|
||||
"""Create a new activity from his name."""
|
||||
bus = dbus.SessionBus()
|
||||
"""Create a new activity from his name."""
|
||||
bus = dbus.SessionBus()
|
||||
|
||||
factory_name = activity_name
|
||||
factory_path = get_path(factory_name)
|
||||
factory_name = activity_name
|
||||
factory_path = get_path(factory_name)
|
||||
|
||||
proxy_obj = bus.get_object(factory_name, factory_path)
|
||||
factory = dbus.Interface(proxy_obj, "com.redhat.Sugar.ActivityFactory")
|
||||
proxy_obj = bus.get_object(factory_name, factory_path)
|
||||
factory = dbus.Interface(proxy_obj, "com.redhat.Sugar.ActivityFactory")
|
||||
|
||||
xid = factory.create()
|
||||
xid = factory.create()
|
||||
|
||||
bus = dbus.SessionBus()
|
||||
proxy_obj = bus.get_object(Activity.get_service_name(xid),
|
||||
Activity.get_object_path(xid))
|
||||
activity = dbus.Interface(proxy_obj, Activity.ACTIVITY_INTERFACE)
|
||||
bus = dbus.SessionBus()
|
||||
proxy_obj = bus.get_object(Activity.get_service_name(xid),
|
||||
Activity.get_object_path(xid))
|
||||
activity = dbus.Interface(proxy_obj, Activity.ACTIVITY_INTERFACE)
|
||||
|
||||
return activity
|
||||
return activity
|
||||
|
||||
def register_factory(name, activity_class):
|
||||
"""Register the activity factory."""
|
||||
factory = ActivityFactory(name, activity_class)
|
||||
"""Register the activity factory."""
|
||||
factory = ActivityFactory(name, activity_class)
|
||||
|
||||
@@ -9,10 +9,10 @@ sizes = 'gtk-large-toolbar=%d, %d' % (grid.dimension(1), grid.dimension(1))
|
||||
settings.set_string_property('gtk-icon-sizes', sizes, '')
|
||||
|
||||
def get_default_type(activity_type):
|
||||
"""Get the activity default type.
|
||||
"""Get the activity default type.
|
||||
|
||||
It's the type of the main network service which tracks presence
|
||||
It's the type of the main network service which tracks presence
|
||||
and provides info about the activity, for example the title."""
|
||||
splitted_id = activity_type.split('.')
|
||||
splitted_id.reverse()
|
||||
return '_' + '_'.join(splitted_id) + '._udp'
|
||||
splitted_id = activity_type.split('.')
|
||||
splitted_id.reverse()
|
||||
return '_' + '_'.join(splitted_id) + '._udp'
|
||||
|
||||
+63
-63
@@ -4,83 +4,83 @@ import os
|
||||
from ConfigParser import ConfigParser
|
||||
|
||||
class Bundle:
|
||||
"""Info about an activity bundle. Wraps the activity.info file."""
|
||||
def __init__(self, path):
|
||||
self._name = None
|
||||
self._icon = None
|
||||
self._service_name = None
|
||||
self._show_launcher = True
|
||||
self._valid = True
|
||||
self._path = path
|
||||
self._activity_version = 0
|
||||
"""Info about an activity bundle. Wraps the activity.info file."""
|
||||
def __init__(self, path):
|
||||
self._name = None
|
||||
self._icon = None
|
||||
self._service_name = None
|
||||
self._show_launcher = True
|
||||
self._valid = True
|
||||
self._path = path
|
||||
self._activity_version = 0
|
||||
|
||||
info_path = os.path.join(path, 'activity', 'activity.info')
|
||||
if os.path.isfile(info_path):
|
||||
self._parse_info(info_path)
|
||||
else:
|
||||
self._valid = False
|
||||
info_path = os.path.join(path, 'activity', 'activity.info')
|
||||
if os.path.isfile(info_path):
|
||||
self._parse_info(info_path)
|
||||
else:
|
||||
self._valid = False
|
||||
|
||||
def _parse_info(self, info_path):
|
||||
cp = ConfigParser()
|
||||
cp.read([info_path])
|
||||
def _parse_info(self, info_path):
|
||||
cp = ConfigParser()
|
||||
cp.read([info_path])
|
||||
|
||||
section = 'Activity'
|
||||
section = 'Activity'
|
||||
|
||||
if cp.has_option(section, 'service_name'):
|
||||
self._service_name = cp.get(section, 'service_name')
|
||||
else:
|
||||
self._valid = False
|
||||
logging.error('%s must specify a service name' % self._path)
|
||||
if cp.has_option(section, 'service_name'):
|
||||
self._service_name = cp.get(section, 'service_name')
|
||||
else:
|
||||
self._valid = False
|
||||
logging.error('%s must specify a service name' % self._path)
|
||||
|
||||
if cp.has_option(section, 'name'):
|
||||
self._name = cp.get(section, 'name')
|
||||
else:
|
||||
self._valid = False
|
||||
logging.error('%s must specify a name' % self._path)
|
||||
if cp.has_option(section, 'name'):
|
||||
self._name = cp.get(section, 'name')
|
||||
else:
|
||||
self._valid = False
|
||||
logging.error('%s must specify a name' % self._path)
|
||||
|
||||
if cp.has_option(section, 'exec'):
|
||||
self._exec = cp.get(section, 'exec')
|
||||
else:
|
||||
self._valid = False
|
||||
logging.error('%s must specify an exec' % self._path)
|
||||
if cp.has_option(section, 'exec'):
|
||||
self._exec = cp.get(section, 'exec')
|
||||
else:
|
||||
self._valid = False
|
||||
logging.error('%s must specify an exec' % self._path)
|
||||
|
||||
if cp.has_option(section, 'show_launcher'):
|
||||
if cp.get(section, 'show_launcher') == 'no':
|
||||
self._show_launcher = False
|
||||
if cp.has_option(section, 'show_launcher'):
|
||||
if cp.get(section, 'show_launcher') == 'no':
|
||||
self._show_launcher = False
|
||||
|
||||
if cp.has_option(section, 'icon'):
|
||||
self._icon = cp.get(section, 'icon')
|
||||
if cp.has_option(section, 'icon'):
|
||||
self._icon = cp.get(section, 'icon')
|
||||
|
||||
if cp.has_option(section, 'activity_version'):
|
||||
self._activity_version = int(cp.get(section, 'activity_version'))
|
||||
if cp.has_option(section, 'activity_version'):
|
||||
self._activity_version = int(cp.get(section, 'activity_version'))
|
||||
|
||||
def is_valid(self):
|
||||
return self._valid
|
||||
def is_valid(self):
|
||||
return self._valid
|
||||
|
||||
def get_path(self):
|
||||
"""Get the activity bundle path."""
|
||||
return self._path
|
||||
def get_path(self):
|
||||
"""Get the activity bundle path."""
|
||||
return self._path
|
||||
|
||||
def get_name(self):
|
||||
"""Get the activity user visible name."""
|
||||
return self._name
|
||||
def get_name(self):
|
||||
"""Get the activity user visible name."""
|
||||
return self._name
|
||||
|
||||
def get_service_name(self):
|
||||
"""Get the activity service name"""
|
||||
return self._service_name
|
||||
def get_service_name(self):
|
||||
"""Get the activity service name"""
|
||||
return self._service_name
|
||||
|
||||
def get_icon(self):
|
||||
"""Get the activity icon name"""
|
||||
return self._icon
|
||||
def get_icon(self):
|
||||
"""Get the activity icon name"""
|
||||
return self._icon
|
||||
|
||||
def get_activity_version(self):
|
||||
"""Get the activity version"""
|
||||
return self._activity_version
|
||||
def get_activity_version(self):
|
||||
"""Get the activity version"""
|
||||
return self._activity_version
|
||||
|
||||
def get_exec(self):
|
||||
"""Get the command to execute to launch the activity factory"""
|
||||
return self._exec
|
||||
def get_exec(self):
|
||||
"""Get the command to execute to launch the activity factory"""
|
||||
return self._exec
|
||||
|
||||
def get_show_launcher(self):
|
||||
"""Get whether there should be a visible launcher for the activity"""
|
||||
return self._show_launcher
|
||||
def get_show_launcher(self):
|
||||
"""Get whether there should be a visible launcher for the activity"""
|
||||
return self._show_launcher
|
||||
|
||||
@@ -25,71 +25,71 @@ import shutil
|
||||
from sugar.activity.bundle import Bundle
|
||||
|
||||
class _SvnFileList(list):
|
||||
def __init__(self):
|
||||
f = os.popen('svn list -R')
|
||||
for line in f.readlines():
|
||||
filename = line.strip()
|
||||
if os.path.isfile(filename):
|
||||
self.append(filename)
|
||||
f.close()
|
||||
def __init__(self):
|
||||
f = os.popen('svn list -R')
|
||||
for line in f.readlines():
|
||||
filename = line.strip()
|
||||
if os.path.isfile(filename):
|
||||
self.append(filename)
|
||||
f.close()
|
||||
|
||||
class _GitFileList(list):
|
||||
def __init__(self):
|
||||
f = os.popen('git-ls-files')
|
||||
for line in f.readlines():
|
||||
filename = line.strip()
|
||||
if not filename.startswith('.'):
|
||||
self.append(filename)
|
||||
f.close()
|
||||
def __init__(self):
|
||||
f = os.popen('git-ls-files')
|
||||
for line in f.readlines():
|
||||
filename = line.strip()
|
||||
if not filename.startswith('.'):
|
||||
self.append(filename)
|
||||
f.close()
|
||||
|
||||
def _extract_bundle(source_file, dest_dir):
|
||||
if not os.path.exists(dest_dir):
|
||||
os.mkdir(dest_dir)
|
||||
if not os.path.exists(dest_dir):
|
||||
os.mkdir(dest_dir)
|
||||
|
||||
zf = zipfile.ZipFile(source_file)
|
||||
zf = zipfile.ZipFile(source_file)
|
||||
|
||||
for i, name in enumerate(zf.namelist()):
|
||||
path = os.path.join(dest_dir, name)
|
||||
|
||||
if not os.path.exists(os.path.dirname(path)):
|
||||
os.makedirs(os.path.dirname(path))
|
||||
for i, name in enumerate(zf.namelist()):
|
||||
path = os.path.join(dest_dir, name)
|
||||
|
||||
if not os.path.exists(os.path.dirname(path)):
|
||||
os.makedirs(os.path.dirname(path))
|
||||
|
||||
outfile = open(path, 'wb')
|
||||
outfile.write(zf.read(name))
|
||||
outfile.flush()
|
||||
outfile.close()
|
||||
outfile = open(path, 'wb')
|
||||
outfile.write(zf.read(name))
|
||||
outfile.flush()
|
||||
outfile.close()
|
||||
|
||||
def _get_source_path():
|
||||
return os.getcwd()
|
||||
return os.getcwd()
|
||||
|
||||
def _get_activities_path():
|
||||
path = os.path.expanduser('~/Activities')
|
||||
if not os.path.isdir(path):
|
||||
os.mkdir(path)
|
||||
return path
|
||||
path = os.path.expanduser('~/Activities')
|
||||
if not os.path.isdir(path):
|
||||
os.mkdir(path)
|
||||
return path
|
||||
|
||||
def _get_bundle_dir():
|
||||
bundle_name = os.path.basename(_get_source_path())
|
||||
return bundle_name + '.activity'
|
||||
bundle_name = os.path.basename(_get_source_path())
|
||||
return bundle_name + '.activity'
|
||||
|
||||
def _get_install_dir(prefix):
|
||||
return os.path.join(prefix, 'share/activities')
|
||||
return os.path.join(prefix, 'share/activities')
|
||||
|
||||
def _get_bundle_path():
|
||||
return os.path.join(_get_activities_path(), _get_bundle_dir())
|
||||
return os.path.join(_get_activities_path(), _get_bundle_dir())
|
||||
|
||||
def _get_package_name():
|
||||
bundle = Bundle(_get_source_path())
|
||||
zipname = '%s-%d.xo' % (bundle.get_name(), bundle.get_activity_version())
|
||||
return zipname
|
||||
bundle = Bundle(_get_source_path())
|
||||
zipname = '%s-%d.xo' % (bundle.get_name(), bundle.get_activity_version())
|
||||
return zipname
|
||||
|
||||
def _delete_backups(arg, dirname, names):
|
||||
for name in names:
|
||||
if name.endswith('~') or name.endswith('pyc'):
|
||||
os.remove(os.path.join(dirname, name))
|
||||
for name in names:
|
||||
if name.endswith('~') or name.endswith('pyc'):
|
||||
os.remove(os.path.join(dirname, name))
|
||||
|
||||
def cmd_help():
|
||||
print 'Usage: \n\
|
||||
print 'Usage: \n\
|
||||
setup.py dev - setup for development \n\
|
||||
setup.py dist - create a bundle package \n\
|
||||
setup.py install - install the bundle \n\
|
||||
@@ -98,59 +98,59 @@ setup.py help - print this message \n\
|
||||
'
|
||||
|
||||
def cmd_dev():
|
||||
bundle_path = get_bundle_path()
|
||||
try:
|
||||
os.symlink(_get_source_path(), bundle_path)
|
||||
except OSError:
|
||||
if os.path.islink(bundle_path):
|
||||
print 'ERROR - The bundle has been already setup for development.'
|
||||
else:
|
||||
print 'ERROR - A bundle with the same name is already installed.'
|
||||
bundle_path = get_bundle_path()
|
||||
try:
|
||||
os.symlink(_get_source_path(), bundle_path)
|
||||
except OSError:
|
||||
if os.path.islink(bundle_path):
|
||||
print 'ERROR - The bundle has been already setup for development.'
|
||||
else:
|
||||
print 'ERROR - A bundle with the same name is already installed.'
|
||||
|
||||
def cmd_dist():
|
||||
if os.path.isdir('.git'):
|
||||
file_list = _GitFileList()
|
||||
elif os.path.isdir('.svn'):
|
||||
file_list = _SvnFileList()
|
||||
else:
|
||||
print 'ERROR - The command works only with git or svn repositories.'
|
||||
if os.path.isdir('.git'):
|
||||
file_list = _GitFileList()
|
||||
elif os.path.isdir('.svn'):
|
||||
file_list = _SvnFileList()
|
||||
else:
|
||||
print 'ERROR - The command works only with git or svn repositories.'
|
||||
|
||||
zipname = _get_package_name()
|
||||
bundle_zip = zipfile.ZipFile(zipname, 'w', zipfile.ZIP_DEFLATED)
|
||||
|
||||
for filename in file_list:
|
||||
arcname = os.path.join(_get_bundle_dir(), filename)
|
||||
bundle_zip.write(filename, arcname)
|
||||
zipname = _get_package_name()
|
||||
bundle_zip = zipfile.ZipFile(zipname, 'w', zipfile.ZIP_DEFLATED)
|
||||
|
||||
for filename in file_list:
|
||||
arcname = os.path.join(_get_bundle_dir(), filename)
|
||||
bundle_zip.write(filename, arcname)
|
||||
|
||||
bundle_zip.close()
|
||||
bundle_zip.close()
|
||||
|
||||
def cmd_install(prefix):
|
||||
cmd_dist()
|
||||
cmd_uninstall(prefix)
|
||||
_extract_bundle(_get_package_name(), _get_install_dir(prefix))
|
||||
cmd_dist()
|
||||
cmd_uninstall(prefix)
|
||||
_extract_bundle(_get_package_name(), _get_install_dir(prefix))
|
||||
|
||||
def cmd_uninstall(prefix):
|
||||
path = os.path.join(_get_install_dir(prefix), _get_bundle_dir())
|
||||
if os.path.isdir(path):
|
||||
shutil.rmtree(path)
|
||||
path = os.path.join(_get_install_dir(prefix), _get_bundle_dir())
|
||||
if os.path.isdir(path):
|
||||
shutil.rmtree(path)
|
||||
|
||||
def cmd_clean():
|
||||
os.path.walk('.', delete_backups, None)
|
||||
os.path.walk('.', delete_backups, None)
|
||||
|
||||
def start():
|
||||
if len(sys.argv) < 2:
|
||||
cmd_help()
|
||||
elif sys.argv[1] == 'build':
|
||||
pass
|
||||
elif sys.argv[1] == 'dev':
|
||||
cmd_dev()
|
||||
elif sys.argv[1] == 'dist':
|
||||
cmd_dist()
|
||||
elif sys.argv[1] == 'install' and len(sys.argv) == 3:
|
||||
cmd_install(sys.argv[2])
|
||||
elif sys.argv[1] == 'uninstall' and len(sys.argv) == 3:
|
||||
cmd_uninstall(sys.argv[2])
|
||||
elif sys.argv[1] == 'clean':
|
||||
cmd_clean()
|
||||
else:
|
||||
cmd_help()
|
||||
if len(sys.argv) < 2:
|
||||
cmd_help()
|
||||
elif sys.argv[1] == 'build':
|
||||
pass
|
||||
elif sys.argv[1] == 'dev':
|
||||
cmd_dev()
|
||||
elif sys.argv[1] == 'dist':
|
||||
cmd_dist()
|
||||
elif sys.argv[1] == 'install' and len(sys.argv) == 3:
|
||||
cmd_install(sys.argv[2])
|
||||
elif sys.argv[1] == 'uninstall' and len(sys.argv) == 3:
|
||||
cmd_uninstall(sys.argv[2])
|
||||
elif sys.argv[1] == 'clean':
|
||||
cmd_clean()
|
||||
else:
|
||||
cmd_help()
|
||||
|
||||
@@ -6,51 +6,51 @@ from sugar import env
|
||||
from sugar import util
|
||||
|
||||
class _ServiceManager(object):
|
||||
def __init__(self):
|
||||
self._path = env.get_user_service_dir()
|
||||
def __init__(self):
|
||||
self._path = env.get_user_service_dir()
|
||||
|
||||
def add(self, bundle):
|
||||
name = bundle.get_service_name()
|
||||
def add(self, bundle):
|
||||
name = bundle.get_service_name()
|
||||
|
||||
# FIXME evil hack. Probably need to fix Exec spec
|
||||
full_exec = env.get_shell_bin_dir() + '/' + bundle.get_exec()
|
||||
full_exec += ' ' + bundle.get_path()
|
||||
# FIXME evil hack. Probably need to fix Exec spec
|
||||
full_exec = env.get_shell_bin_dir() + '/' + bundle.get_exec()
|
||||
full_exec += ' ' + bundle.get_path()
|
||||
|
||||
util.write_service(name, full_exec, self._path)
|
||||
util.write_service(name, full_exec, self._path)
|
||||
|
||||
class BundleRegistry:
|
||||
"""Service that tracks the available activity bundles"""
|
||||
"""Service that tracks the available activity bundles"""
|
||||
|
||||
def __init__(self):
|
||||
self._bundles = {}
|
||||
self._search_path = []
|
||||
self._service_manager = _ServiceManager()
|
||||
def __init__(self):
|
||||
self._bundles = {}
|
||||
self._search_path = []
|
||||
self._service_manager = _ServiceManager()
|
||||
|
||||
def get_bundle(self, service_name):
|
||||
"""Returns an bundle given his service name"""
|
||||
if self._bundles.has_key(service_name):
|
||||
return self._bundles[service_name]
|
||||
else:
|
||||
return None
|
||||
def get_bundle(self, service_name):
|
||||
"""Returns an bundle given his service name"""
|
||||
if self._bundles.has_key(service_name):
|
||||
return self._bundles[service_name]
|
||||
else:
|
||||
return None
|
||||
|
||||
def add_search_path(self, path):
|
||||
"""Add a directory to the bundles search path"""
|
||||
self._search_path.append(path)
|
||||
self._scan_directory(path)
|
||||
|
||||
def __iter__(self):
|
||||
return self._bundles.values().__iter__()
|
||||
def add_search_path(self, path):
|
||||
"""Add a directory to the bundles search path"""
|
||||
self._search_path.append(path)
|
||||
self._scan_directory(path)
|
||||
|
||||
def __iter__(self):
|
||||
return self._bundles.values().__iter__()
|
||||
|
||||
def _scan_directory(self, path):
|
||||
if os.path.isdir(path):
|
||||
for f in os.listdir(path):
|
||||
bundle_dir = os.path.join(path, f)
|
||||
if os.path.isdir(bundle_dir) and \
|
||||
bundle_dir.endswith('.activity'):
|
||||
self._add_bundle(bundle_dir)
|
||||
def _scan_directory(self, path):
|
||||
if os.path.isdir(path):
|
||||
for f in os.listdir(path):
|
||||
bundle_dir = os.path.join(path, f)
|
||||
if os.path.isdir(bundle_dir) and \
|
||||
bundle_dir.endswith('.activity'):
|
||||
self._add_bundle(bundle_dir)
|
||||
|
||||
def _add_bundle(self, bundle_path):
|
||||
bundle = Bundle(bundle_path)
|
||||
if bundle.is_valid():
|
||||
self._bundles[bundle.get_service_name()] = bundle
|
||||
self._service_manager.add(bundle)
|
||||
def _add_bundle(self, bundle_path):
|
||||
bundle = Bundle(bundle_path)
|
||||
if bundle.is_valid():
|
||||
self._bundles[bundle.get_service_name()] = bundle
|
||||
self._service_manager.add(bundle)
|
||||
|
||||
+37
-37
@@ -20,48 +20,48 @@ import logging
|
||||
from sugar.chat.GroupChat import GroupChat
|
||||
|
||||
class ActivityChat(GroupChat):
|
||||
SERVICE_TYPE = "_olpc_activity_chat._udp"
|
||||
SERVICE_TYPE = "_olpc_activity_chat._udp"
|
||||
|
||||
def __init__(self, activity):
|
||||
GroupChat.__init__(self)
|
||||
self._chat_service = None
|
||||
def __init__(self, activity):
|
||||
GroupChat.__init__(self)
|
||||
self._chat_service = None
|
||||
|
||||
self.connect('destroy', self._destroy_cb)
|
||||
self.connect('destroy', self._destroy_cb)
|
||||
|
||||
self._activity = activity
|
||||
self._pservice.register_service_type(ActivityChat.SERVICE_TYPE)
|
||||
self._pservice.connect('service-appeared', self._service_appeared_cb)
|
||||
self._activity = activity
|
||||
self._pservice.register_service_type(ActivityChat.SERVICE_TYPE)
|
||||
self._pservice.connect('service-appeared', self._service_appeared_cb)
|
||||
|
||||
# Find an existing activity chat to latch onto
|
||||
ps_activity = self._pservice.get_activity(activity.get_id())
|
||||
if ps_activity is not None:
|
||||
services = ps_activity.get_services_of_type(ActivityChat.SERVICE_TYPE)
|
||||
if len(services) > 0:
|
||||
self._service_appeared_cb(self._pservice, services[0])
|
||||
# Find an existing activity chat to latch onto
|
||||
ps_activity = self._pservice.get_activity(activity.get_id())
|
||||
if ps_activity is not None:
|
||||
services = ps_activity.get_services_of_type(ActivityChat.SERVICE_TYPE)
|
||||
if len(services) > 0:
|
||||
self._service_appeared_cb(self._pservice, services[0])
|
||||
|
||||
def _service_appeared_cb(self, pservice, service):
|
||||
if service.get_activity_id() != self._activity.get_id():
|
||||
return
|
||||
if service.get_type() != ActivityChat.SERVICE_TYPE:
|
||||
return
|
||||
if self._chat_service:
|
||||
return
|
||||
def _service_appeared_cb(self, pservice, service):
|
||||
if service.get_activity_id() != self._activity.get_id():
|
||||
return
|
||||
if service.get_type() != ActivityChat.SERVICE_TYPE:
|
||||
return
|
||||
if self._chat_service:
|
||||
return
|
||||
|
||||
logging.debug('Activity chat service appeared, setup the stream.')
|
||||
# Ok, there's an existing chat service that we copy
|
||||
# parameters and such from
|
||||
addr = service.get_address()
|
||||
port = service.get_port()
|
||||
self._chat_service = self._pservice.share_activity(self._activity,
|
||||
stype=ActivityChat.SERVICE_TYPE, address=addr, port=port)
|
||||
self._setup_stream(self._chat_service)
|
||||
logging.debug('Activity chat service appeared, setup the stream.')
|
||||
# Ok, there's an existing chat service that we copy
|
||||
# parameters and such from
|
||||
addr = service.get_address()
|
||||
port = service.get_port()
|
||||
self._chat_service = self._pservice.share_activity(self._activity,
|
||||
stype=ActivityChat.SERVICE_TYPE, address=addr, port=port)
|
||||
self._setup_stream(self._chat_service)
|
||||
|
||||
def share(self):
|
||||
"""Only called when we share the activity this chat is tied to."""
|
||||
self._chat_service = self._pservice.share_activity(self._activity,
|
||||
stype=ActivityChat.SERVICE_TYPE)
|
||||
self._setup_stream(self._chat_service)
|
||||
def share(self):
|
||||
"""Only called when we share the activity this chat is tied to."""
|
||||
self._chat_service = self._pservice.share_activity(self._activity,
|
||||
stype=ActivityChat.SERVICE_TYPE)
|
||||
self._setup_stream(self._chat_service)
|
||||
|
||||
def _destroy_cb(self, widget):
|
||||
if self._chat_service:
|
||||
self._pservice.unregister_service(self._chat_service)
|
||||
def _destroy_cb(self, widget):
|
||||
if self._chat_service:
|
||||
self._pservice.unregister_service(self._chat_service)
|
||||
|
||||
+203
-203
@@ -37,244 +37,244 @@ import richtext
|
||||
PANGO_SCALE = 1024 # Where is this defined?
|
||||
|
||||
class Chat(gtk.VBox):
|
||||
SERVICE_TYPE = "_olpc_chat._tcp"
|
||||
SERVICE_PORT = 6100
|
||||
SERVICE_TYPE = "_olpc_chat._tcp"
|
||||
SERVICE_PORT = 6100
|
||||
|
||||
TEXT_MODE = 0
|
||||
SKETCH_MODE = 1
|
||||
TEXT_MODE = 0
|
||||
SKETCH_MODE = 1
|
||||
|
||||
def __init__(self):
|
||||
gtk.VBox.__init__(self, False, 6)
|
||||
def __init__(self):
|
||||
gtk.VBox.__init__(self, False, 6)
|
||||
|
||||
self._pservice = PresenceService.get_instance()
|
||||
self._pservice = PresenceService.get_instance()
|
||||
|
||||
self._stream_writer = None
|
||||
self.set_border_width(12)
|
||||
self._stream_writer = None
|
||||
self.set_border_width(12)
|
||||
|
||||
chat_vbox = gtk.VBox()
|
||||
chat_vbox.set_spacing(6)
|
||||
chat_vbox = gtk.VBox()
|
||||
chat_vbox.set_spacing(6)
|
||||
|
||||
self._chat_sw = gtk.ScrolledWindow()
|
||||
self._chat_sw.set_shadow_type(gtk.SHADOW_IN)
|
||||
self._chat_sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
|
||||
self._chat_view = richtext.RichTextView()
|
||||
self._chat_view.connect("link-clicked", self.__link_clicked_cb)
|
||||
self._chat_view.set_editable(False)
|
||||
self._chat_view.set_cursor_visible(False)
|
||||
self._chat_view.set_pixels_above_lines(7)
|
||||
self._chat_view.set_left_margin(5)
|
||||
self._chat_sw.add(self._chat_view)
|
||||
self._chat_view.show()
|
||||
chat_vbox.pack_start(self._chat_sw)
|
||||
self._chat_sw.show()
|
||||
|
||||
self.pack_start(chat_vbox)
|
||||
chat_vbox.show()
|
||||
self._chat_sw = gtk.ScrolledWindow()
|
||||
self._chat_sw.set_shadow_type(gtk.SHADOW_IN)
|
||||
self._chat_sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
|
||||
self._chat_view = richtext.RichTextView()
|
||||
self._chat_view.connect("link-clicked", self.__link_clicked_cb)
|
||||
self._chat_view.set_editable(False)
|
||||
self._chat_view.set_cursor_visible(False)
|
||||
self._chat_view.set_pixels_above_lines(7)
|
||||
self._chat_view.set_left_margin(5)
|
||||
self._chat_sw.add(self._chat_view)
|
||||
self._chat_view.show()
|
||||
chat_vbox.pack_start(self._chat_sw)
|
||||
self._chat_sw.show()
|
||||
|
||||
self.pack_start(chat_vbox)
|
||||
chat_vbox.show()
|
||||
|
||||
self._mode = Chat.TEXT_MODE
|
||||
self._editor = ChatEditor(self, ChatEditor.TEXT_MODE)
|
||||
self._mode = Chat.TEXT_MODE
|
||||
self._editor = ChatEditor(self, ChatEditor.TEXT_MODE)
|
||||
|
||||
toolbar = ChatToolbar(self._editor)
|
||||
self.pack_start(toolbar, False)
|
||||
toolbar.show()
|
||||
toolbar = ChatToolbar(self._editor)
|
||||
self.pack_start(toolbar, False)
|
||||
toolbar.show()
|
||||
|
||||
self.pack_start(self._editor, False)
|
||||
self._editor.show()
|
||||
self.pack_start(self._editor, False)
|
||||
self._editor.show()
|
||||
|
||||
self.connect("key-press-event", self.__key_press_event_cb)
|
||||
self.connect("key-press-event", self.__key_press_event_cb)
|
||||
|
||||
def __key_press_event_cb(self, window, event):
|
||||
if event.keyval == gtk.keysyms.s and \
|
||||
event.state & gtk.gdk.CONTROL_MASK:
|
||||
if self.get_mode() == Chat.SKETCH_MODE:
|
||||
self.set_mode(Chat.TEXT_MODE)
|
||||
elif self.get_mode() == Chat.TEXT_MODE:
|
||||
self.set_mode(Chat.SKETCH_MODE)
|
||||
def __key_press_event_cb(self, window, event):
|
||||
if event.keyval == gtk.keysyms.s and \
|
||||
event.state & gtk.gdk.CONTROL_MASK:
|
||||
if self.get_mode() == Chat.SKETCH_MODE:
|
||||
self.set_mode(Chat.TEXT_MODE)
|
||||
elif self.get_mode() == Chat.TEXT_MODE:
|
||||
self.set_mode(Chat.SKETCH_MODE)
|
||||
|
||||
def get_mode(self):
|
||||
return self._mode
|
||||
def get_mode(self):
|
||||
return self._mode
|
||||
|
||||
def set_mode(self, mode):
|
||||
self._mode = mode
|
||||
if self._mode == Chat.TEXT_MODE:
|
||||
self._editor.set_mode(ChatEditor.TEXT_MODE)
|
||||
elif self._mode == Chat.SKETCH_MODE:
|
||||
self._editor.set_mode(ChatEditor.SKETCH_MODE)
|
||||
def set_mode(self, mode):
|
||||
self._mode = mode
|
||||
if self._mode == Chat.TEXT_MODE:
|
||||
self._editor.set_mode(ChatEditor.TEXT_MODE)
|
||||
elif self._mode == Chat.SKETCH_MODE:
|
||||
self._editor.set_mode(ChatEditor.SKETCH_MODE)
|
||||
|
||||
def __get_browser_shell(self):
|
||||
bus = dbus.SessionBus()
|
||||
proxy_obj = bus.get_object('com.redhat.Sugar.Browser', '/com/redhat/Sugar/Browser')
|
||||
self._browser_shell = dbus.Interface(proxy_obj, 'com.redhat.Sugar.BrowserShell')
|
||||
def __get_browser_shell(self):
|
||||
bus = dbus.SessionBus()
|
||||
proxy_obj = bus.get_object('com.redhat.Sugar.Browser', '/com/redhat/Sugar/Browser')
|
||||
self._browser_shell = dbus.Interface(proxy_obj, 'com.redhat.Sugar.BrowserShell')
|
||||
|
||||
def __link_clicked_cb(self, view, address):
|
||||
self.__get_browser_shell().open_browser(address)
|
||||
def __link_clicked_cb(self, view, address):
|
||||
self.__get_browser_shell().open_browser(address)
|
||||
|
||||
def _scroll_chat_view_to_bottom(self):
|
||||
# Only scroll to bottom if the view is already close to the bottom
|
||||
vadj = self._chat_sw.get_vadjustment()
|
||||
if vadj.value + vadj.page_size > vadj.upper * 0.8:
|
||||
vadj.value = vadj.upper - vadj.page_size
|
||||
self._chat_sw.set_vadjustment(vadj)
|
||||
def _scroll_chat_view_to_bottom(self):
|
||||
# Only scroll to bottom if the view is already close to the bottom
|
||||
vadj = self._chat_sw.get_vadjustment()
|
||||
if vadj.value + vadj.page_size > vadj.upper * 0.8:
|
||||
vadj.value = vadj.upper - vadj.page_size
|
||||
self._chat_sw.set_vadjustment(vadj)
|
||||
|
||||
def _message_inserted(self):
|
||||
gobject.idle_add(self._scroll_chat_view_to_bottom)
|
||||
def _message_inserted(self):
|
||||
gobject.idle_add(self._scroll_chat_view_to_bottom)
|
||||
|
||||
def _insert_buddy(self, buf, buddy):
|
||||
# Stuff in the buddy icon, if we have one for this buddy
|
||||
icon = buddy.get_icon_pixbuf()
|
||||
if icon:
|
||||
rise = int(icon.get_height() / 4) * -1
|
||||
def _insert_buddy(self, buf, buddy):
|
||||
# Stuff in the buddy icon, if we have one for this buddy
|
||||
icon = buddy.get_icon_pixbuf()
|
||||
if icon:
|
||||
rise = int(icon.get_height() / 4) * -1
|
||||
|
||||
hash_string = "%s-%s" % (buddy.get_name(), buddy.get_ip4_address())
|
||||
sha_hash = sha.new()
|
||||
sha_hash.update(hash_string)
|
||||
tagname = "buddyicon-%s" % sha_hash.hexdigest()
|
||||
hash_string = "%s-%s" % (buddy.get_name(), buddy.get_ip4_address())
|
||||
sha_hash = sha.new()
|
||||
sha_hash.update(hash_string)
|
||||
tagname = "buddyicon-%s" % sha_hash.hexdigest()
|
||||
|
||||
if not buf.get_tag_table().lookup(tagname):
|
||||
buf.create_tag(tagname, rise=(rise * PANGO_SCALE))
|
||||
if not buf.get_tag_table().lookup(tagname):
|
||||
buf.create_tag(tagname, rise=(rise * PANGO_SCALE))
|
||||
|
||||
aniter = buf.get_end_iter()
|
||||
buf.insert_pixbuf(aniter, icon)
|
||||
aniter.backward_char()
|
||||
enditer = buf.get_end_iter()
|
||||
buf.apply_tag_by_name(tagname, aniter, enditer)
|
||||
aniter = buf.get_end_iter()
|
||||
buf.insert_pixbuf(aniter, icon)
|
||||
aniter.backward_char()
|
||||
enditer = buf.get_end_iter()
|
||||
buf.apply_tag_by_name(tagname, aniter, enditer)
|
||||
|
||||
# Stick in the buddy's nickname
|
||||
if not buf.get_tag_table().lookup("nickname"):
|
||||
buf.create_tag("nickname", weight=pango.WEIGHT_BOLD)
|
||||
aniter = buf.get_end_iter()
|
||||
offset = aniter.get_offset()
|
||||
buf.insert(aniter, " " + buddy.get_name() + ": ")
|
||||
enditer = buf.get_iter_at_offset(offset)
|
||||
buf.apply_tag_by_name("nickname", aniter, enditer)
|
||||
|
||||
def _insert_rich_message(self, buddy, msg):
|
||||
msg = Emoticons.get_instance().replace(msg)
|
||||
# Stick in the buddy's nickname
|
||||
if not buf.get_tag_table().lookup("nickname"):
|
||||
buf.create_tag("nickname", weight=pango.WEIGHT_BOLD)
|
||||
aniter = buf.get_end_iter()
|
||||
offset = aniter.get_offset()
|
||||
buf.insert(aniter, " " + buddy.get_name() + ": ")
|
||||
enditer = buf.get_iter_at_offset(offset)
|
||||
buf.apply_tag_by_name("nickname", aniter, enditer)
|
||||
|
||||
def _insert_rich_message(self, buddy, msg):
|
||||
msg = Emoticons.get_instance().replace(msg)
|
||||
|
||||
buf = self._chat_view.get_buffer()
|
||||
self._insert_buddy(buf, buddy)
|
||||
|
||||
serializer = richtext.RichTextSerializer()
|
||||
serializer.deserialize(msg, buf)
|
||||
aniter = buf.get_end_iter()
|
||||
buf.insert(aniter, "\n")
|
||||
|
||||
self._message_inserted()
|
||||
buf = self._chat_view.get_buffer()
|
||||
self._insert_buddy(buf, buddy)
|
||||
|
||||
serializer = richtext.RichTextSerializer()
|
||||
serializer.deserialize(msg, buf)
|
||||
aniter = buf.get_end_iter()
|
||||
buf.insert(aniter, "\n")
|
||||
|
||||
self._message_inserted()
|
||||
|
||||
def _insert_sketch(self, buddy, svgdata):
|
||||
"""Insert a sketch object into the chat buffer."""
|
||||
pbl = gtk.gdk.PixbufLoader("svg")
|
||||
pbl.write(svgdata)
|
||||
pbl.close()
|
||||
pbuf = pbl.get_pixbuf()
|
||||
|
||||
buf = self._chat_view.get_buffer()
|
||||
def _insert_sketch(self, buddy, svgdata):
|
||||
"""Insert a sketch object into the chat buffer."""
|
||||
pbl = gtk.gdk.PixbufLoader("svg")
|
||||
pbl.write(svgdata)
|
||||
pbl.close()
|
||||
pbuf = pbl.get_pixbuf()
|
||||
|
||||
buf = self._chat_view.get_buffer()
|
||||
|
||||
self._insert_buddy(buf, buddy)
|
||||
|
||||
rise = int(pbuf.get_height() / 3) * -1
|
||||
sha_hash = sha.new()
|
||||
sha_hash.update(svgdata)
|
||||
tagname = "sketch-%s" % sha_hash.hexdigest()
|
||||
if not buf.get_tag_table().lookup(tagname):
|
||||
buf.create_tag(tagname, rise=(rise * PANGO_SCALE))
|
||||
self._insert_buddy(buf, buddy)
|
||||
|
||||
rise = int(pbuf.get_height() / 3) * -1
|
||||
sha_hash = sha.new()
|
||||
sha_hash.update(svgdata)
|
||||
tagname = "sketch-%s" % sha_hash.hexdigest()
|
||||
if not buf.get_tag_table().lookup(tagname):
|
||||
buf.create_tag(tagname, rise=(rise * PANGO_SCALE))
|
||||
|
||||
aniter = buf.get_end_iter()
|
||||
buf.insert_pixbuf(aniter, pbuf)
|
||||
aniter.backward_char()
|
||||
enditer = buf.get_end_iter()
|
||||
buf.apply_tag_by_name(tagname, aniter, enditer)
|
||||
aniter = buf.get_end_iter()
|
||||
buf.insert(aniter, "\n")
|
||||
aniter = buf.get_end_iter()
|
||||
buf.insert_pixbuf(aniter, pbuf)
|
||||
aniter.backward_char()
|
||||
enditer = buf.get_end_iter()
|
||||
buf.apply_tag_by_name(tagname, aniter, enditer)
|
||||
aniter = buf.get_end_iter()
|
||||
buf.insert(aniter, "\n")
|
||||
|
||||
self._message_inserted()
|
||||
self._message_inserted()
|
||||
|
||||
def _get_first_richtext_chunk(self, msg):
|
||||
"""Scan the message for the first richtext-tagged chunk and return it."""
|
||||
rt_last = -1
|
||||
tag_rt_start = "<richtext>"
|
||||
tag_rt_end = "</richtext>"
|
||||
rt_first = msg.find(tag_rt_start)
|
||||
length = -1
|
||||
if rt_first >= 0:
|
||||
length = len(msg)
|
||||
rt_last = msg.find(tag_rt_end, rt_first)
|
||||
if rt_first >= 0 and rt_last >= (rt_first + len(tag_rt_start)) and length > 0:
|
||||
return msg[rt_first:rt_last + len(tag_rt_end)]
|
||||
return None
|
||||
def _get_first_richtext_chunk(self, msg):
|
||||
"""Scan the message for the first richtext-tagged chunk and return it."""
|
||||
rt_last = -1
|
||||
tag_rt_start = "<richtext>"
|
||||
tag_rt_end = "</richtext>"
|
||||
rt_first = msg.find(tag_rt_start)
|
||||
length = -1
|
||||
if rt_first >= 0:
|
||||
length = len(msg)
|
||||
rt_last = msg.find(tag_rt_end, rt_first)
|
||||
if rt_first >= 0 and rt_last >= (rt_first + len(tag_rt_start)) and length > 0:
|
||||
return msg[rt_first:rt_last + len(tag_rt_end)]
|
||||
return None
|
||||
|
||||
def _get_first_sketch_chunk(self, msg):
|
||||
"""Scan the message for the first SVG-tagged chunk and return it."""
|
||||
svg_last = -1
|
||||
tag_svg_start = "<svg"
|
||||
tag_svg_end = "</svg>"
|
||||
desc_start = msg.find("<?xml version='1.0' encoding='UTF-8'?>")
|
||||
if desc_start < 0:
|
||||
return None
|
||||
ignore = msg.find("<!DOCTYPE svg")
|
||||
if ignore < 0:
|
||||
return None
|
||||
svg_first = msg.find(tag_svg_start)
|
||||
length = -1
|
||||
if svg_first >= 0:
|
||||
length = len(msg)
|
||||
svg_last = msg.find(tag_svg_end, svg_first)
|
||||
if svg_first >= 0 and svg_last >= (svg_first + len(tag_svg_start)) and length > 0:
|
||||
return msg[desc_start:svg_last + len(tag_svg_end)]
|
||||
return None
|
||||
def _get_first_sketch_chunk(self, msg):
|
||||
"""Scan the message for the first SVG-tagged chunk and return it."""
|
||||
svg_last = -1
|
||||
tag_svg_start = "<svg"
|
||||
tag_svg_end = "</svg>"
|
||||
desc_start = msg.find("<?xml version='1.0' encoding='UTF-8'?>")
|
||||
if desc_start < 0:
|
||||
return None
|
||||
ignore = msg.find("<!DOCTYPE svg")
|
||||
if ignore < 0:
|
||||
return None
|
||||
svg_first = msg.find(tag_svg_start)
|
||||
length = -1
|
||||
if svg_first >= 0:
|
||||
length = len(msg)
|
||||
svg_last = msg.find(tag_svg_end, svg_first)
|
||||
if svg_first >= 0 and svg_last >= (svg_first + len(tag_svg_start)) and length > 0:
|
||||
return msg[desc_start:svg_last + len(tag_svg_end)]
|
||||
return None
|
||||
|
||||
def recv_message(self, message):
|
||||
"""Insert a remote chat message into the chat buffer."""
|
||||
[nick, msg] = Chat.deserialize_message(message)
|
||||
buddy = self._pservice.get_buddy_by_name(nick)
|
||||
if not buddy:
|
||||
logging.error('The buddy %s is not present.' % (nick))
|
||||
return
|
||||
def recv_message(self, message):
|
||||
"""Insert a remote chat message into the chat buffer."""
|
||||
[nick, msg] = Chat.deserialize_message(message)
|
||||
buddy = self._pservice.get_buddy_by_name(nick)
|
||||
if not buddy:
|
||||
logging.error('The buddy %s is not present.' % (nick))
|
||||
return
|
||||
|
||||
# FIXME a better way to compare buddies?
|
||||
owner = self._pservice.get_owner()
|
||||
if buddy.get_name() == owner.get_name():
|
||||
return
|
||||
# FIXME a better way to compare buddies?
|
||||
owner = self._pservice.get_owner()
|
||||
if buddy.get_name() == owner.get_name():
|
||||
return
|
||||
|
||||
chunk = self._get_first_richtext_chunk(msg)
|
||||
if chunk:
|
||||
self._insert_rich_message(buddy, chunk)
|
||||
return
|
||||
chunk = self._get_first_richtext_chunk(msg)
|
||||
if chunk:
|
||||
self._insert_rich_message(buddy, chunk)
|
||||
return
|
||||
|
||||
chunk = self._get_first_sketch_chunk(msg)
|
||||
if chunk:
|
||||
self._insert_sketch(buddy, chunk)
|
||||
return
|
||||
chunk = self._get_first_sketch_chunk(msg)
|
||||
if chunk:
|
||||
self._insert_sketch(buddy, chunk)
|
||||
return
|
||||
|
||||
def set_stream_writer(self, stream_writer):
|
||||
self._stream_writer = stream_writer
|
||||
def set_stream_writer(self, stream_writer):
|
||||
self._stream_writer = stream_writer
|
||||
|
||||
def send_sketch(self, svgdata):
|
||||
if not svgdata or not len(svgdata):
|
||||
return
|
||||
if self._stream_writer:
|
||||
self._stream_writer.write(self.serialize_message(svgdata))
|
||||
owner = self._pservice.get_owner()
|
||||
if owner:
|
||||
self._insert_sketch(owner, svgdata)
|
||||
def send_sketch(self, svgdata):
|
||||
if not svgdata or not len(svgdata):
|
||||
return
|
||||
if self._stream_writer:
|
||||
self._stream_writer.write(self.serialize_message(svgdata))
|
||||
owner = self._pservice.get_owner()
|
||||
if owner:
|
||||
self._insert_sketch(owner, svgdata)
|
||||
|
||||
def send_text_message(self, text):
|
||||
"""Send a chat message and insert it into the local buffer."""
|
||||
if len(text) <= 0:
|
||||
return
|
||||
if self._stream_writer:
|
||||
self._stream_writer.write(self.serialize_message(text))
|
||||
else:
|
||||
logging.warning("Cannot send message, there is no stream writer")
|
||||
owner = self._pservice.get_owner()
|
||||
if owner:
|
||||
self._insert_rich_message(owner, text)
|
||||
def send_text_message(self, text):
|
||||
"""Send a chat message and insert it into the local buffer."""
|
||||
if len(text) <= 0:
|
||||
return
|
||||
if self._stream_writer:
|
||||
self._stream_writer.write(self.serialize_message(text))
|
||||
else:
|
||||
logging.warning("Cannot send message, there is no stream writer")
|
||||
owner = self._pservice.get_owner()
|
||||
if owner:
|
||||
self._insert_rich_message(owner, text)
|
||||
|
||||
def serialize_message(self, message):
|
||||
owner = self._pservice.get_owner()
|
||||
return owner.get_name() + '||' + message
|
||||
|
||||
def deserialize_message(message):
|
||||
return message.split('||', 1)
|
||||
def serialize_message(self, message):
|
||||
owner = self._pservice.get_owner()
|
||||
return owner.get_name() + '||' + message
|
||||
|
||||
def deserialize_message(message):
|
||||
return message.split('||', 1)
|
||||
|
||||
deserialize_message = staticmethod(deserialize_message)
|
||||
deserialize_message = staticmethod(deserialize_message)
|
||||
|
||||
+70
-70
@@ -22,83 +22,83 @@ from sugar.chat.sketchpad.SketchPad import SketchPad
|
||||
import richtext
|
||||
|
||||
class ChatEditor(gtk.HBox):
|
||||
TEXT_MODE = 0
|
||||
SKETCH_MODE = 1
|
||||
TEXT_MODE = 0
|
||||
SKETCH_MODE = 1
|
||||
|
||||
def __init__(self, chat, mode):
|
||||
gtk.HBox.__init__(self, False, 6)
|
||||
def __init__(self, chat, mode):
|
||||
gtk.HBox.__init__(self, False, 6)
|
||||
|
||||
self._chat = chat
|
||||
self._chat = chat
|
||||
|
||||
self._notebook = gtk.Notebook()
|
||||
self._notebook.set_show_tabs(False)
|
||||
self._notebook.set_show_border(False)
|
||||
self._notebook.set_size_request(-1, 70)
|
||||
|
||||
chat_view_sw = gtk.ScrolledWindow()
|
||||
chat_view_sw.set_shadow_type(gtk.SHADOW_IN)
|
||||
chat_view_sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
|
||||
self._text_view = richtext.RichTextView()
|
||||
self._text_view.connect("key-press-event", self.__key_press_event_cb)
|
||||
chat_view_sw.add(self._text_view)
|
||||
self._text_view.show()
|
||||
|
||||
self._notebook.append_page(chat_view_sw)
|
||||
chat_view_sw.show()
|
||||
|
||||
self._sketchpad = SketchPad()
|
||||
self._notebook.append_page(self._sketchpad)
|
||||
self._sketchpad.show()
|
||||
|
||||
self.pack_start(self._notebook)
|
||||
self._notebook.show()
|
||||
|
||||
send_button = gtk.Button(_("Send"))
|
||||
send_button.set_size_request(60, -1)
|
||||
send_button.connect('clicked', self.__send_button_clicked_cb)
|
||||
self.pack_start(send_button, False, True)
|
||||
send_button.show()
|
||||
|
||||
self.set_mode(mode)
|
||||
self._notebook = gtk.Notebook()
|
||||
self._notebook.set_show_tabs(False)
|
||||
self._notebook.set_show_border(False)
|
||||
self._notebook.set_size_request(-1, 70)
|
||||
|
||||
chat_view_sw = gtk.ScrolledWindow()
|
||||
chat_view_sw.set_shadow_type(gtk.SHADOW_IN)
|
||||
chat_view_sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
|
||||
self._text_view = richtext.RichTextView()
|
||||
self._text_view.connect("key-press-event", self.__key_press_event_cb)
|
||||
chat_view_sw.add(self._text_view)
|
||||
self._text_view.show()
|
||||
|
||||
self._notebook.append_page(chat_view_sw)
|
||||
chat_view_sw.show()
|
||||
|
||||
self._sketchpad = SketchPad()
|
||||
self._notebook.append_page(self._sketchpad)
|
||||
self._sketchpad.show()
|
||||
|
||||
self.pack_start(self._notebook)
|
||||
self._notebook.show()
|
||||
|
||||
send_button = gtk.Button(_("Send"))
|
||||
send_button.set_size_request(60, -1)
|
||||
send_button.connect('clicked', self.__send_button_clicked_cb)
|
||||
self.pack_start(send_button, False, True)
|
||||
send_button.show()
|
||||
|
||||
self.set_mode(mode)
|
||||
|
||||
def set_color(self, color):
|
||||
self._sketchpad.set_color(color)
|
||||
|
||||
def get_buffer(self):
|
||||
return self._text_view.get_buffer()
|
||||
def set_color(self, color):
|
||||
self._sketchpad.set_color(color)
|
||||
|
||||
def get_buffer(self):
|
||||
return self._text_view.get_buffer()
|
||||
|
||||
def set_mode(self, mode):
|
||||
self._mode = mode
|
||||
if self._mode == ChatEditor.SKETCH_MODE:
|
||||
self._notebook.set_current_page(1)
|
||||
elif self._mode == ChatEditor.TEXT_MODE:
|
||||
self._notebook.set_current_page(0)
|
||||
def set_mode(self, mode):
|
||||
self._mode = mode
|
||||
if self._mode == ChatEditor.SKETCH_MODE:
|
||||
self._notebook.set_current_page(1)
|
||||
elif self._mode == ChatEditor.TEXT_MODE:
|
||||
self._notebook.set_current_page(0)
|
||||
|
||||
def __send_button_clicked_cb(self, button):
|
||||
self._send()
|
||||
def __send_button_clicked_cb(self, button):
|
||||
self._send()
|
||||
|
||||
def _send(self):
|
||||
if self._mode == ChatEditor.SKETCH_MODE:
|
||||
self._send_sketch()
|
||||
elif self._mode == ChatEditor.TEXT_MODE:
|
||||
self._send_text()
|
||||
def _send(self):
|
||||
if self._mode == ChatEditor.SKETCH_MODE:
|
||||
self._send_sketch()
|
||||
elif self._mode == ChatEditor.TEXT_MODE:
|
||||
self._send_text()
|
||||
|
||||
def _send_sketch(self):
|
||||
self._chat.send_sketch(self._sketchpad.to_svg())
|
||||
self._sketchpad.clear()
|
||||
def _send_sketch(self):
|
||||
self._chat.send_sketch(self._sketchpad.to_svg())
|
||||
self._sketchpad.clear()
|
||||
|
||||
def _send_text(self):
|
||||
buf = self._text_view.get_buffer()
|
||||
text = buf.get_text(buf.get_start_iter(), buf.get_end_iter())
|
||||
if len(text.strip()) > 0:
|
||||
serializer = richtext.RichTextSerializer()
|
||||
text = serializer.serialize(buf)
|
||||
self._chat.send_text_message(text)
|
||||
def _send_text(self):
|
||||
buf = self._text_view.get_buffer()
|
||||
text = buf.get_text(buf.get_start_iter(), buf.get_end_iter())
|
||||
if len(text.strip()) > 0:
|
||||
serializer = richtext.RichTextSerializer()
|
||||
text = serializer.serialize(buf)
|
||||
self._chat.send_text_message(text)
|
||||
|
||||
buf.set_text("")
|
||||
buf.place_cursor(buf.get_start_iter())
|
||||
|
||||
def __key_press_event_cb(self, text_view, event):
|
||||
if event.keyval == gtk.keysyms.Return:
|
||||
self._send()
|
||||
return True
|
||||
buf.set_text("")
|
||||
buf.place_cursor(buf.get_start_iter())
|
||||
|
||||
def __key_press_event_cb(self, text_view, event):
|
||||
if event.keyval == gtk.keysyms.Return:
|
||||
self._send()
|
||||
return True
|
||||
|
||||
+112
-112
@@ -22,129 +22,129 @@ from sugar.chat.sketchpad.Toolbox import Toolbox
|
||||
import richtext
|
||||
|
||||
class ChatToolbar(gtk.HBox):
|
||||
def __init__(self, editor):
|
||||
gtk.HBox.__init__(self, False, 24)
|
||||
|
||||
self._editor = editor
|
||||
self._emt_popup = None
|
||||
def __init__(self, editor):
|
||||
gtk.HBox.__init__(self, False, 24)
|
||||
|
||||
self._editor = editor
|
||||
self._emt_popup = None
|
||||
|
||||
spring = gtk.Label('')
|
||||
self.pack_start(spring, True)
|
||||
spring.show()
|
||||
spring = gtk.Label('')
|
||||
self.pack_start(spring, True)
|
||||
spring.show()
|
||||
|
||||
toolbox = richtext.RichTextToolbox(editor.get_buffer())
|
||||
self.pack_start(toolbox, False)
|
||||
toolbox.show()
|
||||
|
||||
item = gtk.Button()
|
||||
item.unset_flags(gtk.CAN_FOCUS)
|
||||
toolbox = richtext.RichTextToolbox(editor.get_buffer())
|
||||
self.pack_start(toolbox, False)
|
||||
toolbox.show()
|
||||
|
||||
item = gtk.Button()
|
||||
item.unset_flags(gtk.CAN_FOCUS)
|
||||
|
||||
e_hbox = gtk.HBox(False, 6)
|
||||
|
||||
e_image = gtk.Image()
|
||||
e_image.set_from_icon_name('stock_smiley-1', gtk.ICON_SIZE_SMALL_TOOLBAR)
|
||||
e_hbox.pack_start(e_image)
|
||||
e_image.show()
|
||||
|
||||
arrow = gtk.Arrow(gtk.ARROW_DOWN, gtk.SHADOW_NONE)
|
||||
e_hbox.pack_start(arrow)
|
||||
arrow.show()
|
||||
e_hbox = gtk.HBox(False, 6)
|
||||
|
||||
e_image = gtk.Image()
|
||||
e_image.set_from_icon_name('stock_smiley-1', gtk.ICON_SIZE_SMALL_TOOLBAR)
|
||||
e_hbox.pack_start(e_image)
|
||||
e_image.show()
|
||||
|
||||
arrow = gtk.Arrow(gtk.ARROW_DOWN, gtk.SHADOW_NONE)
|
||||
e_hbox.pack_start(arrow)
|
||||
arrow.show()
|
||||
|
||||
item.set_image(e_hbox)
|
||||
item.connect("clicked", self.__emoticons_button_clicked_cb)
|
||||
toolbox.pack_start(item, False)
|
||||
item.show()
|
||||
|
||||
# separator = gtk.SeparatorToolItem()
|
||||
# toolbar.insert(separator, -1)
|
||||
# separator.show()
|
||||
item.set_image(e_hbox)
|
||||
item.connect("clicked", self.__emoticons_button_clicked_cb)
|
||||
toolbox.pack_start(item, False)
|
||||
item.show()
|
||||
|
||||
# separator = gtk.SeparatorToolItem()
|
||||
# toolbar.insert(separator, -1)
|
||||
# separator.show()
|
||||
|
||||
# item = gtk.MenuToolButton(None, "Links")
|
||||
# item.set_menu(gtk.Menu())
|
||||
# item.connect("show-menu", self.__show_link_menu_cb)
|
||||
# toolbar.insert(item, -1)
|
||||
# item.show()
|
||||
# item = gtk.MenuToolButton(None, "Links")
|
||||
# item.set_menu(gtk.Menu())
|
||||
# item.connect("show-menu", self.__show_link_menu_cb)
|
||||
# toolbar.insert(item, -1)
|
||||
# item.show()
|
||||
|
||||
toolbox = Toolbox()
|
||||
toolbox.connect('color-selected', self._color_selected)
|
||||
self.pack_start(toolbox, False)
|
||||
toolbox.show()
|
||||
toolbox = Toolbox()
|
||||
toolbox.connect('color-selected', self._color_selected)
|
||||
self.pack_start(toolbox, False)
|
||||
toolbox.show()
|
||||
|
||||
spring = gtk.Label('')
|
||||
self.pack_start(spring, True)
|
||||
spring.show()
|
||||
spring = gtk.Label('')
|
||||
self.pack_start(spring, True)
|
||||
spring.show()
|
||||
|
||||
def _color_selected(self, toolbox, color):
|
||||
self._editor.set_color(color)
|
||||
def _color_selected(self, toolbox, color):
|
||||
self._editor.set_color(color)
|
||||
|
||||
def __link_activate_cb(self, item, link):
|
||||
buf = self._editor.get_buffer()
|
||||
buf.append_link(link['title'], link['address'])
|
||||
def __link_activate_cb(self, item, link):
|
||||
buf = self._editor.get_buffer()
|
||||
buf.append_link(link['title'], link['address'])
|
||||
|
||||
def __show_link_menu_cb(self, button):
|
||||
menu = gtk.Menu()
|
||||
|
||||
links = self.__get_browser_shell().get_links()
|
||||
def __show_link_menu_cb(self, button):
|
||||
menu = gtk.Menu()
|
||||
|
||||
links = self.__get_browser_shell().get_links()
|
||||
|
||||
for link in links:
|
||||
item = gtk.MenuItem(link['title'], False)
|
||||
item.connect("activate", self.__link_activate_cb, link)
|
||||
menu.append(item)
|
||||
item.show()
|
||||
|
||||
button.set_menu(menu)
|
||||
for link in links:
|
||||
item = gtk.MenuItem(link['title'], False)
|
||||
item.connect("activate", self.__link_activate_cb, link)
|
||||
menu.append(item)
|
||||
item.show()
|
||||
|
||||
button.set_menu(menu)
|
||||
|
||||
def _create_emoticons_popup(self):
|
||||
model = gtk.ListStore(gtk.gdk.Pixbuf, str)
|
||||
|
||||
for name in Emoticons.get_instance().get_all():
|
||||
icon_theme = gtk.icon_theme_get_default()
|
||||
try:
|
||||
pixbuf = icon_theme.load_icon(name, 16, 0)
|
||||
model.append([pixbuf, name])
|
||||
except gobject.GError:
|
||||
pass
|
||||
def _create_emoticons_popup(self):
|
||||
model = gtk.ListStore(gtk.gdk.Pixbuf, str)
|
||||
|
||||
for name in Emoticons.get_instance().get_all():
|
||||
icon_theme = gtk.icon_theme_get_default()
|
||||
try:
|
||||
pixbuf = icon_theme.load_icon(name, 16, 0)
|
||||
model.append([pixbuf, name])
|
||||
except gobject.GError:
|
||||
pass
|
||||
|
||||
icon_view = gtk.IconView(model)
|
||||
icon_view.connect('selection-changed', self.__emoticon_selection_changed_cb)
|
||||
icon_view.set_pixbuf_column(0)
|
||||
icon_view.set_selection_mode(gtk.SELECTION_SINGLE)
|
||||
|
||||
frame = gtk.Frame()
|
||||
frame.set_shadow_type(gtk.SHADOW_ETCHED_IN)
|
||||
frame.add(icon_view)
|
||||
icon_view.show()
|
||||
|
||||
window = gtk.Window(gtk.WINDOW_POPUP)
|
||||
window.add(frame)
|
||||
frame.show()
|
||||
|
||||
return window
|
||||
|
||||
def __emoticon_selection_changed_cb(self, icon_view):
|
||||
items = icon_view.get_selected_items()
|
||||
if items:
|
||||
model = icon_view.get_model()
|
||||
icon_name = model[items[0]][1]
|
||||
self._editor.get_buffer().append_icon(icon_name)
|
||||
self._emt_popup.hide()
|
||||
|
||||
def __emoticons_button_clicked_cb(self, button):
|
||||
# FIXME grabs...
|
||||
if not self._emt_popup:
|
||||
self._emt_popup = self._create_emoticons_popup()
|
||||
icon_view = gtk.IconView(model)
|
||||
icon_view.connect('selection-changed', self.__emoticon_selection_changed_cb)
|
||||
icon_view.set_pixbuf_column(0)
|
||||
icon_view.set_selection_mode(gtk.SELECTION_SINGLE)
|
||||
|
||||
frame = gtk.Frame()
|
||||
frame.set_shadow_type(gtk.SHADOW_ETCHED_IN)
|
||||
frame.add(icon_view)
|
||||
icon_view.show()
|
||||
|
||||
window = gtk.Window(gtk.WINDOW_POPUP)
|
||||
window.add(frame)
|
||||
frame.show()
|
||||
|
||||
return window
|
||||
|
||||
def __emoticon_selection_changed_cb(self, icon_view):
|
||||
items = icon_view.get_selected_items()
|
||||
if items:
|
||||
model = icon_view.get_model()
|
||||
icon_name = model[items[0]][1]
|
||||
self._editor.get_buffer().append_icon(icon_name)
|
||||
self._emt_popup.hide()
|
||||
|
||||
def __emoticons_button_clicked_cb(self, button):
|
||||
# FIXME grabs...
|
||||
if not self._emt_popup:
|
||||
self._emt_popup = self._create_emoticons_popup()
|
||||
|
||||
if self._emt_popup.get_property('visible'):
|
||||
self._emt_popup.hide()
|
||||
else:
|
||||
width = 180
|
||||
height = 130
|
||||
|
||||
self._emt_popup.set_default_size(width, height)
|
||||
|
||||
[x, y] = button.window.get_origin()
|
||||
x += button.allocation.x
|
||||
y += button.allocation.y - height
|
||||
self._emt_popup.move(x, y)
|
||||
|
||||
self._emt_popup.show()
|
||||
if self._emt_popup.get_property('visible'):
|
||||
self._emt_popup.hide()
|
||||
else:
|
||||
width = 180
|
||||
height = 130
|
||||
|
||||
self._emt_popup.set_default_size(width, height)
|
||||
|
||||
[x, y] = button.window.get_origin()
|
||||
x += button.allocation.x
|
||||
y += button.allocation.y - height
|
||||
self._emt_popup.move(x, y)
|
||||
|
||||
self._emt_popup.show()
|
||||
|
||||
+60
-60
@@ -15,70 +15,70 @@
|
||||
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
# Boston, MA 02111-1307, USA.
|
||||
|
||||
emoticons_table = [ \
|
||||
[ 'stock_smiley-10', [ ':P', ':p' ] ], \
|
||||
[ 'stock_smiley-19', None ], \
|
||||
[ 'stock_smiley-2', None ], \
|
||||
[ 'stock_smiley-11', None ], \
|
||||
[ 'stock_smiley-1', [ ':)' ] ], \
|
||||
[ 'stock_smiley-3', None ], \
|
||||
[ 'stock_smiley-12', None ], \
|
||||
[ 'stock_smiley-20', None ], \
|
||||
[ 'stock_smiley-4', [ ':(' ] ], \
|
||||
[ 'stock_smiley-13', None ], \
|
||||
[ 'stock_smiley-21', None ], \
|
||||
[ 'stock_smiley-5', None ], \
|
||||
[ 'stock_smiley-14', None ], \
|
||||
[ 'stock_smiley-22', None ], \
|
||||
[ 'stock_smiley-6', None ], \
|
||||
[ 'stock_smiley-15', None ], \
|
||||
[ 'stock_smiley-23', None ], \
|
||||
[ 'stock_smiley-7', None ], \
|
||||
[ 'stock_smiley-16', None ], \
|
||||
[ 'stock_smiley-24', None ], \
|
||||
[ 'stock_smiley-8', None ], \
|
||||
[ 'stock_smiley-17', None ], \
|
||||
[ 'stock_smiley-25', None ], \
|
||||
[ 'stock_smiley-9', None ], \
|
||||
[ 'stock_smiley-18', None ], \
|
||||
[ 'stock_smiley-26', None ], \
|
||||
emoticons_table = [ \
|
||||
[ 'stock_smiley-10', [ ':P', ':p' ] ], \
|
||||
[ 'stock_smiley-19', None ], \
|
||||
[ 'stock_smiley-2', None ], \
|
||||
[ 'stock_smiley-11', None ], \
|
||||
[ 'stock_smiley-1', [ ':)' ] ], \
|
||||
[ 'stock_smiley-3', None ], \
|
||||
[ 'stock_smiley-12', None ], \
|
||||
[ 'stock_smiley-20', None ], \
|
||||
[ 'stock_smiley-4', [ ':(' ] ], \
|
||||
[ 'stock_smiley-13', None ], \
|
||||
[ 'stock_smiley-21', None ], \
|
||||
[ 'stock_smiley-5', None ], \
|
||||
[ 'stock_smiley-14', None ], \
|
||||
[ 'stock_smiley-22', None ], \
|
||||
[ 'stock_smiley-6', None ], \
|
||||
[ 'stock_smiley-15', None ], \
|
||||
[ 'stock_smiley-23', None ], \
|
||||
[ 'stock_smiley-7', None ], \
|
||||
[ 'stock_smiley-16', None ], \
|
||||
[ 'stock_smiley-24', None ], \
|
||||
[ 'stock_smiley-8', None ], \
|
||||
[ 'stock_smiley-17', None ], \
|
||||
[ 'stock_smiley-25', None ], \
|
||||
[ 'stock_smiley-9', None ], \
|
||||
[ 'stock_smiley-18', None ], \
|
||||
[ 'stock_smiley-26', None ], \
|
||||
]
|
||||
|
||||
class Emoticons:
|
||||
instance = None
|
||||
instance = None
|
||||
|
||||
def get_instance():
|
||||
if not Emoticons.instance:
|
||||
Emoticons.instance = Emoticons()
|
||||
return Emoticons.instance
|
||||
def get_instance():
|
||||
if not Emoticons.instance:
|
||||
Emoticons.instance = Emoticons()
|
||||
return Emoticons.instance
|
||||
|
||||
get_instance = staticmethod(get_instance)
|
||||
get_instance = staticmethod(get_instance)
|
||||
|
||||
def __init__(self):
|
||||
self._table = {}
|
||||
def __init__(self):
|
||||
self._table = {}
|
||||
|
||||
for emoticon in emoticons_table:
|
||||
[ name, text_emts ] = emoticon
|
||||
self.add(name, text_emts)
|
||||
|
||||
def add(self, icon_name, text=None):
|
||||
self._table[icon_name] = text
|
||||
|
||||
def get_all(self):
|
||||
return self._table.keys()
|
||||
|
||||
"""Replace emoticons text with the icon name.
|
||||
|
||||
Parse the provided text to find emoticons (in
|
||||
textual form) and replace them with their xml
|
||||
representation in the form:
|
||||
<icon name="$EMOTICON_ICON_NAME"/>
|
||||
"""
|
||||
def replace(self, text):
|
||||
for icon_name in self._table.keys():
|
||||
text_emts = self._table[icon_name]
|
||||
if text_emts:
|
||||
for emoticon_text in text_emts:
|
||||
xml = '<icon name="' + icon_name + '"/>'
|
||||
text = text.replace(emoticon_text, xml)
|
||||
return text
|
||||
for emoticon in emoticons_table:
|
||||
[ name, text_emts ] = emoticon
|
||||
self.add(name, text_emts)
|
||||
|
||||
def add(self, icon_name, text=None):
|
||||
self._table[icon_name] = text
|
||||
|
||||
def get_all(self):
|
||||
return self._table.keys()
|
||||
|
||||
"""Replace emoticons text with the icon name.
|
||||
|
||||
Parse the provided text to find emoticons (in
|
||||
textual form) and replace them with their xml
|
||||
representation in the form:
|
||||
<icon name="$EMOTICON_ICON_NAME"/>
|
||||
"""
|
||||
def replace(self, text):
|
||||
for icon_name in self._table.keys():
|
||||
text_emts = self._table[icon_name]
|
||||
if text_emts:
|
||||
for emoticon_text in text_emts:
|
||||
xml = '<icon name="' + icon_name + '"/>'
|
||||
text = text.replace(emoticon_text, xml)
|
||||
return text
|
||||
|
||||
+10
-10
@@ -23,15 +23,15 @@ from sugar.presence.PresenceService import PresenceService
|
||||
import sugar.env
|
||||
|
||||
class GroupChat(Chat):
|
||||
def __init__(self):
|
||||
Chat.__init__(self)
|
||||
self._group_stream = None
|
||||
def __init__(self):
|
||||
Chat.__init__(self)
|
||||
self._group_stream = None
|
||||
|
||||
def _setup_stream(self, service):
|
||||
self._group_stream = Stream.new_from_service(service)
|
||||
self._group_stream.set_data_listener(self._group_recv_message)
|
||||
self._stream_writer = self._group_stream.new_writer()
|
||||
def _setup_stream(self, service):
|
||||
self._group_stream = Stream.new_from_service(service)
|
||||
self._group_stream.set_data_listener(self._group_recv_message)
|
||||
self._stream_writer = self._group_stream.new_writer()
|
||||
|
||||
def _group_recv_message(self, address, msg):
|
||||
logging.debug('Group chat received from %s message %s' % (address, msg))
|
||||
self.recv_message(msg)
|
||||
def _group_recv_message(self, address, msg):
|
||||
logging.debug('Group chat received from %s message %s' % (address, msg))
|
||||
self.recv_message(msg)
|
||||
|
||||
+366
-366
@@ -21,431 +21,431 @@ import pango
|
||||
import xml.sax
|
||||
|
||||
class RichTextView(gtk.TextView):
|
||||
|
||||
__gsignals__ = {
|
||||
'link-clicked': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_STRING]))
|
||||
}
|
||||
|
||||
__gsignals__ = {
|
||||
'link-clicked': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_STRING]))
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
gtk.TextView.__init__(self, RichTextBuffer())
|
||||
self.connect("motion-notify-event", self.__motion_notify_cb)
|
||||
self.connect("button-press-event", self.__button_press_cb)
|
||||
self.__hover_link = False
|
||||
def __init__(self):
|
||||
gtk.TextView.__init__(self, RichTextBuffer())
|
||||
self.connect("motion-notify-event", self.__motion_notify_cb)
|
||||
self.connect("button-press-event", self.__button_press_cb)
|
||||
self.__hover_link = False
|
||||
|
||||
def _set_hover_link(self, hover_link):
|
||||
if hover_link != self.__hover_link:
|
||||
self.__hover_link = hover_link
|
||||
display = self.get_toplevel().get_display()
|
||||
child_window = self.get_window(gtk.TEXT_WINDOW_TEXT)
|
||||
|
||||
if hover_link:
|
||||
cursor = gtk.gdk.Cursor(display, gtk.gdk.HAND2)
|
||||
else:
|
||||
cursor = gtk.gdk.Cursor(display, gtk.gdk.XTERM)
|
||||
|
||||
child_window.set_cursor(cursor)
|
||||
gtk.gdk.flush()
|
||||
|
||||
def __iter_is_link(self, it):
|
||||
item = self.get_buffer().get_tag_table().lookup("link")
|
||||
if item:
|
||||
return it.has_tag(item)
|
||||
return False
|
||||
def _set_hover_link(self, hover_link):
|
||||
if hover_link != self.__hover_link:
|
||||
self.__hover_link = hover_link
|
||||
display = self.get_toplevel().get_display()
|
||||
child_window = self.get_window(gtk.TEXT_WINDOW_TEXT)
|
||||
|
||||
if hover_link:
|
||||
cursor = gtk.gdk.Cursor(display, gtk.gdk.HAND2)
|
||||
else:
|
||||
cursor = gtk.gdk.Cursor(display, gtk.gdk.XTERM)
|
||||
|
||||
child_window.set_cursor(cursor)
|
||||
gtk.gdk.flush()
|
||||
|
||||
def __iter_is_link(self, it):
|
||||
item = self.get_buffer().get_tag_table().lookup("link")
|
||||
if item:
|
||||
return it.has_tag(item)
|
||||
return False
|
||||
|
||||
def __get_event_iter(self, event):
|
||||
return self.get_iter_at_location(int(event.x), int(event.y))
|
||||
def __get_event_iter(self, event):
|
||||
return self.get_iter_at_location(int(event.x), int(event.y))
|
||||
|
||||
def __motion_notify_cb(self, widget, event):
|
||||
if event.is_hint:
|
||||
event.window.get_pointer();
|
||||
|
||||
it = self.__get_event_iter(event)
|
||||
if it:
|
||||
hover_link = self.__iter_is_link(it)
|
||||
else:
|
||||
hover_link = False
|
||||
def __motion_notify_cb(self, widget, event):
|
||||
if event.is_hint:
|
||||
event.window.get_pointer();
|
||||
|
||||
it = self.__get_event_iter(event)
|
||||
if it:
|
||||
hover_link = self.__iter_is_link(it)
|
||||
else:
|
||||
hover_link = False
|
||||
|
||||
self._set_hover_link(hover_link)
|
||||
|
||||
def __button_press_cb(self, widget, event):
|
||||
it = self.__get_event_iter(event)
|
||||
if it and self.__iter_is_link(it):
|
||||
buf = self.get_buffer()
|
||||
address_tag = buf.get_tag_table().lookup("object-id")
|
||||
self._set_hover_link(hover_link)
|
||||
|
||||
def __button_press_cb(self, widget, event):
|
||||
it = self.__get_event_iter(event)
|
||||
if it and self.__iter_is_link(it):
|
||||
buf = self.get_buffer()
|
||||
address_tag = buf.get_tag_table().lookup("object-id")
|
||||
|
||||
address_end = it.copy()
|
||||
address_end.backward_to_tag_toggle(address_tag)
|
||||
|
||||
address_start = address_end.copy()
|
||||
address_start.backward_to_tag_toggle(address_tag)
|
||||
|
||||
address = buf.get_text(address_start, address_end)
|
||||
self.emit("link-clicked", address)
|
||||
address_end = it.copy()
|
||||
address_end.backward_to_tag_toggle(address_tag)
|
||||
|
||||
address_start = address_end.copy()
|
||||
address_start.backward_to_tag_toggle(address_tag)
|
||||
|
||||
address = buf.get_text(address_start, address_end)
|
||||
self.emit("link-clicked", address)
|
||||
|
||||
class RichTextBuffer(gtk.TextBuffer):
|
||||
def __init__(self):
|
||||
gtk.TextBuffer.__init__(self)
|
||||
def __init__(self):
|
||||
gtk.TextBuffer.__init__(self)
|
||||
|
||||
self.connect_after("insert-text", self.__insert_text_cb)
|
||||
|
||||
self.__create_tags()
|
||||
self.active_tags = []
|
||||
self.connect_after("insert-text", self.__insert_text_cb)
|
||||
|
||||
self.__create_tags()
|
||||
self.active_tags = []
|
||||
|
||||
def append_link(self, title, address):
|
||||
it = self.get_iter_at_mark(self.get_insert())
|
||||
self.insert_with_tags_by_name(it, address, "link", "object-id")
|
||||
self.insert_with_tags_by_name(it, title, "link")
|
||||
def append_link(self, title, address):
|
||||
it = self.get_iter_at_mark(self.get_insert())
|
||||
self.insert_with_tags_by_name(it, address, "link", "object-id")
|
||||
self.insert_with_tags_by_name(it, title, "link")
|
||||
|
||||
def append_icon(self, name, it = None):
|
||||
if not it:
|
||||
it = self.get_iter_at_mark(self.get_insert())
|
||||
def append_icon(self, name, it = None):
|
||||
if not it:
|
||||
it = self.get_iter_at_mark(self.get_insert())
|
||||
|
||||
self.insert_with_tags_by_name(it, name, "icon", "object-id")
|
||||
icon_theme = gtk.icon_theme_get_default()
|
||||
try:
|
||||
pixbuf = icon_theme.load_icon(name, 16, 0)
|
||||
self.insert_pixbuf(it, pixbuf)
|
||||
except gobject.GError:
|
||||
pass
|
||||
self.insert_with_tags_by_name(it, name, "icon", "object-id")
|
||||
icon_theme = gtk.icon_theme_get_default()
|
||||
try:
|
||||
pixbuf = icon_theme.load_icon(name, 16, 0)
|
||||
self.insert_pixbuf(it, pixbuf)
|
||||
except gobject.GError:
|
||||
pass
|
||||
|
||||
def apply_tag(self, tag_name):
|
||||
self.active_tags.append(tag_name)
|
||||
|
||||
bounds = self.get_selection_bounds()
|
||||
if bounds:
|
||||
[start, end] = bounds
|
||||
self.apply_tag_by_name(tag_name, start, end)
|
||||
def apply_tag(self, tag_name):
|
||||
self.active_tags.append(tag_name)
|
||||
|
||||
bounds = self.get_selection_bounds()
|
||||
if bounds:
|
||||
[start, end] = bounds
|
||||
self.apply_tag_by_name(tag_name, start, end)
|
||||
|
||||
def unapply_tag(self, tag_name):
|
||||
self.active_tags.remove(tag_name)
|
||||
def unapply_tag(self, tag_name):
|
||||
self.active_tags.remove(tag_name)
|
||||
|
||||
bounds = self.get_selection_bounds()
|
||||
if bounds:
|
||||
[start, end] = bounds
|
||||
self.remove_tag_by_name(tag_name, start, end)
|
||||
|
||||
def __create_tags(self):
|
||||
tag = self.create_tag("icon")
|
||||
bounds = self.get_selection_bounds()
|
||||
if bounds:
|
||||
[start, end] = bounds
|
||||
self.remove_tag_by_name(tag_name, start, end)
|
||||
|
||||
def __create_tags(self):
|
||||
tag = self.create_tag("icon")
|
||||
|
||||
tag = self.create_tag("link")
|
||||
tag.set_property("underline", pango.UNDERLINE_SINGLE)
|
||||
tag.set_property("foreground", "#0000FF")
|
||||
tag = self.create_tag("link")
|
||||
tag.set_property("underline", pango.UNDERLINE_SINGLE)
|
||||
tag.set_property("foreground", "#0000FF")
|
||||
|
||||
tag = self.create_tag("object-id")
|
||||
tag.set_property("invisible", True)
|
||||
tag = self.create_tag("object-id")
|
||||
tag.set_property("invisible", True)
|
||||
|
||||
tag = self.create_tag("bold")
|
||||
tag.set_property("weight", pango.WEIGHT_BOLD)
|
||||
|
||||
tag = self.create_tag("italic")
|
||||
tag.set_property("style", pango.STYLE_ITALIC)
|
||||
tag = self.create_tag("bold")
|
||||
tag.set_property("weight", pango.WEIGHT_BOLD)
|
||||
|
||||
tag = self.create_tag("italic")
|
||||
tag.set_property("style", pango.STYLE_ITALIC)
|
||||
|
||||
tag = self.create_tag("font-size-xx-small")
|
||||
tag.set_property("scale", pango.SCALE_XX_SMALL)
|
||||
tag = self.create_tag("font-size-xx-small")
|
||||
tag.set_property("scale", pango.SCALE_XX_SMALL)
|
||||
|
||||
tag = self.create_tag("font-size-x-small")
|
||||
tag.set_property("scale", pango.SCALE_X_SMALL)
|
||||
tag = self.create_tag("font-size-x-small")
|
||||
tag.set_property("scale", pango.SCALE_X_SMALL)
|
||||
|
||||
tag = self.create_tag("font-size-small")
|
||||
tag.set_property("scale", pango.SCALE_SMALL)
|
||||
tag = self.create_tag("font-size-small")
|
||||
tag.set_property("scale", pango.SCALE_SMALL)
|
||||
|
||||
tag = self.create_tag("font-size-large")
|
||||
tag.set_property("scale", pango.SCALE_LARGE)
|
||||
tag = self.create_tag("font-size-large")
|
||||
tag.set_property("scale", pango.SCALE_LARGE)
|
||||
|
||||
tag = self.create_tag("font-size-x-large")
|
||||
tag.set_property("scale", pango.SCALE_X_LARGE)
|
||||
tag = self.create_tag("font-size-x-large")
|
||||
tag.set_property("scale", pango.SCALE_X_LARGE)
|
||||
|
||||
tag = self.create_tag("font-size-xx-large")
|
||||
tag.set_property("scale", pango.SCALE_XX_LARGE)
|
||||
|
||||
def __insert_text_cb(self, widget, pos, text, length):
|
||||
for tag in self.active_tags:
|
||||
pos_end = pos.copy()
|
||||
pos_end.backward_chars(length)
|
||||
self.apply_tag_by_name(tag, pos, pos_end)
|
||||
|
||||
tag = self.create_tag("font-size-xx-large")
|
||||
tag.set_property("scale", pango.SCALE_XX_LARGE)
|
||||
|
||||
def __insert_text_cb(self, widget, pos, text, length):
|
||||
for tag in self.active_tags:
|
||||
pos_end = pos.copy()
|
||||
pos_end.backward_chars(length)
|
||||
self.apply_tag_by_name(tag, pos, pos_end)
|
||||
|
||||
class RichTextToolbox(gtk.HBox):
|
||||
def __init__(self, buf):
|
||||
gtk.HBox.__init__(self, False, 6)
|
||||
|
||||
self.buf = buf
|
||||
|
||||
self._font_size = "normal"
|
||||
self._font_scales = [ "xx-small", "x-small", "small", \
|
||||
"normal", \
|
||||
"large", "x-large", "xx-large" ]
|
||||
|
||||
image = gtk.Image()
|
||||
image.set_from_stock(gtk.STOCK_BOLD, gtk.ICON_SIZE_SMALL_TOOLBAR)
|
||||
def __init__(self, buf):
|
||||
gtk.HBox.__init__(self, False, 6)
|
||||
|
||||
self.buf = buf
|
||||
|
||||
self._font_size = "normal"
|
||||
self._font_scales = [ "xx-small", "x-small", "small", \
|
||||
"normal", \
|
||||
"large", "x-large", "xx-large" ]
|
||||
|
||||
image = gtk.Image()
|
||||
image.set_from_stock(gtk.STOCK_BOLD, gtk.ICON_SIZE_SMALL_TOOLBAR)
|
||||
|
||||
item = gtk.ToggleButton()
|
||||
item.set_image(image)
|
||||
item.connect("toggled", self.__toggle_style_cb, "bold")
|
||||
item.unset_flags(gtk.CAN_FOCUS)
|
||||
self.pack_start(item, False)
|
||||
item.show()
|
||||
item = gtk.ToggleButton()
|
||||
item.set_image(image)
|
||||
item.connect("toggled", self.__toggle_style_cb, "bold")
|
||||
item.unset_flags(gtk.CAN_FOCUS)
|
||||
self.pack_start(item, False)
|
||||
item.show()
|
||||
|
||||
image.show()
|
||||
image.show()
|
||||
|
||||
image = gtk.Image()
|
||||
image.set_from_stock(gtk.STOCK_ITALIC, gtk.ICON_SIZE_SMALL_TOOLBAR)
|
||||
image = gtk.Image()
|
||||
image.set_from_stock(gtk.STOCK_ITALIC, gtk.ICON_SIZE_SMALL_TOOLBAR)
|
||||
|
||||
item = gtk.ToggleButton()
|
||||
item.set_image(image)
|
||||
item.unset_flags(gtk.CAN_FOCUS)
|
||||
item.connect("toggled", self.__toggle_style_cb, "italic")
|
||||
self.pack_start(item, False)
|
||||
item.show()
|
||||
item = gtk.ToggleButton()
|
||||
item.set_image(image)
|
||||
item.unset_flags(gtk.CAN_FOCUS)
|
||||
item.connect("toggled", self.__toggle_style_cb, "italic")
|
||||
self.pack_start(item, False)
|
||||
item.show()
|
||||
|
||||
image = gtk.Image()
|
||||
image.set_from_stock(gtk.STOCK_GO_UP, gtk.ICON_SIZE_SMALL_TOOLBAR)
|
||||
image = gtk.Image()
|
||||
image.set_from_stock(gtk.STOCK_GO_UP, gtk.ICON_SIZE_SMALL_TOOLBAR)
|
||||
|
||||
self._font_size_up = gtk.Button()
|
||||
self._font_size_up.set_image(image)
|
||||
self._font_size_up.unset_flags(gtk.CAN_FOCUS)
|
||||
self._font_size_up.connect("clicked", self.__font_size_up_cb)
|
||||
self.pack_start(self._font_size_up, False)
|
||||
self._font_size_up.show()
|
||||
|
||||
image.show()
|
||||
self._font_size_up = gtk.Button()
|
||||
self._font_size_up.set_image(image)
|
||||
self._font_size_up.unset_flags(gtk.CAN_FOCUS)
|
||||
self._font_size_up.connect("clicked", self.__font_size_up_cb)
|
||||
self.pack_start(self._font_size_up, False)
|
||||
self._font_size_up.show()
|
||||
|
||||
image.show()
|
||||
|
||||
image = gtk.Image()
|
||||
image.set_from_stock(gtk.STOCK_GO_DOWN, gtk.ICON_SIZE_SMALL_TOOLBAR)
|
||||
image = gtk.Image()
|
||||
image.set_from_stock(gtk.STOCK_GO_DOWN, gtk.ICON_SIZE_SMALL_TOOLBAR)
|
||||
|
||||
self._font_size_down = gtk.Button()
|
||||
self._font_size_down.set_image(image)
|
||||
self._font_size_down.unset_flags(gtk.CAN_FOCUS)
|
||||
self._font_size_down.connect("clicked", self.__font_size_down_cb)
|
||||
self.pack_start(self._font_size_down, False)
|
||||
self._font_size_down.show()
|
||||
|
||||
image.show()
|
||||
|
||||
def _get_font_size_index(self):
|
||||
return self._font_scales.index(self._font_size);
|
||||
|
||||
def __toggle_style_cb(self, toggle, tag_name):
|
||||
if toggle.get_active():
|
||||
self.buf.apply_tag(tag_name)
|
||||
else:
|
||||
self.buf.unapply_tag(tag_name)
|
||||
self._font_size_down = gtk.Button()
|
||||
self._font_size_down.set_image(image)
|
||||
self._font_size_down.unset_flags(gtk.CAN_FOCUS)
|
||||
self._font_size_down.connect("clicked", self.__font_size_down_cb)
|
||||
self.pack_start(self._font_size_down, False)
|
||||
self._font_size_down.show()
|
||||
|
||||
image.show()
|
||||
|
||||
def _get_font_size_index(self):
|
||||
return self._font_scales.index(self._font_size);
|
||||
|
||||
def __toggle_style_cb(self, toggle, tag_name):
|
||||
if toggle.get_active():
|
||||
self.buf.apply_tag(tag_name)
|
||||
else:
|
||||
self.buf.unapply_tag(tag_name)
|
||||
|
||||
def _set_font_size(self, font_size):
|
||||
if self._font_size != "normal":
|
||||
self.buf.unapply_tag("font-size-" + self._font_size)
|
||||
if font_size != "normal":
|
||||
self.buf.apply_tag("font-size-" + font_size)
|
||||
|
||||
self._font_size = font_size
|
||||
|
||||
can_up = self._get_font_size_index() < len(self._font_scales) - 1
|
||||
can_down = self._get_font_size_index() > 0
|
||||
self._font_size_up.set_sensitive(can_up)
|
||||
self._font_size_down.set_sensitive(can_down)
|
||||
def _set_font_size(self, font_size):
|
||||
if self._font_size != "normal":
|
||||
self.buf.unapply_tag("font-size-" + self._font_size)
|
||||
if font_size != "normal":
|
||||
self.buf.apply_tag("font-size-" + font_size)
|
||||
|
||||
self._font_size = font_size
|
||||
|
||||
can_up = self._get_font_size_index() < len(self._font_scales) - 1
|
||||
can_down = self._get_font_size_index() > 0
|
||||
self._font_size_up.set_sensitive(can_up)
|
||||
self._font_size_down.set_sensitive(can_down)
|
||||
|
||||
def __font_size_up_cb(self, button):
|
||||
index = self._get_font_size_index()
|
||||
if index + 1 < len(self._font_scales):
|
||||
self._set_font_size(self._font_scales[index + 1])
|
||||
def __font_size_up_cb(self, button):
|
||||
index = self._get_font_size_index()
|
||||
if index + 1 < len(self._font_scales):
|
||||
self._set_font_size(self._font_scales[index + 1])
|
||||
|
||||
def __font_size_down_cb(self, button):
|
||||
index = self._get_font_size_index()
|
||||
if index > 0:
|
||||
self._set_font_size(self._font_scales[index - 1])
|
||||
|
||||
def __font_size_down_cb(self, button):
|
||||
index = self._get_font_size_index()
|
||||
if index > 0:
|
||||
self._set_font_size(self._font_scales[index - 1])
|
||||
|
||||
class RichTextHandler(xml.sax.handler.ContentHandler):
|
||||
def __init__(self, serializer, buf):
|
||||
xml.sax.handler.ContentHandler.__init__(self)
|
||||
self.buf = buf
|
||||
self.serializer = serializer
|
||||
self.tags = []
|
||||
self._in_richtext = False
|
||||
self._done = False
|
||||
def __init__(self, serializer, buf):
|
||||
xml.sax.handler.ContentHandler.__init__(self)
|
||||
self.buf = buf
|
||||
self.serializer = serializer
|
||||
self.tags = []
|
||||
self._in_richtext = False
|
||||
self._done = False
|
||||
|
||||
def startElement(self, name, attrs):
|
||||
# Look for, and only start parsing after 'richtext'
|
||||
if not self._in_richtext and name == "richtext":
|
||||
self._in_richtext = True
|
||||
if not self._in_richtext:
|
||||
return
|
||||
def startElement(self, name, attrs):
|
||||
# Look for, and only start parsing after 'richtext'
|
||||
if not self._in_richtext and name == "richtext":
|
||||
self._in_richtext = True
|
||||
if not self._in_richtext:
|
||||
return
|
||||
|
||||
if name != "richtext":
|
||||
tag = self.serializer.deserialize_element(name, attrs)
|
||||
self.tags.append(tag)
|
||||
if name == "link":
|
||||
self.href = attrs['href']
|
||||
elif name == "icon":
|
||||
self.buf.append_icon(attrs['name'], self.buf.get_end_iter())
|
||||
if name != "richtext":
|
||||
tag = self.serializer.deserialize_element(name, attrs)
|
||||
self.tags.append(tag)
|
||||
if name == "link":
|
||||
self.href = attrs['href']
|
||||
elif name == "icon":
|
||||
self.buf.append_icon(attrs['name'], self.buf.get_end_iter())
|
||||
|
||||
def characters(self, data):
|
||||
start_it = it = self.buf.get_end_iter()
|
||||
mark = self.buf.create_mark(None, start_it, True)
|
||||
self.buf.insert(it, data)
|
||||
start_it = self.buf.get_iter_at_mark(mark)
|
||||
def characters(self, data):
|
||||
start_it = it = self.buf.get_end_iter()
|
||||
mark = self.buf.create_mark(None, start_it, True)
|
||||
self.buf.insert(it, data)
|
||||
start_it = self.buf.get_iter_at_mark(mark)
|
||||
|
||||
for tag in self.tags:
|
||||
self.buf.apply_tag_by_name(tag, start_it, it)
|
||||
if tag == "link":
|
||||
self.buf.insert_with_tags_by_name(start_it, self.href,
|
||||
"link", "object-id")
|
||||
for tag in self.tags:
|
||||
self.buf.apply_tag_by_name(tag, start_it, it)
|
||||
if tag == "link":
|
||||
self.buf.insert_with_tags_by_name(start_it, self.href,
|
||||
"link", "object-id")
|
||||
|
||||
def endElement(self, name):
|
||||
if not self._done and self._in_richtext:
|
||||
if name != "richtext":
|
||||
self.tags.pop()
|
||||
if name == "richtext":
|
||||
self._done = True
|
||||
self._in_richtext = False
|
||||
def endElement(self, name):
|
||||
if not self._done and self._in_richtext:
|
||||
if name != "richtext":
|
||||
self.tags.pop()
|
||||
if name == "richtext":
|
||||
self._done = True
|
||||
self._in_richtext = False
|
||||
|
||||
class RichTextSerializer:
|
||||
def __init__(self):
|
||||
self._open_tags = []
|
||||
def __init__(self):
|
||||
self._open_tags = []
|
||||
|
||||
def deserialize_element(self, el_name, attributes):
|
||||
if el_name == "bold":
|
||||
return "bold"
|
||||
elif el_name == "italic":
|
||||
return "italic"
|
||||
elif el_name == "font":
|
||||
return "font-size-" + attributes["size"]
|
||||
elif el_name == "link":
|
||||
return "link"
|
||||
elif el_name == "icon":
|
||||
return "icon"
|
||||
else:
|
||||
return None
|
||||
def deserialize_element(self, el_name, attributes):
|
||||
if el_name == "bold":
|
||||
return "bold"
|
||||
elif el_name == "italic":
|
||||
return "italic"
|
||||
elif el_name == "font":
|
||||
return "font-size-" + attributes["size"]
|
||||
elif el_name == "link":
|
||||
return "link"
|
||||
elif el_name == "icon":
|
||||
return "icon"
|
||||
else:
|
||||
return None
|
||||
|
||||
def _parse_object_id(self, it):
|
||||
object_id_tag = self.buf.get_tag_table().lookup("object-id")
|
||||
end = it.copy()
|
||||
end.forward_to_tag_toggle(object_id_tag)
|
||||
return self.buf.get_text(it, end)
|
||||
def _parse_object_id(self, it):
|
||||
object_id_tag = self.buf.get_tag_table().lookup("object-id")
|
||||
end = it.copy()
|
||||
end.forward_to_tag_toggle(object_id_tag)
|
||||
return self.buf.get_text(it, end)
|
||||
|
||||
def serialize_tag_start(self, tag, it):
|
||||
name = tag.get_property("name")
|
||||
if name == "bold":
|
||||
return "<bold>"
|
||||
elif name == "italic":
|
||||
return "<italic>"
|
||||
elif name == "link":
|
||||
address = self._parse_object_id(it)
|
||||
return "<link " + "href=\"" + address + "\">"
|
||||
elif name == "icon":
|
||||
name = self._parse_object_id(it)
|
||||
return "<icon " + "name=\"" + name + "\"/>"
|
||||
elif name == "object-id":
|
||||
return ""
|
||||
elif name.startswith("font-size-"):
|
||||
tag_name = name.replace("font-size-", "", 1)
|
||||
return "<font size=\"" + tag_name + "\">"
|
||||
else:
|
||||
return "<unknown>"
|
||||
def serialize_tag_start(self, tag, it):
|
||||
name = tag.get_property("name")
|
||||
if name == "bold":
|
||||
return "<bold>"
|
||||
elif name == "italic":
|
||||
return "<italic>"
|
||||
elif name == "link":
|
||||
address = self._parse_object_id(it)
|
||||
return "<link " + "href=\"" + address + "\">"
|
||||
elif name == "icon":
|
||||
name = self._parse_object_id(it)
|
||||
return "<icon " + "name=\"" + name + "\"/>"
|
||||
elif name == "object-id":
|
||||
return ""
|
||||
elif name.startswith("font-size-"):
|
||||
tag_name = name.replace("font-size-", "", 1)
|
||||
return "<font size=\"" + tag_name + "\">"
|
||||
else:
|
||||
return "<unknown>"
|
||||
|
||||
def serialize_tag_end(self, tag):
|
||||
name = tag.get_property("name")
|
||||
if name == "bold":
|
||||
return "</bold>"
|
||||
elif name == "italic":
|
||||
return "</italic>"
|
||||
elif name == "link":
|
||||
return "</link>"
|
||||
elif name == "icon":
|
||||
return ""
|
||||
elif name == "object-id":
|
||||
return ""
|
||||
elif name.startswith("font-size-"):
|
||||
return "</font>"
|
||||
else:
|
||||
return "</unknown>"
|
||||
|
||||
def serialize(self, buf):
|
||||
self.buf = buf
|
||||
|
||||
res = "<richtext>"
|
||||
def serialize_tag_end(self, tag):
|
||||
name = tag.get_property("name")
|
||||
if name == "bold":
|
||||
return "</bold>"
|
||||
elif name == "italic":
|
||||
return "</italic>"
|
||||
elif name == "link":
|
||||
return "</link>"
|
||||
elif name == "icon":
|
||||
return ""
|
||||
elif name == "object-id":
|
||||
return ""
|
||||
elif name.startswith("font-size-"):
|
||||
return "</font>"
|
||||
else:
|
||||
return "</unknown>"
|
||||
|
||||
def serialize(self, buf):
|
||||
self.buf = buf
|
||||
|
||||
res = "<richtext>"
|
||||
|
||||
next_it = buf.get_start_iter()
|
||||
while not next_it.is_end():
|
||||
it = next_it.copy()
|
||||
if not next_it.forward_to_tag_toggle(None):
|
||||
next_it = buf.get_end_iter()
|
||||
next_it = buf.get_start_iter()
|
||||
while not next_it.is_end():
|
||||
it = next_it.copy()
|
||||
if not next_it.forward_to_tag_toggle(None):
|
||||
next_it = buf.get_end_iter()
|
||||
|
||||
tags_to_reopen = []
|
||||
tags_to_reopen = []
|
||||
|
||||
for tag in it.get_toggled_tags(False):
|
||||
while 1:
|
||||
open_tag = self._open_tags.pop()
|
||||
res += self.serialize_tag_end(tag)
|
||||
if open_tag == tag:
|
||||
break
|
||||
tags_to_reopen.append(open_tag)
|
||||
|
||||
for tag in tags_to_reopen:
|
||||
self._open_tags.append(tag)
|
||||
res += self.serialize_tag_start(tag, it)
|
||||
|
||||
for tag in it.get_toggled_tags(True):
|
||||
self._open_tags.append(tag)
|
||||
res += self.serialize_tag_start(tag, it)
|
||||
|
||||
res += buf.get_text(it, next_it, False)
|
||||
for tag in it.get_toggled_tags(False):
|
||||
while 1:
|
||||
open_tag = self._open_tags.pop()
|
||||
res += self.serialize_tag_end(tag)
|
||||
if open_tag == tag:
|
||||
break
|
||||
tags_to_reopen.append(open_tag)
|
||||
|
||||
for tag in tags_to_reopen:
|
||||
self._open_tags.append(tag)
|
||||
res += self.serialize_tag_start(tag, it)
|
||||
|
||||
for tag in it.get_toggled_tags(True):
|
||||
self._open_tags.append(tag)
|
||||
res += self.serialize_tag_start(tag, it)
|
||||
|
||||
res += buf.get_text(it, next_it, False)
|
||||
|
||||
if next_it.is_end():
|
||||
self._open_tags.reverse()
|
||||
for tag in self._open_tags:
|
||||
res += self.serialize_tag_end(tag)
|
||||
|
||||
res += "</richtext>"
|
||||
|
||||
return res
|
||||
if next_it.is_end():
|
||||
self._open_tags.reverse()
|
||||
for tag in self._open_tags:
|
||||
res += self.serialize_tag_end(tag)
|
||||
|
||||
res += "</richtext>"
|
||||
|
||||
return res
|
||||
|
||||
def deserialize(self, xml_string, buf):
|
||||
parser = xml.sax.make_parser()
|
||||
handler = RichTextHandler(self, buf)
|
||||
parser.setContentHandler(handler)
|
||||
parser.feed(xml_string)
|
||||
parser.close()
|
||||
def deserialize(self, xml_string, buf):
|
||||
parser = xml.sax.make_parser()
|
||||
handler = RichTextHandler(self, buf)
|
||||
parser.setContentHandler(handler)
|
||||
parser.feed(xml_string)
|
||||
parser.close()
|
||||
|
||||
def test_quit(w, rb):
|
||||
print RichTextSerializer().serialize(rb)
|
||||
gtk.main_quit()
|
||||
|
||||
print RichTextSerializer().serialize(rb)
|
||||
gtk.main_quit()
|
||||
|
||||
def link_clicked(v, address):
|
||||
print "Link clicked " + address
|
||||
print "Link clicked " + address
|
||||
|
||||
if __name__ == "__main__":
|
||||
window = gtk.Window()
|
||||
window.set_default_size(400, 300)
|
||||
|
||||
vbox = gtk.VBox()
|
||||
|
||||
view = RichTextView()
|
||||
view.connect("link-clicked", link_clicked)
|
||||
vbox.pack_start(view)
|
||||
view.show()
|
||||
window = gtk.Window()
|
||||
window.set_default_size(400, 300)
|
||||
|
||||
vbox = gtk.VBox()
|
||||
|
||||
view = RichTextView()
|
||||
view.connect("link-clicked", link_clicked)
|
||||
vbox.pack_start(view)
|
||||
view.show()
|
||||
|
||||
rich_buf = view.get_buffer()
|
||||
|
||||
test_xml = "<richtext>"
|
||||
rich_buf = view.get_buffer()
|
||||
|
||||
test_xml = "<richtext>"
|
||||
|
||||
test_xml += "<bold><italic>Test</italic>one</bold>\n"
|
||||
test_xml += "<bold><italic>Test two</italic></bold>"
|
||||
test_xml += "<font size=\"xx-small\">Test three</font>"
|
||||
test_xml += "<link href=\"http://www.gnome.org\">Test link</link>"
|
||||
test_xml += "<icon name=\"stock_help-chat\"/>"
|
||||
test_xml += "</richtext>"
|
||||
test_xml += "<bold><italic>Test</italic>one</bold>\n"
|
||||
test_xml += "<bold><italic>Test two</italic></bold>"
|
||||
test_xml += "<font size=\"xx-small\">Test three</font>"
|
||||
test_xml += "<link href=\"http://www.gnome.org\">Test link</link>"
|
||||
test_xml += "<icon name=\"stock_help-chat\"/>"
|
||||
test_xml += "</richtext>"
|
||||
|
||||
RichTextSerializer().deserialize(test_xml, rich_buf)
|
||||
|
||||
toolbar = RichTextToolbar(rich_buf)
|
||||
vbox.pack_start(toolbar, False)
|
||||
toolbar.show()
|
||||
|
||||
window.add(vbox)
|
||||
vbox.show()
|
||||
|
||||
window.show()
|
||||
|
||||
window.connect("destroy", test_quit, rich_buf)
|
||||
RichTextSerializer().deserialize(test_xml, rich_buf)
|
||||
|
||||
toolbar = RichTextToolbar(rich_buf)
|
||||
vbox.pack_start(toolbar, False)
|
||||
toolbar.show()
|
||||
|
||||
window.add(vbox)
|
||||
vbox.show()
|
||||
|
||||
window.show()
|
||||
|
||||
window.connect("destroy", test_quit, rich_buf)
|
||||
|
||||
gtk.main()
|
||||
gtk.main()
|
||||
|
||||
@@ -18,37 +18,37 @@
|
||||
from SVGdraw import path
|
||||
|
||||
class Sketch:
|
||||
def __init__(self, rgb):
|
||||
self._points = []
|
||||
self._rgb = (float(rgb[0]), float(rgb[1]), float(rgb[2]))
|
||||
|
||||
def add_point(self, x, y):
|
||||
self._points.append((x, y))
|
||||
def __init__(self, rgb):
|
||||
self._points = []
|
||||
self._rgb = (float(rgb[0]), float(rgb[1]), float(rgb[2]))
|
||||
|
||||
def add_point(self, x, y):
|
||||
self._points.append((x, y))
|
||||
|
||||
def get_points(self):
|
||||
return self._points
|
||||
|
||||
def draw(self, ctx):
|
||||
start = True
|
||||
for (x, y) in self._points:
|
||||
if start:
|
||||
ctx.move_to(x, y)
|
||||
start = False
|
||||
else:
|
||||
ctx.line_to(x, y)
|
||||
ctx.set_source_rgb(self._rgb[0], self._rgb[1], self._rgb[2])
|
||||
ctx.stroke()
|
||||
|
||||
def draw_to_svg(self):
|
||||
i = 0
|
||||
for (x, y) in self._points:
|
||||
coords = str(x) + ' ' + str(y) + ' '
|
||||
if i == 0:
|
||||
path_data = 'M ' + coords
|
||||
elif i == 1:
|
||||
path_data += 'L ' + coords
|
||||
else:
|
||||
path_data += coords
|
||||
i += 1
|
||||
color = "#%02X%02X%02X" % (255 * self._rgb[0], 255 * self._rgb[1], 255 * self._rgb[2])
|
||||
return path(path_data, fill = 'none', stroke = color)
|
||||
def get_points(self):
|
||||
return self._points
|
||||
|
||||
def draw(self, ctx):
|
||||
start = True
|
||||
for (x, y) in self._points:
|
||||
if start:
|
||||
ctx.move_to(x, y)
|
||||
start = False
|
||||
else:
|
||||
ctx.line_to(x, y)
|
||||
ctx.set_source_rgb(self._rgb[0], self._rgb[1], self._rgb[2])
|
||||
ctx.stroke()
|
||||
|
||||
def draw_to_svg(self):
|
||||
i = 0
|
||||
for (x, y) in self._points:
|
||||
coords = str(x) + ' ' + str(y) + ' '
|
||||
if i == 0:
|
||||
path_data = 'M ' + coords
|
||||
elif i == 1:
|
||||
path_data += 'L ' + coords
|
||||
else:
|
||||
path_data += coords
|
||||
i += 1
|
||||
color = "#%02X%02X%02X" % (255 * self._rgb[0], 255 * self._rgb[1], 255 * self._rgb[2])
|
||||
return path(path_data, fill = 'none', stroke = color)
|
||||
|
||||
@@ -23,101 +23,101 @@ from SVGdraw import drawing
|
||||
from SVGdraw import svg
|
||||
|
||||
class SketchPad(gtk.DrawingArea):
|
||||
__gsignals__ = {
|
||||
'new-user-sketch':(gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT]))
|
||||
}
|
||||
__gsignals__ = {
|
||||
'new-user-sketch':(gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT]))
|
||||
}
|
||||
|
||||
def __init__(self, bgcolor=(0.6, 1, 0.4)):
|
||||
gtk.DrawingArea.__init__(self)
|
||||
def __init__(self, bgcolor=(0.6, 1, 0.4)):
|
||||
gtk.DrawingArea.__init__(self)
|
||||
|
||||
self._active_sketch = None
|
||||
self._rgb = (0.0, 0.0, 0.0)
|
||||
self._bgcolor = bgcolor
|
||||
self._sketches = []
|
||||
self._active_sketch = None
|
||||
self._rgb = (0.0, 0.0, 0.0)
|
||||
self._bgcolor = bgcolor
|
||||
self._sketches = []
|
||||
|
||||
self.add_events(gtk.gdk.BUTTON_PRESS_MASK |
|
||||
gtk.gdk.BUTTON_RELEASE_MASK |
|
||||
gtk.gdk.BUTTON1_MOTION_MASK)
|
||||
self.connect("button-press-event", self._button_press_cb)
|
||||
self.connect("button-release-event", self._button_release_cb)
|
||||
self.connect("motion-notify-event", self._motion_notify_cb)
|
||||
self.connect('expose_event', self.expose)
|
||||
|
||||
def clear(self):
|
||||
self._sketches = []
|
||||
self.window.invalidate_rect(None, False)
|
||||
self.add_events(gtk.gdk.BUTTON_PRESS_MASK |
|
||||
gtk.gdk.BUTTON_RELEASE_MASK |
|
||||
gtk.gdk.BUTTON1_MOTION_MASK)
|
||||
self.connect("button-press-event", self._button_press_cb)
|
||||
self.connect("button-release-event", self._button_release_cb)
|
||||
self.connect("motion-notify-event", self._motion_notify_cb)
|
||||
self.connect('expose_event', self.expose)
|
||||
|
||||
def clear(self):
|
||||
self._sketches = []
|
||||
self.window.invalidate_rect(None, False)
|
||||
|
||||
def expose(self, widget, event):
|
||||
"""Draw the background of the sketchpad."""
|
||||
rect = self.get_allocation()
|
||||
ctx = widget.window.cairo_create()
|
||||
|
||||
ctx.set_source_rgb(self._bgcolor[0], self._bgcolor[1], self._bgcolor[2])
|
||||
ctx.rectangle(0, 0, rect.width, rect.height)
|
||||
ctx.fill_preserve()
|
||||
|
||||
ctx.set_source_rgb(0, 0.3, 0.2)
|
||||
ctx.stroke()
|
||||
|
||||
for sketch in self._sketches:
|
||||
sketch.draw(ctx)
|
||||
|
||||
return False
|
||||
def expose(self, widget, event):
|
||||
"""Draw the background of the sketchpad."""
|
||||
rect = self.get_allocation()
|
||||
ctx = widget.window.cairo_create()
|
||||
|
||||
ctx.set_source_rgb(self._bgcolor[0], self._bgcolor[1], self._bgcolor[2])
|
||||
ctx.rectangle(0, 0, rect.width, rect.height)
|
||||
ctx.fill_preserve()
|
||||
|
||||
ctx.set_source_rgb(0, 0.3, 0.2)
|
||||
ctx.stroke()
|
||||
|
||||
for sketch in self._sketches:
|
||||
sketch.draw(ctx)
|
||||
|
||||
return False
|
||||
|
||||
def set_color(self, color):
|
||||
"""Sets the current drawing color of the sketchpad.
|
||||
color agument should be 3-item tuple of rgb values between 0 and 1."""
|
||||
self._rgb = color
|
||||
def set_color(self, color):
|
||||
"""Sets the current drawing color of the sketchpad.
|
||||
color agument should be 3-item tuple of rgb values between 0 and 1."""
|
||||
self._rgb = color
|
||||
|
||||
def add_sketch(self, sketch):
|
||||
"""Add a sketch to the the pad. Mostly for subclasses and clients."""
|
||||
self._sketches.append(sketch)
|
||||
self.window.invalidate_rect(None, False)
|
||||
def add_sketch(self, sketch):
|
||||
"""Add a sketch to the the pad. Mostly for subclasses and clients."""
|
||||
self._sketches.append(sketch)
|
||||
self.window.invalidate_rect(None, False)
|
||||
|
||||
def add_point(self, event):
|
||||
if not self._active_sketch:
|
||||
return
|
||||
self._active_sketch.add_point(event.x, event.y)
|
||||
self.window.invalidate_rect(None, False)
|
||||
|
||||
def _button_press_cb(self, widget, event):
|
||||
self._active_sketch = Sketch(self._rgb)
|
||||
self._sketches.append(self._active_sketch)
|
||||
self.add_point(event)
|
||||
|
||||
def _button_release_cb(self, widget, event):
|
||||
self.add_point(event)
|
||||
self.emit('new-user-sketch', self._active_sketch)
|
||||
self._active_sketch = None
|
||||
|
||||
def _motion_notify_cb(self, widget, event):
|
||||
self.add_point(event)
|
||||
|
||||
def to_svg(self):
|
||||
"""Return a string containing an SVG representation of this sketch."""
|
||||
d = drawing()
|
||||
s = svg()
|
||||
for sketch in self._sketches:
|
||||
s.addElement(sketch.draw_to_svg())
|
||||
d.setSVG(s)
|
||||
return d.toXml()
|
||||
def add_point(self, event):
|
||||
if not self._active_sketch:
|
||||
return
|
||||
self._active_sketch.add_point(event.x, event.y)
|
||||
self.window.invalidate_rect(None, False)
|
||||
|
||||
def _button_press_cb(self, widget, event):
|
||||
self._active_sketch = Sketch(self._rgb)
|
||||
self._sketches.append(self._active_sketch)
|
||||
self.add_point(event)
|
||||
|
||||
def _button_release_cb(self, widget, event):
|
||||
self.add_point(event)
|
||||
self.emit('new-user-sketch', self._active_sketch)
|
||||
self._active_sketch = None
|
||||
|
||||
def _motion_notify_cb(self, widget, event):
|
||||
self.add_point(event)
|
||||
|
||||
def to_svg(self):
|
||||
"""Return a string containing an SVG representation of this sketch."""
|
||||
d = drawing()
|
||||
s = svg()
|
||||
for sketch in self._sketches:
|
||||
s.addElement(sketch.draw_to_svg())
|
||||
d.setSVG(s)
|
||||
return d.toXml()
|
||||
|
||||
def test_quit(w, skpad):
|
||||
print skpad.to_svg()
|
||||
gtk.main_quit()
|
||||
print skpad.to_svg()
|
||||
gtk.main_quit()
|
||||
|
||||
if __name__ == "__main__":
|
||||
window = gtk.Window()
|
||||
window.set_default_size(400, 300)
|
||||
window.connect("destroy", lambda w: gtk.main_quit())
|
||||
window = gtk.Window()
|
||||
window.set_default_size(400, 300)
|
||||
window.connect("destroy", lambda w: gtk.main_quit())
|
||||
|
||||
sketchpad = SketchPad()
|
||||
window.add(sketchpad)
|
||||
sketchpad.show()
|
||||
|
||||
window.show()
|
||||
|
||||
window.connect("destroy", test_quit, sketchpad)
|
||||
sketchpad = SketchPad()
|
||||
window.add(sketchpad)
|
||||
sketchpad.show()
|
||||
|
||||
window.show()
|
||||
|
||||
window.connect("destroy", test_quit, sketchpad)
|
||||
|
||||
gtk.main()
|
||||
gtk.main()
|
||||
|
||||
@@ -19,59 +19,59 @@ import gtk
|
||||
import gobject
|
||||
|
||||
class ColorButton(gtk.RadioButton):
|
||||
def __init__(self, group, rgb):
|
||||
gtk.RadioButton.__init__(self, group)
|
||||
|
||||
self._rgb = rgb
|
||||
|
||||
self.set_mode(False)
|
||||
self.set_relief(gtk.RELIEF_NONE)
|
||||
|
||||
drawing_area = gtk.DrawingArea()
|
||||
drawing_area.set_size_request(24, 24)
|
||||
drawing_area.connect_after('expose_event', self.expose)
|
||||
self.add(drawing_area)
|
||||
drawing_area.show()
|
||||
def __init__(self, group, rgb):
|
||||
gtk.RadioButton.__init__(self, group)
|
||||
|
||||
self._rgb = rgb
|
||||
|
||||
self.set_mode(False)
|
||||
self.set_relief(gtk.RELIEF_NONE)
|
||||
|
||||
drawing_area = gtk.DrawingArea()
|
||||
drawing_area.set_size_request(24, 24)
|
||||
drawing_area.connect_after('expose_event', self.expose)
|
||||
self.add(drawing_area)
|
||||
drawing_area.show()
|
||||
|
||||
def color(self):
|
||||
return self._rgb
|
||||
def color(self):
|
||||
return self._rgb
|
||||
|
||||
def expose(self, widget, event):
|
||||
rect = widget.get_allocation()
|
||||
ctx = widget.window.cairo_create()
|
||||
def expose(self, widget, event):
|
||||
rect = widget.get_allocation()
|
||||
ctx = widget.window.cairo_create()
|
||||
|
||||
ctx.set_source_rgb(self._rgb[0], self._rgb[1] , self._rgb[2])
|
||||
ctx.rectangle(4, 4, rect.width - 8, rect.height - 8)
|
||||
ctx.fill()
|
||||
|
||||
return False
|
||||
ctx.set_source_rgb(self._rgb[0], self._rgb[1] , self._rgb[2])
|
||||
ctx.rectangle(4, 4, rect.width - 8, rect.height - 8)
|
||||
ctx.fill()
|
||||
|
||||
return False
|
||||
|
||||
class Toolbox(gtk.HBox):
|
||||
__gsignals__ = {
|
||||
'color-selected': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT]))
|
||||
}
|
||||
__gsignals__ = {
|
||||
'color-selected': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT]))
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
gtk.HBox.__init__(self, False, 6)
|
||||
|
||||
self._colors_group = None
|
||||
|
||||
self._add_color([0, 0, 0])
|
||||
self._add_color([1, 0, 0])
|
||||
self._add_color([0, 1, 0])
|
||||
self._add_color([0, 0, 1])
|
||||
|
||||
def _add_color(self, rgb):
|
||||
color = ColorButton(self._colors_group, rgb)
|
||||
color.unset_flags(gtk.CAN_FOCUS)
|
||||
color.connect('clicked', self.__color_clicked_cb, rgb)
|
||||
self.pack_start(color, False)
|
||||
def __init__(self):
|
||||
gtk.HBox.__init__(self, False, 6)
|
||||
|
||||
self._colors_group = None
|
||||
|
||||
self._add_color([0, 0, 0])
|
||||
self._add_color([1, 0, 0])
|
||||
self._add_color([0, 1, 0])
|
||||
self._add_color([0, 0, 1])
|
||||
|
||||
def _add_color(self, rgb):
|
||||
color = ColorButton(self._colors_group, rgb)
|
||||
color.unset_flags(gtk.CAN_FOCUS)
|
||||
color.connect('clicked', self.__color_clicked_cb, rgb)
|
||||
self.pack_start(color, False)
|
||||
|
||||
if self._colors_group == None:
|
||||
self._colors_group = color
|
||||
if self._colors_group == None:
|
||||
self._colors_group = color
|
||||
|
||||
color.show()
|
||||
color.show()
|
||||
|
||||
def __color_clicked_cb(self, button, rgb):
|
||||
self.emit("color-selected", button.color())
|
||||
def __color_clicked_cb(self, button, rgb):
|
||||
self.emit("color-selected", button.color())
|
||||
|
||||
@@ -7,69 +7,69 @@ DBUS_PATH = "/org/laptop/Clipboard"
|
||||
|
||||
class ClipboardService(gobject.GObject):
|
||||
|
||||
__gsignals__ = {
|
||||
'object-added': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([str, str, str])),
|
||||
'object-deleted': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([str])),
|
||||
'object-state-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([str, int])),
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
gobject.GObject.__init__(self)
|
||||
|
||||
self._dbus_service = None
|
||||
bus = dbus.SessionBus()
|
||||
bus.add_signal_receiver(self._name_owner_changed_cb,
|
||||
signal_name="NameOwnerChanged",
|
||||
dbus_interface="org.freedesktop.DBus")
|
||||
# Try to register to ClipboardService, if we fail, we'll try later.
|
||||
try:
|
||||
self._connect_clipboard_signals()
|
||||
except dbus.DBusException, exception:
|
||||
pass
|
||||
|
||||
def _connect_clipboard_signals(self):
|
||||
bus = dbus.SessionBus()
|
||||
proxy_obj = bus.get_object(DBUS_SERVICE, DBUS_PATH)
|
||||
self._dbus_service = dbus.Interface(proxy_obj, DBUS_SERVICE)
|
||||
self._dbus_service.connect_to_signal('object_added',
|
||||
self._object_added_cb)
|
||||
self._dbus_service.connect_to_signal('object_deleted',
|
||||
self._object_deleted_cb)
|
||||
self._dbus_service.connect_to_signal('object_state_changed',
|
||||
self._object_state_changed_cb)
|
||||
__gsignals__ = {
|
||||
'object-added': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([str, str, str])),
|
||||
'object-deleted': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([str])),
|
||||
'object-state-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([str, int])),
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
gobject.GObject.__init__(self)
|
||||
|
||||
self._dbus_service = None
|
||||
bus = dbus.SessionBus()
|
||||
bus.add_signal_receiver(self._name_owner_changed_cb,
|
||||
signal_name="NameOwnerChanged",
|
||||
dbus_interface="org.freedesktop.DBus")
|
||||
# Try to register to ClipboardService, if we fail, we'll try later.
|
||||
try:
|
||||
self._connect_clipboard_signals()
|
||||
except dbus.DBusException, exception:
|
||||
pass
|
||||
|
||||
def _connect_clipboard_signals(self):
|
||||
bus = dbus.SessionBus()
|
||||
proxy_obj = bus.get_object(DBUS_SERVICE, DBUS_PATH)
|
||||
self._dbus_service = dbus.Interface(proxy_obj, DBUS_SERVICE)
|
||||
self._dbus_service.connect_to_signal('object_added',
|
||||
self._object_added_cb)
|
||||
self._dbus_service.connect_to_signal('object_deleted',
|
||||
self._object_deleted_cb)
|
||||
self._dbus_service.connect_to_signal('object_state_changed',
|
||||
self._object_state_changed_cb)
|
||||
|
||||
def _name_owner_changed_cb(self, name, old, new):
|
||||
if name != DBUS_SERVICE:
|
||||
return
|
||||
|
||||
if (not old and not len(old)) and (new and len(new)):
|
||||
# ClipboardService started up
|
||||
self._connect_clipboard_signals()
|
||||
|
||||
def _object_added_cb(self, name, mimeType, fileName):
|
||||
self.emit('object-added', name, mimeType, fileName)
|
||||
def _name_owner_changed_cb(self, name, old, new):
|
||||
if name != DBUS_SERVICE:
|
||||
return
|
||||
|
||||
if (not old and not len(old)) and (new and len(new)):
|
||||
# ClipboardService started up
|
||||
self._connect_clipboard_signals()
|
||||
|
||||
def _object_added_cb(self, name, mimeType, fileName):
|
||||
self.emit('object-added', name, mimeType, fileName)
|
||||
|
||||
def _object_deleted_cb(self, fileName):
|
||||
self.emit('object-deleted', fileName)
|
||||
def _object_deleted_cb(self, fileName):
|
||||
self.emit('object-deleted', fileName)
|
||||
|
||||
def _object_state_changed_cb(self, fileName, percent):
|
||||
self.emit('object-state-changed', fileName, percent)
|
||||
|
||||
def add_object(self, name, mimeType, fileName):
|
||||
self._dbus_service.add_object(name, mimeType, fileName)
|
||||
def _object_state_changed_cb(self, fileName, percent):
|
||||
self.emit('object-state-changed', fileName, percent)
|
||||
|
||||
def add_object(self, name, mimeType, fileName):
|
||||
self._dbus_service.add_object(name, mimeType, fileName)
|
||||
|
||||
def delete_object(self, fileName):
|
||||
self._dbus_service.delete_object(fileName)
|
||||
|
||||
def set_object_state(self, fileName, percent):
|
||||
self._dbus_service.set_object_state(fileName, percent)
|
||||
def delete_object(self, fileName):
|
||||
self._dbus_service.delete_object(fileName)
|
||||
|
||||
def set_object_state(self, fileName, percent):
|
||||
self._dbus_service.set_object_state(fileName, percent)
|
||||
|
||||
_clipboard_service = None
|
||||
def get_instance():
|
||||
global _clipboard_service
|
||||
if not _clipboard_service:
|
||||
_clipboard_service = ClipboardService()
|
||||
return _clipboard_service
|
||||
global _clipboard_service
|
||||
if not _clipboard_service:
|
||||
_clipboard_service = ClipboardService()
|
||||
return _clipboard_service
|
||||
|
||||
+84
-84
@@ -24,108 +24,108 @@ import gobject
|
||||
from sugar import env
|
||||
|
||||
def get_display_number():
|
||||
"""Find a free display number trying to connect to 6000+ ports"""
|
||||
retries = 20
|
||||
display_number = 1
|
||||
display_is_free = False
|
||||
"""Find a free display number trying to connect to 6000+ ports"""
|
||||
retries = 20
|
||||
display_number = 1
|
||||
display_is_free = False
|
||||
|
||||
while not display_is_free and retries > 0:
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
try:
|
||||
s.connect(('127.0.0.1', 6000 + display_number))
|
||||
s.close()
|
||||
while not display_is_free and retries > 0:
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
try:
|
||||
s.connect(('127.0.0.1', 6000 + display_number))
|
||||
s.close()
|
||||
|
||||
display_number += 1
|
||||
retries -= 1
|
||||
except:
|
||||
display_is_free = True
|
||||
display_number += 1
|
||||
retries -= 1
|
||||
except:
|
||||
display_is_free = True
|
||||
|
||||
if display_is_free:
|
||||
return display_number
|
||||
else:
|
||||
logging.error('Cannot find a free display.')
|
||||
sys.exit(0)
|
||||
if display_is_free:
|
||||
return display_number
|
||||
else:
|
||||
logging.error('Cannot find a free display.')
|
||||
sys.exit(0)
|
||||
|
||||
class Process:
|
||||
"""Object representing one of the session processes"""
|
||||
"""Object representing one of the session processes"""
|
||||
|
||||
def __init__(self, command):
|
||||
self._command = command
|
||||
|
||||
def get_name(self):
|
||||
return self._command
|
||||
|
||||
def start(self, standard_output=False):
|
||||
args = self._command.split()
|
||||
flags = gobject.SPAWN_SEARCH_PATH
|
||||
result = gobject.spawn_async(args, flags=flags,
|
||||
standard_output=standard_output)
|
||||
self.pid = result[0]
|
||||
self._stdout = result[2]
|
||||
def __init__(self, command):
|
||||
self._command = command
|
||||
|
||||
def get_name(self):
|
||||
return self._command
|
||||
|
||||
def start(self, standard_output=False):
|
||||
args = self._command.split()
|
||||
flags = gobject.SPAWN_SEARCH_PATH
|
||||
result = gobject.spawn_async(args, flags=flags,
|
||||
standard_output=standard_output)
|
||||
self.pid = result[0]
|
||||
self._stdout = result[2]
|
||||
|
||||
class MatchboxProcess(Process):
|
||||
def __init__(self):
|
||||
kbd_config = os.path.join(env.get_data_dir(), 'kbdconfig')
|
||||
options = '-kbdconfig %s ' % kbd_config
|
||||
def __init__(self):
|
||||
kbd_config = os.path.join(env.get_data_dir(), 'kbdconfig')
|
||||
options = '-kbdconfig %s ' % kbd_config
|
||||
|
||||
options += '-use_titlebar no '
|
||||
options += '-theme olpc '
|
||||
options += '-use_titlebar no '
|
||||
options += '-theme olpc '
|
||||
|
||||
command = 'matchbox-window-manager %s ' % options
|
||||
Process.__init__(self, command)
|
||||
|
||||
def get_name(self):
|
||||
return 'Matchbox'
|
||||
command = 'matchbox-window-manager %s ' % options
|
||||
Process.__init__(self, command)
|
||||
|
||||
def get_name(self):
|
||||
return 'Matchbox'
|
||||
|
||||
class XephyrProcess(Process):
|
||||
def __init__(self, fullscreen):
|
||||
self._display = get_display_number()
|
||||
cmd = 'Xephyr :%d -ac ' % (self._display)
|
||||
if fullscreen:
|
||||
cmd += '-fullscreen '
|
||||
else:
|
||||
cmd += '-screen 800x600 '
|
||||
Process.__init__(self, cmd)
|
||||
|
||||
def get_name(self):
|
||||
return 'Xephyr'
|
||||
def __init__(self, fullscreen):
|
||||
self._display = get_display_number()
|
||||
cmd = 'Xephyr :%d -ac ' % (self._display)
|
||||
if fullscreen:
|
||||
cmd += '-fullscreen '
|
||||
else:
|
||||
cmd += '-screen 800x600 '
|
||||
Process.__init__(self, cmd)
|
||||
|
||||
def get_name(self):
|
||||
return 'Xephyr'
|
||||
|
||||
def start(self):
|
||||
Process.start(self)
|
||||
os.environ['DISPLAY'] = ":%d" % (self._display)
|
||||
os.environ['SUGAR_XEPHYR_PID'] = '%d' % self.pid
|
||||
def start(self):
|
||||
Process.start(self)
|
||||
os.environ['DISPLAY'] = ":%d" % (self._display)
|
||||
os.environ['SUGAR_XEPHYR_PID'] = '%d' % self.pid
|
||||
|
||||
|
||||
class XnestProcess(Process):
|
||||
def __init__(self):
|
||||
self._display = get_display_number()
|
||||
cmd = 'Xnest :%d -ac -geometry 800x600' % (self._display)
|
||||
Process.__init__(self, cmd)
|
||||
|
||||
def get_name(self):
|
||||
return 'Xnest'
|
||||
def __init__(self):
|
||||
self._display = get_display_number()
|
||||
cmd = 'Xnest :%d -ac -geometry 800x600' % (self._display)
|
||||
Process.__init__(self, cmd)
|
||||
|
||||
def get_name(self):
|
||||
return 'Xnest'
|
||||
|
||||
def start(self):
|
||||
Process.start(self)
|
||||
os.environ['DISPLAY'] = ":%d" % (self._display)
|
||||
def start(self):
|
||||
Process.start(self)
|
||||
os.environ['DISPLAY'] = ":%d" % (self._display)
|
||||
|
||||
class Emulator(object):
|
||||
"""The OLPC emulator"""
|
||||
def __init__(self, fullscreen):
|
||||
self._fullscreen = fullscreen
|
||||
"""The OLPC emulator"""
|
||||
def __init__(self, fullscreen):
|
||||
self._fullscreen = fullscreen
|
||||
|
||||
def start(self):
|
||||
try:
|
||||
process = XephyrProcess(self._fullscreen)
|
||||
process.start()
|
||||
except:
|
||||
try:
|
||||
process = XnestProcess()
|
||||
process.start()
|
||||
except:
|
||||
print 'Cannot run the emulator. You need to install \
|
||||
Xephyr or Xnest.'
|
||||
sys.exit(0)
|
||||
def start(self):
|
||||
try:
|
||||
process = XephyrProcess(self._fullscreen)
|
||||
process.start()
|
||||
except:
|
||||
try:
|
||||
process = XnestProcess()
|
||||
process.start()
|
||||
except:
|
||||
print 'Cannot run the emulator. You need to install \
|
||||
Xephyr or Xnest.'
|
||||
sys.exit(0)
|
||||
|
||||
process = MatchboxProcess()
|
||||
process.start()
|
||||
process = MatchboxProcess()
|
||||
process.start()
|
||||
|
||||
+24
-24
@@ -20,43 +20,43 @@ import sys
|
||||
import pwd
|
||||
|
||||
try:
|
||||
from sugar.__uninstalled__ import *
|
||||
from sugar.__uninstalled__ import *
|
||||
except ImportError:
|
||||
from sugar.__installed__ import *
|
||||
from sugar.__installed__ import *
|
||||
|
||||
def get_profile_path():
|
||||
if os.environ.has_key('SUGAR_PROFILE'):
|
||||
profile_id = os.environ['SUGAR_PROFILE']
|
||||
else:
|
||||
profile_id = 'default'
|
||||
if os.environ.has_key('SUGAR_PROFILE'):
|
||||
profile_id = os.environ['SUGAR_PROFILE']
|
||||
else:
|
||||
profile_id = 'default'
|
||||
|
||||
path = os.path.join(os.path.expanduser('~/.sugar'), profile_id)
|
||||
if not os.path.isdir(path):
|
||||
try:
|
||||
os.makedirs(path)
|
||||
except OSError, exc:
|
||||
print "Could not create user directory."
|
||||
path = os.path.join(os.path.expanduser('~/.sugar'), profile_id)
|
||||
if not os.path.isdir(path):
|
||||
try:
|
||||
os.makedirs(path)
|
||||
except OSError, exc:
|
||||
print "Could not create user directory."
|
||||
|
||||
return path
|
||||
return path
|
||||
|
||||
def get_data_dir():
|
||||
return sugar_data_dir
|
||||
return sugar_data_dir
|
||||
|
||||
def get_services_dir():
|
||||
return sugar_services_dir
|
||||
return sugar_services_dir
|
||||
|
||||
def get_shell_bin_dir():
|
||||
return sugar_shell_bin_dir
|
||||
return sugar_shell_bin_dir
|
||||
|
||||
# http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
|
||||
def get_data_dirs():
|
||||
if os.environ.has_key('XDG_DATA_DIRS'):
|
||||
return os.environ['XDG_DATA_DIRS'].split(':')
|
||||
else:
|
||||
return [ '/usr/local/share/', '/usr/share/' ]
|
||||
if os.environ.has_key('XDG_DATA_DIRS'):
|
||||
return os.environ['XDG_DATA_DIRS'].split(':')
|
||||
else:
|
||||
return [ '/usr/local/share/', '/usr/share/' ]
|
||||
|
||||
def get_user_service_dir():
|
||||
service_dir = os.path.expanduser('~/.local/share/dbus-1/services')
|
||||
if not os.path.isdir(service_dir):
|
||||
os.makedirs(service_dir)
|
||||
return service_dir
|
||||
service_dir = os.path.expanduser('~/.local/share/dbus-1/services')
|
||||
if not os.path.isdir(service_dir):
|
||||
os.makedirs(service_dir)
|
||||
return service_dir
|
||||
|
||||
@@ -24,108 +24,108 @@ import gtk
|
||||
import hippo
|
||||
|
||||
class ClipboardBubble(hippo.CanvasBox, hippo.CanvasItem):
|
||||
__gtype_name__ = 'ClipboardBubble'
|
||||
__gtype_name__ = 'ClipboardBubble'
|
||||
|
||||
__gproperties__ = {
|
||||
'fill-color': (object, None, None,
|
||||
gobject.PARAM_READWRITE),
|
||||
'stroke-color': (object, None, None,
|
||||
gobject.PARAM_READWRITE),
|
||||
'progress-color': (object, None, None,
|
||||
gobject.PARAM_READWRITE),
|
||||
'percent' : (object, None, None,
|
||||
gobject.PARAM_READWRITE),
|
||||
}
|
||||
__gproperties__ = {
|
||||
'fill-color': (object, None, None,
|
||||
gobject.PARAM_READWRITE),
|
||||
'stroke-color': (object, None, None,
|
||||
gobject.PARAM_READWRITE),
|
||||
'progress-color': (object, None, None,
|
||||
gobject.PARAM_READWRITE),
|
||||
'percent' : (object, None, None,
|
||||
gobject.PARAM_READWRITE),
|
||||
}
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self._stroke_color = 0xFFFFFFFF
|
||||
self._fill_color = 0xFFFFFFFF
|
||||
self._progress_color = 0x000000FF
|
||||
self._percent = 0
|
||||
self._radius = 8
|
||||
def __init__(self, **kwargs):
|
||||
self._stroke_color = 0xFFFFFFFF
|
||||
self._fill_color = 0xFFFFFFFF
|
||||
self._progress_color = 0x000000FF
|
||||
self._percent = 0
|
||||
self._radius = 8
|
||||
|
||||
hippo.CanvasBox.__init__(self, **kwargs)
|
||||
hippo.CanvasBox.__init__(self, **kwargs)
|
||||
|
||||
def do_set_property(self, pspec, value):
|
||||
if pspec.name == 'fill-color':
|
||||
self._fill_color = value
|
||||
self.emit_paint_needed(0, 0, -1, -1)
|
||||
elif pspec.name == 'stroke-color':
|
||||
self._stroke_color = value
|
||||
self.emit_paint_needed(0, 0, -1, -1)
|
||||
elif pspec.name == 'progress-color':
|
||||
self._progress_color = value
|
||||
self.emit_paint_needed(0, 0, -1, -1)
|
||||
elif pspec.name == 'percent':
|
||||
self._percent = value
|
||||
self.emit_paint_needed(0, 0, -1, -1)
|
||||
def do_set_property(self, pspec, value):
|
||||
if pspec.name == 'fill-color':
|
||||
self._fill_color = value
|
||||
self.emit_paint_needed(0, 0, -1, -1)
|
||||
elif pspec.name == 'stroke-color':
|
||||
self._stroke_color = value
|
||||
self.emit_paint_needed(0, 0, -1, -1)
|
||||
elif pspec.name == 'progress-color':
|
||||
self._progress_color = value
|
||||
self.emit_paint_needed(0, 0, -1, -1)
|
||||
elif pspec.name == 'percent':
|
||||
self._percent = value
|
||||
self.emit_paint_needed(0, 0, -1, -1)
|
||||
|
||||
def do_get_property(self, pspec):
|
||||
if pspec.name == 'fill-color':
|
||||
return self._fill_color
|
||||
elif pspec.name == 'stroke-color':
|
||||
return self._stroke_color
|
||||
elif pspec.name == 'progress-color':
|
||||
return self._progress_color
|
||||
elif pspec.name == 'percent':
|
||||
return self._percent
|
||||
def do_get_property(self, pspec):
|
||||
if pspec.name == 'fill-color':
|
||||
return self._fill_color
|
||||
elif pspec.name == 'stroke-color':
|
||||
return self._stroke_color
|
||||
elif pspec.name == 'progress-color':
|
||||
return self._progress_color
|
||||
elif pspec.name == 'percent':
|
||||
return self._percent
|
||||
|
||||
def _int_to_rgb(self, int_color):
|
||||
red = (int_color >> 24) & 0x000000FF
|
||||
green = (int_color >> 16) & 0x000000FF
|
||||
blue = (int_color >> 8) & 0x000000FF
|
||||
alpha = int_color & 0x000000FF
|
||||
return (red / 255.0, green / 255.0, blue / 255.0)
|
||||
def _int_to_rgb(self, int_color):
|
||||
red = (int_color >> 24) & 0x000000FF
|
||||
green = (int_color >> 16) & 0x000000FF
|
||||
blue = (int_color >> 8) & 0x000000FF
|
||||
alpha = int_color & 0x000000FF
|
||||
return (red / 255.0, green / 255.0, blue / 255.0)
|
||||
|
||||
def do_paint_below_children(self, cr, damaged_box):
|
||||
[width, height] = self.get_allocation()
|
||||
def do_paint_below_children(self, cr, damaged_box):
|
||||
[width, height] = self.get_allocation()
|
||||
|
||||
line_width = 3.0
|
||||
x = line_width
|
||||
y = line_width
|
||||
width -= line_width * 2
|
||||
height -= line_width * 2
|
||||
line_width = 3.0
|
||||
x = line_width
|
||||
y = line_width
|
||||
width -= line_width * 2
|
||||
height -= line_width * 2
|
||||
|
||||
self._paint_ellipse(cr, x, y, width, height, self._fill_color)
|
||||
self._paint_ellipse(cr, x, y, width, height, self._fill_color)
|
||||
|
||||
color = self._int_to_rgb(self._stroke_color)
|
||||
cr.set_source_rgb(*color)
|
||||
cr.set_line_width(line_width)
|
||||
cr.stroke();
|
||||
color = self._int_to_rgb(self._stroke_color)
|
||||
cr.set_source_rgb(*color)
|
||||
cr.set_line_width(line_width)
|
||||
cr.stroke();
|
||||
|
||||
self._paint_progress_bar(cr, x, y, width, height, line_width)
|
||||
self._paint_progress_bar(cr, x, y, width, height, line_width)
|
||||
|
||||
def _paint_progress_bar(self, cr, x, y, width, height, line_width):
|
||||
prog_x = x + line_width
|
||||
prog_y = y + line_width
|
||||
prog_width = (width - (line_width * 2)) * (self._percent / 100.0)
|
||||
prog_height = (height - (line_width * 2))
|
||||
def _paint_progress_bar(self, cr, x, y, width, height, line_width):
|
||||
prog_x = x + line_width
|
||||
prog_y = y + line_width
|
||||
prog_width = (width - (line_width * 2)) * (self._percent / 100.0)
|
||||
prog_height = (height - (line_width * 2))
|
||||
|
||||
self._paint_ellipse(cr, prog_x, prog_y, width, height, self._progress_color)
|
||||
self._paint_ellipse(cr, prog_x, prog_y, width, height, self._progress_color)
|
||||
|
||||
def _paint_ellipse(self, cr, x, y, width, height, fill_color):
|
||||
cr.move_to(x + self._radius, y)
|
||||
cr.arc(x + width - self._radius,
|
||||
y + self._radius,
|
||||
self._radius,
|
||||
math.pi * 1.5,
|
||||
math.pi * 2)
|
||||
cr.arc(x + width - self._radius,
|
||||
x + height - self._radius,
|
||||
self._radius,
|
||||
0,
|
||||
math.pi * 0.5)
|
||||
cr.arc(x + self._radius,
|
||||
y + height - self._radius,
|
||||
self._radius,
|
||||
math.pi * 0.5,
|
||||
math.pi)
|
||||
cr.arc(x + self._radius,
|
||||
y + self._radius,
|
||||
self._radius,
|
||||
math.pi,
|
||||
math.pi * 1.5);
|
||||
def _paint_ellipse(self, cr, x, y, width, height, fill_color):
|
||||
cr.move_to(x + self._radius, y)
|
||||
cr.arc(x + width - self._radius,
|
||||
y + self._radius,
|
||||
self._radius,
|
||||
math.pi * 1.5,
|
||||
math.pi * 2)
|
||||
cr.arc(x + width - self._radius,
|
||||
x + height - self._radius,
|
||||
self._radius,
|
||||
0,
|
||||
math.pi * 0.5)
|
||||
cr.arc(x + self._radius,
|
||||
y + height - self._radius,
|
||||
self._radius,
|
||||
math.pi * 0.5,
|
||||
math.pi)
|
||||
cr.arc(x + self._radius,
|
||||
y + self._radius,
|
||||
self._radius,
|
||||
math.pi,
|
||||
math.pi * 1.5);
|
||||
|
||||
color = self._int_to_rgb(fill_color)
|
||||
cr.set_source_rgb(*color)
|
||||
cr.fill_preserve();
|
||||
color = self._int_to_rgb(fill_color)
|
||||
cr.set_source_rgb(*color)
|
||||
cr.fill_preserve();
|
||||
|
||||
+42
-42
@@ -22,56 +22,56 @@ import gtk
|
||||
import hippo
|
||||
|
||||
class Bubble(hippo.CanvasBox, hippo.CanvasItem):
|
||||
__gtype_name__ = 'SugarBubble'
|
||||
__gtype_name__ = 'SugarBubble'
|
||||
|
||||
__gproperties__ = {
|
||||
'color' : (object, None, None,
|
||||
gobject.PARAM_READWRITE),
|
||||
}
|
||||
__gproperties__ = {
|
||||
'color' : (object, None, None,
|
||||
gobject.PARAM_READWRITE),
|
||||
}
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self._color = None
|
||||
self._radius = 8
|
||||
def __init__(self, **kwargs):
|
||||
self._color = None
|
||||
self._radius = 8
|
||||
|
||||
hippo.CanvasBox.__init__(self, **kwargs)
|
||||
hippo.CanvasBox.__init__(self, **kwargs)
|
||||
|
||||
def do_set_property(self, pspec, value):
|
||||
if pspec.name == 'color':
|
||||
self._color = value
|
||||
self.emit_paint_needed(0, 0, -1, -1)
|
||||
def do_set_property(self, pspec, value):
|
||||
if pspec.name == 'color':
|
||||
self._color = value
|
||||
self.emit_paint_needed(0, 0, -1, -1)
|
||||
|
||||
def do_get_property(self, pspec):
|
||||
if pspec.name == 'color':
|
||||
return self._color
|
||||
def do_get_property(self, pspec):
|
||||
if pspec.name == 'color':
|
||||
return self._color
|
||||
|
||||
def _string_to_rgb(self, color_string):
|
||||
col = gtk.gdk.color_parse(color_string)
|
||||
return (col.red / 65535.0, col.green / 65535.0, col.blue / 65535.0)
|
||||
def _string_to_rgb(self, color_string):
|
||||
col = gtk.gdk.color_parse(color_string)
|
||||
return (col.red / 65535.0, col.green / 65535.0, col.blue / 65535.0)
|
||||
|
||||
def do_paint_below_children(self, cr, damaged_box):
|
||||
[width, height] = self.get_allocation()
|
||||
def do_paint_below_children(self, cr, damaged_box):
|
||||
[width, height] = self.get_allocation()
|
||||
|
||||
line_width = 3.0
|
||||
x = line_width
|
||||
y = line_width
|
||||
width -= line_width * 2
|
||||
height -= line_width * 2
|
||||
line_width = 3.0
|
||||
x = line_width
|
||||
y = line_width
|
||||
width -= line_width * 2
|
||||
height -= line_width * 2
|
||||
|
||||
cr.move_to(x + self._radius, y);
|
||||
cr.arc(x + width - self._radius, y + self._radius,
|
||||
self._radius, math.pi * 1.5, math.pi * 2);
|
||||
cr.arc(x + width - self._radius, x + height - self._radius,
|
||||
self._radius, 0, math.pi * 0.5);
|
||||
cr.arc(x + self._radius, y + height - self._radius,
|
||||
self._radius, math.pi * 0.5, math.pi);
|
||||
cr.arc(x + self._radius, y + self._radius, self._radius,
|
||||
math.pi, math.pi * 1.5);
|
||||
cr.move_to(x + self._radius, y);
|
||||
cr.arc(x + width - self._radius, y + self._radius,
|
||||
self._radius, math.pi * 1.5, math.pi * 2);
|
||||
cr.arc(x + width - self._radius, x + height - self._radius,
|
||||
self._radius, 0, math.pi * 0.5);
|
||||
cr.arc(x + self._radius, y + height - self._radius,
|
||||
self._radius, math.pi * 0.5, math.pi);
|
||||
cr.arc(x + self._radius, y + self._radius, self._radius,
|
||||
math.pi, math.pi * 1.5);
|
||||
|
||||
color = self._string_to_rgb(self._color.get_fill_color())
|
||||
cr.set_source_rgb(*color)
|
||||
cr.fill_preserve();
|
||||
color = self._string_to_rgb(self._color.get_fill_color())
|
||||
cr.set_source_rgb(*color)
|
||||
cr.fill_preserve();
|
||||
|
||||
color = self._string_to_rgb(self._color.get_stroke_color())
|
||||
cr.set_source_rgb(*color)
|
||||
cr.set_line_width(line_width)
|
||||
cr.stroke();
|
||||
color = self._string_to_rgb(self._color.get_stroke_color())
|
||||
cr.set_source_rgb(*color)
|
||||
cr.set_line_width(line_width)
|
||||
cr.stroke();
|
||||
|
||||
+101
-101
@@ -26,133 +26,133 @@ import cairo
|
||||
from sugar.graphics.iconcolor import IconColor
|
||||
|
||||
class _IconCache:
|
||||
def __init__(self):
|
||||
self._icons = {}
|
||||
self._theme = gtk.icon_theme_get_default()
|
||||
def __init__(self):
|
||||
self._icons = {}
|
||||
self._theme = gtk.icon_theme_get_default()
|
||||
|
||||
def _read_icon(self, filename, color):
|
||||
icon_file = open(filename, 'r')
|
||||
def _read_icon(self, filename, color):
|
||||
icon_file = open(filename, 'r')
|
||||
|
||||
if color == None:
|
||||
return rsvg.Handle(file=filename)
|
||||
else:
|
||||
data = icon_file.read()
|
||||
icon_file.close()
|
||||
if color == None:
|
||||
return rsvg.Handle(file=filename)
|
||||
else:
|
||||
data = icon_file.read()
|
||||
icon_file.close()
|
||||
|
||||
fill = color.get_fill_color()
|
||||
stroke = color.get_stroke_color()
|
||||
|
||||
entity = '<!ENTITY fill_color "%s">' % fill
|
||||
data = re.sub('<!ENTITY fill_color .*>', entity, data)
|
||||
fill = color.get_fill_color()
|
||||
stroke = color.get_stroke_color()
|
||||
|
||||
entity = '<!ENTITY fill_color "%s">' % fill
|
||||
data = re.sub('<!ENTITY fill_color .*>', entity, data)
|
||||
|
||||
entity = '<!ENTITY stroke_color "%s">' % stroke
|
||||
data = re.sub('<!ENTITY stroke_color .*>', entity, data)
|
||||
entity = '<!ENTITY stroke_color "%s">' % stroke
|
||||
data = re.sub('<!ENTITY stroke_color .*>', entity, data)
|
||||
|
||||
return rsvg.Handle(data=data)
|
||||
return rsvg.Handle(data=data)
|
||||
|
||||
def get_handle(self, name, color, size):
|
||||
info = self._theme.lookup_icon(name, int(size), 0)
|
||||
def get_handle(self, name, color, size):
|
||||
info = self._theme.lookup_icon(name, int(size), 0)
|
||||
|
||||
if color:
|
||||
key = (info.get_filename(), color.to_string())
|
||||
else:
|
||||
key = info.get_filename()
|
||||
if color:
|
||||
key = (info.get_filename(), color.to_string())
|
||||
else:
|
||||
key = info.get_filename()
|
||||
|
||||
if self._icons.has_key(key):
|
||||
icon = self._icons[key]
|
||||
else:
|
||||
icon = self._read_icon(info.get_filename(), color)
|
||||
self._icons[key] = icon
|
||||
return icon
|
||||
if self._icons.has_key(key):
|
||||
icon = self._icons[key]
|
||||
else:
|
||||
icon = self._read_icon(info.get_filename(), color)
|
||||
self._icons[key] = icon
|
||||
return icon
|
||||
|
||||
class CanvasIcon(hippo.CanvasBox, hippo.CanvasItem):
|
||||
__gtype_name__ = 'CanvasIcon'
|
||||
__gtype_name__ = 'CanvasIcon'
|
||||
|
||||
__gproperties__ = {
|
||||
'icon-name': (str, None, None, None,
|
||||
gobject.PARAM_READWRITE),
|
||||
'color' : (object, None, None,
|
||||
gobject.PARAM_READWRITE),
|
||||
'size' : (int, None, None,
|
||||
0, 1024, 24,
|
||||
gobject.PARAM_READWRITE)
|
||||
}
|
||||
__gproperties__ = {
|
||||
'icon-name': (str, None, None, None,
|
||||
gobject.PARAM_READWRITE),
|
||||
'color' : (object, None, None,
|
||||
gobject.PARAM_READWRITE),
|
||||
'size' : (int, None, None,
|
||||
0, 1024, 24,
|
||||
gobject.PARAM_READWRITE)
|
||||
}
|
||||
|
||||
_cache = _IconCache()
|
||||
_cache = _IconCache()
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self._size = 24
|
||||
self._color = None
|
||||
self._icon_name = None
|
||||
def __init__(self, **kwargs):
|
||||
self._size = 24
|
||||
self._color = None
|
||||
self._icon_name = None
|
||||
|
||||
hippo.CanvasBox.__init__(self, **kwargs)
|
||||
hippo.CanvasBox.__init__(self, **kwargs)
|
||||
|
||||
self._buffer = None
|
||||
self._buffer = None
|
||||
|
||||
self.connect('button-press-event', self._button_press_event_cb)
|
||||
self.connect('button-press-event', self._button_press_event_cb)
|
||||
|
||||
def do_set_property(self, pspec, value):
|
||||
if pspec.name == 'icon-name':
|
||||
self._icon_name = value
|
||||
self._buffer = None
|
||||
self.emit_paint_needed(0, 0, -1, -1)
|
||||
elif pspec.name == 'color':
|
||||
self._buffer = None
|
||||
self._color = value
|
||||
self.emit_paint_needed(0, 0, -1, -1)
|
||||
elif pspec.name == 'size':
|
||||
self._buffer = None
|
||||
self._size = value
|
||||
self.emit_request_changed()
|
||||
def do_set_property(self, pspec, value):
|
||||
if pspec.name == 'icon-name':
|
||||
self._icon_name = value
|
||||
self._buffer = None
|
||||
self.emit_paint_needed(0, 0, -1, -1)
|
||||
elif pspec.name == 'color':
|
||||
self._buffer = None
|
||||
self._color = value
|
||||
self.emit_paint_needed(0, 0, -1, -1)
|
||||
elif pspec.name == 'size':
|
||||
self._buffer = None
|
||||
self._size = value
|
||||
self.emit_request_changed()
|
||||
|
||||
def do_get_property(self, pspec):
|
||||
if pspec.name == 'size':
|
||||
return self._size
|
||||
elif pspec.name == 'icon-name':
|
||||
return self._icon_name
|
||||
elif pspec.name == 'color':
|
||||
return self._color
|
||||
def do_get_property(self, pspec):
|
||||
if pspec.name == 'size':
|
||||
return self._size
|
||||
elif pspec.name == 'icon-name':
|
||||
return self._icon_name
|
||||
elif pspec.name == 'color':
|
||||
return self._color
|
||||
|
||||
def _get_buffer(self, cr, handle, size):
|
||||
if self._buffer == None:
|
||||
target = cr.get_target()
|
||||
surface = target.create_similar(cairo.CONTENT_COLOR_ALPHA,
|
||||
int(size) + 1, int(size) + 1)
|
||||
def _get_buffer(self, cr, handle, size):
|
||||
if self._buffer == None:
|
||||
target = cr.get_target()
|
||||
surface = target.create_similar(cairo.CONTENT_COLOR_ALPHA,
|
||||
int(size) + 1, int(size) + 1)
|
||||
|
||||
dimensions = handle.get_dimension_data()
|
||||
scale = float(size) / float(dimensions[0])
|
||||
dimensions = handle.get_dimension_data()
|
||||
scale = float(size) / float(dimensions[0])
|
||||
|
||||
ctx = cairo.Context(surface)
|
||||
ctx.scale(scale, scale)
|
||||
handle.render_cairo(ctx)
|
||||
del ctx
|
||||
ctx = cairo.Context(surface)
|
||||
ctx.scale(scale, scale)
|
||||
handle.render_cairo(ctx)
|
||||
del ctx
|
||||
|
||||
self._buffer = surface
|
||||
self._buffer_scale = scale
|
||||
self._buffer = surface
|
||||
self._buffer_scale = scale
|
||||
|
||||
return self._buffer
|
||||
return self._buffer
|
||||
|
||||
def do_paint_below_children(self, cr, damaged_box):
|
||||
icon_name = self._icon_name
|
||||
if icon_name == None:
|
||||
icon_name = 'stock-missing'
|
||||
def do_paint_below_children(self, cr, damaged_box):
|
||||
icon_name = self._icon_name
|
||||
if icon_name == None:
|
||||
icon_name = 'stock-missing'
|
||||
|
||||
handle = CanvasIcon._cache.get_handle(
|
||||
icon_name, self._color, self._size)
|
||||
buf = self._get_buffer(cr, handle, self._size)
|
||||
handle = CanvasIcon._cache.get_handle(
|
||||
icon_name, self._color, self._size)
|
||||
buf = self._get_buffer(cr, handle, self._size)
|
||||
|
||||
[width, height] = self.get_allocation()
|
||||
x = (width - self._size) / 2
|
||||
y = (height - self._size) / 2
|
||||
|
||||
cr.set_source_surface(buf, x, y)
|
||||
cr.paint()
|
||||
[width, height] = self.get_allocation()
|
||||
x = (width - self._size) / 2
|
||||
y = (height - self._size) / 2
|
||||
|
||||
cr.set_source_surface(buf, x, y)
|
||||
cr.paint()
|
||||
|
||||
def do_get_width_request(self):
|
||||
return self._size
|
||||
def do_get_width_request(self):
|
||||
return self._size
|
||||
|
||||
def do_get_height_request(self, for_width):
|
||||
return self._size
|
||||
def do_get_height_request(self, for_width):
|
||||
return self._size
|
||||
|
||||
def _button_press_event_cb(self, item, event):
|
||||
item.emit_activated()
|
||||
def _button_press_event_cb(self, item, event):
|
||||
item.emit_activated()
|
||||
|
||||
+12
-12
@@ -21,19 +21,19 @@ COLS = 16
|
||||
ROWS = 12
|
||||
|
||||
class Grid(object):
|
||||
def __init__(self):
|
||||
self._factor = gtk.gdk.screen_width() / COLS
|
||||
def __init__(self):
|
||||
self._factor = gtk.gdk.screen_width() / COLS
|
||||
|
||||
def point(self, grid_x, grid_y):
|
||||
return [grid_x * self._factor, grid_y * self._factor]
|
||||
def point(self, grid_x, grid_y):
|
||||
return [grid_x * self._factor, grid_y * self._factor]
|
||||
|
||||
def rectangle(self, grid_x, grid_y, grid_w, grid_h):
|
||||
return [grid_x * self._factor, grid_y * self._factor,
|
||||
grid_w * self._factor, grid_h * self._factor]
|
||||
def rectangle(self, grid_x, grid_y, grid_w, grid_h):
|
||||
return [grid_x * self._factor, grid_y * self._factor,
|
||||
grid_w * self._factor, grid_h * self._factor]
|
||||
|
||||
def dimension(self, grid_dimension):
|
||||
return grid_dimension * self._factor
|
||||
def dimension(self, grid_dimension):
|
||||
return grid_dimension * self._factor
|
||||
|
||||
def fit_point(self, x, y):
|
||||
return [int(x / self._factor), int(y / self._factor)]
|
||||
|
||||
def fit_point(self, x, y):
|
||||
return [int(x / self._factor), int(y / self._factor)]
|
||||
|
||||
|
||||
+20
-20
@@ -20,32 +20,32 @@ import random
|
||||
from sugar.graphics.colors import colors
|
||||
|
||||
def _parse_string(color_string):
|
||||
if color_string == 'white':
|
||||
return ['#ffffff', '#414141']
|
||||
if color_string == 'white':
|
||||
return ['#ffffff', '#414141']
|
||||
|
||||
splitted = color_string.split(',')
|
||||
if len(splitted) == 2:
|
||||
return [splitted[0], splitted[1]]
|
||||
else:
|
||||
return None
|
||||
splitted = color_string.split(',')
|
||||
if len(splitted) == 2:
|
||||
return [splitted[0], splitted[1]]
|
||||
else:
|
||||
return None
|
||||
|
||||
def is_valid(color_string):
|
||||
return (_parse_string(color_string) != None)
|
||||
return (_parse_string(color_string) != None)
|
||||
|
||||
class IconColor:
|
||||
def __init__(self, color_string=None):
|
||||
if color_string == None or not is_valid(color_string):
|
||||
n = int(random.random() * (len(colors) - 1))
|
||||
[self._stroke, self._fill] = colors[n]
|
||||
else:
|
||||
[self._stroke, self._fill] = _parse_string(color_string)
|
||||
def __init__(self, color_string=None):
|
||||
if color_string == None or not is_valid(color_string):
|
||||
n = int(random.random() * (len(colors) - 1))
|
||||
[self._stroke, self._fill] = colors[n]
|
||||
else:
|
||||
[self._stroke, self._fill] = _parse_string(color_string)
|
||||
|
||||
def get_stroke_color(self):
|
||||
return self._stroke
|
||||
def get_stroke_color(self):
|
||||
return self._stroke
|
||||
|
||||
def get_fill_color(self):
|
||||
return self._fill
|
||||
def get_fill_color(self):
|
||||
return self._fill
|
||||
|
||||
def to_string(self):
|
||||
return '%s,%s' % (self._stroke, self._fill)
|
||||
def to_string(self):
|
||||
return '%s,%s' % (self._stroke, self._fill)
|
||||
|
||||
|
||||
+62
-62
@@ -23,85 +23,85 @@ from sugar.graphics.canvasicon import CanvasIcon
|
||||
from sugar.graphics import style
|
||||
|
||||
class Menu(gtk.Window):
|
||||
__gsignals__ = {
|
||||
'action': (gobject.SIGNAL_RUN_FIRST,
|
||||
gobject.TYPE_NONE, ([int])),
|
||||
}
|
||||
__gsignals__ = {
|
||||
'action': (gobject.SIGNAL_RUN_FIRST,
|
||||
gobject.TYPE_NONE, ([int])),
|
||||
}
|
||||
|
||||
def __init__(self, title=None, content_box=None):
|
||||
gtk.Window.__init__(self, gtk.WINDOW_POPUP)
|
||||
def __init__(self, title=None, content_box=None):
|
||||
gtk.Window.__init__(self, gtk.WINDOW_POPUP)
|
||||
|
||||
canvas = hippo.Canvas()
|
||||
self.add(canvas)
|
||||
canvas.show()
|
||||
canvas = hippo.Canvas()
|
||||
self.add(canvas)
|
||||
canvas.show()
|
||||
|
||||
self._root = hippo.CanvasBox()
|
||||
style.apply_stylesheet(self._root, 'menu')
|
||||
canvas.set_root(self._root)
|
||||
self._root = hippo.CanvasBox()
|
||||
style.apply_stylesheet(self._root, 'menu')
|
||||
canvas.set_root(self._root)
|
||||
|
||||
if title:
|
||||
self._title_item = hippo.CanvasText(text=title)
|
||||
style.apply_stylesheet(self._title_item, 'menu.Title')
|
||||
self._root.append(self._title_item)
|
||||
else:
|
||||
self._title_item = None
|
||||
if title:
|
||||
self._title_item = hippo.CanvasText(text=title)
|
||||
style.apply_stylesheet(self._title_item, 'menu.Title')
|
||||
self._root.append(self._title_item)
|
||||
else:
|
||||
self._title_item = None
|
||||
|
||||
if content_box:
|
||||
separator = self._create_separator()
|
||||
self._root.append(separator)
|
||||
self._root.append(content_box)
|
||||
if content_box:
|
||||
separator = self._create_separator()
|
||||
self._root.append(separator)
|
||||
self._root.append(content_box)
|
||||
|
||||
self._action_box = None
|
||||
self._item_box = None
|
||||
self._action_box = None
|
||||
self._item_box = None
|
||||
|
||||
def _create_separator(self):
|
||||
separator = hippo.CanvasBox()
|
||||
style.apply_stylesheet(separator, 'menu.Separator')
|
||||
return separator
|
||||
def _create_separator(self):
|
||||
separator = hippo.CanvasBox()
|
||||
style.apply_stylesheet(separator, 'menu.Separator')
|
||||
return separator
|
||||
|
||||
def _create_item_box(self):
|
||||
if self._title_item:
|
||||
separator = self._create_separator()
|
||||
self._root.append(separator)
|
||||
def _create_item_box(self):
|
||||
if self._title_item:
|
||||
separator = self._create_separator()
|
||||
self._root.append(separator)
|
||||
|
||||
self._item_box = hippo.CanvasBox(
|
||||
orientation=hippo.ORIENTATION_VERTICAL)
|
||||
self._root.append(self._item_box)
|
||||
self._item_box = hippo.CanvasBox(
|
||||
orientation=hippo.ORIENTATION_VERTICAL)
|
||||
self._root.append(self._item_box)
|
||||
|
||||
def _create_action_box(self):
|
||||
separator = self._create_separator()
|
||||
self._root.append(separator)
|
||||
def _create_action_box(self):
|
||||
separator = self._create_separator()
|
||||
self._root.append(separator)
|
||||
|
||||
self._action_box = hippo.CanvasBox(
|
||||
orientation=hippo.ORIENTATION_HORIZONTAL)
|
||||
self._root.append(self._action_box)
|
||||
self._action_box = hippo.CanvasBox(
|
||||
orientation=hippo.ORIENTATION_HORIZONTAL)
|
||||
self._root.append(self._action_box)
|
||||
|
||||
def add_item(self, label, action_id):
|
||||
if not self._item_box:
|
||||
self._create_item_box()
|
||||
def add_item(self, label, action_id):
|
||||
if not self._item_box:
|
||||
self._create_item_box()
|
||||
|
||||
text = hippo.CanvasText(text=label)
|
||||
style.apply_stylesheet(text, 'menu.Item')
|
||||
text = hippo.CanvasText(text=label)
|
||||
style.apply_stylesheet(text, 'menu.Item')
|
||||
|
||||
# FIXME need a way to make hippo items activable in python
|
||||
text.connect('button-press-event', self._item_clicked_cb, action_id)
|
||||
#text.connect('activated', self._action_clicked_cb, action_id)
|
||||
# FIXME need a way to make hippo items activable in python
|
||||
text.connect('button-press-event', self._item_clicked_cb, action_id)
|
||||
#text.connect('activated', self._action_clicked_cb, action_id)
|
||||
|
||||
self._item_box.append(text)
|
||||
self._item_box.append(text)
|
||||
|
||||
def add_action(self, icon, action_id):
|
||||
if not self._action_box:
|
||||
self._create_action_box()
|
||||
def add_action(self, icon, action_id):
|
||||
if not self._action_box:
|
||||
self._create_action_box()
|
||||
|
||||
style.apply_stylesheet(icon, 'menu.ActionIcon')
|
||||
icon.connect('activated', self._action_clicked_cb, action_id)
|
||||
self._action_box.append(icon)
|
||||
style.apply_stylesheet(icon, 'menu.ActionIcon')
|
||||
icon.connect('activated', self._action_clicked_cb, action_id)
|
||||
self._action_box.append(icon)
|
||||
|
||||
def remove_action(self, icon):
|
||||
self._action_box.remove(icon)
|
||||
def remove_action(self, icon):
|
||||
self._action_box.remove(icon)
|
||||
|
||||
def _item_clicked_cb(self, icon, event, action):
|
||||
self.emit('action', action)
|
||||
def _item_clicked_cb(self, icon, event, action):
|
||||
self.emit('action', action)
|
||||
|
||||
def _action_clicked_cb(self, icon, action):
|
||||
self.emit('action', action)
|
||||
def _action_clicked_cb(self, icon, action):
|
||||
self.emit('action', action)
|
||||
|
||||
+41
-41
@@ -23,58 +23,58 @@ from sugar.graphics.canvasicon import CanvasIcon
|
||||
from sugar.graphics.timeline import Timeline
|
||||
|
||||
class MenuIcon(CanvasIcon):
|
||||
def __init__(self, menu_shell, **kwargs):
|
||||
CanvasIcon.__init__(self, **kwargs)
|
||||
def __init__(self, menu_shell, **kwargs):
|
||||
CanvasIcon.__init__(self, **kwargs)
|
||||
|
||||
self._menu_shell = menu_shell
|
||||
self._menu = None
|
||||
self._hover_menu = False
|
||||
self._menu_shell = menu_shell
|
||||
self._menu = None
|
||||
self._hover_menu = False
|
||||
|
||||
self._timeline = Timeline(self)
|
||||
self._timeline.add_tag('popup', 6, 6)
|
||||
self._timeline.add_tag('before_popdown', 7, 7)
|
||||
self._timeline.add_tag('popdown', 8, 8)
|
||||
self._timeline = Timeline(self)
|
||||
self._timeline.add_tag('popup', 6, 6)
|
||||
self._timeline.add_tag('before_popdown', 7, 7)
|
||||
self._timeline.add_tag('popdown', 8, 8)
|
||||
|
||||
self.connect('motion-notify-event', self._motion_notify_event_cb)
|
||||
self.connect('motion-notify-event', self._motion_notify_event_cb)
|
||||
|
||||
def do_popup(self, current, n_frames):
|
||||
if self._menu:
|
||||
return
|
||||
def do_popup(self, current, n_frames):
|
||||
if self._menu:
|
||||
return
|
||||
|
||||
self._menu = self.create_menu()
|
||||
self._menu = self.create_menu()
|
||||
|
||||
self._menu.connect('enter-notify-event',
|
||||
self._menu_enter_notify_event_cb)
|
||||
self._menu.connect('leave-notify-event',
|
||||
self._menu_leave_notify_event_cb)
|
||||
self._menu.connect('enter-notify-event',
|
||||
self._menu_enter_notify_event_cb)
|
||||
self._menu.connect('leave-notify-event',
|
||||
self._menu_leave_notify_event_cb)
|
||||
|
||||
[x, y] = self._menu_shell.get_position(self._menu, self)
|
||||
[x, y] = self._menu_shell.get_position(self._menu, self)
|
||||
|
||||
self._menu.move(x, y)
|
||||
self._menu.show()
|
||||
self._menu.move(x, y)
|
||||
self._menu.show()
|
||||
|
||||
self._menu_shell.set_active(self)
|
||||
self._menu_shell.set_active(self)
|
||||
|
||||
def do_popdown(self, current, frame):
|
||||
if self._menu:
|
||||
self._menu.destroy()
|
||||
self._menu = None
|
||||
self._menu_shell.set_active(None)
|
||||
def do_popdown(self, current, frame):
|
||||
if self._menu:
|
||||
self._menu.destroy()
|
||||
self._menu = None
|
||||
self._menu_shell.set_active(None)
|
||||
|
||||
def popdown(self):
|
||||
self._timeline.play('popdown', 'popdown')
|
||||
def popdown(self):
|
||||
self._timeline.play('popdown', 'popdown')
|
||||
|
||||
def _motion_notify_event_cb(self, item, event):
|
||||
if event.detail == hippo.MOTION_DETAIL_ENTER:
|
||||
self._timeline.play(None, 'popup')
|
||||
elif event.detail == hippo.MOTION_DETAIL_LEAVE:
|
||||
if not self._hover_menu:
|
||||
self._timeline.play('before_popdown', 'popdown')
|
||||
def _motion_notify_event_cb(self, item, event):
|
||||
if event.detail == hippo.MOTION_DETAIL_ENTER:
|
||||
self._timeline.play(None, 'popup')
|
||||
elif event.detail == hippo.MOTION_DETAIL_LEAVE:
|
||||
if not self._hover_menu:
|
||||
self._timeline.play('before_popdown', 'popdown')
|
||||
|
||||
def _menu_enter_notify_event_cb(self, widget, event):
|
||||
self._hover_menu = True
|
||||
self._timeline.play('popup', 'popup')
|
||||
def _menu_enter_notify_event_cb(self, widget, event):
|
||||
self._hover_menu = True
|
||||
self._timeline.play('popup', 'popup')
|
||||
|
||||
def _menu_leave_notify_event_cb(self, widget, event):
|
||||
self._hover_menu = False
|
||||
self._timeline.play('popdown', 'popdown')
|
||||
def _menu_leave_notify_event_cb(self, widget, event):
|
||||
self._hover_menu = False
|
||||
self._timeline.play('popdown', 'popdown')
|
||||
|
||||
+63
-63
@@ -19,83 +19,83 @@ import gobject
|
||||
import gtk
|
||||
|
||||
class MenuShell(gobject.GObject):
|
||||
__gsignals__ = {
|
||||
'activated': (gobject.SIGNAL_RUN_FIRST,
|
||||
gobject.TYPE_NONE, ([])),
|
||||
'deactivated': (gobject.SIGNAL_RUN_FIRST,
|
||||
gobject.TYPE_NONE, ([])),
|
||||
}
|
||||
__gsignals__ = {
|
||||
'activated': (gobject.SIGNAL_RUN_FIRST,
|
||||
gobject.TYPE_NONE, ([])),
|
||||
'deactivated': (gobject.SIGNAL_RUN_FIRST,
|
||||
gobject.TYPE_NONE, ([])),
|
||||
}
|
||||
|
||||
AUTO = 0
|
||||
LEFT = 1
|
||||
RIGHT = 2
|
||||
TOP = 3
|
||||
BOTTOM = 4
|
||||
AUTO = 0
|
||||
LEFT = 1
|
||||
RIGHT = 2
|
||||
TOP = 3
|
||||
BOTTOM = 4
|
||||
|
||||
def __init__(self, parent_canvas):
|
||||
gobject.GObject.__init__(self)
|
||||
def __init__(self, parent_canvas):
|
||||
gobject.GObject.__init__(self)
|
||||
|
||||
self._parent_canvas = parent_canvas
|
||||
self._menu_controller = None
|
||||
self._position = MenuShell.AUTO
|
||||
self._parent_canvas = parent_canvas
|
||||
self._menu_controller = None
|
||||
self._position = MenuShell.AUTO
|
||||
|
||||
def set_position(self, position):
|
||||
self._position = position
|
||||
def set_position(self, position):
|
||||
self._position = position
|
||||
|
||||
def is_active(self):
|
||||
return (self._menu_controller != None)
|
||||
def is_active(self):
|
||||
return (self._menu_controller != None)
|
||||
|
||||
def set_active(self, controller):
|
||||
if controller == None:
|
||||
self.emit('deactivated')
|
||||
else:
|
||||
self.emit('activated')
|
||||
def set_active(self, controller):
|
||||
if controller == None:
|
||||
self.emit('deactivated')
|
||||
else:
|
||||
self.emit('activated')
|
||||
|
||||
if self._menu_controller:
|
||||
self._menu_controller.popdown()
|
||||
self._menu_controller = controller
|
||||
if self._menu_controller:
|
||||
self._menu_controller.popdown()
|
||||
self._menu_controller = controller
|
||||
|
||||
def _get_item_rect(self, item):
|
||||
[x, y] = item.get_context().translate_to_widget(item)
|
||||
def _get_item_rect(self, item):
|
||||
[x, y] = item.get_context().translate_to_widget(item)
|
||||
|
||||
[origin_x, origin_y] = self._parent_canvas.window.get_origin()
|
||||
x += origin_x
|
||||
y += origin_y
|
||||
[origin_x, origin_y] = self._parent_canvas.window.get_origin()
|
||||
x += origin_x
|
||||
y += origin_y
|
||||
|
||||
[w, h] = item.get_allocation()
|
||||
[w, h] = item.get_allocation()
|
||||
|
||||
return [x, y, w, h]
|
||||
return [x, y, w, h]
|
||||
|
||||
def get_position(self, menu, item):
|
||||
[item_x, item_y, item_w, item_h] = self._get_item_rect(item)
|
||||
[menu_w, menu_h] = menu.size_request()
|
||||
def get_position(self, menu, item):
|
||||
[item_x, item_y, item_w, item_h] = self._get_item_rect(item)
|
||||
[menu_w, menu_h] = menu.size_request()
|
||||
|
||||
left_x = item_x - menu_w
|
||||
left_y = item_y
|
||||
right_x = item_x + item_w
|
||||
right_y = item_y
|
||||
top_x = item_x
|
||||
top_y = item_y - menu_h
|
||||
bottom_x = item_x
|
||||
bottom_y = item_y + item_h
|
||||
left_x = item_x - menu_w
|
||||
left_y = item_y
|
||||
right_x = item_x + item_w
|
||||
right_y = item_y
|
||||
top_x = item_x
|
||||
top_y = item_y - menu_h
|
||||
bottom_x = item_x
|
||||
bottom_y = item_y + item_h
|
||||
|
||||
if self._position == MenuShell.LEFT:
|
||||
[x, y] = [left_x, left_y]
|
||||
elif self._position == MenuShell.RIGHT:
|
||||
[x, y] = [right_x, right_y]
|
||||
elif self._position == MenuShell.TOP:
|
||||
[x, y] = [top_x, top_y]
|
||||
elif self._position == MenuShell.BOTTOM:
|
||||
[x, y] = [bottom_x, bottom_y]
|
||||
elif self._position == MenuShell.AUTO:
|
||||
[x, y] = [right_x, right_y]
|
||||
if x + menu_w > gtk.gdk.screen_width():
|
||||
[x, y] = [left_x, left_y]
|
||||
if self._position == MenuShell.LEFT:
|
||||
[x, y] = [left_x, left_y]
|
||||
elif self._position == MenuShell.RIGHT:
|
||||
[x, y] = [right_x, right_y]
|
||||
elif self._position == MenuShell.TOP:
|
||||
[x, y] = [top_x, top_y]
|
||||
elif self._position == MenuShell.BOTTOM:
|
||||
[x, y] = [bottom_x, bottom_y]
|
||||
elif self._position == MenuShell.AUTO:
|
||||
[x, y] = [right_x, right_y]
|
||||
if x + menu_w > gtk.gdk.screen_width():
|
||||
[x, y] = [left_x, left_y]
|
||||
|
||||
x = min(x, gtk.gdk.screen_width() - menu_w)
|
||||
x = max(0, x)
|
||||
x = min(x, gtk.gdk.screen_width() - menu_w)
|
||||
x = max(0, x)
|
||||
|
||||
y = min(y, gtk.gdk.screen_height() - menu_h)
|
||||
y = max(0, y)
|
||||
y = min(y, gtk.gdk.screen_height() - menu_h)
|
||||
y = max(0, y)
|
||||
|
||||
return [x, y]
|
||||
return [x, y]
|
||||
|
||||
@@ -25,72 +25,72 @@ _CHILDREN_FACTOR = 1
|
||||
_FLAKE_DISTANCE = 6
|
||||
|
||||
class SnowflakeBox(hippo.CanvasBox, hippo.CanvasItem):
|
||||
__gtype_name__ = 'SugarSnowflakeBox'
|
||||
def __init__(self, **kwargs):
|
||||
hippo.CanvasBox.__init__(self, **kwargs)
|
||||
self._root = None
|
||||
__gtype_name__ = 'SugarSnowflakeBox'
|
||||
def __init__(self, **kwargs):
|
||||
hippo.CanvasBox.__init__(self, **kwargs)
|
||||
self._root = None
|
||||
|
||||
def set_root(self, icon):
|
||||
self._root = icon
|
||||
def set_root(self, icon):
|
||||
self._root = icon
|
||||
|
||||
def _get_center(self):
|
||||
[width, height] = self.get_allocation()
|
||||
return [width / 2, height / 2]
|
||||
def _get_center(self):
|
||||
[width, height] = self.get_allocation()
|
||||
return [width / 2, height / 2]
|
||||
|
||||
def _get_radius(self):
|
||||
return _BASE_RADIUS + _CHILDREN_FACTOR * self._get_n_children()
|
||||
def _get_radius(self):
|
||||
return _BASE_RADIUS + _CHILDREN_FACTOR * self._get_n_children()
|
||||
|
||||
def _layout_root(self):
|
||||
[width, height] = self._root.get_allocation()
|
||||
[cx, cy] = self._get_center()
|
||||
def _layout_root(self):
|
||||
[width, height] = self._root.get_allocation()
|
||||
[cx, cy] = self._get_center()
|
||||
|
||||
x = cx - (width / 2)
|
||||
y = cy - (height / 2)
|
||||
x = cx - (width / 2)
|
||||
y = cy - (height / 2)
|
||||
|
||||
self.move(self._root, int(x), int(y))
|
||||
self.move(self._root, int(x), int(y))
|
||||
|
||||
def _get_n_children(self):
|
||||
return len(self.get_children()) - 1
|
||||
def _get_n_children(self):
|
||||
return len(self.get_children()) - 1
|
||||
|
||||
def _layout_child(self, child, index):
|
||||
r = self._get_radius()
|
||||
if (self._get_n_children() > 10):
|
||||
r += _FLAKE_DISTANCE * (index % 3)
|
||||
def _layout_child(self, child, index):
|
||||
r = self._get_radius()
|
||||
if (self._get_n_children() > 10):
|
||||
r += _FLAKE_DISTANCE * (index % 3)
|
||||
|
||||
angle = 2 * math.pi * index / self._get_n_children()
|
||||
angle = 2 * math.pi * index / self._get_n_children()
|
||||
|
||||
[width, height] = child.get_allocation()
|
||||
[cx, cy] = self._get_center()
|
||||
[width, height] = child.get_allocation()
|
||||
[cx, cy] = self._get_center()
|
||||
|
||||
x = cx + math.cos(angle) * r - (width / 2)
|
||||
y = cy + math.sin(angle) * r - (height / 2)
|
||||
x = cx + math.cos(angle) * r - (width / 2)
|
||||
y = cy + math.sin(angle) * r - (height / 2)
|
||||
|
||||
self.move(child, int(x), int(y))
|
||||
self.move(child, int(x), int(y))
|
||||
|
||||
def do_get_width_request(self):
|
||||
hippo.CanvasBox.do_get_width_request(self)
|
||||
def do_get_width_request(self):
|
||||
hippo.CanvasBox.do_get_width_request(self)
|
||||
|
||||
max_child_size = 0
|
||||
for child in self.get_children():
|
||||
width = child.get_width_request()
|
||||
height = child.get_height_request(width)
|
||||
max_child_size = max (max_child_size, width)
|
||||
max_child_size = max (max_child_size, height)
|
||||
max_child_size = 0
|
||||
for child in self.get_children():
|
||||
width = child.get_width_request()
|
||||
height = child.get_height_request(width)
|
||||
max_child_size = max (max_child_size, width)
|
||||
max_child_size = max (max_child_size, height)
|
||||
|
||||
return self._get_radius() * 2 + \
|
||||
max_child_size + _FLAKE_DISTANCE * 2
|
||||
return self._get_radius() * 2 + \
|
||||
max_child_size + _FLAKE_DISTANCE * 2
|
||||
|
||||
def do_get_height_request(self, width):
|
||||
hippo.CanvasBox.do_get_height_request(self, width)
|
||||
return width
|
||||
def do_get_height_request(self, width):
|
||||
hippo.CanvasBox.do_get_height_request(self, width)
|
||||
return width
|
||||
|
||||
def do_allocate(self, width, height):
|
||||
hippo.CanvasBox.do_allocate(self, width, height)
|
||||
def do_allocate(self, width, height):
|
||||
hippo.CanvasBox.do_allocate(self, width, height)
|
||||
|
||||
self._layout_root()
|
||||
self._layout_root()
|
||||
|
||||
index = 0
|
||||
for child in self.get_children():
|
||||
if child != self._root:
|
||||
self._layout_child(child, index)
|
||||
index += 1
|
||||
index = 0
|
||||
for child in self.get_children():
|
||||
if child != self._root:
|
||||
self._layout_child(child, index)
|
||||
index += 1
|
||||
|
||||
+76
-76
@@ -25,108 +25,108 @@ _DISTANCE_THRESHOLD = 10.0
|
||||
_FORCE_CONSTANT = 0.1
|
||||
|
||||
class SpreadBox(hippo.CanvasBox, hippo.CanvasItem):
|
||||
__gtype_name__ = 'SugarSpreadBox'
|
||||
__gtype_name__ = 'SugarSpreadBox'
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
hippo.CanvasBox.__init__(self, **kwargs)
|
||||
def __init__(self, **kwargs):
|
||||
hippo.CanvasBox.__init__(self, **kwargs)
|
||||
|
||||
self._items_to_position = []
|
||||
self._stable = False
|
||||
self._items_to_position = []
|
||||
self._stable = False
|
||||
|
||||
def add_item(self, item):
|
||||
self._items_to_position.append(item)
|
||||
self.append(item, hippo.PACK_FIXED)
|
||||
def add_item(self, item):
|
||||
self._items_to_position.append(item)
|
||||
self.append(item, hippo.PACK_FIXED)
|
||||
|
||||
def remove_item(self, item):
|
||||
if self._items_to_position.count(item) > 0:
|
||||
self._items_to_position.remove(item)
|
||||
self.remove(item)
|
||||
def remove_item(self, item):
|
||||
if self._items_to_position.count(item) > 0:
|
||||
self._items_to_position.remove(item)
|
||||
self.remove(item)
|
||||
|
||||
def _get_item_radius(self, item):
|
||||
[width, height] = item.get_request()
|
||||
return math.sqrt(width ** 2 + height ** 2) / 2
|
||||
def _get_item_radius(self, item):
|
||||
[width, height] = item.get_request()
|
||||
return math.sqrt(width ** 2 + height ** 2) / 2
|
||||
|
||||
def _get_item_center(self, item):
|
||||
[width, height] = item.get_request()
|
||||
[x, y] = self.get_position(item)
|
||||
def _get_item_center(self, item):
|
||||
[width, height] = item.get_request()
|
||||
[x, y] = self.get_position(item)
|
||||
|
||||
c_x = int(x + float(width) / 2.0)
|
||||
c_y = int(y + float(height) / 2.0)
|
||||
c_x = int(x + float(width) / 2.0)
|
||||
c_y = int(y + float(height) / 2.0)
|
||||
|
||||
return [c_x, c_y]
|
||||
return [c_x, c_y]
|
||||
|
||||
def _get_repulsion(self, icon1, icon2):
|
||||
[c1_x, c1_y] = self._get_item_center(icon1)
|
||||
[c2_x, c2_y] = self._get_item_center(icon2)
|
||||
def _get_repulsion(self, icon1, icon2):
|
||||
[c1_x, c1_y] = self._get_item_center(icon1)
|
||||
[c2_x, c2_y] = self._get_item_center(icon2)
|
||||
|
||||
a = c2_x - c1_x
|
||||
b = c2_y - c1_y
|
||||
a = c2_x - c1_x
|
||||
b = c2_y - c1_y
|
||||
|
||||
r1 = self._get_item_radius(icon1)
|
||||
r2 = self._get_item_radius(icon2)
|
||||
distance = math.sqrt(a ** 2 + b ** 2) - r1 - r2
|
||||
r1 = self._get_item_radius(icon1)
|
||||
r2 = self._get_item_radius(icon2)
|
||||
distance = math.sqrt(a ** 2 + b ** 2) - r1 - r2
|
||||
|
||||
if distance < _DISTANCE_THRESHOLD:
|
||||
f_x = int(math.ceil(-_FORCE_CONSTANT * float(a)))
|
||||
f_y = int(math.ceil(-_FORCE_CONSTANT * float(b)))
|
||||
else:
|
||||
f_x = 0
|
||||
f_y = 0
|
||||
if distance < _DISTANCE_THRESHOLD:
|
||||
f_x = int(math.ceil(-_FORCE_CONSTANT * float(a)))
|
||||
f_y = int(math.ceil(-_FORCE_CONSTANT * float(b)))
|
||||
else:
|
||||
f_x = 0
|
||||
f_y = 0
|
||||
|
||||
return [f_x, f_y]
|
||||
return [f_x, f_y]
|
||||
|
||||
def _clamp_position(self, icon, x, y):
|
||||
x = max(0, x)
|
||||
y = max(0, y)
|
||||
def _clamp_position(self, icon, x, y):
|
||||
x = max(0, x)
|
||||
y = max(0, y)
|
||||
|
||||
[item_w, item_h] = icon.get_request()
|
||||
[box_w, box_h] = self.get_allocation()
|
||||
[item_w, item_h] = icon.get_request()
|
||||
[box_w, box_h] = self.get_allocation()
|
||||
|
||||
x = min(box_w - item_w, x)
|
||||
y = min(box_h - item_h, y)
|
||||
x = min(box_w - item_w, x)
|
||||
y = min(box_h - item_h, y)
|
||||
|
||||
return [x, y]
|
||||
return [x, y]
|
||||
|
||||
def _spread_icons(self):
|
||||
self._stable = True
|
||||
def _spread_icons(self):
|
||||
self._stable = True
|
||||
|
||||
for icon1 in self.get_children():
|
||||
vx = 0
|
||||
vy = 0
|
||||
for icon1 in self.get_children():
|
||||
vx = 0
|
||||
vy = 0
|
||||
|
||||
for icon2 in self.get_children():
|
||||
if icon1 != icon2:
|
||||
[f_x, f_y] = self._get_repulsion(icon1, icon2)
|
||||
if f_x != 0 or f_y != 0:
|
||||
self._stable = False
|
||||
vx += f_x
|
||||
vy += f_y
|
||||
for icon2 in self.get_children():
|
||||
if icon1 != icon2:
|
||||
[f_x, f_y] = self._get_repulsion(icon1, icon2)
|
||||
if f_x != 0 or f_y != 0:
|
||||
self._stable = False
|
||||
vx += f_x
|
||||
vy += f_y
|
||||
|
||||
if vx != 0 or vy != 0:
|
||||
[x, y] = self.get_position(icon1)
|
||||
new_x = x + vx
|
||||
new_y = y + vy
|
||||
if vx != 0 or vy != 0:
|
||||
[x, y] = self.get_position(icon1)
|
||||
new_x = x + vx
|
||||
new_y = y + vy
|
||||
|
||||
[new_x, new_y] = self._clamp_position(icon1, new_x, new_y)
|
||||
[new_x, new_y] = self._clamp_position(icon1, new_x, new_y)
|
||||
|
||||
self.move(icon1, new_x, new_y)
|
||||
self.move(icon1, new_x, new_y)
|
||||
|
||||
def do_allocate(self, width, height):
|
||||
hippo.CanvasBox.do_allocate(self, width, height)
|
||||
def do_allocate(self, width, height):
|
||||
hippo.CanvasBox.do_allocate(self, width, height)
|
||||
|
||||
for item in self._items_to_position:
|
||||
[item_w, item_h] = item.get_request()
|
||||
for item in self._items_to_position:
|
||||
[item_w, item_h] = item.get_request()
|
||||
|
||||
x = int(random.random() * width - item_w)
|
||||
y = int(random.random() * height - item_h)
|
||||
x = int(random.random() * width - item_w)
|
||||
y = int(random.random() * height - item_h)
|
||||
|
||||
[x, y] = self._clamp_position(item, x, y)
|
||||
self.move(item, x, y)
|
||||
[x, y] = self._clamp_position(item, x, y)
|
||||
self.move(item, x, y)
|
||||
|
||||
self._items_to_position = []
|
||||
self._items_to_position = []
|
||||
|
||||
tries = 20
|
||||
self._spread_icons()
|
||||
while not self._stable and tries > 0:
|
||||
self._spread_icons()
|
||||
tries -= 1
|
||||
tries = 20
|
||||
self._spread_icons()
|
||||
while not self._stable and tries > 0:
|
||||
self._spread_icons()
|
||||
tries -= 1
|
||||
|
||||
+12
-12
@@ -31,21 +31,21 @@ large_icon_size = standard_icon_size * 2.0
|
||||
xlarge_icon_size = standard_icon_size * 3.0
|
||||
|
||||
def load_stylesheet(module):
|
||||
for objname in dir(module):
|
||||
if not objname.startswith('_'):
|
||||
obj = getattr(module, objname)
|
||||
if isinstance(obj, dict):
|
||||
register_stylesheet(objname.replace('_', '.'), obj)
|
||||
for objname in dir(module):
|
||||
if not objname.startswith('_'):
|
||||
obj = getattr(module, objname)
|
||||
if isinstance(obj, dict):
|
||||
register_stylesheet(objname.replace('_', '.'), obj)
|
||||
|
||||
def register_stylesheet(name, style):
|
||||
_styles[name] = style
|
||||
_styles[name] = style
|
||||
|
||||
def apply_stylesheet(item, stylesheet_name):
|
||||
if _styles.has_key(stylesheet_name):
|
||||
style_sheet = _styles[stylesheet_name]
|
||||
for name in style_sheet.keys():
|
||||
item.set_property(name, style_sheet[name])
|
||||
if _styles.has_key(stylesheet_name):
|
||||
style_sheet = _styles[stylesheet_name]
|
||||
for name in style_sheet.keys():
|
||||
item.set_property(name, style_sheet[name])
|
||||
|
||||
def get_font_description(style, relative_size):
|
||||
base_size = 18 * _screen_factor
|
||||
return '%s %dpx' % (style, int(base_size * relative_size))
|
||||
base_size = 18 * _screen_factor
|
||||
return '%s %dpx' % (style, int(base_size * relative_size))
|
||||
|
||||
@@ -1,31 +1,31 @@
|
||||
from sugar.graphics import style
|
||||
|
||||
menu = {
|
||||
'background_color' : 0x000000FF,
|
||||
'spacing' : style.space_unit,
|
||||
'padding' : style.space_unit
|
||||
'background_color' : 0x000000FF,
|
||||
'spacing' : style.space_unit,
|
||||
'padding' : style.space_unit
|
||||
}
|
||||
|
||||
menu_Title = {
|
||||
'color' : 0xFFFFFFFF,
|
||||
'font' : style.get_font_description('Bold', 1.2)
|
||||
'color' : 0xFFFFFFFF,
|
||||
'font' : style.get_font_description('Bold', 1.2)
|
||||
}
|
||||
|
||||
menu_Separator = {
|
||||
'background_color' : 0xFFFFFFFF,
|
||||
'box_height' : style.separator_thickness
|
||||
'background_color' : 0xFFFFFFFF,
|
||||
'box_height' : style.separator_thickness
|
||||
}
|
||||
|
||||
menu_ActionIcon = {
|
||||
'size' : style.standard_icon_size
|
||||
'size' : style.standard_icon_size
|
||||
}
|
||||
|
||||
menu_Item = {
|
||||
'color' : 0xFFFFFFFF,
|
||||
'font' : style.get_font_description('Plain', 1.1)
|
||||
'color' : 0xFFFFFFFF,
|
||||
'font' : style.get_font_description('Plain', 1.1)
|
||||
}
|
||||
|
||||
menu_Text = {
|
||||
'color' : 0xFFFFFFFF,
|
||||
'font' : style.get_font_description('Plain', 1.2)
|
||||
'color' : 0xFFFFFFFF,
|
||||
'font' : style.get_font_description('Plain', 1.2)
|
||||
}
|
||||
|
||||
+75
-75
@@ -18,100 +18,100 @@
|
||||
import gobject
|
||||
|
||||
class _Tag:
|
||||
def __init__(self, name, start_frame, end_frame):
|
||||
self.name = name
|
||||
self.start_frame = start_frame
|
||||
self.end_frame = end_frame
|
||||
def __init__(self, name, start_frame, end_frame):
|
||||
self.name = name
|
||||
self.start_frame = start_frame
|
||||
self.end_frame = end_frame
|
||||
|
||||
class TimelineObserver:
|
||||
def __init__(self, observer):
|
||||
self._observer = observer
|
||||
def __init__(self, observer):
|
||||
self._observer = observer
|
||||
|
||||
def next_frame(self, tag, current_frame, n_frames):
|
||||
try:
|
||||
method = getattr(self._observer, 'do_' + tag)
|
||||
except AttributeError:
|
||||
method = None
|
||||
def next_frame(self, tag, current_frame, n_frames):
|
||||
try:
|
||||
method = getattr(self._observer, 'do_' + tag)
|
||||
except AttributeError:
|
||||
method = None
|
||||
|
||||
if method:
|
||||
method(current_frame, n_frames)
|
||||
if method:
|
||||
method(current_frame, n_frames)
|
||||
|
||||
class Timeline:
|
||||
def __init__(self, observer):
|
||||
self._fps = 12
|
||||
self._tags = []
|
||||
self._name_to_tag = {}
|
||||
self._current_frame = 0
|
||||
self._timeout_sid = 0
|
||||
self._observer = TimelineObserver(observer)
|
||||
def __init__(self, observer):
|
||||
self._fps = 12
|
||||
self._tags = []
|
||||
self._name_to_tag = {}
|
||||
self._current_frame = 0
|
||||
self._timeout_sid = 0
|
||||
self._observer = TimelineObserver(observer)
|
||||
|
||||
def add_tag(self, name, start_frame, end_frame):
|
||||
tag = _Tag(name, start_frame, end_frame)
|
||||
self._tags.append(tag)
|
||||
self._name_to_tag[name] = tag
|
||||
def add_tag(self, name, start_frame, end_frame):
|
||||
tag = _Tag(name, start_frame, end_frame)
|
||||
self._tags.append(tag)
|
||||
self._name_to_tag[name] = tag
|
||||
|
||||
def remove_tag(self, name):
|
||||
tag = self._tags[name]
|
||||
self._tags.remove(tag)
|
||||
del self._tags[name]
|
||||
def remove_tag(self, name):
|
||||
tag = self._tags[name]
|
||||
self._tags.remove(tag)
|
||||
del self._tags[name]
|
||||
|
||||
def _next_frame(self, tag, frame):
|
||||
n_frames = tag.start_frame - tag.end_frame
|
||||
self._observer.next_frame(tag.name, frame, n_frames)
|
||||
def _next_frame(self, tag, frame):
|
||||
n_frames = tag.start_frame - tag.end_frame
|
||||
self._observer.next_frame(tag.name, frame, n_frames)
|
||||
|
||||
def goto(self, tag_name, end_frame=False):
|
||||
self.pause()
|
||||
def goto(self, tag_name, end_frame=False):
|
||||
self.pause()
|
||||
|
||||
tag = self._name_to_tag[tag_name]
|
||||
if end_frame:
|
||||
self._current_frame = tag.end_frame
|
||||
else:
|
||||
self._current_frame = tag.start_frame
|
||||
tag = self._name_to_tag[tag_name]
|
||||
if end_frame:
|
||||
self._current_frame = tag.end_frame
|
||||
else:
|
||||
self._current_frame = tag.start_frame
|
||||
|
||||
self._next_frame(tag, self._current_frame)
|
||||
self._next_frame(tag, self._current_frame)
|
||||
|
||||
def on_tag(self, name):
|
||||
tag = self._name_to_tag[name]
|
||||
return (tag.start_frame <= self._current_frame and \
|
||||
tag.end_frame >= self._current_frame)
|
||||
def on_tag(self, name):
|
||||
tag = self._name_to_tag[name]
|
||||
return (tag.start_frame <= self._current_frame and \
|
||||
tag.end_frame >= self._current_frame)
|
||||
|
||||
def _get_tags_for_frame(self, frame):
|
||||
result = []
|
||||
for tag in self._tags:
|
||||
if tag.start_frame <= frame and tag.end_frame >= frame:
|
||||
result.append(tag)
|
||||
return result
|
||||
def _get_tags_for_frame(self, frame):
|
||||
result = []
|
||||
for tag in self._tags:
|
||||
if tag.start_frame <= frame and tag.end_frame >= frame:
|
||||
result.append(tag)
|
||||
return result
|
||||
|
||||
def _timeout_cb(self, end_frame):
|
||||
for tag in self._get_tags_for_frame(self._current_frame):
|
||||
cur_frame = self._current_frame - tag.start_frame
|
||||
self._next_frame(tag, cur_frame)
|
||||
def _timeout_cb(self, end_frame):
|
||||
for tag in self._get_tags_for_frame(self._current_frame):
|
||||
cur_frame = self._current_frame - tag.start_frame
|
||||
self._next_frame(tag, cur_frame)
|
||||
|
||||
if self._current_frame < end_frame:
|
||||
self._current_frame += 1
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
if self._current_frame < end_frame:
|
||||
self._current_frame += 1
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def play(self, start_tag=None, stop_tag=None):
|
||||
self.pause()
|
||||
def play(self, start_tag=None, stop_tag=None):
|
||||
self.pause()
|
||||
|
||||
if start_tag == None:
|
||||
start = 0
|
||||
else:
|
||||
start = self._name_to_tag[start_tag].start_frame
|
||||
if start_tag == None:
|
||||
start = 0
|
||||
else:
|
||||
start = self._name_to_tag[start_tag].start_frame
|
||||
|
||||
if stop_tag == None:
|
||||
end = self._tags[len(self._tags) - 1].end_frame
|
||||
else:
|
||||
end = self._name_to_tag[stop_tag].end_frame
|
||||
if stop_tag == None:
|
||||
end = self._tags[len(self._tags) - 1].end_frame
|
||||
else:
|
||||
end = self._name_to_tag[stop_tag].end_frame
|
||||
|
||||
self._current_frame = start
|
||||
self._current_frame = start
|
||||
|
||||
interval = 1000 / self._fps
|
||||
self._timeout_sid = gobject.timeout_add(
|
||||
interval, self._timeout_cb, end)
|
||||
interval = 1000 / self._fps
|
||||
self._timeout_sid = gobject.timeout_add(
|
||||
interval, self._timeout_cb, end)
|
||||
|
||||
def pause(self):
|
||||
if self._timeout_sid > 0:
|
||||
gobject.source_remove(self._timeout_sid)
|
||||
def pause(self):
|
||||
if self._timeout_sid > 0:
|
||||
gobject.source_remove(self._timeout_sid)
|
||||
|
||||
+55
-55
@@ -29,82 +29,82 @@ STDOUT_LEVEL = 1000
|
||||
STDERR_LEVEL = 2000
|
||||
|
||||
class LogWriter:
|
||||
def __init__(self, module_id):
|
||||
self._module_id = module_id
|
||||
def __init__(self, module_id):
|
||||
self._module_id = module_id
|
||||
|
||||
logs_dir = _get_logs_dir()
|
||||
log_path = os.path.join(logs_dir, module_id + '.log')
|
||||
self._log_file = open(log_path, 'w')
|
||||
logs_dir = _get_logs_dir()
|
||||
log_path = os.path.join(logs_dir, module_id + '.log')
|
||||
self._log_file = open(log_path, 'w')
|
||||
|
||||
def write_record(self, record):
|
||||
self.write(record.levelno, record.msg)
|
||||
def write_record(self, record):
|
||||
self.write(record.levelno, record.msg)
|
||||
|
||||
def write(self, level, msg):
|
||||
if level == logging.ERROR:
|
||||
level_txt = 'ERROR'
|
||||
elif level == logging.WARNING:
|
||||
level_txt = 'WARNING'
|
||||
elif level == logging.DEBUG:
|
||||
level_txt = 'DEBUG'
|
||||
elif level == logging.INFO:
|
||||
level_txt = 'INFO'
|
||||
elif level == STDERR_LEVEL:
|
||||
level_txt = 'STDERR'
|
||||
elif level == STDOUT_LEVEL:
|
||||
level_txt = 'STDOUT'
|
||||
def write(self, level, msg):
|
||||
if level == logging.ERROR:
|
||||
level_txt = 'ERROR'
|
||||
elif level == logging.WARNING:
|
||||
level_txt = 'WARNING'
|
||||
elif level == logging.DEBUG:
|
||||
level_txt = 'DEBUG'
|
||||
elif level == logging.INFO:
|
||||
level_txt = 'INFO'
|
||||
elif level == STDERR_LEVEL:
|
||||
level_txt = 'STDERR'
|
||||
elif level == STDOUT_LEVEL:
|
||||
level_txt = 'STDOUT'
|
||||
|
||||
fmt = "%s - %s\n" % (level_txt, msg)
|
||||
fmt = fmt.encode("utf8")
|
||||
self._log_file.write(fmt)
|
||||
self._log_file.flush()
|
||||
fmt = "%s - %s\n" % (level_txt, msg)
|
||||
fmt = fmt.encode("utf8")
|
||||
self._log_file.write(fmt)
|
||||
self._log_file.flush()
|
||||
|
||||
class Handler(logging.Handler):
|
||||
def __init__(self, writer):
|
||||
logging.Handler.__init__(self)
|
||||
def __init__(self, writer):
|
||||
logging.Handler.__init__(self)
|
||||
|
||||
self._writer = writer
|
||||
self._writer = writer
|
||||
|
||||
def emit(self, record):
|
||||
self._writer.write_record(record)
|
||||
def emit(self, record):
|
||||
self._writer.write_record(record)
|
||||
|
||||
class StdoutCatcher:
|
||||
def write(self, txt):
|
||||
_log_writer.write(STDOUT_LEVEL, txt)
|
||||
sys.__stdout__.write(txt)
|
||||
def write(self, txt):
|
||||
_log_writer.write(STDOUT_LEVEL, txt)
|
||||
sys.__stdout__.write(txt)
|
||||
|
||||
class StderrCatcher:
|
||||
def write(self, txt):
|
||||
_log_writer.write(STDERR_LEVEL, txt)
|
||||
sys.__stderr__.write(txt)
|
||||
def write(self, txt):
|
||||
_log_writer.write(STDERR_LEVEL, txt)
|
||||
sys.__stderr__.write(txt)
|
||||
|
||||
def __exception_handler(typ, exc, tb):
|
||||
trace = StringIO()
|
||||
traceback.print_exception(typ, exc, tb, None, trace)
|
||||
print >> sys.stderr, trace.getvalue()
|
||||
trace = StringIO()
|
||||
traceback.print_exception(typ, exc, tb, None, trace)
|
||||
print >> sys.stderr, trace.getvalue()
|
||||
|
||||
_log_writer.write(logging.ERROR, trace.getvalue())
|
||||
_log_writer.write(logging.ERROR, trace.getvalue())
|
||||
|
||||
def _get_logs_dir():
|
||||
logs_dir = os.path.join(env.get_profile_path(), 'logs')
|
||||
if not os.path.isdir(logs_dir):
|
||||
os.makedirs(logs_dir)
|
||||
return logs_dir
|
||||
logs_dir = os.path.join(env.get_profile_path(), 'logs')
|
||||
if not os.path.isdir(logs_dir):
|
||||
os.makedirs(logs_dir)
|
||||
return logs_dir
|
||||
|
||||
def start(module_id):
|
||||
log_writer = LogWriter(module_id)
|
||||
log_writer = LogWriter(module_id)
|
||||
|
||||
root_logger = logging.getLogger('')
|
||||
root_logger.setLevel(logging.DEBUG)
|
||||
root_logger.addHandler(Handler(log_writer))
|
||||
root_logger = logging.getLogger('')
|
||||
root_logger.setLevel(logging.DEBUG)
|
||||
root_logger.addHandler(Handler(log_writer))
|
||||
|
||||
sys.stdout = StdoutCatcher()
|
||||
sys.stderr = StderrCatcher()
|
||||
sys.stdout = StdoutCatcher()
|
||||
sys.stderr = StderrCatcher()
|
||||
|
||||
global _log_writer
|
||||
_log_writer = log_writer
|
||||
sys.excepthook = __exception_handler
|
||||
global _log_writer
|
||||
_log_writer = log_writer
|
||||
sys.excepthook = __exception_handler
|
||||
|
||||
def cleanup():
|
||||
logs_dir = _get_logs_dir()
|
||||
for f in os.listdir(logs_dir):
|
||||
os.remove(os.path.join(logs_dir, f))
|
||||
logs_dir = _get_logs_dir()
|
||||
for f in os.listdir(logs_dir):
|
||||
os.remove(os.path.join(logs_dir, f))
|
||||
|
||||
+1102
-1102
File diff suppressed because it is too large
Load Diff
@@ -21,18 +21,18 @@ from sugar.p2p.Notifier import Notifier
|
||||
from sugar.p2p import network
|
||||
|
||||
class NotificationListener:
|
||||
def __init__(self, service):
|
||||
logging.debug('Start notification listener. Service %s, address %s, port %s' % (service.get_type(), service.get_address(), service.get_port()))
|
||||
server = network.GroupServer(service.get_address(),
|
||||
service.get_port(),
|
||||
self._recv_multicast)
|
||||
server.start()
|
||||
|
||||
self._listeners = []
|
||||
|
||||
def add_listener(self, listener):
|
||||
self._listeners.append(listener)
|
||||
|
||||
def _recv_multicast(self, msg):
|
||||
for listener in self._listeners:
|
||||
listener(msg)
|
||||
def __init__(self, service):
|
||||
logging.debug('Start notification listener. Service %s, address %s, port %s' % (service.get_type(), service.get_address(), service.get_port()))
|
||||
server = network.GroupServer(service.get_address(),
|
||||
service.get_port(),
|
||||
self._recv_multicast)
|
||||
server.start()
|
||||
|
||||
self._listeners = []
|
||||
|
||||
def add_listener(self, listener):
|
||||
self._listeners.append(listener)
|
||||
|
||||
def _recv_multicast(self, msg):
|
||||
for listener in self._listeners:
|
||||
listener(msg)
|
||||
|
||||
@@ -18,10 +18,10 @@
|
||||
from sugar.p2p import network
|
||||
|
||||
class Notifier:
|
||||
def __init__(self, service):
|
||||
address = service.get_address()
|
||||
port = service.get_port()
|
||||
self._client = network.GroupClient(address, port)
|
||||
|
||||
def notify(self, msg):
|
||||
self._client.send_msg(msg)
|
||||
def __init__(self, service):
|
||||
address = service.get_address()
|
||||
port = service.get_port()
|
||||
self._client = network.GroupClient(address, port)
|
||||
|
||||
def notify(self, msg):
|
||||
self._client.send_msg(msg)
|
||||
|
||||
+107
-107
@@ -26,135 +26,135 @@ from MostlyReliablePipe import MostlyReliablePipe
|
||||
from sugar.presence import Service
|
||||
|
||||
def is_multicast_address(address):
|
||||
"""Simple numerical check for whether an IP4 address
|
||||
is in the range for multicast addresses or not."""
|
||||
if not address:
|
||||
return False
|
||||
if address[3] != '.':
|
||||
return False
|
||||
first = int(float(address[:3]))
|
||||
if first >= 224 and first <= 239:
|
||||
return True
|
||||
return False
|
||||
"""Simple numerical check for whether an IP4 address
|
||||
is in the range for multicast addresses or not."""
|
||||
if not address:
|
||||
return False
|
||||
if address[3] != '.':
|
||||
return False
|
||||
first = int(float(address[:3]))
|
||||
if first >= 224 and first <= 239:
|
||||
return True
|
||||
return False
|
||||
|
||||
class Stream(object):
|
||||
def __init__(self, service):
|
||||
if not service.get_port():
|
||||
raise ValueError("service must have an address.")
|
||||
self._service = service
|
||||
self._reader_port = self._service.get_port()
|
||||
self._writer_port = self._reader_port
|
||||
self._address = self._service.get_address()
|
||||
self._callback = None
|
||||
def __init__(self, service):
|
||||
if not service.get_port():
|
||||
raise ValueError("service must have an address.")
|
||||
self._service = service
|
||||
self._reader_port = self._service.get_port()
|
||||
self._writer_port = self._reader_port
|
||||
self._address = self._service.get_address()
|
||||
self._callback = None
|
||||
|
||||
def new_from_service(service, start_reader=True):
|
||||
if is_multicast_address(service.get_address()):
|
||||
return MulticastStream(service)
|
||||
else:
|
||||
return UnicastStream(service, start_reader)
|
||||
new_from_service = staticmethod(new_from_service)
|
||||
def new_from_service(service, start_reader=True):
|
||||
if is_multicast_address(service.get_address()):
|
||||
return MulticastStream(service)
|
||||
else:
|
||||
return UnicastStream(service, start_reader)
|
||||
new_from_service = staticmethod(new_from_service)
|
||||
|
||||
def set_data_listener(self, callback):
|
||||
self._callback = callback
|
||||
def set_data_listener(self, callback):
|
||||
self._callback = callback
|
||||
|
||||
def _recv(self, address, data):
|
||||
if self._callback:
|
||||
self._callback(address, data)
|
||||
def _recv(self, address, data):
|
||||
if self._callback:
|
||||
self._callback(address, data)
|
||||
|
||||
|
||||
class UnicastStreamWriter(object):
|
||||
def __init__(self, stream, service):
|
||||
# set up the writer
|
||||
self._service = service
|
||||
if not service.get_address():
|
||||
raise ValueError("service must have a valid address.")
|
||||
self._address = self._service.get_address()
|
||||
self._port = self._service.get_port()
|
||||
self._xmlrpc_addr = "http://%s:%d" % (self._address, self._port)
|
||||
self._writer = network.GlibServerProxy(self._xmlrpc_addr)
|
||||
def __init__(self, stream, service):
|
||||
# set up the writer
|
||||
self._service = service
|
||||
if not service.get_address():
|
||||
raise ValueError("service must have a valid address.")
|
||||
self._address = self._service.get_address()
|
||||
self._port = self._service.get_port()
|
||||
self._xmlrpc_addr = "http://%s:%d" % (self._address, self._port)
|
||||
self._writer = network.GlibServerProxy(self._xmlrpc_addr)
|
||||
|
||||
def write(self, xmlrpc_data):
|
||||
"""Write some data to the default endpoint of this pipe on the remote server."""
|
||||
try:
|
||||
self._writer.message(None, None, xmlrpc_data)
|
||||
return True
|
||||
except (socket.error, xmlrpclib.Fault, xmlrpclib.ProtocolError):
|
||||
traceback.print_exc()
|
||||
return False
|
||||
def write(self, xmlrpc_data):
|
||||
"""Write some data to the default endpoint of this pipe on the remote server."""
|
||||
try:
|
||||
self._writer.message(None, None, xmlrpc_data)
|
||||
return True
|
||||
except (socket.error, xmlrpclib.Fault, xmlrpclib.ProtocolError):
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def custom_request(self, method_name, request_cb, user_data, *args):
|
||||
"""Call a custom XML-RPC method on the remote server."""
|
||||
try:
|
||||
method = getattr(self._writer, method_name)
|
||||
method(request_cb, user_data, *args)
|
||||
return True
|
||||
except (socket.error, xmlrpclib.Fault, xmlrpclib.ProtocolError):
|
||||
traceback.print_exc()
|
||||
return False
|
||||
def custom_request(self, method_name, request_cb, user_data, *args):
|
||||
"""Call a custom XML-RPC method on the remote server."""
|
||||
try:
|
||||
method = getattr(self._writer, method_name)
|
||||
method(request_cb, user_data, *args)
|
||||
return True
|
||||
except (socket.error, xmlrpclib.Fault, xmlrpclib.ProtocolError):
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
|
||||
class UnicastStream(Stream):
|
||||
def __init__(self, service, start_reader=True):
|
||||
"""Initializes the stream. If the 'start_reader' argument is True,
|
||||
the stream will initialize and start a new stream reader, if it
|
||||
is False, no reader will be created and the caller must call the
|
||||
start_reader() method to start the stream reader and be able to
|
||||
receive any data from the stream."""
|
||||
Stream.__init__(self, service)
|
||||
if start_reader:
|
||||
self.start_reader()
|
||||
def __init__(self, service, start_reader=True):
|
||||
"""Initializes the stream. If the 'start_reader' argument is True,
|
||||
the stream will initialize and start a new stream reader, if it
|
||||
is False, no reader will be created and the caller must call the
|
||||
start_reader() method to start the stream reader and be able to
|
||||
receive any data from the stream."""
|
||||
Stream.__init__(self, service)
|
||||
if start_reader:
|
||||
self.start_reader()
|
||||
|
||||
def start_reader(self):
|
||||
"""Start the stream's reader, which for UnicastStream objects is
|
||||
and XMLRPC server. If there's a port conflict with some other
|
||||
service, the reader will try to find another port to use instead.
|
||||
Returns the port number used for the reader."""
|
||||
# Set up the reader
|
||||
self._reader = network.GlibXMLRPCServer(("", self._reader_port))
|
||||
self._reader.register_function(self._message, "message")
|
||||
def start_reader(self):
|
||||
"""Start the stream's reader, which for UnicastStream objects is
|
||||
and XMLRPC server. If there's a port conflict with some other
|
||||
service, the reader will try to find another port to use instead.
|
||||
Returns the port number used for the reader."""
|
||||
# Set up the reader
|
||||
self._reader = network.GlibXMLRPCServer(("", self._reader_port))
|
||||
self._reader.register_function(self._message, "message")
|
||||
|
||||
def _message(self, message):
|
||||
"""Called by the XMLRPC server when network data arrives."""
|
||||
address = network.get_authinfo()
|
||||
self._recv(address, message)
|
||||
return True
|
||||
def _message(self, message):
|
||||
"""Called by the XMLRPC server when network data arrives."""
|
||||
address = network.get_authinfo()
|
||||
self._recv(address, message)
|
||||
return True
|
||||
|
||||
def register_reader_handler(self, handler, name):
|
||||
"""Register a custom message handler with the reader. This call
|
||||
adds a custom XMLRPC method call with the name 'name' to the reader's
|
||||
XMLRPC server, which then calls the 'handler' argument back when
|
||||
a method call for it arrives over the network."""
|
||||
if name == "message":
|
||||
raise ValueError("Handler name 'message' is a reserved handler.")
|
||||
self._reader.register_function(handler, name)
|
||||
def register_reader_handler(self, handler, name):
|
||||
"""Register a custom message handler with the reader. This call
|
||||
adds a custom XMLRPC method call with the name 'name' to the reader's
|
||||
XMLRPC server, which then calls the 'handler' argument back when
|
||||
a method call for it arrives over the network."""
|
||||
if name == "message":
|
||||
raise ValueError("Handler name 'message' is a reserved handler.")
|
||||
self._reader.register_function(handler, name)
|
||||
|
||||
def new_writer(self, service):
|
||||
"""Return a new stream writer object."""
|
||||
return UnicastStreamWriter(self, service)
|
||||
def new_writer(self, service):
|
||||
"""Return a new stream writer object."""
|
||||
return UnicastStreamWriter(self, service)
|
||||
|
||||
|
||||
class MulticastStream(Stream):
|
||||
def __init__(self, service):
|
||||
Stream.__init__(self, service)
|
||||
self._service = service
|
||||
self._internal_start_reader()
|
||||
def __init__(self, service):
|
||||
Stream.__init__(self, service)
|
||||
self._service = service
|
||||
self._internal_start_reader()
|
||||
|
||||
def start_reader(self):
|
||||
return self._reader_port
|
||||
def start_reader(self):
|
||||
return self._reader_port
|
||||
|
||||
def _internal_start_reader(self):
|
||||
logging.debug('Start multicast stream, address %s, port %d' % (self._address, self._reader_port))
|
||||
if not self._service.get_address():
|
||||
raise ValueError("service must have a valid address.")
|
||||
self._pipe = MostlyReliablePipe('', self._address, self._reader_port,
|
||||
self._recv_data_cb)
|
||||
self._pipe.start()
|
||||
def _internal_start_reader(self):
|
||||
logging.debug('Start multicast stream, address %s, port %d' % (self._address, self._reader_port))
|
||||
if not self._service.get_address():
|
||||
raise ValueError("service must have a valid address.")
|
||||
self._pipe = MostlyReliablePipe('', self._address, self._reader_port,
|
||||
self._recv_data_cb)
|
||||
self._pipe.start()
|
||||
|
||||
def write(self, data):
|
||||
self._pipe.send(data)
|
||||
def write(self, data):
|
||||
self._pipe.send(data)
|
||||
|
||||
def _recv_data_cb(self, address, data, user_data=None):
|
||||
self._recv(address[0], data)
|
||||
def _recv_data_cb(self, address, data, user_data=None):
|
||||
self._recv(address[0], data)
|
||||
|
||||
def new_writer(self, service=None):
|
||||
return self
|
||||
def new_writer(self, service=None):
|
||||
return self
|
||||
|
||||
+263
-263
@@ -35,347 +35,347 @@ RESULT_SUCCESS = 1
|
||||
__authinfos = {}
|
||||
|
||||
def _add_authinfo(authinfo):
|
||||
__authinfos[threading.currentThread()] = authinfo
|
||||
__authinfos[threading.currentThread()] = authinfo
|
||||
|
||||
def get_authinfo():
|
||||
return __authinfos.get(threading.currentThread())
|
||||
return __authinfos.get(threading.currentThread())
|
||||
|
||||
def _del_authinfo():
|
||||
del __authinfos[threading.currentThread()]
|
||||
del __authinfos[threading.currentThread()]
|
||||
|
||||
|
||||
class GlibTCPServer(SocketServer.TCPServer):
|
||||
"""GlibTCPServer
|
||||
"""GlibTCPServer
|
||||
|
||||
Integrate socket accept into glib mainloop.
|
||||
"""
|
||||
Integrate socket accept into glib mainloop.
|
||||
"""
|
||||
|
||||
allow_reuse_address = True
|
||||
request_queue_size = 20
|
||||
allow_reuse_address = True
|
||||
request_queue_size = 20
|
||||
|
||||
def __init__(self, server_address, RequestHandlerClass):
|
||||
SocketServer.TCPServer.__init__(self, server_address, RequestHandlerClass)
|
||||
self.socket.setblocking(0) # Set nonblocking
|
||||
def __init__(self, server_address, RequestHandlerClass):
|
||||
SocketServer.TCPServer.__init__(self, server_address, RequestHandlerClass)
|
||||
self.socket.setblocking(0) # Set nonblocking
|
||||
|
||||
# Watch the listener socket for data
|
||||
gobject.io_add_watch(self.socket, gobject.IO_IN, self._handle_accept)
|
||||
# Watch the listener socket for data
|
||||
gobject.io_add_watch(self.socket, gobject.IO_IN, self._handle_accept)
|
||||
|
||||
def _handle_accept(self, source, condition):
|
||||
"""Process incoming data on the server's socket by doing an accept()
|
||||
via handle_request()."""
|
||||
if not (condition & gobject.IO_IN):
|
||||
return True
|
||||
self.handle_request()
|
||||
return True
|
||||
def _handle_accept(self, source, condition):
|
||||
"""Process incoming data on the server's socket by doing an accept()
|
||||
via handle_request()."""
|
||||
if not (condition & gobject.IO_IN):
|
||||
return True
|
||||
self.handle_request()
|
||||
return True
|
||||
|
||||
class GlibXMLRPCRequestHandler(SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
|
||||
""" GlibXMLRPCRequestHandler
|
||||
|
||||
The stock SimpleXMLRPCRequestHandler and server don't allow any way to pass
|
||||
the client's address and/or SSL certificate into the function that actually
|
||||
_processes_ the request. So we have to store it in a thread-indexed dict.
|
||||
"""
|
||||
""" GlibXMLRPCRequestHandler
|
||||
|
||||
The stock SimpleXMLRPCRequestHandler and server don't allow any way to pass
|
||||
the client's address and/or SSL certificate into the function that actually
|
||||
_processes_ the request. So we have to store it in a thread-indexed dict.
|
||||
"""
|
||||
|
||||
def do_POST(self):
|
||||
_add_authinfo(self.client_address)
|
||||
try:
|
||||
SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.do_POST(self)
|
||||
except socket.timeout:
|
||||
pass
|
||||
except socket.error, e:
|
||||
print "Error (%s): socket error - '%s'" % (self.client_address, e)
|
||||
except:
|
||||
print "Error while processing POST:"
|
||||
traceback.print_exc()
|
||||
_del_authinfo()
|
||||
def do_POST(self):
|
||||
_add_authinfo(self.client_address)
|
||||
try:
|
||||
SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.do_POST(self)
|
||||
except socket.timeout:
|
||||
pass
|
||||
except socket.error, e:
|
||||
print "Error (%s): socket error - '%s'" % (self.client_address, e)
|
||||
except:
|
||||
print "Error while processing POST:"
|
||||
traceback.print_exc()
|
||||
_del_authinfo()
|
||||
|
||||
class GlibXMLRPCServer(GlibTCPServer, SimpleXMLRPCServer.SimpleXMLRPCDispatcher):
|
||||
"""GlibXMLRPCServer
|
||||
|
||||
Use nonblocking sockets and handle the accept via glib rather than
|
||||
blocking on accept().
|
||||
"""
|
||||
"""GlibXMLRPCServer
|
||||
|
||||
Use nonblocking sockets and handle the accept via glib rather than
|
||||
blocking on accept().
|
||||
"""
|
||||
|
||||
def __init__(self, addr, requestHandler=GlibXMLRPCRequestHandler, logRequests=0):
|
||||
self.logRequests = logRequests
|
||||
SimpleXMLRPCServer.SimpleXMLRPCDispatcher.__init__(self)
|
||||
GlibTCPServer.__init__(self, addr, requestHandler)
|
||||
def __init__(self, addr, requestHandler=GlibXMLRPCRequestHandler, logRequests=0):
|
||||
self.logRequests = logRequests
|
||||
SimpleXMLRPCServer.SimpleXMLRPCDispatcher.__init__(self)
|
||||
GlibTCPServer.__init__(self, addr, requestHandler)
|
||||
|
||||
def _marshaled_dispatch(self, data, dispatch_method = None):
|
||||
"""Dispatches an XML-RPC method from marshalled (XML) data.
|
||||
def _marshaled_dispatch(self, data, dispatch_method = None):
|
||||
"""Dispatches an XML-RPC method from marshalled (XML) data.
|
||||
|
||||
XML-RPC methods are dispatched from the marshalled (XML) data
|
||||
using the _dispatch method and the result is returned as
|
||||
marshalled data. For backwards compatibility, a dispatch
|
||||
function can be provided as an argument (see comment in
|
||||
SimpleXMLRPCRequestHandler.do_POST) but overriding the
|
||||
existing method through subclassing is the prefered means
|
||||
of changing method dispatch behavior.
|
||||
"""
|
||||
XML-RPC methods are dispatched from the marshalled (XML) data
|
||||
using the _dispatch method and the result is returned as
|
||||
marshalled data. For backwards compatibility, a dispatch
|
||||
function can be provided as an argument (see comment in
|
||||
SimpleXMLRPCRequestHandler.do_POST) but overriding the
|
||||
existing method through subclassing is the prefered means
|
||||
of changing method dispatch behavior.
|
||||
"""
|
||||
|
||||
params, method = xmlrpclib.loads(data)
|
||||
params, method = xmlrpclib.loads(data)
|
||||
|
||||
# generate response
|
||||
try:
|
||||
if dispatch_method is not None:
|
||||
response = dispatch_method(method, params)
|
||||
else:
|
||||
response = self._dispatch(method, params)
|
||||
# wrap response in a singleton tuple
|
||||
response = (response,)
|
||||
response = xmlrpclib.dumps(response, methodresponse=1)
|
||||
except xmlrpclib.Fault, fault:
|
||||
response = xmlrpclib.dumps(fault)
|
||||
except:
|
||||
print "Exception while processing request:"
|
||||
traceback.print_exc()
|
||||
# generate response
|
||||
try:
|
||||
if dispatch_method is not None:
|
||||
response = dispatch_method(method, params)
|
||||
else:
|
||||
response = self._dispatch(method, params)
|
||||
# wrap response in a singleton tuple
|
||||
response = (response,)
|
||||
response = xmlrpclib.dumps(response, methodresponse=1)
|
||||
except xmlrpclib.Fault, fault:
|
||||
response = xmlrpclib.dumps(fault)
|
||||
except:
|
||||
print "Exception while processing request:"
|
||||
traceback.print_exc()
|
||||
|
||||
# report exception back to server
|
||||
response = xmlrpclib.dumps(
|
||||
xmlrpclib.Fault(1, "%s:%s" % (sys.exc_type, sys.exc_value))
|
||||
)
|
||||
# report exception back to server
|
||||
response = xmlrpclib.dumps(
|
||||
xmlrpclib.Fault(1, "%s:%s" % (sys.exc_type, sys.exc_value))
|
||||
)
|
||||
|
||||
return response
|
||||
return response
|
||||
|
||||
|
||||
class GlibHTTP(httplib.HTTP):
|
||||
"""Subclass HTTP so we can return it's connection class' socket."""
|
||||
def connect(self, host=None, port=None):
|
||||
httplib.HTTP.connect(self, host, port)
|
||||
self._conn.sock.setblocking(0)
|
||||
def get_sock(self):
|
||||
return self._conn.sock
|
||||
"""Subclass HTTP so we can return it's connection class' socket."""
|
||||
def connect(self, host=None, port=None):
|
||||
httplib.HTTP.connect(self, host, port)
|
||||
self._conn.sock.setblocking(0)
|
||||
def get_sock(self):
|
||||
return self._conn.sock
|
||||
|
||||
class GlibXMLRPCTransport(xmlrpclib.Transport):
|
||||
"""Integrate the request with the glib mainloop rather than blocking."""
|
||||
##
|
||||
# Connect to server.
|
||||
#
|
||||
# @param host Target host.
|
||||
# @return A connection handle.
|
||||
"""Integrate the request with the glib mainloop rather than blocking."""
|
||||
##
|
||||
# Connect to server.
|
||||
#
|
||||
# @param host Target host.
|
||||
# @return A connection handle.
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def make_connection(self, host):
|
||||
"""Use our own connection object so we can get its socket."""
|
||||
# create a HTTP connection object from a host descriptor
|
||||
host, extra_headers, x509 = self.get_host_info(host)
|
||||
return GlibHTTP(host)
|
||||
def make_connection(self, host):
|
||||
"""Use our own connection object so we can get its socket."""
|
||||
# create a HTTP connection object from a host descriptor
|
||||
host, extra_headers, x509 = self.get_host_info(host)
|
||||
return GlibHTTP(host)
|
||||
|
||||
##
|
||||
# Send a complete request, and parse the response.
|
||||
#
|
||||
# @param host Target host.
|
||||
# @param handler Target PRC handler.
|
||||
# @param request_body XML-RPC request body.
|
||||
# @param verbose Debugging flag.
|
||||
# @return Parsed response.
|
||||
##
|
||||
# Send a complete request, and parse the response.
|
||||
#
|
||||
# @param host Target host.
|
||||
# @param handler Target PRC handler.
|
||||
# @param request_body XML-RPC request body.
|
||||
# @param verbose Debugging flag.
|
||||
# @return Parsed response.
|
||||
|
||||
def start_request(self, host, handler, request_body, verbose=0, request_cb=None, user_data=None):
|
||||
"""Do the first half of the request by sending data to the remote
|
||||
server. The bottom half bits get run when the remote server's response
|
||||
actually comes back."""
|
||||
# issue XML-RPC request
|
||||
def start_request(self, host, handler, request_body, verbose=0, request_cb=None, user_data=None):
|
||||
"""Do the first half of the request by sending data to the remote
|
||||
server. The bottom half bits get run when the remote server's response
|
||||
actually comes back."""
|
||||
# issue XML-RPC request
|
||||
|
||||
h = self.make_connection(host)
|
||||
if verbose:
|
||||
h.set_debuglevel(1)
|
||||
h = self.make_connection(host)
|
||||
if verbose:
|
||||
h.set_debuglevel(1)
|
||||
|
||||
self.send_request(h, handler, request_body)
|
||||
self.send_host(h, host)
|
||||
self.send_user_agent(h)
|
||||
self.send_content(h, request_body)
|
||||
self.send_request(h, handler, request_body)
|
||||
self.send_host(h, host)
|
||||
self.send_user_agent(h)
|
||||
self.send_content(h, request_body)
|
||||
|
||||
# Schedule a GIOWatch so we don't block waiting for the response
|
||||
gobject.io_add_watch(h.get_sock(), gobject.IO_IN, self._finish_request,
|
||||
h, host, handler, verbose, request_cb, user_data)
|
||||
# Schedule a GIOWatch so we don't block waiting for the response
|
||||
gobject.io_add_watch(h.get_sock(), gobject.IO_IN, self._finish_request,
|
||||
h, host, handler, verbose, request_cb, user_data)
|
||||
|
||||
def _finish_request(self, source, condition, h, host, handler, verbose, request_cb, user_data):
|
||||
"""Parse and return response when the remote server actually returns it."""
|
||||
if not (condition & gobject.IO_IN):
|
||||
return True
|
||||
def _finish_request(self, source, condition, h, host, handler, verbose, request_cb, user_data):
|
||||
"""Parse and return response when the remote server actually returns it."""
|
||||
if not (condition & gobject.IO_IN):
|
||||
return True
|
||||
|
||||
try:
|
||||
errcode, errmsg, headers = h.getreply()
|
||||
except socket.error, err:
|
||||
if err[0] != 104:
|
||||
raise socket.error(err)
|
||||
else:
|
||||
gobject.idle_add(request_cb, RESULT_FAILED, None, user_data)
|
||||
return False
|
||||
|
||||
if errcode != 200:
|
||||
raise xmlrpclib.ProtocolError(host + handler, errcode, errmsg, headers)
|
||||
self.verbose = verbose
|
||||
response = self._parse_response(h.getfile(), h.get_sock())
|
||||
if request_cb:
|
||||
if len(response) == 1:
|
||||
response = response[0]
|
||||
gobject.idle_add(request_cb, RESULT_SUCCESS, response, user_data)
|
||||
return False
|
||||
try:
|
||||
errcode, errmsg, headers = h.getreply()
|
||||
except socket.error, err:
|
||||
if err[0] != 104:
|
||||
raise socket.error(err)
|
||||
else:
|
||||
gobject.idle_add(request_cb, RESULT_FAILED, None, user_data)
|
||||
return False
|
||||
|
||||
if errcode != 200:
|
||||
raise xmlrpclib.ProtocolError(host + handler, errcode, errmsg, headers)
|
||||
self.verbose = verbose
|
||||
response = self._parse_response(h.getfile(), h.get_sock())
|
||||
if request_cb:
|
||||
if len(response) == 1:
|
||||
response = response[0]
|
||||
gobject.idle_add(request_cb, RESULT_SUCCESS, response, user_data)
|
||||
return False
|
||||
|
||||
class _Method:
|
||||
"""Right, so python people thought it would be funny to make this
|
||||
class private to xmlrpclib.py..."""
|
||||
# some magic to bind an XML-RPC method to an RPC server.
|
||||
# supports "nested" methods (e.g. examples.getStateName)
|
||||
def __init__(self, send, name):
|
||||
self.__send = send
|
||||
self.__name = name
|
||||
def __getattr__(self, name):
|
||||
return _Method(self.__send, "%s.%s" % (self.__name, name))
|
||||
def __call__(self, request_cb, user_data, *args):
|
||||
return self.__send(self.__name, request_cb, user_data, args)
|
||||
"""Right, so python people thought it would be funny to make this
|
||||
class private to xmlrpclib.py..."""
|
||||
# some magic to bind an XML-RPC method to an RPC server.
|
||||
# supports "nested" methods (e.g. examples.getStateName)
|
||||
def __init__(self, send, name):
|
||||
self.__send = send
|
||||
self.__name = name
|
||||
def __getattr__(self, name):
|
||||
return _Method(self.__send, "%s.%s" % (self.__name, name))
|
||||
def __call__(self, request_cb, user_data, *args):
|
||||
return self.__send(self.__name, request_cb, user_data, args)
|
||||
|
||||
|
||||
class GlibServerProxy(xmlrpclib.ServerProxy):
|
||||
"""Subclass xmlrpclib.ServerProxy so we can run the XML-RPC request
|
||||
in two parts, integrated with the glib mainloop, such that we don't
|
||||
block anywhere.
|
||||
|
||||
Using this object is somewhat special; it requires more arguments to each
|
||||
XML-RPC request call than the normal xmlrpclib.ServerProxy object:
|
||||
|
||||
client = GlibServerProxy("http://127.0.0.1:8888")
|
||||
user_data = "bar"
|
||||
xmlrpc_arg1 = "test"
|
||||
xmlrpc_arg2 = "foo"
|
||||
client.test(xmlrpc_test_cb, user_data, xmlrpc_arg1, xmlrpc_arg2)
|
||||
"""Subclass xmlrpclib.ServerProxy so we can run the XML-RPC request
|
||||
in two parts, integrated with the glib mainloop, such that we don't
|
||||
block anywhere.
|
||||
|
||||
Using this object is somewhat special; it requires more arguments to each
|
||||
XML-RPC request call than the normal xmlrpclib.ServerProxy object:
|
||||
|
||||
client = GlibServerProxy("http://127.0.0.1:8888")
|
||||
user_data = "bar"
|
||||
xmlrpc_arg1 = "test"
|
||||
xmlrpc_arg2 = "foo"
|
||||
client.test(xmlrpc_test_cb, user_data, xmlrpc_arg1, xmlrpc_arg2)
|
||||
|
||||
Here, 'xmlrpc_test_cb' is the callback function, which has the following
|
||||
signature:
|
||||
|
||||
def xmlrpc_test_cb(result_status, response, user_data=None):
|
||||
...
|
||||
"""
|
||||
def __init__(self, uri, encoding=None, verbose=0, allow_none=0):
|
||||
self._transport = GlibXMLRPCTransport()
|
||||
self._encoding = encoding
|
||||
self._verbose = verbose
|
||||
self._allow_none = allow_none
|
||||
xmlrpclib.ServerProxy.__init__(self, uri, self._transport, encoding, verbose, allow_none)
|
||||
Here, 'xmlrpc_test_cb' is the callback function, which has the following
|
||||
signature:
|
||||
|
||||
def xmlrpc_test_cb(result_status, response, user_data=None):
|
||||
...
|
||||
"""
|
||||
def __init__(self, uri, encoding=None, verbose=0, allow_none=0):
|
||||
self._transport = GlibXMLRPCTransport()
|
||||
self._encoding = encoding
|
||||
self._verbose = verbose
|
||||
self._allow_none = allow_none
|
||||
xmlrpclib.ServerProxy.__init__(self, uri, self._transport, encoding, verbose, allow_none)
|
||||
|
||||
# get the url
|
||||
import urllib
|
||||
urltype, uri = urllib.splittype(uri)
|
||||
if urltype not in ("http", "https"):
|
||||
raise IOError, "unsupported XML-RPC protocol"
|
||||
self._host, self._handler = urllib.splithost(uri)
|
||||
if not self._handler:
|
||||
self._handler = "/RPC2"
|
||||
# get the url
|
||||
import urllib
|
||||
urltype, uri = urllib.splittype(uri)
|
||||
if urltype not in ("http", "https"):
|
||||
raise IOError, "unsupported XML-RPC protocol"
|
||||
self._host, self._handler = urllib.splithost(uri)
|
||||
if not self._handler:
|
||||
self._handler = "/RPC2"
|
||||
|
||||
def __request(self, methodname, request_cb, user_data, params):
|
||||
"""Call the method on the remote server. We just start the request here
|
||||
and the transport itself takes care of scheduling the response callback
|
||||
when the remote server returns the response. We don't want to block anywhere."""
|
||||
def __request(self, methodname, request_cb, user_data, params):
|
||||
"""Call the method on the remote server. We just start the request here
|
||||
and the transport itself takes care of scheduling the response callback
|
||||
when the remote server returns the response. We don't want to block anywhere."""
|
||||
|
||||
request = xmlrpclib.dumps(params, methodname, encoding=self._encoding,
|
||||
allow_none=self._allow_none)
|
||||
request = xmlrpclib.dumps(params, methodname, encoding=self._encoding,
|
||||
allow_none=self._allow_none)
|
||||
|
||||
try:
|
||||
response = self._transport.start_request(
|
||||
self._host,
|
||||
self._handler,
|
||||
request,
|
||||
verbose=self._verbose,
|
||||
request_cb=request_cb,
|
||||
user_data=user_data
|
||||
)
|
||||
except socket.error, exc:
|
||||
gobject.idle_add(request_cb, RESULT_FAILED, None, user_data)
|
||||
try:
|
||||
response = self._transport.start_request(
|
||||
self._host,
|
||||
self._handler,
|
||||
request,
|
||||
verbose=self._verbose,
|
||||
request_cb=request_cb,
|
||||
user_data=user_data
|
||||
)
|
||||
except socket.error, exc:
|
||||
gobject.idle_add(request_cb, RESULT_FAILED, None, user_data)
|
||||
|
||||
def __getattr__(self, name):
|
||||
# magic method dispatcher
|
||||
return _Method(self.__request, name)
|
||||
def __getattr__(self, name):
|
||||
# magic method dispatcher
|
||||
return _Method(self.__request, name)
|
||||
|
||||
|
||||
class GroupServer(object):
|
||||
|
||||
_MAX_MSG_SIZE = 500
|
||||
_MAX_MSG_SIZE = 500
|
||||
|
||||
def __init__(self, address, port, data_cb):
|
||||
self._address = address
|
||||
self._port = port
|
||||
self._data_cb = data_cb
|
||||
def __init__(self, address, port, data_cb):
|
||||
self._address = address
|
||||
self._port = port
|
||||
self._data_cb = data_cb
|
||||
|
||||
self._setup_listener()
|
||||
self._setup_listener()
|
||||
|
||||
def _setup_listener(self):
|
||||
# Listener socket
|
||||
self._listen_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
def _setup_listener(self):
|
||||
# Listener socket
|
||||
self._listen_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
|
||||
# Set some options to make it multicast-friendly
|
||||
self._listen_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_TTL, 20)
|
||||
self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_LOOP, 1)
|
||||
# Set some options to make it multicast-friendly
|
||||
self._listen_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_TTL, 20)
|
||||
self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_LOOP, 1)
|
||||
|
||||
def start(self):
|
||||
# Set some more multicast options
|
||||
self._listen_sock.bind(('', self._port))
|
||||
self._listen_sock.settimeout(2)
|
||||
intf = socket.gethostbyname(socket.gethostname())
|
||||
self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_IF, socket.inet_aton(intf) + socket.inet_aton('0.0.0.0'))
|
||||
self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_ADD_MEMBERSHIP, socket.inet_aton(self._address) + socket.inet_aton('0.0.0.0'))
|
||||
def start(self):
|
||||
# Set some more multicast options
|
||||
self._listen_sock.bind(('', self._port))
|
||||
self._listen_sock.settimeout(2)
|
||||
intf = socket.gethostbyname(socket.gethostname())
|
||||
self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_IF, socket.inet_aton(intf) + socket.inet_aton('0.0.0.0'))
|
||||
self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_ADD_MEMBERSHIP, socket.inet_aton(self._address) + socket.inet_aton('0.0.0.0'))
|
||||
|
||||
# Watch the listener socket for data
|
||||
gobject.io_add_watch(self._listen_sock, gobject.IO_IN, self._handle_incoming_data)
|
||||
# Watch the listener socket for data
|
||||
gobject.io_add_watch(self._listen_sock, gobject.IO_IN, self._handle_incoming_data)
|
||||
|
||||
def _handle_incoming_data(self, source, condition):
|
||||
if not (condition & gobject.IO_IN):
|
||||
return True
|
||||
msg = {}
|
||||
msg['data'], (msg['addr'], msg['port']) = source.recvfrom(self._MAX_MSG_SIZE)
|
||||
if self._data_cb:
|
||||
self._data_cb(msg)
|
||||
return True
|
||||
def _handle_incoming_data(self, source, condition):
|
||||
if not (condition & gobject.IO_IN):
|
||||
return True
|
||||
msg = {}
|
||||
msg['data'], (msg['addr'], msg['port']) = source.recvfrom(self._MAX_MSG_SIZE)
|
||||
if self._data_cb:
|
||||
self._data_cb(msg)
|
||||
return True
|
||||
|
||||
class GroupClient(object):
|
||||
|
||||
_MAX_MSG_SIZE = 500
|
||||
_MAX_MSG_SIZE = 500
|
||||
|
||||
def __init__(self, address, port):
|
||||
self._address = address
|
||||
self._port = port
|
||||
def __init__(self, address, port):
|
||||
self._address = address
|
||||
self._port = port
|
||||
|
||||
self._send_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
# Make the socket multicast-aware, and set TTL.
|
||||
self._send_sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 20) # Change TTL (=20) to suit
|
||||
self._send_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
# Make the socket multicast-aware, and set TTL.
|
||||
self._send_sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 20) # Change TTL (=20) to suit
|
||||
|
||||
def send_msg(self, data):
|
||||
self._send_sock.sendto(data, (self._address, self._port))
|
||||
def send_msg(self, data):
|
||||
self._send_sock.sendto(data, (self._address, self._port))
|
||||
|
||||
|
||||
|
||||
class Test(object):
|
||||
def test(self, arg1):
|
||||
print "Request got %s" % arg1
|
||||
return "success"
|
||||
def test(self, arg1):
|
||||
print "Request got %s" % arg1
|
||||
return "success"
|
||||
|
||||
def xmlrpc_test_cb(response, user_data=None):
|
||||
print "Response was %s, user_data was %s" % (response, user_data)
|
||||
import gtk
|
||||
gtk.main_quit()
|
||||
print "Response was %s, user_data was %s" % (response, user_data)
|
||||
import gtk
|
||||
gtk.main_quit()
|
||||
|
||||
|
||||
def xmlrpc_test():
|
||||
client = GlibServerProxy("http://127.0.0.1:8888")
|
||||
client.test(xmlrpc_test_cb, "bar", "test data")
|
||||
client = GlibServerProxy("http://127.0.0.1:8888")
|
||||
client.test(xmlrpc_test_cb, "bar", "test data")
|
||||
|
||||
|
||||
def main():
|
||||
import gtk
|
||||
server = GlibXMLRPCServer(("", 8888))
|
||||
inst = Test()
|
||||
server.register_instance(inst)
|
||||
|
||||
gobject.idle_add(xmlrpc_test)
|
||||
import gtk
|
||||
server = GlibXMLRPCServer(("", 8888))
|
||||
inst = Test()
|
||||
server.register_instance(inst)
|
||||
|
||||
gobject.idle_add(xmlrpc_test)
|
||||
|
||||
try:
|
||||
gtk.main()
|
||||
except KeyboardInterrupt:
|
||||
print 'Ctrl+C pressed, exiting...'
|
||||
print "Done."
|
||||
try:
|
||||
gtk.main()
|
||||
except KeyboardInterrupt:
|
||||
print 'Ctrl+C pressed, exiting...'
|
||||
print "Done."
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
main()
|
||||
|
||||
+78
-78
@@ -20,98 +20,98 @@ import dbus
|
||||
|
||||
class Activity(gobject.GObject):
|
||||
|
||||
__gsignals__ = {
|
||||
'buddy-joined': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT])),
|
||||
'buddy-left': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT])),
|
||||
'service-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT])),
|
||||
'service-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT]))
|
||||
}
|
||||
__gsignals__ = {
|
||||
'buddy-joined': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT])),
|
||||
'buddy-left': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT])),
|
||||
'service-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT])),
|
||||
'service-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT]))
|
||||
}
|
||||
|
||||
_PRESENCE_SERVICE = "org.laptop.Presence"
|
||||
_ACTIVITY_DBUS_INTERFACE = "org.laptop.Presence.Activity"
|
||||
_PRESENCE_SERVICE = "org.laptop.Presence"
|
||||
_ACTIVITY_DBUS_INTERFACE = "org.laptop.Presence.Activity"
|
||||
|
||||
def __init__(self, bus, new_obj_cb, del_obj_cb, object_path):
|
||||
gobject.GObject.__init__(self)
|
||||
self._object_path = object_path
|
||||
self._ps_new_object = new_obj_cb
|
||||
self._ps_del_object = del_obj_cb
|
||||
bobj = bus.get_object(self._PRESENCE_SERVICE, object_path)
|
||||
self._activity = dbus.Interface(bobj, self._ACTIVITY_DBUS_INTERFACE)
|
||||
self._activity.connect_to_signal('BuddyJoined', self._buddy_joined_cb)
|
||||
self._activity.connect_to_signal('BuddyLeft', self._buddy_left_cb)
|
||||
self._activity.connect_to_signal('ServiceAppeared', self._service_appeared_cb)
|
||||
self._activity.connect_to_signal('ServiceDisappeared', self._service_disappeared_cb)
|
||||
|
||||
self._id = None
|
||||
self._color = None
|
||||
def __init__(self, bus, new_obj_cb, del_obj_cb, object_path):
|
||||
gobject.GObject.__init__(self)
|
||||
self._object_path = object_path
|
||||
self._ps_new_object = new_obj_cb
|
||||
self._ps_del_object = del_obj_cb
|
||||
bobj = bus.get_object(self._PRESENCE_SERVICE, object_path)
|
||||
self._activity = dbus.Interface(bobj, self._ACTIVITY_DBUS_INTERFACE)
|
||||
self._activity.connect_to_signal('BuddyJoined', self._buddy_joined_cb)
|
||||
self._activity.connect_to_signal('BuddyLeft', self._buddy_left_cb)
|
||||
self._activity.connect_to_signal('ServiceAppeared', self._service_appeared_cb)
|
||||
self._activity.connect_to_signal('ServiceDisappeared', self._service_disappeared_cb)
|
||||
|
||||
self._id = None
|
||||
self._color = None
|
||||
|
||||
def object_path(self):
|
||||
return self._object_path
|
||||
def object_path(self):
|
||||
return self._object_path
|
||||
|
||||
def _emit_buddy_joined_signal(self, object_path):
|
||||
self.emit('buddy-joined', self._ps_new_object(object_path))
|
||||
return False
|
||||
def _emit_buddy_joined_signal(self, object_path):
|
||||
self.emit('buddy-joined', self._ps_new_object(object_path))
|
||||
return False
|
||||
|
||||
def _buddy_joined_cb(self, object_path):
|
||||
gobject.idle_add(self._emit_buddy_joined_signal, object_path)
|
||||
def _buddy_joined_cb(self, object_path):
|
||||
gobject.idle_add(self._emit_buddy_joined_signal, object_path)
|
||||
|
||||
def _emit_buddy_left_signal(self, object_path):
|
||||
self.emit('buddy-left', self._ps_new_object(object_path))
|
||||
return False
|
||||
def _emit_buddy_left_signal(self, object_path):
|
||||
self.emit('buddy-left', self._ps_new_object(object_path))
|
||||
return False
|
||||
|
||||
def _buddy_left_cb(self, object_path):
|
||||
gobject.idle_add(self._emit_buddy_left_signal, object_path)
|
||||
def _buddy_left_cb(self, object_path):
|
||||
gobject.idle_add(self._emit_buddy_left_signal, object_path)
|
||||
|
||||
def _emit_service_appeared_signal(self, object_path):
|
||||
self.emit('service-appeared', self._ps_new_object(object_path))
|
||||
return False
|
||||
def _emit_service_appeared_signal(self, object_path):
|
||||
self.emit('service-appeared', self._ps_new_object(object_path))
|
||||
return False
|
||||
|
||||
def _service_appeared_cb(self, object_path):
|
||||
gobject.idle_add(self._emit_service_appeared_signal, object_path)
|
||||
def _service_appeared_cb(self, object_path):
|
||||
gobject.idle_add(self._emit_service_appeared_signal, object_path)
|
||||
|
||||
def _emit_service_disappeared_signal(self, object_path):
|
||||
self.emit('service-disappeared', self._ps_new_object(object_path))
|
||||
return False
|
||||
def _emit_service_disappeared_signal(self, object_path):
|
||||
self.emit('service-disappeared', self._ps_new_object(object_path))
|
||||
return False
|
||||
|
||||
def _service_disappeared_cb(self, object_path):
|
||||
gobject.idle_add(self._emit_service_disappeared_signal, object_path)
|
||||
def _service_disappeared_cb(self, object_path):
|
||||
gobject.idle_add(self._emit_service_disappeared_signal, object_path)
|
||||
|
||||
def get_id(self):
|
||||
# Cache activity ID, which should never change anyway
|
||||
if not self._id:
|
||||
self._id = self._activity.getId()
|
||||
return self._id
|
||||
def get_id(self):
|
||||
# Cache activity ID, which should never change anyway
|
||||
if not self._id:
|
||||
self._id = self._activity.getId()
|
||||
return self._id
|
||||
|
||||
def get_color(self):
|
||||
if not self._color:
|
||||
self._color = self._activity.getColor()
|
||||
return self._color
|
||||
def get_color(self):
|
||||
if not self._color:
|
||||
self._color = self._activity.getColor()
|
||||
return self._color
|
||||
|
||||
def get_services(self):
|
||||
resp = self._activity.getServices()
|
||||
servs = []
|
||||
for item in resp:
|
||||
servs.append(self._ps_new_object(item))
|
||||
return servs
|
||||
def get_services(self):
|
||||
resp = self._activity.getServices()
|
||||
servs = []
|
||||
for item in resp:
|
||||
servs.append(self._ps_new_object(item))
|
||||
return servs
|
||||
|
||||
def get_services_of_type(self, stype):
|
||||
resp = self._activity.getServicesOfType(stype)
|
||||
servs = []
|
||||
for item in resp:
|
||||
servs.append(self._ps_new_object(item))
|
||||
return servs
|
||||
def get_services_of_type(self, stype):
|
||||
resp = self._activity.getServicesOfType(stype)
|
||||
servs = []
|
||||
for item in resp:
|
||||
servs.append(self._ps_new_object(item))
|
||||
return servs
|
||||
|
||||
def get_joined_buddies(self):
|
||||
resp = self._activity.getJoinedBuddies()
|
||||
buddies = []
|
||||
for item in resp:
|
||||
buddies.append(self._ps_new_object(item))
|
||||
return buddies
|
||||
def get_joined_buddies(self):
|
||||
resp = self._activity.getJoinedBuddies()
|
||||
buddies = []
|
||||
for item in resp:
|
||||
buddies.append(self._ps_new_object(item))
|
||||
return buddies
|
||||
|
||||
def owner_has_joined(self):
|
||||
# FIXME
|
||||
return False
|
||||
def owner_has_joined(self):
|
||||
# FIXME
|
||||
return False
|
||||
|
||||
+140
-140
@@ -21,173 +21,173 @@ import dbus
|
||||
|
||||
class Buddy(gobject.GObject):
|
||||
|
||||
__gsignals__ = {
|
||||
'icon-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([])),
|
||||
'disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([])),
|
||||
'service-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT])),
|
||||
'service-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT])),
|
||||
'joined-activity': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT])),
|
||||
'left-activity': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT])),
|
||||
'property-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT])),
|
||||
'current-activity-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT]))
|
||||
}
|
||||
__gsignals__ = {
|
||||
'icon-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([])),
|
||||
'disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([])),
|
||||
'service-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT])),
|
||||
'service-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT])),
|
||||
'joined-activity': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT])),
|
||||
'left-activity': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT])),
|
||||
'property-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT])),
|
||||
'current-activity-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT]))
|
||||
}
|
||||
|
||||
_PRESENCE_SERVICE = "org.laptop.Presence"
|
||||
_BUDDY_DBUS_INTERFACE = "org.laptop.Presence.Buddy"
|
||||
_PRESENCE_SERVICE = "org.laptop.Presence"
|
||||
_BUDDY_DBUS_INTERFACE = "org.laptop.Presence.Buddy"
|
||||
|
||||
def __init__(self, bus, new_obj_cb, del_obj_cb, object_path):
|
||||
gobject.GObject.__init__(self)
|
||||
self._object_path = object_path
|
||||
self._ps_new_object = new_obj_cb
|
||||
self._ps_del_object = del_obj_cb
|
||||
self._properties = {}
|
||||
bobj = bus.get_object(self._PRESENCE_SERVICE, object_path)
|
||||
self._buddy = dbus.Interface(bobj, self._BUDDY_DBUS_INTERFACE)
|
||||
self._buddy.connect_to_signal('IconChanged', self._icon_changed_cb)
|
||||
self._buddy.connect_to_signal('ServiceAppeared', self._service_appeared_cb)
|
||||
self._buddy.connect_to_signal('ServiceDisappeared', self._service_disappeared_cb)
|
||||
self._buddy.connect_to_signal('Disappeared', self._disappeared_cb)
|
||||
self._buddy.connect_to_signal('JoinedActivity', self._joined_activity_cb)
|
||||
self._buddy.connect_to_signal('LeftActivity', self._left_activity_cb)
|
||||
self._buddy.connect_to_signal('PropertyChanged', self._property_changed_cb)
|
||||
self._buddy.connect_to_signal('CurrentActivityChanged', self._current_activity_changed_cb)
|
||||
self._properties = self._get_properties_helper()
|
||||
def __init__(self, bus, new_obj_cb, del_obj_cb, object_path):
|
||||
gobject.GObject.__init__(self)
|
||||
self._object_path = object_path
|
||||
self._ps_new_object = new_obj_cb
|
||||
self._ps_del_object = del_obj_cb
|
||||
self._properties = {}
|
||||
bobj = bus.get_object(self._PRESENCE_SERVICE, object_path)
|
||||
self._buddy = dbus.Interface(bobj, self._BUDDY_DBUS_INTERFACE)
|
||||
self._buddy.connect_to_signal('IconChanged', self._icon_changed_cb)
|
||||
self._buddy.connect_to_signal('ServiceAppeared', self._service_appeared_cb)
|
||||
self._buddy.connect_to_signal('ServiceDisappeared', self._service_disappeared_cb)
|
||||
self._buddy.connect_to_signal('Disappeared', self._disappeared_cb)
|
||||
self._buddy.connect_to_signal('JoinedActivity', self._joined_activity_cb)
|
||||
self._buddy.connect_to_signal('LeftActivity', self._left_activity_cb)
|
||||
self._buddy.connect_to_signal('PropertyChanged', self._property_changed_cb)
|
||||
self._buddy.connect_to_signal('CurrentActivityChanged', self._current_activity_changed_cb)
|
||||
self._properties = self._get_properties_helper()
|
||||
|
||||
self._current_activity = None
|
||||
try:
|
||||
self._current_activity = self._buddy.getCurrentActivity()
|
||||
except Exception, e:
|
||||
pass
|
||||
self._current_activity = None
|
||||
try:
|
||||
self._current_activity = self._buddy.getCurrentActivity()
|
||||
except Exception, e:
|
||||
pass
|
||||
|
||||
def _get_properties_helper(self):
|
||||
props = self._buddy.getProperties()
|
||||
if not props:
|
||||
return {}
|
||||
return props
|
||||
def _get_properties_helper(self):
|
||||
props = self._buddy.getProperties()
|
||||
if not props:
|
||||
return {}
|
||||
return props
|
||||
|
||||
def object_path(self):
|
||||
return self._object_path
|
||||
def object_path(self):
|
||||
return self._object_path
|
||||
|
||||
def _emit_icon_changed_signal(self):
|
||||
self.emit('icon-changed')
|
||||
return False
|
||||
def _emit_icon_changed_signal(self):
|
||||
self.emit('icon-changed')
|
||||
return False
|
||||
|
||||
def _icon_changed_cb(self):
|
||||
gobject.idle_add(self._emit_icon_changed_signal)
|
||||
def _icon_changed_cb(self):
|
||||
gobject.idle_add(self._emit_icon_changed_signal)
|
||||
|
||||
def _emit_disappeared_signal(self):
|
||||
self.emit('disappeared')
|
||||
def _emit_disappeared_signal(self):
|
||||
self.emit('disappeared')
|
||||
|
||||
def _disappeared_cb(self):
|
||||
gobject.idle_add(self._emit_disappeared_signal)
|
||||
def _disappeared_cb(self):
|
||||
gobject.idle_add(self._emit_disappeared_signal)
|
||||
|
||||
def _emit_service_appeared_signal(self, object_path):
|
||||
self.emit('service-appeared', self._ps_new_object(object_path))
|
||||
return False
|
||||
def _emit_service_appeared_signal(self, object_path):
|
||||
self.emit('service-appeared', self._ps_new_object(object_path))
|
||||
return False
|
||||
|
||||
def _service_appeared_cb(self, object_path):
|
||||
gobject.idle_add(self._emit_service_appeared_signal, object_path)
|
||||
def _service_appeared_cb(self, object_path):
|
||||
gobject.idle_add(self._emit_service_appeared_signal, object_path)
|
||||
|
||||
def _emit_service_disappeared_signal(self, object_path):
|
||||
self.emit('service-disappeared', self._ps_new_object(object_path))
|
||||
return False
|
||||
def _emit_service_disappeared_signal(self, object_path):
|
||||
self.emit('service-disappeared', self._ps_new_object(object_path))
|
||||
return False
|
||||
|
||||
def _service_disappeared_cb(self, object_path):
|
||||
gobject.idle_add(self._emit_service_disappeared_signal, object_path)
|
||||
def _service_disappeared_cb(self, object_path):
|
||||
gobject.idle_add(self._emit_service_disappeared_signal, object_path)
|
||||
|
||||
def _emit_joined_activity_signal(self, object_path):
|
||||
self.emit('joined-activity', self._ps_new_object(object_path))
|
||||
return False
|
||||
def _emit_joined_activity_signal(self, object_path):
|
||||
self.emit('joined-activity', self._ps_new_object(object_path))
|
||||
return False
|
||||
|
||||
def _joined_activity_cb(self, object_path):
|
||||
gobject.idle_add(self._emit_joined_activity_signal, object_path)
|
||||
def _joined_activity_cb(self, object_path):
|
||||
gobject.idle_add(self._emit_joined_activity_signal, object_path)
|
||||
|
||||
def _emit_left_activity_signal(self, object_path):
|
||||
self.emit('left-activity', self._ps_new_object(object_path))
|
||||
return False
|
||||
def _emit_left_activity_signal(self, object_path):
|
||||
self.emit('left-activity', self._ps_new_object(object_path))
|
||||
return False
|
||||
|
||||
def _left_activity_cb(self, object_path):
|
||||
gobject.idle_add(self._emit_left_activity_signal, object_path)
|
||||
def _left_activity_cb(self, object_path):
|
||||
gobject.idle_add(self._emit_left_activity_signal, object_path)
|
||||
|
||||
def _handle_property_changed_signal(self, prop_list):
|
||||
self._properties = self._get_properties_helper()
|
||||
self.emit('property-changed', prop_list)
|
||||
return False
|
||||
def _handle_property_changed_signal(self, prop_list):
|
||||
self._properties = self._get_properties_helper()
|
||||
self.emit('property-changed', prop_list)
|
||||
return False
|
||||
|
||||
def _property_changed_cb(self, prop_list):
|
||||
gobject.idle_add(self._handle_property_changed_signal, prop_list)
|
||||
def _property_changed_cb(self, prop_list):
|
||||
gobject.idle_add(self._handle_property_changed_signal, prop_list)
|
||||
|
||||
def _handle_current_activity_changed_signal(self, act_list):
|
||||
if len(act_list) == 0:
|
||||
self._current_activity = None
|
||||
self.emit('current-activity-changed', None)
|
||||
else:
|
||||
self._current_activity = act_list[0]
|
||||
self.emit('current-activity-changed', self._ps_new_object(act_list[0]))
|
||||
return False
|
||||
def _handle_current_activity_changed_signal(self, act_list):
|
||||
if len(act_list) == 0:
|
||||
self._current_activity = None
|
||||
self.emit('current-activity-changed', None)
|
||||
else:
|
||||
self._current_activity = act_list[0]
|
||||
self.emit('current-activity-changed', self._ps_new_object(act_list[0]))
|
||||
return False
|
||||
|
||||
def _current_activity_changed_cb(self, act_list):
|
||||
gobject.idle_add(self._handle_current_activity_changed_signal, act_list)
|
||||
def _current_activity_changed_cb(self, act_list):
|
||||
gobject.idle_add(self._handle_current_activity_changed_signal, act_list)
|
||||
|
||||
def get_name(self):
|
||||
return self._properties['name']
|
||||
def get_name(self):
|
||||
return self._properties['name']
|
||||
|
||||
def get_ip4_address(self):
|
||||
return self._properties['ip4_address']
|
||||
def get_ip4_address(self):
|
||||
return self._properties['ip4_address']
|
||||
|
||||
def is_owner(self):
|
||||
return self._properties['owner']
|
||||
def is_owner(self):
|
||||
return self._properties['owner']
|
||||
|
||||
def get_color(self):
|
||||
return self._properties['color']
|
||||
def get_color(self):
|
||||
return self._properties['color']
|
||||
|
||||
def get_icon(self):
|
||||
return self._buddy.getIcon()
|
||||
def get_icon(self):
|
||||
return self._buddy.getIcon()
|
||||
|
||||
def get_current_activity(self):
|
||||
if not self._current_activity:
|
||||
return None
|
||||
return self._ps_new_object(self._current_activity)
|
||||
def get_current_activity(self):
|
||||
if not self._current_activity:
|
||||
return None
|
||||
return self._ps_new_object(self._current_activity)
|
||||
|
||||
def get_icon_pixbuf(self):
|
||||
icon = self._buddy.getIcon()
|
||||
if icon and len(icon):
|
||||
pbl = gtk.gdk.PixbufLoader()
|
||||
icon_data = ""
|
||||
for item in icon:
|
||||
if item < 0:
|
||||
item = item + 128
|
||||
icon_data = icon_data + chr(item)
|
||||
pbl.write(icon_data)
|
||||
pbl.close()
|
||||
return pbl.get_pixbuf()
|
||||
else:
|
||||
return None
|
||||
def get_icon_pixbuf(self):
|
||||
icon = self._buddy.getIcon()
|
||||
if icon and len(icon):
|
||||
pbl = gtk.gdk.PixbufLoader()
|
||||
icon_data = ""
|
||||
for item in icon:
|
||||
if item < 0:
|
||||
item = item + 128
|
||||
icon_data = icon_data + chr(item)
|
||||
pbl.write(icon_data)
|
||||
pbl.close()
|
||||
return pbl.get_pixbuf()
|
||||
else:
|
||||
return None
|
||||
|
||||
def get_service_of_type(self, stype, activity=None):
|
||||
try:
|
||||
act_op = "/"
|
||||
if activity:
|
||||
act_op = activity.object_path()
|
||||
object_path = self._buddy.getServiceOfType(stype, act_op)
|
||||
except dbus.exceptions.DBusException:
|
||||
return None
|
||||
return self._ps_new_object(object_path)
|
||||
def get_service_of_type(self, stype, activity=None):
|
||||
try:
|
||||
act_op = "/"
|
||||
if activity:
|
||||
act_op = activity.object_path()
|
||||
object_path = self._buddy.getServiceOfType(stype, act_op)
|
||||
except dbus.exceptions.DBusException:
|
||||
return None
|
||||
return self._ps_new_object(object_path)
|
||||
|
||||
def get_joined_activities(self):
|
||||
try:
|
||||
resp = self._buddy.getJoinedActivities()
|
||||
except dbus.exceptions.DBusException:
|
||||
return []
|
||||
acts = []
|
||||
for item in resp:
|
||||
acts.append(self._ps_new_object(item))
|
||||
return acts
|
||||
def get_joined_activities(self):
|
||||
try:
|
||||
resp = self._buddy.getJoinedActivities()
|
||||
except dbus.exceptions.DBusException:
|
||||
return []
|
||||
acts = []
|
||||
for item in resp:
|
||||
acts.append(self._ps_new_object(item))
|
||||
return acts
|
||||
|
||||
+167
-167
@@ -20,23 +20,23 @@ import dbus, dbus.glib, gobject
|
||||
import Buddy, Service, Activity
|
||||
|
||||
class ObjectCache(object):
|
||||
def __init__(self):
|
||||
self._cache = {}
|
||||
def __init__(self):
|
||||
self._cache = {}
|
||||
|
||||
def get(self, object_path):
|
||||
try:
|
||||
return self._cache[object_path]
|
||||
except KeyError:
|
||||
return None
|
||||
def get(self, object_path):
|
||||
try:
|
||||
return self._cache[object_path]
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
def add(self, obj):
|
||||
op = obj.object_path()
|
||||
if not self._cache.has_key(op):
|
||||
self._cache[op] = obj
|
||||
def add(self, obj):
|
||||
op = obj.object_path()
|
||||
if not self._cache.has_key(op):
|
||||
self._cache[op] = obj
|
||||
|
||||
def remove(self, object_path):
|
||||
if self._cache.has_key(object_path):
|
||||
del self._cache[object_path]
|
||||
def remove(self, object_path):
|
||||
if self._cache.has_key(object_path):
|
||||
del self._cache[object_path]
|
||||
|
||||
|
||||
DBUS_SERVICE = "org.laptop.Presence"
|
||||
@@ -46,192 +46,192 @@ DBUS_PATH = "/org/laptop/Presence"
|
||||
|
||||
class PresenceService(gobject.GObject):
|
||||
|
||||
__gsignals__ = {
|
||||
'buddy-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT])),
|
||||
'buddy-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT])),
|
||||
'service-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT])),
|
||||
'service-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT])),
|
||||
'activity-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT])),
|
||||
'activity-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT]))
|
||||
}
|
||||
__gsignals__ = {
|
||||
'buddy-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT])),
|
||||
'buddy-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT])),
|
||||
'service-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT])),
|
||||
'service-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT])),
|
||||
'activity-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT])),
|
||||
'activity-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT]))
|
||||
}
|
||||
|
||||
_PS_BUDDY_OP = DBUS_PATH + "/Buddies/"
|
||||
_PS_SERVICE_OP = DBUS_PATH + "/Services/"
|
||||
_PS_ACTIVITY_OP = DBUS_PATH + "/Activities/"
|
||||
|
||||
_PS_BUDDY_OP = DBUS_PATH + "/Buddies/"
|
||||
_PS_SERVICE_OP = DBUS_PATH + "/Services/"
|
||||
_PS_ACTIVITY_OP = DBUS_PATH + "/Activities/"
|
||||
|
||||
|
||||
def __init__(self):
|
||||
gobject.GObject.__init__(self)
|
||||
self._objcache = ObjectCache()
|
||||
self._bus = dbus.SessionBus()
|
||||
self._ps = dbus.Interface(self._bus.get_object(DBUS_SERVICE,
|
||||
DBUS_PATH), DBUS_INTERFACE)
|
||||
self._ps.connect_to_signal('BuddyAppeared', self._buddy_appeared_cb)
|
||||
self._ps.connect_to_signal('BuddyDisappeared', self._buddy_disappeared_cb)
|
||||
self._ps.connect_to_signal('ServiceAppeared', self._service_appeared_cb)
|
||||
self._ps.connect_to_signal('ServiceDisappeared', self._service_disappeared_cb)
|
||||
self._ps.connect_to_signal('ActivityAppeared', self._activity_appeared_cb)
|
||||
self._ps.connect_to_signal('ActivityDisappeared', self._activity_disappeared_cb)
|
||||
def __init__(self):
|
||||
gobject.GObject.__init__(self)
|
||||
self._objcache = ObjectCache()
|
||||
self._bus = dbus.SessionBus()
|
||||
self._ps = dbus.Interface(self._bus.get_object(DBUS_SERVICE,
|
||||
DBUS_PATH), DBUS_INTERFACE)
|
||||
self._ps.connect_to_signal('BuddyAppeared', self._buddy_appeared_cb)
|
||||
self._ps.connect_to_signal('BuddyDisappeared', self._buddy_disappeared_cb)
|
||||
self._ps.connect_to_signal('ServiceAppeared', self._service_appeared_cb)
|
||||
self._ps.connect_to_signal('ServiceDisappeared', self._service_disappeared_cb)
|
||||
self._ps.connect_to_signal('ActivityAppeared', self._activity_appeared_cb)
|
||||
self._ps.connect_to_signal('ActivityDisappeared', self._activity_disappeared_cb)
|
||||
|
||||
def _new_object(self, object_path):
|
||||
obj = self._objcache.get(object_path)
|
||||
if not obj:
|
||||
if object_path.startswith(self._PS_SERVICE_OP):
|
||||
obj = Service.Service(self._bus, self._new_object,
|
||||
self._del_object, object_path)
|
||||
elif object_path.startswith(self._PS_BUDDY_OP):
|
||||
obj = Buddy.Buddy(self._bus, self._new_object,
|
||||
self._del_object, object_path)
|
||||
elif object_path.startswith(self._PS_ACTIVITY_OP):
|
||||
obj = Activity.Activity(self._bus, self._new_object,
|
||||
self._del_object, object_path)
|
||||
else:
|
||||
raise RuntimeError("Unknown object type")
|
||||
self._objcache.add(obj)
|
||||
return obj
|
||||
def _new_object(self, object_path):
|
||||
obj = self._objcache.get(object_path)
|
||||
if not obj:
|
||||
if object_path.startswith(self._PS_SERVICE_OP):
|
||||
obj = Service.Service(self._bus, self._new_object,
|
||||
self._del_object, object_path)
|
||||
elif object_path.startswith(self._PS_BUDDY_OP):
|
||||
obj = Buddy.Buddy(self._bus, self._new_object,
|
||||
self._del_object, object_path)
|
||||
elif object_path.startswith(self._PS_ACTIVITY_OP):
|
||||
obj = Activity.Activity(self._bus, self._new_object,
|
||||
self._del_object, object_path)
|
||||
else:
|
||||
raise RuntimeError("Unknown object type")
|
||||
self._objcache.add(obj)
|
||||
return obj
|
||||
|
||||
def _del_object(self, object_path):
|
||||
# FIXME
|
||||
pass
|
||||
def _del_object(self, object_path):
|
||||
# FIXME
|
||||
pass
|
||||
|
||||
def _emit_buddy_appeared_signal(self, object_path):
|
||||
self.emit('buddy-appeared', self._new_object(object_path))
|
||||
return False
|
||||
def _emit_buddy_appeared_signal(self, object_path):
|
||||
self.emit('buddy-appeared', self._new_object(object_path))
|
||||
return False
|
||||
|
||||
def _buddy_appeared_cb(self, op):
|
||||
gobject.idle_add(self._emit_buddy_appeared_signal, op)
|
||||
def _buddy_appeared_cb(self, op):
|
||||
gobject.idle_add(self._emit_buddy_appeared_signal, op)
|
||||
|
||||
def _emit_buddy_disappeared_signal(self, object_path):
|
||||
self.emit('buddy-disappeared', self._new_object(object_path))
|
||||
return False
|
||||
def _emit_buddy_disappeared_signal(self, object_path):
|
||||
self.emit('buddy-disappeared', self._new_object(object_path))
|
||||
return False
|
||||
|
||||
def _buddy_disappeared_cb(self, object_path):
|
||||
gobject.idle_add(self._emit_buddy_disappeared_signal, object_path)
|
||||
def _buddy_disappeared_cb(self, object_path):
|
||||
gobject.idle_add(self._emit_buddy_disappeared_signal, object_path)
|
||||
|
||||
def _emit_service_appeared_signal(self, object_path):
|
||||
self.emit('service-appeared', self._new_object(object_path))
|
||||
return False
|
||||
def _emit_service_appeared_signal(self, object_path):
|
||||
self.emit('service-appeared', self._new_object(object_path))
|
||||
return False
|
||||
|
||||
def _service_appeared_cb(self, object_path):
|
||||
gobject.idle_add(self._emit_service_appeared_signal, object_path)
|
||||
def _service_appeared_cb(self, object_path):
|
||||
gobject.idle_add(self._emit_service_appeared_signal, object_path)
|
||||
|
||||
def _emit_service_disappeared_signal(self, object_path):
|
||||
self.emit('service-disappeared', self._new_object(object_path))
|
||||
return False
|
||||
def _emit_service_disappeared_signal(self, object_path):
|
||||
self.emit('service-disappeared', self._new_object(object_path))
|
||||
return False
|
||||
|
||||
def _service_disappeared_cb(self, object_path):
|
||||
gobject.idle_add(self._emit_service_disappeared_signal, object_path)
|
||||
def _service_disappeared_cb(self, object_path):
|
||||
gobject.idle_add(self._emit_service_disappeared_signal, object_path)
|
||||
|
||||
def _emit_activity_appeared_signal(self, object_path):
|
||||
self.emit('activity-appeared', self._new_object(object_path))
|
||||
return False
|
||||
def _emit_activity_appeared_signal(self, object_path):
|
||||
self.emit('activity-appeared', self._new_object(object_path))
|
||||
return False
|
||||
|
||||
def _activity_appeared_cb(self, object_path):
|
||||
gobject.idle_add(self._emit_activity_appeared_signal, object_path)
|
||||
def _activity_appeared_cb(self, object_path):
|
||||
gobject.idle_add(self._emit_activity_appeared_signal, object_path)
|
||||
|
||||
def _emit_activity_disappeared_signal(self, object_path):
|
||||
self.emit('activity-disappeared', self._new_object(object_path))
|
||||
return False
|
||||
def _emit_activity_disappeared_signal(self, object_path):
|
||||
self.emit('activity-disappeared', self._new_object(object_path))
|
||||
return False
|
||||
|
||||
def _activity_disappeared_cb(self, object_path):
|
||||
gobject.idle_add(self._emit_activity_disappeared_signal, object_path)
|
||||
def _activity_disappeared_cb(self, object_path):
|
||||
gobject.idle_add(self._emit_activity_disappeared_signal, object_path)
|
||||
|
||||
def get(self, object_path):
|
||||
return self._new_object(object_path)
|
||||
def get(self, object_path):
|
||||
return self._new_object(object_path)
|
||||
|
||||
def get_services(self):
|
||||
resp = self._ps.getServices()
|
||||
servs = []
|
||||
for item in resp:
|
||||
servs.append(self._new_object(item))
|
||||
return servs
|
||||
def get_services(self):
|
||||
resp = self._ps.getServices()
|
||||
servs = []
|
||||
for item in resp:
|
||||
servs.append(self._new_object(item))
|
||||
return servs
|
||||
|
||||
def get_services_of_type(self, stype):
|
||||
resp = self._ps.getServicesOfType(stype)
|
||||
servs = []
|
||||
for item in resp:
|
||||
servs.append(self._new_object(item))
|
||||
return servs
|
||||
def get_services_of_type(self, stype):
|
||||
resp = self._ps.getServicesOfType(stype)
|
||||
servs = []
|
||||
for item in resp:
|
||||
servs.append(self._new_object(item))
|
||||
return servs
|
||||
|
||||
def get_activities(self):
|
||||
resp = self._ps.getActivities()
|
||||
acts = []
|
||||
for item in resp:
|
||||
acts.append(self._new_object(item))
|
||||
return acts
|
||||
def get_activities(self):
|
||||
resp = self._ps.getActivities()
|
||||
acts = []
|
||||
for item in resp:
|
||||
acts.append(self._new_object(item))
|
||||
return acts
|
||||
|
||||
def get_activity(self, activity_id):
|
||||
try:
|
||||
act_op = self._ps.getActivity(activity_id)
|
||||
except dbus.exceptions.DBusException:
|
||||
return None
|
||||
return self._new_object(act_op)
|
||||
def get_activity(self, activity_id):
|
||||
try:
|
||||
act_op = self._ps.getActivity(activity_id)
|
||||
except dbus.exceptions.DBusException:
|
||||
return None
|
||||
return self._new_object(act_op)
|
||||
|
||||
def get_buddies(self):
|
||||
resp = self._ps.getBuddies()
|
||||
buddies = []
|
||||
for item in resp:
|
||||
buddies.append(self._new_object(item))
|
||||
return buddies
|
||||
def get_buddies(self):
|
||||
resp = self._ps.getBuddies()
|
||||
buddies = []
|
||||
for item in resp:
|
||||
buddies.append(self._new_object(item))
|
||||
return buddies
|
||||
|
||||
def get_buddy_by_name(self, name):
|
||||
try:
|
||||
buddy_op = self._ps.getBuddyByName(name)
|
||||
except dbus.exceptions.DBusException:
|
||||
return None
|
||||
return self._new_object(buddy_op)
|
||||
def get_buddy_by_name(self, name):
|
||||
try:
|
||||
buddy_op = self._ps.getBuddyByName(name)
|
||||
except dbus.exceptions.DBusException:
|
||||
return None
|
||||
return self._new_object(buddy_op)
|
||||
|
||||
def get_buddy_by_address(self, addr):
|
||||
try:
|
||||
buddy_op = self._ps.getBuddyByAddress(addr)
|
||||
except dbus.exceptions.DBusException:
|
||||
return None
|
||||
return self._new_object(buddy_op)
|
||||
def get_buddy_by_address(self, addr):
|
||||
try:
|
||||
buddy_op = self._ps.getBuddyByAddress(addr)
|
||||
except dbus.exceptions.DBusException:
|
||||
return None
|
||||
return self._new_object(buddy_op)
|
||||
|
||||
def get_owner(self):
|
||||
try:
|
||||
owner_op = self._ps.getOwner()
|
||||
except dbus.exceptions.DBusException:
|
||||
return None
|
||||
return self._new_object(owner_op)
|
||||
def get_owner(self):
|
||||
try:
|
||||
owner_op = self._ps.getOwner()
|
||||
except dbus.exceptions.DBusException:
|
||||
return None
|
||||
return self._new_object(owner_op)
|
||||
|
||||
def share_activity(self, activity, stype, properties={}, address=None, port=-1, domain=u"local"):
|
||||
actid = activity.get_id()
|
||||
if address == None:
|
||||
address = u""
|
||||
serv_op = self._ps.shareActivity(actid, stype, properties, address, port, domain)
|
||||
return self._new_object(serv_op)
|
||||
def share_activity(self, activity, stype, properties={}, address=None, port=-1, domain=u"local"):
|
||||
actid = activity.get_id()
|
||||
if address == None:
|
||||
address = u""
|
||||
serv_op = self._ps.shareActivity(actid, stype, properties, address, port, domain)
|
||||
return self._new_object(serv_op)
|
||||
|
||||
def register_service(self, name, stype, properties={}, address=None, port=-1, domain=u"local"):
|
||||
if address == None:
|
||||
address = u""
|
||||
serv_op = self._ps.registerService(name, stype, properties, address, port, domain)
|
||||
return self._new_object(serv_op)
|
||||
def register_service(self, name, stype, properties={}, address=None, port=-1, domain=u"local"):
|
||||
if address == None:
|
||||
address = u""
|
||||
serv_op = self._ps.registerService(name, stype, properties, address, port, domain)
|
||||
return self._new_object(serv_op)
|
||||
|
||||
def unregister_service(self, service):
|
||||
self._ps.unregisterService(service.object_path())
|
||||
def unregister_service(self, service):
|
||||
self._ps.unregisterService(service.object_path())
|
||||
|
||||
def register_service_type(self, stype):
|
||||
self._ps.registerServiceType(stype)
|
||||
def register_service_type(self, stype):
|
||||
self._ps.registerServiceType(stype)
|
||||
|
||||
def unregister_service_type(self, stype):
|
||||
self._ps.unregisterServiceType(stype)
|
||||
def unregister_service_type(self, stype):
|
||||
self._ps.unregisterServiceType(stype)
|
||||
|
||||
_ps = None
|
||||
def get_instance():
|
||||
global _ps
|
||||
if not _ps:
|
||||
_ps = PresenceService()
|
||||
return _ps
|
||||
global _ps
|
||||
if not _ps:
|
||||
_ps = PresenceService()
|
||||
return _ps
|
||||
|
||||
|
||||
def start():
|
||||
bus = dbus.SessionBus()
|
||||
ps = dbus.Interface(bus.get_object(DBUS_SERVICE, DBUS_PATH), DBUS_INTERFACE)
|
||||
ps.start()
|
||||
bus = dbus.SessionBus()
|
||||
ps = dbus.Interface(bus.get_object(DBUS_SERVICE, DBUS_PATH), DBUS_INTERFACE)
|
||||
ps.start()
|
||||
|
||||
+77
-77
@@ -20,101 +20,101 @@ import dbus
|
||||
|
||||
|
||||
def _one_dict_differs(dict1, dict2):
|
||||
diff_keys = []
|
||||
for key, value in dict1.items():
|
||||
if not dict2.has_key(key) or dict2[key] != value:
|
||||
diff_keys.append(key)
|
||||
return diff_keys
|
||||
diff_keys = []
|
||||
for key, value in dict1.items():
|
||||
if not dict2.has_key(key) or dict2[key] != value:
|
||||
diff_keys.append(key)
|
||||
return diff_keys
|
||||
|
||||
def _dicts_differ(dict1, dict2):
|
||||
diff_keys = []
|
||||
diff1 = _one_dict_differs(dict1, dict2)
|
||||
diff2 = _one_dict_differs(dict2, dict1)
|
||||
for key in diff2:
|
||||
if key not in diff1:
|
||||
diff_keys.append(key)
|
||||
diff_keys += diff1
|
||||
return diff_keys
|
||||
diff_keys = []
|
||||
diff1 = _one_dict_differs(dict1, dict2)
|
||||
diff2 = _one_dict_differs(dict2, dict1)
|
||||
for key in diff2:
|
||||
if key not in diff1:
|
||||
diff_keys.append(key)
|
||||
diff_keys += diff1
|
||||
return diff_keys
|
||||
|
||||
class Service(gobject.GObject):
|
||||
|
||||
_PRESENCE_SERVICE = "org.laptop.Presence"
|
||||
_SERVICE_DBUS_INTERFACE = "org.laptop.Presence.Service"
|
||||
_PRESENCE_SERVICE = "org.laptop.Presence"
|
||||
_SERVICE_DBUS_INTERFACE = "org.laptop.Presence.Service"
|
||||
|
||||
__gsignals__ = {
|
||||
'published-value-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT]))
|
||||
}
|
||||
__gsignals__ = {
|
||||
'published-value-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT]))
|
||||
}
|
||||
|
||||
def __init__(self, bus, new_obj_cb, del_obj_cb, object_path):
|
||||
gobject.GObject.__init__(self)
|
||||
self._object_path = object_path
|
||||
self._ps_new_object = new_obj_cb
|
||||
self._ps_del_object = del_obj_cb
|
||||
sobj = bus.get_object(self._PRESENCE_SERVICE, object_path)
|
||||
self._service = dbus.Interface(sobj, self._SERVICE_DBUS_INTERFACE)
|
||||
self._service.connect_to_signal('PropertyChanged', self.__property_changed_cb)
|
||||
self._service.connect_to_signal('PublishedValueChanged',
|
||||
self.__published_value_changed_cb)
|
||||
self._props = self._service.getProperties()
|
||||
self._pubvals = self._service.getPublishedValues()
|
||||
def __init__(self, bus, new_obj_cb, del_obj_cb, object_path):
|
||||
gobject.GObject.__init__(self)
|
||||
self._object_path = object_path
|
||||
self._ps_new_object = new_obj_cb
|
||||
self._ps_del_object = del_obj_cb
|
||||
sobj = bus.get_object(self._PRESENCE_SERVICE, object_path)
|
||||
self._service = dbus.Interface(sobj, self._SERVICE_DBUS_INTERFACE)
|
||||
self._service.connect_to_signal('PropertyChanged', self.__property_changed_cb)
|
||||
self._service.connect_to_signal('PublishedValueChanged',
|
||||
self.__published_value_changed_cb)
|
||||
self._props = self._service.getProperties()
|
||||
self._pubvals = self._service.getPublishedValues()
|
||||
|
||||
def object_path(self):
|
||||
return self._object_path
|
||||
def object_path(self):
|
||||
return self._object_path
|
||||
|
||||
def __property_changed_cb(self, prop_list):
|
||||
self._props = self._service.getProperties()
|
||||
def __property_changed_cb(self, prop_list):
|
||||
self._props = self._service.getProperties()
|
||||
|
||||
def get_published_value(self, key):
|
||||
return self._pubvals[key]
|
||||
def get_published_value(self, key):
|
||||
return self._pubvals[key]
|
||||
|
||||
def get_published_values(self):
|
||||
self._pubvals = self._service.getPublishedValues()
|
||||
return self._pubvals
|
||||
def get_published_values(self):
|
||||
self._pubvals = self._service.getPublishedValues()
|
||||
return self._pubvals
|
||||
|
||||
def set_published_value(self, key, value):
|
||||
if self._pubvals.has_key(key):
|
||||
if self._pubvals[key] == value:
|
||||
return
|
||||
self._pubvals[key] = value
|
||||
self._service.setPublishedValue(key, value)
|
||||
def set_published_value(self, key, value):
|
||||
if self._pubvals.has_key(key):
|
||||
if self._pubvals[key] == value:
|
||||
return
|
||||
self._pubvals[key] = value
|
||||
self._service.setPublishedValue(key, value)
|
||||
|
||||
def set_published_values(self, vals):
|
||||
self._service.setPublishedValues(vals)
|
||||
self._pubvals = vals
|
||||
def set_published_values(self, vals):
|
||||
self._service.setPublishedValues(vals)
|
||||
self._pubvals = vals
|
||||
|
||||
def __published_value_changed_cb(self, keys):
|
||||
oldvals = self._pubvals
|
||||
self.get_published_values()
|
||||
diff_keys = _dicts_differ(oldvals, self._pubvals)
|
||||
if len(diff_keys) > 0:
|
||||
self.emit('published-value-changed', diff_keys)
|
||||
def __published_value_changed_cb(self, keys):
|
||||
oldvals = self._pubvals
|
||||
self.get_published_values()
|
||||
diff_keys = _dicts_differ(oldvals, self._pubvals)
|
||||
if len(diff_keys) > 0:
|
||||
self.emit('published-value-changed', diff_keys)
|
||||
|
||||
def get_name(self):
|
||||
return self._props['name']
|
||||
def get_name(self):
|
||||
return self._props['name']
|
||||
|
||||
def get_type(self):
|
||||
return self._props['type']
|
||||
def get_type(self):
|
||||
return self._props['type']
|
||||
|
||||
def get_domain(self):
|
||||
return self._props['domain']
|
||||
def get_domain(self):
|
||||
return self._props['domain']
|
||||
|
||||
def get_address(self):
|
||||
if self._props.has_key('address'):
|
||||
return self._props['address']
|
||||
return None
|
||||
def get_address(self):
|
||||
if self._props.has_key('address'):
|
||||
return self._props['address']
|
||||
return None
|
||||
|
||||
def get_activity_id(self):
|
||||
if self._props.has_key('activityId'):
|
||||
return self._props['activityId']
|
||||
return None
|
||||
def get_activity_id(self):
|
||||
if self._props.has_key('activityId'):
|
||||
return self._props['activityId']
|
||||
return None
|
||||
|
||||
def get_port(self):
|
||||
if self._props.has_key('port'):
|
||||
return self._props['port']
|
||||
return None
|
||||
def get_port(self):
|
||||
if self._props.has_key('port'):
|
||||
return self._props['port']
|
||||
return None
|
||||
|
||||
def get_source_address(self):
|
||||
if self._props.has_key('sourceAddress'):
|
||||
return self._props['sourceAddress']
|
||||
return None
|
||||
def get_source_address(self):
|
||||
if self._props.has_key('sourceAddress'):
|
||||
return self._props['sourceAddress']
|
||||
return None
|
||||
|
||||
+18
-18
@@ -21,34 +21,34 @@ from sugar import env
|
||||
from sugar.graphics.iconcolor import IconColor
|
||||
|
||||
class _Profile(object):
|
||||
def __init__(self):
|
||||
self.name = None
|
||||
self.color = None
|
||||
self._load()
|
||||
def __init__(self):
|
||||
self.name = None
|
||||
self.color = None
|
||||
self._load()
|
||||
|
||||
def update(self):
|
||||
self._load()
|
||||
def update(self):
|
||||
self._load()
|
||||
|
||||
def _load(self):
|
||||
cp = ConfigParser()
|
||||
config_path = os.path.join(env.get_profile_path(), 'config')
|
||||
parsed = cp.read([config_path])
|
||||
def _load(self):
|
||||
cp = ConfigParser()
|
||||
config_path = os.path.join(env.get_profile_path(), 'config')
|
||||
parsed = cp.read([config_path])
|
||||
|
||||
if cp.has_option('Buddy', 'NickName'):
|
||||
self.name = cp.get('Buddy', 'NickName')
|
||||
if cp.has_option('Buddy', 'NickName'):
|
||||
self.name = cp.get('Buddy', 'NickName')
|
||||
|
||||
if cp.has_option('Buddy', 'Color'):
|
||||
self.color = IconColor(cp.get('Buddy', 'Color'))
|
||||
if cp.has_option('Buddy', 'Color'):
|
||||
self.color = IconColor(cp.get('Buddy', 'Color'))
|
||||
|
||||
del cp
|
||||
del cp
|
||||
|
||||
def get_nick_name():
|
||||
return _profile.name
|
||||
return _profile.name
|
||||
|
||||
def get_color():
|
||||
return _profile.color
|
||||
return _profile.color
|
||||
|
||||
def update():
|
||||
_profile.update()
|
||||
_profile.update()
|
||||
|
||||
_profile = _Profile()
|
||||
|
||||
+108
-108
@@ -33,151 +33,151 @@ _PRESENCE_SERVICE_TYPE = "_presence_olpc._tcp"
|
||||
_activity_refs = {}
|
||||
|
||||
class _NameCollection(object):
|
||||
def __init__(self):
|
||||
self._names = copy.copy(_nick_names)
|
||||
def __init__(self):
|
||||
self._names = copy.copy(_nick_names)
|
||||
|
||||
def get_name(self):
|
||||
i = random.randint(0, len(self._names))
|
||||
return self._names.pop(i)
|
||||
def get_name(self):
|
||||
i = random.randint(0, len(self._names))
|
||||
return self._names.pop(i)
|
||||
|
||||
class _BotService(object):
|
||||
def __init__(self, bot):
|
||||
self._bot = bot
|
||||
def __init__(self, bot):
|
||||
self._bot = bot
|
||||
|
||||
def announce(self):
|
||||
props = { 'color': self._bot.color.to_string() }
|
||||
pservice = PresenceService.get_instance()
|
||||
self._service = pservice.register_service(self._bot.name,
|
||||
_PRESENCE_SERVICE_TYPE, properties=props)
|
||||
def announce(self):
|
||||
props = { 'color': self._bot.color.to_string() }
|
||||
pservice = PresenceService.get_instance()
|
||||
self._service = pservice.register_service(self._bot.name,
|
||||
_PRESENCE_SERVICE_TYPE, properties=props)
|
||||
|
||||
self._stream = Stream.Stream.new_from_service(self._service)
|
||||
self._stream.register_reader_handler(
|
||||
self._handle_buddy_icon_request, "get_buddy_icon")
|
||||
self._stream.register_reader_handler(
|
||||
self._handle_invite, "invite")
|
||||
self._stream = Stream.Stream.new_from_service(self._service)
|
||||
self._stream.register_reader_handler(
|
||||
self._handle_buddy_icon_request, "get_buddy_icon")
|
||||
self._stream.register_reader_handler(
|
||||
self._handle_invite, "invite")
|
||||
|
||||
def _handle_buddy_icon_request(self):
|
||||
if self._bot.icon:
|
||||
fd = open(self._bot.icon, "r")
|
||||
icon_data = fd.read()
|
||||
fd.close()
|
||||
if icon_data:
|
||||
return base64.b64encode(self._icon)
|
||||
return ''
|
||||
def _handle_buddy_icon_request(self):
|
||||
if self._bot.icon:
|
||||
fd = open(self._bot.icon, "r")
|
||||
icon_data = fd.read()
|
||||
fd.close()
|
||||
if icon_data:
|
||||
return base64.b64encode(self._icon)
|
||||
return ''
|
||||
|
||||
def _handle_invite(self, issuer, bundle_id, activity_id):
|
||||
return ''
|
||||
def _handle_invite(self, issuer, bundle_id, activity_id):
|
||||
return ''
|
||||
|
||||
def set_current_activity(self, activity_id):
|
||||
self._service.set_published_value('curact', dbus.String(activity_id))
|
||||
def set_current_activity(self, activity_id):
|
||||
self._service.set_published_value('curact', dbus.String(activity_id))
|
||||
|
||||
class _JoinActivityAction(object):
|
||||
def __init__(self, bot, named_ref):
|
||||
self._bot = bot
|
||||
self._named_ref = named_ref
|
||||
def __init__(self, bot, named_ref):
|
||||
self._bot = bot
|
||||
self._named_ref = named_ref
|
||||
|
||||
def execute(self):
|
||||
activity_id = _activity_refs[self._named_ref]
|
||||
def execute(self):
|
||||
activity_id = _activity_refs[self._named_ref]
|
||||
|
||||
pservice = PresenceService.get_instance()
|
||||
activity = pservice.get_activity(activity_id)
|
||||
service = activity.get_services()[0]
|
||||
pservice = PresenceService.get_instance()
|
||||
activity = pservice.get_activity(activity_id)
|
||||
service = activity.get_services()[0]
|
||||
|
||||
name = "%s [%s]" % (self._bot.name, activity_id)
|
||||
properties = { 'title' : service.get_published_value('title'),
|
||||
'color' : service.get_published_value('color') }
|
||||
name = "%s [%s]" % (self._bot.name, activity_id)
|
||||
properties = { 'title' : service.get_published_value('title'),
|
||||
'color' : service.get_published_value('color') }
|
||||
|
||||
pservice.register_service(name, service.get_type(),
|
||||
properties, service.get_address(),
|
||||
service.get_port())
|
||||
pservice.register_service(name, service.get_type(),
|
||||
properties, service.get_address(),
|
||||
service.get_port())
|
||||
|
||||
self._bot._service.set_current_activity(activity_id)
|
||||
self._bot._service.set_current_activity(activity_id)
|
||||
|
||||
class _ChangeActivityAction(object):
|
||||
def __init__(self, bot, named_ref):
|
||||
self._bot = bot
|
||||
self._named_ref = named_ref
|
||||
def __init__(self, bot, named_ref):
|
||||
self._bot = bot
|
||||
self._named_ref = named_ref
|
||||
|
||||
def execute(self):
|
||||
activity_id = _activity_refs[self._named_ref]
|
||||
self._bot._service.set_current_activity(activity_id)
|
||||
def execute(self):
|
||||
activity_id = _activity_refs[self._named_ref]
|
||||
self._bot._service.set_current_activity(activity_id)
|
||||
|
||||
class _ShareChatAction(object):
|
||||
def __init__(self, bot, named_ref, title):
|
||||
self._bot = bot
|
||||
self._title = title
|
||||
self._id = util.unique_id()
|
||||
def __init__(self, bot, named_ref, title):
|
||||
self._bot = bot
|
||||
self._title = title
|
||||
self._id = util.unique_id()
|
||||
|
||||
_activity_refs[named_ref] = self._id
|
||||
_activity_refs[named_ref] = self._id
|
||||
|
||||
def execute(self):
|
||||
name = "%s [%s]" % (self._bot.name, self._id)
|
||||
stype = '_GroupChatActivity_Sugar_redhat_com._udp'
|
||||
properties = { 'title' : self._title,
|
||||
'color' : self._bot.color.to_string() }
|
||||
address = u"232.%d.%d.%d" % (random.randint(0, 254),
|
||||
random.randint(1, 254),
|
||||
random.randint(1, 254))
|
||||
def execute(self):
|
||||
name = "%s [%s]" % (self._bot.name, self._id)
|
||||
stype = '_GroupChatActivity_Sugar_redhat_com._udp'
|
||||
properties = { 'title' : self._title,
|
||||
'color' : self._bot.color.to_string() }
|
||||
address = u"232.%d.%d.%d" % (random.randint(0, 254),
|
||||
random.randint(1, 254),
|
||||
random.randint(1, 254))
|
||||
|
||||
pservice = PresenceService.get_instance()
|
||||
pservice.register_service(name, stype, properties, address)
|
||||
pservice = PresenceService.get_instance()
|
||||
pservice.register_service(name, stype, properties, address)
|
||||
|
||||
class _WaitAction(object):
|
||||
def __init__(self, bot, seconds):
|
||||
self._bot = bot
|
||||
self._seconds = seconds
|
||||
|
||||
def execute(self):
|
||||
self._bot._pause_queue(self._seconds)
|
||||
def __init__(self, bot, seconds):
|
||||
self._bot = bot
|
||||
self._seconds = seconds
|
||||
|
||||
def execute(self):
|
||||
self._bot._pause_queue(self._seconds)
|
||||
|
||||
class Bot(object):
|
||||
_name_collection = _NameCollection()
|
||||
_name_collection = _NameCollection()
|
||||
|
||||
def __init__(self):
|
||||
self.name = Bot._name_collection.get_name()
|
||||
self.color = IconColor()
|
||||
self.icon = None
|
||||
def __init__(self):
|
||||
self.name = Bot._name_collection.get_name()
|
||||
self.color = IconColor()
|
||||
self.icon = None
|
||||
|
||||
self._queue = []
|
||||
self._queue = []
|
||||
|
||||
def wait(self, seconds):
|
||||
action = _WaitAction(self, seconds)
|
||||
self._queue.append(action)
|
||||
def wait(self, seconds):
|
||||
action = _WaitAction(self, seconds)
|
||||
self._queue.append(action)
|
||||
|
||||
def share_chat(self, activity_id, title):
|
||||
action = _ShareChatAction(self, activity_id, title)
|
||||
self._queue.append(action)
|
||||
def share_chat(self, activity_id, title):
|
||||
action = _ShareChatAction(self, activity_id, title)
|
||||
self._queue.append(action)
|
||||
|
||||
def change_activity(self, activity_id):
|
||||
action = _ChangeActivityAction(self, activity_id)
|
||||
self._queue.append(action)
|
||||
def change_activity(self, activity_id):
|
||||
action = _ChangeActivityAction(self, activity_id)
|
||||
self._queue.append(action)
|
||||
|
||||
def join_activity(self, activity_id):
|
||||
action = _JoinActivityAction(self, activity_id)
|
||||
self._queue.append(action)
|
||||
def join_activity(self, activity_id):
|
||||
action = _JoinActivityAction(self, activity_id)
|
||||
self._queue.append(action)
|
||||
|
||||
def start(self):
|
||||
self._service = _BotService(self)
|
||||
self._service.announce()
|
||||
def start(self):
|
||||
self._service = _BotService(self)
|
||||
self._service.announce()
|
||||
|
||||
self._start_queue()
|
||||
self._start_queue()
|
||||
|
||||
def _idle_cb(self):
|
||||
self._next_action()
|
||||
return True
|
||||
def _idle_cb(self):
|
||||
self._next_action()
|
||||
return True
|
||||
|
||||
def _pause_done_cb(self):
|
||||
self._start_queue()
|
||||
return False
|
||||
def _pause_done_cb(self):
|
||||
self._start_queue()
|
||||
return False
|
||||
|
||||
def _start_queue(self):
|
||||
self._queue_sid = gobject.idle_add(self._idle_cb)
|
||||
def _start_queue(self):
|
||||
self._queue_sid = gobject.idle_add(self._idle_cb)
|
||||
|
||||
def _pause_queue(self, seconds):
|
||||
gobject.source_remove(self._queue_sid)
|
||||
gobject.timeout_add(int(seconds * 1000), self._pause_done_cb)
|
||||
def _pause_queue(self, seconds):
|
||||
gobject.source_remove(self._queue_sid)
|
||||
gobject.timeout_add(int(seconds * 1000), self._pause_done_cb)
|
||||
|
||||
def _next_action(self):
|
||||
if len(self._queue) > 0:
|
||||
action = self._queue.pop(0)
|
||||
action.execute()
|
||||
def _next_action(self):
|
||||
if len(self._queue) > 0:
|
||||
action = self._queue.pop(0)
|
||||
action.execute()
|
||||
|
||||
+31
-31
@@ -25,50 +25,50 @@ from ConfigParser import ConfigParser
|
||||
from ConfigParser import NoOptionError
|
||||
|
||||
def printable_hash(in_hash):
|
||||
"""Convert binary hash data into printable characters."""
|
||||
printable = ""
|
||||
for char in in_hash:
|
||||
printable = printable + binascii.b2a_hex(char)
|
||||
return printable
|
||||
"""Convert binary hash data into printable characters."""
|
||||
printable = ""
|
||||
for char in in_hash:
|
||||
printable = printable + binascii.b2a_hex(char)
|
||||
return printable
|
||||
|
||||
def _sha_data(data):
|
||||
"""sha1 hash some bytes."""
|
||||
sha_hash = sha.new()
|
||||
sha_hash.update(data)
|
||||
return sha_hash.digest()
|
||||
"""sha1 hash some bytes."""
|
||||
sha_hash = sha.new()
|
||||
sha_hash.update(data)
|
||||
return sha_hash.digest()
|
||||
|
||||
def unique_id(data = ''):
|
||||
data_string = "%s%s%s" % (time.time(), random.randint(10000, 100000), data)
|
||||
return printable_hash(_sha_data(data_string))
|
||||
data_string = "%s%s%s" % (time.time(), random.randint(10000, 100000), data)
|
||||
return printable_hash(_sha_data(data_string))
|
||||
|
||||
|
||||
ACTIVITY_ID_LEN = 40
|
||||
|
||||
def is_hex(s):
|
||||
return s.strip(string.hexdigits) == ''
|
||||
return s.strip(string.hexdigits) == ''
|
||||
|
||||
def validate_activity_id(actid):
|
||||
"""Validate an activity ID."""
|
||||
if not isinstance(actid, str) and not isinstance(actid, unicode):
|
||||
return False
|
||||
if len(actid) != ACTIVITY_ID_LEN:
|
||||
return False
|
||||
if not is_hex(actid):
|
||||
return False
|
||||
return True
|
||||
"""Validate an activity ID."""
|
||||
if not isinstance(actid, str) and not isinstance(actid, unicode):
|
||||
return False
|
||||
if len(actid) != ACTIVITY_ID_LEN:
|
||||
return False
|
||||
if not is_hex(actid):
|
||||
return False
|
||||
return True
|
||||
|
||||
class _ServiceParser(ConfigParser):
|
||||
def optionxform(self, option):
|
||||
return option
|
||||
def optionxform(self, option):
|
||||
return option
|
||||
|
||||
def write_service(name, bin, path):
|
||||
service_cp = _ServiceParser()
|
||||
section = 'D-BUS Service'
|
||||
service_cp.add_section(section)
|
||||
service_cp.set(section, 'Name', name)
|
||||
service_cp.set(section, 'Exec', bin)
|
||||
service_cp = _ServiceParser()
|
||||
section = 'D-BUS Service'
|
||||
service_cp.add_section(section)
|
||||
service_cp.set(section, 'Name', name)
|
||||
service_cp.set(section, 'Exec', bin)
|
||||
|
||||
dest_filename = os.path.join(path, name + '.service')
|
||||
fileobject = open(dest_filename, 'w')
|
||||
service_cp.write(fileobject)
|
||||
fileobject.close()
|
||||
dest_filename = os.path.join(path, name + '.service')
|
||||
fileobject = open(dest_filename, 'w')
|
||||
service_cp.write(fileobject)
|
||||
fileobject.close()
|
||||
|
||||
Reference in New Issue
Block a user