Changed all tabs to 4 spaces for python style

This commit is contained in:
Justin Gallardo 2006-12-04 11:12:24 -08:00
parent f5ae066248
commit b9f9ef0fe9
110 changed files with 9987 additions and 9987 deletions

View File

@ -24,53 +24,53 @@ from sugar import env
class ClipboardDBusServiceHelper(dbus.service.Object): class ClipboardDBusServiceHelper(dbus.service.Object):
_CLIPBOARD_DBUS_INTERFACE = "org.laptop.Clipboard" _CLIPBOARD_DBUS_INTERFACE = "org.laptop.Clipboard"
_CLIPBOARD_OBJECT_PATH = "/org/laptop/Clipboard" _CLIPBOARD_OBJECT_PATH = "/org/laptop/Clipboard"
def __init__(self, parent): def __init__(self, parent):
self._parent = parent self._parent = parent
bus = dbus.SessionBus() bus = dbus.SessionBus()
bus_name = dbus.service.BusName(self._CLIPBOARD_DBUS_INTERFACE, bus=bus) bus_name = dbus.service.BusName(self._CLIPBOARD_DBUS_INTERFACE, bus=bus)
dbus.service.Object.__init__(self, bus_name, self._CLIPBOARD_OBJECT_PATH) dbus.service.Object.__init__(self, bus_name, self._CLIPBOARD_OBJECT_PATH)
@dbus.service.method(_CLIPBOARD_DBUS_INTERFACE, @dbus.service.method(_CLIPBOARD_DBUS_INTERFACE,
in_signature="sss", out_signature="") in_signature="sss", out_signature="")
def add_object(self, name, mimeType, fileName): def add_object(self, name, mimeType, fileName):
self.object_added(name, mimeType, fileName) self.object_added(name, mimeType, fileName)
logging.debug('Added object of type ' + mimeType + ' with path at ' + fileName) logging.debug('Added object of type ' + mimeType + ' with path at ' + fileName)
@dbus.service.method(_CLIPBOARD_DBUS_INTERFACE, @dbus.service.method(_CLIPBOARD_DBUS_INTERFACE,
in_signature="s", out_signature="") in_signature="s", out_signature="")
def delete_object(self, fileName): def delete_object(self, fileName):
self.object_deleted(fileName) self.object_deleted(fileName)
logging.debug('Deleted object with path at ' + fileName) logging.debug('Deleted object with path at ' + fileName)
@dbus.service.method(_CLIPBOARD_DBUS_INTERFACE, @dbus.service.method(_CLIPBOARD_DBUS_INTERFACE,
in_signature="si", out_signature="") in_signature="si", out_signature="")
def set_object_state(self, fileName, percent): def set_object_state(self, fileName, percent):
logging.debug('Changed object with path at ' + fileName + ' with percent ' + str(percent)) logging.debug('Changed object with path at ' + fileName + ' with percent ' + str(percent))
self.object_state_changed(fileName, percent) self.object_state_changed(fileName, percent)
@dbus.service.signal(_CLIPBOARD_DBUS_INTERFACE, signature="sss") @dbus.service.signal(_CLIPBOARD_DBUS_INTERFACE, signature="sss")
def object_added(self, name, mimeType, fileName): def object_added(self, name, mimeType, fileName):
pass pass
@dbus.service.signal(_CLIPBOARD_DBUS_INTERFACE, signature="s") @dbus.service.signal(_CLIPBOARD_DBUS_INTERFACE, signature="s")
def object_deleted(self, fileName): def object_deleted(self, fileName):
pass pass
@dbus.service.signal(_CLIPBOARD_DBUS_INTERFACE, signature="si") @dbus.service.signal(_CLIPBOARD_DBUS_INTERFACE, signature="si")
def object_state_changed(self, fileName, percent): def object_state_changed(self, fileName, percent):
pass pass
class ClipboardService(object): class ClipboardService(object):
def __init__(self): def __init__(self):
self._dbus_helper = ClipboardDBusServiceHelper(self) self._dbus_helper = ClipboardDBusServiceHelper(self)
def run(self): def run(self):
loop = gobject.MainLoop() loop = gobject.MainLoop()
try: try:
loop.run() loop.run()
except KeyboardInterrupt: except KeyboardInterrupt:
print 'Ctrl+C pressed, exiting...' print 'Ctrl+C pressed, exiting...'

View File

@ -22,111 +22,111 @@ import gtk
import hippo import hippo
class Bubble(hippo.CanvasBox, hippo.CanvasItem): class Bubble(hippo.CanvasBox, hippo.CanvasItem):
__gtype_name__ = 'NetworkBubble' __gtype_name__ = 'NetworkBubble'
__gproperties__ = { __gproperties__ = {
'fill-color': (object, None, None, 'fill-color': (object, None, None,
gobject.PARAM_READWRITE), gobject.PARAM_READWRITE),
'stroke-color': (object, None, None, 'stroke-color': (object, None, None,
gobject.PARAM_READWRITE), gobject.PARAM_READWRITE),
'progress-color': (object, None, None, 'progress-color': (object, None, None,
gobject.PARAM_READWRITE), gobject.PARAM_READWRITE),
'percent' : (object, None, None, 'percent' : (object, None, None,
gobject.PARAM_READWRITE), gobject.PARAM_READWRITE),
} }
def __init__(self, **kwargs): def __init__(self, **kwargs):
self._stroke_color = 0xFFFFFFFF self._stroke_color = 0xFFFFFFFF
self._fill_color = 0xFFFFFFFF self._fill_color = 0xFFFFFFFF
self._progress_color = 0x000000FF self._progress_color = 0x000000FF
self._percent = 0 self._percent = 0
self._radius = 8 self._radius = 8
hippo.CanvasBox.__init__(self, **kwargs) hippo.CanvasBox.__init__(self, **kwargs)
def do_set_property(self, pspec, value): def do_set_property(self, pspec, value):
if pspec.name == 'fill-color': if pspec.name == 'fill-color':
self._fill_color = value self._fill_color = value
self.emit_paint_needed(0, 0, -1, -1) self.emit_paint_needed(0, 0, -1, -1)
elif pspec.name == 'stroke-color': elif pspec.name == 'stroke-color':
self._stroke_color = value self._stroke_color = value
self.emit_paint_needed(0, 0, -1, -1) self.emit_paint_needed(0, 0, -1, -1)
elif pspec.name == 'progress-color': elif pspec.name == 'progress-color':
self._progress_color = value self._progress_color = value
self.emit_paint_needed(0, 0, -1, -1) self.emit_paint_needed(0, 0, -1, -1)
elif pspec.name == 'percent': elif pspec.name == 'percent':
self._percent = value self._percent = value
self.emit_paint_needed(0, 0, -1, -1) self.emit_paint_needed(0, 0, -1, -1)
def do_get_property(self, pspec): def do_get_property(self, pspec):
if pspec.name == 'fill-color': if pspec.name == 'fill-color':
return self._fill_color return self._fill_color
elif pspec.name == 'stroke-color': elif pspec.name == 'stroke-color':
return self._stroke_color return self._stroke_color
elif pspec.name == 'progress-color': elif pspec.name == 'progress-color':
return self._progress_color return self._progress_color
elif pspec.name == 'percent': elif pspec.name == 'percent':
return self._percent return self._percent
def _int_to_rgb(self, int_color): def _int_to_rgb(self, int_color):
red = (int_color >> 24) & 0x000000FF red = (int_color >> 24) & 0x000000FF
green = (int_color >> 16) & 0x000000FF green = (int_color >> 16) & 0x000000FF
blue = (int_color >> 8) & 0x000000FF blue = (int_color >> 8) & 0x000000FF
alpha = int_color & 0x000000FF alpha = int_color & 0x000000FF
return (red / 255.0, green / 255.0, blue / 255.0) return (red / 255.0, green / 255.0, blue / 255.0)
def do_paint_below_children(self, cr, damaged_box): def do_paint_below_children(self, cr, damaged_box):
[width, height] = self.get_allocation() [width, height] = self.get_allocation()
line_width = 3.0 line_width = 3.0
x = line_width x = line_width
y = line_width y = line_width
width -= line_width * 2 width -= line_width * 2
height -= line_width * 2 height -= line_width * 2
cr.move_to(x + self._radius, y); cr.move_to(x + self._radius, y);
cr.arc(x + width - self._radius, y + self._radius, cr.arc(x + width - self._radius, y + self._radius,
self._radius, math.pi * 1.5, math.pi * 2); self._radius, math.pi * 1.5, math.pi * 2);
cr.arc(x + width - self._radius, x + height - self._radius, cr.arc(x + width - self._radius, x + height - self._radius,
self._radius, 0, math.pi * 0.5); self._radius, 0, math.pi * 0.5);
cr.arc(x + self._radius, y + height - self._radius, cr.arc(x + self._radius, y + height - self._radius,
self._radius, math.pi * 0.5, math.pi); self._radius, math.pi * 0.5, math.pi);
cr.arc(x + self._radius, y + self._radius, self._radius, cr.arc(x + self._radius, y + self._radius, self._radius,
math.pi, math.pi * 1.5); math.pi, math.pi * 1.5);
color = self._int_to_rgb(self._fill_color) color = self._int_to_rgb(self._fill_color)
cr.set_source_rgb(*color) cr.set_source_rgb(*color)
cr.fill_preserve(); cr.fill_preserve();
color = self._int_to_rgb(self._stroke_color) color = self._int_to_rgb(self._stroke_color)
cr.set_source_rgb(*color) cr.set_source_rgb(*color)
cr.set_line_width(line_width) cr.set_line_width(line_width)
cr.stroke(); cr.stroke();
if self._percent > 0: if self._percent > 0:
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): def _paint_progress_bar(self, cr, x, y, width, height, line_width):
prog_x = x + line_width prog_x = x + line_width
prog_y = y + line_width prog_y = y + line_width
prog_width = (width - (line_width * 2)) * (self._percent / 100.0) prog_width = (width - (line_width * 2)) * (self._percent / 100.0)
prog_height = (height - (line_width * 2)) prog_height = (height - (line_width * 2))
x = prog_x x = prog_x
y = prog_y y = prog_y
width = prog_width width = prog_width
height = prog_height height = prog_height
cr.move_to(x + self._radius, y); cr.move_to(x + self._radius, y);
cr.arc(x + width - self._radius, y + self._radius, cr.arc(x + width - self._radius, y + self._radius,
self._radius, math.pi * 1.5, math.pi * 2); self._radius, math.pi * 1.5, math.pi * 2);
cr.arc(x + width - self._radius, x + height - self._radius, cr.arc(x + width - self._radius, x + height - self._radius,
self._radius, 0, math.pi * 0.5); self._radius, 0, math.pi * 0.5);
cr.arc(x + self._radius, y + height - self._radius, cr.arc(x + self._radius, y + height - self._radius,
self._radius, math.pi * 0.5, math.pi); self._radius, math.pi * 0.5, math.pi);
cr.arc(x + self._radius, y + self._radius, self._radius, cr.arc(x + self._radius, y + self._radius, self._radius,
math.pi, math.pi * 1.5); math.pi, math.pi * 1.5);
color = self._int_to_rgb(self._progress_color) color = self._int_to_rgb(self._progress_color)
cr.set_source_rgb(*color) cr.set_source_rgb(*color)
cr.fill_preserve(); cr.fill_preserve();

File diff suppressed because it is too large Load Diff

View File

@ -26,65 +26,65 @@ import logging
import nmclient import nmclient
try: try:
from sugar import env from sugar import env
except ImportError: except ImportError:
pass pass
NM_INFO_IFACE='org.freedesktop.NetworkManagerInfo' NM_INFO_IFACE='org.freedesktop.NetworkManagerInfo'
NM_INFO_PATH='/org/freedesktop/NetworkManagerInfo' NM_INFO_PATH='/org/freedesktop/NetworkManagerInfo'
class NoNetworks(dbus.DBusException): class NoNetworks(dbus.DBusException):
def __init__(self): def __init__(self):
dbus.DBusException.__init__(self) dbus.DBusException.__init__(self)
self._dbus_error_name = NM_INFO_IFACE + '.NoNetworks' self._dbus_error_name = NM_INFO_IFACE + '.NoNetworks'
class CanceledKeyRequestError(dbus.DBusException): class CanceledKeyRequestError(dbus.DBusException):
def __init__(self): def __init__(self):
dbus.DBusException.__init__(self) dbus.DBusException.__init__(self)
self._dbus_error_name = NM_INFO_IFACE + '.CanceledError' self._dbus_error_name = NM_INFO_IFACE + '.CanceledError'
class NetworkInvalidError(Exception): class NetworkInvalidError(Exception):
pass pass
class NMConfig(ConfigParser.ConfigParser): class NMConfig(ConfigParser.ConfigParser):
def get_bool(self, section, name): def get_bool(self, section, name):
opt = self.get(section, name) opt = self.get(section, name)
if type(opt) == type(""): if type(opt) == type(""):
if opt.lower() == 'yes' or opt.lower() == 'true': if opt.lower() == 'yes' or opt.lower() == 'true':
return True return True
elif opt.lower() == 'no' or opt.lower() == 'false': elif opt.lower() == 'no' or opt.lower() == 'false':
return False return False
raise ValueError("Invalid format for %s/%s. Should be one of [yes, no, true, false]." % (section, name)) raise ValueError("Invalid format for %s/%s. Should be one of [yes, no, true, false]." % (section, name))
def get_list(self, section, name): def get_list(self, section, name):
opt = self.get(section, name) opt = self.get(section, name)
if type(opt) == type(""): if type(opt) == type(""):
if not len(opt): if not len(opt):
return [] return []
try: try:
return opt.split() return opt.split()
except Exception: except Exception:
pass pass
raise ValueError("Invalid format for %s/%s. Should be a space-separate list." % (section, name)) raise ValueError("Invalid format for %s/%s. Should be a space-separate list." % (section, name))
def get_int(self, section, name): def get_int(self, section, name):
opt = self.get(section, name) opt = self.get(section, name)
try: try:
return int(opt) return int(opt)
except Exception: except Exception:
pass pass
raise ValueError("Invalid format for %s/%s. Should be a valid integer." % (section, name)) raise ValueError("Invalid format for %s/%s. Should be a valid integer." % (section, name))
def get_float(self, section, name): def get_float(self, section, name):
opt = self.get(section, name) opt = self.get(section, name)
try: try:
return float(opt) return float(opt)
except Exception: except Exception:
pass pass
raise ValueError("Invalid format for %s/%s. Should be a valid float." % (section, name)) raise ValueError("Invalid format for %s/%s. Should be a valid float." % (section, name))
IW_AUTH_CIPHER_NONE = 0x00000001 IW_AUTH_CIPHER_NONE = 0x00000001
@ -102,366 +102,366 @@ NETWORK_TYPE_INVALID = 2
class Security(object): class Security(object):
def __init__(self, we_cipher): def __init__(self, we_cipher):
self._we_cipher = we_cipher self._we_cipher = we_cipher
def read_from_config(self, cfg, name): def read_from_config(self, cfg, name):
pass pass
def read_from_args(self, args): def read_from_args(self, args):
pass pass
def new_from_config(cfg, name): def new_from_config(cfg, name):
security = None security = None
try: try:
we_cipher = cfg.get_int(name, "we_cipher") we_cipher = cfg.get_int(name, "we_cipher")
if we_cipher == IW_AUTH_CIPHER_NONE: if we_cipher == IW_AUTH_CIPHER_NONE:
security = Security(we_cipher) security = Security(we_cipher)
elif we_cipher == IW_AUTH_CIPHER_WEP40 or we_cipher == IW_AUTH_CIPHER_WEP104: elif we_cipher == IW_AUTH_CIPHER_WEP40 or we_cipher == IW_AUTH_CIPHER_WEP104:
security = WEPSecurity(we_cipher) security = WEPSecurity(we_cipher)
else: else:
# FIXME: find a way to make WPA config option matrix not # FIXME: find a way to make WPA config option matrix not
# make you want to throw up # make you want to throw up
raise ValueError("Unsupported security combo") raise ValueError("Unsupported security combo")
security.read_from_config(cfg, name) security.read_from_config(cfg, name)
except (ConfigParser.NoOptionError, ValueError), e: except (ConfigParser.NoOptionError, ValueError), e:
return None return None
return security return security
new_from_config = staticmethod(new_from_config) new_from_config = staticmethod(new_from_config)
def new_from_args(we_cipher, args): def new_from_args(we_cipher, args):
security = None security = None
try: try:
if we_cipher == IW_AUTH_CIPHER_NONE: if we_cipher == IW_AUTH_CIPHER_NONE:
security = Security(we_cipher) security = Security(we_cipher)
elif we_cipher == IW_AUTH_CIPHER_WEP40 or we_cipher == IW_AUTH_CIPHER_WEP104: elif we_cipher == IW_AUTH_CIPHER_WEP40 or we_cipher == IW_AUTH_CIPHER_WEP104:
security = WEPSecurity(we_cipher) security = WEPSecurity(we_cipher)
else: else:
# FIXME: find a way to make WPA config option matrix not # FIXME: find a way to make WPA config option matrix not
# make you want to throw up # make you want to throw up
raise ValueError("Unsupported security combo") raise ValueError("Unsupported security combo")
security.read_from_args(args) security.read_from_args(args)
except ValueError, e: except ValueError, e:
logging.debug("Error reading security information: %s" % e) logging.debug("Error reading security information: %s" % e)
del security del security
return None return None
return security return security
new_from_args = staticmethod(new_from_args) new_from_args = staticmethod(new_from_args)
def get_properties(self): def get_properties(self):
return [dbus.Int32(self._we_cipher)] return [dbus.Int32(self._we_cipher)]
def write_to_config(self, section, config): def write_to_config(self, section, config):
config.set(section, "we_cipher", self._we_cipher) config.set(section, "we_cipher", self._we_cipher)
class WEPSecurity(Security): class WEPSecurity(Security):
def read_from_args(self, args): def read_from_args(self, args):
if len(args) != 2: if len(args) != 2:
raise ValueError("not enough arguments") raise ValueError("not enough arguments")
key = args[0] key = args[0]
auth_alg = args[1] auth_alg = args[1]
if isinstance(key, unicode): if isinstance(key, unicode):
key = key.encode() key = key.encode()
if not isinstance(key, str): if not isinstance(key, str):
raise ValueError("wrong argument type for key") raise ValueError("wrong argument type for key")
if not isinstance(auth_alg, int): if not isinstance(auth_alg, int):
raise ValueError("wrong argument type for auth_alg") raise ValueError("wrong argument type for auth_alg")
self._key = key self._key = key
self._auth_alg = auth_alg self._auth_alg = auth_alg
def read_from_config(self, cfg, name): def read_from_config(self, cfg, name):
# Key should be a hex encoded string # Key should be a hex encoded string
self._key = cfg.get(name, "key") self._key = cfg.get(name, "key")
if self._we_cipher == IW_AUTH_CIPHER_WEP40 and len(self._key) != 10: if self._we_cipher == IW_AUTH_CIPHER_WEP40 and len(self._key) != 10:
raise ValueError("Key length not right for 40-bit WEP") raise ValueError("Key length not right for 40-bit WEP")
if self._we_cipher == IW_AUTH_CIPHER_WEP104 and len(self._key) != 26: if self._we_cipher == IW_AUTH_CIPHER_WEP104 and len(self._key) != 26:
raise ValueError("Key length not right for 104-bit WEP") raise ValueError("Key length not right for 104-bit WEP")
try: try:
a = binascii.a2b_hex(self._key) a = binascii.a2b_hex(self._key)
except TypeError: except TypeError:
raise ValueError("Key was not a hexadecimal string.") raise ValueError("Key was not a hexadecimal string.")
self._auth_alg = cfg.get_int(name, "auth_alg") self._auth_alg = cfg.get_int(name, "auth_alg")
if self._auth_alg != IW_AUTH_ALG_OPEN_SYSTEM and self._auth_alg != IW_AUTH_ALG_SHARED_KEY: if self._auth_alg != IW_AUTH_ALG_OPEN_SYSTEM and self._auth_alg != IW_AUTH_ALG_SHARED_KEY:
raise ValueError("Invalid authentication algorithm %d" % self._auth_alg) raise ValueError("Invalid authentication algorithm %d" % self._auth_alg)
def get_properties(self): def get_properties(self):
args = Security.get_properties(self) args = Security.get_properties(self)
args.append(dbus.String(self._key)) args.append(dbus.String(self._key))
args.append(dbus.Int32(self._auth_alg)) args.append(dbus.Int32(self._auth_alg))
return args return args
def write_to_config(self, section, config): def write_to_config(self, section, config):
Security.write_to_config(self, section, config) Security.write_to_config(self, section, config)
config.set(section, "key", self._key) config.set(section, "key", self._key)
config.set(section, "auth_alg", self._auth_alg) config.set(section, "auth_alg", self._auth_alg)
class Network: class Network:
def __init__(self, ssid): def __init__(self, ssid):
self.ssid = ssid self.ssid = ssid
self.timestamp = int(time.time()) self.timestamp = int(time.time())
self.bssids = [] self.bssids = []
self.we_cipher = 0 self.we_cipher = 0
self._security = None self._security = None
def get_properties(self): def get_properties(self):
bssid_list = dbus.Array([], signature="s") bssid_list = dbus.Array([], signature="s")
for item in self.bssids: for item in self.bssids:
bssid_list.append(dbus.String(item)) bssid_list.append(dbus.String(item))
args = [dbus.String(self.ssid), dbus.Int32(self.timestamp), dbus.Boolean(True), bssid_list] args = [dbus.String(self.ssid), dbus.Int32(self.timestamp), dbus.Boolean(True), bssid_list]
args += self._security.get_properties() args += self._security.get_properties()
return tuple(args) return tuple(args)
def get_security(self): def get_security(self):
return self._security.get_properties() return self._security.get_properties()
def set_security(self, security): def set_security(self, security):
self._security = security self._security = security
def read_from_args(self, auto, bssid, we_cipher, args): def read_from_args(self, auto, bssid, we_cipher, args):
if auto == False: if auto == False:
self.timestamp = int(time.time()) self.timestamp = int(time.time())
if not bssid in self.bssids: if not bssid in self.bssids:
self.bssids.append(bssid) self.bssids.append(bssid)
self._security = Security.new_from_args(we_cipher, args) self._security = Security.new_from_args(we_cipher, args)
if not self._security: if not self._security:
raise NetworkInvalidError("Invalid security information") raise NetworkInvalidError("Invalid security information")
def read_from_config(self, config): def read_from_config(self, config):
try: try:
self.timestamp = config.get_int(self.ssid, "timestamp") self.timestamp = config.get_int(self.ssid, "timestamp")
except (ConfigParser.NoOptionError, ValueError), e: except (ConfigParser.NoOptionError, ValueError), e:
raise NetworkInvalidError(e) raise NetworkInvalidError(e)
self._security = Security.new_from_config(config, self.ssid) self._security = Security.new_from_config(config, self.ssid)
if not self._security: if not self._security:
raise NetworkInvalidError(e) raise NetworkInvalidError(e)
# The following don't need to be present # The following don't need to be present
try: try:
self.bssids = config.get_list(self.ssid, "bssids") self.bssids = config.get_list(self.ssid, "bssids")
except (ConfigParser.NoOptionError, ValueError), e: except (ConfigParser.NoOptionError, ValueError), e:
pass pass
def write_to_config(self, config): def write_to_config(self, config):
try: try:
config.add_section(self.ssid) config.add_section(self.ssid)
config.set(self.ssid, "timestamp", self.timestamp) config.set(self.ssid, "timestamp", self.timestamp)
if len(self.bssids) > 0: if len(self.bssids) > 0:
opt = " " opt = " "
opt.join(self.bssids) opt.join(self.bssids)
config.set(self.ssid, "bssids", opt) config.set(self.ssid, "bssids", opt)
self._security.write_to_config(self.ssid, config) self._security.write_to_config(self.ssid, config)
except Exception, e: except Exception, e:
logging.debug("Error writing '%s': %s" % (self.ssid, e)) logging.debug("Error writing '%s': %s" % (self.ssid, e))
class NotFoundError(dbus.DBusException): class NotFoundError(dbus.DBusException):
pass pass
class UnsupportedError(dbus.DBusException): class UnsupportedError(dbus.DBusException):
pass pass
class NMInfoDBusServiceHelper(dbus.service.Object): class NMInfoDBusServiceHelper(dbus.service.Object):
def __init__(self, parent): def __init__(self, parent):
self._parent = parent self._parent = parent
bus = dbus.SystemBus() bus = dbus.SystemBus()
# If NMI is already around, don't grab the NMI service # If NMI is already around, don't grab the NMI service
bus_object = bus.get_object('org.freedesktop.DBus', '/org/freedesktop/DBus') bus_object = bus.get_object('org.freedesktop.DBus', '/org/freedesktop/DBus')
name = None name = None
try: try:
name = bus_object.GetNameOwner("org.freedesktop.NetworkManagerInfo", \ name = bus_object.GetNameOwner("org.freedesktop.NetworkManagerInfo", \
dbus_interface='org.freedesktop.DBus') dbus_interface='org.freedesktop.DBus')
except dbus.DBusException: except dbus.DBusException:
pass pass
if name: if name:
logging.debug("NMI service already owned by %s, won't claim it." % name) logging.debug("NMI service already owned by %s, won't claim it." % name)
raise RuntimeError raise RuntimeError
bus_name = dbus.service.BusName(NM_INFO_IFACE, bus=bus) bus_name = dbus.service.BusName(NM_INFO_IFACE, bus=bus)
dbus.service.Object.__init__(self, bus_name, NM_INFO_PATH) dbus.service.Object.__init__(self, bus_name, NM_INFO_PATH)
@dbus.service.method(NM_INFO_IFACE, in_signature='i', out_signature='as') @dbus.service.method(NM_INFO_IFACE, in_signature='i', out_signature='as')
def getNetworks(self, net_type): def getNetworks(self, net_type):
ssids = self._parent.get_networks(net_type) ssids = self._parent.get_networks(net_type)
if len(ssids) > 0: if len(ssids) > 0:
return dbus.Array(ssids) return dbus.Array(ssids)
raise NoNetworks() raise NoNetworks()
@dbus.service.method(NM_INFO_IFACE, in_signature='si', async_callbacks=('async_cb', 'async_err_cb')) @dbus.service.method(NM_INFO_IFACE, in_signature='si', async_callbacks=('async_cb', 'async_err_cb'))
def getNetworkProperties(self, ssid, net_type, async_cb, async_err_cb): def getNetworkProperties(self, ssid, net_type, async_cb, async_err_cb):
self._parent.get_network_properties(ssid, net_type, async_cb, async_err_cb) self._parent.get_network_properties(ssid, net_type, async_cb, async_err_cb)
@dbus.service.method(NM_INFO_IFACE) @dbus.service.method(NM_INFO_IFACE)
def updateNetworkInfo(self, ssid, bauto, bssid, cipher, *args): def updateNetworkInfo(self, ssid, bauto, bssid, cipher, *args):
self._parent.update_network_info(ssid, bauto, bssid, cipher, args) self._parent.update_network_info(ssid, bauto, bssid, cipher, args)
@dbus.service.method(NM_INFO_IFACE, async_callbacks=('async_cb', 'async_err_cb')) @dbus.service.method(NM_INFO_IFACE, async_callbacks=('async_cb', 'async_err_cb'))
def getKeyForNetwork(self, dev_path, net_path, ssid, attempt, new_key, async_cb, async_err_cb): def getKeyForNetwork(self, dev_path, net_path, ssid, attempt, new_key, async_cb, async_err_cb):
self._parent.get_key_for_network(dev_path, net_path, ssid, self._parent.get_key_for_network(dev_path, net_path, ssid,
attempt, new_key, async_cb, async_err_cb) attempt, new_key, async_cb, async_err_cb)
@dbus.service.method(NM_INFO_IFACE) @dbus.service.method(NM_INFO_IFACE)
def cancelGetKeyForNetwork(self): def cancelGetKeyForNetwork(self):
self._parent.cancel_get_key_for_network() self._parent.cancel_get_key_for_network()
class NMInfo(object): class NMInfo(object):
def __init__(self, client): def __init__(self, client):
try: try:
profile_path = env.get_profile_path() profile_path = env.get_profile_path()
except NameError: except NameError:
home = os.path.expanduser("~") home = os.path.expanduser("~")
profile_path = os.path.join(home, ".sugar", "default") profile_path = os.path.join(home, ".sugar", "default")
self._cfg_file = os.path.join(profile_path, "nm", "networks.cfg") self._cfg_file = os.path.join(profile_path, "nm", "networks.cfg")
self._nmclient = client self._nmclient = client
self._allowed_networks = self._read_config() self._allowed_networks = self._read_config()
self._dbus_helper = NMInfoDBusServiceHelper(self) self._dbus_helper = NMInfoDBusServiceHelper(self)
def save_config(self): def save_config(self):
self._write_config(self._allowed_networks) self._write_config(self._allowed_networks)
def _read_config(self): def _read_config(self):
if not os.path.exists(os.path.dirname(self._cfg_file)): if not os.path.exists(os.path.dirname(self._cfg_file)):
os.makedirs(os.path.dirname(self._cfg_file), 0755) os.makedirs(os.path.dirname(self._cfg_file), 0755)
if not os.path.exists(self._cfg_file): if not os.path.exists(self._cfg_file):
self._write_config({}) self._write_config({})
return {} return {}
config = NMConfig() config = NMConfig()
config.read(self._cfg_file) config.read(self._cfg_file)
networks = {} networks = {}
for name in config.sections(): for name in config.sections():
if not isinstance(name, unicode): if not isinstance(name, unicode):
name = unicode(name) name = unicode(name)
net = Network(name) net = Network(name)
try: try:
net.read_from_config(config) net.read_from_config(config)
networks[name] = net networks[name] = net
except NetworkInvalidError, e: except NetworkInvalidError, e:
logging.debug("Error: invalid stored network config: %s" % e) logging.debug("Error: invalid stored network config: %s" % e)
del net del net
del config del config
return networks return networks
def _write_config(self, networks): def _write_config(self, networks):
fp = open(self._cfg_file, 'w') fp = open(self._cfg_file, 'w')
config = NMConfig() config = NMConfig()
for net in networks.values(): for net in networks.values():
net.write_to_config(config) net.write_to_config(config)
config.write(fp) config.write(fp)
fp.close() fp.close()
del config del config
def get_networks(self, net_type): def get_networks(self, net_type):
if net_type != NETWORK_TYPE_ALLOWED: if net_type != NETWORK_TYPE_ALLOWED:
raise ValueError("Bad network type") raise ValueError("Bad network type")
nets = [] nets = []
for net in self._allowed_networks.values(): for net in self._allowed_networks.values():
nets.append(net.ssid) nets.append(net.ssid)
logging.debug("Returning networks: %s" % nets) logging.debug("Returning networks: %s" % nets)
return nets return nets
def get_network_properties(self, ssid, net_type, async_cb, async_err_cb): def get_network_properties(self, ssid, net_type, async_cb, async_err_cb):
if not isinstance(ssid, unicode): if not isinstance(ssid, unicode):
async_err_cb(ValueError("Invalid arguments; ssid must be unicode.")) async_err_cb(ValueError("Invalid arguments; ssid must be unicode."))
if net_type != NETWORK_TYPE_ALLOWED: if net_type != NETWORK_TYPE_ALLOWED:
async_err_cb(ValueError("Bad network type")) async_err_cb(ValueError("Bad network type"))
if not self._allowed_networks.has_key(ssid): if not self._allowed_networks.has_key(ssid):
async_err_cb(NotFoundError("Network '%s' not found." % ssid)) async_err_cb(NotFoundError("Network '%s' not found." % ssid))
network = self._allowed_networks[ssid] network = self._allowed_networks[ssid]
props = network.get_properties() props = network.get_properties()
# DBus workaround: the normal method return handler wraps # DBus workaround: the normal method return handler wraps
# the returned arguments in a tuple and then converts that to a # the returned arguments in a tuple and then converts that to a
# struct, but NetworkManager expects a plain list of arguments. # struct, but NetworkManager expects a plain list of arguments.
# It turns out that the async callback method return code _doesn't_ # It turns out that the async callback method return code _doesn't_
# wrap the returned arguments in a tuple, so as a workaround use # wrap the returned arguments in a tuple, so as a workaround use
# the async callback stuff here even though we're not doing it # the async callback stuff here even though we're not doing it
# asynchronously. # asynchronously.
async_cb(*props) async_cb(*props)
def update_network_info(self, ssid, auto, bssid, we_cipher, args): def update_network_info(self, ssid, auto, bssid, we_cipher, args):
if not isinstance(ssid, unicode): if not isinstance(ssid, unicode):
raise ValueError("Invalid arguments; ssid must be unicode.") raise ValueError("Invalid arguments; ssid must be unicode.")
if self._allowed_networks.has_key(ssid): if self._allowed_networks.has_key(ssid):
del self._allowed_networks[ssid] del self._allowed_networks[ssid]
net = Network(ssid) net = Network(ssid)
try: try:
net.read_from_args(auto, bssid, we_cipher, args) net.read_from_args(auto, bssid, we_cipher, args)
logging.debug("Updated network information for '%s'." % ssid) logging.debug("Updated network information for '%s'." % ssid)
self._allowed_networks[ssid] = net self._allowed_networks[ssid] = net
self.save_config() self.save_config()
except NetworkInvalidError, e: except NetworkInvalidError, e:
logging.debug("Error updating network information: %s" % e) logging.debug("Error updating network information: %s" % e)
del net del net
def get_key_for_network(self, dev_op, net_op, ssid, attempt, new_key, async_cb, async_err_cb): def get_key_for_network(self, dev_op, net_op, ssid, attempt, new_key, async_cb, async_err_cb):
if not isinstance(ssid, unicode): if not isinstance(ssid, unicode):
raise ValueError("Invalid arguments; ssid must be unicode.") raise ValueError("Invalid arguments; ssid must be unicode.")
if self._allowed_networks.has_key(ssid) and not new_key: if self._allowed_networks.has_key(ssid) and not new_key:
# We've got the info already # We've got the info already
net = self._allowed_networks[ssid] net = self._allowed_networks[ssid]
async_cb(tuple(net.get_security())) async_cb(tuple(net.get_security()))
return return
# Otherwise, ask the user for it # Otherwise, ask the user for it
net = None net = None
dev = self._nmclient.get_device(dev_op) dev = self._nmclient.get_device(dev_op)
if not dev: if not dev:
async_err_cb(NotFoundError("Device was unknown.")) async_err_cb(NotFoundError("Device was unknown."))
return return
if dev.get_type() == nmclient.DEVICE_TYPE_802_3_ETHERNET: if dev.get_type() == nmclient.DEVICE_TYPE_802_3_ETHERNET:
# We don't support wired 802.1x yet... # We don't support wired 802.1x yet...
async_err_cb(UnsupportedError("Device type is unsupported by NMI.")) async_err_cb(UnsupportedError("Device type is unsupported by NMI."))
return return
net = dev.get_network(net_op) net = dev.get_network(net_op)
if not net: if not net:
async_err_cb(NotFoundError("Network was unknown.")) async_err_cb(NotFoundError("Network was unknown."))
return return
self._nmclient.get_key_for_network(net, async_cb, async_err_cb) self._nmclient.get_key_for_network(net, async_cb, async_err_cb)
def get_key_for_network_cb(self, net, key, auth_alg, async_cb, async_err_cb, canceled=False): def get_key_for_network_cb(self, net, key, auth_alg, async_cb, async_err_cb, canceled=False):
""" """
Called by the NMClient when the Wireless Network Key dialog Called by the NMClient when the Wireless Network Key dialog
is closed. is closed.
""" """
if canceled: if canceled:
e = CanceledKeyRequestError("Request was canceled.") e = CanceledKeyRequestError("Request was canceled.")
# key dialog dialog was canceled; send the error back to NM # key dialog dialog was canceled; send the error back to NM
async_err_cb(e) async_err_cb(e)
return return
if not key or not auth_alg: if not key or not auth_alg:
# no key returned, *** BUG ***; the key dialog # no key returned, *** BUG ***; the key dialog
# should always return either a key + auth_alg, or a # should always return either a key + auth_alg, or a
#cancel error #cancel error
raise RuntimeError("No key or auth alg given! Bug!") raise RuntimeError("No key or auth alg given! Bug!")
we_cipher = None we_cipher = None
if len(key) == 26: if len(key) == 26:
we_cipher = IW_AUTH_CIPHER_WEP104 we_cipher = IW_AUTH_CIPHER_WEP104
elif len(key) == 10: elif len(key) == 10:
we_cipher = IW_AUTH_CIPHER_WEP40 we_cipher = IW_AUTH_CIPHER_WEP40
else: else:
raise RuntimeError("Invalid key length!") raise RuntimeError("Invalid key length!")
# Stuff the returned key and auth algorithm into a security object # Stuff the returned key and auth algorithm into a security object
# and return it to NetworkManager # and return it to NetworkManager
sec = Security.new_from_args(we_cipher, (key, auth_alg)) sec = Security.new_from_args(we_cipher, (key, auth_alg))
if not sec: if not sec:
raise RuntimeError("Invalid security arguments.") raise RuntimeError("Invalid security arguments.")
props = sec.get_properties() props = sec.get_properties()
a = tuple(props) a = tuple(props)
async_cb(*a) async_cb(*a)
def cancel_get_key_for_network(self): def cancel_get_key_for_network(self):
# Tell the NMClient to close the key request dialog # Tell the NMClient to close the key request dialog
self._nmclient.cancel_get_key_for_network() self._nmclient.cancel_get_key_for_network()

View File

@ -22,60 +22,60 @@ IW_AUTH_ALG_OPEN_SYSTEM = 0x00000001
IW_AUTH_ALG_SHARED_KEY = 0x00000002 IW_AUTH_ALG_SHARED_KEY = 0x00000002
class WEPKeyDialog(gtk.Dialog): class WEPKeyDialog(gtk.Dialog):
def __init__(self, net, async_cb, async_err_cb): def __init__(self, net, async_cb, async_err_cb):
gtk.Dialog.__init__(self) gtk.Dialog.__init__(self)
self.set_title("Wireless Key Required") self.set_title("Wireless Key Required")
self._net = net self._net = net
self._async_cb = async_cb self._async_cb = async_cb
self._async_err_cb = async_err_cb self._async_err_cb = async_err_cb
self.set_has_separator(False) self.set_has_separator(False)
label = gtk.Label("A wireless encryption key is required for\n" \ label = gtk.Label("A wireless encryption key is required for\n" \
" the wireless network '%s'." % net.get_ssid()) " the wireless network '%s'." % net.get_ssid())
self.vbox.pack_start(label) self.vbox.pack_start(label)
self._entry = gtk.Entry() self._entry = gtk.Entry()
self._entry.props.visibility = False self._entry.props.visibility = False
self._entry.connect('changed', self._entry_changed_cb) self._entry.connect('changed', self._entry_changed_cb)
self.vbox.pack_start(self._entry) self.vbox.pack_start(self._entry)
self.vbox.show_all() self.vbox.show_all()
self.add_buttons(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, self.add_buttons(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
gtk.STOCK_OK, gtk.RESPONSE_OK) gtk.STOCK_OK, gtk.RESPONSE_OK)
self.set_default_response(gtk.RESPONSE_OK) self.set_default_response(gtk.RESPONSE_OK)
self._update_response_sensitivity() self._update_response_sensitivity()
def get_key(self): def get_key(self):
return self._entry.get_text() return self._entry.get_text()
def get_auth_alg(self): def get_auth_alg(self):
return IW_AUTH_ALG_OPEN_SYSTEM return IW_AUTH_ALG_OPEN_SYSTEM
def get_network(self): def get_network(self):
return self._net return self._net
def get_callbacks(self): def get_callbacks(self):
return (self._async_cb, self._async_err_cb) return (self._async_cb, self._async_err_cb)
def _entry_changed_cb(self, entry): def _entry_changed_cb(self, entry):
self._update_response_sensitivity() self._update_response_sensitivity()
def _update_response_sensitivity(self): def _update_response_sensitivity(self):
key = self.get_key() key = self.get_key()
is_hex = True is_hex = True
for c in key: for c in key:
if not 'a' <= c <= 'f' and not '0' <= c <= '9': if not 'a' <= c <= 'f' and not '0' <= c <= '9':
is_hex = False is_hex = False
valid_len = (len(key) == 10 or len(key) == 26) valid_len = (len(key) == 10 or len(key) == 26)
self.set_response_sensitive(gtk.RESPONSE_OK, is_hex and valid_len) self.set_response_sensitive(gtk.RESPONSE_OK, is_hex and valid_len)
if __name__ == "__main__": if __name__ == "__main__":
dialog = WEPKeyDialog() dialog = WEPKeyDialog()
dialog.run() dialog.run()
print dialog.get_key() print dialog.get_key()

View File

@ -22,155 +22,155 @@ ACTIVITY_DBUS_INTERFACE = "org.laptop.Presence.Activity"
class ActivityDBusHelper(dbus.service.Object): class ActivityDBusHelper(dbus.service.Object):
def __init__(self, parent, bus_name, object_path): def __init__(self, parent, bus_name, object_path):
self._parent = parent self._parent = parent
self._bus_name = bus_name self._bus_name = bus_name
self._object_path = object_path self._object_path = object_path
dbus.service.Object.__init__(self, bus_name, self._object_path) dbus.service.Object.__init__(self, bus_name, self._object_path)
@dbus.service.method(ACTIVITY_DBUS_INTERFACE, @dbus.service.method(ACTIVITY_DBUS_INTERFACE,
in_signature="s", out_signature="ao") in_signature="s", out_signature="ao")
def getServicesOfType(self, stype): def getServicesOfType(self, stype):
ret = [] ret = []
for serv in self._parent.get_services_of_type(stype): for serv in self._parent.get_services_of_type(stype):
ret.append(serv.object_path()) ret.append(serv.object_path())
return ret return ret
@dbus.service.method(ACTIVITY_DBUS_INTERFACE, @dbus.service.method(ACTIVITY_DBUS_INTERFACE,
in_signature="", out_signature="ao") in_signature="", out_signature="ao")
def getServices(self): def getServices(self):
ret = [] ret = []
for serv in self._parent.get_services(): for serv in self._parent.get_services():
ret.append(serv.object_path()) ret.append(serv.object_path())
return ret return ret
@dbus.service.method(ACTIVITY_DBUS_INTERFACE, @dbus.service.method(ACTIVITY_DBUS_INTERFACE,
in_signature="", out_signature="s") in_signature="", out_signature="s")
def getId(self): def getId(self):
return self._parent.get_id() return self._parent.get_id()
@dbus.service.method(ACTIVITY_DBUS_INTERFACE, @dbus.service.method(ACTIVITY_DBUS_INTERFACE,
in_signature="", out_signature="s") in_signature="", out_signature="s")
def getColor(self): def getColor(self):
return self._parent.get_color() return self._parent.get_color()
@dbus.service.method(ACTIVITY_DBUS_INTERFACE, @dbus.service.method(ACTIVITY_DBUS_INTERFACE,
in_signature="", out_signature="ao") in_signature="", out_signature="ao")
def getJoinedBuddies(self): def getJoinedBuddies(self):
ret = [] ret = []
for buddy in self._parent.get_joined_buddies(): for buddy in self._parent.get_joined_buddies():
ret.append(buddy.object_path()) ret.append(buddy.object_path())
return ret return ret
@dbus.service.signal(ACTIVITY_DBUS_INTERFACE, @dbus.service.signal(ACTIVITY_DBUS_INTERFACE,
signature="o") signature="o")
def ServiceAppeared(self, object_path): def ServiceAppeared(self, object_path):
pass pass
@dbus.service.signal(ACTIVITY_DBUS_INTERFACE, @dbus.service.signal(ACTIVITY_DBUS_INTERFACE,
signature="o") signature="o")
def ServiceDisappeared(self, object_path): def ServiceDisappeared(self, object_path):
pass pass
@dbus.service.signal(ACTIVITY_DBUS_INTERFACE, @dbus.service.signal(ACTIVITY_DBUS_INTERFACE,
signature="o") signature="o")
def BuddyJoined(self, object_path): def BuddyJoined(self, object_path):
pass pass
@dbus.service.signal(ACTIVITY_DBUS_INTERFACE, @dbus.service.signal(ACTIVITY_DBUS_INTERFACE,
signature="o") signature="o")
def BuddyLeft(self, object_path): def BuddyLeft(self, object_path):
pass pass
class Activity(object): class Activity(object):
def __init__(self, bus_name, object_id, initial_service): def __init__(self, bus_name, object_id, initial_service):
if not initial_service.get_activity_id(): if not initial_service.get_activity_id():
raise ValueError("Service must have a valid Activity ID") raise ValueError("Service must have a valid Activity ID")
self._activity_id = initial_service.get_activity_id() self._activity_id = initial_service.get_activity_id()
self._buddies = [] self._buddies = []
self._services = {} # service type -> list of Services self._services = {} # service type -> list of Services
self._color = None self._color = None
self._valid = False self._valid = False
self._object_id = object_id self._object_id = object_id
self._object_path = "/org/laptop/Presence/Activities/%d" % self._object_id self._object_path = "/org/laptop/Presence/Activities/%d" % self._object_id
self._dbus_helper = ActivityDBusHelper(self, bus_name, self._object_path) self._dbus_helper = ActivityDBusHelper(self, bus_name, self._object_path)
self.add_service(initial_service) self.add_service(initial_service)
def object_path(self): def object_path(self):
return dbus.ObjectPath(self._object_path) return dbus.ObjectPath(self._object_path)
def is_valid(self): def is_valid(self):
"""An activity is only valid when it's color is available.""" """An activity is only valid when it's color is available."""
return self._valid return self._valid
def get_id(self): def get_id(self):
return self._activity_id return self._activity_id
def get_color(self): def get_color(self):
return self._color return self._color
def get_services(self): def get_services(self):
ret = [] ret = []
for serv_list in self._services.values(): for serv_list in self._services.values():
for service in serv_list: for service in serv_list:
if service not in ret: if service not in ret:
ret.append(service) ret.append(service)
return ret return ret
def get_services_of_type(self, stype): def get_services_of_type(self, stype):
if self._services.has_key(stype): if self._services.has_key(stype):
return self._services[stype] return self._services[stype]
return [] return []
def get_joined_buddies(self): def get_joined_buddies(self):
buddies = [] buddies = []
for serv_list in self._services.values(): for serv_list in self._services.values():
for serv in serv_list: for serv in serv_list:
owner = serv.get_owner() owner = serv.get_owner()
if owner and not owner in buddies and owner.is_valid(): if owner and not owner in buddies and owner.is_valid():
buddies.append(owner) buddies.append(owner)
return buddies return buddies
def add_service(self, service): def add_service(self, service):
stype = service.get_type() stype = service.get_type()
if not self._services.has_key(stype): if not self._services.has_key(stype):
self._services[stype] = [] self._services[stype] = []
if not self._color: if not self._color:
color = service.get_one_property('color') color = service.get_one_property('color')
if color: if color:
self._color = color self._color = color
self._valid = True self._valid = True
# Send out the BuddyJoined signal if this is the first # Send out the BuddyJoined signal if this is the first
# service from the buddy that we've seen # service from the buddy that we've seen
buddies = self.get_joined_buddies() buddies = self.get_joined_buddies()
serv_owner = service.get_owner() serv_owner = service.get_owner()
if serv_owner and serv_owner not in buddies and serv_owner.is_valid(): if serv_owner and serv_owner not in buddies and serv_owner.is_valid():
self._dbus_helper.BuddyJoined(serv_owner.object_path()) self._dbus_helper.BuddyJoined(serv_owner.object_path())
serv_owner.add_activity(self) serv_owner.add_activity(self)
if not service in self._services[stype]: if not service in self._services[stype]:
self._services[stype].append(service) self._services[stype].append(service)
self._dbus_helper.ServiceAppeared(service.object_path()) self._dbus_helper.ServiceAppeared(service.object_path())
def remove_service(self, service): def remove_service(self, service):
stype = service.get_type() stype = service.get_type()
if not self._services.has_key(stype): if not self._services.has_key(stype):
return return
self._services[stype].remove(service) self._services[stype].remove(service)
self._dbus_helper.ServiceDisappeared(service.object_path()) self._dbus_helper.ServiceDisappeared(service.object_path())
if len(self._services[stype]) == 0: if len(self._services[stype]) == 0:
del self._services[stype] del self._services[stype]
# Send out the BuddyLeft signal if this is the last # Send out the BuddyLeft signal if this is the last
# service from the buddy # service from the buddy
buddies = self.get_joined_buddies() buddies = self.get_joined_buddies()
serv_owner = service.get_owner() serv_owner = service.get_owner()
if serv_owner and serv_owner not in buddies and serv_owner.is_valid(): if serv_owner and serv_owner not in buddies and serv_owner.is_valid():
serv_owner.remove_activity(self) serv_owner.remove_activity(self)
self._dbus_helper.BuddyLeft(serv_owner.object_path()) self._dbus_helper.BuddyLeft(serv_owner.object_path())

View File

@ -30,433 +30,433 @@ _BUDDY_KEY_COLOR = 'color'
_BUDDY_KEY_CURACT = 'curact' _BUDDY_KEY_CURACT = 'curact'
class NotFoundError(Exception): class NotFoundError(Exception):
pass pass
class BuddyDBusHelper(dbus.service.Object): class BuddyDBusHelper(dbus.service.Object):
def __init__(self, parent, bus_name, object_path): def __init__(self, parent, bus_name, object_path):
self._parent = parent self._parent = parent
self._bus_name = bus_name self._bus_name = bus_name
self._object_path = object_path self._object_path = object_path
dbus.service.Object.__init__(self, bus_name, self._object_path) dbus.service.Object.__init__(self, bus_name, self._object_path)
@dbus.service.signal(BUDDY_DBUS_INTERFACE, @dbus.service.signal(BUDDY_DBUS_INTERFACE,
signature="o") signature="o")
def ServiceAppeared(self, object_path): def ServiceAppeared(self, object_path):
pass pass
@dbus.service.signal(BUDDY_DBUS_INTERFACE, @dbus.service.signal(BUDDY_DBUS_INTERFACE,
signature="o") signature="o")
def ServiceDisappeared(self, object_path): def ServiceDisappeared(self, object_path):
pass pass
@dbus.service.signal(BUDDY_DBUS_INTERFACE, @dbus.service.signal(BUDDY_DBUS_INTERFACE,
signature="") signature="")
def Disappeared(self): def Disappeared(self):
pass pass
@dbus.service.signal(BUDDY_DBUS_INTERFACE, @dbus.service.signal(BUDDY_DBUS_INTERFACE,
signature="ao") signature="ao")
def CurrentActivityChanged(self, activities): def CurrentActivityChanged(self, activities):
pass pass
@dbus.service.signal(BUDDY_DBUS_INTERFACE, @dbus.service.signal(BUDDY_DBUS_INTERFACE,
signature="") signature="")
def IconChanged(self): def IconChanged(self):
pass pass
@dbus.service.signal(BUDDY_DBUS_INTERFACE, @dbus.service.signal(BUDDY_DBUS_INTERFACE,
signature="o") signature="o")
def JoinedActivity(self, object_path): def JoinedActivity(self, object_path):
pass pass
@dbus.service.signal(BUDDY_DBUS_INTERFACE, @dbus.service.signal(BUDDY_DBUS_INTERFACE,
signature="o") signature="o")
def LeftActivity(self, object_path): def LeftActivity(self, object_path):
pass pass
@dbus.service.signal(BUDDY_DBUS_INTERFACE, @dbus.service.signal(BUDDY_DBUS_INTERFACE,
signature="as") signature="as")
def PropertyChanged(self, prop_list): def PropertyChanged(self, prop_list):
pass pass
@dbus.service.method(BUDDY_DBUS_INTERFACE, @dbus.service.method(BUDDY_DBUS_INTERFACE,
in_signature="", out_signature="ay") in_signature="", out_signature="ay")
def getIcon(self): def getIcon(self):
icon = self._parent.get_icon() icon = self._parent.get_icon()
if not icon: if not icon:
return "" return ""
return icon return icon
@dbus.service.method(BUDDY_DBUS_INTERFACE, @dbus.service.method(BUDDY_DBUS_INTERFACE,
in_signature="so", out_signature="o") in_signature="so", out_signature="o")
def getServiceOfType(self, stype, activity_op): def getServiceOfType(self, stype, activity_op):
activity = None activity = None
# "/" is the placeholder for None # "/" is the placeholder for None
if activity_op != "/": if activity_op != "/":
for act in self._parent.get_joined_activities(): for act in self._parent.get_joined_activities():
if act.object_path() == activity_op: if act.object_path() == activity_op:
activity = act activity = act
if not activity: if not activity:
raise NotFoundError("Not found") raise NotFoundError("Not found")
service = self._parent.get_service_of_type(stype, activity) service = self._parent.get_service_of_type(stype, activity)
if not service: if not service:
raise NotFoundError("Not found") raise NotFoundError("Not found")
return service.object_path() return service.object_path()
@dbus.service.method(BUDDY_DBUS_INTERFACE, @dbus.service.method(BUDDY_DBUS_INTERFACE,
in_signature="", out_signature="ao") in_signature="", out_signature="ao")
def getJoinedActivities(self): def getJoinedActivities(self):
acts = [] acts = []
for act in self._parent.get_joined_activities(): for act in self._parent.get_joined_activities():
acts.append(act.object_path()) acts.append(act.object_path())
return acts return acts
@dbus.service.method(BUDDY_DBUS_INTERFACE, @dbus.service.method(BUDDY_DBUS_INTERFACE,
in_signature="", out_signature="a{sv}") in_signature="", out_signature="a{sv}")
def getProperties(self): def getProperties(self):
props = {} props = {}
props['name'] = self._parent.get_name() props['name'] = self._parent.get_name()
addr = self._parent.get_address() addr = self._parent.get_address()
if addr: if addr:
props['ip4_address'] = addr props['ip4_address'] = addr
props['owner'] = self._parent.is_owner() props['owner'] = self._parent.is_owner()
color = self._parent.get_color() color = self._parent.get_color()
if color: if color:
props[_BUDDY_KEY_COLOR] = self._parent.get_color() props[_BUDDY_KEY_COLOR] = self._parent.get_color()
return props return props
@dbus.service.method(BUDDY_DBUS_INTERFACE, @dbus.service.method(BUDDY_DBUS_INTERFACE,
in_signature="", out_signature="o") in_signature="", out_signature="o")
def getCurrentActivity(self): def getCurrentActivity(self):
activity = self._parent.get_current_activity() activity = self._parent.get_current_activity()
if not activity: if not activity:
raise NotFoundError() raise NotFoundError()
return activity.object_path() return activity.object_path()
class Buddy(object): class Buddy(object):
"""Represents another person on the network and keeps track of the """Represents another person on the network and keeps track of the
activities and resources they make available for sharing.""" activities and resources they make available for sharing."""
def __init__(self, bus_name, object_id, service, icon_cache): def __init__(self, bus_name, object_id, service, icon_cache):
if not bus_name: if not bus_name:
raise ValueError("DBus bus name must be valid") raise ValueError("DBus bus name must be valid")
if not object_id or not isinstance(object_id, int): if not object_id or not isinstance(object_id, int):
raise ValueError("object id must be a valid number") raise ValueError("object id must be a valid number")
# Normal Buddy objects must be created with a valid service, # Normal Buddy objects must be created with a valid service,
# owner objects do not # owner objects do not
if not isinstance(self, Owner): if not isinstance(self, Owner):
if not isinstance(service, Service.Service): if not isinstance(service, Service.Service):
raise ValueError("service must be a valid service object") raise ValueError("service must be a valid service object")
self._services = {} self._services = {}
self._activities = {} self._activities = {}
self._icon_cache = icon_cache self._icon_cache = icon_cache
self._nick_name = None self._nick_name = None
self._address = None self._address = None
if service is not None: if service is not None:
self._nick_name = service.get_name() self._nick_name = service.get_name()
self._address = service.get_source_address() self._address = service.get_source_address()
self._color = None self._color = None
self._current_activity = None self._current_activity = None
self._valid = False self._valid = False
self._icon = None self._icon = None
self._icon_tries = 0 self._icon_tries = 0
self._object_id = object_id self._object_id = object_id
self._object_path = BUDDY_DBUS_OBJECT_PATH + str(self._object_id) self._object_path = BUDDY_DBUS_OBJECT_PATH + str(self._object_id)
self._dbus_helper = BuddyDBusHelper(self, bus_name, self._object_path) self._dbus_helper = BuddyDBusHelper(self, bus_name, self._object_path)
self._buddy_presence_service = None self._buddy_presence_service = None
if service is not None: if service is not None:
self.add_service(service) self.add_service(service)
def object_path(self): def object_path(self):
return dbus.ObjectPath(self._object_path) return dbus.ObjectPath(self._object_path)
def _request_buddy_icon_cb(self, result_status, response, user_data): def _request_buddy_icon_cb(self, result_status, response, user_data):
"""Callback when icon request has completed.""" """Callback when icon request has completed."""
from sugar.p2p import network from sugar.p2p import network
icon = response icon = response
service = user_data service = user_data
if result_status == network.RESULT_SUCCESS: if result_status == network.RESULT_SUCCESS:
if icon and len(icon): if icon and len(icon):
icon = base64.b64decode(icon) icon = base64.b64decode(icon)
self._set_icon(icon) self._set_icon(icon)
self._icon_cache.add_icon(icon) self._icon_cache.add_icon(icon)
if (result_status == network.RESULT_FAILED or not icon) and self._icon_tries < 3: if (result_status == network.RESULT_FAILED or not icon) and self._icon_tries < 3:
self._icon_tries = self._icon_tries + 1 self._icon_tries = self._icon_tries + 1
if self._icon_tries >= 3: if self._icon_tries >= 3:
logging.debug("Failed to retrieve buddy icon for '%s'." % self._nick_name) logging.debug("Failed to retrieve buddy icon for '%s'." % self._nick_name)
gobject.timeout_add(1000, self._get_buddy_icon, service, True) gobject.timeout_add(1000, self._get_buddy_icon, service, True)
return False return False
def _get_buddy_icon(self, service, retry=False): def _get_buddy_icon(self, service, retry=False):
"""Get the buddy's icon. Check the cache first, if its """Get the buddy's icon. Check the cache first, if its
not there get the icon from the buddy over the network.""" not there get the icon from the buddy over the network."""
if retry != True: if retry != True:
# Only hit the cache once # Only hit the cache once
icon_hash = service.get_one_property('icon-hash') icon_hash = service.get_one_property('icon-hash')
if icon_hash is not None: if icon_hash is not None:
icon = self._icon_cache.get_icon(icon_hash) icon = self._icon_cache.get_icon(icon_hash)
if icon: if icon:
logging.debug("%s: icon cache hit for %s." % (self._nick_name, icon_hash)) logging.debug("%s: icon cache hit for %s." % (self._nick_name, icon_hash))
self._set_icon(icon) self._set_icon(icon)
return False return False
logging.debug("%s: icon cache miss, fetching icon from buddy..." % self._nick_name) logging.debug("%s: icon cache miss, fetching icon from buddy..." % self._nick_name)
from sugar.p2p import Stream from sugar.p2p import Stream
buddy_stream = Stream.Stream.new_from_service(service, start_reader=False) buddy_stream = Stream.Stream.new_from_service(service, start_reader=False)
writer = buddy_stream.new_writer(service) writer = buddy_stream.new_writer(service)
success = writer.custom_request("get_buddy_icon", self._request_buddy_icon_cb, service) success = writer.custom_request("get_buddy_icon", self._request_buddy_icon_cb, service)
if not success: if not success:
del writer, buddy_stream del writer, buddy_stream
gobject.timeout_add(1000, self._get_buddy_icon, service, True) gobject.timeout_add(1000, self._get_buddy_icon, service, True)
return False return False
def _get_service_key(self, service): def _get_service_key(self, service):
return (service.get_type(), service.get_activity_id()) return (service.get_type(), service.get_activity_id())
def add_service(self, service): def add_service(self, service):
"""Adds a new service to this buddy's service list, returning """Adds a new service to this buddy's service list, returning
True if the service was successfully added, and False if it was not.""" True if the service was successfully added, and False if it was not."""
if service.get_name() != self._nick_name: if service.get_name() != self._nick_name:
logging.error("Service and buddy nick names doesn't match: " \ logging.error("Service and buddy nick names doesn't match: " \
"%s %s" % (service.get_name(), self._nick_name)) "%s %s" % (service.get_name(), self._nick_name))
return False return False
source_addr = service.get_source_address() source_addr = service.get_source_address()
if source_addr != self._address: if source_addr != self._address:
logging.error("Service source and buddy address doesn't " \ logging.error("Service source and buddy address doesn't " \
"match: %s %s" % (source_addr, self._address)) "match: %s %s" % (source_addr, self._address))
return False return False
return self._internal_add_service(service) return self._internal_add_service(service)
def _internal_add_service(self, service): def _internal_add_service(self, service):
service_key = self._get_service_key(service) service_key = self._get_service_key(service)
if service_key in self._services.keys(): if service_key in self._services.keys():
logging.error("Service already known: %s %s" % (service_key[0], logging.error("Service already known: %s %s" % (service_key[0],
service_key[1])) service_key[1]))
return False return False
if service.get_type() == PRESENCE_SERVICE_TYPE and self._buddy_presence_service: if service.get_type() == PRESENCE_SERVICE_TYPE and self._buddy_presence_service:
# already have a presence service for this buddy # already have a presence service for this buddy
logging.debug("!!! Tried to add a buddy presence service when " \ logging.debug("!!! Tried to add a buddy presence service when " \
"one already existed.") "one already existed.")
return False return False
logging.debug("Buddy %s added service type %s id %s" % (self._nick_name, logging.debug("Buddy %s added service type %s id %s" % (self._nick_name,
service.get_type(), service.get_activity_id())) service.get_type(), service.get_activity_id()))
self._services[service_key] = service self._services[service_key] = service
service.set_owner(self) service.set_owner(self)
if service.get_type() == PRESENCE_SERVICE_TYPE: if service.get_type() == PRESENCE_SERVICE_TYPE:
self._buddy_presence_service = service self._buddy_presence_service = service
# A buddy isn't valid until its official presence # A buddy isn't valid until its official presence
# service has been found and resolved # service has been found and resolved
self._valid = True self._valid = True
self._get_buddy_icon(service) self._get_buddy_icon(service)
self._color = service.get_one_property(_BUDDY_KEY_COLOR) self._color = service.get_one_property(_BUDDY_KEY_COLOR)
self._current_activity = service.get_one_property(_BUDDY_KEY_CURACT) self._current_activity = service.get_one_property(_BUDDY_KEY_CURACT)
# Monitor further buddy property changes, like current activity # Monitor further buddy property changes, like current activity
# and color # and color
service.connect('property-changed', service.connect('property-changed',
self.__buddy_presence_service_property_changed_cb) self.__buddy_presence_service_property_changed_cb)
if self._valid: if self._valid:
self._dbus_helper.ServiceAppeared(service.object_path()) self._dbus_helper.ServiceAppeared(service.object_path())
return True return True
def __buddy_presence_service_property_changed_cb(self, service, keys): def __buddy_presence_service_property_changed_cb(self, service, keys):
if _BUDDY_KEY_COLOR in keys: if _BUDDY_KEY_COLOR in keys:
new_color = service.get_one_property(_BUDDY_KEY_COLOR) new_color = service.get_one_property(_BUDDY_KEY_COLOR)
if new_color and self._color != new_color: if new_color and self._color != new_color:
self._color = new_color self._color = new_color
self._dbus_helper.PropertyChanged([_BUDDY_KEY_COLOR]) self._dbus_helper.PropertyChanged([_BUDDY_KEY_COLOR])
if _BUDDY_KEY_CURACT in keys: if _BUDDY_KEY_CURACT in keys:
# Three cases here: # Three cases here:
# 1) Buddy didn't publish a 'curact' key at all; we do nothing # 1) Buddy didn't publish a 'curact' key at all; we do nothing
# 2) Buddy published a blank/zero-length 'curact' key; we send # 2) Buddy published a blank/zero-length 'curact' key; we send
# a current-activity-changed signal for no activity # a current-activity-changed signal for no activity
# 3) Buddy published a non-zero-length 'curact' key; we send # 3) Buddy published a non-zero-length 'curact' key; we send
# a current-activity-changed signal if we know about the # a current-activity-changed signal if we know about the
# activity already, if not we postpone until the activity # activity already, if not we postpone until the activity
# is found on the network and added to the buddy # is found on the network and added to the buddy
new_curact = service.get_one_property(_BUDDY_KEY_CURACT) new_curact = service.get_one_property(_BUDDY_KEY_CURACT)
if new_curact and self._current_activity != new_curact: if new_curact and self._current_activity != new_curact:
if not len(new_curact): if not len(new_curact):
new_curact = None new_curact = None
self._current_activity = new_curact self._current_activity = new_curact
if self._activities.has_key(self._current_activity): if self._activities.has_key(self._current_activity):
# Case (3) above, valid activity id # Case (3) above, valid activity id
activity = self._activities[self._current_activity] activity = self._activities[self._current_activity]
if activity.is_valid(): if activity.is_valid():
self._dbus_helper.CurrentActivityChanged([activity.object_path()]) self._dbus_helper.CurrentActivityChanged([activity.object_path()])
elif not self._current_activity: elif not self._current_activity:
# Case (2) above, no current activity # Case (2) above, no current activity
self._dbus_helper.CurrentActivityChanged([]) self._dbus_helper.CurrentActivityChanged([])
def __find_service_by_activity_id(self, actid): def __find_service_by_activity_id(self, actid):
for serv in self._services.values(): for serv in self._services.values():
if serv.get_activity_id() == actid: if serv.get_activity_id() == actid:
return serv return serv
return None return None
def add_activity(self, activity): def add_activity(self, activity):
if activity in self._activities.values(): if activity in self._activities.values():
return return
actid = activity.get_id() actid = activity.get_id()
if not self.__find_service_by_activity_id(actid): if not self.__find_service_by_activity_id(actid):
raise RuntimeError("Tried to add activity for which we had no service") raise RuntimeError("Tried to add activity for which we had no service")
self._activities[actid] = activity self._activities[actid] = activity
if activity.is_valid(): if activity.is_valid():
self._dbus_helper.JoinedActivity(activity.object_path()) self._dbus_helper.JoinedActivity(activity.object_path())
# If when we received a current activity update from the buddy, # If when we received a current activity update from the buddy,
# but didn't know about that activity yet, and now we do know about # but didn't know about that activity yet, and now we do know about
# it, we need to send out the changed activity signal # it, we need to send out the changed activity signal
if actid == self._current_activity: if actid == self._current_activity:
self._dbus_helper.CurrentActivityChanged([activity.object_path()]) self._dbus_helper.CurrentActivityChanged([activity.object_path()])
def remove_service(self, service): def remove_service(self, service):
"""Remove a service from a buddy; ie, the activity was closed """Remove a service from a buddy; ie, the activity was closed
or the buddy went away.""" or the buddy went away."""
if service.get_source_address() != self._address: if service.get_source_address() != self._address:
return return
if service.get_name() != self._nick_name: if service.get_name() != self._nick_name:
return return
if service.get_type() == PRESENCE_SERVICE_TYPE \ if service.get_type() == PRESENCE_SERVICE_TYPE \
and self._buddy_presence_service \ and self._buddy_presence_service \
and service != self._buddy_presence_service: and service != self._buddy_presence_service:
logging.debug("!!! Tried to remove a spurious buddy presence service.") logging.debug("!!! Tried to remove a spurious buddy presence service.")
return return
service_key = self._get_service_key(service) service_key = self._get_service_key(service)
if self._services.has_key(service_key): if self._services.has_key(service_key):
if self._valid: if self._valid:
self._dbus_helper.ServiceDisappeared(service.object_path()) self._dbus_helper.ServiceDisappeared(service.object_path())
del self._services[service_key] del self._services[service_key]
if service.get_type() == PRESENCE_SERVICE_TYPE: if service.get_type() == PRESENCE_SERVICE_TYPE:
self._valid = False self._valid = False
self._dbus_helper.Disappeared() self._dbus_helper.Disappeared()
def remove_activity(self, activity): def remove_activity(self, activity):
actid = activity.get_id() actid = activity.get_id()
if not self._activities.has_key(actid): if not self._activities.has_key(actid):
return return
del self._activities[actid] del self._activities[actid]
if activity.is_valid(): if activity.is_valid():
self._dbus_helper.LeftActivity(activity.object_path()) self._dbus_helper.LeftActivity(activity.object_path())
# If we just removed the buddy's current activity, # If we just removed the buddy's current activity,
# send out a signal # send out a signal
if actid == self._current_activity: if actid == self._current_activity:
self._current_activity = None self._current_activity = None
self._dbus_helper.CurrentActivityChanged([]) self._dbus_helper.CurrentActivityChanged([])
def get_joined_activities(self): def get_joined_activities(self):
acts = [] acts = []
for act in self._activities.values(): for act in self._activities.values():
if act.is_valid(): if act.is_valid():
acts.append(act) acts.append(act)
return acts return acts
def get_service_of_type(self, stype, activity=None): def get_service_of_type(self, stype, activity=None):
"""Return a service of a certain type, or None if the buddy """Return a service of a certain type, or None if the buddy
doesn't provide that service.""" doesn't provide that service."""
if not stype: if not stype:
raise RuntimeError("Need to specify a service type.") raise RuntimeError("Need to specify a service type.")
if activity and not activity.is_valid(): if activity and not activity.is_valid():
raise RuntimeError("Activity is not yet valid.") raise RuntimeError("Activity is not yet valid.")
if activity: if activity:
key = (stype, activity.get_id()) key = (stype, activity.get_id())
else: else:
key = (stype, None) key = (stype, None)
if self._services.has_key(key): if self._services.has_key(key):
return self._services[key] return self._services[key]
return None return None
def is_valid(self): def is_valid(self):
"""Return whether the buddy is valid or not. A buddy is """Return whether the buddy is valid or not. A buddy is
not valid until its official presence service has been found not valid until its official presence service has been found
and successfully resolved.""" and successfully resolved."""
return self._valid return self._valid
def get_icon(self): def get_icon(self):
"""Return the buddies icon, if any.""" """Return the buddies icon, if any."""
return self._icon return self._icon
def get_address(self): def get_address(self):
return self._address return self._address
def get_name(self): def get_name(self):
return self._nick_name return self._nick_name
def get_color(self): def get_color(self):
return self._color return self._color
def get_current_activity(self): def get_current_activity(self):
if not self._current_activity: if not self._current_activity:
return None return None
if not self._activities.has_key(self._current_activity): if not self._activities.has_key(self._current_activity):
return None return None
return self._activities[self._current_activity] return self._activities[self._current_activity]
def _set_icon(self, icon): def _set_icon(self, icon):
"""Can only set icon for other buddies. The Owner """Can only set icon for other buddies. The Owner
takes care of setting it's own icon.""" takes care of setting it's own icon."""
if icon != self._icon: if icon != self._icon:
self._icon = icon self._icon = icon
self._dbus_helper.IconChanged() self._dbus_helper.IconChanged()
def is_owner(self): def is_owner(self):
return False return False
class Owner(Buddy): class Owner(Buddy):
"""Class representing the owner of the machine. This is the client """Class representing the owner of the machine. This is the client
portion of the Owner, paired with the server portion in Owner.py.""" portion of the Owner, paired with the server portion in Owner.py."""
def __init__(self, ps, bus_name, object_id, icon_cache): def __init__(self, ps, bus_name, object_id, icon_cache):
Buddy.__init__(self, bus_name, object_id, None, icon_cache) Buddy.__init__(self, bus_name, object_id, None, icon_cache)
self._nick_name = profile.get_nick_name() self._nick_name = profile.get_nick_name()
self._color = profile.get_color() self._color = profile.get_color()
self._ps = ps self._ps = ps
def add_service(self, service): def add_service(self, service):
"""Adds a new service to this buddy's service list, returning """Adds a new service to this buddy's service list, returning
True if the service was successfully added, and False if it was not.""" True if the service was successfully added, and False if it was not."""
if service.get_name() != self._nick_name: if service.get_name() != self._nick_name:
logging.error("Service and buddy nick names doesn't match: " \ logging.error("Service and buddy nick names doesn't match: " \
"%s %s" % (service.get_name(), self._nick_name)) "%s %s" % (service.get_name(), self._nick_name))
return False return False
# The Owner initially doesn't have an address, so the first # The Owner initially doesn't have an address, so the first
# service added to the Owner determines the owner's address # service added to the Owner determines the owner's address
source_addr = service.get_source_address() source_addr = service.get_source_address()
if self._address is None and service.is_local(): if self._address is None and service.is_local():
self._address = source_addr self._address = source_addr
self._dbus_helper.PropertyChanged(['ip4_address']) self._dbus_helper.PropertyChanged(['ip4_address'])
# The owner bypasses address checks and only cares if # The owner bypasses address checks and only cares if
# avahi says the service is a local service # avahi says the service is a local service
if not service.is_local(): if not service.is_local():
logging.error("Cannot add remote service to owner object.") logging.error("Cannot add remote service to owner object.")
return False return False
logging.debug("Adding owner service %s.%s at %s:%d." % (service.get_name(), logging.debug("Adding owner service %s.%s at %s:%d." % (service.get_name(),
service.get_type(), service.get_source_address(), service.get_type(), service.get_source_address(),
service.get_port())) service.get_port()))
return self._internal_add_service(service) return self._internal_add_service(service)
def is_owner(self): def is_owner(self):
return True return True
################################################################# #################################################################
@ -468,62 +468,62 @@ import Service
__objid_seq = 0 __objid_seq = 0
def _next_objid(): def _next_objid():
global __objid_seq global __objid_seq
__objid_seq = __objid_seq + 1 __objid_seq = __objid_seq + 1
return __objid_seq return __objid_seq
class BuddyTestCase(unittest.TestCase): class BuddyTestCase(unittest.TestCase):
_DEF_NAME = u"Tommy" _DEF_NAME = u"Tommy"
_DEF_STYPE = unicode(PRESENCE_SERVICE_TYPE) _DEF_STYPE = unicode(PRESENCE_SERVICE_TYPE)
_DEF_DOMAIN = u"local" _DEF_DOMAIN = u"local"
_DEF_ADDRESS = u"1.1.1.1" _DEF_ADDRESS = u"1.1.1.1"
_DEF_PORT = 1234 _DEF_PORT = 1234
def __init__(self, name): def __init__(self, name):
self._bus = dbus.SessionBus() self._bus = dbus.SessionBus()
self._bus_name = dbus.service.BusName('org.laptop.Presence', bus=self._bus) self._bus_name = dbus.service.BusName('org.laptop.Presence', bus=self._bus)
unittest.TestCase.__init__(self, name) unittest.TestCase.__init__(self, name)
def __del__(self): def __del__(self):
del self._bus_name del self._bus_name
del self._bus del self._bus
def _test_init_fail(self, service, fail_msg): def _test_init_fail(self, service, fail_msg):
"""Test something we expect to fail.""" """Test something we expect to fail."""
try: try:
objid = _next_objid() objid = _next_objid()
buddy = Buddy(self._bus_name, objid, service, owner=False) buddy = Buddy(self._bus_name, objid, service, owner=False)
except ValueError, exc: except ValueError, exc:
pass pass
else: else:
self.fail("expected a ValueError for %s." % fail_msg) self.fail("expected a ValueError for %s." % fail_msg)
def testService(self): def testService(self):
service = None service = None
self._test_init_fail(service, "invalid service") self._test_init_fail(service, "invalid service")
def testGoodInit(self): def testGoodInit(self):
objid = _next_objid() objid = _next_objid()
service = Service.Service(self._bus_name, objid, self._DEF_NAME, self._DEF_STYPE, self._DEF_DOMAIN, service = Service.Service(self._bus_name, objid, self._DEF_NAME, self._DEF_STYPE, self._DEF_DOMAIN,
self._DEF_ADDRESS, self._DEF_PORT) self._DEF_ADDRESS, self._DEF_PORT)
objid = _next_objid() objid = _next_objid()
buddy = Buddy(self._bus_name, objid, service) buddy = Buddy(self._bus_name, objid, service)
assert buddy.get_name() == self._DEF_NAME, "buddy name wasn't correct after init." assert buddy.get_name() == self._DEF_NAME, "buddy name wasn't correct after init."
assert buddy.get_address() == self._DEF_ADDRESS, "buddy address wasn't correct after init." assert buddy.get_address() == self._DEF_ADDRESS, "buddy address wasn't correct after init."
assert buddy.object_path() == BUDDY_DBUS_OBJECT_PATH + str(objid) assert buddy.object_path() == BUDDY_DBUS_OBJECT_PATH + str(objid)
def addToSuite(suite): def addToSuite(suite):
suite.addTest(BuddyTestCase("testService")) suite.addTest(BuddyTestCase("testService"))
suite.addTest(BuddyTestCase("testGoodInit")) suite.addTest(BuddyTestCase("testGoodInit"))
addToSuite = staticmethod(addToSuite) addToSuite = staticmethod(addToSuite)
def main(): def main():
suite = unittest.TestSuite() suite = unittest.TestSuite()
BuddyTestCase.addToSuite(suite) BuddyTestCase.addToSuite(suite)
runner = unittest.TextTestRunner() runner = unittest.TextTestRunner()
runner.run(suite) runner.run(suite)
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@ -19,59 +19,59 @@ from sugar import env
from sugar import util from sugar import util
class BuddyIconCache(object): class BuddyIconCache(object):
"""Caches icons on disk and finds them based on md5 hash.""" """Caches icons on disk and finds them based on md5 hash."""
def __init__(self): def __init__(self):
ppath = env.get_profile_path() ppath = env.get_profile_path()
self._cachepath = os.path.join(ppath, "cache", "buddy-icons") self._cachepath = os.path.join(ppath, "cache", "buddy-icons")
if not os.path.exists(self._cachepath): if not os.path.exists(self._cachepath):
os.makedirs(self._cachepath) os.makedirs(self._cachepath)
self._cache = {} self._cache = {}
# Read all cached icons and their sums # Read all cached icons and their sums
for fname in os.listdir(self._cachepath): for fname in os.listdir(self._cachepath):
m = md5.new() m = md5.new()
data = self._get_icon_data(fname) data = self._get_icon_data(fname)
if len(data) == 0: if len(data) == 0:
continue continue
m.update(data) m.update(data)
printable_hash = util.printable_hash(m.digest()) printable_hash = util.printable_hash(m.digest())
self._cache[printable_hash] = fname self._cache[printable_hash] = fname
del m del m
def _get_icon_data(self, fname): def _get_icon_data(self, fname):
fd = open(os.path.join(self._cachepath, fname), "r") fd = open(os.path.join(self._cachepath, fname), "r")
data = fd.read() data = fd.read()
fd.close() fd.close()
del fd del fd
return data return data
def get_icon(self, printable_hash): def get_icon(self, printable_hash):
if not isinstance(printable_hash, unicode): if not isinstance(printable_hash, unicode):
raise RuntimeError("printable_hash must be a unicode string.") raise RuntimeError("printable_hash must be a unicode string.")
try: try:
fname = self._cache[printable_hash] fname = self._cache[printable_hash]
return self._get_icon_data(fname) return self._get_icon_data(fname)
except KeyError: except KeyError:
pass pass
return None return None
def add_icon(self, icon_data): def add_icon(self, icon_data):
if len(icon_data) == 0: if len(icon_data) == 0:
return return
m = md5.new() m = md5.new()
m.update(icon_data) m.update(icon_data)
printable_hash = util.printable_hash(m.digest()) printable_hash = util.printable_hash(m.digest())
if self._cache.has_key(printable_hash): if self._cache.has_key(printable_hash):
del m del m
return return
# Write the icon to disk and add an entry to our cache for it # Write the icon to disk and add an entry to our cache for it
m.update(time.asctime()) m.update(time.asctime())
fname = util.printable_hash(m.digest()) fname = util.printable_hash(m.digest())
fd = open(os.path.join(self._cachepath, fname), "w") fd = open(os.path.join(self._cachepath, fname), "w")
fd.write(icon_data) fd.write(icon_data)
fd.close() fd.close()
self._cache[printable_hash] = fname self._cache[printable_hash] = fname
del m del m

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -27,7 +27,7 @@ logviewer_widget = logviewer.Interface().widget
logviewer_widget.show() logviewer_widget.show()
# Terminal interface # Terminal interface
terminal_widget = terminal.Interface().widget terminal_widget = terminal.Interface().widget
terminal_widget.show() terminal_widget.show()
# Notebook # Notebook

View File

@ -26,76 +26,76 @@ import gobject
from sugar import env from sugar import env
class LogBuffer(gtk.TextBuffer): class LogBuffer(gtk.TextBuffer):
def __init__(self, logfile): def __init__(self, logfile):
gtk.TextBuffer.__init__(self) gtk.TextBuffer.__init__(self)
self._logfile = logfile self._logfile = logfile
self._pos = 0 self._pos = 0
self.update() self.update()
def update(self): def update(self):
f = open(self._logfile, 'r') f = open(self._logfile, 'r')
f.seek(self._pos) f.seek(self._pos)
self.insert(self.get_end_iter(), f.read()) self.insert(self.get_end_iter(), f.read())
self._pos = f.tell() self._pos = f.tell()
f.close() f.close()
return True return True
class LogView(gtk.ScrolledWindow): class LogView(gtk.ScrolledWindow):
def __init__(self, model): def __init__(self, model):
gtk.ScrolledWindow.__init__(self) gtk.ScrolledWindow.__init__(self)
self.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) self.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
textview = gtk.TextView(model) textview = gtk.TextView(model)
textview.set_wrap_mode(gtk.WRAP_WORD) textview.set_wrap_mode(gtk.WRAP_WORD)
textview.set_editable(False) textview.set_editable(False)
self.add(textview) self.add(textview)
textview.show() textview.show()
class MultiLogView(gtk.Notebook): class MultiLogView(gtk.Notebook):
def __init__(self, path): def __init__(self, path):
gtk.Notebook.__init__(self) gtk.Notebook.__init__(self)
self._logs_path = path self._logs_path = path
self._pages = {} self._pages = {}
self._update() self._update()
gobject.timeout_add(1000, self._update) gobject.timeout_add(1000, self._update)
def _add_page(self, logfile): def _add_page(self, logfile):
full_log_path = os.path.join(self._logs_path, logfile) full_log_path = os.path.join(self._logs_path, logfile)
model = LogBuffer(full_log_path) model = LogBuffer(full_log_path)
view = LogView(model) view = LogView(model)
self.append_page(view, gtk.Label(logfile)) self.append_page(view, gtk.Label(logfile))
view.show() view.show()
self._pages[logfile] = model self._pages[logfile] = model
def _update(self): def _update(self):
if not os.path.isdir(self._logs_path): if not os.path.isdir(self._logs_path):
return True return True
for logfile in os.listdir(self._logs_path): for logfile in os.listdir(self._logs_path):
if self._pages.has_key(logfile): if self._pages.has_key(logfile):
self._pages[logfile].update() self._pages[logfile].update()
else: else:
self._add_page(logfile) self._add_page(logfile)
return True return True
class Interface: class Interface:
def __init__(self): def __init__(self):
path = os.path.join(env.get_profile_path(), 'logs') path = os.path.join(env.get_profile_path(), 'logs')
viewer = MultiLogView(path) viewer = MultiLogView(path)
viewer.show() viewer.show()
self.widget = viewer self.widget = viewer

View File

@ -8,175 +8,175 @@ import plugin
from procmem import proc from procmem import proc
try: try:
import gtk import gtk
import gtk.gdk import gtk.gdk
import gobject import gobject
except: except:
sys.exit(1) sys.exit(1)
class Interface: class Interface:
store_data_types = [] store_data_types = []
store_data_types_details = [] store_data_types_details = []
def __init__(self): def __init__(self):
# Our GtkTree (Treeview) # Our GtkTree (Treeview)
self.treeview = gtk.TreeView() self.treeview = gtk.TreeView()
self.widget = self.treeview self.widget = self.treeview
# Loading plugins # Loading plugins
self.plg = plugin.Plugin() self.plg = plugin.Plugin()
# TOP data types (columns) # TOP data types (columns)
self.store_data_types = [] self.store_data_types = []
for plg in self.plg.list: for plg in self.plg.list:
plg_data = plg.INTERNALS plg_data = plg.INTERNALS
# Give plugin object to plugin # Give plugin object to plugin
plg.INTERNALS['Plg'] = self.plg plg.INTERNALS['Plg'] = self.plg
# Creating a store model and loading process data to Treeview # Creating a store model and loading process data to Treeview
# self.store_data_types, ex [int, str, str, str, int,...] # self.store_data_types, ex [int, str, str, str, int,...]
#self.store = gtk.TreeStore(*self.store_data_types) #self.store = gtk.TreeStore(*self.store_data_types)
self.data = Data(self.treeview, self.plg.list) self.data = Data(self.treeview, self.plg.list)
class Data: class Data:
treeview = None treeview = None
last_col_index = 0 last_col_index = 0
store_data_cols = [] store_data_cols = []
store_data_types = [] store_data_types = []
store_data_types_details = [] store_data_types_details = []
def __init__(self, treeview, plg_list): def __init__(self, treeview, plg_list):
# Top data types # Top data types
self.plg_list = plg_list self.plg_list = plg_list
for plg in self.plg_list: for plg in self.plg_list:
if plg.INTERNALS['top_data'] != None: if plg.INTERNALS['top_data'] != None:
last_dt = len(self.store_data_types) last_dt = len(self.store_data_types)
if last_dt > 0: if last_dt > 0:
last_dt -= 1 last_dt -= 1
len_dt = len(plg.INTERNALS['top_data']) len_dt = len(plg.INTERNALS['top_data'])
self.store_data_types_details.append({"plugin": plg, "init": last_dt, "end": last_dt + len_dt}) self.store_data_types_details.append({"plugin": plg, "init": last_dt, "end": last_dt + len_dt})
for dt in plg.INTERNALS['top_data']: for dt in plg.INTERNALS['top_data']:
self.store_data_types.append(dt) self.store_data_types.append(dt)
for col in plg.INTERNALS['top_cols']: for col in plg.INTERNALS['top_cols']:
self.store_data_cols.append(col) self.store_data_cols.append(col)
# Set global treeview # Set global treeview
self.treeview = treeview self.treeview = treeview
# Basic columns # Basic columns
index = 0 index = 0
for column_name in self.store_data_cols: for column_name in self.store_data_cols:
self.add_column(column_name, index) self.add_column(column_name, index)
index += 1 index += 1
self.store = gtk.TreeStore(*self.store_data_types) self.store = gtk.TreeStore(*self.store_data_types)
treeview.set_model(self.store) treeview.set_model(self.store)
# Update information every 1 second # Update information every 1 second
gobject.timeout_add(500, self.load_data, treeview) gobject.timeout_add(500, self.load_data, treeview)
# Add a new column to the main treeview # Add a new column to the main treeview
def add_column(self, column_name, index): def add_column(self, column_name, index):
cell = gtk.CellRendererText() cell = gtk.CellRendererText()
col_tv = gtk.TreeViewColumn(column_name, cell, text=index) col_tv = gtk.TreeViewColumn(column_name, cell, text=index)
col_tv.set_resizable(True) col_tv.set_resizable(True)
col_tv.connect('clicked', self.sort_column_clicked) col_tv.connect('clicked', self.sort_column_clicked)
col_tv.set_property('clickable', True) col_tv.set_property('clickable', True)
self.treeview.append_column(col_tv) self.treeview.append_column(col_tv)
# Set the last column index added # Set the last column index added
self.last_col_index = index self.last_col_index = index
# Sorting # Sorting
def sort_column_clicked(self, TreeViewColumn): def sort_column_clicked(self, TreeViewColumn):
cols = self.treeview.get_columns() cols = self.treeview.get_columns()
# Searching column index # Searching column index
index = 0 index = 0
for col in cols: for col in cols:
if col == TreeViewColumn: if col == TreeViewColumn:
break break
index += 1 index += 1
self.store.set_sort_column_id(index, gtk.SORT_DESCENDING) self.store.set_sort_column_id(index, gtk.SORT_DESCENDING)
def load_data(self, treeview): def load_data(self, treeview):
self.store.clear() self.store.clear()
# Getting procfs data # Getting procfs data
self.procdata = proc.ProcInfo() self.procdata = proc.ProcInfo()
self.process_list = [] self.process_list = []
pids = [] pids = []
screen = wnck.screen_get_default() screen = wnck.screen_get_default()
windows = screen.get_windows() windows = screen.get_windows()
current_pid = os.getpid() current_pid = os.getpid()
for win in windows: for win in windows:
pid = int(win.get_pid()) pid = int(win.get_pid())
if current_pid != pid: if current_pid != pid:
pids.append(pid) pids.append(pid)
self.process_list = set(pids) self.process_list = set(pids)
# Sort rows using pid # Sort rows using pid
#self.process_list.sort(key=operator.itemgetter('pid')) #self.process_list.sort(key=operator.itemgetter('pid'))
self.process_iter = [] self.process_iter = []
for pid in self.process_list: for pid in self.process_list:
pi = self.build_row(self.store, None, self.procdata, pid) pi = self.build_row(self.store, None, self.procdata, pid)
self.process_iter.append(pi) self.process_iter.append(pi)
treeview.set_rules_hint(True) treeview.set_rules_hint(True)
treeview.expand_all() treeview.expand_all()
return True return True
def build_row(self, store, parent_iter, proc_data, pid): def build_row(self, store, parent_iter, proc_data, pid):
data = [] data = []
pinfo = proc_data.MemoryInfo(pid) pinfo = proc_data.MemoryInfo(pid)
# Look for plugins that need to update the top data treeview # Look for plugins that need to update the top data treeview
for plg in self.plg_list: for plg in self.plg_list:
plg_data = [] plg_data = []
if plg.INTERNALS['top_data'] != None: if plg.INTERNALS['top_data'] != None:
# data = [xxx, yyy,zzz,...] # data = [xxx, yyy,zzz,...]
plg_data = plg.info.plg_on_top_data_refresh(plg, pinfo) plg_data = plg.info.plg_on_top_data_refresh(plg, pinfo)
for field in plg_data: for field in plg_data:
data.append(field) data.append(field)
pi = self.insert_row(store, parent_iter, data) pi = self.insert_row(store, parent_iter, data)
return pi return pi
# Insert a Row in our TreeView # Insert a Row in our TreeView
def insert_row(self, store, parent, row_data): def insert_row(self, store, parent, row_data):
iter = store.insert_after(parent, None) iter = store.insert_after(parent, None)
index = 0 index = 0
for data in row_data: for data in row_data:
store.set_value(iter, index , data) store.set_value(iter, index , data)
index += 1 index += 1
return iter return iter

View File

@ -9,42 +9,42 @@ from procmem import proc, proc_smaps, analysis
class Plugin: class Plugin:
# Plugin list # Plugin list
list = [] list = []
proc = proc.ProcInfo() proc = proc.ProcInfo()
internal_plugin = "memphis_init" internal_plugin = "memphis_init"
plg_path = os.path.dirname(os.path.abspath(__file__)) + "/plugins" plg_path = os.path.dirname(os.path.abspath(__file__)) + "/plugins"
# Frequency timer, managed by main program # Frequency timer, managed by main program
freq_timer = 0 freq_timer = 0
def __init__(self): def __init__(self):
sys.path.insert(0, self.plg_path) sys.path.insert(0, self.plg_path)
# Including memphis plugin # Including memphis plugin
self.list.append(__import__(self.internal_plugin)) self.list.append(__import__(self.internal_plugin))
if os.path.isdir(self.plg_path): if os.path.isdir(self.plg_path):
# around dir entries # around dir entries
for plg in os.listdir(self.plg_path): for plg in os.listdir(self.plg_path):
if plg == self.internal_plugin: if plg == self.internal_plugin:
continue continue
if os.path.isdir(self.plg_path + "/" + plg): if os.path.isdir(self.plg_path + "/" + plg):
p = __import__(plg) p = __import__(plg)
self.list.append(__import__(plg)) self.list.append(__import__(plg))
# Parse /proc/PID/smaps information # Parse /proc/PID/smaps information
def proc_get_smaps(self, pid): def proc_get_smaps(self, pid):
return proc_smaps.ProcSmaps(pid) return proc_smaps.ProcSmaps(pid)
# Parse /proc/PID/maps information # Parse /proc/PID/maps information
def proc_get_maps(self, pid): def proc_get_maps(self, pid):
return proc_smaps.ProcMaps(pid) return proc_smaps.ProcMaps(pid)
def proc_analysis(self, pid): def proc_analysis(self, pid):
return analysis.Analysis(pid) return analysis.Analysis(pid)

View File

@ -2,15 +2,15 @@
import info import info
INTERNALS = { INTERNALS = {
# Basic information # Basic information
'PLGNAME': "Clean Size", 'PLGNAME': "Clean Size",
'TABNAME': None, 'TABNAME': None,
'AUTHOR': "Eduardo Silva", 'AUTHOR': "Eduardo Silva",
'DESC': "Print the approx real memory usage", 'DESC': "Print the approx real memory usage",
# Plugin API # Plugin API
'Plg': None, # Plugin object 'Plg': None, # Plugin object
'top_data': [int], # Top data types needed by memphis core plugin 'top_data': [int], # Top data types needed by memphis core plugin
'top_cols': ["Approx Real Usage (kb)"] 'top_cols': ["Approx Real Usage (kb)"]
} }

View File

@ -7,9 +7,9 @@
############################################################ ############################################################
def plg_on_top_data_refresh(self, pinfo): def plg_on_top_data_refresh(self, pinfo):
# Get clean size # Get clean size
maps = self.INTERNALS['Plg'].proc_get_maps(pinfo['pid']) maps = self.INTERNALS['Plg'].proc_get_maps(pinfo['pid'])
size = (maps.clean_size/1024) size = (maps.clean_size/1024)
return [size] return [size]

View File

@ -2,20 +2,20 @@ import os
import info import info
INTERNALS = { INTERNALS = {
'PLGNAME': "cpu", 'PLGNAME': "cpu",
'TABNAME': None, 'TABNAME': None,
'AUTHOR': "Eduardo Silva", 'AUTHOR': "Eduardo Silva",
'DESC': "Print CPU usage", 'DESC': "Print CPU usage",
# Plugin API # Plugin API
'Plg': None, # Plugin object 'Plg': None, # Plugin object
'current_plg': None, # Current plugin object 'current_plg': None, # Current plugin object
'current_page': None, # Current page number 'current_page': None, # Current page number
# Top process view requirements # Top process view requirements
'top_data': [int], # Top data types needed by memphis core plugin 'top_data': [int], # Top data types needed by memphis core plugin
'top_cols': ["%CPU "] # Column names 'top_cols': ["%CPU "] # Column names
} }
# Get CPU frequency # Get CPU frequency
cpu_hz = os.sysconf(2) cpu_hz = os.sysconf(2)

View File

@ -7,42 +7,42 @@
############################################################ ############################################################
def plg_on_top_data_refresh(self, pinfo): def plg_on_top_data_refresh(self, pinfo):
PI = self.INTERNALS['Plg'].proc PI = self.INTERNALS['Plg'].proc
pid = pinfo['pid'] pid = pinfo['pid']
# Get JIFFIES CPU usage # Get JIFFIES CPU usage
used_jiffies = pinfo['utime'] + pinfo['stime'] used_jiffies = pinfo['utime'] + pinfo['stime']
last_ujiffies = get_pid_ujiffies(self, pid) last_ujiffies = get_pid_ujiffies(self, pid)
cpu_usage = PI.get_CPU_usage(self.cpu_hz, used_jiffies, pinfo['start_time']) cpu_usage = PI.get_CPU_usage(self.cpu_hz, used_jiffies, pinfo['start_time'])
# Get PERCENT CPU usage # Get PERCENT CPU usage
if last_ujiffies == 0.0: if last_ujiffies == 0.0:
pcpu = 0.0 pcpu = 0.0
set_pid_ujiffies(self, pid, cpu_usage['used_jiffies']) set_pid_ujiffies(self, pid, cpu_usage['used_jiffies'])
data = [int(pcpu)] data = [int(pcpu)]
return data return data
used_jiffies = cpu_usage['used_jiffies'] - last_ujiffies used_jiffies = cpu_usage['used_jiffies'] - last_ujiffies
# Available jiffies are # Available jiffies are
avail_jiffies = (500/1000.0)*self.cpu_hz # 500 = 0.5 second avail_jiffies = (500/1000.0)*self.cpu_hz # 500 = 0.5 second
pcpu = ((used_jiffies*100)/avail_jiffies) pcpu = ((used_jiffies*100)/avail_jiffies)
set_pid_ujiffies(self, pid, cpu_usage['used_jiffies']) set_pid_ujiffies(self, pid, cpu_usage['used_jiffies'])
data = [int(pcpu)] data = [int(pcpu)]
return data return data
def get_pid_ujiffies(self, pid): def get_pid_ujiffies(self, pid):
if pid in self.pids_ujiffies: if pid in self.pids_ujiffies:
return self.pids_ujiffies[pid] return self.pids_ujiffies[pid]
else: else:
set_pid_ujiffies(self, pid, 0) set_pid_ujiffies(self, pid, 0)
return self.pids_ujiffies[pid] return self.pids_ujiffies[pid]
def set_pid_ujiffies(self, pid, ujiffies): def set_pid_ujiffies(self, pid, ujiffies):
self.pids_ujiffies[pid] = ujiffies self.pids_ujiffies[pid] = ujiffies

View File

@ -3,15 +3,15 @@ import info
INTERNALS = { INTERNALS = {
# Basic information # Basic information
'PLGNAME': "Dirty Size", 'PLGNAME': "Dirty Size",
'TABNAME': None, # No tabbed plugin 'TABNAME': None, # No tabbed plugin
'AUTHOR': "Eduardo Silva", 'AUTHOR': "Eduardo Silva",
'DESC': "Get dirty size memory usage", 'DESC': "Get dirty size memory usage",
# Plugin API # Plugin API
'Plg': None, # Plugin object 'Plg': None, # Plugin object
'top_data': [int], # Top data types needed by memphis core plugin 'top_data': [int], # Top data types needed by memphis core plugin
'top_cols': ["PDRSS (kb)"] 'top_cols': ["PDRSS (kb)"]
} }

View File

@ -9,12 +9,12 @@
def plg_on_top_data_refresh(self, ppinfo): def plg_on_top_data_refresh(self, ppinfo):
dirty_sizes = get_dirty(self, ppinfo['pid']) dirty_sizes = get_dirty(self, ppinfo['pid'])
# memhis need an array # memhis need an array
return [dirty_sizes['private']] return [dirty_sizes['private']]
def get_dirty(pself, pid): def get_dirty(pself, pid):
ProcAnalysis = pself.INTERNALS['Plg'].proc_analysis(pid) ProcAnalysis = pself.INTERNALS['Plg'].proc_analysis(pid)
return ProcAnalysis.DirtyRSS() return ProcAnalysis.DirtyRSS()

View File

@ -1,15 +1,15 @@
import info import info
INTERNALS = { INTERNALS = {
'PLGNAME': "memphis", 'PLGNAME': "memphis",
'TABNAME': None, 'TABNAME': None,
'AUTHOR': "Eduardo Silva", 'AUTHOR': "Eduardo Silva",
'DESC': "Print basic process information", 'DESC': "Print basic process information",
# Plugin API # Plugin API
'Plg': None, # Plugin object 'Plg': None, # Plugin object
# Top process view requirements # Top process view requirements
'top_data': [int, str, str], # Top data types needed by memphis core plugin 'top_data': [int, str, str], # Top data types needed by memphis core plugin
'top_cols': ["PID", "Process Name", "Status"] # Column names 'top_cols': ["PID", "Process Name", "Status"] # Column names
} }

View File

@ -8,6 +8,6 @@
def plg_on_top_data_refresh(self, ppinfo): def plg_on_top_data_refresh(self, ppinfo):
data = [ppinfo['pid'], ppinfo['name'], ppinfo['state_name']] data = [ppinfo['pid'], ppinfo['name'], ppinfo['state_name']]
return data return data

View File

@ -1,30 +1,30 @@
import proc, proc_smaps import proc, proc_smaps
class Analysis: class Analysis:
pid = 0 pid = 0
def __init__(self, pid): def __init__(self, pid):
self.pid = pid self.pid = pid
def DirtyRSS(self): def DirtyRSS(self):
smaps = proc_smaps.ProcSmaps(self.pid) smaps = proc_smaps.ProcSmaps(self.pid)
dirty = [] dirty = []
private = 0 private = 0
shared = 0 shared = 0
for map in smaps.mappings: for map in smaps.mappings:
private += map.private_dirty private += map.private_dirty
shared += map.shared_dirty shared += map.shared_dirty
dirty = {"private": int(private), "shared": int(shared)} dirty = {"private": int(private), "shared": int(shared)}
return dirty return dirty
def ApproxRealMemoryUsage(self): def ApproxRealMemoryUsage(self):
maps = proc_smaps.ProcMaps(self.pid) maps = proc_smaps.ProcMaps(self.pid)
size = (maps.clean_size/1024) size = (maps.clean_size/1024)
return size return size

View File

@ -5,96 +5,96 @@ import string
class ProcInfo: class ProcInfo:
dir_path = "/proc/" # Our cute Proc File System dir_path = "/proc/" # Our cute Proc File System
status_file = "status" status_file = "status"
stat_file = "stat" stat_file = "stat"
proc_list = [] # Our PID list :D proc_list = [] # Our PID list :D
proc_info = [] # proc_info = [] #
def __init__(self): def __init__(self):
self.proc_list = self.Get_PID_List() self.proc_list = self.Get_PID_List()
# Returns Process List # Returns Process List
def Get_PID_List(self): def Get_PID_List(self):
list = [] list = []
# Exists our procfs ? # Exists our procfs ?
if os.path.isdir(self.dir_path): if os.path.isdir(self.dir_path):
# around dir entries # around dir entries
for f in os.listdir(self.dir_path): for f in os.listdir(self.dir_path):
if os.path.isdir(self.dir_path+f) & str.isdigit(f): if os.path.isdir(self.dir_path+f) & str.isdigit(f):
list.append(int(f)) list.append(int(f))
return list return list
def MemoryInfo(self, pid): def MemoryInfo(self, pid):
# Path # Path
pidfile = self.dir_path + str(pid) + "/stat" pidfile = self.dir_path + str(pid) + "/stat"
try: try:
infile = open(pidfile, "r") infile = open(pidfile, "r")
except: except:
print "Error trying " + pidfile print "Error trying " + pidfile
return None return None
# Parsing data , check 'man 5 proc' for details # Parsing data , check 'man 5 proc' for details
data = infile.read().split() data = infile.read().split()
infile.close() infile.close()
state_dic = { state_dic = {
'R': 'Running', 'R': 'Running',
'S': 'Sleeping', 'S': 'Sleeping',
'D': 'Disk sleep', 'D': 'Disk sleep',
'Z': 'Zombie', 'Z': 'Zombie',
'T': 'Traced/Stopped', 'T': 'Traced/Stopped',
'W': 'Paging' 'W': 'Paging'
} }
# user and group owners # user and group owners
pidstat = os.stat(pidfile) pidstat = os.stat(pidfile)
info = { info = {
'pid': int(data[0]), # Process ID 'pid': int(data[0]), # Process ID
'name': data[1].strip('()'), # Process name 'name': data[1].strip('()'), # Process name
'state': data[2], # Process State, ex: R|S|D|Z|T|W 'state': data[2], # Process State, ex: R|S|D|Z|T|W
'state_name': state_dic[data[2]], # Process State name, ex: Running, sleeping, Zombie, etc 'state_name': state_dic[data[2]], # Process State name, ex: Running, sleeping, Zombie, etc
'ppid': int(data[3]), # Parent process ID 'ppid': int(data[3]), # Parent process ID
'utime': int(data[13]), # Used jiffies in user mode 'utime': int(data[13]), # Used jiffies in user mode
'stime': int(data[14]), # Used jiffies in kernel mode 'stime': int(data[14]), # Used jiffies in kernel mode
'start_time': int(data[21]), # Process time from system boot (jiffies) 'start_time': int(data[21]), # Process time from system boot (jiffies)
'vsize': int(data[22]), # Virtual memory size used (bytes) 'vsize': int(data[22]), # Virtual memory size used (bytes)
'rss': int(data[23])*4, # Resident Set Size (bytes) 'rss': int(data[23])*4, # Resident Set Size (bytes)
'user_id': pidstat.st_uid, # process owner 'user_id': pidstat.st_uid, # process owner
'group_id': pidstat.st_gid # owner group 'group_id': pidstat.st_gid # owner group
} }
return info return info
# Returns the CPU usage expressed in Jiffies # Returns the CPU usage expressed in Jiffies
def get_CPU_usage(self, cpu_hz, used_jiffies, start_time): def get_CPU_usage(self, cpu_hz, used_jiffies, start_time):
# Uptime info # Uptime info
uptime_file = self.dir_path + "/uptime" uptime_file = self.dir_path + "/uptime"
try: try:
infile = file(uptime_file, "r") infile = file(uptime_file, "r")
except: except:
print "Error trying uptime file" print "Error trying uptime file"
return None return None
uptime_line = infile.readline() uptime_line = infile.readline()
uptime = string.split(uptime_line, " ",2) uptime = string.split(uptime_line, " ",2)
infile.close() infile.close()
# System uptime, from /proc/uptime # System uptime, from /proc/uptime
uptime = float(uptime[0]) uptime = float(uptime[0])
# Jiffies # Jiffies
avail_jiffies = (uptime * cpu_hz) - start_time avail_jiffies = (uptime * cpu_hz) - start_time
cpu_usage = {'used_jiffies': used_jiffies, 'avail_jiffies': avail_jiffies} cpu_usage = {'used_jiffies': used_jiffies, 'avail_jiffies': avail_jiffies}
return cpu_usage return cpu_usage

View File

@ -9,121 +9,121 @@ import os
# Parse the /proc/PID/smaps file # Parse the /proc/PID/smaps file
class ProcSmaps: class ProcSmaps:
mappings = [] # Devices information mappings = [] # Devices information
def __init__(self, pid): def __init__(self, pid):
smapfile = "/proc/%s/smaps" % pid smapfile = "/proc/%s/smaps" % pid
self.mappings = [] self.mappings = []
# Coded by Federico Mena (script) # Coded by Federico Mena (script)
try: try:
infile = open(smapfile, "r") infile = open(smapfile, "r")
input = infile.read() input = infile.read()
infile.close() infile.close()
except: except:
print "Error trying " + smapfile print "Error trying " + smapfile
return return
lines = input.splitlines() lines = input.splitlines()
num_lines = len (lines) num_lines = len (lines)
line_idx = 0 line_idx = 0
# 08065000-08067000 rw-p 0001c000 03:01 147613 /opt/gnome/bin/evolution-2.6 # 08065000-08067000 rw-p 0001c000 03:01 147613 /opt/gnome/bin/evolution-2.6
# Size: 8 kB # Size: 8 kB
# Rss: 8 kB # Rss: 8 kB
# Shared_Clean: 0 kB # Shared_Clean: 0 kB
# Shared_Dirty: 0 kB # Shared_Dirty: 0 kB
# Private_Clean: 8 kB # Private_Clean: 8 kB
# Private_Dirty: 0 kB # Private_Dirty: 0 kB
while num_lines > 0: while num_lines > 0:
fields = lines[line_idx].split (" ", 5) fields = lines[line_idx].split (" ", 5)
if len (fields) == 6: if len (fields) == 6:
(offsets, permissions, bin_permissions, device, inode, name) = fields (offsets, permissions, bin_permissions, device, inode, name) = fields
else: else:
(offsets, permissions, bin_permissions, device, inode) = fields (offsets, permissions, bin_permissions, device, inode) = fields
name = "" name = ""
size = self.parse_smaps_size_line (lines[line_idx + 1]) size = self.parse_smaps_size_line (lines[line_idx + 1])
rss = self.parse_smaps_size_line (lines[line_idx + 2]) rss = self.parse_smaps_size_line (lines[line_idx + 2])
shared_clean = self.parse_smaps_size_line (lines[line_idx + 3]) shared_clean = self.parse_smaps_size_line (lines[line_idx + 3])
shared_dirty = self.parse_smaps_size_line (lines[line_idx + 4]) shared_dirty = self.parse_smaps_size_line (lines[line_idx + 4])
private_clean = self.parse_smaps_size_line (lines[line_idx + 5]) private_clean = self.parse_smaps_size_line (lines[line_idx + 5])
private_dirty = self.parse_smaps_size_line (lines[line_idx + 6]) private_dirty = self.parse_smaps_size_line (lines[line_idx + 6])
name = name.strip () name = name.strip ()
mapping = Mapping (size, rss, shared_clean, shared_dirty, private_clean, private_dirty, permissions, name) mapping = Mapping (size, rss, shared_clean, shared_dirty, private_clean, private_dirty, permissions, name)
self.mappings.append (mapping) self.mappings.append (mapping)
num_lines -= 7 num_lines -= 7
line_idx += 7 line_idx += 7
# Parses a line of the form "foo: 42 kB" and returns an integer for the "42" field # Parses a line of the form "foo: 42 kB" and returns an integer for the "42" field
def parse_smaps_size_line (self, line): def parse_smaps_size_line (self, line):
# Rss: 8 kB # Rss: 8 kB
fields = line.split () fields = line.split ()
return int(fields[1]) return int(fields[1])
class Mapping: class Mapping:
def __init__ (self, size, rss, shared_clean, shared_dirty, private_clean, private_dirty, permissions, name): def __init__ (self, size, rss, shared_clean, shared_dirty, private_clean, private_dirty, permissions, name):
self.size = size self.size = size
self.rss = rss self.rss = rss
self.shared_clean = shared_clean self.shared_clean = shared_clean
self.shared_dirty = shared_dirty self.shared_dirty = shared_dirty
self.private_clean = private_clean self.private_clean = private_clean
self.private_dirty = private_dirty self.private_dirty = private_dirty
self.permissions = permissions self.permissions = permissions
self.name = name self.name = name
# Parse /proc/PID/maps file to get the clean memory usage by process, # Parse /proc/PID/maps file to get the clean memory usage by process,
# we avoid lines with backed-files # we avoid lines with backed-files
class ProcMaps: class ProcMaps:
clean_size = 0 clean_size = 0
def __init__(self, pid): def __init__(self, pid):
mapfile = "/proc/%s/maps" % pid mapfile = "/proc/%s/maps" % pid
try: try:
infile = open(mapfile, "r") infile = open(mapfile, "r")
except: except:
print "Error trying " + mapfile print "Error trying " + mapfile
return None return None
sum = 0 sum = 0
to_data_do = { to_data_do = {
"[anon]": self.parse_size_line, "[anon]": self.parse_size_line,
"[heap]": self.parse_size_line "[heap]": self.parse_size_line
} }
for line in infile: for line in infile:
arr = line.split() arr = line.split()
# Just parse writable mapped areas # Just parse writable mapped areas
if arr[1][1] != "w": if arr[1][1] != "w":
continue continue
if len(arr) == 6: if len(arr) == 6:
# if we got a backed-file we skip this info # if we got a backed-file we skip this info
if os.path.isfile(arr[5]): if os.path.isfile(arr[5]):
continue continue
else: else:
line_size = to_data_do.get(arr[5], self.skip)(line) line_size = to_data_do.get(arr[5], self.skip)(line)
sum += line_size sum += line_size
else: else:
line_size = self.parse_size_line(line) line_size = self.parse_size_line(line)
sum += line_size sum += line_size
infile.close() infile.close()
self.clean_size = sum self.clean_size = sum
def skip(self, line): def skip(self, line):
return 0 return 0
# Parse a maps line and return the mapped size # Parse a maps line and return the mapped size
def parse_size_line(self, line): def parse_size_line(self, line):
start, end = line.split()[0].split('-') start, end = line.split()[0].split('-')
size = int(end, 16) - int(start, 16) size = int(end, 16) - int(start, 16)
return size return size

View File

@ -3,141 +3,141 @@ import vte
import pango import pango
class Terminal(gtk.HBox): class Terminal(gtk.HBox):
def __init__(self): def __init__(self):
gtk.HBox.__init__(self, False, 4) gtk.HBox.__init__(self, False, 4)
self._vte = vte.Terminal() self._vte = vte.Terminal()
self._configure_vte() self._configure_vte()
self._vte.set_size(30, 5) self._vte.set_size(30, 5)
self._vte.set_size_request(200, 450) self._vte.set_size_request(200, 450)
self._vte.show() self._vte.show()
self.pack_start(self._vte) self.pack_start(self._vte)
self._scrollbar = gtk.VScrollbar(self._vte.get_adjustment()) self._scrollbar = gtk.VScrollbar(self._vte.get_adjustment())
self._scrollbar.show() self._scrollbar.show()
self.pack_start(self._scrollbar, False, False, 0) self.pack_start(self._scrollbar, False, False, 0)
self._vte.connect("child-exited", lambda term: term.fork_command()) self._vte.connect("child-exited", lambda term: term.fork_command())
self._vte.fork_command() self._vte.fork_command()
def _configure_vte(self): def _configure_vte(self):
self._vte.set_font(pango.FontDescription('Monospace 10')) self._vte.set_font(pango.FontDescription('Monospace 10'))
self._vte.set_colors(gtk.gdk.color_parse ('#AAAAAA'), self._vte.set_colors(gtk.gdk.color_parse ('#AAAAAA'),
gtk.gdk.color_parse ('#000000'), gtk.gdk.color_parse ('#000000'),
[]) [])
self._vte.set_cursor_blinks(False) self._vte.set_cursor_blinks(False)
self._vte.set_audible_bell(False) self._vte.set_audible_bell(False)
self._vte.set_scrollback_lines(100) self._vte.set_scrollback_lines(100)
self._vte.set_allow_bold(True) self._vte.set_allow_bold(True)
self._vte.set_scroll_on_keystroke(False) self._vte.set_scroll_on_keystroke(False)
self._vte.set_scroll_on_output(False) self._vte.set_scroll_on_output(False)
self._vte.set_emulation('xterm') self._vte.set_emulation('xterm')
self._vte.set_visible_bell(False) self._vte.set_visible_bell(False)
def on_gconf_notification(self, client, cnxn_id, entry, what): def on_gconf_notification(self, client, cnxn_id, entry, what):
self.reconfigure_vte() self.reconfigure_vte()
def on_vte_button_press(self, term, event): def on_vte_button_press(self, term, event):
if event.button == 3: if event.button == 3:
self.do_popup(event) self.do_popup(event)
return True return True
def on_vte_popup_menu(self, term): def on_vte_popup_menu(self, term):
pass pass
class Multiple: class Multiple:
page_number = 0 page_number = 0
def __init__(self): def __init__(self):
self.notebook = gtk.Notebook() self.notebook = gtk.Notebook()
self.add_new_terminal() self.add_new_terminal()
open_terminal = gtk.Button('Open a new terminal') open_terminal = gtk.Button('Open a new terminal')
open_terminal.connect("clicked", self.add_new_terminal) open_terminal.connect("clicked", self.add_new_terminal)
open_terminal.show() open_terminal.show()
self.notebook.show() self.notebook.show()
self.main_vbox = gtk.VBox(False, 3) self.main_vbox = gtk.VBox(False, 3)
self.main_vbox.pack_start(open_terminal, True, True, 2) self.main_vbox.pack_start(open_terminal, True, True, 2)
self.main_vbox.pack_start(self.notebook, True, True, 2) self.main_vbox.pack_start(self.notebook, True, True, 2)
self.main_vbox.show_all() self.main_vbox.show_all()
# Remove a page from the notebook # Remove a page from the notebook
def close_terminal(self, button, child): def close_terminal(self, button, child):
page = self.notebook.page_num(child) page = self.notebook.page_num(child)
if page != -1: if page != -1:
self.notebook.remove_page(page) self.notebook.remove_page(page)
pages = self.notebook.get_n_pages() pages = self.notebook.get_n_pages()
if pages <= 0: if pages <= 0:
self.page_number = 0 self.page_number = 0
self.add_new_terminal() self.add_new_terminal()
# Need to refresh the widget -- # Need to refresh the widget --
# This forces the widget to redraw itself. # This forces the widget to redraw itself.
self.notebook.queue_draw_area(0, 0, -1, -1) self.notebook.queue_draw_area(0, 0, -1, -1)
def add_icon_to_button(self, button): def add_icon_to_button(self, button):
iconBox = gtk.HBox(False, 0) iconBox = gtk.HBox(False, 0)
image = gtk.Image() image = gtk.Image()
image.set_from_stock(gtk.STOCK_CLOSE, gtk.ICON_SIZE_MENU) image.set_from_stock(gtk.STOCK_CLOSE, gtk.ICON_SIZE_MENU)
gtk.Button.set_relief(button, gtk.RELIEF_NONE) gtk.Button.set_relief(button, gtk.RELIEF_NONE)
settings = gtk.Widget.get_settings (button) settings = gtk.Widget.get_settings (button)
(w,h) = gtk.icon_size_lookup_for_settings (settings, gtk.ICON_SIZE_MENU) (w,h) = gtk.icon_size_lookup_for_settings (settings, gtk.ICON_SIZE_MENU)
gtk.Widget.set_size_request (button, w + 4, h + 4) gtk.Widget.set_size_request (button, w + 4, h + 4)
image.show() image.show()
iconBox.pack_start(image, True, False, 0) iconBox.pack_start(image, True, False, 0)
button.add(iconBox) button.add(iconBox)
iconBox.show() iconBox.show()
def add_new_terminal(self, *arguments, **keywords): def add_new_terminal(self, *arguments, **keywords):
self.page_number += 1 self.page_number += 1
terminal = Terminal() terminal = Terminal()
terminal.show() terminal.show()
eventBox = self.create_custom_tab("Term %d" % self.page_number, terminal) eventBox = self.create_custom_tab("Term %d" % self.page_number, terminal)
self.notebook.append_page(terminal, eventBox) self.notebook.append_page(terminal, eventBox)
# Set the new page # Set the new page
pages = gtk.Notebook.get_n_pages(self.notebook) pages = gtk.Notebook.get_n_pages(self.notebook)
self.notebook.set_current_page(pages - 1) self.notebook.set_current_page(pages - 1)
return True return True
def create_custom_tab(self, text, child): def create_custom_tab(self, text, child):
eventBox = gtk.EventBox() eventBox = gtk.EventBox()
tabBox = gtk.HBox(False, 2) tabBox = gtk.HBox(False, 2)
tabLabel = gtk.Label(text) tabLabel = gtk.Label(text)
tabButton = gtk.Button() tabButton = gtk.Button()
tabButton.connect('clicked', self.close_terminal, child) tabButton.connect('clicked', self.close_terminal, child)
# Add a picture on a button # Add a picture on a button
self.add_icon_to_button(tabButton) self.add_icon_to_button(tabButton)
iconBox = gtk.HBox(False, 0) iconBox = gtk.HBox(False, 0)
eventBox.show() eventBox.show()
tabButton.show() tabButton.show()
tabLabel.show() tabLabel.show()
tabBox.pack_start(tabLabel, False) tabBox.pack_start(tabLabel, False)
tabBox.pack_start(tabButton, False) tabBox.pack_start(tabButton, False)
tabBox.show_all() tabBox.show_all()
eventBox.add(tabBox) eventBox.add(tabBox)
return eventBox return eventBox
class Interface: class Interface:
def __init__(self): def __init__(self):
multiple = Multiple() multiple = Multiple()
self.widget = multiple.main_vbox self.widget = multiple.main_vbox

View File

@ -21,122 +21,122 @@ import gobject
_NOT_PRESENT_COLOR = "#888888,#BBBBBB" _NOT_PRESENT_COLOR = "#888888,#BBBBBB"
class BuddyModel(gobject.GObject): class BuddyModel(gobject.GObject):
__gsignals__ = { __gsignals__ = {
'appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([])), 'appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([])),
'disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([])), 'disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([])),
'color-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, 'color-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([gobject.TYPE_PYOBJECT])), ([gobject.TYPE_PYOBJECT])),
'icon-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, 'icon-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([])), ([])),
'current-activity-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, 'current-activity-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([gobject.TYPE_PYOBJECT])) ([gobject.TYPE_PYOBJECT]))
} }
def __init__(self, name=None, buddy=None): def __init__(self, name=None, buddy=None):
if name and buddy: if name and buddy:
raise RuntimeError("Must specify only _one_ of name or buddy.") raise RuntimeError("Must specify only _one_ of name or buddy.")
gobject.GObject.__init__(self) gobject.GObject.__init__(self)
self._ba_handler = None self._ba_handler = None
self._pc_handler = None self._pc_handler = None
self._dis_handler = None self._dis_handler = None
self._bic_handler = None self._bic_handler = None
self._cac_handler = None self._cac_handler = None
self._pservice = PresenceService.get_instance() self._pservice = PresenceService.get_instance()
self._buddy = None self._buddy = None
# If given just a name, try to get the buddy from the PS first # If given just a name, try to get the buddy from the PS first
if not buddy: if not buddy:
self._name = name self._name = name
# FIXME: use public key, not name # FIXME: use public key, not name
buddy = self._pservice.get_buddy_by_name(self._name) buddy = self._pservice.get_buddy_by_name(self._name)
# If successful, copy properties from the PS buddy object # If successful, copy properties from the PS buddy object
if buddy: if buddy:
self.__update_buddy(buddy) self.__update_buddy(buddy)
else: else:
# Otherwise, connect to the PS's buddy-appeared signal and # Otherwise, connect to the PS's buddy-appeared signal and
# wait for the buddy to appear # wait for the buddy to appear
self._ba_handler = self._pservice.connect('buddy-appeared', self._ba_handler = self._pservice.connect('buddy-appeared',
self.__buddy_appeared_cb) self.__buddy_appeared_cb)
self._name = name self._name = name
# Set color to 'inactive'/'disconnected' # Set color to 'inactive'/'disconnected'
self.__set_color_from_string(_NOT_PRESENT_COLOR) self.__set_color_from_string(_NOT_PRESENT_COLOR)
def __set_color_from_string(self, color_string): def __set_color_from_string(self, color_string):
self._color = IconColor(color_string) self._color = IconColor(color_string)
def get_name(self): def get_name(self):
return self._name return self._name
def get_color(self): def get_color(self):
return self._color return self._color
def get_buddy(self): def get_buddy(self):
return self._buddy return self._buddy
def is_present(self): def is_present(self):
if self._buddy: if self._buddy:
return True return True
return False return False
def get_current_activity(self): def get_current_activity(self):
if self._buddy: if self._buddy:
return self._buddy.get_current_activity() return self._buddy.get_current_activity()
return None return None
def __update_buddy(self, buddy): def __update_buddy(self, buddy):
if not buddy: if not buddy:
raise ValueError("Buddy cannot be None.") raise ValueError("Buddy cannot be None.")
self._buddy = buddy self._buddy = buddy
self._name = self._buddy.get_name() self._name = self._buddy.get_name()
self.__set_color_from_string(self._buddy.get_color()) self.__set_color_from_string(self._buddy.get_color())
self._pc_handler = self._buddy.connect('property-changed', self.__buddy_property_changed_cb) self._pc_handler = self._buddy.connect('property-changed', self.__buddy_property_changed_cb)
self._dis_handler = self._buddy.connect('disappeared', self.__buddy_disappeared_cb) self._dis_handler = self._buddy.connect('disappeared', self.__buddy_disappeared_cb)
self._bic_handler = self._buddy.connect('icon-changed', self.__buddy_icon_changed_cb) self._bic_handler = self._buddy.connect('icon-changed', self.__buddy_icon_changed_cb)
self._cac_handler = self._buddy.connect('current-activity-changed', self.__buddy_current_activity_changed_cb) self._cac_handler = self._buddy.connect('current-activity-changed', self.__buddy_current_activity_changed_cb)
def __buddy_appeared_cb(self, pservice, buddy): def __buddy_appeared_cb(self, pservice, buddy):
# FIXME: use public key rather than buddy name # FIXME: use public key rather than buddy name
if self._buddy or buddy.get_name() != self._name: if self._buddy or buddy.get_name() != self._name:
return return
if self._ba_handler: if self._ba_handler:
# Once we have the buddy, we no longer need to # Once we have the buddy, we no longer need to
# monitor buddy-appeared events # monitor buddy-appeared events
self._pservice.disconnect(self._ba_handler) self._pservice.disconnect(self._ba_handler)
self._ba_handler = None self._ba_handler = None
self.__update_buddy(buddy) self.__update_buddy(buddy)
self.emit('appeared') self.emit('appeared')
def __buddy_property_changed_cb(self, buddy, keys): def __buddy_property_changed_cb(self, buddy, keys):
if not self._buddy: if not self._buddy:
return return
if 'color' in keys: if 'color' in keys:
self.__set_color_from_string(self._buddy.get_color()) self.__set_color_from_string(self._buddy.get_color())
self.emit('color-changed', self.get_color()) self.emit('color-changed', self.get_color())
def __buddy_disappeared_cb(self, buddy): def __buddy_disappeared_cb(self, buddy):
if buddy != self._buddy: if buddy != self._buddy:
return return
self._buddy.disconnect(self._pc_handler) self._buddy.disconnect(self._pc_handler)
self._buddy.disconnect(self._dis_handler) self._buddy.disconnect(self._dis_handler)
self._buddy.disconnect(self._bic_handler) self._buddy.disconnect(self._bic_handler)
self._buddy.disconnect(self._cac_handler) self._buddy.disconnect(self._cac_handler)
self.__set_color_from_string(_NOT_PRESENT_COLOR) self.__set_color_from_string(_NOT_PRESENT_COLOR)
self.emit('disappeared') self.emit('disappeared')
self._buddy = None self._buddy = None
def __buddy_icon_changed_cb(self, buddy): def __buddy_icon_changed_cb(self, buddy):
self.emit('icon-changed') self.emit('icon-changed')
def __buddy_current_activity_changed_cb(self, buddy, activity=None): def __buddy_current_activity_changed_cb(self, buddy, activity=None):
if not self._buddy: if not self._buddy:
return return
self.emit('current-activity-changed', activity) self.emit('current-activity-changed', activity)

View File

@ -24,61 +24,61 @@ from sugar import env
import logging import logging
class Friends(gobject.GObject): class Friends(gobject.GObject):
__gsignals__ = { __gsignals__ = {
'friend-added': (gobject.SIGNAL_RUN_FIRST, 'friend-added': (gobject.SIGNAL_RUN_FIRST,
gobject.TYPE_NONE, ([object])), gobject.TYPE_NONE, ([object])),
'friend-removed': (gobject.SIGNAL_RUN_FIRST, 'friend-removed': (gobject.SIGNAL_RUN_FIRST,
gobject.TYPE_NONE, ([str])), gobject.TYPE_NONE, ([str])),
} }
def __init__(self): def __init__(self):
gobject.GObject.__init__(self) gobject.GObject.__init__(self)
self._friends = {} self._friends = {}
self._path = os.path.join(env.get_profile_path(), 'friends') self._path = os.path.join(env.get_profile_path(), 'friends')
self.load() self.load()
def has_buddy(self, buddy): def has_buddy(self, buddy):
return self._friends.has_key(buddy.get_name()) return self._friends.has_key(buddy.get_name())
def add_friend(self, buddy_info): def add_friend(self, buddy_info):
self._friends[buddy_info.get_name()] = buddy_info self._friends[buddy_info.get_name()] = buddy_info
self.emit('friend-added', buddy_info) self.emit('friend-added', buddy_info)
def make_friend(self, buddy): def make_friend(self, buddy):
if not self.has_buddy(buddy): if not self.has_buddy(buddy):
self.add_friend(BuddyModel(buddy=buddy)) self.add_friend(BuddyModel(buddy=buddy))
self.save() self.save()
def remove(self, buddy_info): def remove(self, buddy_info):
del self._friends[buddy_info.get_name()] del self._friends[buddy_info.get_name()]
self.save() self.save()
self.emit('friend-removed', buddy_info.get_name()) self.emit('friend-removed', buddy_info.get_name())
def __iter__(self): def __iter__(self):
return self._friends.values().__iter__() return self._friends.values().__iter__()
def load(self): def load(self):
cp = ConfigParser() cp = ConfigParser()
try: try:
success = cp.read([self._path]) success = cp.read([self._path])
if success: if success:
for name in cp.sections(): for name in cp.sections():
buddy = BuddyModel(name) buddy = BuddyModel(name)
self.add_friend(buddy) self.add_friend(buddy)
except Exception, exc: except Exception, exc:
logging.error("Error parsing friends file: %s" % exc) logging.error("Error parsing friends file: %s" % exc)
def save(self): def save(self):
cp = ConfigParser() cp = ConfigParser()
for friend in self: for friend in self:
section = friend.get_name() section = friend.get_name()
cp.add_section(section) cp.add_section(section)
cp.set(section, 'color', friend.get_color().to_string()) cp.set(section, 'color', friend.get_color().to_string())
fileobject = open(self._path, 'w') fileobject = open(self._path, 'w')
cp.write(fileobject) cp.write(fileobject)
fileobject.close() fileobject.close()

View File

@ -17,38 +17,38 @@
import gobject import gobject
class Invite: class Invite:
def __init__(self, issuer, bundle_id, activity_id): def __init__(self, issuer, bundle_id, activity_id):
self._issuer = issuer self._issuer = issuer
self._activity_id = activity_id self._activity_id = activity_id
self._bundle_id = bundle_id self._bundle_id = bundle_id
def get_activity_id(self): def get_activity_id(self):
return self._activity_id return self._activity_id
def get_bundle_id(self): def get_bundle_id(self):
return self._bundle_id return self._bundle_id
class Invites(gobject.GObject): class Invites(gobject.GObject):
__gsignals__ = { __gsignals__ = {
'invite-added': (gobject.SIGNAL_RUN_FIRST, 'invite-added': (gobject.SIGNAL_RUN_FIRST,
gobject.TYPE_NONE, ([object])), gobject.TYPE_NONE, ([object])),
'invite-removed': (gobject.SIGNAL_RUN_FIRST, 'invite-removed': (gobject.SIGNAL_RUN_FIRST,
gobject.TYPE_NONE, ([object])), gobject.TYPE_NONE, ([object])),
} }
def __init__(self): def __init__(self):
gobject.GObject.__init__(self) gobject.GObject.__init__(self)
self._list = [] self._list = []
def add_invite(self, issuer, bundle_id, activity_id): def add_invite(self, issuer, bundle_id, activity_id):
invite = Invite(issuer, bundle_id, activity_id) invite = Invite(issuer, bundle_id, activity_id)
self._list.append(invite) self._list.append(invite)
self.emit('invite-added', invite) self.emit('invite-added', invite)
def remove_invite(self, invite): def remove_invite(self, invite):
self._list.remove(invite) self._list.remove(invite)
self.emit('invite-removed', invite) self.emit('invite-removed', invite)
def __iter__(self): def __iter__(self):
return self._list.__iter__() return self._list.__iter__()

View File

@ -21,137 +21,137 @@ from sugar.presence import PresenceService
from model.BuddyModel import BuddyModel from model.BuddyModel import BuddyModel
class ActivityModel: class ActivityModel:
def __init__(self, activity, bundle, service): def __init__(self, activity, bundle, service):
self._service = service self._service = service
self._activity = activity self._activity = activity
def get_id(self): def get_id(self):
return self._activity.get_id() return self._activity.get_id()
def get_icon_name(self): def get_icon_name(self):
return bundle.get_icon() return bundle.get_icon()
def get_color(self): def get_color(self):
return IconColor(self._activity.get_color()) return IconColor(self._activity.get_color())
def get_service(self): def get_service(self):
return self._service return self._service
class MeshModel(gobject.GObject): class MeshModel(gobject.GObject):
__gsignals__ = { __gsignals__ = {
'activity-added': (gobject.SIGNAL_RUN_FIRST, 'activity-added': (gobject.SIGNAL_RUN_FIRST,
gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])), gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])),
'activity-removed': (gobject.SIGNAL_RUN_FIRST, 'activity-removed': (gobject.SIGNAL_RUN_FIRST,
gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])), gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])),
'buddy-added': (gobject.SIGNAL_RUN_FIRST, 'buddy-added': (gobject.SIGNAL_RUN_FIRST,
gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])), gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])),
'buddy-moved': (gobject.SIGNAL_RUN_FIRST, 'buddy-moved': (gobject.SIGNAL_RUN_FIRST,
gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT, gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT,
gobject.TYPE_PYOBJECT])), gobject.TYPE_PYOBJECT])),
'buddy-removed': (gobject.SIGNAL_RUN_FIRST, 'buddy-removed': (gobject.SIGNAL_RUN_FIRST,
gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])) gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT]))
} }
def __init__(self, bundle_registry): def __init__(self, bundle_registry):
gobject.GObject.__init__(self) gobject.GObject.__init__(self)
self._activities = {} self._activities = {}
self._buddies = {} self._buddies = {}
self._bundle_registry = bundle_registry self._bundle_registry = bundle_registry
self._pservice = PresenceService.get_instance() self._pservice = PresenceService.get_instance()
self._pservice.connect("service-appeared", self._pservice.connect("service-appeared",
self._service_appeared_cb) self._service_appeared_cb)
self._pservice.connect('activity-disappeared', self._pservice.connect('activity-disappeared',
self._activity_disappeared_cb) self._activity_disappeared_cb)
self._pservice.connect("buddy-appeared", self._pservice.connect("buddy-appeared",
self._buddy_appeared_cb) self._buddy_appeared_cb)
self._pservice.connect("buddy-disappeared", self._pservice.connect("buddy-disappeared",
self._buddy_disappeared_cb) self._buddy_disappeared_cb)
# Add any buddies the PS knows about already # Add any buddies the PS knows about already
for buddy in self._pservice.get_buddies(): for buddy in self._pservice.get_buddies():
self._buddy_appeared_cb(self._pservice, buddy) self._buddy_appeared_cb(self._pservice, buddy)
for service in self._pservice.get_services(): for service in self._pservice.get_services():
self._check_service(service) self._check_service(service)
def get_activities(self): def get_activities(self):
return self._activities.values() return self._activities.values()
def get_buddies(self): def get_buddies(self):
return self._buddies.values() return self._buddies.values()
def _buddy_activity_changed_cb(self, buddy, cur_activity): def _buddy_activity_changed_cb(self, buddy, cur_activity):
if not self._buddies.has_key(buddy.get_name()): if not self._buddies.has_key(buddy.get_name()):
return return
buddy_model = self._buddies[buddy.get_name()] buddy_model = self._buddies[buddy.get_name()]
if cur_activity == None: if cur_activity == None:
self.emit('buddy-moved', buddy_model, None) self.emit('buddy-moved', buddy_model, None)
else: else:
self._notify_buddy_change(buddy_model, cur_activity) self._notify_buddy_change(buddy_model, cur_activity)
def _notify_buddy_change(self, buddy_model, cur_activity): def _notify_buddy_change(self, buddy_model, cur_activity):
if self._activities.has_key(cur_activity.get_id()): if self._activities.has_key(cur_activity.get_id()):
activity_model = self._activities[cur_activity.get_id()] activity_model = self._activities[cur_activity.get_id()]
self.emit('buddy-moved', buddy_model, activity_model) self.emit('buddy-moved', buddy_model, activity_model)
def _buddy_appeared_cb(self, pservice, buddy): def _buddy_appeared_cb(self, pservice, buddy):
model = BuddyModel(buddy=buddy) model = BuddyModel(buddy=buddy)
if self._buddies.has_key(model.get_name()): if self._buddies.has_key(model.get_name()):
del model del model
return return
model.connect('current-activity-changed', model.connect('current-activity-changed',
self._buddy_activity_changed_cb) self._buddy_activity_changed_cb)
self._buddies[model.get_name()] = model self._buddies[model.get_name()] = model
self.emit('buddy-added', model) self.emit('buddy-added', model)
cur_activity = buddy.get_current_activity() cur_activity = buddy.get_current_activity()
if cur_activity: if cur_activity:
self._notify_buddy_change(model, cur_activity) self._notify_buddy_change(model, cur_activity)
def _buddy_disappeared_cb(self, pservice, buddy): def _buddy_disappeared_cb(self, pservice, buddy):
if not self._buddies.has_key(buddy.get_name()): if not self._buddies.has_key(buddy.get_name()):
return return
self.emit('buddy-removed', buddy) self.emit('buddy-removed', buddy)
del self._buddies[buddy.get_name()] del self._buddies[buddy.get_name()]
def _service_appeared_cb(self, pservice, service): def _service_appeared_cb(self, pservice, service):
self._check_service(service) self._check_service(service)
def _check_service(self, service): def _check_service(self, service):
if self._bundle_registry.get_bundle(service.get_type()) != None: if self._bundle_registry.get_bundle(service.get_type()) != None:
activity_id = service.get_activity_id() activity_id = service.get_activity_id()
if not self.has_activity(activity_id): if not self.has_activity(activity_id):
activity = self._pservice.get_activity(activity_id) activity = self._pservice.get_activity(activity_id)
if activity != None: if activity != None:
self.add_activity(activity, service) self.add_activity(activity, service)
def has_activity(self, activity_id): def has_activity(self, activity_id):
return self._activities.has_key(activity_id) return self._activities.has_key(activity_id)
def get_activity(self, activity_id): def get_activity(self, activity_id):
if self.has_activity(activity_id): if self.has_activity(activity_id):
return self._activities[activity_id] return self._activities[activity_id]
else: else:
return None return None
def add_activity(self, activity, service): def add_activity(self, activity, service):
bundle = self._bundle_registry.get_bundle(service.get_type()) bundle = self._bundle_registry.get_bundle(service.get_type())
model = ActivityModel(activity, bundle, service) model = ActivityModel(activity, bundle, service)
self._activities[model.get_id()] = model self._activities[model.get_id()] = model
self.emit('activity-added', model) self.emit('activity-added', model)
for buddy in self._pservice.get_buddies(): for buddy in self._pservice.get_buddies():
cur_activity = buddy.get_current_activity() cur_activity = buddy.get_current_activity()
name = buddy.get_name() name = buddy.get_name()
if cur_activity == activity and self._buddies.has_key(name): if cur_activity == activity and self._buddies.has_key(name):
buddy_model = self._buddies[name] buddy_model = self._buddies[name]
self.emit('buddy-moved', buddy_model, model) self.emit('buddy-moved', buddy_model, model)
def _activity_disappeared_cb(self, pservice, activity): def _activity_disappeared_cb(self, pservice, activity):
if self._activities.has_key(activity.get_id()): if self._activities.has_key(activity.get_id()):
activity_model = self._activities[activity.get_id()] activity_model = self._activities[activity.get_id()]
self.emit('activity-removed', activity_model) self.emit('activity-removed', activity_model)
del self._activities[activity.get_id()] del self._activities[activity.get_id()]

View File

@ -31,90 +31,90 @@ from model.Invites import Invites
PRESENCE_SERVICE_TYPE = "_presence_olpc._tcp" PRESENCE_SERVICE_TYPE = "_presence_olpc._tcp"
class ShellOwner(object): class ShellOwner(object):
"""Class representing the owner of this machine/instance. This class """Class representing the owner of this machine/instance. This class
runs in the shell and serves up the buddy icon and other stuff. It's the runs in the shell and serves up the buddy icon and other stuff. It's the
server portion of the Owner, paired with the client portion in Buddy.py.""" server portion of the Owner, paired with the client portion in Buddy.py."""
def __init__(self): def __init__(self):
self._nick = profile.get_nick_name() self._nick = profile.get_nick_name()
user_dir = env.get_profile_path() user_dir = env.get_profile_path()
self._icon = None self._icon = None
self._icon_hash = "" self._icon_hash = ""
for fname in os.listdir(user_dir): for fname in os.listdir(user_dir):
if not fname.startswith("buddy-icon."): if not fname.startswith("buddy-icon."):
continue continue
fd = open(os.path.join(user_dir, fname), "r") fd = open(os.path.join(user_dir, fname), "r")
self._icon = fd.read() self._icon = fd.read()
if self._icon: if self._icon:
# Get the icon's hash # Get the icon's hash
import md5, binascii import md5, binascii
digest = md5.new(self._icon).digest() digest = md5.new(self._icon).digest()
self._icon_hash = util.printable_hash(digest) self._icon_hash = util.printable_hash(digest)
fd.close() fd.close()
break break
self._pservice = PresenceService.get_instance() self._pservice = PresenceService.get_instance()
self._invites = Invites() self._invites = Invites()
self._last_activity_update = time.time() self._last_activity_update = time.time()
self._pending_activity_update_timer = None self._pending_activity_update_timer = None
self._pending_activity_update = None self._pending_activity_update = None
def get_invites(self): def get_invites(self):
return self._invites return self._invites
def get_name(self): def get_name(self):
return self._nick return self._nick
def announce(self): def announce(self):
# Create and announce our presence # Create and announce our presence
color = profile.get_color() color = profile.get_color()
props = {'color': color.to_string(), 'icon-hash': self._icon_hash} props = {'color': color.to_string(), 'icon-hash': self._icon_hash}
self._service = self._pservice.register_service(self._nick, self._service = self._pservice.register_service(self._nick,
PRESENCE_SERVICE_TYPE, properties=props) PRESENCE_SERVICE_TYPE, properties=props)
logging.debug("Owner '%s' using port %d" % (self._nick, self._service.get_port())) logging.debug("Owner '%s' using port %d" % (self._nick, self._service.get_port()))
self._icon_stream = Stream.Stream.new_from_service(self._service) self._icon_stream = Stream.Stream.new_from_service(self._service)
self._icon_stream.register_reader_handler(self._handle_buddy_icon_request, "get_buddy_icon") self._icon_stream.register_reader_handler(self._handle_buddy_icon_request, "get_buddy_icon")
self._icon_stream.register_reader_handler(self._handle_invite, "invite") self._icon_stream.register_reader_handler(self._handle_invite, "invite")
def _handle_buddy_icon_request(self): def _handle_buddy_icon_request(self):
"""XMLRPC method, return the owner's icon encoded with base64.""" """XMLRPC method, return the owner's icon encoded with base64."""
if self._icon: if self._icon:
return base64.b64encode(self._icon) return base64.b64encode(self._icon)
return "" return ""
def _handle_invite(self, issuer, bundle_id, activity_id): def _handle_invite(self, issuer, bundle_id, activity_id):
"""XMLRPC method, called when the owner is invited to an activity.""" """XMLRPC method, called when the owner is invited to an activity."""
self._invites.add_invite(issuer, bundle_id, activity_id) self._invites.add_invite(issuer, bundle_id, activity_id)
return '' return ''
def __update_advertised_current_activity_cb(self): def __update_advertised_current_activity_cb(self):
self._last_activity_update = time.time() self._last_activity_update = time.time()
self._pending_activity_update_timer = None self._pending_activity_update_timer = None
if self._pending_activity_update: if self._pending_activity_update:
logging.debug("*** Updating current activity to %s" % self._pending_activity_update) logging.debug("*** Updating current activity to %s" % self._pending_activity_update)
self._service.set_published_value('curact', dbus.String(self._pending_activity_update)) self._service.set_published_value('curact', dbus.String(self._pending_activity_update))
return False return False
def set_current_activity(self, activity_id): def set_current_activity(self, activity_id):
"""Update our presence service with the latest activity, but no """Update our presence service with the latest activity, but no
more frequently than every 30 seconds""" more frequently than every 30 seconds"""
self._pending_activity_update = activity_id self._pending_activity_update = activity_id
# If there's no pending update, we must not have updated it in the # If there's no pending update, we must not have updated it in the
# last 30 seconds (except for the initial update, hence we also check # last 30 seconds (except for the initial update, hence we also check
# for the last update) # for the last update)
if not self._pending_activity_update_timer or time.time() - self._last_activity_update > 30: if not self._pending_activity_update_timer or time.time() - self._last_activity_update > 30:
self.__update_advertised_current_activity_cb() self.__update_advertised_current_activity_cb()
return return
# If we have a pending update already, we have nothing left to do # If we have a pending update already, we have nothing left to do
if self._pending_activity_update_timer: if self._pending_activity_update_timer:
return return
# Otherwise, we start a timer to update the activity at the next # Otherwise, we start a timer to update the activity at the next
# interval, which should be 30 seconds from the last update, or if that # interval, which should be 30 seconds from the last update, or if that
# is in the past already, then now # is in the past already, then now
next = 30 - max(30, time.time() - self._last_activity_update) next = 30 - max(30, time.time() - self._last_activity_update)
self._pending_activity_update_timer = gobject.timeout_add(next * 1000, self._pending_activity_update_timer = gobject.timeout_add(next * 1000,
self.__update_advertised_current_activity_cb) self.__update_advertised_current_activity_cb)

View File

@ -24,45 +24,45 @@ from model.Owner import ShellOwner
from sugar import env from sugar import env
class ShellModel: class ShellModel:
def __init__(self): def __init__(self):
self._current_activity = None self._current_activity = None
self._bundle_registry = BundleRegistry() self._bundle_registry = BundleRegistry()
PresenceService.start() PresenceService.start()
self._pservice = PresenceService.get_instance() self._pservice = PresenceService.get_instance()
self._owner = ShellOwner() self._owner = ShellOwner()
self._owner.announce() self._owner.announce()
self._friends = Friends() self._friends = Friends()
self._mesh = MeshModel(self._bundle_registry) self._mesh = MeshModel(self._bundle_registry)
path = os.path.expanduser('~/Activities') path = os.path.expanduser('~/Activities')
self._bundle_registry.add_search_path(path) self._bundle_registry.add_search_path(path)
for path in env.get_data_dirs(): for path in env.get_data_dirs():
bundles_path = os.path.join(path, 'activities') bundles_path = os.path.join(path, 'activities')
self._bundle_registry.add_search_path(bundles_path) self._bundle_registry.add_search_path(bundles_path)
def get_bundle_registry(self): def get_bundle_registry(self):
return self._bundle_registry return self._bundle_registry
def get_mesh(self): def get_mesh(self):
return self._mesh return self._mesh
def get_friends(self): def get_friends(self):
return self._friends return self._friends
def get_invites(self): def get_invites(self):
return self._owner.get_invites() return self._owner.get_invites()
def get_owner(self): def get_owner(self):
return self._owner return self._owner
def set_current_activity(self, activity_id): def set_current_activity(self, activity_id):
self._current_activity = activity_id self._current_activity = activity_id
self._owner.set_current_activity(activity_id) self._owner.set_current_activity(activity_id)
def get_current_activity(self): def get_current_activity(self):
return self._current_activity return self._current_activity

View File

@ -27,122 +27,122 @@ from sugar.chat import ActivityChat
import OverlayWindow import OverlayWindow
class ActivityChatWindow(gtk.Window): class ActivityChatWindow(gtk.Window):
def __init__(self, gdk_window, chat_widget): def __init__(self, gdk_window, chat_widget):
gtk.Window.__init__(self) gtk.Window.__init__(self)
self.realize() self.realize()
self.set_decorated(False) self.set_decorated(False)
self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG) self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
self.window.set_accept_focus(True) self.window.set_accept_focus(True)
self.window.set_transient_for(gdk_window) self.window.set_transient_for(gdk_window)
self.set_position(gtk.WIN_POS_CENTER_ALWAYS) self.set_position(gtk.WIN_POS_CENTER_ALWAYS)
self.set_default_size(600, 450) self.set_default_size(600, 450)
self.add(chat_widget) self.add(chat_widget)
class ActivityHost: class ActivityHost:
def __init__(self, shell_model, window): def __init__(self, shell_model, window):
self._window = window self._window = window
self._xid = window.get_xid() self._xid = window.get_xid()
self._pservice = PresenceService.get_instance() self._pservice = PresenceService.get_instance()
bus = dbus.SessionBus() bus = dbus.SessionBus()
proxy_obj = bus.get_object(Activity.get_service_name(self._xid), proxy_obj = bus.get_object(Activity.get_service_name(self._xid),
Activity.get_object_path(self._xid)) Activity.get_object_path(self._xid))
self._activity = dbus.Interface(proxy_obj, Activity.ACTIVITY_INTERFACE) self._activity = dbus.Interface(proxy_obj, Activity.ACTIVITY_INTERFACE)
self._id = self._activity.get_id() self._id = self._activity.get_id()
self._type = self._activity.get_type() self._type = self._activity.get_type()
self._gdk_window = gtk.gdk.window_foreign_new(self._xid) self._gdk_window = gtk.gdk.window_foreign_new(self._xid)
registry = shell_model.get_bundle_registry() registry = shell_model.get_bundle_registry()
info = registry.get_bundle(self._type) info = registry.get_bundle(self._type)
self._icon_name = info.get_icon() self._icon_name = info.get_icon()
try: try:
self._overlay_window = OverlayWindow.OverlayWindow(self._gdk_window) self._overlay_window = OverlayWindow.OverlayWindow(self._gdk_window)
win = self._overlay_window.window win = self._overlay_window.window
except RuntimeError: except RuntimeError:
self._overlay_window = None self._overlay_window = None
win = self._gdk_window win = self._gdk_window
self._chat_widget = ActivityChat.ActivityChat(self) self._chat_widget = ActivityChat.ActivityChat(self)
self._chat_window = ActivityChatWindow(win, self._chat_widget) self._chat_window = ActivityChatWindow(win, self._chat_widget)
self._frame_was_visible = False self._frame_was_visible = False
def get_id(self): def get_id(self):
return self._id return self._id
def get_title(self): def get_title(self):
return self._window.get_name() return self._window.get_name()
def get_xid(self): def get_xid(self):
return self._xid return self._xid
def get_icon_name(self): def get_icon_name(self):
return self._icon_name return self._icon_name
def get_icon_color(self): def get_icon_color(self):
activity = self._pservice.get_activity(self._id) activity = self._pservice.get_activity(self._id)
if activity != None: if activity != None:
return IconColor(activity.get_color()) return IconColor(activity.get_color())
else: else:
return profile.get_color() return profile.get_color()
def share(self): def share(self):
self._activity.share() self._activity.share()
self._chat_widget.share() self._chat_widget.share()
def invite(self, buddy): def invite(self, buddy):
if not self.get_shared(): if not self.get_shared():
self.share() self.share()
issuer = self._pservice.get_owner().get_name() issuer = self._pservice.get_owner().get_name()
service = buddy.get_service_of_type("_presence_olpc._tcp") service = buddy.get_service_of_type("_presence_olpc._tcp")
stream = Stream.Stream.new_from_service(service, start_reader=False) stream = Stream.Stream.new_from_service(service, start_reader=False)
writer = stream.new_writer(service) writer = stream.new_writer(service)
writer.custom_request("invite", None, None, issuer, writer.custom_request("invite", None, None, issuer,
self._type, self._id) self._type, self._id)
def get_shared(self): def get_shared(self):
return self._activity.get_shared() return self._activity.get_shared()
def get_type(self): def get_type(self):
return self._type return self._type
def present(self): def present(self):
self._window.activate(gtk.get_current_event_time()) self._window.activate(gtk.get_current_event_time())
def close(self): def close(self):
self._window.close(gtk.get_current_event_time()) self._window.close(gtk.get_current_event_time())
def show_dialog(self, dialog): def show_dialog(self, dialog):
dialog.show() dialog.show()
dialog.window.set_transient_for(self._gdk_window) dialog.window.set_transient_for(self._gdk_window)
def chat_show(self, frame_was_visible): def chat_show(self, frame_was_visible):
if self._overlay_window: if self._overlay_window:
self._overlay_window.show_all() self._overlay_window.show_all()
self._chat_window.show_all() self._chat_window.show_all()
self._frame_was_visible = frame_was_visible self._frame_was_visible = frame_was_visible
def chat_hide(self): def chat_hide(self):
self._chat_window.hide() self._chat_window.hide()
if self._overlay_window: if self._overlay_window:
self._overlay_window.hide() self._overlay_window.hide()
wasvis = self._frame_was_visible wasvis = self._frame_was_visible
self._frame_was_visible = False self._frame_was_visible = False
return wasvis return wasvis
def is_chat_visible(self): def is_chat_visible(self):
return self._chat_window.get_property('visible') return self._chat_window.get_property('visible')
def set_active(self, active): def set_active(self, active):
if not active: if not active:
self.chat_hide() self.chat_hide()
self._frame_was_visible = False self._frame_was_visible = False
def destroy(self): def destroy(self):
self._chat_window.destroy() self._chat_window.destroy()
self._frame_was_visible = False self._frame_was_visible = False

View File

@ -18,41 +18,41 @@ from sugar.graphics.menuicon import MenuIcon
from view.BuddyMenu import BuddyMenu from view.BuddyMenu import BuddyMenu
class BuddyIcon(MenuIcon): class BuddyIcon(MenuIcon):
def __init__(self, shell, menu_shell, buddy): def __init__(self, shell, menu_shell, buddy):
MenuIcon.__init__(self, menu_shell, icon_name='stock-buddy', MenuIcon.__init__(self, menu_shell, icon_name='stock-buddy',
color=buddy.get_color()) color=buddy.get_color())
self._shell = shell self._shell = shell
self._buddy = buddy self._buddy = buddy
self._buddy.connect('appeared', self._buddy_presence_change_cb) self._buddy.connect('appeared', self._buddy_presence_change_cb)
self._buddy.connect('disappeared', self._buddy_presence_change_cb) self._buddy.connect('disappeared', self._buddy_presence_change_cb)
self._buddy.connect('color-changed', self._buddy_presence_change_cb) self._buddy.connect('color-changed', self._buddy_presence_change_cb)
def _buddy_presence_change_cb(self, buddy, color=None): def _buddy_presence_change_cb(self, buddy, color=None):
# Update the icon's color when the buddy comes and goes # Update the icon's color when the buddy comes and goes
self.set_property('color', buddy.get_color()) self.set_property('color', buddy.get_color())
def set_popup_distance(self, distance): def set_popup_distance(self, distance):
self._popup_distance = distance self._popup_distance = distance
def create_menu(self): def create_menu(self):
menu = BuddyMenu(self._shell, self._buddy) menu = BuddyMenu(self._shell, self._buddy)
menu.connect('action', self._popup_action_cb) menu.connect('action', self._popup_action_cb)
return menu return menu
def _popup_action_cb(self, popup, action): def _popup_action_cb(self, popup, action):
self.popdown() self.popdown()
friends = self._shell.get_model().get_friends() friends = self._shell.get_model().get_friends()
if action == BuddyMenu.ACTION_REMOVE_FRIEND: if action == BuddyMenu.ACTION_REMOVE_FRIEND:
friends.remove(self._buddy) friends.remove(self._buddy)
ps_buddy = self._buddy.get_buddy() ps_buddy = self._buddy.get_buddy()
if ps_buddy == None: if ps_buddy == None:
return return
if action == BuddyMenu.ACTION_INVITE: if action == BuddyMenu.ACTION_INVITE:
activity = self._shell.get_current_activity() activity = self._shell.get_current_activity()
activity.invite(ps_buddy) activity.invite(ps_buddy)
elif action == BuddyMenu.ACTION_MAKE_FRIEND: elif action == BuddyMenu.ACTION_MAKE_FRIEND:
friends.make_friend(ps_buddy) friends.make_friend(ps_buddy)

View File

@ -25,73 +25,73 @@ from sugar.presence import PresenceService
_ICON_SIZE = 75 _ICON_SIZE = 75
class BuddyMenu(Menu): class BuddyMenu(Menu):
ACTION_MAKE_FRIEND = 0 ACTION_MAKE_FRIEND = 0
ACTION_INVITE = 1 ACTION_INVITE = 1
ACTION_REMOVE_FRIEND = 2 ACTION_REMOVE_FRIEND = 2
def __init__(self, shell, buddy): def __init__(self, shell, buddy):
self._buddy = buddy self._buddy = buddy
self._shell = shell self._shell = shell
icon_item = None icon_item = None
pixbuf = self._get_buddy_icon_pixbuf() pixbuf = self._get_buddy_icon_pixbuf()
if pixbuf: if pixbuf:
scaled_pixbuf = pixbuf.scale_simple(_ICON_SIZE, _ICON_SIZE, scaled_pixbuf = pixbuf.scale_simple(_ICON_SIZE, _ICON_SIZE,
gtk.gdk.INTERP_BILINEAR) gtk.gdk.INTERP_BILINEAR)
del pixbuf del pixbuf
icon_item = hippo.CanvasImage(pixbuf=scaled_pixbuf) icon_item = hippo.CanvasImage(pixbuf=scaled_pixbuf)
Menu.__init__(self, buddy.get_name(), icon_item) Menu.__init__(self, buddy.get_name(), icon_item)
self._buddy.connect('icon-changed', self.__buddy_icon_changed_cb) self._buddy.connect('icon-changed', self.__buddy_icon_changed_cb)
owner = shell.get_model().get_owner() owner = shell.get_model().get_owner()
if buddy.get_name() != owner.get_name(): if buddy.get_name() != owner.get_name():
self._add_actions() self._add_actions()
def _get_buddy_icon_pixbuf(self): def _get_buddy_icon_pixbuf(self):
buddy_object = self._buddy.get_buddy() buddy_object = self._buddy.get_buddy()
if not buddy_object: if not buddy_object:
return None return None
pixbuf = None pixbuf = None
icon_data = buddy_object.get_icon() icon_data = buddy_object.get_icon()
icon_data_string = "" icon_data_string = ""
for item in icon_data: for item in icon_data:
if item < 0: if item < 0:
item = item + 128 item = item + 128
icon_data_string += chr(item) icon_data_string += chr(item)
pbl = gtk.gdk.PixbufLoader() pbl = gtk.gdk.PixbufLoader()
pbl.write(icon_data_string) pbl.write(icon_data_string)
try: try:
pbl.close() pbl.close()
pixbuf = pbl.get_pixbuf() pixbuf = pbl.get_pixbuf()
except gobject.GError: except gobject.GError:
pass pass
del pbl del pbl
return pixbuf return pixbuf
def _add_actions(self): def _add_actions(self):
shell_model = self._shell.get_model() shell_model = self._shell.get_model()
pservice = PresenceService.get_instance() pservice = PresenceService.get_instance()
friends = shell_model.get_friends() friends = shell_model.get_friends()
if friends.has_buddy(self._buddy): if friends.has_buddy(self._buddy):
icon = CanvasIcon(icon_name='stock-remove') icon = CanvasIcon(icon_name='stock-remove')
self.add_action(icon, BuddyMenu.ACTION_REMOVE_FRIEND) self.add_action(icon, BuddyMenu.ACTION_REMOVE_FRIEND)
else: else:
icon = CanvasIcon(icon_name='stock-add') icon = CanvasIcon(icon_name='stock-add')
self.add_action(icon, BuddyMenu.ACTION_MAKE_FRIEND) self.add_action(icon, BuddyMenu.ACTION_MAKE_FRIEND)
activity_id = shell_model.get_current_activity() activity_id = shell_model.get_current_activity()
if activity_id != None: if activity_id != None:
activity_ps = pservice.get_activity(activity_id) activity_ps = pservice.get_activity(activity_id)
# FIXME check that the buddy is not in the activity already # FIXME check that the buddy is not in the activity already
icon = CanvasIcon(icon_name='stock-invite') icon = CanvasIcon(icon_name='stock-invite')
self.add_action(icon, BuddyMenu.ACTION_INVITE) self.add_action(icon, BuddyMenu.ACTION_INVITE)
def __buddy_icon_changed_cb(self, buddy): def __buddy_icon_changed_cb(self, buddy):
pass pass

View File

@ -5,34 +5,34 @@ from sugar.clipboard import ClipboardService
class ClipboardIcon(MenuIcon): class ClipboardIcon(MenuIcon):
def __init__(self, menu_shell, name, file_name): def __init__(self, menu_shell, name, file_name):
MenuIcon.__init__(self, menu_shell, icon_name='activity-xbook') MenuIcon.__init__(self, menu_shell, icon_name='activity-xbook')
self._name = name self._name = name
self._file_name = file_name self._file_name = file_name
self._percent = 0 self._percent = 0
self.connect('activated', self._icon_activated_cb) self.connect('activated', self._icon_activated_cb)
self._menu = None self._menu = None
def create_menu(self): def create_menu(self):
self._menu = ClipboardMenu(self._name, self._percent) self._menu = ClipboardMenu(self._name, self._percent)
self._menu.connect('action', self._popup_action_cb) self._menu.connect('action', self._popup_action_cb)
return self._menu return self._menu
def set_percent(self, percent): def set_percent(self, percent):
self._percent = percent self._percent = percent
if self._menu: if self._menu:
self._menu.set_percent(percent) self._menu.set_percent(percent)
def _icon_activated_cb(self, icon): def _icon_activated_cb(self, icon):
if self._percent == 100: if self._percent == 100:
activity = ActivityFactory.create("org.laptop.sugar.Xbook") activity = ActivityFactory.create("org.laptop.sugar.Xbook")
activity.execute("open_document", [self._file_name]) activity.execute("open_document", [self._file_name])
def _popup_action_cb(self, popup, action): def _popup_action_cb(self, popup, action):
self.popdown() self.popdown()
if action == ClipboardMenu.ACTION_STOP_DOWNLOAD: if action == ClipboardMenu.ACTION_STOP_DOWNLOAD:
raise "Stopping downloads still not implemented." raise "Stopping downloads still not implemented."
elif action == ClipboardMenu.ACTION_DELETE: elif action == ClipboardMenu.ACTION_DELETE:
cb_service = ClipboardService.get_instance() cb_service = ClipboardService.get_instance()
cb_service.delete_object(self._file_name) cb_service.delete_object(self._file_name)

View File

@ -9,48 +9,48 @@ from sugar.graphics import style
class ClipboardMenuItem(ClipboardBubble): class ClipboardMenuItem(ClipboardBubble):
def __init__(self, percent = 0, stylesheet="clipboard.Bubble"): def __init__(self, percent = 0, stylesheet="clipboard.Bubble"):
ClipboardBubble.__init__(self, percent = percent) ClipboardBubble.__init__(self, percent = percent)
style.apply_stylesheet(self, stylesheet) style.apply_stylesheet(self, stylesheet)
class ClipboardMenu(Menu): class ClipboardMenu(Menu):
ACTION_DELETE = 0 ACTION_DELETE = 0
ACTION_SHARE = 1 ACTION_SHARE = 1
ACTION_STOP_DOWNLOAD = 2 ACTION_STOP_DOWNLOAD = 2
def __init__(self, name, percent): def __init__(self, name, percent):
Menu.__init__(self, name) Menu.__init__(self, name)
self._progress_bar = ClipboardMenuItem(percent) self._progress_bar = ClipboardMenuItem(percent)
self._root.append(self._progress_bar) self._root.append(self._progress_bar)
#icon = CanvasIcon(icon_name='stock-share-mesh') #icon = CanvasIcon(icon_name='stock-share-mesh')
#self.add_action(icon, ClipboardMenu.ACTION_SHARE) #self.add_action(icon, ClipboardMenu.ACTION_SHARE)
self._remove_icon = None self._remove_icon = None
self._stop_icon = None self._stop_icon = None
self._create_icons(percent) self._create_icons(percent)
def _create_icons(self, percent): def _create_icons(self, percent):
if percent == 100: if percent == 100:
if not self._remove_icon: if not self._remove_icon:
self._remove_icon = CanvasIcon(icon_name='stock-remove') self._remove_icon = CanvasIcon(icon_name='stock-remove')
self.add_action(self._remove_icon, ClipboardMenu.ACTION_DELETE) self.add_action(self._remove_icon, ClipboardMenu.ACTION_DELETE)
if self._stop_icon: if self._stop_icon:
self.remove_action(self._stop_icon) self.remove_action(self._stop_icon)
self._stop_icon = None self._stop_icon = None
else: else:
if not self._stop_icon: if not self._stop_icon:
self._stop_icon = CanvasIcon(icon_name='stock-close') self._stop_icon = CanvasIcon(icon_name='stock-close')
self.add_action(self._stop_icon, ClipboardMenu.ACTION_STOP_DOWNLOAD) self.add_action(self._stop_icon, ClipboardMenu.ACTION_STOP_DOWNLOAD)
if self._remove_icon: if self._remove_icon:
self.remove_action(self._remove_icon) self.remove_action(self._remove_icon)
self._remove_icon = None self._remove_icon = None
def set_percent(self, percent): def set_percent(self, percent):
self._progress_bar.set_property('percent', percent) self._progress_bar.set_property('percent', percent)
self._create_icons(percent) self._create_icons(percent)

View File

@ -24,47 +24,47 @@ from sugar.graphics.iconcolor import IconColor
from sugar import env from sugar import env
class FirstTimeDialog(gtk.Dialog): class FirstTimeDialog(gtk.Dialog):
def __init__(self): def __init__(self):
gtk.Dialog.__init__(self) gtk.Dialog.__init__(self)
label = gtk.Label(_('Nick Name:')) label = gtk.Label(_('Nick Name:'))
label.set_alignment(0.0, 0.5) label.set_alignment(0.0, 0.5)
self.vbox.pack_start(label) self.vbox.pack_start(label)
label.show() label.show()
self._entry = gtk.Entry() self._entry = gtk.Entry()
self._entry.connect('changed', self._entry_changed_cb) self._entry.connect('changed', self._entry_changed_cb)
self._entry.connect('activate', self._entry_activated_cb) self._entry.connect('activate', self._entry_activated_cb)
self.vbox.pack_start(self._entry) self.vbox.pack_start(self._entry)
self._entry.show() self._entry.show()
self._ok = gtk.Button(None, gtk.STOCK_OK) self._ok = gtk.Button(None, gtk.STOCK_OK)
self._ok.set_sensitive(False) self._ok.set_sensitive(False)
self.vbox.pack_start(self._ok) self.vbox.pack_start(self._ok)
self._ok.connect('clicked', self._ok_button_clicked_cb) self._ok.connect('clicked', self._ok_button_clicked_cb)
self._ok.show() self._ok.show()
def _entry_changed_cb(self, entry): def _entry_changed_cb(self, entry):
valid = (len(entry.get_text()) > 0) valid = (len(entry.get_text()) > 0)
self._ok.set_sensitive(valid) self._ok.set_sensitive(valid)
def _entry_activated_cb(self, entry): def _entry_activated_cb(self, entry):
self._create_buddy_section() self._create_buddy_section()
def _ok_button_clicked_cb(self, button): def _ok_button_clicked_cb(self, button):
self._create_buddy_section() self._create_buddy_section()
def _create_buddy_section(self): def _create_buddy_section(self):
cp = ConfigParser() cp = ConfigParser()
section = 'Buddy' section = 'Buddy'
cp.add_section(section) cp.add_section(section)
cp.set(section, 'NickName', self._entry.get_text()) cp.set(section, 'NickName', self._entry.get_text())
cp.set(section, 'Color', IconColor().to_string()) cp.set(section, 'Color', IconColor().to_string())
config_path = os.path.join(env.get_profile_path(), 'config') config_path = os.path.join(env.get_profile_path(), 'config')
fileobject = open(config_path, 'w') fileobject = open(config_path, 'w')
cp.write(fileobject) cp.write(fileobject)
fileobject.close() fileobject.close()
self.destroy() self.destroy()

View File

@ -19,32 +19,32 @@ import cairo
class OverlayWindow(gtk.Window): class OverlayWindow(gtk.Window):
def __init__(self, lower_window): def __init__(self, lower_window):
gtk.Window.__init__(self) gtk.Window.__init__(self)
colormap = self.get_screen().get_rgba_colormap() colormap = self.get_screen().get_rgba_colormap()
colormap=None colormap=None
if not colormap: if not colormap:
raise RuntimeError("The window manager doesn't support compositing.") raise RuntimeError("The window manager doesn't support compositing.")
self.set_colormap(colormap) self.set_colormap(colormap)
self.realize() self.realize()
self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG) self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
self.window.set_accept_focus(False) self.window.set_accept_focus(False)
self.window.set_transient_for(lower_window) self.window.set_transient_for(lower_window)
self.set_decorated(False) self.set_decorated(False)
self.set_position(gtk.WIN_POS_CENTER_ALWAYS) self.set_position(gtk.WIN_POS_CENTER_ALWAYS)
self.set_default_size(gtk.gdk.screen_width(), gtk.gdk.screen_height()) self.set_default_size(gtk.gdk.screen_width(), gtk.gdk.screen_height())
self.set_app_paintable(True) self.set_app_paintable(True)
self.connect('expose-event', self._expose_cb) self.connect('expose-event', self._expose_cb)
def _expose_cb(self, widget, event): def _expose_cb(self, widget, event):
cr = widget.window.cairo_create() cr = widget.window.cairo_create()
cr.set_source_rgba(0.0, 0.0, 0.0, 0.4) # Transparent cr.set_source_rgba(0.0, 0.0, 0.0, 0.4) # Transparent
cr.set_operator(cairo.OPERATOR_SOURCE) cr.set_operator(cairo.OPERATOR_SOURCE)
cr.paint() cr.paint()
return False return False

View File

@ -31,206 +31,206 @@ from _sugar import KeyGrabber
import sugar import sugar
class Shell(gobject.GObject): class Shell(gobject.GObject):
__gsignals__ = { __gsignals__ = {
'activity-opened': (gobject.SIGNAL_RUN_FIRST, 'activity-opened': (gobject.SIGNAL_RUN_FIRST,
gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])), gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])),
'activity-changed': (gobject.SIGNAL_RUN_FIRST, 'activity-changed': (gobject.SIGNAL_RUN_FIRST,
gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])), gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])),
'activity-closed': (gobject.SIGNAL_RUN_FIRST, 'activity-closed': (gobject.SIGNAL_RUN_FIRST,
gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])) gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT]))
} }
def __init__(self, model): def __init__(self, model):
gobject.GObject.__init__(self) gobject.GObject.__init__(self)
self._model = model self._model = model
self._hosts = {} self._hosts = {}
self._screen = wnck.screen_get_default() self._screen = wnck.screen_get_default()
self._current_host = None self._current_host = None
style.load_stylesheet(view.stylesheet) style.load_stylesheet(view.stylesheet)
self._dcon_manager = DCONManager() self._dcon_manager = DCONManager()
self._key_grabber = KeyGrabber() self._key_grabber = KeyGrabber()
self._key_grabber.connect('key-pressed', self._key_grabber.connect('key-pressed',
self.__global_key_pressed_cb) self.__global_key_pressed_cb)
self._key_grabber.connect('key-released', self._key_grabber.connect('key-released',
self.__global_key_released_cb) self.__global_key_released_cb)
self._key_grabber.grab('F1') self._key_grabber.grab('F1')
self._key_grabber.grab('F2') self._key_grabber.grab('F2')
self._key_grabber.grab('F3') self._key_grabber.grab('F3')
self._key_grabber.grab('F4') self._key_grabber.grab('F4')
self._key_grabber.grab('F5') self._key_grabber.grab('F5')
self._key_grabber.grab('F6') self._key_grabber.grab('F6')
self._key_grabber.grab('F7') self._key_grabber.grab('F7')
self._key_grabber.grab('F8') self._key_grabber.grab('F8')
self._key_grabber.grab('0xDC') # Camera key self._key_grabber.grab('0xDC') # Camera key
self._key_grabber.grab('0xE0') # Overlay key self._key_grabber.grab('0xE0') # Overlay key
self._key_grabber.grab('0x93') # Frame key self._key_grabber.grab('0x93') # Frame key
# For non-OLPC machines # For non-OLPC machines
self._key_grabber.grab('<shft><alt>F9') self._key_grabber.grab('<shft><alt>F9')
self._key_grabber.grab('<shft><alt>F10') self._key_grabber.grab('<shft><alt>F10')
self._key_grabber.grab('<shft><alt>F11') self._key_grabber.grab('<shft><alt>F11')
self._home_window = HomeWindow(self) self._home_window = HomeWindow(self)
self._home_window.show() self._home_window.show()
self.set_zoom_level(sugar.ZOOM_HOME) self.set_zoom_level(sugar.ZOOM_HOME)
self._screen.connect('window-opened', self.__window_opened_cb) self._screen.connect('window-opened', self.__window_opened_cb)
self._screen.connect('window-closed', self.__window_closed_cb) self._screen.connect('window-closed', self.__window_closed_cb)
self._screen.connect('active-window-changed', self._screen.connect('active-window-changed',
self.__active_window_changed_cb) self.__active_window_changed_cb)
self._frame = Frame(self) self._frame = Frame(self)
self._frame.show_and_hide(3) self._frame.show_and_hide(3)
def _open_terminal_cb(self): def _open_terminal_cb(self):
self.start_activity('org.sugar.Terminal') self.start_activity('org.sugar.Terminal')
return False return False
def __global_key_pressed_cb(self, grabber, key): def __global_key_pressed_cb(self, grabber, key):
if key == 'F1': if key == 'F1':
self.set_zoom_level(sugar.ZOOM_MESH) self.set_zoom_level(sugar.ZOOM_MESH)
elif key == 'F2': elif key == 'F2':
self.set_zoom_level(sugar.ZOOM_FRIENDS) self.set_zoom_level(sugar.ZOOM_FRIENDS)
elif key == 'F3': elif key == 'F3':
self.set_zoom_level(sugar.ZOOM_HOME) self.set_zoom_level(sugar.ZOOM_HOME)
elif key == 'F4': elif key == 'F4':
self.set_zoom_level(sugar.ZOOM_ACTIVITY) self.set_zoom_level(sugar.ZOOM_ACTIVITY)
elif key == 'F5': elif key == 'F5':
self._dcon_manager.decrease_brightness() self._dcon_manager.decrease_brightness()
elif key == 'F6': elif key == 'F6':
self._dcon_manager.increase_brightness() self._dcon_manager.increase_brightness()
elif key == 'F7': elif key == 'F7':
self._dcon_manager.set_mode(DCONManager.COLOR_MODE) self._dcon_manager.set_mode(DCONManager.COLOR_MODE)
elif key == 'F8': elif key == 'F8':
self._dcon_manager.set_mode(DCONManager.BLACK_AND_WHITE_MODE) self._dcon_manager.set_mode(DCONManager.BLACK_AND_WHITE_MODE)
elif key == '<shft><alt>F9': elif key == '<shft><alt>F9':
self._frame.notify_key_press() self._frame.notify_key_press()
elif key == '<shft><alt>F10': elif key == '<shft><alt>F10':
self.toggle_chat_visibility() self.toggle_chat_visibility()
elif key == '<shft><alt>F11': elif key == '<shft><alt>F11':
gobject.idle_add(self._open_terminal_cb) gobject.idle_add(self._open_terminal_cb)
elif key == '0xDC': # Camera key elif key == '0xDC': # Camera key
pass pass
elif key == '0xE0': # Overlay key elif key == '0xE0': # Overlay key
self.toggle_chat_visibility() self.toggle_chat_visibility()
elif key == '0x93': # Frame key elif key == '0x93': # Frame key
self._frame.notify_key_press() self._frame.notify_key_press()
def __global_key_released_cb(self, grabber, key): def __global_key_released_cb(self, grabber, key):
if key == '<shft><alt>F9': if key == '<shft><alt>F9':
self._frame.notify_key_release() self._frame.notify_key_release()
elif key == '0x93': elif key == '0x93':
self._frame.notify_key_release() self._frame.notify_key_release()
def __window_opened_cb(self, screen, window): def __window_opened_cb(self, screen, window):
if window.get_window_type() == wnck.WINDOW_NORMAL: if window.get_window_type() == wnck.WINDOW_NORMAL:
activity_host = ActivityHost(self.get_model(), window) activity_host = ActivityHost(self.get_model(), window)
self._hosts[activity_host.get_xid()] = activity_host self._hosts[activity_host.get_xid()] = activity_host
self.emit('activity-opened', activity_host) self.emit('activity-opened', activity_host)
def __active_window_changed_cb(self, screen): def __active_window_changed_cb(self, screen):
window = screen.get_active_window() window = screen.get_active_window()
if not window or window.get_window_type() != wnck.WINDOW_NORMAL: if not window or window.get_window_type() != wnck.WINDOW_NORMAL:
return return
if not self._hosts.has_key(window.get_xid()): if not self._hosts.has_key(window.get_xid()):
return return
activity_host = self._hosts[window.get_xid()] activity_host = self._hosts[window.get_xid()]
current = self._model.get_current_activity() current = self._model.get_current_activity()
if activity_host.get_id() == current: if activity_host.get_id() == current:
return return
self._set_current_activity(activity_host) self._set_current_activity(activity_host)
def __window_closed_cb(self, screen, window): def __window_closed_cb(self, screen, window):
if window.get_window_type() != wnck.WINDOW_NORMAL: if window.get_window_type() != wnck.WINDOW_NORMAL:
return return
if not self._hosts.has_key(window.get_xid()): if not self._hosts.has_key(window.get_xid()):
return return
host = self._hosts[window.get_xid()] host = self._hosts[window.get_xid()]
host.destroy() host.destroy()
self.emit('activity-closed', host) self.emit('activity-closed', host)
del self._hosts[window.get_xid()] del self._hosts[window.get_xid()]
if len(self._hosts) == 0: if len(self._hosts) == 0:
self._set_current_activity(None) self._set_current_activity(None)
def _set_current_activity(self, host): def _set_current_activity(self, host):
if host: if host:
self._model.set_current_activity(host.get_id()) self._model.set_current_activity(host.get_id())
else: else:
self._model.set_current_activity(None) self._model.set_current_activity(None)
if self._current_host: if self._current_host:
self._current_host.set_active(False) self._current_host.set_active(False)
self._current_host = host self._current_host = host
if self._current_host: if self._current_host:
self._current_host.set_active(True) self._current_host.set_active(True)
self.emit('activity-changed', host) self.emit('activity-changed', host)
def get_model(self): def get_model(self):
return self._model return self._model
def join_activity(self, bundle_id, activity_id): def join_activity(self, bundle_id, activity_id):
pservice = PresenceService.get_instance() pservice = PresenceService.get_instance()
activity = self._get_activity(activity_id) activity = self._get_activity(activity_id)
if activity: if activity:
activity.present() activity.present()
else: else:
activity_ps = pservice.get_activity(activity_id) activity_ps = pservice.get_activity(activity_id)
if activity_ps: if activity_ps:
activity = ActivityFactory.create(bundle_id) activity = ActivityFactory.create(bundle_id)
activity.join(activity_ps.object_path()) activity.join(activity_ps.object_path())
else: else:
logging.error('Cannot start activity.') logging.error('Cannot start activity.')
def start_activity(self, activity_type): def start_activity(self, activity_type):
activity = ActivityFactory.create(activity_type) activity = ActivityFactory.create(activity_type)
activity.execute('test', []) activity.execute('test', [])
return activity return activity
def set_zoom_level(self, level): def set_zoom_level(self, level):
if level == sugar.ZOOM_ACTIVITY: if level == sugar.ZOOM_ACTIVITY:
self._screen.toggle_showing_desktop(False) self._screen.toggle_showing_desktop(False)
else: else:
self._screen.toggle_showing_desktop(True) self._screen.toggle_showing_desktop(True)
self._home_window.set_zoom_level(level) self._home_window.set_zoom_level(level)
def get_current_activity(self): def get_current_activity(self):
activity_id = self._model.get_current_activity() activity_id = self._model.get_current_activity()
if activity_id: if activity_id:
return self._get_activity(activity_id) return self._get_activity(activity_id)
else: else:
return None return None
def _get_activity(self, activity_id): def _get_activity(self, activity_id):
for host in self._hosts.values(): for host in self._hosts.values():
if host.get_id() == activity_id: if host.get_id() == activity_id:
return host return host
return None return None
def toggle_chat_visibility(self): def toggle_chat_visibility(self):
act = self.get_current_activity() act = self.get_current_activity()
if not act: if not act:
return return
is_visible = self._frame.is_visible() is_visible = self._frame.is_visible()
if act.is_chat_visible(): if act.is_chat_visible():
frame_was_visible = act.chat_hide() frame_was_visible = act.chat_hide()
if not frame_was_visible: if not frame_was_visible:
self._frame.do_slide_out() self._frame.do_slide_out()
else: else:
if not is_visible: if not is_visible:
self._frame.do_slide_in() self._frame.do_slide_in()
act.chat_show(is_visible) act.chat_show(is_visible)

View File

@ -21,23 +21,23 @@ DCON_MANAGER_SERVICE = 'org.laptop.DCONManager'
DCON_MANAGER_OBJECT_PATH = '/org/laptop/DCONManager' DCON_MANAGER_OBJECT_PATH = '/org/laptop/DCONManager'
class DCONManager(object): class DCONManager(object):
COLOR_MODE = 0 COLOR_MODE = 0
BLACK_AND_WHITE_MODE = 1 BLACK_AND_WHITE_MODE = 1
def __init__(self): def __init__(self):
bus = dbus.SystemBus() bus = dbus.SystemBus()
proxy = bus.get_object(DCON_MANAGER_SERVICE, DCON_MANAGER_OBJECT_PATH) proxy = bus.get_object(DCON_MANAGER_SERVICE, DCON_MANAGER_OBJECT_PATH)
self._service = dbus.Interface(proxy, DCON_MANAGER_INTERFACE) self._service = dbus.Interface(proxy, DCON_MANAGER_INTERFACE)
def set_mode(self, mode): def set_mode(self, mode):
self._service.set_mode(mode) self._service.set_mode(mode)
def increase_brightness(self): def increase_brightness(self):
level = self._service.get_backlight_level() level = self._service.get_backlight_level()
if level >= 0: if level >= 0:
self._service.set_backlight_level(level + 1) self._service.set_backlight_level(level + 1)
def decrease_brightness(self): def decrease_brightness(self):
level = self._service.get_backlight_level() level = self._service.get_backlight_level()
if level >= 0: if level >= 0:
self._service.set_backlight_level(level - 1) self._service.set_backlight_level(level - 1)

View File

@ -22,80 +22,80 @@ from sugar.presence import PresenceService
from sugar.graphics import style from sugar.graphics import style
class ActivityItem(CanvasIcon): class ActivityItem(CanvasIcon):
def __init__(self, activity): def __init__(self, activity):
icon_name = activity.get_icon() icon_name = activity.get_icon()
CanvasIcon.__init__(self, icon_name=icon_name) CanvasIcon.__init__(self, icon_name=icon_name)
style.apply_stylesheet(self, 'frame.ActivityIcon') style.apply_stylesheet(self, 'frame.ActivityIcon')
self._activity = activity self._activity = activity
def get_bundle_id(self): def get_bundle_id(self):
return self._activity.get_service_name() return self._activity.get_service_name()
class InviteItem(CanvasIcon): class InviteItem(CanvasIcon):
def __init__(self, activity, invite): def __init__(self, activity, invite):
CanvasIcon.__init__(self, icon_name=activity.get_icon()) CanvasIcon.__init__(self, icon_name=activity.get_icon())
style.apply_stylesheet(self, 'frame.ActivityIcon') style.apply_stylesheet(self, 'frame.ActivityIcon')
self.props.color = activity.get_color() self.props.color = activity.get_color()
self._invite = invite self._invite = invite
def get_activity_id(self): def get_activity_id(self):
return self._invite.get_activity_id() return self._invite.get_activity_id()
def get_bundle_id(self): def get_bundle_id(self):
return self._invite.get_bundle_id() return self._invite.get_bundle_id()
def get_invite(self): def get_invite(self):
return self._invite return self._invite
class ActivitiesBox(hippo.CanvasBox): class ActivitiesBox(hippo.CanvasBox):
def __init__(self, shell): def __init__(self, shell):
hippo.CanvasBox.__init__(self, orientation=hippo.ORIENTATION_HORIZONTAL) hippo.CanvasBox.__init__(self, orientation=hippo.ORIENTATION_HORIZONTAL)
self._shell = shell self._shell = shell
self._shell_model = self._shell.get_model() self._shell_model = self._shell.get_model()
self._invite_to_item = {} self._invite_to_item = {}
self._invites = self._shell_model.get_invites() self._invites = self._shell_model.get_invites()
for bundle in self._shell_model.get_bundle_registry(): for bundle in self._shell_model.get_bundle_registry():
if bundle.get_show_launcher(): if bundle.get_show_launcher():
self.add_activity(bundle) self.add_activity(bundle)
for invite in self._invites: for invite in self._invites:
self.add_invite(invite) self.add_invite(invite)
self._invites.connect('invite-added', self._invite_added_cb) self._invites.connect('invite-added', self._invite_added_cb)
self._invites.connect('invite-removed', self._invite_removed_cb) self._invites.connect('invite-removed', self._invite_removed_cb)
def _activity_clicked_cb(self, icon): def _activity_clicked_cb(self, icon):
self._shell.start_activity(icon.get_bundle_id()) self._shell.start_activity(icon.get_bundle_id())
def _invite_clicked_cb(self, icon): def _invite_clicked_cb(self, icon):
self._invites.remove_invite(icon.get_invite()) self._invites.remove_invite(icon.get_invite())
self._shell.join_activity(icon.get_bundle_id(), self._shell.join_activity(icon.get_bundle_id(),
icon.get_activity_id()) icon.get_activity_id())
def _invite_added_cb(self, invites, invite): def _invite_added_cb(self, invites, invite):
self.add_invite(invite) self.add_invite(invite)
def _invite_removed_cb(self, invites, invite): def _invite_removed_cb(self, invites, invite):
self.remove_invite(invite) self.remove_invite(invite)
def add_activity(self, activity): def add_activity(self, activity):
item = ActivityItem(activity) item = ActivityItem(activity)
item.connect('activated', self._activity_clicked_cb) item.connect('activated', self._activity_clicked_cb)
self.append(item, 0) self.append(item, 0)
def add_invite(self, invite): def add_invite(self, invite):
mesh = self._shell_model.get_mesh() mesh = self._shell_model.get_mesh()
activity = mesh.get_activity(invite.get_activity_id()) activity = mesh.get_activity(invite.get_activity_id())
if activity: if activity:
item = InviteItem(activity, invite) item = InviteItem(activity, invite)
item.connect('activated', self._invite_clicked_cb) item.connect('activated', self._invite_clicked_cb)
self.append(item, 0) self.append(item, 0)
self._invite_to_item[invite] = item self._invite_to_item[invite] = item
def remove_invite(self, invite): def remove_invite(self, invite):
self.remove(self._invite_to_item[invite]) self.remove(self._invite_to_item[invite])
del self._invite_to_item[invite] del self._invite_to_item[invite]

View File

@ -7,36 +7,36 @@ from view.ClipboardIcon import ClipboardIcon
from sugar.clipboard import ClipboardService from sugar.clipboard import ClipboardService
class ClipboardBox(hippo.CanvasBox): class ClipboardBox(hippo.CanvasBox):
def __init__(self, frame, menu_shell): def __init__(self, frame, menu_shell):
hippo.CanvasBox.__init__(self) hippo.CanvasBox.__init__(self)
self._frame = frame self._frame = frame
self._menu_shell = menu_shell self._menu_shell = menu_shell
self._icons = {} self._icons = {}
cb_service = ClipboardService.get_instance() cb_service = ClipboardService.get_instance()
cb_service.connect('object-added', self._object_added_cb) cb_service.connect('object-added', self._object_added_cb)
cb_service.connect('object-deleted', self._object_deleted_cb) cb_service.connect('object-deleted', self._object_deleted_cb)
cb_service.connect('object-state-changed', self._object_state_changed_cb) cb_service.connect('object-state-changed', self._object_state_changed_cb)
def _object_added_cb(self, cb_service, name, mimeType, fileName): def _object_added_cb(self, cb_service, name, mimeType, fileName):
icon = ClipboardIcon(self._menu_shell, name, fileName) icon = ClipboardIcon(self._menu_shell, name, fileName)
style.apply_stylesheet(icon, 'frame.BuddyIcon') style.apply_stylesheet(icon, 'frame.BuddyIcon')
self.append(icon) self.append(icon)
self._icons[fileName] = icon self._icons[fileName] = icon
if not self._frame.is_visible(): if not self._frame.is_visible():
self._frame.show_and_hide(0.1) self._frame.show_and_hide(0.1)
logging.debug('ClipboardBox: ' + fileName + ' was added.') logging.debug('ClipboardBox: ' + fileName + ' was added.')
def _object_deleted_cb(self, cb_service, fileName): def _object_deleted_cb(self, cb_service, fileName):
icon = self._icons[fileName] icon = self._icons[fileName]
self.remove(icon) self.remove(icon)
del self._icons[fileName] del self._icons[fileName]
logging.debug('ClipboardBox: ' + fileName + ' was deleted.') logging.debug('ClipboardBox: ' + fileName + ' was deleted.')
def _object_state_changed_cb(self, cb_service, fileName, percent): def _object_state_changed_cb(self, cb_service, fileName, percent):
icon = self._icons[fileName] icon = self._icons[fileName]
icon.set_percent(percent) icon.set_percent(percent)
logging.debug('ClipboardBox: ' + fileName + ' state was changed.') logging.debug('ClipboardBox: ' + fileName + ' state was changed.')

View File

@ -32,268 +32,268 @@ from sugar.graphics.grid import Grid
from sugar.graphics.menushell import MenuShell from sugar.graphics.menushell import MenuShell
class EventFrame(gobject.GObject): class EventFrame(gobject.GObject):
__gsignals__ = { __gsignals__ = {
'enter-edge': (gobject.SIGNAL_RUN_FIRST, 'enter-edge': (gobject.SIGNAL_RUN_FIRST,
gobject.TYPE_NONE, ([])), gobject.TYPE_NONE, ([])),
'enter-corner': (gobject.SIGNAL_RUN_FIRST, 'enter-corner': (gobject.SIGNAL_RUN_FIRST,
gobject.TYPE_NONE, ([])), gobject.TYPE_NONE, ([])),
'leave': (gobject.SIGNAL_RUN_FIRST, 'leave': (gobject.SIGNAL_RUN_FIRST,
gobject.TYPE_NONE, ([])) gobject.TYPE_NONE, ([]))
} }
HOVER_NONE = 0 HOVER_NONE = 0
HOVER_CORNER = 1 HOVER_CORNER = 1
HOVER_EDGE = 2 HOVER_EDGE = 2
def __init__(self): def __init__(self):
gobject.GObject.__init__(self) gobject.GObject.__init__(self)
self._windows = [] self._windows = []
self._hover = EventFrame.HOVER_NONE self._hover = EventFrame.HOVER_NONE
self._active = False self._active = False
invisible = self._create_invisible(0, 0, gtk.gdk.screen_width(), 1) invisible = self._create_invisible(0, 0, gtk.gdk.screen_width(), 1)
self._windows.append(invisible) self._windows.append(invisible)
invisible = self._create_invisible(0, 0, 1, gtk.gdk.screen_height()) invisible = self._create_invisible(0, 0, 1, gtk.gdk.screen_height())
self._windows.append(invisible) self._windows.append(invisible)
invisible = self._create_invisible(gtk.gdk.screen_width() - 1, 0, invisible = self._create_invisible(gtk.gdk.screen_width() - 1, 0,
gtk.gdk.screen_width(), gtk.gdk.screen_width(),
gtk.gdk.screen_height()) gtk.gdk.screen_height())
self._windows.append(invisible) self._windows.append(invisible)
invisible = self._create_invisible(0, gtk.gdk.screen_height() - 1, invisible = self._create_invisible(0, gtk.gdk.screen_height() - 1,
gtk.gdk.screen_width(), gtk.gdk.screen_width(),
gtk.gdk.screen_height()) gtk.gdk.screen_height())
self._windows.append(invisible) self._windows.append(invisible)
screen = wnck.screen_get_default() screen = wnck.screen_get_default()
screen.connect('active-window-changed', screen.connect('active-window-changed',
self._active_window_changed_cb) self._active_window_changed_cb)
def _create_invisible(self, x, y, width, height): def _create_invisible(self, x, y, width, height):
invisible = gtk.Invisible() invisible = gtk.Invisible()
invisible.connect('motion-notify-event', self._motion_notify_cb) invisible.connect('motion-notify-event', self._motion_notify_cb)
invisible.connect('enter-notify-event', self._enter_notify_cb) invisible.connect('enter-notify-event', self._enter_notify_cb)
invisible.connect('leave-notify-event', self._leave_notify_cb) invisible.connect('leave-notify-event', self._leave_notify_cb)
invisible.realize() invisible.realize()
invisible.window.set_events(gtk.gdk.POINTER_MOTION_MASK | invisible.window.set_events(gtk.gdk.POINTER_MOTION_MASK |
gtk.gdk.ENTER_NOTIFY_MASK | gtk.gdk.ENTER_NOTIFY_MASK |
gtk.gdk.LEAVE_NOTIFY_MASK) gtk.gdk.LEAVE_NOTIFY_MASK)
invisible.window.move_resize(x, y, width, height) invisible.window.move_resize(x, y, width, height)
return invisible return invisible
def _enter_notify_cb(self, widget, event): def _enter_notify_cb(self, widget, event):
self._notify_enter(event.x, event.y) self._notify_enter(event.x, event.y)
def _motion_notify_cb(self, widget, event): def _motion_notify_cb(self, widget, event):
self._notify_enter(event.x, event.y) self._notify_enter(event.x, event.y)
def _notify_enter(self, x, y): def _notify_enter(self, x, y):
screen_w = gtk.gdk.screen_width() screen_w = gtk.gdk.screen_width()
screen_h = gtk.gdk.screen_height() screen_h = gtk.gdk.screen_height()
if (x == 0 and y == 0) or \ if (x == 0 and y == 0) or \
(x == 0 and y == screen_h - 1) or \ (x == 0 and y == screen_h - 1) or \
(x == screen_w - 1 and y == 0) or \ (x == screen_w - 1 and y == 0) or \
(x == screen_w - 1 and y == screen_h - 1): (x == screen_w - 1 and y == screen_h - 1):
if self._hover != EventFrame.HOVER_CORNER: if self._hover != EventFrame.HOVER_CORNER:
self._hover = EventFrame.HOVER_CORNER self._hover = EventFrame.HOVER_CORNER
self.emit('enter-corner') self.emit('enter-corner')
else: else:
if self._hover != EventFrame.HOVER_EDGE: if self._hover != EventFrame.HOVER_EDGE:
self._hover = EventFrame.HOVER_EDGE self._hover = EventFrame.HOVER_EDGE
self.emit('enter-edge') self.emit('enter-edge')
def _leave_notify_cb(self, widget, event): def _leave_notify_cb(self, widget, event):
self._hover = EventFrame.HOVER_NONE self._hover = EventFrame.HOVER_NONE
if self._active: if self._active:
self.emit('leave') self.emit('leave')
def show(self): def show(self):
self._active = True self._active = True
for window in self._windows: for window in self._windows:
window.show() window.show()
def hide(self): def hide(self):
self._active = False self._active = False
for window in self._windows: for window in self._windows:
window.hide() window.hide()
def _active_window_changed_cb(self, screen): def _active_window_changed_cb(self, screen):
for window in self._windows: for window in self._windows:
window.window.raise_() window.window.raise_()
class Frame: class Frame:
INACTIVE = 0 INACTIVE = 0
TEMPORARY = 1 TEMPORARY = 1
STICKY = 2 STICKY = 2
HIDE_ON_LEAVE = 3 HIDE_ON_LEAVE = 3
AUTOMATIC = 4 AUTOMATIC = 4
def __init__(self, shell): def __init__(self, shell):
self._windows = [] self._windows = []
self._active_menus = 0 self._active_menus = 0
self._shell = shell self._shell = shell
self._mode = Frame.INACTIVE self._mode = Frame.INACTIVE
self._timeline = Timeline(self) self._timeline = Timeline(self)
self._timeline.add_tag('slide_in', 6, 12) self._timeline.add_tag('slide_in', 6, 12)
self._timeline.add_tag('before_slide_out', 36, 36) self._timeline.add_tag('before_slide_out', 36, 36)
self._timeline.add_tag('slide_out', 37, 42) self._timeline.add_tag('slide_out', 37, 42)
self._event_frame = EventFrame() self._event_frame = EventFrame()
self._event_frame.connect('enter-edge', self._enter_edge_cb) self._event_frame.connect('enter-edge', self._enter_edge_cb)
self._event_frame.connect('enter-corner', self._enter_corner_cb) self._event_frame.connect('enter-corner', self._enter_corner_cb)
self._event_frame.connect('leave', self._event_frame_leave_cb) self._event_frame.connect('leave', self._event_frame_leave_cb)
self._event_frame.show() self._event_frame.show()
grid = Grid() grid = Grid()
# Top panel # Top panel
[menu_shell, root] = self._create_panel(grid, 0, 0, 16, 1) [menu_shell, root] = self._create_panel(grid, 0, 0, 16, 1)
menu_shell.set_position(MenuShell.BOTTOM) menu_shell.set_position(MenuShell.BOTTOM)
box = ZoomBox(self._shell, menu_shell) box = ZoomBox(self._shell, menu_shell)
[x, y] = grid.point(1, 0) [x, y] = grid.point(1, 0)
root.append(box, hippo.PACK_FIXED) root.append(box, hippo.PACK_FIXED)
root.move(box, x, y) root.move(box, x, y)
tray = NotificationTray() tray = NotificationTray()
tray_box = hippo.CanvasBox(box_width=grid.dimension(1), tray_box = hippo.CanvasBox(box_width=grid.dimension(1),
box_height=grid.dimension(1), box_height=grid.dimension(1),
xalign=hippo.ALIGNMENT_END) xalign=hippo.ALIGNMENT_END)
tray_widget = hippo.CanvasWidget() tray_widget = hippo.CanvasWidget()
tray_widget.props.widget = tray tray_widget.props.widget = tray
tray_box.append(tray_widget, gtk.EXPAND) tray_box.append(tray_widget, gtk.EXPAND)
[x, y] = grid.point(13, 0) [x, y] = grid.point(13, 0)
root.append(tray_box, hippo.PACK_FIXED) root.append(tray_box, hippo.PACK_FIXED)
root.move(tray_box, x, y) root.move(tray_box, x, y)
box = OverlayBox(self._shell) box = OverlayBox(self._shell)
[x, y] = grid.point(14, 0) [x, y] = grid.point(14, 0)
root.append(box, hippo.PACK_FIXED) root.append(box, hippo.PACK_FIXED)
root.move(box, x, y) root.move(box, x, y)
shutdown_icon = ShutdownIcon(menu_shell) shutdown_icon = ShutdownIcon(menu_shell)
[x, y] = grid.point(12, 0) [x, y] = grid.point(12, 0)
root.append(shutdown_icon, hippo.PACK_FIXED) root.append(shutdown_icon, hippo.PACK_FIXED)
root.move(shutdown_icon, x, y) root.move(shutdown_icon, x, y)
# Bottom panel # Bottom panel
[menu_shell, root] = self._create_panel(grid, 0, 11, 16, 1) [menu_shell, root] = self._create_panel(grid, 0, 11, 16, 1)
menu_shell.set_position(MenuShell.TOP) menu_shell.set_position(MenuShell.TOP)
box = ActivitiesBox(self._shell) box = ActivitiesBox(self._shell)
root.append(box, hippo.PACK_FIXED) root.append(box, hippo.PACK_FIXED)
[x, y] = grid.point(1, 0) [x, y] = grid.point(1, 0)
root.move(box, x, y) root.move(box, x, y)
# Right panel # Right panel
[menu_shell, root] = self._create_panel(grid, 15, 1, 1, 10) [menu_shell, root] = self._create_panel(grid, 15, 1, 1, 10)
menu_shell.set_position(MenuShell.LEFT) menu_shell.set_position(MenuShell.LEFT)
box = FriendsBox(self._shell, menu_shell) box = FriendsBox(self._shell, menu_shell)
root.append(box) root.append(box)
# Left panel # Left panel
[menu_shell, root] = self._create_panel(grid, 0, 1, 1, 10) [menu_shell, root] = self._create_panel(grid, 0, 1, 1, 10)
box = ClipboardBox(self, menu_shell) box = ClipboardBox(self, menu_shell)
root.append(box) root.append(box)
def _create_panel(self, grid, x, y, width, height): def _create_panel(self, grid, x, y, width, height):
panel = PanelWindow() panel = PanelWindow()
panel.connect('enter-notify-event', self._enter_notify_cb) panel.connect('enter-notify-event', self._enter_notify_cb)
panel.connect('leave-notify-event', self._leave_notify_cb) panel.connect('leave-notify-event', self._leave_notify_cb)
menu_shell = panel.get_menu_shell() menu_shell = panel.get_menu_shell()
menu_shell.connect('activated', self._menu_shell_activated_cb) menu_shell.connect('activated', self._menu_shell_activated_cb)
menu_shell.connect('deactivated', self._menu_shell_deactivated_cb) menu_shell.connect('deactivated', self._menu_shell_deactivated_cb)
[x, y, width, height] = grid.rectangle(x, y, width, height) [x, y, width, height] = grid.rectangle(x, y, width, height)
panel.move(x, y) panel.move(x, y)
panel.resize(width, height) panel.resize(width, height)
self._windows.append(panel) self._windows.append(panel)
return [panel.get_menu_shell(), panel.get_root()] return [panel.get_menu_shell(), panel.get_root()]
def _menu_shell_activated_cb(self, menu_shell): def _menu_shell_activated_cb(self, menu_shell):
self._active_menus += 1 self._active_menus += 1
self._timeline.goto('slide_in', True) self._timeline.goto('slide_in', True)
def _menu_shell_deactivated_cb(self, menu_shell): def _menu_shell_deactivated_cb(self, menu_shell):
self._active_menus -= 1 self._active_menus -= 1
if self._mode != Frame.STICKY: if self._mode != Frame.STICKY:
self._timeline.play('before_slide_out', 'slide_out') self._timeline.play('before_slide_out', 'slide_out')
def _enter_notify_cb(self, window, event): def _enter_notify_cb(self, window, event):
self._timeline.goto('slide_in', True) self._timeline.goto('slide_in', True)
def _leave_notify_cb(self, window, event): def _leave_notify_cb(self, window, event):
# FIXME for some reason every click cause also a leave-notify # FIXME for some reason every click cause also a leave-notify
if event.state == gtk.gdk.BUTTON1_MASK: if event.state == gtk.gdk.BUTTON1_MASK:
return return
if self._active_menus == 0 and \ if self._active_menus == 0 and \
(self._mode == Frame.HIDE_ON_LEAVE or \ (self._mode == Frame.HIDE_ON_LEAVE or \
self._mode == Frame.AUTOMATIC): self._mode == Frame.AUTOMATIC):
self._timeline.play('before_slide_out', 'slide_out') self._timeline.play('before_slide_out', 'slide_out')
def _enter_edge_cb(self, event_frame): def _enter_edge_cb(self, event_frame):
self._mode = Frame.HIDE_ON_LEAVE self._mode = Frame.HIDE_ON_LEAVE
self._timeline.play(None, 'slide_in') self._timeline.play(None, 'slide_in')
def _enter_corner_cb(self, event_frame): def _enter_corner_cb(self, event_frame):
self._mode = Frame.HIDE_ON_LEAVE self._mode = Frame.HIDE_ON_LEAVE
self._timeline.play('slide_in', 'slide_in') self._timeline.play('slide_in', 'slide_in')
def _event_frame_leave_cb(self, event_frame): def _event_frame_leave_cb(self, event_frame):
if self._mode != Frame.STICKY: if self._mode != Frame.STICKY:
self._timeline.goto('slide_out', True) self._timeline.goto('slide_out', True)
def show_and_hide(self, seconds): def show_and_hide(self, seconds):
self._mode = Frame.AUTOMATIC self._mode = Frame.AUTOMATIC
self._timeline.play() self._timeline.play()
def notify_key_press(self): def notify_key_press(self):
if self._timeline.on_tag('slide_in'): if self._timeline.on_tag('slide_in'):
self._timeline.play('before_slide_out', 'slide_out') self._timeline.play('before_slide_out', 'slide_out')
elif self._timeline.on_tag('before_slide_out'): elif self._timeline.on_tag('before_slide_out'):
self._mode = Frame.TEMPORARY self._mode = Frame.TEMPORARY
else: else:
self._mode = Frame.STICKY self._mode = Frame.STICKY
self._timeline.play('slide_in', 'slide_in') self._timeline.play('slide_in', 'slide_in')
def notify_key_release(self): def notify_key_release(self):
if self._mode == Frame.TEMPORARY: if self._mode == Frame.TEMPORARY:
self._timeline.play('before_slide_out', 'slide_out') self._timeline.play('before_slide_out', 'slide_out')
def do_slide_in(self, current=0, n_frames=0): def do_slide_in(self, current=0, n_frames=0):
if not self._windows[0].props.visible: if not self._windows[0].props.visible:
for panel in self._windows: for panel in self._windows:
panel.show() panel.show()
self._event_frame.hide() self._event_frame.hide()
def do_slide_out(self, current=0, n_frames=0): def do_slide_out(self, current=0, n_frames=0):
if self._windows[0].props.visible: if self._windows[0].props.visible:
for panel in self._windows: for panel in self._windows:
panel.hide() panel.hide()
self._event_frame.show() self._event_frame.show()
def is_visible(self): def is_visible(self):
if self._windows[0].props.visible: if self._windows[0].props.visible:
return True return True
return False return False

View File

@ -24,85 +24,85 @@ from view.BuddyIcon import BuddyIcon
from model.BuddyModel import BuddyModel from model.BuddyModel import BuddyModel
class FriendsBox(hippo.CanvasBox): class FriendsBox(hippo.CanvasBox):
def __init__(self, shell, menu_shell): def __init__(self, shell, menu_shell):
hippo.CanvasBox.__init__(self) hippo.CanvasBox.__init__(self)
self._shell = shell self._shell = shell
self._menu_shell = menu_shell self._menu_shell = menu_shell
self._activity_ps = None self._activity_ps = None
self._joined_hid = -1 self._joined_hid = -1
self._left_hid = -1 self._left_hid = -1
self._buddies = {} self._buddies = {}
self._pservice = PresenceService.get_instance() self._pservice = PresenceService.get_instance()
self._pservice.connect('activity-appeared', self._pservice.connect('activity-appeared',
self.__activity_appeared_cb) self.__activity_appeared_cb)
# Add initial activities the PS knows about # Add initial activities the PS knows about
for activity in self._pservice.get_activities(): for activity in self._pservice.get_activities():
self.__activity_appeared_cb(self._pservice, activity) self.__activity_appeared_cb(self._pservice, activity)
shell.connect('activity-changed', self.__activity_changed_cb) shell.connect('activity-changed', self.__activity_changed_cb)
def add_buddy(self, buddy): def add_buddy(self, buddy):
if self._buddies.has_key(buddy.get_name()): if self._buddies.has_key(buddy.get_name()):
return return
model = BuddyModel(buddy=buddy) model = BuddyModel(buddy=buddy)
icon = BuddyIcon(self._shell, self._menu_shell, model) icon = BuddyIcon(self._shell, self._menu_shell, model)
style.apply_stylesheet(icon, 'frame.BuddyIcon') style.apply_stylesheet(icon, 'frame.BuddyIcon')
self.append(icon) self.append(icon)
self._buddies[buddy.get_name()] = icon self._buddies[buddy.get_name()] = icon
def remove_buddy(self, buddy): def remove_buddy(self, buddy):
if not self._buddies.has_key(buddy.get_name()): if not self._buddies.has_key(buddy.get_name()):
return return
self.remove(self._buddies[buddy.get_name()]) self.remove(self._buddies[buddy.get_name()])
def clear(self): def clear(self):
for item in self.get_children(): for item in self.get_children():
self.remove(item) self.remove(item)
self._buddies = {} self._buddies = {}
def __activity_appeared_cb(self, pservice, activity_ps): def __activity_appeared_cb(self, pservice, activity_ps):
activity = self._shell.get_current_activity() activity = self._shell.get_current_activity()
if activity and activity_ps.get_id() == activity.get_id(): if activity and activity_ps.get_id() == activity.get_id():
self._set_activity_ps(activity_ps) self._set_activity_ps(activity_ps)
def _set_activity_ps(self, activity_ps): def _set_activity_ps(self, activity_ps):
if self._activity_ps == activity_ps: if self._activity_ps == activity_ps:
return return
if self._joined_hid > 0: if self._joined_hid > 0:
self._activity_ps.disconnect(self._joined_hid) self._activity_ps.disconnect(self._joined_hid)
self._joined_hid = -1 self._joined_hid = -1
if self._left_hid > 0: if self._left_hid > 0:
self._activity_ps.disconnect(self._left_hid) self._activity_ps.disconnect(self._left_hid)
self._left_hid = -1 self._left_hid = -1
self._activity_ps = activity_ps self._activity_ps = activity_ps
self.clear() self.clear()
if activity_ps != None: if activity_ps != None:
for buddy in activity_ps.get_joined_buddies(): for buddy in activity_ps.get_joined_buddies():
self.add_buddy(buddy) self.add_buddy(buddy)
self._joined_hid = activity_ps.connect( self._joined_hid = activity_ps.connect(
'buddy-joined', self.__buddy_joined_cb) 'buddy-joined', self.__buddy_joined_cb)
self._left_hid = activity_ps.connect( self._left_hid = activity_ps.connect(
'buddy-left', self.__buddy_left_cb) 'buddy-left', self.__buddy_left_cb)
def __activity_changed_cb(self, group, activity): def __activity_changed_cb(self, group, activity):
if activity: if activity:
ps = self._pservice.get_activity(activity.get_id()) ps = self._pservice.get_activity(activity.get_id())
self._set_activity_ps(ps) self._set_activity_ps(ps)
else: else:
self._set_activity_ps(None) self._set_activity_ps(None)
def __buddy_joined_cb(self, activity, buddy): def __buddy_joined_cb(self, activity, buddy):
self.add_buddy(buddy) self.add_buddy(buddy)
def __buddy_left_cb(self, activity, buddy): def __buddy_left_cb(self, activity, buddy):
self.remove_buddy(buddy) self.remove_buddy(buddy)

View File

@ -20,28 +20,28 @@ import hippo
from sugar.graphics.menushell import MenuShell from sugar.graphics.menushell import MenuShell
class PanelWindow(gtk.Window): class PanelWindow(gtk.Window):
def __init__(self): def __init__(self):
gtk.Window.__init__(self) gtk.Window.__init__(self)
self.set_decorated(False) self.set_decorated(False)
self.connect('realize', self._realize_cb) self.connect('realize', self._realize_cb)
canvas = hippo.Canvas() canvas = hippo.Canvas()
self._bg = hippo.CanvasBox(background_color=0x414141ff) self._bg = hippo.CanvasBox(background_color=0x414141ff)
canvas.set_root(self._bg) canvas.set_root(self._bg)
self.add(canvas) self.add(canvas)
canvas.show() canvas.show()
self._menu_shell = MenuShell(canvas) self._menu_shell = MenuShell(canvas)
def get_menu_shell(self): def get_menu_shell(self):
return self._menu_shell return self._menu_shell
def get_root(self): def get_root(self):
return self._bg return self._bg
def _realize_cb(self, widget): def _realize_cb(self, widget):
self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG) self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
self.window.set_accept_focus(False) self.window.set_accept_focus(False)

View File

@ -23,98 +23,98 @@ from sugar.graphics import style
import sugar import sugar
class ActivityMenu(Menu): class ActivityMenu(Menu):
ACTION_SHARE = 1 ACTION_SHARE = 1
ACTION_CLOSE = 2 ACTION_CLOSE = 2
def __init__(self, activity_host): def __init__(self, activity_host):
Menu.__init__(self, activity_host.get_title()) Menu.__init__(self, activity_host.get_title())
if not activity_host.get_shared(): if not activity_host.get_shared():
self._add_mesh_action() self._add_mesh_action()
self._add_close_action() self._add_close_action()
def _add_mesh_action(self): def _add_mesh_action(self):
icon = CanvasIcon(icon_name='stock-share-mesh') icon = CanvasIcon(icon_name='stock-share-mesh')
self.add_action(icon, ActivityMenu.ACTION_SHARE) self.add_action(icon, ActivityMenu.ACTION_SHARE)
def _add_close_action(self): def _add_close_action(self):
icon = CanvasIcon(icon_name='stock-close') icon = CanvasIcon(icon_name='stock-close')
self.add_action(icon, ActivityMenu.ACTION_CLOSE) self.add_action(icon, ActivityMenu.ACTION_CLOSE)
class ActivityIcon(MenuIcon): class ActivityIcon(MenuIcon):
def __init__(self, shell, menu_shell, activity_host): def __init__(self, shell, menu_shell, activity_host):
self._shell = shell self._shell = shell
self._activity_host = activity_host self._activity_host = activity_host
icon_name = activity_host.get_icon_name() icon_name = activity_host.get_icon_name()
icon_color = activity_host.get_icon_color() icon_color = activity_host.get_icon_color()
MenuIcon.__init__(self, menu_shell, icon_name=icon_name, MenuIcon.__init__(self, menu_shell, icon_name=icon_name,
color=icon_color) color=icon_color)
def create_menu(self): def create_menu(self):
menu = ActivityMenu(self._activity_host) menu = ActivityMenu(self._activity_host)
menu.connect('action', self._action_cb) menu.connect('action', self._action_cb)
return menu return menu
def _action_cb(self, menu, action): def _action_cb(self, menu, action):
self.popdown() self.popdown()
activity = self._shell.get_current_activity() activity = self._shell.get_current_activity()
if activity == None: if activity == None:
return return
if action == ActivityMenu.ACTION_SHARE: if action == ActivityMenu.ACTION_SHARE:
activity.share() activity.share()
if action == ActivityMenu.ACTION_CLOSE: if action == ActivityMenu.ACTION_CLOSE:
activity.close() activity.close()
class ZoomBox(hippo.CanvasBox): class ZoomBox(hippo.CanvasBox):
def __init__(self, shell, menu_shell): def __init__(self, shell, menu_shell):
hippo.CanvasBox.__init__(self, orientation=hippo.ORIENTATION_HORIZONTAL) hippo.CanvasBox.__init__(self, orientation=hippo.ORIENTATION_HORIZONTAL)
self._shell = shell self._shell = shell
self._menu_shell = menu_shell self._menu_shell = menu_shell
self._activity_icon = None self._activity_icon = None
icon = CanvasIcon(icon_name='stock-zoom-mesh') icon = CanvasIcon(icon_name='stock-zoom-mesh')
style.apply_stylesheet(icon, 'frame.ZoomIcon') style.apply_stylesheet(icon, 'frame.ZoomIcon')
icon.connect('activated', self._level_clicked_cb, sugar.ZOOM_MESH) icon.connect('activated', self._level_clicked_cb, sugar.ZOOM_MESH)
self.append(icon) self.append(icon)
icon = CanvasIcon(icon_name='stock-zoom-friends') icon = CanvasIcon(icon_name='stock-zoom-friends')
style.apply_stylesheet(icon, 'frame.ZoomIcon') style.apply_stylesheet(icon, 'frame.ZoomIcon')
icon.connect('activated', self._level_clicked_cb, sugar.ZOOM_FRIENDS) icon.connect('activated', self._level_clicked_cb, sugar.ZOOM_FRIENDS)
self.append(icon) self.append(icon)
icon = CanvasIcon(icon_name='stock-zoom-home') icon = CanvasIcon(icon_name='stock-zoom-home')
style.apply_stylesheet(icon, 'frame.ZoomIcon') style.apply_stylesheet(icon, 'frame.ZoomIcon')
icon.connect('activated', self._level_clicked_cb, sugar.ZOOM_HOME) icon.connect('activated', self._level_clicked_cb, sugar.ZOOM_HOME)
self.append(icon) self.append(icon)
icon = CanvasIcon(icon_name='stock-zoom-activity') icon = CanvasIcon(icon_name='stock-zoom-activity')
style.apply_stylesheet(icon, 'frame.ZoomIcon') style.apply_stylesheet(icon, 'frame.ZoomIcon')
icon.connect('activated', self._level_clicked_cb, sugar.ZOOM_ACTIVITY) icon.connect('activated', self._level_clicked_cb, sugar.ZOOM_ACTIVITY)
self.append(icon) self.append(icon)
shell.connect('activity-changed', self._activity_changed_cb) shell.connect('activity-changed', self._activity_changed_cb)
self._set_current_activity(shell.get_current_activity()) self._set_current_activity(shell.get_current_activity())
def _set_current_activity(self, activity): def _set_current_activity(self, activity):
if self._activity_icon: if self._activity_icon:
self.remove(self._activity_icon) self.remove(self._activity_icon)
if activity: if activity:
icon = ActivityIcon(self._shell, self._menu_shell, activity) icon = ActivityIcon(self._shell, self._menu_shell, activity)
style.apply_stylesheet(icon, 'frame.ZoomIcon') style.apply_stylesheet(icon, 'frame.ZoomIcon')
self.append(icon, 0) self.append(icon, 0)
self._activity_icon = icon self._activity_icon = icon
else: else:
self._activity_icon = None self._activity_icon = None
def _activity_changed_cb(self, shell_model, activity): def _activity_changed_cb(self, shell_model, activity):
self._set_current_activity(activity) self._set_current_activity(activity)
def _level_clicked_cb(self, item, level): def _level_clicked_cb(self, item, level):
self._shell.set_zoom_level(level) self._shell.set_zoom_level(level)

View File

@ -3,16 +3,16 @@ import gtk
from _sugar import TrayManager from _sugar import TrayManager
class NotificationTray(gtk.HBox): class NotificationTray(gtk.HBox):
def __init__(self): def __init__(self):
gtk.HBox.__init__(self) gtk.HBox.__init__(self)
self._manager = TrayManager() self._manager = TrayManager()
self._manager.connect('tray-icon-added', self._icon_added_cb) self._manager.connect('tray-icon-added', self._icon_added_cb)
self._manager.connect('tray-icon-removed', self._icon_removed_cb) self._manager.connect('tray-icon-removed', self._icon_removed_cb)
self._manager.manage_screen(gtk.gdk.screen_get_default()) self._manager.manage_screen(gtk.gdk.screen_get_default())
def _icon_added_cb(self, manager, icon): def _icon_added_cb(self, manager, icon):
self.pack_start(icon, False) self.pack_start(icon, False)
def _icon_removed_cb(self, manager, icon): def _icon_removed_cb(self, manager, icon):
icon.destroy() icon.destroy()

View File

@ -4,15 +4,15 @@ from sugar.graphics import style
from sugar.graphics.canvasicon import CanvasIcon from sugar.graphics.canvasicon import CanvasIcon
class OverlayBox(hippo.CanvasBox): class OverlayBox(hippo.CanvasBox):
def __init__(self, shell): def __init__(self, shell):
hippo.CanvasBox.__init__(self, orientation=hippo.ORIENTATION_HORIZONTAL) hippo.CanvasBox.__init__(self, orientation=hippo.ORIENTATION_HORIZONTAL)
self._shell = shell self._shell = shell
icon = CanvasIcon(icon_name='stock-chat') icon = CanvasIcon(icon_name='stock-chat')
style.apply_stylesheet(icon, 'frame.OverlayIcon') style.apply_stylesheet(icon, 'frame.OverlayIcon')
icon.connect('activated', self._overlay_clicked_cb) icon.connect('activated', self._overlay_clicked_cb)
self.append(icon) self.append(icon)
def _overlay_clicked_cb(self, item): def _overlay_clicked_cb(self, item):
self._shell.toggle_chat_visibility() self._shell.toggle_chat_visibility()

View File

@ -21,24 +21,24 @@ from sugar.graphics.menu import Menu
from sugar.graphics import style from sugar.graphics import style
class ShutdownIcon(MenuIcon): class ShutdownIcon(MenuIcon):
ACTION_SHUTDOWN = 2 ACTION_SHUTDOWN = 2
def __init__(self, menu_shell): def __init__(self, menu_shell):
MenuIcon.__init__(self, menu_shell, icon_name='stock-close') MenuIcon.__init__(self, menu_shell, icon_name='stock-close')
style.apply_stylesheet(self, 'menu.ActionIcon') style.apply_stylesheet(self, 'menu.ActionIcon')
def create_menu(self): def create_menu(self):
menu = Menu() menu = Menu()
menu.add_item('Shut Down', ShutdownIcon.ACTION_SHUTDOWN) menu.add_item('Shut Down', ShutdownIcon.ACTION_SHUTDOWN)
menu.connect('action', self._action_cb) menu.connect('action', self._action_cb)
return menu return menu
def _action_cb(self, menu, action): def _action_cb(self, menu, action):
self.popdown() self.popdown()
if action == ShutdownIcon.ACTION_SHUTDOWN: if action == ShutdownIcon.ACTION_SHUTDOWN:
bus = dbus.SystemBus() bus = dbus.SystemBus()
proxy = bus.get_object('org.freedesktop.Hal', proxy = bus.get_object('org.freedesktop.Hal',
'/org/freedesktop/Hal/devices/computer') '/org/freedesktop/Hal/devices/computer')
mgr = dbus.Interface(proxy, 'org.freedesktop.Hal.Device.SystemPowerManagement') mgr = dbus.Interface(proxy, 'org.freedesktop.Hal.Device.SystemPowerManagement')
mgr.Shutdown() mgr.Shutdown()

View File

@ -23,67 +23,67 @@ from sugar.graphics import style
from sugar.presence import PresenceService from sugar.presence import PresenceService
class FriendView(hippo.CanvasBox): class FriendView(hippo.CanvasBox):
def __init__(self, shell, menu_shell, buddy, **kwargs): def __init__(self, shell, menu_shell, buddy, **kwargs):
hippo.CanvasBox.__init__(self, **kwargs) hippo.CanvasBox.__init__(self, **kwargs)
self._pservice = PresenceService.get_instance() self._pservice = PresenceService.get_instance()
self._buddy = buddy self._buddy = buddy
self._buddy_icon = BuddyIcon(shell, menu_shell, buddy) self._buddy_icon = BuddyIcon(shell, menu_shell, buddy)
style.apply_stylesheet(self._buddy_icon, 'friends.FriendIcon') style.apply_stylesheet(self._buddy_icon, 'friends.FriendIcon')
self.append(self._buddy_icon) self.append(self._buddy_icon)
self._activity_icon = CanvasIcon() self._activity_icon = CanvasIcon()
style.apply_stylesheet(self._activity_icon, 'friends.ActivityIcon') style.apply_stylesheet(self._activity_icon, 'friends.ActivityIcon')
self._activity_icon_visible = False self._activity_icon_visible = False
if self._buddy.is_present(): if self._buddy.is_present():
self._buddy_appeared_cb(buddy) self._buddy_appeared_cb(buddy)
self._buddy.connect('current-activity-changed', self._buddy_activity_changed_cb) self._buddy.connect('current-activity-changed', self._buddy_activity_changed_cb)
self._buddy.connect('appeared', self._buddy_appeared_cb) self._buddy.connect('appeared', self._buddy_appeared_cb)
self._buddy.connect('disappeared', self._buddy_disappeared_cb) self._buddy.connect('disappeared', self._buddy_disappeared_cb)
self._buddy.connect('color-changed', self._buddy_color_changed_cb) self._buddy.connect('color-changed', self._buddy_color_changed_cb)
def _get_new_icon_name(self, activity): def _get_new_icon_name(self, activity):
# FIXME: do something better here; we probably need to use "flagship" # FIXME: do something better here; we probably need to use "flagship"
# services like mDNS where activities default services are marked # services like mDNS where activities default services are marked
# somehow. # somehow.
activity_registry = shell.get_model().get_bundle_registry() activity_registry = shell.get_model().get_bundle_registry()
for serv in activity.get_services(): for serv in activity.get_services():
bundle = activity_registry.get_bundle(serv.get_type()) bundle = activity_registry.get_bundle(serv.get_type())
if bundle: if bundle:
return bundle.get_icon() return bundle.get_icon()
return None return None
def _remove_activity_icon(self): def _remove_activity_icon(self):
if self._activity_icon_visible: if self._activity_icon_visible:
self.remove(self._activity_icon) self.remove(self._activity_icon)
self._activity_icon_visible = False self._activity_icon_visible = False
def _buddy_activity_changed_cb(self, buddy, activity=None): def _buddy_activity_changed_cb(self, buddy, activity=None):
if not activity: if not activity:
self._remove_activity_icon() self._remove_activity_icon()
return return
# FIXME: use some sort of "unknown activity" icon rather # FIXME: use some sort of "unknown activity" icon rather
# than hiding the icon? # than hiding the icon?
name = self._get_new_icon_name(activity) name = self._get_new_icon_name(activity)
if name: if name:
self._activity_icon.props.icon_name = name self._activity_icon.props.icon_name = name
self._activity_icon.props.color = buddy.get_color() self._activity_icon.props.color = buddy.get_color()
if not self._activity_icon_visible: if not self._activity_icon_visible:
self.append(self._activity_icon, hippo.PACK_EXPAND) self.append(self._activity_icon, hippo.PACK_EXPAND)
self._activity_icon_visible = True self._activity_icon_visible = True
else: else:
self._remove_activity_icon() self._remove_activity_icon()
def _buddy_appeared_cb(self, buddy): def _buddy_appeared_cb(self, buddy):
activity = self._buddy.get_current_activity() activity = self._buddy.get_current_activity()
self._buddy_activity_changed_cb(buddy, activity) self._buddy_activity_changed_cb(buddy, activity)
def _buddy_disappeared_cb(self, buddy): def _buddy_disappeared_cb(self, buddy):
self._buddy_activity_changed_cb(buddy, None) self._buddy_activity_changed_cb(buddy, None)
def _buddy_color_changed_cb(self, buddy, color): def _buddy_color_changed_cb(self, buddy, color):
self._activity_icon.props.color = buddy.get_color() self._activity_icon.props.color = buddy.get_color()

View File

@ -25,42 +25,42 @@ from view.home.MyIcon import MyIcon
from view.home.FriendView import FriendView from view.home.FriendView import FriendView
class FriendsBox(SpreadBox, hippo.CanvasItem): class FriendsBox(SpreadBox, hippo.CanvasItem):
__gtype_name__ = 'SugarFriendsBox' __gtype_name__ = 'SugarFriendsBox'
def __init__(self, shell, menu_shell): def __init__(self, shell, menu_shell):
SpreadBox.__init__(self, background_color=0xe2e2e2ff) SpreadBox.__init__(self, background_color=0xe2e2e2ff)
self._shell = shell self._shell = shell
self._menu_shell = menu_shell self._menu_shell = menu_shell
self._friends = {} self._friends = {}
self._my_icon = MyIcon() self._my_icon = MyIcon()
style.apply_stylesheet(self._my_icon, 'friends.MyIcon') style.apply_stylesheet(self._my_icon, 'friends.MyIcon')
self.append(self._my_icon, hippo.PACK_FIXED) self.append(self._my_icon, hippo.PACK_FIXED)
friends = self._shell.get_model().get_friends() friends = self._shell.get_model().get_friends()
for friend in friends: for friend in friends:
self.add_friend(friend) self.add_friend(friend)
friends.connect('friend-added', self._friend_added_cb) friends.connect('friend-added', self._friend_added_cb)
friends.connect('friend-removed', self._friend_removed_cb) friends.connect('friend-removed', self._friend_removed_cb)
def add_friend(self, buddy_info): def add_friend(self, buddy_info):
icon = FriendView(self._shell, self._menu_shell, buddy_info) icon = FriendView(self._shell, self._menu_shell, buddy_info)
self.add_item(icon) self.add_item(icon)
self._friends[buddy_info.get_name()] = icon self._friends[buddy_info.get_name()] = icon
def _friend_added_cb(self, data_model, buddy_info): def _friend_added_cb(self, data_model, buddy_info):
self.add_friend(buddy_info) self.add_friend(buddy_info)
def _friend_removed_cb(self, data_model, name): def _friend_removed_cb(self, data_model, name):
self.remove_item(self._friends[name]) self.remove_item(self._friends[name])
del self._friends[name] del self._friends[name]
def do_allocate(self, width, height): def do_allocate(self, width, height):
SpreadBox.do_allocate(self, width, height) SpreadBox.do_allocate(self, width, height)
[icon_width, icon_height] = self._my_icon.get_allocation() [icon_width, icon_height] = self._my_icon.get_allocation()
self.move(self._my_icon, (width - icon_width) / 2, self.move(self._my_icon, (width - icon_width) / 2,
(height - icon_height) / 2) (height - icon_height) / 2)

View File

@ -22,24 +22,24 @@ from sugar.graphics.grid import Grid
from sugar.graphics import style from sugar.graphics import style
class HomeBox(hippo.CanvasBox, hippo.CanvasItem): class HomeBox(hippo.CanvasBox, hippo.CanvasItem):
__gtype_name__ = 'SugarHomeBox' __gtype_name__ = 'SugarHomeBox'
def __init__(self, shell): def __init__(self, shell):
hippo.CanvasBox.__init__(self, background_color=0xe2e2e2ff, hippo.CanvasBox.__init__(self, background_color=0xe2e2e2ff,
yalign=2) yalign=2)
grid = Grid() grid = Grid()
donut = ActivitiesDonut(shell, box_width=grid.dimension(7), donut = ActivitiesDonut(shell, box_width=grid.dimension(7),
box_height=grid.dimension(7)) box_height=grid.dimension(7))
self.append(donut) self.append(donut)
self._my_icon = MyIcon() self._my_icon = MyIcon()
style.apply_stylesheet(self._my_icon, 'home.MyIcon') style.apply_stylesheet(self._my_icon, 'home.MyIcon')
self.append(self._my_icon, hippo.PACK_FIXED) self.append(self._my_icon, hippo.PACK_FIXED)
def do_allocate(self, width, height): def do_allocate(self, width, height):
hippo.CanvasBox.do_allocate(self, width, height) hippo.CanvasBox.do_allocate(self, width, height)
[icon_width, icon_height] = self._my_icon.get_allocation() [icon_width, icon_height] = self._my_icon.get_allocation()
self.move(self._my_icon, (width - icon_width) / 2, self.move(self._my_icon, (width - icon_width) / 2,
(height - icon_height) / 2) (height - icon_height) / 2)

View File

@ -25,45 +25,45 @@ from view.home.HomeBox import HomeBox
from view.home.FriendsBox import FriendsBox from view.home.FriendsBox import FriendsBox
class HomeWindow(gtk.Window): class HomeWindow(gtk.Window):
def __init__(self, shell): def __init__(self, shell):
gtk.Window.__init__(self) gtk.Window.__init__(self)
self._shell = shell self._shell = shell
self.set_default_size(gtk.gdk.screen_width(), self.set_default_size(gtk.gdk.screen_width(),
gtk.gdk.screen_height()) gtk.gdk.screen_height())
self.realize() self.realize()
self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DESKTOP) self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DESKTOP)
self._nb = gtk.Notebook() self._nb = gtk.Notebook()
self._nb.set_show_border(False) self._nb.set_show_border(False)
self._nb.set_show_tabs(False) self._nb.set_show_tabs(False)
self.add(self._nb) self.add(self._nb)
self._nb.show() self._nb.show()
canvas = hippo.Canvas() canvas = hippo.Canvas()
box = HomeBox(shell) box = HomeBox(shell)
canvas.set_root(box) canvas.set_root(box)
self._nb.append_page(canvas) self._nb.append_page(canvas)
canvas.show() canvas.show()
canvas = hippo.Canvas() canvas = hippo.Canvas()
box = FriendsBox(shell, MenuShell(canvas)) box = FriendsBox(shell, MenuShell(canvas))
canvas.set_root(box) canvas.set_root(box)
self._nb.append_page(canvas) self._nb.append_page(canvas)
canvas.show() canvas.show()
canvas = hippo.Canvas() canvas = hippo.Canvas()
box = MeshBox(shell, MenuShell(canvas)) box = MeshBox(shell, MenuShell(canvas))
canvas.set_root(box) canvas.set_root(box)
self._nb.append_page(canvas) self._nb.append_page(canvas)
canvas.show() canvas.show()
def set_zoom_level(self, level): def set_zoom_level(self, level):
if level == sugar.ZOOM_HOME: if level == sugar.ZOOM_HOME:
self._nb.set_current_page(0) self._nb.set_current_page(0)
elif level == sugar.ZOOM_FRIENDS: elif level == sugar.ZOOM_FRIENDS:
self._nb.set_current_page(1) self._nb.set_current_page(1)
elif level == sugar.ZOOM_MESH: elif level == sugar.ZOOM_MESH:
self._nb.set_current_page(2) self._nb.set_current_page(2)

View File

@ -25,116 +25,116 @@ from sugar.graphics.canvasicon import CanvasIcon
from view.BuddyIcon import BuddyIcon from view.BuddyIcon import BuddyIcon
class ActivityView(SnowflakeBox): class ActivityView(SnowflakeBox):
def __init__(self, shell, menu_shell, model): def __init__(self, shell, menu_shell, model):
SnowflakeBox.__init__(self) SnowflakeBox.__init__(self)
self._shell = shell self._shell = shell
self._model = model self._model = model
self._icons = {} self._icons = {}
icon = CanvasIcon(icon_name=model.get_icon_name(), icon = CanvasIcon(icon_name=model.get_icon_name(),
color=model.get_color(), size=80) color=model.get_color(), size=80)
icon.connect('activated', self._clicked_cb) icon.connect('activated', self._clicked_cb)
self.append(icon, hippo.PACK_FIXED) self.append(icon, hippo.PACK_FIXED)
self.set_root(icon) self.set_root(icon)
def has_buddy_icon(self, name): def has_buddy_icon(self, name):
return self._icons.has_key(name) return self._icons.has_key(name)
def add_buddy_icon(self, name, icon): def add_buddy_icon(self, name, icon):
self._icons[name] = icon self._icons[name] = icon
self.append(icon, hippo.PACK_FIXED) self.append(icon, hippo.PACK_FIXED)
def remove_buddy_icon(self, name): def remove_buddy_icon(self, name):
icon = self._icons[name] icon = self._icons[name]
self.remove(icon) self.remove(icon)
del self._icons[name] del self._icons[name]
def _clicked_cb(self, item): def _clicked_cb(self, item):
bundle_id = self._model.get_service().get_type() bundle_id = self._model.get_service().get_type()
self._shell.join_activity(bundle_id, self._model.get_id()) self._shell.join_activity(bundle_id, self._model.get_id())
class MeshBox(SpreadBox): class MeshBox(SpreadBox):
def __init__(self, shell, menu_shell): def __init__(self, shell, menu_shell):
SpreadBox.__init__(self, background_color=0xe2e2e2ff) SpreadBox.__init__(self, background_color=0xe2e2e2ff)
self._shell = shell self._shell = shell
self._menu_shell = menu_shell self._menu_shell = menu_shell
self._model = shell.get_model().get_mesh() self._model = shell.get_model().get_mesh()
self._buddies = {} self._buddies = {}
self._activities = {} self._activities = {}
self._buddy_to_activity = {} self._buddy_to_activity = {}
for buddy_model in self._model.get_buddies(): for buddy_model in self._model.get_buddies():
self._add_alone_buddy(buddy_model) self._add_alone_buddy(buddy_model)
self._model.connect('buddy-added', self._buddy_added_cb) self._model.connect('buddy-added', self._buddy_added_cb)
self._model.connect('buddy-removed', self._buddy_removed_cb) self._model.connect('buddy-removed', self._buddy_removed_cb)
self._model.connect('buddy-moved', self._buddy_moved_cb) self._model.connect('buddy-moved', self._buddy_moved_cb)
for activity_model in self._model.get_activities(): for activity_model in self._model.get_activities():
self._add_activity(activity_model) self._add_activity(activity_model)
self._model.connect('activity-added', self._activity_added_cb) self._model.connect('activity-added', self._activity_added_cb)
self._model.connect('activity-removed', self._activity_removed_cb) self._model.connect('activity-removed', self._activity_removed_cb)
def _buddy_added_cb(self, model, buddy_model): def _buddy_added_cb(self, model, buddy_model):
self._add_alone_buddy(buddy_model) self._add_alone_buddy(buddy_model)
def _buddy_removed_cb(self, model, buddy_model): def _buddy_removed_cb(self, model, buddy_model):
self._remove_buddy(buddy_model) self._remove_buddy(buddy_model)
def _buddy_moved_cb(self, model, buddy_model, activity_model): def _buddy_moved_cb(self, model, buddy_model, activity_model):
self._move_buddy(buddy_model, activity_model) self._move_buddy(buddy_model, activity_model)
def _activity_added_cb(self, model, activity_model): def _activity_added_cb(self, model, activity_model):
self._add_activity(activity_model) self._add_activity(activity_model)
def _activity_removed_cb(self, model, activity_model): def _activity_removed_cb(self, model, activity_model):
self._remove_activity(activity_model) self._remove_activity(activity_model)
def _add_alone_buddy(self, buddy_model): def _add_alone_buddy(self, buddy_model):
icon = BuddyIcon(self._shell, self._menu_shell, buddy_model) icon = BuddyIcon(self._shell, self._menu_shell, buddy_model)
icon.props.size = 80 icon.props.size = 80
self.add_item(icon) self.add_item(icon)
self._buddies[buddy_model.get_name()] = icon self._buddies[buddy_model.get_name()] = icon
def _remove_alone_buddy(self, buddy_model): def _remove_alone_buddy(self, buddy_model):
icon = self._buddies[buddy_model.get_name()] icon = self._buddies[buddy_model.get_name()]
self.remove_item(icon) self.remove_item(icon)
del self._buddies[buddy_model.get_name()] del self._buddies[buddy_model.get_name()]
def _remove_buddy(self, buddy_model): def _remove_buddy(self, buddy_model):
name = buddy_model.get_name() name = buddy_model.get_name()
if self._buddies.has_key(name): if self._buddies.has_key(name):
self._remove_alone_buddy(buddy_model) self._remove_alone_buddy(buddy_model)
else: else:
for activity in self._activities.values(): for activity in self._activities.values():
if activity.has_buddy_icon(name): if activity.has_buddy_icon(name):
activity.remove_buddy_icon(name) activity.remove_buddy_icon(name)
def _move_buddy(self, buddy_model, activity_model): def _move_buddy(self, buddy_model, activity_model):
name = buddy_model.get_name() name = buddy_model.get_name()
self._remove_buddy(buddy_model) self._remove_buddy(buddy_model)
if activity_model == None: if activity_model == None:
self._add_alone_buddy(buddy_model) self._add_alone_buddy(buddy_model)
else: else:
activity = self._activities[activity_model.get_id()] activity = self._activities[activity_model.get_id()]
icon = BuddyIcon(self._shell, self._menu_shell, buddy_model) icon = BuddyIcon(self._shell, self._menu_shell, buddy_model)
icon.props.size = 60 icon.props.size = 60
activity.add_buddy_icon(buddy_model.get_name(), icon) activity.add_buddy_icon(buddy_model.get_name(), icon)
def _add_activity(self, activity_model): def _add_activity(self, activity_model):
icon = ActivityView(self._shell, self._menu_shell, activity_model) icon = ActivityView(self._shell, self._menu_shell, activity_model)
self.add_item(icon) self.add_item(icon)
self._activities[activity_model.get_id()] = icon self._activities[activity_model.get_id()] = icon
def _remove_activity(self, activity_model): def _remove_activity(self, activity_model):
icon = self._activities[activity_model.get_id()] icon = self._activities[activity_model.get_id()]
self.remove_item(icon) self.remove_item(icon)
del self._activities[activity_model.get_id()] del self._activities[activity_model.get_id()]

View File

@ -18,6 +18,6 @@ from sugar.graphics.canvasicon import CanvasIcon
from sugar import profile from sugar import profile
class MyIcon(CanvasIcon): class MyIcon(CanvasIcon):
def __init__(self): def __init__(self):
CanvasIcon.__init__(self, icon_name='stock-buddy', CanvasIcon.__init__(self, icon_name='stock-buddy',
color=profile.get_color()) color=profile.get_color())

View File

@ -21,100 +21,100 @@ from sugar.graphics.canvasicon import CanvasIcon
from sugar.graphics import style from sugar.graphics import style
class ActivitiesDonut(hippo.CanvasBox, hippo.CanvasItem): class ActivitiesDonut(hippo.CanvasBox, hippo.CanvasItem):
__gtype_name__ = 'SugarActivitiesDonut' __gtype_name__ = 'SugarActivitiesDonut'
def __init__(self, shell, **kwargs): def __init__(self, shell, **kwargs):
hippo.CanvasBox.__init__(self, **kwargs) hippo.CanvasBox.__init__(self, **kwargs)
self._activities = {} self._activities = {}
shell.connect('activity_opened', self.__activity_opened_cb) shell.connect('activity_opened', self.__activity_opened_cb)
shell.connect('activity_closed', self.__activity_closed_cb) shell.connect('activity_closed', self.__activity_closed_cb)
def __activity_opened_cb(self, model, activity): def __activity_opened_cb(self, model, activity):
self._add_activity(activity) self._add_activity(activity)
def __activity_closed_cb(self, model, activity): def __activity_closed_cb(self, model, activity):
self._remove_activity(activity) self._remove_activity(activity)
def _remove_activity(self, activity): def _remove_activity(self, activity):
icon = self._activities[activity.get_id()] icon = self._activities[activity.get_id()]
self.remove(icon) self.remove(icon)
del self._activities[activity.get_id()] del self._activities[activity.get_id()]
def _add_activity(self, activity): def _add_activity(self, activity):
icon_name = activity.get_icon_name() icon_name = activity.get_icon_name()
icon_color = activity.get_icon_color() icon_color = activity.get_icon_color()
icon = CanvasIcon(icon_name=icon_name, color=icon_color) icon = CanvasIcon(icon_name=icon_name, color=icon_color)
style.apply_stylesheet(icon, 'ring.ActivityIcon') style.apply_stylesheet(icon, 'ring.ActivityIcon')
icon.connect('activated', self.__activity_icon_clicked_cb, activity) icon.connect('activated', self.__activity_icon_clicked_cb, activity)
self.append(icon, hippo.PACK_FIXED) self.append(icon, hippo.PACK_FIXED)
self._activities[activity.get_id()] = icon self._activities[activity.get_id()] = icon
self.emit_paint_needed(0, 0, -1, -1) self.emit_paint_needed(0, 0, -1, -1)
def __activity_icon_clicked_cb(self, item, activity): def __activity_icon_clicked_cb(self, item, activity):
activity.present() activity.present()
def _get_angles(self, index): def _get_angles(self, index):
angle = 2 * math.pi / 8 angle = 2 * math.pi / 8
return [index * angle, (index + 1) * angle] return [index * angle, (index + 1) * angle]
def _get_radius(self): def _get_radius(self):
[width, height] = self.get_allocation() [width, height] = self.get_allocation()
return min(width, height) / 2 return min(width, height) / 2
def _get_inner_radius(self): def _get_inner_radius(self):
return self._get_radius() * 0.5 return self._get_radius() * 0.5
def do_paint_below_children(self, cr, damaged_box): def do_paint_below_children(self, cr, damaged_box):
[width, height] = self.get_allocation() [width, height] = self.get_allocation()
cr.translate(width / 2, height / 2) cr.translate(width / 2, height / 2)
radius = self._get_radius() radius = self._get_radius()
cr.set_source_rgb(0xf1 / 255.0, 0xf1 / 255.0, 0xf1 / 255.0) cr.set_source_rgb(0xf1 / 255.0, 0xf1 / 255.0, 0xf1 / 255.0)
cr.arc(0, 0, radius, 0, 2 * math.pi) cr.arc(0, 0, radius, 0, 2 * math.pi)
cr.fill() cr.fill()
angle_end = 0 angle_end = 0
for i in range(0, len(self._activities)): for i in range(0, len(self._activities)):
[angle_start, angle_end] = self._get_angles(i) [angle_start, angle_end] = self._get_angles(i)
cr.new_path() cr.new_path()
cr.move_to(0, 0) cr.move_to(0, 0)
cr.line_to(radius * math.cos(angle_start), cr.line_to(radius * math.cos(angle_start),
radius * math.sin(angle_start)) radius * math.sin(angle_start))
cr.arc(0, 0, radius, angle_start, angle_end) cr.arc(0, 0, radius, angle_start, angle_end)
cr.line_to(0, 0) cr.line_to(0, 0)
cr.set_source_rgb(0xe2 / 255.0, 0xe2 / 255.0, 0xe2 / 255.0) cr.set_source_rgb(0xe2 / 255.0, 0xe2 / 255.0, 0xe2 / 255.0)
cr.set_line_width(4) cr.set_line_width(4)
cr.stroke_preserve() cr.stroke_preserve()
cr.set_source_rgb(1, 1, 1) cr.set_source_rgb(1, 1, 1)
cr.fill() cr.fill()
cr.set_source_rgb(0xe2 / 255.0, 0xe2 / 255.0, 0xe2 / 255.0) cr.set_source_rgb(0xe2 / 255.0, 0xe2 / 255.0, 0xe2 / 255.0)
cr.arc(0, 0, self._get_inner_radius(), 0, 2 * math.pi) cr.arc(0, 0, self._get_inner_radius(), 0, 2 * math.pi)
cr.fill() cr.fill()
def do_allocate(self, width, height): def do_allocate(self, width, height):
hippo.CanvasBox.do_allocate(self, width, height) hippo.CanvasBox.do_allocate(self, width, height)
radius = (self._get_inner_radius() + self._get_radius()) / 2 radius = (self._get_inner_radius() + self._get_radius()) / 2
i = 0 i = 0
for icon in self._activities.values(): for icon in self._activities.values():
[angle_start, angle_end] = self._get_angles(i) [angle_start, angle_end] = self._get_angles(i)
angle = angle_start + (angle_end - angle_start) / 2 angle = angle_start + (angle_end - angle_start) / 2
[icon_width, icon_height] = icon.get_allocation() [icon_width, icon_height] = icon.get_allocation()
x = int(radius * math.cos(angle)) - icon_width / 2 x = int(radius * math.cos(angle)) - icon_width / 2
y = int(radius * math.sin(angle)) - icon_height / 2 y = int(radius * math.sin(angle)) - icon_height / 2
self.move(icon, x + width / 2, y + height / 2) self.move(icon, x + width / 2, y + height / 2)
i += 1 i += 1

View File

@ -21,59 +21,59 @@ from sugar.graphics.iconcolor import IconColor
from sugar.graphics import style from sugar.graphics import style
frame_ActivityIcon = { frame_ActivityIcon = {
'color' : IconColor('white'), 'color' : IconColor('white'),
'size' : style.standard_icon_size 'size' : style.standard_icon_size
} }
frame_ShutdownIcon = { frame_ShutdownIcon = {
'size' : style.standard_icon_size 'size' : style.standard_icon_size
} }
frame_OverlayIcon = { frame_OverlayIcon = {
'size' : style.standard_icon_size 'size' : style.standard_icon_size
} }
frame_ZoomIcon = { frame_ZoomIcon = {
'size' : style.standard_icon_size 'size' : style.standard_icon_size
} }
frame_BuddyIcon = { frame_BuddyIcon = {
'size' : style.standard_icon_size 'size' : style.standard_icon_size
} }
home_MyIcon = { home_MyIcon = {
'size' : style.xlarge_icon_size 'size' : style.xlarge_icon_size
} }
ring_ActivityIcon = { ring_ActivityIcon = {
'size' : style.medium_icon_size 'size' : style.medium_icon_size
} }
friends_MyIcon = { friends_MyIcon = {
'size' : style.large_icon_size 'size' : style.large_icon_size
} }
friends_FriendIcon = { friends_FriendIcon = {
'size' : style.large_icon_size 'size' : style.large_icon_size
} }
friends_ActivityIcon = { friends_ActivityIcon = {
'size' : style.standard_icon_size 'size' : style.standard_icon_size
} }
clipboard_bubble = { clipboard_bubble = {
'fill-color' : 0x646464FF, 'fill-color' : 0x646464FF,
'stroke-color' : 0x646464FF, 'stroke-color' : 0x646464FF,
'progress-color': 0x333333FF, 'progress-color': 0x333333FF,
'spacing' : style.space_unit, 'spacing' : style.space_unit,
'padding' : style.space_unit * 1.5 'padding' : style.space_unit * 1.5
} }
clipboard_menu_item_title = { clipboard_menu_item_title = {
'xalign': hippo.ALIGNMENT_START, 'xalign': hippo.ALIGNMENT_START,
'padding-left': 5, 'padding-left': 5,
'color' : 0xFFFFFFFF, 'color' : 0xFFFFFFFF,
'font' : style.get_font_description('Bold', 1.2) 'font' : style.get_font_description('Bold', 1.2)
} }
style.register_stylesheet("clipboard.Bubble", clipboard_bubble) style.register_stylesheet("clipboard.Bubble", clipboard_bubble)

View File

@ -22,33 +22,33 @@ import signal
haveThreadframe = True haveThreadframe = True
try: try:
import threadframe import threadframe
except ImportError: except ImportError:
haveThreadframe = False haveThreadframe = False
class TracebackHelper(object): class TracebackHelper(object):
def __init__(self): def __init__(self):
fname = "%s-%d" % (os.path.basename(sys.argv[0]), os.getpid()) fname = "%s-%d" % (os.path.basename(sys.argv[0]), os.getpid())
self._fpath = os.path.join("/tmp", fname) self._fpath = os.path.join("/tmp", fname)
print "Tracebacks will be written to %s on SIGUSR1" % self._fpath print "Tracebacks will be written to %s on SIGUSR1" % self._fpath
signal.signal(signal.SIGUSR1, self._handler) signal.signal(signal.SIGUSR1, self._handler)
def __del__(self): def __del__(self):
try: try:
os.remove(self._fpath) os.remove(self._fpath)
except OSError: except OSError:
pass pass
def _handler(self, signum, pframe): def _handler(self, signum, pframe):
f = open(self._fpath, "a") f = open(self._fpath, "a")
if not haveThreadframe: if not haveThreadframe:
f.write("Threadframe not installed. No traceback available.\n") f.write("Threadframe not installed. No traceback available.\n")
else: else:
frames = threadframe.dict() frames = threadframe.dict()
for thread_id, frame in frames.iteritems(): for thread_id, frame in frames.iteritems():
f.write(('-' * 79) + '\n') f.write(('-' * 79) + '\n')
f.write('[Thread %s] %d' % (thread_id, sys.getrefcount(frame)) + '\n') f.write('[Thread %s] %d' % (thread_id, sys.getrefcount(frame)) + '\n')
traceback.print_stack(frame, limit=None, file=f) traceback.print_stack(frame, limit=None, file=f)
f.write("\n") f.write("\n")
f.write('\n') f.write('\n')
f.close() f.close()

View File

@ -32,133 +32,133 @@ ACTIVITY_SERVICE_PATH = "/org/laptop/Activity"
ACTIVITY_INTERFACE = "org.laptop.Activity" ACTIVITY_INTERFACE = "org.laptop.Activity"
def get_service_name(xid): def get_service_name(xid):
return ACTIVITY_SERVICE_NAME + '%d' % xid return ACTIVITY_SERVICE_NAME + '%d' % xid
def get_object_path(xid): def get_object_path(xid):
return ACTIVITY_SERVICE_PATH + "/%s" % xid return ACTIVITY_SERVICE_PATH + "/%s" % xid
class ActivityDbusService(dbus.service.Object): class ActivityDbusService(dbus.service.Object):
"""Base dbus service object that each Activity uses to export dbus methods. """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 The dbus service is separate from the actual Activity object so that we can
tightly control what stuff passes through the dbus python bindings.""" tightly control what stuff passes through the dbus python bindings."""
def start(self, pservice, activity): def start(self, pservice, activity):
self._activity = activity self._activity = activity
self._pservice = pservice self._pservice = pservice
@dbus.service.method(ACTIVITY_INTERFACE) @dbus.service.method(ACTIVITY_INTERFACE)
def share(self): def share(self):
"""Called by the shell to request the activity to share itself on the network.""" """Called by the shell to request the activity to share itself on the network."""
self._activity.share() self._activity.share()
@dbus.service.method(ACTIVITY_INTERFACE) @dbus.service.method(ACTIVITY_INTERFACE)
def join(self, activity_ps_path): def join(self, activity_ps_path):
"""Join the activity specified by its presence service path""" """Join the activity specified by its presence service path"""
activity_ps = self._pservice.get(activity_ps_path) activity_ps = self._pservice.get(activity_ps_path)
return self._activity.join(activity_ps) return self._activity.join(activity_ps)
@dbus.service.method(ACTIVITY_INTERFACE) @dbus.service.method(ACTIVITY_INTERFACE)
def get_id(self): def get_id(self):
"""Get the activity identifier""" """Get the activity identifier"""
return self._activity.get_id() return self._activity.get_id()
@dbus.service.method(ACTIVITY_INTERFACE) @dbus.service.method(ACTIVITY_INTERFACE)
def get_type(self): def get_type(self):
"""Get the activity type""" """Get the activity type"""
return self._activity.get_type() return self._activity.get_type()
@dbus.service.method(ACTIVITY_INTERFACE) @dbus.service.method(ACTIVITY_INTERFACE)
def get_shared(self): def get_shared(self):
"""Returns True if the activity is shared on the mesh.""" """Returns True if the activity is shared on the mesh."""
return self._activity.get_shared() return self._activity.get_shared()
@dbus.service.method(ACTIVITY_INTERFACE, @dbus.service.method(ACTIVITY_INTERFACE,
in_signature="sas", out_signature="") in_signature="sas", out_signature="")
def execute(self, command, args): def execute(self, command, args):
self._activity.execute(command, args) self._activity.execute(command, args)
class Activity(gtk.Window): 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): def __init__(self):
gtk.Window.__init__(self) gtk.Window.__init__(self)
self.connect('destroy', self.__destroy_cb) self.connect('destroy', self.__destroy_cb)
self._shared = False self._shared = False
self._activity_id = None self._activity_id = None
self._default_type = None self._default_type = None
self._service = None self._service = None
self._pservice = PresenceService() self._pservice = PresenceService()
self.present() self.present()
group = gtk.Window() group = gtk.Window()
group.realize() group.realize()
self.window.set_group(group.window) self.window.set_group(group.window)
bus = dbus.SessionBus() bus = dbus.SessionBus()
xid = self.window.xid xid = self.window.xid
bus_name = dbus.service.BusName(get_service_name(xid), bus=bus) bus_name = dbus.service.BusName(get_service_name(xid), bus=bus)
self._bus = ActivityDbusService(bus_name, get_object_path(xid)) self._bus = ActivityDbusService(bus_name, get_object_path(xid))
self._bus.start(self._pservice, self) self._bus.start(self._pservice, self)
def set_type(self, activity_type): def set_type(self, activity_type):
"""Sets the activity type.""" """Sets the activity type."""
self._activity_type = activity_type self._activity_type = activity_type
self._default_type = activity.get_default_type(activity_type) self._default_type = activity.get_default_type(activity_type)
def get_type(self): def get_type(self):
"""Gets the activity type.""" """Gets the activity type."""
return self._activity_type return self._activity_type
def get_default_type(self): def get_default_type(self):
return self._default_type return self._default_type
def get_shared(self): def get_shared(self):
"""Returns TRUE if the activity is shared on the mesh.""" """Returns TRUE if the activity is shared on the mesh."""
return self._shared return self._shared
def get_id(self): def get_id(self):
"""Get the unique activity identifier.""" """Get the unique activity identifier."""
if self._activity_id == None: if self._activity_id == None:
self._activity_id = sugar.util.unique_id() self._activity_id = sugar.util.unique_id()
return self._activity_id return self._activity_id
def join(self, activity_ps): def join(self, activity_ps):
"""Join an activity shared on the network.""" """Join an activity shared on the network."""
self._shared = True self._shared = True
self._activity_id = activity_ps.get_id() self._activity_id = activity_ps.get_id()
# Publish the default service, it's a copy of # Publish the default service, it's a copy of
# one of those we found on the network. # one of those we found on the network.
services = activity_ps.get_services_of_type(self._default_type) services = activity_ps.get_services_of_type(self._default_type)
if len(services) > 0: if len(services) > 0:
service = services[0] service = services[0]
addr = service.get_address() addr = service.get_address()
port = service.get_port() port = service.get_port()
properties = service.get_published_values() properties = service.get_published_values()
self._service = self._pservice.share_activity( self._service = self._pservice.share_activity(
self, self._default_type, properties, addr, port) self, self._default_type, properties, addr, port)
else: else:
logging.error('Cannot join the activity') logging.error('Cannot join the activity')
def share(self): def share(self):
"""Share the activity on the network.""" """Share the activity on the network."""
logging.debug('Share activity %s on the network.' % self.get_id()) logging.debug('Share activity %s on the network.' % self.get_id())
self._service = self._pservice.share_activity(self, self._default_type) self._service = self._pservice.share_activity(self, self._default_type)
self._shared = True self._shared = True
def execute(self, command, args): def execute(self, command, args):
"""Execute the given command with args""" """Execute the given command with args"""
pass pass
def __destroy_cb(self, window): def __destroy_cb(self, window):
if self._bus: if self._bus:
del self._bus del self._bus
self._bus = None self._bus = None
if self._service: if self._service:
self._pservice.unregister_service(self._service) self._pservice.unregister_service(self._service)

View File

@ -27,72 +27,72 @@ from sugar.presence.PresenceService import PresenceService
from sugar.activity import Activity from sugar.activity import Activity
def get_path(activity_name): def get_path(activity_name):
"""Returns the activity path""" """Returns the activity path"""
return '/' + activity_name.replace('.', '/') return '/' + activity_name.replace('.', '/')
class ActivityFactory(dbus.service.Object): 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): def __init__(self, activity_type, activity_class):
self._activity_type = activity_type self._activity_type = activity_type
self._activities = [] self._activities = []
splitted_module = activity_class.rsplit('.', 1) splitted_module = activity_class.rsplit('.', 1)
module_name = splitted_module[0] module_name = splitted_module[0]
class_name = splitted_module[1] class_name = splitted_module[1]
module = __import__(module_name) module = __import__(module_name)
for comp in module_name.split('.')[1:]: for comp in module_name.split('.')[1:]:
module = getattr(module, comp) module = getattr(module, comp)
if hasattr(module, 'start'): if hasattr(module, 'start'):
module.start() module.start()
self._module = module self._module = module
self._constructor = getattr(module, class_name) self._constructor = getattr(module, class_name)
bus = dbus.SessionBus() bus = dbus.SessionBus()
factory = activity_type factory = activity_type
bus_name = dbus.service.BusName(factory, bus = bus) bus_name = dbus.service.BusName(factory, bus = bus)
dbus.service.Object.__init__(self, bus_name, get_path(factory)) dbus.service.Object.__init__(self, bus_name, get_path(factory))
@dbus.service.method("com.redhat.Sugar.ActivityFactory") @dbus.service.method("com.redhat.Sugar.ActivityFactory")
def create(self): def create(self):
activity = self._constructor() activity = self._constructor()
activity.set_type(self._activity_type) activity.set_type(self._activity_type)
self._activities.append(activity) self._activities.append(activity)
activity.connect('destroy', self._activity_destroy_cb) activity.connect('destroy', self._activity_destroy_cb)
return activity.window.xid return activity.window.xid
def _activity_destroy_cb(self, activity): def _activity_destroy_cb(self, activity):
self._activities.remove(activity) self._activities.remove(activity)
if hasattr(self._module, 'stop'): if hasattr(self._module, 'stop'):
self._module.stop() self._module.stop()
if len(self._activities) == 0: if len(self._activities) == 0:
gtk.main_quit() gtk.main_quit()
def create(activity_name): def create(activity_name):
"""Create a new activity from his name.""" """Create a new activity from his name."""
bus = dbus.SessionBus() bus = dbus.SessionBus()
factory_name = activity_name factory_name = activity_name
factory_path = get_path(factory_name) factory_path = get_path(factory_name)
proxy_obj = bus.get_object(factory_name, factory_path) proxy_obj = bus.get_object(factory_name, factory_path)
factory = dbus.Interface(proxy_obj, "com.redhat.Sugar.ActivityFactory") factory = dbus.Interface(proxy_obj, "com.redhat.Sugar.ActivityFactory")
xid = factory.create() xid = factory.create()
bus = dbus.SessionBus() bus = dbus.SessionBus()
proxy_obj = bus.get_object(Activity.get_service_name(xid), proxy_obj = bus.get_object(Activity.get_service_name(xid),
Activity.get_object_path(xid)) Activity.get_object_path(xid))
activity = dbus.Interface(proxy_obj, Activity.ACTIVITY_INTERFACE) activity = dbus.Interface(proxy_obj, Activity.ACTIVITY_INTERFACE)
return activity return activity
def register_factory(name, activity_class): def register_factory(name, activity_class):
"""Register the activity factory.""" """Register the activity factory."""
factory = ActivityFactory(name, activity_class) factory = ActivityFactory(name, activity_class)

View File

@ -9,10 +9,10 @@ sizes = 'gtk-large-toolbar=%d, %d' % (grid.dimension(1), grid.dimension(1))
settings.set_string_property('gtk-icon-sizes', sizes, '') settings.set_string_property('gtk-icon-sizes', sizes, '')
def get_default_type(activity_type): 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.""" and provides info about the activity, for example the title."""
splitted_id = activity_type.split('.') splitted_id = activity_type.split('.')
splitted_id.reverse() splitted_id.reverse()
return '_' + '_'.join(splitted_id) + '._udp' return '_' + '_'.join(splitted_id) + '._udp'

View File

@ -4,83 +4,83 @@ import os
from ConfigParser import ConfigParser from ConfigParser import ConfigParser
class Bundle: class Bundle:
"""Info about an activity bundle. Wraps the activity.info file.""" """Info about an activity bundle. Wraps the activity.info file."""
def __init__(self, path): def __init__(self, path):
self._name = None self._name = None
self._icon = None self._icon = None
self._service_name = None self._service_name = None
self._show_launcher = True self._show_launcher = True
self._valid = True self._valid = True
self._path = path self._path = path
self._activity_version = 0 self._activity_version = 0
info_path = os.path.join(path, 'activity', 'activity.info') info_path = os.path.join(path, 'activity', 'activity.info')
if os.path.isfile(info_path): if os.path.isfile(info_path):
self._parse_info(info_path) self._parse_info(info_path)
else: else:
self._valid = False self._valid = False
def _parse_info(self, info_path): def _parse_info(self, info_path):
cp = ConfigParser() cp = ConfigParser()
cp.read([info_path]) cp.read([info_path])
section = 'Activity' section = 'Activity'
if cp.has_option(section, 'service_name'): if cp.has_option(section, 'service_name'):
self._service_name = cp.get(section, 'service_name') self._service_name = cp.get(section, 'service_name')
else: else:
self._valid = False self._valid = False
logging.error('%s must specify a service name' % self._path) logging.error('%s must specify a service name' % self._path)
if cp.has_option(section, 'name'): if cp.has_option(section, 'name'):
self._name = cp.get(section, 'name') self._name = cp.get(section, 'name')
else: else:
self._valid = False self._valid = False
logging.error('%s must specify a name' % self._path) logging.error('%s must specify a name' % self._path)
if cp.has_option(section, 'exec'): if cp.has_option(section, 'exec'):
self._exec = cp.get(section, 'exec') self._exec = cp.get(section, 'exec')
else: else:
self._valid = False self._valid = False
logging.error('%s must specify an exec' % self._path) logging.error('%s must specify an exec' % self._path)
if cp.has_option(section, 'show_launcher'): if cp.has_option(section, 'show_launcher'):
if cp.get(section, 'show_launcher') == 'no': if cp.get(section, 'show_launcher') == 'no':
self._show_launcher = False self._show_launcher = False
if cp.has_option(section, 'icon'): if cp.has_option(section, 'icon'):
self._icon = cp.get(section, 'icon') self._icon = cp.get(section, 'icon')
if cp.has_option(section, 'activity_version'): if cp.has_option(section, 'activity_version'):
self._activity_version = int(cp.get(section, 'activity_version')) self._activity_version = int(cp.get(section, 'activity_version'))
def is_valid(self): def is_valid(self):
return self._valid return self._valid
def get_path(self): def get_path(self):
"""Get the activity bundle path.""" """Get the activity bundle path."""
return self._path return self._path
def get_name(self): def get_name(self):
"""Get the activity user visible name.""" """Get the activity user visible name."""
return self._name return self._name
def get_service_name(self): def get_service_name(self):
"""Get the activity service name""" """Get the activity service name"""
return self._service_name return self._service_name
def get_icon(self): def get_icon(self):
"""Get the activity icon name""" """Get the activity icon name"""
return self._icon return self._icon
def get_activity_version(self): def get_activity_version(self):
"""Get the activity version""" """Get the activity version"""
return self._activity_version return self._activity_version
def get_exec(self): def get_exec(self):
"""Get the command to execute to launch the activity factory""" """Get the command to execute to launch the activity factory"""
return self._exec return self._exec
def get_show_launcher(self): def get_show_launcher(self):
"""Get whether there should be a visible launcher for the activity""" """Get whether there should be a visible launcher for the activity"""
return self._show_launcher return self._show_launcher

View File

@ -25,71 +25,71 @@ import shutil
from sugar.activity.bundle import Bundle from sugar.activity.bundle import Bundle
class _SvnFileList(list): class _SvnFileList(list):
def __init__(self): def __init__(self):
f = os.popen('svn list -R') f = os.popen('svn list -R')
for line in f.readlines(): for line in f.readlines():
filename = line.strip() filename = line.strip()
if os.path.isfile(filename): if os.path.isfile(filename):
self.append(filename) self.append(filename)
f.close() f.close()
class _GitFileList(list): class _GitFileList(list):
def __init__(self): def __init__(self):
f = os.popen('git-ls-files') f = os.popen('git-ls-files')
for line in f.readlines(): for line in f.readlines():
filename = line.strip() filename = line.strip()
if not filename.startswith('.'): if not filename.startswith('.'):
self.append(filename) self.append(filename)
f.close() f.close()
def _extract_bundle(source_file, dest_dir): def _extract_bundle(source_file, dest_dir):
if not os.path.exists(dest_dir): if not os.path.exists(dest_dir):
os.mkdir(dest_dir) os.mkdir(dest_dir)
zf = zipfile.ZipFile(source_file) zf = zipfile.ZipFile(source_file)
for i, name in enumerate(zf.namelist()): for i, name in enumerate(zf.namelist()):
path = os.path.join(dest_dir, name) path = os.path.join(dest_dir, name)
if not os.path.exists(os.path.dirname(path)): if not os.path.exists(os.path.dirname(path)):
os.makedirs(os.path.dirname(path)) os.makedirs(os.path.dirname(path))
outfile = open(path, 'wb') outfile = open(path, 'wb')
outfile.write(zf.read(name)) outfile.write(zf.read(name))
outfile.flush() outfile.flush()
outfile.close() outfile.close()
def _get_source_path(): def _get_source_path():
return os.getcwd() return os.getcwd()
def _get_activities_path(): def _get_activities_path():
path = os.path.expanduser('~/Activities') path = os.path.expanduser('~/Activities')
if not os.path.isdir(path): if not os.path.isdir(path):
os.mkdir(path) os.mkdir(path)
return path return path
def _get_bundle_dir(): def _get_bundle_dir():
bundle_name = os.path.basename(_get_source_path()) bundle_name = os.path.basename(_get_source_path())
return bundle_name + '.activity' return bundle_name + '.activity'
def _get_install_dir(prefix): def _get_install_dir(prefix):
return os.path.join(prefix, 'share/activities') return os.path.join(prefix, 'share/activities')
def _get_bundle_path(): 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(): def _get_package_name():
bundle = Bundle(_get_source_path()) bundle = Bundle(_get_source_path())
zipname = '%s-%d.xo' % (bundle.get_name(), bundle.get_activity_version()) zipname = '%s-%d.xo' % (bundle.get_name(), bundle.get_activity_version())
return zipname return zipname
def _delete_backups(arg, dirname, names): def _delete_backups(arg, dirname, names):
for name in names: for name in names:
if name.endswith('~') or name.endswith('pyc'): if name.endswith('~') or name.endswith('pyc'):
os.remove(os.path.join(dirname, name)) os.remove(os.path.join(dirname, name))
def cmd_help(): def cmd_help():
print 'Usage: \n\ print 'Usage: \n\
setup.py dev - setup for development \n\ setup.py dev - setup for development \n\
setup.py dist - create a bundle package \n\ setup.py dist - create a bundle package \n\
setup.py install - install the bundle \n\ setup.py install - install the bundle \n\
@ -98,59 +98,59 @@ setup.py help - print this message \n\
' '
def cmd_dev(): def cmd_dev():
bundle_path = get_bundle_path() bundle_path = get_bundle_path()
try: try:
os.symlink(_get_source_path(), bundle_path) os.symlink(_get_source_path(), bundle_path)
except OSError: except OSError:
if os.path.islink(bundle_path): if os.path.islink(bundle_path):
print 'ERROR - The bundle has been already setup for development.' print 'ERROR - The bundle has been already setup for development.'
else: else:
print 'ERROR - A bundle with the same name is already installed.' print 'ERROR - A bundle with the same name is already installed.'
def cmd_dist(): def cmd_dist():
if os.path.isdir('.git'): if os.path.isdir('.git'):
file_list = _GitFileList() file_list = _GitFileList()
elif os.path.isdir('.svn'): elif os.path.isdir('.svn'):
file_list = _SvnFileList() file_list = _SvnFileList()
else: else:
print 'ERROR - The command works only with git or svn repositories.' print 'ERROR - The command works only with git or svn repositories.'
zipname = _get_package_name() zipname = _get_package_name()
bundle_zip = zipfile.ZipFile(zipname, 'w', zipfile.ZIP_DEFLATED) bundle_zip = zipfile.ZipFile(zipname, 'w', zipfile.ZIP_DEFLATED)
for filename in file_list: for filename in file_list:
arcname = os.path.join(_get_bundle_dir(), filename) arcname = os.path.join(_get_bundle_dir(), filename)
bundle_zip.write(filename, arcname) bundle_zip.write(filename, arcname)
bundle_zip.close() bundle_zip.close()
def cmd_install(prefix): def cmd_install(prefix):
cmd_dist() cmd_dist()
cmd_uninstall(prefix) cmd_uninstall(prefix)
_extract_bundle(_get_package_name(), _get_install_dir(prefix)) _extract_bundle(_get_package_name(), _get_install_dir(prefix))
def cmd_uninstall(prefix): def cmd_uninstall(prefix):
path = os.path.join(_get_install_dir(prefix), _get_bundle_dir()) path = os.path.join(_get_install_dir(prefix), _get_bundle_dir())
if os.path.isdir(path): if os.path.isdir(path):
shutil.rmtree(path) shutil.rmtree(path)
def cmd_clean(): def cmd_clean():
os.path.walk('.', delete_backups, None) os.path.walk('.', delete_backups, None)
def start(): def start():
if len(sys.argv) < 2: if len(sys.argv) < 2:
cmd_help() cmd_help()
elif sys.argv[1] == 'build': elif sys.argv[1] == 'build':
pass pass
elif sys.argv[1] == 'dev': elif sys.argv[1] == 'dev':
cmd_dev() cmd_dev()
elif sys.argv[1] == 'dist': elif sys.argv[1] == 'dist':
cmd_dist() cmd_dist()
elif sys.argv[1] == 'install' and len(sys.argv) == 3: elif sys.argv[1] == 'install' and len(sys.argv) == 3:
cmd_install(sys.argv[2]) cmd_install(sys.argv[2])
elif sys.argv[1] == 'uninstall' and len(sys.argv) == 3: elif sys.argv[1] == 'uninstall' and len(sys.argv) == 3:
cmd_uninstall(sys.argv[2]) cmd_uninstall(sys.argv[2])
elif sys.argv[1] == 'clean': elif sys.argv[1] == 'clean':
cmd_clean() cmd_clean()
else: else:
cmd_help() cmd_help()

View File

@ -6,51 +6,51 @@ from sugar import env
from sugar import util from sugar import util
class _ServiceManager(object): class _ServiceManager(object):
def __init__(self): def __init__(self):
self._path = env.get_user_service_dir() self._path = env.get_user_service_dir()
def add(self, bundle): def add(self, bundle):
name = bundle.get_service_name() name = bundle.get_service_name()
# FIXME evil hack. Probably need to fix Exec spec # FIXME evil hack. Probably need to fix Exec spec
full_exec = env.get_shell_bin_dir() + '/' + bundle.get_exec() full_exec = env.get_shell_bin_dir() + '/' + bundle.get_exec()
full_exec += ' ' + bundle.get_path() full_exec += ' ' + bundle.get_path()
util.write_service(name, full_exec, self._path) util.write_service(name, full_exec, self._path)
class BundleRegistry: class BundleRegistry:
"""Service that tracks the available activity bundles""" """Service that tracks the available activity bundles"""
def __init__(self): def __init__(self):
self._bundles = {} self._bundles = {}
self._search_path = [] self._search_path = []
self._service_manager = _ServiceManager() self._service_manager = _ServiceManager()
def get_bundle(self, service_name): def get_bundle(self, service_name):
"""Returns an bundle given his service name""" """Returns an bundle given his service name"""
if self._bundles.has_key(service_name): if self._bundles.has_key(service_name):
return self._bundles[service_name] return self._bundles[service_name]
else: else:
return None return None
def add_search_path(self, path): def add_search_path(self, path):
"""Add a directory to the bundles search path""" """Add a directory to the bundles search path"""
self._search_path.append(path) self._search_path.append(path)
self._scan_directory(path) self._scan_directory(path)
def __iter__(self): def __iter__(self):
return self._bundles.values().__iter__() return self._bundles.values().__iter__()
def _scan_directory(self, path): def _scan_directory(self, path):
if os.path.isdir(path): if os.path.isdir(path):
for f in os.listdir(path): for f in os.listdir(path):
bundle_dir = os.path.join(path, f) bundle_dir = os.path.join(path, f)
if os.path.isdir(bundle_dir) and \ if os.path.isdir(bundle_dir) and \
bundle_dir.endswith('.activity'): bundle_dir.endswith('.activity'):
self._add_bundle(bundle_dir) self._add_bundle(bundle_dir)
def _add_bundle(self, bundle_path): def _add_bundle(self, bundle_path):
bundle = Bundle(bundle_path) bundle = Bundle(bundle_path)
if bundle.is_valid(): if bundle.is_valid():
self._bundles[bundle.get_service_name()] = bundle self._bundles[bundle.get_service_name()] = bundle
self._service_manager.add(bundle) self._service_manager.add(bundle)

View File

@ -20,48 +20,48 @@ import logging
from sugar.chat.GroupChat import GroupChat from sugar.chat.GroupChat import GroupChat
class ActivityChat(GroupChat): class ActivityChat(GroupChat):
SERVICE_TYPE = "_olpc_activity_chat._udp" SERVICE_TYPE = "_olpc_activity_chat._udp"
def __init__(self, activity): def __init__(self, activity):
GroupChat.__init__(self) GroupChat.__init__(self)
self._chat_service = None self._chat_service = None
self.connect('destroy', self._destroy_cb) self.connect('destroy', self._destroy_cb)
self._activity = activity self._activity = activity
self._pservice.register_service_type(ActivityChat.SERVICE_TYPE) self._pservice.register_service_type(ActivityChat.SERVICE_TYPE)
self._pservice.connect('service-appeared', self._service_appeared_cb) self._pservice.connect('service-appeared', self._service_appeared_cb)
# Find an existing activity chat to latch onto # Find an existing activity chat to latch onto
ps_activity = self._pservice.get_activity(activity.get_id()) ps_activity = self._pservice.get_activity(activity.get_id())
if ps_activity is not None: if ps_activity is not None:
services = ps_activity.get_services_of_type(ActivityChat.SERVICE_TYPE) services = ps_activity.get_services_of_type(ActivityChat.SERVICE_TYPE)
if len(services) > 0: if len(services) > 0:
self._service_appeared_cb(self._pservice, services[0]) self._service_appeared_cb(self._pservice, services[0])
def _service_appeared_cb(self, pservice, service): def _service_appeared_cb(self, pservice, service):
if service.get_activity_id() != self._activity.get_id(): if service.get_activity_id() != self._activity.get_id():
return return
if service.get_type() != ActivityChat.SERVICE_TYPE: if service.get_type() != ActivityChat.SERVICE_TYPE:
return return
if self._chat_service: if self._chat_service:
return return
logging.debug('Activity chat service appeared, setup the stream.') logging.debug('Activity chat service appeared, setup the stream.')
# Ok, there's an existing chat service that we copy # Ok, there's an existing chat service that we copy
# parameters and such from # parameters and such from
addr = service.get_address() addr = service.get_address()
port = service.get_port() port = service.get_port()
self._chat_service = self._pservice.share_activity(self._activity, self._chat_service = self._pservice.share_activity(self._activity,
stype=ActivityChat.SERVICE_TYPE, address=addr, port=port) stype=ActivityChat.SERVICE_TYPE, address=addr, port=port)
self._setup_stream(self._chat_service) self._setup_stream(self._chat_service)
def share(self): def share(self):
"""Only called when we share the activity this chat is tied to.""" """Only called when we share the activity this chat is tied to."""
self._chat_service = self._pservice.share_activity(self._activity, self._chat_service = self._pservice.share_activity(self._activity,
stype=ActivityChat.SERVICE_TYPE) stype=ActivityChat.SERVICE_TYPE)
self._setup_stream(self._chat_service) self._setup_stream(self._chat_service)
def _destroy_cb(self, widget): def _destroy_cb(self, widget):
if self._chat_service: if self._chat_service:
self._pservice.unregister_service(self._chat_service) self._pservice.unregister_service(self._chat_service)

View File

@ -37,244 +37,244 @@ import richtext
PANGO_SCALE = 1024 # Where is this defined? PANGO_SCALE = 1024 # Where is this defined?
class Chat(gtk.VBox): class Chat(gtk.VBox):
SERVICE_TYPE = "_olpc_chat._tcp" SERVICE_TYPE = "_olpc_chat._tcp"
SERVICE_PORT = 6100 SERVICE_PORT = 6100
TEXT_MODE = 0 TEXT_MODE = 0
SKETCH_MODE = 1 SKETCH_MODE = 1
def __init__(self): def __init__(self):
gtk.VBox.__init__(self, False, 6) gtk.VBox.__init__(self, False, 6)
self._pservice = PresenceService.get_instance() self._pservice = PresenceService.get_instance()
self._stream_writer = None self._stream_writer = None
self.set_border_width(12) self.set_border_width(12)
chat_vbox = gtk.VBox() chat_vbox = gtk.VBox()
chat_vbox.set_spacing(6) chat_vbox.set_spacing(6)
self._chat_sw = gtk.ScrolledWindow() self._chat_sw = gtk.ScrolledWindow()
self._chat_sw.set_shadow_type(gtk.SHADOW_IN) self._chat_sw.set_shadow_type(gtk.SHADOW_IN)
self._chat_sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS) self._chat_sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
self._chat_view = richtext.RichTextView() self._chat_view = richtext.RichTextView()
self._chat_view.connect("link-clicked", self.__link_clicked_cb) self._chat_view.connect("link-clicked", self.__link_clicked_cb)
self._chat_view.set_editable(False) self._chat_view.set_editable(False)
self._chat_view.set_cursor_visible(False) self._chat_view.set_cursor_visible(False)
self._chat_view.set_pixels_above_lines(7) self._chat_view.set_pixels_above_lines(7)
self._chat_view.set_left_margin(5) self._chat_view.set_left_margin(5)
self._chat_sw.add(self._chat_view) self._chat_sw.add(self._chat_view)
self._chat_view.show() self._chat_view.show()
chat_vbox.pack_start(self._chat_sw) chat_vbox.pack_start(self._chat_sw)
self._chat_sw.show() self._chat_sw.show()
self.pack_start(chat_vbox) self.pack_start(chat_vbox)
chat_vbox.show() chat_vbox.show()
self._mode = Chat.TEXT_MODE self._mode = Chat.TEXT_MODE
self._editor = ChatEditor(self, ChatEditor.TEXT_MODE) self._editor = ChatEditor(self, ChatEditor.TEXT_MODE)
toolbar = ChatToolbar(self._editor) toolbar = ChatToolbar(self._editor)
self.pack_start(toolbar, False) self.pack_start(toolbar, False)
toolbar.show() toolbar.show()
self.pack_start(self._editor, False) self.pack_start(self._editor, False)
self._editor.show() 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): def __key_press_event_cb(self, window, event):
if event.keyval == gtk.keysyms.s and \ if event.keyval == gtk.keysyms.s and \
event.state & gtk.gdk.CONTROL_MASK: event.state & gtk.gdk.CONTROL_MASK:
if self.get_mode() == Chat.SKETCH_MODE: if self.get_mode() == Chat.SKETCH_MODE:
self.set_mode(Chat.TEXT_MODE) self.set_mode(Chat.TEXT_MODE)
elif self.get_mode() == Chat.TEXT_MODE: elif self.get_mode() == Chat.TEXT_MODE:
self.set_mode(Chat.SKETCH_MODE) self.set_mode(Chat.SKETCH_MODE)
def get_mode(self): def get_mode(self):
return self._mode return self._mode
def set_mode(self, mode): def set_mode(self, mode):
self._mode = mode self._mode = mode
if self._mode == Chat.TEXT_MODE: if self._mode == Chat.TEXT_MODE:
self._editor.set_mode(ChatEditor.TEXT_MODE) self._editor.set_mode(ChatEditor.TEXT_MODE)
elif self._mode == Chat.SKETCH_MODE: elif self._mode == Chat.SKETCH_MODE:
self._editor.set_mode(ChatEditor.SKETCH_MODE) self._editor.set_mode(ChatEditor.SKETCH_MODE)
def __get_browser_shell(self): def __get_browser_shell(self):
bus = dbus.SessionBus() bus = dbus.SessionBus()
proxy_obj = bus.get_object('com.redhat.Sugar.Browser', '/com/redhat/Sugar/Browser') proxy_obj = bus.get_object('com.redhat.Sugar.Browser', '/com/redhat/Sugar/Browser')
self._browser_shell = dbus.Interface(proxy_obj, 'com.redhat.Sugar.BrowserShell') self._browser_shell = dbus.Interface(proxy_obj, 'com.redhat.Sugar.BrowserShell')
def __link_clicked_cb(self, view, address): def __link_clicked_cb(self, view, address):
self.__get_browser_shell().open_browser(address) self.__get_browser_shell().open_browser(address)
def _scroll_chat_view_to_bottom(self): def _scroll_chat_view_to_bottom(self):
# Only scroll to bottom if the view is already close to the bottom # Only scroll to bottom if the view is already close to the bottom
vadj = self._chat_sw.get_vadjustment() vadj = self._chat_sw.get_vadjustment()
if vadj.value + vadj.page_size > vadj.upper * 0.8: if vadj.value + vadj.page_size > vadj.upper * 0.8:
vadj.value = vadj.upper - vadj.page_size vadj.value = vadj.upper - vadj.page_size
self._chat_sw.set_vadjustment(vadj) self._chat_sw.set_vadjustment(vadj)
def _message_inserted(self): def _message_inserted(self):
gobject.idle_add(self._scroll_chat_view_to_bottom) gobject.idle_add(self._scroll_chat_view_to_bottom)
def _insert_buddy(self, buf, buddy): def _insert_buddy(self, buf, buddy):
# Stuff in the buddy icon, if we have one for this buddy # Stuff in the buddy icon, if we have one for this buddy
icon = buddy.get_icon_pixbuf() icon = buddy.get_icon_pixbuf()
if icon: if icon:
rise = int(icon.get_height() / 4) * -1 rise = int(icon.get_height() / 4) * -1
hash_string = "%s-%s" % (buddy.get_name(), buddy.get_ip4_address()) hash_string = "%s-%s" % (buddy.get_name(), buddy.get_ip4_address())
sha_hash = sha.new() sha_hash = sha.new()
sha_hash.update(hash_string) sha_hash.update(hash_string)
tagname = "buddyicon-%s" % sha_hash.hexdigest() tagname = "buddyicon-%s" % sha_hash.hexdigest()
if not buf.get_tag_table().lookup(tagname): if not buf.get_tag_table().lookup(tagname):
buf.create_tag(tagname, rise=(rise * PANGO_SCALE)) buf.create_tag(tagname, rise=(rise * PANGO_SCALE))
aniter = buf.get_end_iter() aniter = buf.get_end_iter()
buf.insert_pixbuf(aniter, icon) buf.insert_pixbuf(aniter, icon)
aniter.backward_char() aniter.backward_char()
enditer = buf.get_end_iter() enditer = buf.get_end_iter()
buf.apply_tag_by_name(tagname, aniter, enditer) buf.apply_tag_by_name(tagname, aniter, enditer)
# Stick in the buddy's nickname # Stick in the buddy's nickname
if not buf.get_tag_table().lookup("nickname"): if not buf.get_tag_table().lookup("nickname"):
buf.create_tag("nickname", weight=pango.WEIGHT_BOLD) buf.create_tag("nickname", weight=pango.WEIGHT_BOLD)
aniter = buf.get_end_iter() aniter = buf.get_end_iter()
offset = aniter.get_offset() offset = aniter.get_offset()
buf.insert(aniter, " " + buddy.get_name() + ": ") buf.insert(aniter, " " + buddy.get_name() + ": ")
enditer = buf.get_iter_at_offset(offset) enditer = buf.get_iter_at_offset(offset)
buf.apply_tag_by_name("nickname", aniter, enditer) buf.apply_tag_by_name("nickname", aniter, enditer)
def _insert_rich_message(self, buddy, msg): def _insert_rich_message(self, buddy, msg):
msg = Emoticons.get_instance().replace(msg) msg = Emoticons.get_instance().replace(msg)
buf = self._chat_view.get_buffer() buf = self._chat_view.get_buffer()
self._insert_buddy(buf, buddy) self._insert_buddy(buf, buddy)
serializer = richtext.RichTextSerializer() serializer = richtext.RichTextSerializer()
serializer.deserialize(msg, buf) serializer.deserialize(msg, buf)
aniter = buf.get_end_iter() aniter = buf.get_end_iter()
buf.insert(aniter, "\n") buf.insert(aniter, "\n")
self._message_inserted() self._message_inserted()
def _insert_sketch(self, buddy, svgdata): def _insert_sketch(self, buddy, svgdata):
"""Insert a sketch object into the chat buffer.""" """Insert a sketch object into the chat buffer."""
pbl = gtk.gdk.PixbufLoader("svg") pbl = gtk.gdk.PixbufLoader("svg")
pbl.write(svgdata) pbl.write(svgdata)
pbl.close() pbl.close()
pbuf = pbl.get_pixbuf() pbuf = pbl.get_pixbuf()
buf = self._chat_view.get_buffer() buf = self._chat_view.get_buffer()
self._insert_buddy(buf, buddy) self._insert_buddy(buf, buddy)
rise = int(pbuf.get_height() / 3) * -1 rise = int(pbuf.get_height() / 3) * -1
sha_hash = sha.new() sha_hash = sha.new()
sha_hash.update(svgdata) sha_hash.update(svgdata)
tagname = "sketch-%s" % sha_hash.hexdigest() tagname = "sketch-%s" % sha_hash.hexdigest()
if not buf.get_tag_table().lookup(tagname): if not buf.get_tag_table().lookup(tagname):
buf.create_tag(tagname, rise=(rise * PANGO_SCALE)) buf.create_tag(tagname, rise=(rise * PANGO_SCALE))
aniter = buf.get_end_iter() aniter = buf.get_end_iter()
buf.insert_pixbuf(aniter, pbuf) buf.insert_pixbuf(aniter, pbuf)
aniter.backward_char() aniter.backward_char()
enditer = buf.get_end_iter() enditer = buf.get_end_iter()
buf.apply_tag_by_name(tagname, aniter, enditer) buf.apply_tag_by_name(tagname, aniter, enditer)
aniter = buf.get_end_iter() aniter = buf.get_end_iter()
buf.insert(aniter, "\n") buf.insert(aniter, "\n")
self._message_inserted() self._message_inserted()
def _get_first_richtext_chunk(self, msg): def _get_first_richtext_chunk(self, msg):
"""Scan the message for the first richtext-tagged chunk and return it.""" """Scan the message for the first richtext-tagged chunk and return it."""
rt_last = -1 rt_last = -1
tag_rt_start = "<richtext>" tag_rt_start = "<richtext>"
tag_rt_end = "</richtext>" tag_rt_end = "</richtext>"
rt_first = msg.find(tag_rt_start) rt_first = msg.find(tag_rt_start)
length = -1 length = -1
if rt_first >= 0: if rt_first >= 0:
length = len(msg) length = len(msg)
rt_last = msg.find(tag_rt_end, rt_first) 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: 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 msg[rt_first:rt_last + len(tag_rt_end)]
return None return None
def _get_first_sketch_chunk(self, msg): def _get_first_sketch_chunk(self, msg):
"""Scan the message for the first SVG-tagged chunk and return it.""" """Scan the message for the first SVG-tagged chunk and return it."""
svg_last = -1 svg_last = -1
tag_svg_start = "<svg" tag_svg_start = "<svg"
tag_svg_end = "</svg>" tag_svg_end = "</svg>"
desc_start = msg.find("<?xml version='1.0' encoding='UTF-8'?>") desc_start = msg.find("<?xml version='1.0' encoding='UTF-8'?>")
if desc_start < 0: if desc_start < 0:
return None return None
ignore = msg.find("<!DOCTYPE svg") ignore = msg.find("<!DOCTYPE svg")
if ignore < 0: if ignore < 0:
return None return None
svg_first = msg.find(tag_svg_start) svg_first = msg.find(tag_svg_start)
length = -1 length = -1
if svg_first >= 0: if svg_first >= 0:
length = len(msg) length = len(msg)
svg_last = msg.find(tag_svg_end, svg_first) 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: 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 msg[desc_start:svg_last + len(tag_svg_end)]
return None return None
def recv_message(self, message): def recv_message(self, message):
"""Insert a remote chat message into the chat buffer.""" """Insert a remote chat message into the chat buffer."""
[nick, msg] = Chat.deserialize_message(message) [nick, msg] = Chat.deserialize_message(message)
buddy = self._pservice.get_buddy_by_name(nick) buddy = self._pservice.get_buddy_by_name(nick)
if not buddy: if not buddy:
logging.error('The buddy %s is not present.' % (nick)) logging.error('The buddy %s is not present.' % (nick))
return return
# FIXME a better way to compare buddies? # FIXME a better way to compare buddies?
owner = self._pservice.get_owner() owner = self._pservice.get_owner()
if buddy.get_name() == owner.get_name(): if buddy.get_name() == owner.get_name():
return return
chunk = self._get_first_richtext_chunk(msg) chunk = self._get_first_richtext_chunk(msg)
if chunk: if chunk:
self._insert_rich_message(buddy, chunk) self._insert_rich_message(buddy, chunk)
return return
chunk = self._get_first_sketch_chunk(msg) chunk = self._get_first_sketch_chunk(msg)
if chunk: if chunk:
self._insert_sketch(buddy, chunk) self._insert_sketch(buddy, chunk)
return return
def set_stream_writer(self, stream_writer): def set_stream_writer(self, stream_writer):
self._stream_writer = stream_writer self._stream_writer = stream_writer
def send_sketch(self, svgdata): def send_sketch(self, svgdata):
if not svgdata or not len(svgdata): if not svgdata or not len(svgdata):
return return
if self._stream_writer: if self._stream_writer:
self._stream_writer.write(self.serialize_message(svgdata)) self._stream_writer.write(self.serialize_message(svgdata))
owner = self._pservice.get_owner() owner = self._pservice.get_owner()
if owner: if owner:
self._insert_sketch(owner, svgdata) self._insert_sketch(owner, svgdata)
def send_text_message(self, text): def send_text_message(self, text):
"""Send a chat message and insert it into the local buffer.""" """Send a chat message and insert it into the local buffer."""
if len(text) <= 0: if len(text) <= 0:
return return
if self._stream_writer: if self._stream_writer:
self._stream_writer.write(self.serialize_message(text)) self._stream_writer.write(self.serialize_message(text))
else: else:
logging.warning("Cannot send message, there is no stream writer") logging.warning("Cannot send message, there is no stream writer")
owner = self._pservice.get_owner() owner = self._pservice.get_owner()
if owner: if owner:
self._insert_rich_message(owner, text) self._insert_rich_message(owner, text)
def serialize_message(self, message): def serialize_message(self, message):
owner = self._pservice.get_owner() owner = self._pservice.get_owner()
return owner.get_name() + '||' + message return owner.get_name() + '||' + message
def deserialize_message(message): def deserialize_message(message):
return message.split('||', 1) return message.split('||', 1)
deserialize_message = staticmethod(deserialize_message) deserialize_message = staticmethod(deserialize_message)

View File

@ -22,83 +22,83 @@ from sugar.chat.sketchpad.SketchPad import SketchPad
import richtext import richtext
class ChatEditor(gtk.HBox): class ChatEditor(gtk.HBox):
TEXT_MODE = 0 TEXT_MODE = 0
SKETCH_MODE = 1 SKETCH_MODE = 1
def __init__(self, chat, mode): def __init__(self, chat, mode):
gtk.HBox.__init__(self, False, 6) gtk.HBox.__init__(self, False, 6)
self._chat = chat self._chat = chat
self._notebook = gtk.Notebook() self._notebook = gtk.Notebook()
self._notebook.set_show_tabs(False) self._notebook.set_show_tabs(False)
self._notebook.set_show_border(False) self._notebook.set_show_border(False)
self._notebook.set_size_request(-1, 70) self._notebook.set_size_request(-1, 70)
chat_view_sw = gtk.ScrolledWindow() chat_view_sw = gtk.ScrolledWindow()
chat_view_sw.set_shadow_type(gtk.SHADOW_IN) chat_view_sw.set_shadow_type(gtk.SHADOW_IN)
chat_view_sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) chat_view_sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
self._text_view = richtext.RichTextView() self._text_view = richtext.RichTextView()
self._text_view.connect("key-press-event", self.__key_press_event_cb) self._text_view.connect("key-press-event", self.__key_press_event_cb)
chat_view_sw.add(self._text_view) chat_view_sw.add(self._text_view)
self._text_view.show() self._text_view.show()
self._notebook.append_page(chat_view_sw) self._notebook.append_page(chat_view_sw)
chat_view_sw.show() chat_view_sw.show()
self._sketchpad = SketchPad() self._sketchpad = SketchPad()
self._notebook.append_page(self._sketchpad) self._notebook.append_page(self._sketchpad)
self._sketchpad.show() self._sketchpad.show()
self.pack_start(self._notebook) self.pack_start(self._notebook)
self._notebook.show() self._notebook.show()
send_button = gtk.Button(_("Send")) send_button = gtk.Button(_("Send"))
send_button.set_size_request(60, -1) send_button.set_size_request(60, -1)
send_button.connect('clicked', self.__send_button_clicked_cb) send_button.connect('clicked', self.__send_button_clicked_cb)
self.pack_start(send_button, False, True) self.pack_start(send_button, False, True)
send_button.show() send_button.show()
self.set_mode(mode) self.set_mode(mode)
def set_color(self, color): def set_color(self, color):
self._sketchpad.set_color(color) self._sketchpad.set_color(color)
def get_buffer(self): def get_buffer(self):
return self._text_view.get_buffer() return self._text_view.get_buffer()
def set_mode(self, mode): def set_mode(self, mode):
self._mode = mode self._mode = mode
if self._mode == ChatEditor.SKETCH_MODE: if self._mode == ChatEditor.SKETCH_MODE:
self._notebook.set_current_page(1) self._notebook.set_current_page(1)
elif self._mode == ChatEditor.TEXT_MODE: elif self._mode == ChatEditor.TEXT_MODE:
self._notebook.set_current_page(0) self._notebook.set_current_page(0)
def __send_button_clicked_cb(self, button): def __send_button_clicked_cb(self, button):
self._send() self._send()
def _send(self): def _send(self):
if self._mode == ChatEditor.SKETCH_MODE: if self._mode == ChatEditor.SKETCH_MODE:
self._send_sketch() self._send_sketch()
elif self._mode == ChatEditor.TEXT_MODE: elif self._mode == ChatEditor.TEXT_MODE:
self._send_text() self._send_text()
def _send_sketch(self): def _send_sketch(self):
self._chat.send_sketch(self._sketchpad.to_svg()) self._chat.send_sketch(self._sketchpad.to_svg())
self._sketchpad.clear() self._sketchpad.clear()
def _send_text(self): def _send_text(self):
buf = self._text_view.get_buffer() buf = self._text_view.get_buffer()
text = buf.get_text(buf.get_start_iter(), buf.get_end_iter()) text = buf.get_text(buf.get_start_iter(), buf.get_end_iter())
if len(text.strip()) > 0: if len(text.strip()) > 0:
serializer = richtext.RichTextSerializer() serializer = richtext.RichTextSerializer()
text = serializer.serialize(buf) text = serializer.serialize(buf)
self._chat.send_text_message(text) self._chat.send_text_message(text)
buf.set_text("") buf.set_text("")
buf.place_cursor(buf.get_start_iter()) buf.place_cursor(buf.get_start_iter())
def __key_press_event_cb(self, text_view, event): def __key_press_event_cb(self, text_view, event):
if event.keyval == gtk.keysyms.Return: if event.keyval == gtk.keysyms.Return:
self._send() self._send()
return True return True

View File

@ -22,129 +22,129 @@ from sugar.chat.sketchpad.Toolbox import Toolbox
import richtext import richtext
class ChatToolbar(gtk.HBox): class ChatToolbar(gtk.HBox):
def __init__(self, editor): def __init__(self, editor):
gtk.HBox.__init__(self, False, 24) gtk.HBox.__init__(self, False, 24)
self._editor = editor self._editor = editor
self._emt_popup = None self._emt_popup = None
spring = gtk.Label('') spring = gtk.Label('')
self.pack_start(spring, True) self.pack_start(spring, True)
spring.show() spring.show()
toolbox = richtext.RichTextToolbox(editor.get_buffer()) toolbox = richtext.RichTextToolbox(editor.get_buffer())
self.pack_start(toolbox, False) self.pack_start(toolbox, False)
toolbox.show() toolbox.show()
item = gtk.Button() item = gtk.Button()
item.unset_flags(gtk.CAN_FOCUS) item.unset_flags(gtk.CAN_FOCUS)
e_hbox = gtk.HBox(False, 6) e_hbox = gtk.HBox(False, 6)
e_image = gtk.Image() e_image = gtk.Image()
e_image.set_from_icon_name('stock_smiley-1', gtk.ICON_SIZE_SMALL_TOOLBAR) e_image.set_from_icon_name('stock_smiley-1', gtk.ICON_SIZE_SMALL_TOOLBAR)
e_hbox.pack_start(e_image) e_hbox.pack_start(e_image)
e_image.show() e_image.show()
arrow = gtk.Arrow(gtk.ARROW_DOWN, gtk.SHADOW_NONE) arrow = gtk.Arrow(gtk.ARROW_DOWN, gtk.SHADOW_NONE)
e_hbox.pack_start(arrow) e_hbox.pack_start(arrow)
arrow.show() arrow.show()
item.set_image(e_hbox) item.set_image(e_hbox)
item.connect("clicked", self.__emoticons_button_clicked_cb) item.connect("clicked", self.__emoticons_button_clicked_cb)
toolbox.pack_start(item, False) toolbox.pack_start(item, False)
item.show() item.show()
# separator = gtk.SeparatorToolItem() # separator = gtk.SeparatorToolItem()
# toolbar.insert(separator, -1) # toolbar.insert(separator, -1)
# separator.show() # separator.show()
# item = gtk.MenuToolButton(None, "Links") # item = gtk.MenuToolButton(None, "Links")
# item.set_menu(gtk.Menu()) # item.set_menu(gtk.Menu())
# item.connect("show-menu", self.__show_link_menu_cb) # item.connect("show-menu", self.__show_link_menu_cb)
# toolbar.insert(item, -1) # toolbar.insert(item, -1)
# item.show() # item.show()
toolbox = Toolbox() toolbox = Toolbox()
toolbox.connect('color-selected', self._color_selected) toolbox.connect('color-selected', self._color_selected)
self.pack_start(toolbox, False) self.pack_start(toolbox, False)
toolbox.show() toolbox.show()
spring = gtk.Label('') spring = gtk.Label('')
self.pack_start(spring, True) self.pack_start(spring, True)
spring.show() spring.show()
def _color_selected(self, toolbox, color): def _color_selected(self, toolbox, color):
self._editor.set_color(color) self._editor.set_color(color)
def __link_activate_cb(self, item, link): def __link_activate_cb(self, item, link):
buf = self._editor.get_buffer() buf = self._editor.get_buffer()
buf.append_link(link['title'], link['address']) buf.append_link(link['title'], link['address'])
def __show_link_menu_cb(self, button): def __show_link_menu_cb(self, button):
menu = gtk.Menu() menu = gtk.Menu()
links = self.__get_browser_shell().get_links() links = self.__get_browser_shell().get_links()
for link in links: for link in links:
item = gtk.MenuItem(link['title'], False) item = gtk.MenuItem(link['title'], False)
item.connect("activate", self.__link_activate_cb, link) item.connect("activate", self.__link_activate_cb, link)
menu.append(item) menu.append(item)
item.show() item.show()
button.set_menu(menu) button.set_menu(menu)
def _create_emoticons_popup(self): def _create_emoticons_popup(self):
model = gtk.ListStore(gtk.gdk.Pixbuf, str) model = gtk.ListStore(gtk.gdk.Pixbuf, str)
for name in Emoticons.get_instance().get_all(): for name in Emoticons.get_instance().get_all():
icon_theme = gtk.icon_theme_get_default() icon_theme = gtk.icon_theme_get_default()
try: try:
pixbuf = icon_theme.load_icon(name, 16, 0) pixbuf = icon_theme.load_icon(name, 16, 0)
model.append([pixbuf, name]) model.append([pixbuf, name])
except gobject.GError: except gobject.GError:
pass pass
icon_view = gtk.IconView(model) icon_view = gtk.IconView(model)
icon_view.connect('selection-changed', self.__emoticon_selection_changed_cb) icon_view.connect('selection-changed', self.__emoticon_selection_changed_cb)
icon_view.set_pixbuf_column(0) icon_view.set_pixbuf_column(0)
icon_view.set_selection_mode(gtk.SELECTION_SINGLE) icon_view.set_selection_mode(gtk.SELECTION_SINGLE)
frame = gtk.Frame() frame = gtk.Frame()
frame.set_shadow_type(gtk.SHADOW_ETCHED_IN) frame.set_shadow_type(gtk.SHADOW_ETCHED_IN)
frame.add(icon_view) frame.add(icon_view)
icon_view.show() icon_view.show()
window = gtk.Window(gtk.WINDOW_POPUP) window = gtk.Window(gtk.WINDOW_POPUP)
window.add(frame) window.add(frame)
frame.show() frame.show()
return window return window
def __emoticon_selection_changed_cb(self, icon_view): def __emoticon_selection_changed_cb(self, icon_view):
items = icon_view.get_selected_items() items = icon_view.get_selected_items()
if items: if items:
model = icon_view.get_model() model = icon_view.get_model()
icon_name = model[items[0]][1] icon_name = model[items[0]][1]
self._editor.get_buffer().append_icon(icon_name) self._editor.get_buffer().append_icon(icon_name)
self._emt_popup.hide() self._emt_popup.hide()
def __emoticons_button_clicked_cb(self, button): def __emoticons_button_clicked_cb(self, button):
# FIXME grabs... # FIXME grabs...
if not self._emt_popup: if not self._emt_popup:
self._emt_popup = self._create_emoticons_popup() self._emt_popup = self._create_emoticons_popup()
if self._emt_popup.get_property('visible'): if self._emt_popup.get_property('visible'):
self._emt_popup.hide() self._emt_popup.hide()
else: else:
width = 180 width = 180
height = 130 height = 130
self._emt_popup.set_default_size(width, height) self._emt_popup.set_default_size(width, height)
[x, y] = button.window.get_origin() [x, y] = button.window.get_origin()
x += button.allocation.x x += button.allocation.x
y += button.allocation.y - height y += button.allocation.y - height
self._emt_popup.move(x, y) self._emt_popup.move(x, y)
self._emt_popup.show() self._emt_popup.show()

View File

@ -15,70 +15,70 @@
# Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA. # Boston, MA 02111-1307, USA.
emoticons_table = [ \ emoticons_table = [ \
[ 'stock_smiley-10', [ ':P', ':p' ] ], \ [ 'stock_smiley-10', [ ':P', ':p' ] ], \
[ 'stock_smiley-19', None ], \ [ 'stock_smiley-19', None ], \
[ 'stock_smiley-2', None ], \ [ 'stock_smiley-2', None ], \
[ 'stock_smiley-11', None ], \ [ 'stock_smiley-11', None ], \
[ 'stock_smiley-1', [ ':)' ] ], \ [ 'stock_smiley-1', [ ':)' ] ], \
[ 'stock_smiley-3', None ], \ [ 'stock_smiley-3', None ], \
[ 'stock_smiley-12', None ], \ [ 'stock_smiley-12', None ], \
[ 'stock_smiley-20', None ], \ [ 'stock_smiley-20', None ], \
[ 'stock_smiley-4', [ ':(' ] ], \ [ 'stock_smiley-4', [ ':(' ] ], \
[ 'stock_smiley-13', None ], \ [ 'stock_smiley-13', None ], \
[ 'stock_smiley-21', None ], \ [ 'stock_smiley-21', None ], \
[ 'stock_smiley-5', None ], \ [ 'stock_smiley-5', None ], \
[ 'stock_smiley-14', None ], \ [ 'stock_smiley-14', None ], \
[ 'stock_smiley-22', None ], \ [ 'stock_smiley-22', None ], \
[ 'stock_smiley-6', None ], \ [ 'stock_smiley-6', None ], \
[ 'stock_smiley-15', None ], \ [ 'stock_smiley-15', None ], \
[ 'stock_smiley-23', None ], \ [ 'stock_smiley-23', None ], \
[ 'stock_smiley-7', None ], \ [ 'stock_smiley-7', None ], \
[ 'stock_smiley-16', None ], \ [ 'stock_smiley-16', None ], \
[ 'stock_smiley-24', None ], \ [ 'stock_smiley-24', None ], \
[ 'stock_smiley-8', None ], \ [ 'stock_smiley-8', None ], \
[ 'stock_smiley-17', None ], \ [ 'stock_smiley-17', None ], \
[ 'stock_smiley-25', None ], \ [ 'stock_smiley-25', None ], \
[ 'stock_smiley-9', None ], \ [ 'stock_smiley-9', None ], \
[ 'stock_smiley-18', None ], \ [ 'stock_smiley-18', None ], \
[ 'stock_smiley-26', None ], \ [ 'stock_smiley-26', None ], \
] ]
class Emoticons: class Emoticons:
instance = None instance = None
def get_instance(): def get_instance():
if not Emoticons.instance: if not Emoticons.instance:
Emoticons.instance = Emoticons() Emoticons.instance = Emoticons()
return Emoticons.instance return Emoticons.instance
get_instance = staticmethod(get_instance) get_instance = staticmethod(get_instance)
def __init__(self): def __init__(self):
self._table = {} self._table = {}
for emoticon in emoticons_table: for emoticon in emoticons_table:
[ name, text_emts ] = emoticon [ name, text_emts ] = emoticon
self.add(name, text_emts) self.add(name, text_emts)
def add(self, icon_name, text=None): def add(self, icon_name, text=None):
self._table[icon_name] = text self._table[icon_name] = text
def get_all(self): def get_all(self):
return self._table.keys() return self._table.keys()
"""Replace emoticons text with the icon name. """Replace emoticons text with the icon name.
Parse the provided text to find emoticons (in Parse the provided text to find emoticons (in
textual form) and replace them with their xml textual form) and replace them with their xml
representation in the form: representation in the form:
<icon name="$EMOTICON_ICON_NAME"/> <icon name="$EMOTICON_ICON_NAME"/>
""" """
def replace(self, text): def replace(self, text):
for icon_name in self._table.keys(): for icon_name in self._table.keys():
text_emts = self._table[icon_name] text_emts = self._table[icon_name]
if text_emts: if text_emts:
for emoticon_text in text_emts: for emoticon_text in text_emts:
xml = '<icon name="' + icon_name + '"/>' xml = '<icon name="' + icon_name + '"/>'
text = text.replace(emoticon_text, xml) text = text.replace(emoticon_text, xml)
return text return text

View File

@ -23,15 +23,15 @@ from sugar.presence.PresenceService import PresenceService
import sugar.env import sugar.env
class GroupChat(Chat): class GroupChat(Chat):
def __init__(self): def __init__(self):
Chat.__init__(self) Chat.__init__(self)
self._group_stream = None self._group_stream = None
def _setup_stream(self, service): def _setup_stream(self, service):
self._group_stream = Stream.new_from_service(service) self._group_stream = Stream.new_from_service(service)
self._group_stream.set_data_listener(self._group_recv_message) self._group_stream.set_data_listener(self._group_recv_message)
self._stream_writer = self._group_stream.new_writer() self._stream_writer = self._group_stream.new_writer()
def _group_recv_message(self, address, msg): def _group_recv_message(self, address, msg):
logging.debug('Group chat received from %s message %s' % (address, msg)) logging.debug('Group chat received from %s message %s' % (address, msg))
self.recv_message(msg) self.recv_message(msg)

View File

@ -21,431 +21,431 @@ import pango
import xml.sax import xml.sax
class RichTextView(gtk.TextView): class RichTextView(gtk.TextView):
__gsignals__ = { __gsignals__ = {
'link-clicked': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, 'link-clicked': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([gobject.TYPE_STRING])) ([gobject.TYPE_STRING]))
} }
def __init__(self): def __init__(self):
gtk.TextView.__init__(self, RichTextBuffer()) gtk.TextView.__init__(self, RichTextBuffer())
self.connect("motion-notify-event", self.__motion_notify_cb) self.connect("motion-notify-event", self.__motion_notify_cb)
self.connect("button-press-event", self.__button_press_cb) self.connect("button-press-event", self.__button_press_cb)
self.__hover_link = False self.__hover_link = False
def _set_hover_link(self, hover_link): def _set_hover_link(self, hover_link):
if hover_link != self.__hover_link: if hover_link != self.__hover_link:
self.__hover_link = hover_link self.__hover_link = hover_link
display = self.get_toplevel().get_display() display = self.get_toplevel().get_display()
child_window = self.get_window(gtk.TEXT_WINDOW_TEXT) child_window = self.get_window(gtk.TEXT_WINDOW_TEXT)
if hover_link: if hover_link:
cursor = gtk.gdk.Cursor(display, gtk.gdk.HAND2) cursor = gtk.gdk.Cursor(display, gtk.gdk.HAND2)
else: else:
cursor = gtk.gdk.Cursor(display, gtk.gdk.XTERM) cursor = gtk.gdk.Cursor(display, gtk.gdk.XTERM)
child_window.set_cursor(cursor) child_window.set_cursor(cursor)
gtk.gdk.flush() gtk.gdk.flush()
def __iter_is_link(self, it): def __iter_is_link(self, it):
item = self.get_buffer().get_tag_table().lookup("link") item = self.get_buffer().get_tag_table().lookup("link")
if item: if item:
return it.has_tag(item) return it.has_tag(item)
return False return False
def __get_event_iter(self, event): def __get_event_iter(self, event):
return self.get_iter_at_location(int(event.x), int(event.y)) return self.get_iter_at_location(int(event.x), int(event.y))
def __motion_notify_cb(self, widget, event): def __motion_notify_cb(self, widget, event):
if event.is_hint: if event.is_hint:
event.window.get_pointer(); event.window.get_pointer();
it = self.__get_event_iter(event) it = self.__get_event_iter(event)
if it: if it:
hover_link = self.__iter_is_link(it) hover_link = self.__iter_is_link(it)
else: else:
hover_link = False hover_link = False
self._set_hover_link(hover_link) self._set_hover_link(hover_link)
def __button_press_cb(self, widget, event): def __button_press_cb(self, widget, event):
it = self.__get_event_iter(event) it = self.__get_event_iter(event)
if it and self.__iter_is_link(it): if it and self.__iter_is_link(it):
buf = self.get_buffer() buf = self.get_buffer()
address_tag = buf.get_tag_table().lookup("object-id") address_tag = buf.get_tag_table().lookup("object-id")
address_end = it.copy() address_end = it.copy()
address_end.backward_to_tag_toggle(address_tag) address_end.backward_to_tag_toggle(address_tag)
address_start = address_end.copy() address_start = address_end.copy()
address_start.backward_to_tag_toggle(address_tag) address_start.backward_to_tag_toggle(address_tag)
address = buf.get_text(address_start, address_end) address = buf.get_text(address_start, address_end)
self.emit("link-clicked", address) self.emit("link-clicked", address)
class RichTextBuffer(gtk.TextBuffer): class RichTextBuffer(gtk.TextBuffer):
def __init__(self): def __init__(self):
gtk.TextBuffer.__init__(self) gtk.TextBuffer.__init__(self)
self.connect_after("insert-text", self.__insert_text_cb) self.connect_after("insert-text", self.__insert_text_cb)
self.__create_tags() self.__create_tags()
self.active_tags = [] self.active_tags = []
def append_link(self, title, address): def append_link(self, title, address):
it = self.get_iter_at_mark(self.get_insert()) 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, address, "link", "object-id")
self.insert_with_tags_by_name(it, title, "link") self.insert_with_tags_by_name(it, title, "link")
def append_icon(self, name, it = None): def append_icon(self, name, it = None):
if not it: if not it:
it = self.get_iter_at_mark(self.get_insert()) it = self.get_iter_at_mark(self.get_insert())
self.insert_with_tags_by_name(it, name, "icon", "object-id") self.insert_with_tags_by_name(it, name, "icon", "object-id")
icon_theme = gtk.icon_theme_get_default() icon_theme = gtk.icon_theme_get_default()
try: try:
pixbuf = icon_theme.load_icon(name, 16, 0) pixbuf = icon_theme.load_icon(name, 16, 0)
self.insert_pixbuf(it, pixbuf) self.insert_pixbuf(it, pixbuf)
except gobject.GError: except gobject.GError:
pass pass
def apply_tag(self, tag_name): def apply_tag(self, tag_name):
self.active_tags.append(tag_name) self.active_tags.append(tag_name)
bounds = self.get_selection_bounds() bounds = self.get_selection_bounds()
if bounds: if bounds:
[start, end] = bounds [start, end] = bounds
self.apply_tag_by_name(tag_name, start, end) self.apply_tag_by_name(tag_name, start, end)
def unapply_tag(self, tag_name): def unapply_tag(self, tag_name):
self.active_tags.remove(tag_name) self.active_tags.remove(tag_name)
bounds = self.get_selection_bounds() bounds = self.get_selection_bounds()
if bounds: if bounds:
[start, end] = bounds [start, end] = bounds
self.remove_tag_by_name(tag_name, start, end) self.remove_tag_by_name(tag_name, start, end)
def __create_tags(self): def __create_tags(self):
tag = self.create_tag("icon") tag = self.create_tag("icon")
tag = self.create_tag("link") tag = self.create_tag("link")
tag.set_property("underline", pango.UNDERLINE_SINGLE) tag.set_property("underline", pango.UNDERLINE_SINGLE)
tag.set_property("foreground", "#0000FF") tag.set_property("foreground", "#0000FF")
tag = self.create_tag("object-id") tag = self.create_tag("object-id")
tag.set_property("invisible", True) tag.set_property("invisible", True)
tag = self.create_tag("bold") tag = self.create_tag("bold")
tag.set_property("weight", pango.WEIGHT_BOLD) tag.set_property("weight", pango.WEIGHT_BOLD)
tag = self.create_tag("italic") tag = self.create_tag("italic")
tag.set_property("style", pango.STYLE_ITALIC) tag.set_property("style", pango.STYLE_ITALIC)
tag = self.create_tag("font-size-xx-small") tag = self.create_tag("font-size-xx-small")
tag.set_property("scale", pango.SCALE_XX_SMALL) tag.set_property("scale", pango.SCALE_XX_SMALL)
tag = self.create_tag("font-size-x-small") tag = self.create_tag("font-size-x-small")
tag.set_property("scale", pango.SCALE_X_SMALL) tag.set_property("scale", pango.SCALE_X_SMALL)
tag = self.create_tag("font-size-small") tag = self.create_tag("font-size-small")
tag.set_property("scale", pango.SCALE_SMALL) tag.set_property("scale", pango.SCALE_SMALL)
tag = self.create_tag("font-size-large") tag = self.create_tag("font-size-large")
tag.set_property("scale", pango.SCALE_LARGE) tag.set_property("scale", pango.SCALE_LARGE)
tag = self.create_tag("font-size-x-large") tag = self.create_tag("font-size-x-large")
tag.set_property("scale", pango.SCALE_X_LARGE) tag.set_property("scale", pango.SCALE_X_LARGE)
tag = self.create_tag("font-size-xx-large") tag = self.create_tag("font-size-xx-large")
tag.set_property("scale", pango.SCALE_XX_LARGE) tag.set_property("scale", pango.SCALE_XX_LARGE)
def __insert_text_cb(self, widget, pos, text, length): def __insert_text_cb(self, widget, pos, text, length):
for tag in self.active_tags: for tag in self.active_tags:
pos_end = pos.copy() pos_end = pos.copy()
pos_end.backward_chars(length) pos_end.backward_chars(length)
self.apply_tag_by_name(tag, pos, pos_end) self.apply_tag_by_name(tag, pos, pos_end)
class RichTextToolbox(gtk.HBox): class RichTextToolbox(gtk.HBox):
def __init__(self, buf): def __init__(self, buf):
gtk.HBox.__init__(self, False, 6) gtk.HBox.__init__(self, False, 6)
self.buf = buf self.buf = buf
self._font_size = "normal" self._font_size = "normal"
self._font_scales = [ "xx-small", "x-small", "small", \ self._font_scales = [ "xx-small", "x-small", "small", \
"normal", \ "normal", \
"large", "x-large", "xx-large" ] "large", "x-large", "xx-large" ]
image = gtk.Image() image = gtk.Image()
image.set_from_stock(gtk.STOCK_BOLD, gtk.ICON_SIZE_SMALL_TOOLBAR) image.set_from_stock(gtk.STOCK_BOLD, gtk.ICON_SIZE_SMALL_TOOLBAR)
item = gtk.ToggleButton() item = gtk.ToggleButton()
item.set_image(image) item.set_image(image)
item.connect("toggled", self.__toggle_style_cb, "bold") item.connect("toggled", self.__toggle_style_cb, "bold")
item.unset_flags(gtk.CAN_FOCUS) item.unset_flags(gtk.CAN_FOCUS)
self.pack_start(item, False) self.pack_start(item, False)
item.show() item.show()
image.show() image.show()
image = gtk.Image() image = gtk.Image()
image.set_from_stock(gtk.STOCK_ITALIC, gtk.ICON_SIZE_SMALL_TOOLBAR) image.set_from_stock(gtk.STOCK_ITALIC, gtk.ICON_SIZE_SMALL_TOOLBAR)
item = gtk.ToggleButton() item = gtk.ToggleButton()
item.set_image(image) item.set_image(image)
item.unset_flags(gtk.CAN_FOCUS) item.unset_flags(gtk.CAN_FOCUS)
item.connect("toggled", self.__toggle_style_cb, "italic") item.connect("toggled", self.__toggle_style_cb, "italic")
self.pack_start(item, False) self.pack_start(item, False)
item.show() item.show()
image = gtk.Image() image = gtk.Image()
image.set_from_stock(gtk.STOCK_GO_UP, gtk.ICON_SIZE_SMALL_TOOLBAR) image.set_from_stock(gtk.STOCK_GO_UP, gtk.ICON_SIZE_SMALL_TOOLBAR)
self._font_size_up = gtk.Button() self._font_size_up = gtk.Button()
self._font_size_up.set_image(image) self._font_size_up.set_image(image)
self._font_size_up.unset_flags(gtk.CAN_FOCUS) self._font_size_up.unset_flags(gtk.CAN_FOCUS)
self._font_size_up.connect("clicked", self.__font_size_up_cb) self._font_size_up.connect("clicked", self.__font_size_up_cb)
self.pack_start(self._font_size_up, False) self.pack_start(self._font_size_up, False)
self._font_size_up.show() self._font_size_up.show()
image.show() image.show()
image = gtk.Image() image = gtk.Image()
image.set_from_stock(gtk.STOCK_GO_DOWN, gtk.ICON_SIZE_SMALL_TOOLBAR) image.set_from_stock(gtk.STOCK_GO_DOWN, gtk.ICON_SIZE_SMALL_TOOLBAR)
self._font_size_down = gtk.Button() self._font_size_down = gtk.Button()
self._font_size_down.set_image(image) self._font_size_down.set_image(image)
self._font_size_down.unset_flags(gtk.CAN_FOCUS) self._font_size_down.unset_flags(gtk.CAN_FOCUS)
self._font_size_down.connect("clicked", self.__font_size_down_cb) self._font_size_down.connect("clicked", self.__font_size_down_cb)
self.pack_start(self._font_size_down, False) self.pack_start(self._font_size_down, False)
self._font_size_down.show() self._font_size_down.show()
image.show() image.show()
def _get_font_size_index(self): def _get_font_size_index(self):
return self._font_scales.index(self._font_size); return self._font_scales.index(self._font_size);
def __toggle_style_cb(self, toggle, tag_name): def __toggle_style_cb(self, toggle, tag_name):
if toggle.get_active(): if toggle.get_active():
self.buf.apply_tag(tag_name) self.buf.apply_tag(tag_name)
else: else:
self.buf.unapply_tag(tag_name) self.buf.unapply_tag(tag_name)
def _set_font_size(self, font_size): def _set_font_size(self, font_size):
if self._font_size != "normal": if self._font_size != "normal":
self.buf.unapply_tag("font-size-" + self._font_size) self.buf.unapply_tag("font-size-" + self._font_size)
if font_size != "normal": if font_size != "normal":
self.buf.apply_tag("font-size-" + font_size) self.buf.apply_tag("font-size-" + font_size)
self._font_size = font_size self._font_size = font_size
can_up = self._get_font_size_index() < len(self._font_scales) - 1 can_up = self._get_font_size_index() < len(self._font_scales) - 1
can_down = self._get_font_size_index() > 0 can_down = self._get_font_size_index() > 0
self._font_size_up.set_sensitive(can_up) self._font_size_up.set_sensitive(can_up)
self._font_size_down.set_sensitive(can_down) self._font_size_down.set_sensitive(can_down)
def __font_size_up_cb(self, button): def __font_size_up_cb(self, button):
index = self._get_font_size_index() index = self._get_font_size_index()
if index + 1 < len(self._font_scales): if index + 1 < len(self._font_scales):
self._set_font_size(self._font_scales[index + 1]) self._set_font_size(self._font_scales[index + 1])
def __font_size_down_cb(self, button): def __font_size_down_cb(self, button):
index = self._get_font_size_index() index = self._get_font_size_index()
if index > 0: if index > 0:
self._set_font_size(self._font_scales[index - 1]) self._set_font_size(self._font_scales[index - 1])
class RichTextHandler(xml.sax.handler.ContentHandler): class RichTextHandler(xml.sax.handler.ContentHandler):
def __init__(self, serializer, buf): def __init__(self, serializer, buf):
xml.sax.handler.ContentHandler.__init__(self) xml.sax.handler.ContentHandler.__init__(self)
self.buf = buf self.buf = buf
self.serializer = serializer self.serializer = serializer
self.tags = [] self.tags = []
self._in_richtext = False self._in_richtext = False
self._done = False self._done = False
def startElement(self, name, attrs): def startElement(self, name, attrs):
# Look for, and only start parsing after 'richtext' # Look for, and only start parsing after 'richtext'
if not self._in_richtext and name == "richtext": if not self._in_richtext and name == "richtext":
self._in_richtext = True self._in_richtext = True
if not self._in_richtext: if not self._in_richtext:
return return
if name != "richtext": if name != "richtext":
tag = self.serializer.deserialize_element(name, attrs) tag = self.serializer.deserialize_element(name, attrs)
self.tags.append(tag) self.tags.append(tag)
if name == "link": if name == "link":
self.href = attrs['href'] self.href = attrs['href']
elif name == "icon": elif name == "icon":
self.buf.append_icon(attrs['name'], self.buf.get_end_iter()) self.buf.append_icon(attrs['name'], self.buf.get_end_iter())
def characters(self, data): def characters(self, data):
start_it = it = self.buf.get_end_iter() start_it = it = self.buf.get_end_iter()
mark = self.buf.create_mark(None, start_it, True) mark = self.buf.create_mark(None, start_it, True)
self.buf.insert(it, data) self.buf.insert(it, data)
start_it = self.buf.get_iter_at_mark(mark) start_it = self.buf.get_iter_at_mark(mark)
for tag in self.tags: for tag in self.tags:
self.buf.apply_tag_by_name(tag, start_it, it) self.buf.apply_tag_by_name(tag, start_it, it)
if tag == "link": if tag == "link":
self.buf.insert_with_tags_by_name(start_it, self.href, self.buf.insert_with_tags_by_name(start_it, self.href,
"link", "object-id") "link", "object-id")
def endElement(self, name): def endElement(self, name):
if not self._done and self._in_richtext: if not self._done and self._in_richtext:
if name != "richtext": if name != "richtext":
self.tags.pop() self.tags.pop()
if name == "richtext": if name == "richtext":
self._done = True self._done = True
self._in_richtext = False self._in_richtext = False
class RichTextSerializer: class RichTextSerializer:
def __init__(self): def __init__(self):
self._open_tags = [] self._open_tags = []
def deserialize_element(self, el_name, attributes): def deserialize_element(self, el_name, attributes):
if el_name == "bold": if el_name == "bold":
return "bold" return "bold"
elif el_name == "italic": elif el_name == "italic":
return "italic" return "italic"
elif el_name == "font": elif el_name == "font":
return "font-size-" + attributes["size"] return "font-size-" + attributes["size"]
elif el_name == "link": elif el_name == "link":
return "link" return "link"
elif el_name == "icon": elif el_name == "icon":
return "icon" return "icon"
else: else:
return None return None
def _parse_object_id(self, it): def _parse_object_id(self, it):
object_id_tag = self.buf.get_tag_table().lookup("object-id") object_id_tag = self.buf.get_tag_table().lookup("object-id")
end = it.copy() end = it.copy()
end.forward_to_tag_toggle(object_id_tag) end.forward_to_tag_toggle(object_id_tag)
return self.buf.get_text(it, end) return self.buf.get_text(it, end)
def serialize_tag_start(self, tag, it): def serialize_tag_start(self, tag, it):
name = tag.get_property("name") name = tag.get_property("name")
if name == "bold": if name == "bold":
return "<bold>" return "<bold>"
elif name == "italic": elif name == "italic":
return "<italic>" return "<italic>"
elif name == "link": elif name == "link":
address = self._parse_object_id(it) address = self._parse_object_id(it)
return "<link " + "href=\"" + address + "\">" return "<link " + "href=\"" + address + "\">"
elif name == "icon": elif name == "icon":
name = self._parse_object_id(it) name = self._parse_object_id(it)
return "<icon " + "name=\"" + name + "\"/>" return "<icon " + "name=\"" + name + "\"/>"
elif name == "object-id": elif name == "object-id":
return "" return ""
elif name.startswith("font-size-"): elif name.startswith("font-size-"):
tag_name = name.replace("font-size-", "", 1) tag_name = name.replace("font-size-", "", 1)
return "<font size=\"" + tag_name + "\">" return "<font size=\"" + tag_name + "\">"
else: else:
return "<unknown>" return "<unknown>"
def serialize_tag_end(self, tag): def serialize_tag_end(self, tag):
name = tag.get_property("name") name = tag.get_property("name")
if name == "bold": if name == "bold":
return "</bold>" return "</bold>"
elif name == "italic": elif name == "italic":
return "</italic>" return "</italic>"
elif name == "link": elif name == "link":
return "</link>" return "</link>"
elif name == "icon": elif name == "icon":
return "" return ""
elif name == "object-id": elif name == "object-id":
return "" return ""
elif name.startswith("font-size-"): elif name.startswith("font-size-"):
return "</font>" return "</font>"
else: else:
return "</unknown>" return "</unknown>"
def serialize(self, buf): def serialize(self, buf):
self.buf = buf self.buf = buf
res = "<richtext>" res = "<richtext>"
next_it = buf.get_start_iter() next_it = buf.get_start_iter()
while not next_it.is_end(): while not next_it.is_end():
it = next_it.copy() it = next_it.copy()
if not next_it.forward_to_tag_toggle(None): if not next_it.forward_to_tag_toggle(None):
next_it = buf.get_end_iter() next_it = buf.get_end_iter()
tags_to_reopen = [] tags_to_reopen = []
for tag in it.get_toggled_tags(False): for tag in it.get_toggled_tags(False):
while 1: while 1:
open_tag = self._open_tags.pop() open_tag = self._open_tags.pop()
res += self.serialize_tag_end(tag) res += self.serialize_tag_end(tag)
if open_tag == tag: if open_tag == tag:
break break
tags_to_reopen.append(open_tag) tags_to_reopen.append(open_tag)
for tag in tags_to_reopen: for tag in tags_to_reopen:
self._open_tags.append(tag) self._open_tags.append(tag)
res += self.serialize_tag_start(tag, it) res += self.serialize_tag_start(tag, it)
for tag in it.get_toggled_tags(True): for tag in it.get_toggled_tags(True):
self._open_tags.append(tag) self._open_tags.append(tag)
res += self.serialize_tag_start(tag, it) res += self.serialize_tag_start(tag, it)
res += buf.get_text(it, next_it, False) res += buf.get_text(it, next_it, False)
if next_it.is_end(): if next_it.is_end():
self._open_tags.reverse() self._open_tags.reverse()
for tag in self._open_tags: for tag in self._open_tags:
res += self.serialize_tag_end(tag) res += self.serialize_tag_end(tag)
res += "</richtext>" res += "</richtext>"
return res return res
def deserialize(self, xml_string, buf): def deserialize(self, xml_string, buf):
parser = xml.sax.make_parser() parser = xml.sax.make_parser()
handler = RichTextHandler(self, buf) handler = RichTextHandler(self, buf)
parser.setContentHandler(handler) parser.setContentHandler(handler)
parser.feed(xml_string) parser.feed(xml_string)
parser.close() parser.close()
def test_quit(w, rb): def test_quit(w, rb):
print RichTextSerializer().serialize(rb) print RichTextSerializer().serialize(rb)
gtk.main_quit() gtk.main_quit()
def link_clicked(v, address): def link_clicked(v, address):
print "Link clicked " + address print "Link clicked " + address
if __name__ == "__main__": if __name__ == "__main__":
window = gtk.Window() window = gtk.Window()
window.set_default_size(400, 300) window.set_default_size(400, 300)
vbox = gtk.VBox() vbox = gtk.VBox()
view = RichTextView() view = RichTextView()
view.connect("link-clicked", link_clicked) view.connect("link-clicked", link_clicked)
vbox.pack_start(view) vbox.pack_start(view)
view.show() view.show()
rich_buf = view.get_buffer() rich_buf = view.get_buffer()
test_xml = "<richtext>" test_xml = "<richtext>"
test_xml += "<bold><italic>Test</italic>one</bold>\n" test_xml += "<bold><italic>Test</italic>one</bold>\n"
test_xml += "<bold><italic>Test two</italic></bold>" test_xml += "<bold><italic>Test two</italic></bold>"
test_xml += "<font size=\"xx-small\">Test three</font>" test_xml += "<font size=\"xx-small\">Test three</font>"
test_xml += "<link href=\"http://www.gnome.org\">Test link</link>" test_xml += "<link href=\"http://www.gnome.org\">Test link</link>"
test_xml += "<icon name=\"stock_help-chat\"/>" test_xml += "<icon name=\"stock_help-chat\"/>"
test_xml += "</richtext>" test_xml += "</richtext>"
RichTextSerializer().deserialize(test_xml, rich_buf) RichTextSerializer().deserialize(test_xml, rich_buf)
toolbar = RichTextToolbar(rich_buf) toolbar = RichTextToolbar(rich_buf)
vbox.pack_start(toolbar, False) vbox.pack_start(toolbar, False)
toolbar.show() toolbar.show()
window.add(vbox) window.add(vbox)
vbox.show() vbox.show()
window.show() window.show()
window.connect("destroy", test_quit, rich_buf) window.connect("destroy", test_quit, rich_buf)
gtk.main() gtk.main()

View File

@ -18,37 +18,37 @@
from SVGdraw import path from SVGdraw import path
class Sketch: class Sketch:
def __init__(self, rgb): def __init__(self, rgb):
self._points = [] self._points = []
self._rgb = (float(rgb[0]), float(rgb[1]), float(rgb[2])) self._rgb = (float(rgb[0]), float(rgb[1]), float(rgb[2]))
def add_point(self, x, y): def add_point(self, x, y):
self._points.append((x, y)) self._points.append((x, y))
def get_points(self): def get_points(self):
return self._points return self._points
def draw(self, ctx): def draw(self, ctx):
start = True start = True
for (x, y) in self._points: for (x, y) in self._points:
if start: if start:
ctx.move_to(x, y) ctx.move_to(x, y)
start = False start = False
else: else:
ctx.line_to(x, y) ctx.line_to(x, y)
ctx.set_source_rgb(self._rgb[0], self._rgb[1], self._rgb[2]) ctx.set_source_rgb(self._rgb[0], self._rgb[1], self._rgb[2])
ctx.stroke() ctx.stroke()
def draw_to_svg(self): def draw_to_svg(self):
i = 0 i = 0
for (x, y) in self._points: for (x, y) in self._points:
coords = str(x) + ' ' + str(y) + ' ' coords = str(x) + ' ' + str(y) + ' '
if i == 0: if i == 0:
path_data = 'M ' + coords path_data = 'M ' + coords
elif i == 1: elif i == 1:
path_data += 'L ' + coords path_data += 'L ' + coords
else: else:
path_data += coords path_data += coords
i += 1 i += 1
color = "#%02X%02X%02X" % (255 * self._rgb[0], 255 * self._rgb[1], 255 * self._rgb[2]) color = "#%02X%02X%02X" % (255 * self._rgb[0], 255 * self._rgb[1], 255 * self._rgb[2])
return path(path_data, fill = 'none', stroke = color) return path(path_data, fill = 'none', stroke = color)

View File

@ -23,101 +23,101 @@ from SVGdraw import drawing
from SVGdraw import svg from SVGdraw import svg
class SketchPad(gtk.DrawingArea): class SketchPad(gtk.DrawingArea):
__gsignals__ = { __gsignals__ = {
'new-user-sketch':(gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, 'new-user-sketch':(gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([gobject.TYPE_PYOBJECT])) ([gobject.TYPE_PYOBJECT]))
} }
def __init__(self, bgcolor=(0.6, 1, 0.4)): def __init__(self, bgcolor=(0.6, 1, 0.4)):
gtk.DrawingArea.__init__(self) gtk.DrawingArea.__init__(self)
self._active_sketch = None self._active_sketch = None
self._rgb = (0.0, 0.0, 0.0) self._rgb = (0.0, 0.0, 0.0)
self._bgcolor = bgcolor self._bgcolor = bgcolor
self._sketches = [] self._sketches = []
self.add_events(gtk.gdk.BUTTON_PRESS_MASK | self.add_events(gtk.gdk.BUTTON_PRESS_MASK |
gtk.gdk.BUTTON_RELEASE_MASK | gtk.gdk.BUTTON_RELEASE_MASK |
gtk.gdk.BUTTON1_MOTION_MASK) gtk.gdk.BUTTON1_MOTION_MASK)
self.connect("button-press-event", self._button_press_cb) self.connect("button-press-event", self._button_press_cb)
self.connect("button-release-event", self._button_release_cb) self.connect("button-release-event", self._button_release_cb)
self.connect("motion-notify-event", self._motion_notify_cb) self.connect("motion-notify-event", self._motion_notify_cb)
self.connect('expose_event', self.expose) self.connect('expose_event', self.expose)
def clear(self): def clear(self):
self._sketches = [] self._sketches = []
self.window.invalidate_rect(None, False) self.window.invalidate_rect(None, False)
def expose(self, widget, event): def expose(self, widget, event):
"""Draw the background of the sketchpad.""" """Draw the background of the sketchpad."""
rect = self.get_allocation() rect = self.get_allocation()
ctx = widget.window.cairo_create() ctx = widget.window.cairo_create()
ctx.set_source_rgb(self._bgcolor[0], self._bgcolor[1], self._bgcolor[2]) ctx.set_source_rgb(self._bgcolor[0], self._bgcolor[1], self._bgcolor[2])
ctx.rectangle(0, 0, rect.width, rect.height) ctx.rectangle(0, 0, rect.width, rect.height)
ctx.fill_preserve() ctx.fill_preserve()
ctx.set_source_rgb(0, 0.3, 0.2) ctx.set_source_rgb(0, 0.3, 0.2)
ctx.stroke() ctx.stroke()
for sketch in self._sketches: for sketch in self._sketches:
sketch.draw(ctx) sketch.draw(ctx)
return False return False
def set_color(self, color): def set_color(self, color):
"""Sets the current drawing color of the sketchpad. """Sets the current drawing color of the sketchpad.
color agument should be 3-item tuple of rgb values between 0 and 1.""" color agument should be 3-item tuple of rgb values between 0 and 1."""
self._rgb = color self._rgb = color
def add_sketch(self, sketch): def add_sketch(self, sketch):
"""Add a sketch to the the pad. Mostly for subclasses and clients.""" """Add a sketch to the the pad. Mostly for subclasses and clients."""
self._sketches.append(sketch) self._sketches.append(sketch)
self.window.invalidate_rect(None, False) self.window.invalidate_rect(None, False)
def add_point(self, event): def add_point(self, event):
if not self._active_sketch: if not self._active_sketch:
return return
self._active_sketch.add_point(event.x, event.y) self._active_sketch.add_point(event.x, event.y)
self.window.invalidate_rect(None, False) self.window.invalidate_rect(None, False)
def _button_press_cb(self, widget, event): def _button_press_cb(self, widget, event):
self._active_sketch = Sketch(self._rgb) self._active_sketch = Sketch(self._rgb)
self._sketches.append(self._active_sketch) self._sketches.append(self._active_sketch)
self.add_point(event) self.add_point(event)
def _button_release_cb(self, widget, event): def _button_release_cb(self, widget, event):
self.add_point(event) self.add_point(event)
self.emit('new-user-sketch', self._active_sketch) self.emit('new-user-sketch', self._active_sketch)
self._active_sketch = None self._active_sketch = None
def _motion_notify_cb(self, widget, event): def _motion_notify_cb(self, widget, event):
self.add_point(event) self.add_point(event)
def to_svg(self): def to_svg(self):
"""Return a string containing an SVG representation of this sketch.""" """Return a string containing an SVG representation of this sketch."""
d = drawing() d = drawing()
s = svg() s = svg()
for sketch in self._sketches: for sketch in self._sketches:
s.addElement(sketch.draw_to_svg()) s.addElement(sketch.draw_to_svg())
d.setSVG(s) d.setSVG(s)
return d.toXml() return d.toXml()
def test_quit(w, skpad): def test_quit(w, skpad):
print skpad.to_svg() print skpad.to_svg()
gtk.main_quit() gtk.main_quit()
if __name__ == "__main__": if __name__ == "__main__":
window = gtk.Window() window = gtk.Window()
window.set_default_size(400, 300) window.set_default_size(400, 300)
window.connect("destroy", lambda w: gtk.main_quit()) window.connect("destroy", lambda w: gtk.main_quit())
sketchpad = SketchPad() sketchpad = SketchPad()
window.add(sketchpad) window.add(sketchpad)
sketchpad.show() sketchpad.show()
window.show() window.show()
window.connect("destroy", test_quit, sketchpad) window.connect("destroy", test_quit, sketchpad)
gtk.main() gtk.main()

View File

@ -19,59 +19,59 @@ import gtk
import gobject import gobject
class ColorButton(gtk.RadioButton): class ColorButton(gtk.RadioButton):
def __init__(self, group, rgb): def __init__(self, group, rgb):
gtk.RadioButton.__init__(self, group) gtk.RadioButton.__init__(self, group)
self._rgb = rgb self._rgb = rgb
self.set_mode(False) self.set_mode(False)
self.set_relief(gtk.RELIEF_NONE) self.set_relief(gtk.RELIEF_NONE)
drawing_area = gtk.DrawingArea() drawing_area = gtk.DrawingArea()
drawing_area.set_size_request(24, 24) drawing_area.set_size_request(24, 24)
drawing_area.connect_after('expose_event', self.expose) drawing_area.connect_after('expose_event', self.expose)
self.add(drawing_area) self.add(drawing_area)
drawing_area.show() drawing_area.show()
def color(self): def color(self):
return self._rgb return self._rgb
def expose(self, widget, event): def expose(self, widget, event):
rect = widget.get_allocation() rect = widget.get_allocation()
ctx = widget.window.cairo_create() ctx = widget.window.cairo_create()
ctx.set_source_rgb(self._rgb[0], self._rgb[1] , self._rgb[2]) ctx.set_source_rgb(self._rgb[0], self._rgb[1] , self._rgb[2])
ctx.rectangle(4, 4, rect.width - 8, rect.height - 8) ctx.rectangle(4, 4, rect.width - 8, rect.height - 8)
ctx.fill() ctx.fill()
return False return False
class Toolbox(gtk.HBox): class Toolbox(gtk.HBox):
__gsignals__ = { __gsignals__ = {
'color-selected': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, 'color-selected': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([gobject.TYPE_PYOBJECT])) ([gobject.TYPE_PYOBJECT]))
} }
def __init__(self): def __init__(self):
gtk.HBox.__init__(self, False, 6) gtk.HBox.__init__(self, False, 6)
self._colors_group = None self._colors_group = None
self._add_color([0, 0, 0]) self._add_color([0, 0, 0])
self._add_color([1, 0, 0]) self._add_color([1, 0, 0])
self._add_color([0, 1, 0]) self._add_color([0, 1, 0])
self._add_color([0, 0, 1]) self._add_color([0, 0, 1])
def _add_color(self, rgb): def _add_color(self, rgb):
color = ColorButton(self._colors_group, rgb) color = ColorButton(self._colors_group, rgb)
color.unset_flags(gtk.CAN_FOCUS) color.unset_flags(gtk.CAN_FOCUS)
color.connect('clicked', self.__color_clicked_cb, rgb) color.connect('clicked', self.__color_clicked_cb, rgb)
self.pack_start(color, False) self.pack_start(color, False)
if self._colors_group == None: if self._colors_group == None:
self._colors_group = color self._colors_group = color
color.show() color.show()
def __color_clicked_cb(self, button, rgb): def __color_clicked_cb(self, button, rgb):
self.emit("color-selected", button.color()) self.emit("color-selected", button.color())

View File

@ -7,69 +7,69 @@ DBUS_PATH = "/org/laptop/Clipboard"
class ClipboardService(gobject.GObject): class ClipboardService(gobject.GObject):
__gsignals__ = { __gsignals__ = {
'object-added': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, 'object-added': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([str, str, str])), ([str, str, str])),
'object-deleted': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, 'object-deleted': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([str])), ([str])),
'object-state-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, 'object-state-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([str, int])), ([str, int])),
} }
def __init__(self): def __init__(self):
gobject.GObject.__init__(self) gobject.GObject.__init__(self)
self._dbus_service = None self._dbus_service = None
bus = dbus.SessionBus() bus = dbus.SessionBus()
bus.add_signal_receiver(self._name_owner_changed_cb, bus.add_signal_receiver(self._name_owner_changed_cb,
signal_name="NameOwnerChanged", signal_name="NameOwnerChanged",
dbus_interface="org.freedesktop.DBus") dbus_interface="org.freedesktop.DBus")
# Try to register to ClipboardService, if we fail, we'll try later. # Try to register to ClipboardService, if we fail, we'll try later.
try: try:
self._connect_clipboard_signals() self._connect_clipboard_signals()
except dbus.DBusException, exception: except dbus.DBusException, exception:
pass pass
def _connect_clipboard_signals(self): def _connect_clipboard_signals(self):
bus = dbus.SessionBus() bus = dbus.SessionBus()
proxy_obj = bus.get_object(DBUS_SERVICE, DBUS_PATH) proxy_obj = bus.get_object(DBUS_SERVICE, DBUS_PATH)
self._dbus_service = dbus.Interface(proxy_obj, DBUS_SERVICE) self._dbus_service = dbus.Interface(proxy_obj, DBUS_SERVICE)
self._dbus_service.connect_to_signal('object_added', self._dbus_service.connect_to_signal('object_added',
self._object_added_cb) self._object_added_cb)
self._dbus_service.connect_to_signal('object_deleted', self._dbus_service.connect_to_signal('object_deleted',
self._object_deleted_cb) self._object_deleted_cb)
self._dbus_service.connect_to_signal('object_state_changed', self._dbus_service.connect_to_signal('object_state_changed',
self._object_state_changed_cb) self._object_state_changed_cb)
def _name_owner_changed_cb(self, name, old, new): def _name_owner_changed_cb(self, name, old, new):
if name != DBUS_SERVICE: if name != DBUS_SERVICE:
return return
if (not old and not len(old)) and (new and len(new)): if (not old and not len(old)) and (new and len(new)):
# ClipboardService started up # ClipboardService started up
self._connect_clipboard_signals() self._connect_clipboard_signals()
def _object_added_cb(self, name, mimeType, fileName): def _object_added_cb(self, name, mimeType, fileName):
self.emit('object-added', name, mimeType, fileName) self.emit('object-added', name, mimeType, fileName)
def _object_deleted_cb(self, fileName): def _object_deleted_cb(self, fileName):
self.emit('object-deleted', fileName) self.emit('object-deleted', fileName)
def _object_state_changed_cb(self, fileName, percent): def _object_state_changed_cb(self, fileName, percent):
self.emit('object-state-changed', fileName, percent) self.emit('object-state-changed', fileName, percent)
def add_object(self, name, mimeType, fileName): def add_object(self, name, mimeType, fileName):
self._dbus_service.add_object(name, mimeType, fileName) self._dbus_service.add_object(name, mimeType, fileName)
def delete_object(self, fileName): def delete_object(self, fileName):
self._dbus_service.delete_object(fileName) self._dbus_service.delete_object(fileName)
def set_object_state(self, fileName, percent): def set_object_state(self, fileName, percent):
self._dbus_service.set_object_state(fileName, percent) self._dbus_service.set_object_state(fileName, percent)
_clipboard_service = None _clipboard_service = None
def get_instance(): def get_instance():
global _clipboard_service global _clipboard_service
if not _clipboard_service: if not _clipboard_service:
_clipboard_service = ClipboardService() _clipboard_service = ClipboardService()
return _clipboard_service return _clipboard_service

View File

@ -24,108 +24,108 @@ import gobject
from sugar import env from sugar import env
def get_display_number(): def get_display_number():
"""Find a free display number trying to connect to 6000+ ports""" """Find a free display number trying to connect to 6000+ ports"""
retries = 20 retries = 20
display_number = 1 display_number = 1
display_is_free = False display_is_free = False
while not display_is_free and retries > 0: while not display_is_free and retries > 0:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try: try:
s.connect(('127.0.0.1', 6000 + display_number)) s.connect(('127.0.0.1', 6000 + display_number))
s.close() s.close()
display_number += 1 display_number += 1
retries -= 1 retries -= 1
except: except:
display_is_free = True display_is_free = True
if display_is_free: if display_is_free:
return display_number return display_number
else: else:
logging.error('Cannot find a free display.') logging.error('Cannot find a free display.')
sys.exit(0) sys.exit(0)
class Process: class Process:
"""Object representing one of the session processes""" """Object representing one of the session processes"""
def __init__(self, command): def __init__(self, command):
self._command = command self._command = command
def get_name(self): def get_name(self):
return self._command return self._command
def start(self, standard_output=False): def start(self, standard_output=False):
args = self._command.split() args = self._command.split()
flags = gobject.SPAWN_SEARCH_PATH flags = gobject.SPAWN_SEARCH_PATH
result = gobject.spawn_async(args, flags=flags, result = gobject.spawn_async(args, flags=flags,
standard_output=standard_output) standard_output=standard_output)
self.pid = result[0] self.pid = result[0]
self._stdout = result[2] self._stdout = result[2]
class MatchboxProcess(Process): class MatchboxProcess(Process):
def __init__(self): def __init__(self):
kbd_config = os.path.join(env.get_data_dir(), 'kbdconfig') kbd_config = os.path.join(env.get_data_dir(), 'kbdconfig')
options = '-kbdconfig %s ' % kbd_config options = '-kbdconfig %s ' % kbd_config
options += '-use_titlebar no ' options += '-use_titlebar no '
options += '-theme olpc ' options += '-theme olpc '
command = 'matchbox-window-manager %s ' % options command = 'matchbox-window-manager %s ' % options
Process.__init__(self, command) Process.__init__(self, command)
def get_name(self): def get_name(self):
return 'Matchbox' return 'Matchbox'
class XephyrProcess(Process): class XephyrProcess(Process):
def __init__(self, fullscreen): def __init__(self, fullscreen):
self._display = get_display_number() self._display = get_display_number()
cmd = 'Xephyr :%d -ac ' % (self._display) cmd = 'Xephyr :%d -ac ' % (self._display)
if fullscreen: if fullscreen:
cmd += '-fullscreen ' cmd += '-fullscreen '
else: else:
cmd += '-screen 800x600 ' cmd += '-screen 800x600 '
Process.__init__(self, cmd) Process.__init__(self, cmd)
def get_name(self): def get_name(self):
return 'Xephyr' return 'Xephyr'
def start(self): def start(self):
Process.start(self) Process.start(self)
os.environ['DISPLAY'] = ":%d" % (self._display) os.environ['DISPLAY'] = ":%d" % (self._display)
os.environ['SUGAR_XEPHYR_PID'] = '%d' % self.pid os.environ['SUGAR_XEPHYR_PID'] = '%d' % self.pid
class XnestProcess(Process): class XnestProcess(Process):
def __init__(self): def __init__(self):
self._display = get_display_number() self._display = get_display_number()
cmd = 'Xnest :%d -ac -geometry 800x600' % (self._display) cmd = 'Xnest :%d -ac -geometry 800x600' % (self._display)
Process.__init__(self, cmd) Process.__init__(self, cmd)
def get_name(self): def get_name(self):
return 'Xnest' return 'Xnest'
def start(self): def start(self):
Process.start(self) Process.start(self)
os.environ['DISPLAY'] = ":%d" % (self._display) os.environ['DISPLAY'] = ":%d" % (self._display)
class Emulator(object): class Emulator(object):
"""The OLPC emulator""" """The OLPC emulator"""
def __init__(self, fullscreen): def __init__(self, fullscreen):
self._fullscreen = fullscreen self._fullscreen = fullscreen
def start(self): def start(self):
try: try:
process = XephyrProcess(self._fullscreen) process = XephyrProcess(self._fullscreen)
process.start() process.start()
except: except:
try: try:
process = XnestProcess() process = XnestProcess()
process.start() process.start()
except: except:
print 'Cannot run the emulator. You need to install \ print 'Cannot run the emulator. You need to install \
Xephyr or Xnest.' Xephyr or Xnest.'
sys.exit(0) sys.exit(0)
process = MatchboxProcess() process = MatchboxProcess()
process.start() process.start()

View File

@ -20,43 +20,43 @@ import sys
import pwd import pwd
try: try:
from sugar.__uninstalled__ import * from sugar.__uninstalled__ import *
except ImportError: except ImportError:
from sugar.__installed__ import * from sugar.__installed__ import *
def get_profile_path(): def get_profile_path():
if os.environ.has_key('SUGAR_PROFILE'): if os.environ.has_key('SUGAR_PROFILE'):
profile_id = os.environ['SUGAR_PROFILE'] profile_id = os.environ['SUGAR_PROFILE']
else: else:
profile_id = 'default' profile_id = 'default'
path = os.path.join(os.path.expanduser('~/.sugar'), profile_id) path = os.path.join(os.path.expanduser('~/.sugar'), profile_id)
if not os.path.isdir(path): if not os.path.isdir(path):
try: try:
os.makedirs(path) os.makedirs(path)
except OSError, exc: except OSError, exc:
print "Could not create user directory." print "Could not create user directory."
return path return path
def get_data_dir(): def get_data_dir():
return sugar_data_dir return sugar_data_dir
def get_services_dir(): def get_services_dir():
return sugar_services_dir return sugar_services_dir
def get_shell_bin_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 # http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
def get_data_dirs(): def get_data_dirs():
if os.environ.has_key('XDG_DATA_DIRS'): if os.environ.has_key('XDG_DATA_DIRS'):
return os.environ['XDG_DATA_DIRS'].split(':') return os.environ['XDG_DATA_DIRS'].split(':')
else: else:
return [ '/usr/local/share/', '/usr/share/' ] return [ '/usr/local/share/', '/usr/share/' ]
def get_user_service_dir(): def get_user_service_dir():
service_dir = os.path.expanduser('~/.local/share/dbus-1/services') service_dir = os.path.expanduser('~/.local/share/dbus-1/services')
if not os.path.isdir(service_dir): if not os.path.isdir(service_dir):
os.makedirs(service_dir) os.makedirs(service_dir)
return service_dir return service_dir

View File

@ -24,108 +24,108 @@ import gtk
import hippo import hippo
class ClipboardBubble(hippo.CanvasBox, hippo.CanvasItem): class ClipboardBubble(hippo.CanvasBox, hippo.CanvasItem):
__gtype_name__ = 'ClipboardBubble' __gtype_name__ = 'ClipboardBubble'
__gproperties__ = { __gproperties__ = {
'fill-color': (object, None, None, 'fill-color': (object, None, None,
gobject.PARAM_READWRITE), gobject.PARAM_READWRITE),
'stroke-color': (object, None, None, 'stroke-color': (object, None, None,
gobject.PARAM_READWRITE), gobject.PARAM_READWRITE),
'progress-color': (object, None, None, 'progress-color': (object, None, None,
gobject.PARAM_READWRITE), gobject.PARAM_READWRITE),
'percent' : (object, None, None, 'percent' : (object, None, None,
gobject.PARAM_READWRITE), gobject.PARAM_READWRITE),
} }
def __init__(self, **kwargs): def __init__(self, **kwargs):
self._stroke_color = 0xFFFFFFFF self._stroke_color = 0xFFFFFFFF
self._fill_color = 0xFFFFFFFF self._fill_color = 0xFFFFFFFF
self._progress_color = 0x000000FF self._progress_color = 0x000000FF
self._percent = 0 self._percent = 0
self._radius = 8 self._radius = 8
hippo.CanvasBox.__init__(self, **kwargs) hippo.CanvasBox.__init__(self, **kwargs)
def do_set_property(self, pspec, value): def do_set_property(self, pspec, value):
if pspec.name == 'fill-color': if pspec.name == 'fill-color':
self._fill_color = value self._fill_color = value
self.emit_paint_needed(0, 0, -1, -1) self.emit_paint_needed(0, 0, -1, -1)
elif pspec.name == 'stroke-color': elif pspec.name == 'stroke-color':
self._stroke_color = value self._stroke_color = value
self.emit_paint_needed(0, 0, -1, -1) self.emit_paint_needed(0, 0, -1, -1)
elif pspec.name == 'progress-color': elif pspec.name == 'progress-color':
self._progress_color = value self._progress_color = value
self.emit_paint_needed(0, 0, -1, -1) self.emit_paint_needed(0, 0, -1, -1)
elif pspec.name == 'percent': elif pspec.name == 'percent':
self._percent = value self._percent = value
self.emit_paint_needed(0, 0, -1, -1) self.emit_paint_needed(0, 0, -1, -1)
def do_get_property(self, pspec): def do_get_property(self, pspec):
if pspec.name == 'fill-color': if pspec.name == 'fill-color':
return self._fill_color return self._fill_color
elif pspec.name == 'stroke-color': elif pspec.name == 'stroke-color':
return self._stroke_color return self._stroke_color
elif pspec.name == 'progress-color': elif pspec.name == 'progress-color':
return self._progress_color return self._progress_color
elif pspec.name == 'percent': elif pspec.name == 'percent':
return self._percent return self._percent
def _int_to_rgb(self, int_color): def _int_to_rgb(self, int_color):
red = (int_color >> 24) & 0x000000FF red = (int_color >> 24) & 0x000000FF
green = (int_color >> 16) & 0x000000FF green = (int_color >> 16) & 0x000000FF
blue = (int_color >> 8) & 0x000000FF blue = (int_color >> 8) & 0x000000FF
alpha = int_color & 0x000000FF alpha = int_color & 0x000000FF
return (red / 255.0, green / 255.0, blue / 255.0) return (red / 255.0, green / 255.0, blue / 255.0)
def do_paint_below_children(self, cr, damaged_box): def do_paint_below_children(self, cr, damaged_box):
[width, height] = self.get_allocation() [width, height] = self.get_allocation()
line_width = 3.0 line_width = 3.0
x = line_width x = line_width
y = line_width y = line_width
width -= line_width * 2 width -= line_width * 2
height -= 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) color = self._int_to_rgb(self._stroke_color)
cr.set_source_rgb(*color) cr.set_source_rgb(*color)
cr.set_line_width(line_width) cr.set_line_width(line_width)
cr.stroke(); 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): def _paint_progress_bar(self, cr, x, y, width, height, line_width):
prog_x = x + line_width prog_x = x + line_width
prog_y = y + line_width prog_y = y + line_width
prog_width = (width - (line_width * 2)) * (self._percent / 100.0) prog_width = (width - (line_width * 2)) * (self._percent / 100.0)
prog_height = (height - (line_width * 2)) 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): def _paint_ellipse(self, cr, x, y, width, height, fill_color):
cr.move_to(x + self._radius, y) cr.move_to(x + self._radius, y)
cr.arc(x + width - self._radius, cr.arc(x + width - self._radius,
y + self._radius, y + self._radius,
self._radius, self._radius,
math.pi * 1.5, math.pi * 1.5,
math.pi * 2) math.pi * 2)
cr.arc(x + width - self._radius, cr.arc(x + width - self._radius,
x + height - self._radius, x + height - self._radius,
self._radius, self._radius,
0, 0,
math.pi * 0.5) math.pi * 0.5)
cr.arc(x + self._radius, cr.arc(x + self._radius,
y + height - self._radius, y + height - self._radius,
self._radius, self._radius,
math.pi * 0.5, math.pi * 0.5,
math.pi) math.pi)
cr.arc(x + self._radius, cr.arc(x + self._radius,
y + self._radius, y + self._radius,
self._radius, self._radius,
math.pi, math.pi,
math.pi * 1.5); math.pi * 1.5);
color = self._int_to_rgb(fill_color) color = self._int_to_rgb(fill_color)
cr.set_source_rgb(*color) cr.set_source_rgb(*color)
cr.fill_preserve(); cr.fill_preserve();

View File

@ -22,56 +22,56 @@ import gtk
import hippo import hippo
class Bubble(hippo.CanvasBox, hippo.CanvasItem): class Bubble(hippo.CanvasBox, hippo.CanvasItem):
__gtype_name__ = 'SugarBubble' __gtype_name__ = 'SugarBubble'
__gproperties__ = { __gproperties__ = {
'color' : (object, None, None, 'color' : (object, None, None,
gobject.PARAM_READWRITE), gobject.PARAM_READWRITE),
} }
def __init__(self, **kwargs): def __init__(self, **kwargs):
self._color = None self._color = None
self._radius = 8 self._radius = 8
hippo.CanvasBox.__init__(self, **kwargs) hippo.CanvasBox.__init__(self, **kwargs)
def do_set_property(self, pspec, value): def do_set_property(self, pspec, value):
if pspec.name == 'color': if pspec.name == 'color':
self._color = value self._color = value
self.emit_paint_needed(0, 0, -1, -1) self.emit_paint_needed(0, 0, -1, -1)
def do_get_property(self, pspec): def do_get_property(self, pspec):
if pspec.name == 'color': if pspec.name == 'color':
return self._color return self._color
def _string_to_rgb(self, color_string): def _string_to_rgb(self, color_string):
col = gtk.gdk.color_parse(color_string) col = gtk.gdk.color_parse(color_string)
return (col.red / 65535.0, col.green / 65535.0, col.blue / 65535.0) return (col.red / 65535.0, col.green / 65535.0, col.blue / 65535.0)
def do_paint_below_children(self, cr, damaged_box): def do_paint_below_children(self, cr, damaged_box):
[width, height] = self.get_allocation() [width, height] = self.get_allocation()
line_width = 3.0 line_width = 3.0
x = line_width x = line_width
y = line_width y = line_width
width -= line_width * 2 width -= line_width * 2
height -= line_width * 2 height -= line_width * 2
cr.move_to(x + self._radius, y); cr.move_to(x + self._radius, y);
cr.arc(x + width - self._radius, y + self._radius, cr.arc(x + width - self._radius, y + self._radius,
self._radius, math.pi * 1.5, math.pi * 2); self._radius, math.pi * 1.5, math.pi * 2);
cr.arc(x + width - self._radius, x + height - self._radius, cr.arc(x + width - self._radius, x + height - self._radius,
self._radius, 0, math.pi * 0.5); self._radius, 0, math.pi * 0.5);
cr.arc(x + self._radius, y + height - self._radius, cr.arc(x + self._radius, y + height - self._radius,
self._radius, math.pi * 0.5, math.pi); self._radius, math.pi * 0.5, math.pi);
cr.arc(x + self._radius, y + self._radius, self._radius, cr.arc(x + self._radius, y + self._radius, self._radius,
math.pi, math.pi * 1.5); math.pi, math.pi * 1.5);
color = self._string_to_rgb(self._color.get_fill_color()) color = self._string_to_rgb(self._color.get_fill_color())
cr.set_source_rgb(*color) cr.set_source_rgb(*color)
cr.fill_preserve(); cr.fill_preserve();
color = self._string_to_rgb(self._color.get_stroke_color()) color = self._string_to_rgb(self._color.get_stroke_color())
cr.set_source_rgb(*color) cr.set_source_rgb(*color)
cr.set_line_width(line_width) cr.set_line_width(line_width)
cr.stroke(); cr.stroke();

View File

@ -26,133 +26,133 @@ import cairo
from sugar.graphics.iconcolor import IconColor from sugar.graphics.iconcolor import IconColor
class _IconCache: class _IconCache:
def __init__(self): def __init__(self):
self._icons = {} self._icons = {}
self._theme = gtk.icon_theme_get_default() self._theme = gtk.icon_theme_get_default()
def _read_icon(self, filename, color): def _read_icon(self, filename, color):
icon_file = open(filename, 'r') icon_file = open(filename, 'r')
if color == None: if color == None:
return rsvg.Handle(file=filename) return rsvg.Handle(file=filename)
else: else:
data = icon_file.read() data = icon_file.read()
icon_file.close() icon_file.close()
fill = color.get_fill_color() fill = color.get_fill_color()
stroke = color.get_stroke_color() stroke = color.get_stroke_color()
entity = '<!ENTITY fill_color "%s">' % fill entity = '<!ENTITY fill_color "%s">' % fill
data = re.sub('<!ENTITY fill_color .*>', entity, data) data = re.sub('<!ENTITY fill_color .*>', entity, data)
entity = '<!ENTITY stroke_color "%s">' % stroke entity = '<!ENTITY stroke_color "%s">' % stroke
data = re.sub('<!ENTITY stroke_color .*>', entity, data) 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): def get_handle(self, name, color, size):
info = self._theme.lookup_icon(name, int(size), 0) info = self._theme.lookup_icon(name, int(size), 0)
if color: if color:
key = (info.get_filename(), color.to_string()) key = (info.get_filename(), color.to_string())
else: else:
key = info.get_filename() key = info.get_filename()
if self._icons.has_key(key): if self._icons.has_key(key):
icon = self._icons[key] icon = self._icons[key]
else: else:
icon = self._read_icon(info.get_filename(), color) icon = self._read_icon(info.get_filename(), color)
self._icons[key] = icon self._icons[key] = icon
return icon return icon
class CanvasIcon(hippo.CanvasBox, hippo.CanvasItem): class CanvasIcon(hippo.CanvasBox, hippo.CanvasItem):
__gtype_name__ = 'CanvasIcon' __gtype_name__ = 'CanvasIcon'
__gproperties__ = { __gproperties__ = {
'icon-name': (str, None, None, None, 'icon-name': (str, None, None, None,
gobject.PARAM_READWRITE), gobject.PARAM_READWRITE),
'color' : (object, None, None, 'color' : (object, None, None,
gobject.PARAM_READWRITE), gobject.PARAM_READWRITE),
'size' : (int, None, None, 'size' : (int, None, None,
0, 1024, 24, 0, 1024, 24,
gobject.PARAM_READWRITE) gobject.PARAM_READWRITE)
} }
_cache = _IconCache() _cache = _IconCache()
def __init__(self, **kwargs): def __init__(self, **kwargs):
self._size = 24 self._size = 24
self._color = None self._color = None
self._icon_name = 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): def do_set_property(self, pspec, value):
if pspec.name == 'icon-name': if pspec.name == 'icon-name':
self._icon_name = value self._icon_name = value
self._buffer = None self._buffer = None
self.emit_paint_needed(0, 0, -1, -1) self.emit_paint_needed(0, 0, -1, -1)
elif pspec.name == 'color': elif pspec.name == 'color':
self._buffer = None self._buffer = None
self._color = value self._color = value
self.emit_paint_needed(0, 0, -1, -1) self.emit_paint_needed(0, 0, -1, -1)
elif pspec.name == 'size': elif pspec.name == 'size':
self._buffer = None self._buffer = None
self._size = value self._size = value
self.emit_request_changed() self.emit_request_changed()
def do_get_property(self, pspec): def do_get_property(self, pspec):
if pspec.name == 'size': if pspec.name == 'size':
return self._size return self._size
elif pspec.name == 'icon-name': elif pspec.name == 'icon-name':
return self._icon_name return self._icon_name
elif pspec.name == 'color': elif pspec.name == 'color':
return self._color return self._color
def _get_buffer(self, cr, handle, size): def _get_buffer(self, cr, handle, size):
if self._buffer == None: if self._buffer == None:
target = cr.get_target() target = cr.get_target()
surface = target.create_similar(cairo.CONTENT_COLOR_ALPHA, surface = target.create_similar(cairo.CONTENT_COLOR_ALPHA,
int(size) + 1, int(size) + 1) int(size) + 1, int(size) + 1)
dimensions = handle.get_dimension_data() dimensions = handle.get_dimension_data()
scale = float(size) / float(dimensions[0]) scale = float(size) / float(dimensions[0])
ctx = cairo.Context(surface) ctx = cairo.Context(surface)
ctx.scale(scale, scale) ctx.scale(scale, scale)
handle.render_cairo(ctx) handle.render_cairo(ctx)
del ctx del ctx
self._buffer = surface self._buffer = surface
self._buffer_scale = scale self._buffer_scale = scale
return self._buffer return self._buffer
def do_paint_below_children(self, cr, damaged_box): def do_paint_below_children(self, cr, damaged_box):
icon_name = self._icon_name icon_name = self._icon_name
if icon_name == None: if icon_name == None:
icon_name = 'stock-missing' icon_name = 'stock-missing'
handle = CanvasIcon._cache.get_handle( handle = CanvasIcon._cache.get_handle(
icon_name, self._color, self._size) icon_name, self._color, self._size)
buf = self._get_buffer(cr, handle, self._size) buf = self._get_buffer(cr, handle, self._size)
[width, height] = self.get_allocation() [width, height] = self.get_allocation()
x = (width - self._size) / 2 x = (width - self._size) / 2
y = (height - self._size) / 2 y = (height - self._size) / 2
cr.set_source_surface(buf, x, y) cr.set_source_surface(buf, x, y)
cr.paint() cr.paint()
def do_get_width_request(self): def do_get_width_request(self):
return self._size return self._size
def do_get_height_request(self, for_width): def do_get_height_request(self, for_width):
return self._size return self._size
def _button_press_event_cb(self, item, event): def _button_press_event_cb(self, item, event):
item.emit_activated() item.emit_activated()

View File

@ -21,19 +21,19 @@ COLS = 16
ROWS = 12 ROWS = 12
class Grid(object): class Grid(object):
def __init__(self): def __init__(self):
self._factor = gtk.gdk.screen_width() / COLS self._factor = gtk.gdk.screen_width() / COLS
def point(self, grid_x, grid_y): def point(self, grid_x, grid_y):
return [grid_x * self._factor, grid_y * self._factor] return [grid_x * self._factor, grid_y * self._factor]
def rectangle(self, grid_x, grid_y, grid_w, grid_h): def rectangle(self, grid_x, grid_y, grid_w, grid_h):
return [grid_x * self._factor, grid_y * self._factor, return [grid_x * self._factor, grid_y * self._factor,
grid_w * self._factor, grid_h * self._factor] grid_w * self._factor, grid_h * self._factor]
def dimension(self, grid_dimension): def dimension(self, grid_dimension):
return grid_dimension * self._factor return grid_dimension * self._factor
def fit_point(self, x, y): def fit_point(self, x, y):
return [int(x / self._factor), int(y / self._factor)] return [int(x / self._factor), int(y / self._factor)]

View File

@ -20,32 +20,32 @@ import random
from sugar.graphics.colors import colors from sugar.graphics.colors import colors
def _parse_string(color_string): def _parse_string(color_string):
if color_string == 'white': if color_string == 'white':
return ['#ffffff', '#414141'] return ['#ffffff', '#414141']
splitted = color_string.split(',') splitted = color_string.split(',')
if len(splitted) == 2: if len(splitted) == 2:
return [splitted[0], splitted[1]] return [splitted[0], splitted[1]]
else: else:
return None return None
def is_valid(color_string): def is_valid(color_string):
return (_parse_string(color_string) != None) return (_parse_string(color_string) != None)
class IconColor: class IconColor:
def __init__(self, color_string=None): def __init__(self, color_string=None):
if color_string == None or not is_valid(color_string): if color_string == None or not is_valid(color_string):
n = int(random.random() * (len(colors) - 1)) n = int(random.random() * (len(colors) - 1))
[self._stroke, self._fill] = colors[n] [self._stroke, self._fill] = colors[n]
else: else:
[self._stroke, self._fill] = _parse_string(color_string) [self._stroke, self._fill] = _parse_string(color_string)
def get_stroke_color(self): def get_stroke_color(self):
return self._stroke return self._stroke
def get_fill_color(self): def get_fill_color(self):
return self._fill return self._fill
def to_string(self): def to_string(self):
return '%s,%s' % (self._stroke, self._fill) return '%s,%s' % (self._stroke, self._fill)

View File

@ -23,85 +23,85 @@ from sugar.graphics.canvasicon import CanvasIcon
from sugar.graphics import style from sugar.graphics import style
class Menu(gtk.Window): class Menu(gtk.Window):
__gsignals__ = { __gsignals__ = {
'action': (gobject.SIGNAL_RUN_FIRST, 'action': (gobject.SIGNAL_RUN_FIRST,
gobject.TYPE_NONE, ([int])), gobject.TYPE_NONE, ([int])),
} }
def __init__(self, title=None, content_box=None): def __init__(self, title=None, content_box=None):
gtk.Window.__init__(self, gtk.WINDOW_POPUP) gtk.Window.__init__(self, gtk.WINDOW_POPUP)
canvas = hippo.Canvas() canvas = hippo.Canvas()
self.add(canvas) self.add(canvas)
canvas.show() canvas.show()
self._root = hippo.CanvasBox() self._root = hippo.CanvasBox()
style.apply_stylesheet(self._root, 'menu') style.apply_stylesheet(self._root, 'menu')
canvas.set_root(self._root) canvas.set_root(self._root)
if title: if title:
self._title_item = hippo.CanvasText(text=title) self._title_item = hippo.CanvasText(text=title)
style.apply_stylesheet(self._title_item, 'menu.Title') style.apply_stylesheet(self._title_item, 'menu.Title')
self._root.append(self._title_item) self._root.append(self._title_item)
else: else:
self._title_item = None self._title_item = None
if content_box: if content_box:
separator = self._create_separator() separator = self._create_separator()
self._root.append(separator) self._root.append(separator)
self._root.append(content_box) self._root.append(content_box)
self._action_box = None self._action_box = None
self._item_box = None self._item_box = None
def _create_separator(self): def _create_separator(self):
separator = hippo.CanvasBox() separator = hippo.CanvasBox()
style.apply_stylesheet(separator, 'menu.Separator') style.apply_stylesheet(separator, 'menu.Separator')
return separator return separator
def _create_item_box(self): def _create_item_box(self):
if self._title_item: if self._title_item:
separator = self._create_separator() separator = self._create_separator()
self._root.append(separator) self._root.append(separator)
self._item_box = hippo.CanvasBox( self._item_box = hippo.CanvasBox(
orientation=hippo.ORIENTATION_VERTICAL) orientation=hippo.ORIENTATION_VERTICAL)
self._root.append(self._item_box) self._root.append(self._item_box)
def _create_action_box(self): def _create_action_box(self):
separator = self._create_separator() separator = self._create_separator()
self._root.append(separator) self._root.append(separator)
self._action_box = hippo.CanvasBox( self._action_box = hippo.CanvasBox(
orientation=hippo.ORIENTATION_HORIZONTAL) orientation=hippo.ORIENTATION_HORIZONTAL)
self._root.append(self._action_box) self._root.append(self._action_box)
def add_item(self, label, action_id): def add_item(self, label, action_id):
if not self._item_box: if not self._item_box:
self._create_item_box() self._create_item_box()
text = hippo.CanvasText(text=label) text = hippo.CanvasText(text=label)
style.apply_stylesheet(text, 'menu.Item') style.apply_stylesheet(text, 'menu.Item')
# FIXME need a way to make hippo items activable in python # FIXME need a way to make hippo items activable in python
text.connect('button-press-event', self._item_clicked_cb, action_id) text.connect('button-press-event', self._item_clicked_cb, action_id)
#text.connect('activated', self._action_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): def add_action(self, icon, action_id):
if not self._action_box: if not self._action_box:
self._create_action_box() self._create_action_box()
style.apply_stylesheet(icon, 'menu.ActionIcon') style.apply_stylesheet(icon, 'menu.ActionIcon')
icon.connect('activated', self._action_clicked_cb, action_id) icon.connect('activated', self._action_clicked_cb, action_id)
self._action_box.append(icon) self._action_box.append(icon)
def remove_action(self, icon): def remove_action(self, icon):
self._action_box.remove(icon) self._action_box.remove(icon)
def _item_clicked_cb(self, icon, event, action): def _item_clicked_cb(self, icon, event, action):
self.emit('action', action) self.emit('action', action)
def _action_clicked_cb(self, icon, action): def _action_clicked_cb(self, icon, action):
self.emit('action', action) self.emit('action', action)

View File

@ -23,58 +23,58 @@ from sugar.graphics.canvasicon import CanvasIcon
from sugar.graphics.timeline import Timeline from sugar.graphics.timeline import Timeline
class MenuIcon(CanvasIcon): class MenuIcon(CanvasIcon):
def __init__(self, menu_shell, **kwargs): def __init__(self, menu_shell, **kwargs):
CanvasIcon.__init__(self, **kwargs) CanvasIcon.__init__(self, **kwargs)
self._menu_shell = menu_shell self._menu_shell = menu_shell
self._menu = None self._menu = None
self._hover_menu = False self._hover_menu = False
self._timeline = Timeline(self) self._timeline = Timeline(self)
self._timeline.add_tag('popup', 6, 6) self._timeline.add_tag('popup', 6, 6)
self._timeline.add_tag('before_popdown', 7, 7) self._timeline.add_tag('before_popdown', 7, 7)
self._timeline.add_tag('popdown', 8, 8) 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): def do_popup(self, current, n_frames):
if self._menu: if self._menu:
return return
self._menu = self.create_menu() self._menu = self.create_menu()
self._menu.connect('enter-notify-event', self._menu.connect('enter-notify-event',
self._menu_enter_notify_event_cb) self._menu_enter_notify_event_cb)
self._menu.connect('leave-notify-event', self._menu.connect('leave-notify-event',
self._menu_leave_notify_event_cb) 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.move(x, y)
self._menu.show() self._menu.show()
self._menu_shell.set_active(self) self._menu_shell.set_active(self)
def do_popdown(self, current, frame): def do_popdown(self, current, frame):
if self._menu: if self._menu:
self._menu.destroy() self._menu.destroy()
self._menu = None self._menu = None
self._menu_shell.set_active(None) self._menu_shell.set_active(None)
def popdown(self): def popdown(self):
self._timeline.play('popdown', 'popdown') self._timeline.play('popdown', 'popdown')
def _motion_notify_event_cb(self, item, event): def _motion_notify_event_cb(self, item, event):
if event.detail == hippo.MOTION_DETAIL_ENTER: if event.detail == hippo.MOTION_DETAIL_ENTER:
self._timeline.play(None, 'popup') self._timeline.play(None, 'popup')
elif event.detail == hippo.MOTION_DETAIL_LEAVE: elif event.detail == hippo.MOTION_DETAIL_LEAVE:
if not self._hover_menu: if not self._hover_menu:
self._timeline.play('before_popdown', 'popdown') self._timeline.play('before_popdown', 'popdown')
def _menu_enter_notify_event_cb(self, widget, event): def _menu_enter_notify_event_cb(self, widget, event):
self._hover_menu = True self._hover_menu = True
self._timeline.play('popup', 'popup') self._timeline.play('popup', 'popup')
def _menu_leave_notify_event_cb(self, widget, event): def _menu_leave_notify_event_cb(self, widget, event):
self._hover_menu = False self._hover_menu = False
self._timeline.play('popdown', 'popdown') self._timeline.play('popdown', 'popdown')

View File

@ -19,83 +19,83 @@ import gobject
import gtk import gtk
class MenuShell(gobject.GObject): class MenuShell(gobject.GObject):
__gsignals__ = { __gsignals__ = {
'activated': (gobject.SIGNAL_RUN_FIRST, 'activated': (gobject.SIGNAL_RUN_FIRST,
gobject.TYPE_NONE, ([])), gobject.TYPE_NONE, ([])),
'deactivated': (gobject.SIGNAL_RUN_FIRST, 'deactivated': (gobject.SIGNAL_RUN_FIRST,
gobject.TYPE_NONE, ([])), gobject.TYPE_NONE, ([])),
} }
AUTO = 0 AUTO = 0
LEFT = 1 LEFT = 1
RIGHT = 2 RIGHT = 2
TOP = 3 TOP = 3
BOTTOM = 4 BOTTOM = 4
def __init__(self, parent_canvas): def __init__(self, parent_canvas):
gobject.GObject.__init__(self) gobject.GObject.__init__(self)
self._parent_canvas = parent_canvas self._parent_canvas = parent_canvas
self._menu_controller = None self._menu_controller = None
self._position = MenuShell.AUTO self._position = MenuShell.AUTO
def set_position(self, position): def set_position(self, position):
self._position = position self._position = position
def is_active(self): def is_active(self):
return (self._menu_controller != None) return (self._menu_controller != None)
def set_active(self, controller): def set_active(self, controller):
if controller == None: if controller == None:
self.emit('deactivated') self.emit('deactivated')
else: else:
self.emit('activated') self.emit('activated')
if self._menu_controller: if self._menu_controller:
self._menu_controller.popdown() self._menu_controller.popdown()
self._menu_controller = controller self._menu_controller = controller
def _get_item_rect(self, item): def _get_item_rect(self, item):
[x, y] = item.get_context().translate_to_widget(item) [x, y] = item.get_context().translate_to_widget(item)
[origin_x, origin_y] = self._parent_canvas.window.get_origin() [origin_x, origin_y] = self._parent_canvas.window.get_origin()
x += origin_x x += origin_x
y += origin_y 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): def get_position(self, menu, item):
[item_x, item_y, item_w, item_h] = self._get_item_rect(item) [item_x, item_y, item_w, item_h] = self._get_item_rect(item)
[menu_w, menu_h] = menu.size_request() [menu_w, menu_h] = menu.size_request()
left_x = item_x - menu_w left_x = item_x - menu_w
left_y = item_y left_y = item_y
right_x = item_x + item_w right_x = item_x + item_w
right_y = item_y right_y = item_y
top_x = item_x top_x = item_x
top_y = item_y - menu_h top_y = item_y - menu_h
bottom_x = item_x bottom_x = item_x
bottom_y = item_y + item_h bottom_y = item_y + item_h
if self._position == MenuShell.LEFT: if self._position == MenuShell.LEFT:
[x, y] = [left_x, left_y] [x, y] = [left_x, left_y]
elif self._position == MenuShell.RIGHT: elif self._position == MenuShell.RIGHT:
[x, y] = [right_x, right_y] [x, y] = [right_x, right_y]
elif self._position == MenuShell.TOP: elif self._position == MenuShell.TOP:
[x, y] = [top_x, top_y] [x, y] = [top_x, top_y]
elif self._position == MenuShell.BOTTOM: elif self._position == MenuShell.BOTTOM:
[x, y] = [bottom_x, bottom_y] [x, y] = [bottom_x, bottom_y]
elif self._position == MenuShell.AUTO: elif self._position == MenuShell.AUTO:
[x, y] = [right_x, right_y] [x, y] = [right_x, right_y]
if x + menu_w > gtk.gdk.screen_width(): if x + menu_w > gtk.gdk.screen_width():
[x, y] = [left_x, left_y] [x, y] = [left_x, left_y]
x = min(x, gtk.gdk.screen_width() - menu_w) x = min(x, gtk.gdk.screen_width() - menu_w)
x = max(0, x) x = max(0, x)
y = min(y, gtk.gdk.screen_height() - menu_h) y = min(y, gtk.gdk.screen_height() - menu_h)
y = max(0, y) y = max(0, y)
return [x, y] return [x, y]

View File

@ -25,72 +25,72 @@ _CHILDREN_FACTOR = 1
_FLAKE_DISTANCE = 6 _FLAKE_DISTANCE = 6
class SnowflakeBox(hippo.CanvasBox, hippo.CanvasItem): class SnowflakeBox(hippo.CanvasBox, hippo.CanvasItem):
__gtype_name__ = 'SugarSnowflakeBox' __gtype_name__ = 'SugarSnowflakeBox'
def __init__(self, **kwargs): def __init__(self, **kwargs):
hippo.CanvasBox.__init__(self, **kwargs) hippo.CanvasBox.__init__(self, **kwargs)
self._root = None self._root = None
def set_root(self, icon): def set_root(self, icon):
self._root = icon self._root = icon
def _get_center(self): def _get_center(self):
[width, height] = self.get_allocation() [width, height] = self.get_allocation()
return [width / 2, height / 2] return [width / 2, height / 2]
def _get_radius(self): def _get_radius(self):
return _BASE_RADIUS + _CHILDREN_FACTOR * self._get_n_children() return _BASE_RADIUS + _CHILDREN_FACTOR * self._get_n_children()
def _layout_root(self): def _layout_root(self):
[width, height] = self._root.get_allocation() [width, height] = self._root.get_allocation()
[cx, cy] = self._get_center() [cx, cy] = self._get_center()
x = cx - (width / 2) x = cx - (width / 2)
y = cy - (height / 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): def _get_n_children(self):
return len(self.get_children()) - 1 return len(self.get_children()) - 1
def _layout_child(self, child, index): def _layout_child(self, child, index):
r = self._get_radius() r = self._get_radius()
if (self._get_n_children() > 10): if (self._get_n_children() > 10):
r += _FLAKE_DISTANCE * (index % 3) 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() [width, height] = child.get_allocation()
[cx, cy] = self._get_center() [cx, cy] = self._get_center()
x = cx + math.cos(angle) * r - (width / 2) x = cx + math.cos(angle) * r - (width / 2)
y = cy + math.sin(angle) * r - (height / 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): def do_get_width_request(self):
hippo.CanvasBox.do_get_width_request(self) hippo.CanvasBox.do_get_width_request(self)
max_child_size = 0 max_child_size = 0
for child in self.get_children(): for child in self.get_children():
width = child.get_width_request() width = child.get_width_request()
height = child.get_height_request(width) height = child.get_height_request(width)
max_child_size = max (max_child_size, width) max_child_size = max (max_child_size, width)
max_child_size = max (max_child_size, height) max_child_size = max (max_child_size, height)
return self._get_radius() * 2 + \ return self._get_radius() * 2 + \
max_child_size + _FLAKE_DISTANCE * 2 max_child_size + _FLAKE_DISTANCE * 2
def do_get_height_request(self, width): def do_get_height_request(self, width):
hippo.CanvasBox.do_get_height_request(self, width) hippo.CanvasBox.do_get_height_request(self, width)
return width return width
def do_allocate(self, width, height): def do_allocate(self, width, height):
hippo.CanvasBox.do_allocate(self, width, height) hippo.CanvasBox.do_allocate(self, width, height)
self._layout_root() self._layout_root()
index = 0 index = 0
for child in self.get_children(): for child in self.get_children():
if child != self._root: if child != self._root:
self._layout_child(child, index) self._layout_child(child, index)
index += 1 index += 1

View File

@ -25,108 +25,108 @@ _DISTANCE_THRESHOLD = 10.0
_FORCE_CONSTANT = 0.1 _FORCE_CONSTANT = 0.1
class SpreadBox(hippo.CanvasBox, hippo.CanvasItem): class SpreadBox(hippo.CanvasBox, hippo.CanvasItem):
__gtype_name__ = 'SugarSpreadBox' __gtype_name__ = 'SugarSpreadBox'
def __init__(self, **kwargs): def __init__(self, **kwargs):
hippo.CanvasBox.__init__(self, **kwargs) hippo.CanvasBox.__init__(self, **kwargs)
self._items_to_position = [] self._items_to_position = []
self._stable = False self._stable = False
def add_item(self, item): def add_item(self, item):
self._items_to_position.append(item) self._items_to_position.append(item)
self.append(item, hippo.PACK_FIXED) self.append(item, hippo.PACK_FIXED)
def remove_item(self, item): def remove_item(self, item):
if self._items_to_position.count(item) > 0: if self._items_to_position.count(item) > 0:
self._items_to_position.remove(item) self._items_to_position.remove(item)
self.remove(item) self.remove(item)
def _get_item_radius(self, item): def _get_item_radius(self, item):
[width, height] = item.get_request() [width, height] = item.get_request()
return math.sqrt(width ** 2 + height ** 2) / 2 return math.sqrt(width ** 2 + height ** 2) / 2
def _get_item_center(self, item): def _get_item_center(self, item):
[width, height] = item.get_request() [width, height] = item.get_request()
[x, y] = self.get_position(item) [x, y] = self.get_position(item)
c_x = int(x + float(width) / 2.0) c_x = int(x + float(width) / 2.0)
c_y = int(y + float(height) / 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): def _get_repulsion(self, icon1, icon2):
[c1_x, c1_y] = self._get_item_center(icon1) [c1_x, c1_y] = self._get_item_center(icon1)
[c2_x, c2_y] = self._get_item_center(icon2) [c2_x, c2_y] = self._get_item_center(icon2)
a = c2_x - c1_x a = c2_x - c1_x
b = c2_y - c1_y b = c2_y - c1_y
r1 = self._get_item_radius(icon1) r1 = self._get_item_radius(icon1)
r2 = self._get_item_radius(icon2) r2 = self._get_item_radius(icon2)
distance = math.sqrt(a ** 2 + b ** 2) - r1 - r2 distance = math.sqrt(a ** 2 + b ** 2) - r1 - r2
if distance < _DISTANCE_THRESHOLD: if distance < _DISTANCE_THRESHOLD:
f_x = int(math.ceil(-_FORCE_CONSTANT * float(a))) f_x = int(math.ceil(-_FORCE_CONSTANT * float(a)))
f_y = int(math.ceil(-_FORCE_CONSTANT * float(b))) f_y = int(math.ceil(-_FORCE_CONSTANT * float(b)))
else: else:
f_x = 0 f_x = 0
f_y = 0 f_y = 0
return [f_x, f_y] return [f_x, f_y]
def _clamp_position(self, icon, x, y): def _clamp_position(self, icon, x, y):
x = max(0, x) x = max(0, x)
y = max(0, y) y = max(0, y)
[item_w, item_h] = icon.get_request() [item_w, item_h] = icon.get_request()
[box_w, box_h] = self.get_allocation() [box_w, box_h] = self.get_allocation()
x = min(box_w - item_w, x) x = min(box_w - item_w, x)
y = min(box_h - item_h, y) y = min(box_h - item_h, y)
return [x, y] return [x, y]
def _spread_icons(self): def _spread_icons(self):
self._stable = True self._stable = True
for icon1 in self.get_children(): for icon1 in self.get_children():
vx = 0 vx = 0
vy = 0 vy = 0
for icon2 in self.get_children(): for icon2 in self.get_children():
if icon1 != icon2: if icon1 != icon2:
[f_x, f_y] = self._get_repulsion(icon1, icon2) [f_x, f_y] = self._get_repulsion(icon1, icon2)
if f_x != 0 or f_y != 0: if f_x != 0 or f_y != 0:
self._stable = False self._stable = False
vx += f_x vx += f_x
vy += f_y vy += f_y
if vx != 0 or vy != 0: if vx != 0 or vy != 0:
[x, y] = self.get_position(icon1) [x, y] = self.get_position(icon1)
new_x = x + vx new_x = x + vx
new_y = y + vy 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): def do_allocate(self, width, height):
hippo.CanvasBox.do_allocate(self, width, height) hippo.CanvasBox.do_allocate(self, width, height)
for item in self._items_to_position: for item in self._items_to_position:
[item_w, item_h] = item.get_request() [item_w, item_h] = item.get_request()
x = int(random.random() * width - item_w) x = int(random.random() * width - item_w)
y = int(random.random() * height - item_h) y = int(random.random() * height - item_h)
[x, y] = self._clamp_position(item, x, y) [x, y] = self._clamp_position(item, x, y)
self.move(item, x, y) self.move(item, x, y)
self._items_to_position = [] self._items_to_position = []
tries = 20 tries = 20
self._spread_icons() self._spread_icons()
while not self._stable and tries > 0: while not self._stable and tries > 0:
self._spread_icons() self._spread_icons()
tries -= 1 tries -= 1

View File

@ -31,21 +31,21 @@ large_icon_size = standard_icon_size * 2.0
xlarge_icon_size = standard_icon_size * 3.0 xlarge_icon_size = standard_icon_size * 3.0
def load_stylesheet(module): def load_stylesheet(module):
for objname in dir(module): for objname in dir(module):
if not objname.startswith('_'): if not objname.startswith('_'):
obj = getattr(module, objname) obj = getattr(module, objname)
if isinstance(obj, dict): if isinstance(obj, dict):
register_stylesheet(objname.replace('_', '.'), obj) register_stylesheet(objname.replace('_', '.'), obj)
def register_stylesheet(name, style): def register_stylesheet(name, style):
_styles[name] = style _styles[name] = style
def apply_stylesheet(item, stylesheet_name): def apply_stylesheet(item, stylesheet_name):
if _styles.has_key(stylesheet_name): if _styles.has_key(stylesheet_name):
style_sheet = _styles[stylesheet_name] style_sheet = _styles[stylesheet_name]
for name in style_sheet.keys(): for name in style_sheet.keys():
item.set_property(name, style_sheet[name]) item.set_property(name, style_sheet[name])
def get_font_description(style, relative_size): def get_font_description(style, relative_size):
base_size = 18 * _screen_factor base_size = 18 * _screen_factor
return '%s %dpx' % (style, int(base_size * relative_size)) return '%s %dpx' % (style, int(base_size * relative_size))

View File

@ -1,31 +1,31 @@
from sugar.graphics import style from sugar.graphics import style
menu = { menu = {
'background_color' : 0x000000FF, 'background_color' : 0x000000FF,
'spacing' : style.space_unit, 'spacing' : style.space_unit,
'padding' : style.space_unit 'padding' : style.space_unit
} }
menu_Title = { menu_Title = {
'color' : 0xFFFFFFFF, 'color' : 0xFFFFFFFF,
'font' : style.get_font_description('Bold', 1.2) 'font' : style.get_font_description('Bold', 1.2)
} }
menu_Separator = { menu_Separator = {
'background_color' : 0xFFFFFFFF, 'background_color' : 0xFFFFFFFF,
'box_height' : style.separator_thickness 'box_height' : style.separator_thickness
} }
menu_ActionIcon = { menu_ActionIcon = {
'size' : style.standard_icon_size 'size' : style.standard_icon_size
} }
menu_Item = { menu_Item = {
'color' : 0xFFFFFFFF, 'color' : 0xFFFFFFFF,
'font' : style.get_font_description('Plain', 1.1) 'font' : style.get_font_description('Plain', 1.1)
} }
menu_Text = { menu_Text = {
'color' : 0xFFFFFFFF, 'color' : 0xFFFFFFFF,
'font' : style.get_font_description('Plain', 1.2) 'font' : style.get_font_description('Plain', 1.2)
} }

View File

@ -18,100 +18,100 @@
import gobject import gobject
class _Tag: class _Tag:
def __init__(self, name, start_frame, end_frame): def __init__(self, name, start_frame, end_frame):
self.name = name self.name = name
self.start_frame = start_frame self.start_frame = start_frame
self.end_frame = end_frame self.end_frame = end_frame
class TimelineObserver: class TimelineObserver:
def __init__(self, observer): def __init__(self, observer):
self._observer = observer self._observer = observer
def next_frame(self, tag, current_frame, n_frames): def next_frame(self, tag, current_frame, n_frames):
try: try:
method = getattr(self._observer, 'do_' + tag) method = getattr(self._observer, 'do_' + tag)
except AttributeError: except AttributeError:
method = None method = None
if method: if method:
method(current_frame, n_frames) method(current_frame, n_frames)
class Timeline: class Timeline:
def __init__(self, observer): def __init__(self, observer):
self._fps = 12 self._fps = 12
self._tags = [] self._tags = []
self._name_to_tag = {} self._name_to_tag = {}
self._current_frame = 0 self._current_frame = 0
self._timeout_sid = 0 self._timeout_sid = 0
self._observer = TimelineObserver(observer) self._observer = TimelineObserver(observer)
def add_tag(self, name, start_frame, end_frame): def add_tag(self, name, start_frame, end_frame):
tag = _Tag(name, start_frame, end_frame) tag = _Tag(name, start_frame, end_frame)
self._tags.append(tag) self._tags.append(tag)
self._name_to_tag[name] = tag self._name_to_tag[name] = tag
def remove_tag(self, name): def remove_tag(self, name):
tag = self._tags[name] tag = self._tags[name]
self._tags.remove(tag) self._tags.remove(tag)
del self._tags[name] del self._tags[name]
def _next_frame(self, tag, frame): def _next_frame(self, tag, frame):
n_frames = tag.start_frame - tag.end_frame n_frames = tag.start_frame - tag.end_frame
self._observer.next_frame(tag.name, frame, n_frames) self._observer.next_frame(tag.name, frame, n_frames)
def goto(self, tag_name, end_frame=False): def goto(self, tag_name, end_frame=False):
self.pause() self.pause()
tag = self._name_to_tag[tag_name] tag = self._name_to_tag[tag_name]
if end_frame: if end_frame:
self._current_frame = tag.end_frame self._current_frame = tag.end_frame
else: else:
self._current_frame = tag.start_frame 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): def on_tag(self, name):
tag = self._name_to_tag[name] tag = self._name_to_tag[name]
return (tag.start_frame <= self._current_frame and \ return (tag.start_frame <= self._current_frame and \
tag.end_frame >= self._current_frame) tag.end_frame >= self._current_frame)
def _get_tags_for_frame(self, frame): def _get_tags_for_frame(self, frame):
result = [] result = []
for tag in self._tags: for tag in self._tags:
if tag.start_frame <= frame and tag.end_frame >= frame: if tag.start_frame <= frame and tag.end_frame >= frame:
result.append(tag) result.append(tag)
return result return result
def _timeout_cb(self, end_frame): def _timeout_cb(self, end_frame):
for tag in self._get_tags_for_frame(self._current_frame): for tag in self._get_tags_for_frame(self._current_frame):
cur_frame = self._current_frame - tag.start_frame cur_frame = self._current_frame - tag.start_frame
self._next_frame(tag, cur_frame) self._next_frame(tag, cur_frame)
if self._current_frame < end_frame: if self._current_frame < end_frame:
self._current_frame += 1 self._current_frame += 1
return True return True
else: else:
return False return False
def play(self, start_tag=None, stop_tag=None): def play(self, start_tag=None, stop_tag=None):
self.pause() self.pause()
if start_tag == None: if start_tag == None:
start = 0 start = 0
else: else:
start = self._name_to_tag[start_tag].start_frame start = self._name_to_tag[start_tag].start_frame
if stop_tag == None: if stop_tag == None:
end = self._tags[len(self._tags) - 1].end_frame end = self._tags[len(self._tags) - 1].end_frame
else: else:
end = self._name_to_tag[stop_tag].end_frame end = self._name_to_tag[stop_tag].end_frame
self._current_frame = start self._current_frame = start
interval = 1000 / self._fps interval = 1000 / self._fps
self._timeout_sid = gobject.timeout_add( self._timeout_sid = gobject.timeout_add(
interval, self._timeout_cb, end) interval, self._timeout_cb, end)
def pause(self): def pause(self):
if self._timeout_sid > 0: if self._timeout_sid > 0:
gobject.source_remove(self._timeout_sid) gobject.source_remove(self._timeout_sid)

View File

@ -29,82 +29,82 @@ STDOUT_LEVEL = 1000
STDERR_LEVEL = 2000 STDERR_LEVEL = 2000
class LogWriter: class LogWriter:
def __init__(self, module_id): def __init__(self, module_id):
self._module_id = module_id self._module_id = module_id
logs_dir = _get_logs_dir() logs_dir = _get_logs_dir()
log_path = os.path.join(logs_dir, module_id + '.log') log_path = os.path.join(logs_dir, module_id + '.log')
self._log_file = open(log_path, 'w') self._log_file = open(log_path, 'w')
def write_record(self, record): def write_record(self, record):
self.write(record.levelno, record.msg) self.write(record.levelno, record.msg)
def write(self, level, msg): def write(self, level, msg):
if level == logging.ERROR: if level == logging.ERROR:
level_txt = 'ERROR' level_txt = 'ERROR'
elif level == logging.WARNING: elif level == logging.WARNING:
level_txt = 'WARNING' level_txt = 'WARNING'
elif level == logging.DEBUG: elif level == logging.DEBUG:
level_txt = 'DEBUG' level_txt = 'DEBUG'
elif level == logging.INFO: elif level == logging.INFO:
level_txt = 'INFO' level_txt = 'INFO'
elif level == STDERR_LEVEL: elif level == STDERR_LEVEL:
level_txt = 'STDERR' level_txt = 'STDERR'
elif level == STDOUT_LEVEL: elif level == STDOUT_LEVEL:
level_txt = 'STDOUT' level_txt = 'STDOUT'
fmt = "%s - %s\n" % (level_txt, msg) fmt = "%s - %s\n" % (level_txt, msg)
fmt = fmt.encode("utf8") fmt = fmt.encode("utf8")
self._log_file.write(fmt) self._log_file.write(fmt)
self._log_file.flush() self._log_file.flush()
class Handler(logging.Handler): class Handler(logging.Handler):
def __init__(self, writer): def __init__(self, writer):
logging.Handler.__init__(self) logging.Handler.__init__(self)
self._writer = writer self._writer = writer
def emit(self, record): def emit(self, record):
self._writer.write_record(record) self._writer.write_record(record)
class StdoutCatcher: class StdoutCatcher:
def write(self, txt): def write(self, txt):
_log_writer.write(STDOUT_LEVEL, txt) _log_writer.write(STDOUT_LEVEL, txt)
sys.__stdout__.write(txt) sys.__stdout__.write(txt)
class StderrCatcher: class StderrCatcher:
def write(self, txt): def write(self, txt):
_log_writer.write(STDERR_LEVEL, txt) _log_writer.write(STDERR_LEVEL, txt)
sys.__stderr__.write(txt) sys.__stderr__.write(txt)
def __exception_handler(typ, exc, tb): def __exception_handler(typ, exc, tb):
trace = StringIO() trace = StringIO()
traceback.print_exception(typ, exc, tb, None, trace) traceback.print_exception(typ, exc, tb, None, trace)
print >> sys.stderr, trace.getvalue() print >> sys.stderr, trace.getvalue()
_log_writer.write(logging.ERROR, trace.getvalue()) _log_writer.write(logging.ERROR, trace.getvalue())
def _get_logs_dir(): def _get_logs_dir():
logs_dir = os.path.join(env.get_profile_path(), 'logs') logs_dir = os.path.join(env.get_profile_path(), 'logs')
if not os.path.isdir(logs_dir): if not os.path.isdir(logs_dir):
os.makedirs(logs_dir) os.makedirs(logs_dir)
return logs_dir return logs_dir
def start(module_id): def start(module_id):
log_writer = LogWriter(module_id) log_writer = LogWriter(module_id)
root_logger = logging.getLogger('') root_logger = logging.getLogger('')
root_logger.setLevel(logging.DEBUG) root_logger.setLevel(logging.DEBUG)
root_logger.addHandler(Handler(log_writer)) root_logger.addHandler(Handler(log_writer))
sys.stdout = StdoutCatcher() sys.stdout = StdoutCatcher()
sys.stderr = StderrCatcher() sys.stderr = StderrCatcher()
global _log_writer global _log_writer
_log_writer = log_writer _log_writer = log_writer
sys.excepthook = __exception_handler sys.excepthook = __exception_handler
def cleanup(): def cleanup():
logs_dir = _get_logs_dir() logs_dir = _get_logs_dir()
for f in os.listdir(logs_dir): for f in os.listdir(logs_dir):
os.remove(os.path.join(logs_dir, f)) os.remove(os.path.join(logs_dir, f))

File diff suppressed because it is too large Load Diff

View File

@ -21,18 +21,18 @@ from sugar.p2p.Notifier import Notifier
from sugar.p2p import network from sugar.p2p import network
class NotificationListener: class NotificationListener:
def __init__(self, service): def __init__(self, service):
logging.debug('Start notification listener. Service %s, address %s, port %s' % (service.get_type(), service.get_address(), service.get_port())) 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(), server = network.GroupServer(service.get_address(),
service.get_port(), service.get_port(),
self._recv_multicast) self._recv_multicast)
server.start() server.start()
self._listeners = [] self._listeners = []
def add_listener(self, listener): def add_listener(self, listener):
self._listeners.append(listener) self._listeners.append(listener)
def _recv_multicast(self, msg): def _recv_multicast(self, msg):
for listener in self._listeners: for listener in self._listeners:
listener(msg) listener(msg)

View File

@ -18,10 +18,10 @@
from sugar.p2p import network from sugar.p2p import network
class Notifier: class Notifier:
def __init__(self, service): def __init__(self, service):
address = service.get_address() address = service.get_address()
port = service.get_port() port = service.get_port()
self._client = network.GroupClient(address, port) self._client = network.GroupClient(address, port)
def notify(self, msg): def notify(self, msg):
self._client.send_msg(msg) self._client.send_msg(msg)

View File

@ -26,135 +26,135 @@ from MostlyReliablePipe import MostlyReliablePipe
from sugar.presence import Service from sugar.presence import Service
def is_multicast_address(address): def is_multicast_address(address):
"""Simple numerical check for whether an IP4 address """Simple numerical check for whether an IP4 address
is in the range for multicast addresses or not.""" is in the range for multicast addresses or not."""
if not address: if not address:
return False return False
if address[3] != '.': if address[3] != '.':
return False return False
first = int(float(address[:3])) first = int(float(address[:3]))
if first >= 224 and first <= 239: if first >= 224 and first <= 239:
return True return True
return False return False
class Stream(object): class Stream(object):
def __init__(self, service): def __init__(self, service):
if not service.get_port(): if not service.get_port():
raise ValueError("service must have an address.") raise ValueError("service must have an address.")
self._service = service self._service = service
self._reader_port = self._service.get_port() self._reader_port = self._service.get_port()
self._writer_port = self._reader_port self._writer_port = self._reader_port
self._address = self._service.get_address() self._address = self._service.get_address()
self._callback = None self._callback = None
def new_from_service(service, start_reader=True): def new_from_service(service, start_reader=True):
if is_multicast_address(service.get_address()): if is_multicast_address(service.get_address()):
return MulticastStream(service) return MulticastStream(service)
else: else:
return UnicastStream(service, start_reader) return UnicastStream(service, start_reader)
new_from_service = staticmethod(new_from_service) new_from_service = staticmethod(new_from_service)
def set_data_listener(self, callback): def set_data_listener(self, callback):
self._callback = callback self._callback = callback
def _recv(self, address, data): def _recv(self, address, data):
if self._callback: if self._callback:
self._callback(address, data) self._callback(address, data)
class UnicastStreamWriter(object): class UnicastStreamWriter(object):
def __init__(self, stream, service): def __init__(self, stream, service):
# set up the writer # set up the writer
self._service = service self._service = service
if not service.get_address(): if not service.get_address():
raise ValueError("service must have a valid address.") raise ValueError("service must have a valid address.")
self._address = self._service.get_address() self._address = self._service.get_address()
self._port = self._service.get_port() self._port = self._service.get_port()
self._xmlrpc_addr = "http://%s:%d" % (self._address, self._port) self._xmlrpc_addr = "http://%s:%d" % (self._address, self._port)
self._writer = network.GlibServerProxy(self._xmlrpc_addr) self._writer = network.GlibServerProxy(self._xmlrpc_addr)
def write(self, xmlrpc_data): def write(self, xmlrpc_data):
"""Write some data to the default endpoint of this pipe on the remote server.""" """Write some data to the default endpoint of this pipe on the remote server."""
try: try:
self._writer.message(None, None, xmlrpc_data) self._writer.message(None, None, xmlrpc_data)
return True return True
except (socket.error, xmlrpclib.Fault, xmlrpclib.ProtocolError): except (socket.error, xmlrpclib.Fault, xmlrpclib.ProtocolError):
traceback.print_exc() traceback.print_exc()
return False return False
def custom_request(self, method_name, request_cb, user_data, *args): def custom_request(self, method_name, request_cb, user_data, *args):
"""Call a custom XML-RPC method on the remote server.""" """Call a custom XML-RPC method on the remote server."""
try: try:
method = getattr(self._writer, method_name) method = getattr(self._writer, method_name)
method(request_cb, user_data, *args) method(request_cb, user_data, *args)
return True return True
except (socket.error, xmlrpclib.Fault, xmlrpclib.ProtocolError): except (socket.error, xmlrpclib.Fault, xmlrpclib.ProtocolError):
traceback.print_exc() traceback.print_exc()
return False return False
class UnicastStream(Stream): class UnicastStream(Stream):
def __init__(self, service, start_reader=True): def __init__(self, service, start_reader=True):
"""Initializes the stream. If the 'start_reader' argument is True, """Initializes the stream. If the 'start_reader' argument is True,
the stream will initialize and start a new stream reader, if it 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 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 start_reader() method to start the stream reader and be able to
receive any data from the stream.""" receive any data from the stream."""
Stream.__init__(self, service) Stream.__init__(self, service)
if start_reader: if start_reader:
self.start_reader() self.start_reader()
def start_reader(self): def start_reader(self):
"""Start the stream's reader, which for UnicastStream objects is """Start the stream's reader, which for UnicastStream objects is
and XMLRPC server. If there's a port conflict with some other and XMLRPC server. If there's a port conflict with some other
service, the reader will try to find another port to use instead. service, the reader will try to find another port to use instead.
Returns the port number used for the reader.""" Returns the port number used for the reader."""
# Set up the reader # Set up the reader
self._reader = network.GlibXMLRPCServer(("", self._reader_port)) self._reader = network.GlibXMLRPCServer(("", self._reader_port))
self._reader.register_function(self._message, "message") self._reader.register_function(self._message, "message")
def _message(self, message): def _message(self, message):
"""Called by the XMLRPC server when network data arrives.""" """Called by the XMLRPC server when network data arrives."""
address = network.get_authinfo() address = network.get_authinfo()
self._recv(address, message) self._recv(address, message)
return True return True
def register_reader_handler(self, handler, name): def register_reader_handler(self, handler, name):
"""Register a custom message handler with the reader. This call """Register a custom message handler with the reader. This call
adds a custom XMLRPC method call with the name 'name' to the reader's adds a custom XMLRPC method call with the name 'name' to the reader's
XMLRPC server, which then calls the 'handler' argument back when XMLRPC server, which then calls the 'handler' argument back when
a method call for it arrives over the network.""" a method call for it arrives over the network."""
if name == "message": if name == "message":
raise ValueError("Handler name 'message' is a reserved handler.") raise ValueError("Handler name 'message' is a reserved handler.")
self._reader.register_function(handler, name) self._reader.register_function(handler, name)
def new_writer(self, service): def new_writer(self, service):
"""Return a new stream writer object.""" """Return a new stream writer object."""
return UnicastStreamWriter(self, service) return UnicastStreamWriter(self, service)
class MulticastStream(Stream): class MulticastStream(Stream):
def __init__(self, service): def __init__(self, service):
Stream.__init__(self, service) Stream.__init__(self, service)
self._service = service self._service = service
self._internal_start_reader() self._internal_start_reader()
def start_reader(self): def start_reader(self):
return self._reader_port return self._reader_port
def _internal_start_reader(self): def _internal_start_reader(self):
logging.debug('Start multicast stream, address %s, port %d' % (self._address, self._reader_port)) logging.debug('Start multicast stream, address %s, port %d' % (self._address, self._reader_port))
if not self._service.get_address(): if not self._service.get_address():
raise ValueError("service must have a valid address.") raise ValueError("service must have a valid address.")
self._pipe = MostlyReliablePipe('', self._address, self._reader_port, self._pipe = MostlyReliablePipe('', self._address, self._reader_port,
self._recv_data_cb) self._recv_data_cb)
self._pipe.start() self._pipe.start()
def write(self, data): def write(self, data):
self._pipe.send(data) self._pipe.send(data)
def _recv_data_cb(self, address, data, user_data=None): def _recv_data_cb(self, address, data, user_data=None):
self._recv(address[0], data) self._recv(address[0], data)
def new_writer(self, service=None): def new_writer(self, service=None):
return self return self

View File

@ -35,347 +35,347 @@ RESULT_SUCCESS = 1
__authinfos = {} __authinfos = {}
def _add_authinfo(authinfo): def _add_authinfo(authinfo):
__authinfos[threading.currentThread()] = authinfo __authinfos[threading.currentThread()] = authinfo
def get_authinfo(): def get_authinfo():
return __authinfos.get(threading.currentThread()) return __authinfos.get(threading.currentThread())
def _del_authinfo(): def _del_authinfo():
del __authinfos[threading.currentThread()] del __authinfos[threading.currentThread()]
class GlibTCPServer(SocketServer.TCPServer): class GlibTCPServer(SocketServer.TCPServer):
"""GlibTCPServer """GlibTCPServer
Integrate socket accept into glib mainloop. Integrate socket accept into glib mainloop.
""" """
allow_reuse_address = True allow_reuse_address = True
request_queue_size = 20 request_queue_size = 20
def __init__(self, server_address, RequestHandlerClass): def __init__(self, server_address, RequestHandlerClass):
SocketServer.TCPServer.__init__(self, server_address, RequestHandlerClass) SocketServer.TCPServer.__init__(self, server_address, RequestHandlerClass)
self.socket.setblocking(0) # Set nonblocking self.socket.setblocking(0) # Set nonblocking
# Watch the listener socket for data # Watch the listener socket for data
gobject.io_add_watch(self.socket, gobject.IO_IN, self._handle_accept) gobject.io_add_watch(self.socket, gobject.IO_IN, self._handle_accept)
def _handle_accept(self, source, condition): def _handle_accept(self, source, condition):
"""Process incoming data on the server's socket by doing an accept() """Process incoming data on the server's socket by doing an accept()
via handle_request().""" via handle_request()."""
if not (condition & gobject.IO_IN): if not (condition & gobject.IO_IN):
return True return True
self.handle_request() self.handle_request()
return True return True
class GlibXMLRPCRequestHandler(SimpleXMLRPCServer.SimpleXMLRPCRequestHandler): class GlibXMLRPCRequestHandler(SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
""" GlibXMLRPCRequestHandler """ GlibXMLRPCRequestHandler
The stock SimpleXMLRPCRequestHandler and server don't allow any way to pass 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 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. _processes_ the request. So we have to store it in a thread-indexed dict.
""" """
def do_POST(self): def do_POST(self):
_add_authinfo(self.client_address) _add_authinfo(self.client_address)
try: try:
SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.do_POST(self) SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.do_POST(self)
except socket.timeout: except socket.timeout:
pass pass
except socket.error, e: except socket.error, e:
print "Error (%s): socket error - '%s'" % (self.client_address, e) print "Error (%s): socket error - '%s'" % (self.client_address, e)
except: except:
print "Error while processing POST:" print "Error while processing POST:"
traceback.print_exc() traceback.print_exc()
_del_authinfo() _del_authinfo()
class GlibXMLRPCServer(GlibTCPServer, SimpleXMLRPCServer.SimpleXMLRPCDispatcher): class GlibXMLRPCServer(GlibTCPServer, SimpleXMLRPCServer.SimpleXMLRPCDispatcher):
"""GlibXMLRPCServer """GlibXMLRPCServer
Use nonblocking sockets and handle the accept via glib rather than Use nonblocking sockets and handle the accept via glib rather than
blocking on accept(). blocking on accept().
""" """
def __init__(self, addr, requestHandler=GlibXMLRPCRequestHandler, logRequests=0): def __init__(self, addr, requestHandler=GlibXMLRPCRequestHandler, logRequests=0):
self.logRequests = logRequests self.logRequests = logRequests
SimpleXMLRPCServer.SimpleXMLRPCDispatcher.__init__(self) SimpleXMLRPCServer.SimpleXMLRPCDispatcher.__init__(self)
GlibTCPServer.__init__(self, addr, requestHandler) GlibTCPServer.__init__(self, addr, requestHandler)
def _marshaled_dispatch(self, data, dispatch_method = None): def _marshaled_dispatch(self, data, dispatch_method = None):
"""Dispatches an XML-RPC method from marshalled (XML) data. """Dispatches an XML-RPC method from marshalled (XML) data.
XML-RPC methods are dispatched from the marshalled (XML) data XML-RPC methods are dispatched from the marshalled (XML) data
using the _dispatch method and the result is returned as using the _dispatch method and the result is returned as
marshalled data. For backwards compatibility, a dispatch marshalled data. For backwards compatibility, a dispatch
function can be provided as an argument (see comment in function can be provided as an argument (see comment in
SimpleXMLRPCRequestHandler.do_POST) but overriding the SimpleXMLRPCRequestHandler.do_POST) but overriding the
existing method through subclassing is the prefered means existing method through subclassing is the prefered means
of changing method dispatch behavior. of changing method dispatch behavior.
""" """
params, method = xmlrpclib.loads(data) params, method = xmlrpclib.loads(data)
# generate response # generate response
try: try:
if dispatch_method is not None: if dispatch_method is not None:
response = dispatch_method(method, params) response = dispatch_method(method, params)
else: else:
response = self._dispatch(method, params) response = self._dispatch(method, params)
# wrap response in a singleton tuple # wrap response in a singleton tuple
response = (response,) response = (response,)
response = xmlrpclib.dumps(response, methodresponse=1) response = xmlrpclib.dumps(response, methodresponse=1)
except xmlrpclib.Fault, fault: except xmlrpclib.Fault, fault:
response = xmlrpclib.dumps(fault) response = xmlrpclib.dumps(fault)
except: except:
print "Exception while processing request:" print "Exception while processing request:"
traceback.print_exc() traceback.print_exc()
# report exception back to server # report exception back to server
response = xmlrpclib.dumps( response = xmlrpclib.dumps(
xmlrpclib.Fault(1, "%s:%s" % (sys.exc_type, sys.exc_value)) xmlrpclib.Fault(1, "%s:%s" % (sys.exc_type, sys.exc_value))
) )
return response return response
class GlibHTTP(httplib.HTTP): class GlibHTTP(httplib.HTTP):
"""Subclass HTTP so we can return it's connection class' socket.""" """Subclass HTTP so we can return it's connection class' socket."""
def connect(self, host=None, port=None): def connect(self, host=None, port=None):
httplib.HTTP.connect(self, host, port) httplib.HTTP.connect(self, host, port)
self._conn.sock.setblocking(0) self._conn.sock.setblocking(0)
def get_sock(self): def get_sock(self):
return self._conn.sock return self._conn.sock
class GlibXMLRPCTransport(xmlrpclib.Transport): class GlibXMLRPCTransport(xmlrpclib.Transport):
"""Integrate the request with the glib mainloop rather than blocking.""" """Integrate the request with the glib mainloop rather than blocking."""
## ##
# Connect to server. # Connect to server.
# #
# @param host Target host. # @param host Target host.
# @return A connection handle. # @return A connection handle.
def __init__(self): def __init__(self):
pass pass
def make_connection(self, host): def make_connection(self, host):
"""Use our own connection object so we can get its socket.""" """Use our own connection object so we can get its socket."""
# create a HTTP connection object from a host descriptor # create a HTTP connection object from a host descriptor
host, extra_headers, x509 = self.get_host_info(host) host, extra_headers, x509 = self.get_host_info(host)
return GlibHTTP(host) return GlibHTTP(host)
## ##
# Send a complete request, and parse the response. # Send a complete request, and parse the response.
# #
# @param host Target host. # @param host Target host.
# @param handler Target PRC handler. # @param handler Target PRC handler.
# @param request_body XML-RPC request body. # @param request_body XML-RPC request body.
# @param verbose Debugging flag. # @param verbose Debugging flag.
# @return Parsed response. # @return Parsed response.
def start_request(self, host, handler, request_body, verbose=0, request_cb=None, user_data=None): 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 """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 server. The bottom half bits get run when the remote server's response
actually comes back.""" actually comes back."""
# issue XML-RPC request # issue XML-RPC request
h = self.make_connection(host) h = self.make_connection(host)
if verbose: if verbose:
h.set_debuglevel(1) h.set_debuglevel(1)
self.send_request(h, handler, request_body) self.send_request(h, handler, request_body)
self.send_host(h, host) self.send_host(h, host)
self.send_user_agent(h) self.send_user_agent(h)
self.send_content(h, request_body) self.send_content(h, request_body)
# Schedule a GIOWatch so we don't block waiting for the response # 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, gobject.io_add_watch(h.get_sock(), gobject.IO_IN, self._finish_request,
h, host, handler, verbose, request_cb, user_data) h, host, handler, verbose, request_cb, user_data)
def _finish_request(self, source, condition, 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.""" """Parse and return response when the remote server actually returns it."""
if not (condition & gobject.IO_IN): if not (condition & gobject.IO_IN):
return True return True
try: try:
errcode, errmsg, headers = h.getreply() errcode, errmsg, headers = h.getreply()
except socket.error, err: except socket.error, err:
if err[0] != 104: if err[0] != 104:
raise socket.error(err) raise socket.error(err)
else: else:
gobject.idle_add(request_cb, RESULT_FAILED, None, user_data) gobject.idle_add(request_cb, RESULT_FAILED, None, user_data)
return False return False
if errcode != 200: if errcode != 200:
raise xmlrpclib.ProtocolError(host + handler, errcode, errmsg, headers) raise xmlrpclib.ProtocolError(host + handler, errcode, errmsg, headers)
self.verbose = verbose self.verbose = verbose
response = self._parse_response(h.getfile(), h.get_sock()) response = self._parse_response(h.getfile(), h.get_sock())
if request_cb: if request_cb:
if len(response) == 1: if len(response) == 1:
response = response[0] response = response[0]
gobject.idle_add(request_cb, RESULT_SUCCESS, response, user_data) gobject.idle_add(request_cb, RESULT_SUCCESS, response, user_data)
return False return False
class _Method: class _Method:
"""Right, so python people thought it would be funny to make this """Right, so python people thought it would be funny to make this
class private to xmlrpclib.py...""" class private to xmlrpclib.py..."""
# some magic to bind an XML-RPC method to an RPC server. # some magic to bind an XML-RPC method to an RPC server.
# supports "nested" methods (e.g. examples.getStateName) # supports "nested" methods (e.g. examples.getStateName)
def __init__(self, send, name): def __init__(self, send, name):
self.__send = send self.__send = send
self.__name = name self.__name = name
def __getattr__(self, name): def __getattr__(self, name):
return _Method(self.__send, "%s.%s" % (self.__name, name)) return _Method(self.__send, "%s.%s" % (self.__name, name))
def __call__(self, request_cb, user_data, *args): def __call__(self, request_cb, user_data, *args):
return self.__send(self.__name, request_cb, user_data, args) return self.__send(self.__name, request_cb, user_data, args)
class GlibServerProxy(xmlrpclib.ServerProxy): class GlibServerProxy(xmlrpclib.ServerProxy):
"""Subclass xmlrpclib.ServerProxy so we can run the XML-RPC request """Subclass xmlrpclib.ServerProxy so we can run the XML-RPC request
in two parts, integrated with the glib mainloop, such that we don't in two parts, integrated with the glib mainloop, such that we don't
block anywhere. block anywhere.
Using this object is somewhat special; it requires more arguments to each Using this object is somewhat special; it requires more arguments to each
XML-RPC request call than the normal xmlrpclib.ServerProxy object: XML-RPC request call than the normal xmlrpclib.ServerProxy object:
client = GlibServerProxy("http://127.0.0.1:8888") client = GlibServerProxy("http://127.0.0.1:8888")
user_data = "bar" user_data = "bar"
xmlrpc_arg1 = "test" xmlrpc_arg1 = "test"
xmlrpc_arg2 = "foo" xmlrpc_arg2 = "foo"
client.test(xmlrpc_test_cb, user_data, xmlrpc_arg1, xmlrpc_arg2) client.test(xmlrpc_test_cb, user_data, xmlrpc_arg1, xmlrpc_arg2)
Here, 'xmlrpc_test_cb' is the callback function, which has the following Here, 'xmlrpc_test_cb' is the callback function, which has the following
signature: signature:
def xmlrpc_test_cb(result_status, response, user_data=None): def xmlrpc_test_cb(result_status, response, user_data=None):
... ...
""" """
def __init__(self, uri, encoding=None, verbose=0, allow_none=0): def __init__(self, uri, encoding=None, verbose=0, allow_none=0):
self._transport = GlibXMLRPCTransport() self._transport = GlibXMLRPCTransport()
self._encoding = encoding self._encoding = encoding
self._verbose = verbose self._verbose = verbose
self._allow_none = allow_none self._allow_none = allow_none
xmlrpclib.ServerProxy.__init__(self, uri, self._transport, encoding, verbose, allow_none) xmlrpclib.ServerProxy.__init__(self, uri, self._transport, encoding, verbose, allow_none)
# get the url # get the url
import urllib import urllib
urltype, uri = urllib.splittype(uri) urltype, uri = urllib.splittype(uri)
if urltype not in ("http", "https"): if urltype not in ("http", "https"):
raise IOError, "unsupported XML-RPC protocol" raise IOError, "unsupported XML-RPC protocol"
self._host, self._handler = urllib.splithost(uri) self._host, self._handler = urllib.splithost(uri)
if not self._handler: if not self._handler:
self._handler = "/RPC2" self._handler = "/RPC2"
def __request(self, methodname, request_cb, user_data, params): def __request(self, methodname, request_cb, user_data, params):
"""Call the method on the remote server. We just start the request here """Call the method on the remote server. We just start the request here
and the transport itself takes care of scheduling the response callback 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.""" when the remote server returns the response. We don't want to block anywhere."""
request = xmlrpclib.dumps(params, methodname, encoding=self._encoding, request = xmlrpclib.dumps(params, methodname, encoding=self._encoding,
allow_none=self._allow_none) allow_none=self._allow_none)
try: try:
response = self._transport.start_request( response = self._transport.start_request(
self._host, self._host,
self._handler, self._handler,
request, request,
verbose=self._verbose, verbose=self._verbose,
request_cb=request_cb, request_cb=request_cb,
user_data=user_data user_data=user_data
) )
except socket.error, exc: except socket.error, exc:
gobject.idle_add(request_cb, RESULT_FAILED, None, user_data) gobject.idle_add(request_cb, RESULT_FAILED, None, user_data)
def __getattr__(self, name): def __getattr__(self, name):
# magic method dispatcher # magic method dispatcher
return _Method(self.__request, name) return _Method(self.__request, name)
class GroupServer(object): class GroupServer(object):
_MAX_MSG_SIZE = 500 _MAX_MSG_SIZE = 500
def __init__(self, address, port, data_cb): def __init__(self, address, port, data_cb):
self._address = address self._address = address
self._port = port self._port = port
self._data_cb = data_cb self._data_cb = data_cb
self._setup_listener() self._setup_listener()
def _setup_listener(self): def _setup_listener(self):
# Listener socket # Listener socket
self._listen_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self._listen_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# Set some options to make it multicast-friendly # 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_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_TTL, 20)
self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_LOOP, 1) self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_LOOP, 1)
def start(self): def start(self):
# Set some more multicast options # Set some more multicast options
self._listen_sock.bind(('', self._port)) self._listen_sock.bind(('', self._port))
self._listen_sock.settimeout(2) self._listen_sock.settimeout(2)
intf = socket.gethostbyname(socket.gethostname()) 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_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')) 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 # Watch the listener socket for data
gobject.io_add_watch(self._listen_sock, gobject.IO_IN, self._handle_incoming_data) gobject.io_add_watch(self._listen_sock, gobject.IO_IN, self._handle_incoming_data)
def _handle_incoming_data(self, source, condition): def _handle_incoming_data(self, source, condition):
if not (condition & gobject.IO_IN): if not (condition & gobject.IO_IN):
return True return True
msg = {} msg = {}
msg['data'], (msg['addr'], msg['port']) = source.recvfrom(self._MAX_MSG_SIZE) msg['data'], (msg['addr'], msg['port']) = source.recvfrom(self._MAX_MSG_SIZE)
if self._data_cb: if self._data_cb:
self._data_cb(msg) self._data_cb(msg)
return True return True
class GroupClient(object): class GroupClient(object):
_MAX_MSG_SIZE = 500 _MAX_MSG_SIZE = 500
def __init__(self, address, port): def __init__(self, address, port):
self._address = address self._address = address
self._port = port self._port = port
self._send_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self._send_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# Make the socket multicast-aware, and set TTL. # 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.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 20) # Change TTL (=20) to suit
def send_msg(self, data): def send_msg(self, data):
self._send_sock.sendto(data, (self._address, self._port)) self._send_sock.sendto(data, (self._address, self._port))
class Test(object): class Test(object):
def test(self, arg1): def test(self, arg1):
print "Request got %s" % arg1 print "Request got %s" % arg1
return "success" return "success"
def xmlrpc_test_cb(response, user_data=None): def xmlrpc_test_cb(response, user_data=None):
print "Response was %s, user_data was %s" % (response, user_data) print "Response was %s, user_data was %s" % (response, user_data)
import gtk import gtk
gtk.main_quit() gtk.main_quit()
def xmlrpc_test(): def xmlrpc_test():
client = GlibServerProxy("http://127.0.0.1:8888") client = GlibServerProxy("http://127.0.0.1:8888")
client.test(xmlrpc_test_cb, "bar", "test data") client.test(xmlrpc_test_cb, "bar", "test data")
def main(): def main():
import gtk import gtk
server = GlibXMLRPCServer(("", 8888)) server = GlibXMLRPCServer(("", 8888))
inst = Test() inst = Test()
server.register_instance(inst) server.register_instance(inst)
gobject.idle_add(xmlrpc_test) gobject.idle_add(xmlrpc_test)
try: try:
gtk.main() gtk.main()
except KeyboardInterrupt: except KeyboardInterrupt:
print 'Ctrl+C pressed, exiting...' print 'Ctrl+C pressed, exiting...'
print "Done." print "Done."
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@ -20,98 +20,98 @@ import dbus
class Activity(gobject.GObject): class Activity(gobject.GObject):
__gsignals__ = { __gsignals__ = {
'buddy-joined': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, 'buddy-joined': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([gobject.TYPE_PYOBJECT])), ([gobject.TYPE_PYOBJECT])),
'buddy-left': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, 'buddy-left': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([gobject.TYPE_PYOBJECT])), ([gobject.TYPE_PYOBJECT])),
'service-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, 'service-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([gobject.TYPE_PYOBJECT])), ([gobject.TYPE_PYOBJECT])),
'service-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, 'service-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([gobject.TYPE_PYOBJECT])) ([gobject.TYPE_PYOBJECT]))
} }
_PRESENCE_SERVICE = "org.laptop.Presence" _PRESENCE_SERVICE = "org.laptop.Presence"
_ACTIVITY_DBUS_INTERFACE = "org.laptop.Presence.Activity" _ACTIVITY_DBUS_INTERFACE = "org.laptop.Presence.Activity"
def __init__(self, bus, new_obj_cb, del_obj_cb, object_path): def __init__(self, bus, new_obj_cb, del_obj_cb, object_path):
gobject.GObject.__init__(self) gobject.GObject.__init__(self)
self._object_path = object_path self._object_path = object_path
self._ps_new_object = new_obj_cb self._ps_new_object = new_obj_cb
self._ps_del_object = del_obj_cb self._ps_del_object = del_obj_cb
bobj = bus.get_object(self._PRESENCE_SERVICE, object_path) bobj = bus.get_object(self._PRESENCE_SERVICE, object_path)
self._activity = dbus.Interface(bobj, self._ACTIVITY_DBUS_INTERFACE) self._activity = dbus.Interface(bobj, self._ACTIVITY_DBUS_INTERFACE)
self._activity.connect_to_signal('BuddyJoined', self._buddy_joined_cb) 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('BuddyLeft', self._buddy_left_cb)
self._activity.connect_to_signal('ServiceAppeared', self._service_appeared_cb) self._activity.connect_to_signal('ServiceAppeared', self._service_appeared_cb)
self._activity.connect_to_signal('ServiceDisappeared', self._service_disappeared_cb) self._activity.connect_to_signal('ServiceDisappeared', self._service_disappeared_cb)
self._id = None self._id = None
self._color = None self._color = None
def object_path(self): def object_path(self):
return self._object_path return self._object_path
def _emit_buddy_joined_signal(self, object_path): def _emit_buddy_joined_signal(self, object_path):
self.emit('buddy-joined', self._ps_new_object(object_path)) self.emit('buddy-joined', self._ps_new_object(object_path))
return False return False
def _buddy_joined_cb(self, object_path): def _buddy_joined_cb(self, object_path):
gobject.idle_add(self._emit_buddy_joined_signal, object_path) gobject.idle_add(self._emit_buddy_joined_signal, object_path)
def _emit_buddy_left_signal(self, object_path): def _emit_buddy_left_signal(self, object_path):
self.emit('buddy-left', self._ps_new_object(object_path)) self.emit('buddy-left', self._ps_new_object(object_path))
return False return False
def _buddy_left_cb(self, object_path): def _buddy_left_cb(self, object_path):
gobject.idle_add(self._emit_buddy_left_signal, object_path) gobject.idle_add(self._emit_buddy_left_signal, object_path)
def _emit_service_appeared_signal(self, object_path): def _emit_service_appeared_signal(self, object_path):
self.emit('service-appeared', self._ps_new_object(object_path)) self.emit('service-appeared', self._ps_new_object(object_path))
return False return False
def _service_appeared_cb(self, object_path): def _service_appeared_cb(self, object_path):
gobject.idle_add(self._emit_service_appeared_signal, object_path) gobject.idle_add(self._emit_service_appeared_signal, object_path)
def _emit_service_disappeared_signal(self, object_path): def _emit_service_disappeared_signal(self, object_path):
self.emit('service-disappeared', self._ps_new_object(object_path)) self.emit('service-disappeared', self._ps_new_object(object_path))
return False return False
def _service_disappeared_cb(self, object_path): def _service_disappeared_cb(self, object_path):
gobject.idle_add(self._emit_service_disappeared_signal, object_path) gobject.idle_add(self._emit_service_disappeared_signal, object_path)
def get_id(self): def get_id(self):
# Cache activity ID, which should never change anyway # Cache activity ID, which should never change anyway
if not self._id: if not self._id:
self._id = self._activity.getId() self._id = self._activity.getId()
return self._id return self._id
def get_color(self): def get_color(self):
if not self._color: if not self._color:
self._color = self._activity.getColor() self._color = self._activity.getColor()
return self._color return self._color
def get_services(self): def get_services(self):
resp = self._activity.getServices() resp = self._activity.getServices()
servs = [] servs = []
for item in resp: for item in resp:
servs.append(self._ps_new_object(item)) servs.append(self._ps_new_object(item))
return servs return servs
def get_services_of_type(self, stype): def get_services_of_type(self, stype):
resp = self._activity.getServicesOfType(stype) resp = self._activity.getServicesOfType(stype)
servs = [] servs = []
for item in resp: for item in resp:
servs.append(self._ps_new_object(item)) servs.append(self._ps_new_object(item))
return servs return servs
def get_joined_buddies(self): def get_joined_buddies(self):
resp = self._activity.getJoinedBuddies() resp = self._activity.getJoinedBuddies()
buddies = [] buddies = []
for item in resp: for item in resp:
buddies.append(self._ps_new_object(item)) buddies.append(self._ps_new_object(item))
return buddies return buddies
def owner_has_joined(self): def owner_has_joined(self):
# FIXME # FIXME
return False return False

View File

@ -21,173 +21,173 @@ import dbus
class Buddy(gobject.GObject): class Buddy(gobject.GObject):
__gsignals__ = { __gsignals__ = {
'icon-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, 'icon-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([])), ([])),
'disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, 'disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([])), ([])),
'service-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, 'service-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([gobject.TYPE_PYOBJECT])), ([gobject.TYPE_PYOBJECT])),
'service-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, 'service-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([gobject.TYPE_PYOBJECT])), ([gobject.TYPE_PYOBJECT])),
'joined-activity': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, 'joined-activity': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([gobject.TYPE_PYOBJECT])), ([gobject.TYPE_PYOBJECT])),
'left-activity': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, 'left-activity': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([gobject.TYPE_PYOBJECT])), ([gobject.TYPE_PYOBJECT])),
'property-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, 'property-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([gobject.TYPE_PYOBJECT])), ([gobject.TYPE_PYOBJECT])),
'current-activity-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, 'current-activity-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([gobject.TYPE_PYOBJECT])) ([gobject.TYPE_PYOBJECT]))
} }
_PRESENCE_SERVICE = "org.laptop.Presence" _PRESENCE_SERVICE = "org.laptop.Presence"
_BUDDY_DBUS_INTERFACE = "org.laptop.Presence.Buddy" _BUDDY_DBUS_INTERFACE = "org.laptop.Presence.Buddy"
def __init__(self, bus, new_obj_cb, del_obj_cb, object_path): def __init__(self, bus, new_obj_cb, del_obj_cb, object_path):
gobject.GObject.__init__(self) gobject.GObject.__init__(self)
self._object_path = object_path self._object_path = object_path
self._ps_new_object = new_obj_cb self._ps_new_object = new_obj_cb
self._ps_del_object = del_obj_cb self._ps_del_object = del_obj_cb
self._properties = {} self._properties = {}
bobj = bus.get_object(self._PRESENCE_SERVICE, object_path) bobj = bus.get_object(self._PRESENCE_SERVICE, object_path)
self._buddy = dbus.Interface(bobj, self._BUDDY_DBUS_INTERFACE) self._buddy = dbus.Interface(bobj, self._BUDDY_DBUS_INTERFACE)
self._buddy.connect_to_signal('IconChanged', self._icon_changed_cb) 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('ServiceAppeared', self._service_appeared_cb)
self._buddy.connect_to_signal('ServiceDisappeared', self._service_disappeared_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('Disappeared', self._disappeared_cb)
self._buddy.connect_to_signal('JoinedActivity', self._joined_activity_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('LeftActivity', self._left_activity_cb)
self._buddy.connect_to_signal('PropertyChanged', self._property_changed_cb) self._buddy.connect_to_signal('PropertyChanged', self._property_changed_cb)
self._buddy.connect_to_signal('CurrentActivityChanged', self._current_activity_changed_cb) self._buddy.connect_to_signal('CurrentActivityChanged', self._current_activity_changed_cb)
self._properties = self._get_properties_helper() self._properties = self._get_properties_helper()
self._current_activity = None self._current_activity = None
try: try:
self._current_activity = self._buddy.getCurrentActivity() self._current_activity = self._buddy.getCurrentActivity()
except Exception, e: except Exception, e:
pass pass
def _get_properties_helper(self): def _get_properties_helper(self):
props = self._buddy.getProperties() props = self._buddy.getProperties()
if not props: if not props:
return {} return {}
return props return props
def object_path(self): def object_path(self):
return self._object_path return self._object_path
def _emit_icon_changed_signal(self): def _emit_icon_changed_signal(self):
self.emit('icon-changed') self.emit('icon-changed')
return False return False
def _icon_changed_cb(self): def _icon_changed_cb(self):
gobject.idle_add(self._emit_icon_changed_signal) gobject.idle_add(self._emit_icon_changed_signal)
def _emit_disappeared_signal(self): def _emit_disappeared_signal(self):
self.emit('disappeared') self.emit('disappeared')
def _disappeared_cb(self): def _disappeared_cb(self):
gobject.idle_add(self._emit_disappeared_signal) gobject.idle_add(self._emit_disappeared_signal)
def _emit_service_appeared_signal(self, object_path): def _emit_service_appeared_signal(self, object_path):
self.emit('service-appeared', self._ps_new_object(object_path)) self.emit('service-appeared', self._ps_new_object(object_path))
return False return False
def _service_appeared_cb(self, object_path): def _service_appeared_cb(self, object_path):
gobject.idle_add(self._emit_service_appeared_signal, object_path) gobject.idle_add(self._emit_service_appeared_signal, object_path)
def _emit_service_disappeared_signal(self, object_path): def _emit_service_disappeared_signal(self, object_path):
self.emit('service-disappeared', self._ps_new_object(object_path)) self.emit('service-disappeared', self._ps_new_object(object_path))
return False return False
def _service_disappeared_cb(self, object_path): def _service_disappeared_cb(self, object_path):
gobject.idle_add(self._emit_service_disappeared_signal, object_path) gobject.idle_add(self._emit_service_disappeared_signal, object_path)
def _emit_joined_activity_signal(self, object_path): def _emit_joined_activity_signal(self, object_path):
self.emit('joined-activity', self._ps_new_object(object_path)) self.emit('joined-activity', self._ps_new_object(object_path))
return False return False
def _joined_activity_cb(self, object_path): def _joined_activity_cb(self, object_path):
gobject.idle_add(self._emit_joined_activity_signal, object_path) gobject.idle_add(self._emit_joined_activity_signal, object_path)
def _emit_left_activity_signal(self, object_path): def _emit_left_activity_signal(self, object_path):
self.emit('left-activity', self._ps_new_object(object_path)) self.emit('left-activity', self._ps_new_object(object_path))
return False return False
def _left_activity_cb(self, object_path): def _left_activity_cb(self, object_path):
gobject.idle_add(self._emit_left_activity_signal, object_path) gobject.idle_add(self._emit_left_activity_signal, object_path)
def _handle_property_changed_signal(self, prop_list): def _handle_property_changed_signal(self, prop_list):
self._properties = self._get_properties_helper() self._properties = self._get_properties_helper()
self.emit('property-changed', prop_list) self.emit('property-changed', prop_list)
return False return False
def _property_changed_cb(self, prop_list): def _property_changed_cb(self, prop_list):
gobject.idle_add(self._handle_property_changed_signal, prop_list) gobject.idle_add(self._handle_property_changed_signal, prop_list)
def _handle_current_activity_changed_signal(self, act_list): def _handle_current_activity_changed_signal(self, act_list):
if len(act_list) == 0: if len(act_list) == 0:
self._current_activity = None self._current_activity = None
self.emit('current-activity-changed', None) self.emit('current-activity-changed', None)
else: else:
self._current_activity = act_list[0] self._current_activity = act_list[0]
self.emit('current-activity-changed', self._ps_new_object(act_list[0])) self.emit('current-activity-changed', self._ps_new_object(act_list[0]))
return False return False
def _current_activity_changed_cb(self, act_list): def _current_activity_changed_cb(self, act_list):
gobject.idle_add(self._handle_current_activity_changed_signal, act_list) gobject.idle_add(self._handle_current_activity_changed_signal, act_list)
def get_name(self): def get_name(self):
return self._properties['name'] return self._properties['name']
def get_ip4_address(self): def get_ip4_address(self):
return self._properties['ip4_address'] return self._properties['ip4_address']
def is_owner(self): def is_owner(self):
return self._properties['owner'] return self._properties['owner']
def get_color(self): def get_color(self):
return self._properties['color'] return self._properties['color']
def get_icon(self): def get_icon(self):
return self._buddy.getIcon() return self._buddy.getIcon()
def get_current_activity(self): def get_current_activity(self):
if not self._current_activity: if not self._current_activity:
return None return None
return self._ps_new_object(self._current_activity) return self._ps_new_object(self._current_activity)
def get_icon_pixbuf(self): def get_icon_pixbuf(self):
icon = self._buddy.getIcon() icon = self._buddy.getIcon()
if icon and len(icon): if icon and len(icon):
pbl = gtk.gdk.PixbufLoader() pbl = gtk.gdk.PixbufLoader()
icon_data = "" icon_data = ""
for item in icon: for item in icon:
if item < 0: if item < 0:
item = item + 128 item = item + 128
icon_data = icon_data + chr(item) icon_data = icon_data + chr(item)
pbl.write(icon_data) pbl.write(icon_data)
pbl.close() pbl.close()
return pbl.get_pixbuf() return pbl.get_pixbuf()
else: else:
return None return None
def get_service_of_type(self, stype, activity=None): def get_service_of_type(self, stype, activity=None):
try: try:
act_op = "/" act_op = "/"
if activity: if activity:
act_op = activity.object_path() act_op = activity.object_path()
object_path = self._buddy.getServiceOfType(stype, act_op) object_path = self._buddy.getServiceOfType(stype, act_op)
except dbus.exceptions.DBusException: except dbus.exceptions.DBusException:
return None return None
return self._ps_new_object(object_path) return self._ps_new_object(object_path)
def get_joined_activities(self): def get_joined_activities(self):
try: try:
resp = self._buddy.getJoinedActivities() resp = self._buddy.getJoinedActivities()
except dbus.exceptions.DBusException: except dbus.exceptions.DBusException:
return [] return []
acts = [] acts = []
for item in resp: for item in resp:
acts.append(self._ps_new_object(item)) acts.append(self._ps_new_object(item))
return acts return acts

View File

@ -20,23 +20,23 @@ import dbus, dbus.glib, gobject
import Buddy, Service, Activity import Buddy, Service, Activity
class ObjectCache(object): class ObjectCache(object):
def __init__(self): def __init__(self):
self._cache = {} self._cache = {}
def get(self, object_path): def get(self, object_path):
try: try:
return self._cache[object_path] return self._cache[object_path]
except KeyError: except KeyError:
return None return None
def add(self, obj): def add(self, obj):
op = obj.object_path() op = obj.object_path()
if not self._cache.has_key(op): if not self._cache.has_key(op):
self._cache[op] = obj self._cache[op] = obj
def remove(self, object_path): def remove(self, object_path):
if self._cache.has_key(object_path): if self._cache.has_key(object_path):
del self._cache[object_path] del self._cache[object_path]
DBUS_SERVICE = "org.laptop.Presence" DBUS_SERVICE = "org.laptop.Presence"
@ -46,192 +46,192 @@ DBUS_PATH = "/org/laptop/Presence"
class PresenceService(gobject.GObject): class PresenceService(gobject.GObject):
__gsignals__ = { __gsignals__ = {
'buddy-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, 'buddy-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([gobject.TYPE_PYOBJECT])), ([gobject.TYPE_PYOBJECT])),
'buddy-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, 'buddy-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([gobject.TYPE_PYOBJECT])), ([gobject.TYPE_PYOBJECT])),
'service-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, 'service-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([gobject.TYPE_PYOBJECT])), ([gobject.TYPE_PYOBJECT])),
'service-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, 'service-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([gobject.TYPE_PYOBJECT])), ([gobject.TYPE_PYOBJECT])),
'activity-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, 'activity-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([gobject.TYPE_PYOBJECT])), ([gobject.TYPE_PYOBJECT])),
'activity-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, 'activity-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([gobject.TYPE_PYOBJECT])) ([gobject.TYPE_PYOBJECT]))
} }
_PS_BUDDY_OP = DBUS_PATH + "/Buddies/" _PS_BUDDY_OP = DBUS_PATH + "/Buddies/"
_PS_SERVICE_OP = DBUS_PATH + "/Services/" _PS_SERVICE_OP = DBUS_PATH + "/Services/"
_PS_ACTIVITY_OP = DBUS_PATH + "/Activities/" _PS_ACTIVITY_OP = DBUS_PATH + "/Activities/"
def __init__(self): def __init__(self):
gobject.GObject.__init__(self) gobject.GObject.__init__(self)
self._objcache = ObjectCache() self._objcache = ObjectCache()
self._bus = dbus.SessionBus() self._bus = dbus.SessionBus()
self._ps = dbus.Interface(self._bus.get_object(DBUS_SERVICE, self._ps = dbus.Interface(self._bus.get_object(DBUS_SERVICE,
DBUS_PATH), DBUS_INTERFACE) DBUS_PATH), DBUS_INTERFACE)
self._ps.connect_to_signal('BuddyAppeared', self._buddy_appeared_cb) 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('BuddyDisappeared', self._buddy_disappeared_cb)
self._ps.connect_to_signal('ServiceAppeared', self._service_appeared_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('ServiceDisappeared', self._service_disappeared_cb)
self._ps.connect_to_signal('ActivityAppeared', self._activity_appeared_cb) self._ps.connect_to_signal('ActivityAppeared', self._activity_appeared_cb)
self._ps.connect_to_signal('ActivityDisappeared', self._activity_disappeared_cb) self._ps.connect_to_signal('ActivityDisappeared', self._activity_disappeared_cb)
def _new_object(self, object_path): def _new_object(self, object_path):
obj = self._objcache.get(object_path) obj = self._objcache.get(object_path)
if not obj: if not obj:
if object_path.startswith(self._PS_SERVICE_OP): if object_path.startswith(self._PS_SERVICE_OP):
obj = Service.Service(self._bus, self._new_object, obj = Service.Service(self._bus, self._new_object,
self._del_object, object_path) self._del_object, object_path)
elif object_path.startswith(self._PS_BUDDY_OP): elif object_path.startswith(self._PS_BUDDY_OP):
obj = Buddy.Buddy(self._bus, self._new_object, obj = Buddy.Buddy(self._bus, self._new_object,
self._del_object, object_path) self._del_object, object_path)
elif object_path.startswith(self._PS_ACTIVITY_OP): elif object_path.startswith(self._PS_ACTIVITY_OP):
obj = Activity.Activity(self._bus, self._new_object, obj = Activity.Activity(self._bus, self._new_object,
self._del_object, object_path) self._del_object, object_path)
else: else:
raise RuntimeError("Unknown object type") raise RuntimeError("Unknown object type")
self._objcache.add(obj) self._objcache.add(obj)
return obj return obj
def _del_object(self, object_path): def _del_object(self, object_path):
# FIXME # FIXME
pass pass
def _emit_buddy_appeared_signal(self, object_path): def _emit_buddy_appeared_signal(self, object_path):
self.emit('buddy-appeared', self._new_object(object_path)) self.emit('buddy-appeared', self._new_object(object_path))
return False return False
def _buddy_appeared_cb(self, op): def _buddy_appeared_cb(self, op):
gobject.idle_add(self._emit_buddy_appeared_signal, op) gobject.idle_add(self._emit_buddy_appeared_signal, op)
def _emit_buddy_disappeared_signal(self, object_path): def _emit_buddy_disappeared_signal(self, object_path):
self.emit('buddy-disappeared', self._new_object(object_path)) self.emit('buddy-disappeared', self._new_object(object_path))
return False return False
def _buddy_disappeared_cb(self, object_path): def _buddy_disappeared_cb(self, object_path):
gobject.idle_add(self._emit_buddy_disappeared_signal, object_path) gobject.idle_add(self._emit_buddy_disappeared_signal, object_path)
def _emit_service_appeared_signal(self, object_path): def _emit_service_appeared_signal(self, object_path):
self.emit('service-appeared', self._new_object(object_path)) self.emit('service-appeared', self._new_object(object_path))
return False return False
def _service_appeared_cb(self, object_path): def _service_appeared_cb(self, object_path):
gobject.idle_add(self._emit_service_appeared_signal, object_path) gobject.idle_add(self._emit_service_appeared_signal, object_path)
def _emit_service_disappeared_signal(self, object_path): def _emit_service_disappeared_signal(self, object_path):
self.emit('service-disappeared', self._new_object(object_path)) self.emit('service-disappeared', self._new_object(object_path))
return False return False
def _service_disappeared_cb(self, object_path): def _service_disappeared_cb(self, object_path):
gobject.idle_add(self._emit_service_disappeared_signal, object_path) gobject.idle_add(self._emit_service_disappeared_signal, object_path)
def _emit_activity_appeared_signal(self, object_path): def _emit_activity_appeared_signal(self, object_path):
self.emit('activity-appeared', self._new_object(object_path)) self.emit('activity-appeared', self._new_object(object_path))
return False return False
def _activity_appeared_cb(self, object_path): def _activity_appeared_cb(self, object_path):
gobject.idle_add(self._emit_activity_appeared_signal, object_path) gobject.idle_add(self._emit_activity_appeared_signal, object_path)
def _emit_activity_disappeared_signal(self, object_path): def _emit_activity_disappeared_signal(self, object_path):
self.emit('activity-disappeared', self._new_object(object_path)) self.emit('activity-disappeared', self._new_object(object_path))
return False return False
def _activity_disappeared_cb(self, object_path): def _activity_disappeared_cb(self, object_path):
gobject.idle_add(self._emit_activity_disappeared_signal, object_path) gobject.idle_add(self._emit_activity_disappeared_signal, object_path)
def get(self, object_path): def get(self, object_path):
return self._new_object(object_path) return self._new_object(object_path)
def get_services(self): def get_services(self):
resp = self._ps.getServices() resp = self._ps.getServices()
servs = [] servs = []
for item in resp: for item in resp:
servs.append(self._new_object(item)) servs.append(self._new_object(item))
return servs return servs
def get_services_of_type(self, stype): def get_services_of_type(self, stype):
resp = self._ps.getServicesOfType(stype) resp = self._ps.getServicesOfType(stype)
servs = [] servs = []
for item in resp: for item in resp:
servs.append(self._new_object(item)) servs.append(self._new_object(item))
return servs return servs
def get_activities(self): def get_activities(self):
resp = self._ps.getActivities() resp = self._ps.getActivities()
acts = [] acts = []
for item in resp: for item in resp:
acts.append(self._new_object(item)) acts.append(self._new_object(item))
return acts return acts
def get_activity(self, activity_id): def get_activity(self, activity_id):
try: try:
act_op = self._ps.getActivity(activity_id) act_op = self._ps.getActivity(activity_id)
except dbus.exceptions.DBusException: except dbus.exceptions.DBusException:
return None return None
return self._new_object(act_op) return self._new_object(act_op)
def get_buddies(self): def get_buddies(self):
resp = self._ps.getBuddies() resp = self._ps.getBuddies()
buddies = [] buddies = []
for item in resp: for item in resp:
buddies.append(self._new_object(item)) buddies.append(self._new_object(item))
return buddies return buddies
def get_buddy_by_name(self, name): def get_buddy_by_name(self, name):
try: try:
buddy_op = self._ps.getBuddyByName(name) buddy_op = self._ps.getBuddyByName(name)
except dbus.exceptions.DBusException: except dbus.exceptions.DBusException:
return None return None
return self._new_object(buddy_op) return self._new_object(buddy_op)
def get_buddy_by_address(self, addr): def get_buddy_by_address(self, addr):
try: try:
buddy_op = self._ps.getBuddyByAddress(addr) buddy_op = self._ps.getBuddyByAddress(addr)
except dbus.exceptions.DBusException: except dbus.exceptions.DBusException:
return None return None
return self._new_object(buddy_op) return self._new_object(buddy_op)
def get_owner(self): def get_owner(self):
try: try:
owner_op = self._ps.getOwner() owner_op = self._ps.getOwner()
except dbus.exceptions.DBusException: except dbus.exceptions.DBusException:
return None return None
return self._new_object(owner_op) return self._new_object(owner_op)
def share_activity(self, activity, stype, properties={}, address=None, port=-1, domain=u"local"): def share_activity(self, activity, stype, properties={}, address=None, port=-1, domain=u"local"):
actid = activity.get_id() actid = activity.get_id()
if address == None: if address == None:
address = u"" address = u""
serv_op = self._ps.shareActivity(actid, stype, properties, address, port, domain) serv_op = self._ps.shareActivity(actid, stype, properties, address, port, domain)
return self._new_object(serv_op) return self._new_object(serv_op)
def register_service(self, name, stype, properties={}, address=None, port=-1, domain=u"local"): def register_service(self, name, stype, properties={}, address=None, port=-1, domain=u"local"):
if address == None: if address == None:
address = u"" address = u""
serv_op = self._ps.registerService(name, stype, properties, address, port, domain) serv_op = self._ps.registerService(name, stype, properties, address, port, domain)
return self._new_object(serv_op) return self._new_object(serv_op)
def unregister_service(self, service): def unregister_service(self, service):
self._ps.unregisterService(service.object_path()) self._ps.unregisterService(service.object_path())
def register_service_type(self, stype): def register_service_type(self, stype):
self._ps.registerServiceType(stype) self._ps.registerServiceType(stype)
def unregister_service_type(self, stype): def unregister_service_type(self, stype):
self._ps.unregisterServiceType(stype) self._ps.unregisterServiceType(stype)
_ps = None _ps = None
def get_instance(): def get_instance():
global _ps global _ps
if not _ps: if not _ps:
_ps = PresenceService() _ps = PresenceService()
return _ps return _ps
def start(): def start():
bus = dbus.SessionBus() bus = dbus.SessionBus()
ps = dbus.Interface(bus.get_object(DBUS_SERVICE, DBUS_PATH), DBUS_INTERFACE) ps = dbus.Interface(bus.get_object(DBUS_SERVICE, DBUS_PATH), DBUS_INTERFACE)
ps.start() ps.start()

Some files were not shown because too many files have changed in this diff Show More