Changed all tabs to 4 spaces for python style
This commit is contained in:
parent
f5ae066248
commit
b9f9ef0fe9
@ -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...'
|
||||||
|
@ -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
@ -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()
|
||||||
|
@ -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()
|
||||||
|
@ -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())
|
||||||
|
@ -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()
|
||||||
|
@ -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
@ -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
|
||||||
|
@ -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
|
||||||
|
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
|
@ -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)"]
|
||||||
}
|
}
|
||||||
|
@ -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]
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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)"]
|
||||||
}
|
}
|
||||||
|
@ -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()
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
|
@ -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)
|
||||||
|
@ -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()
|
||||||
|
@ -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__()
|
||||||
|
@ -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()]
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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()
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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]
|
||||||
|
@ -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.')
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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()
|
||||||
|
@ -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()
|
||||||
|
@ -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()
|
||||||
|
@ -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()
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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()]
|
||||||
|
@ -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())
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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()
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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'
|
||||||
|
@ -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
|
||||||
|
@ -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()
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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()
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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()
|
||||||
|
@ -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)
|
||||||
|
@ -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()
|
||||||
|
@ -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())
|
||||||
|
@ -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
|
||||||
|
@ -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()
|
||||||
|
48
sugar/env.py
48
sugar/env.py
@ -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
|
||||||
|
@ -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();
|
||||||
|
@ -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();
|
||||||
|
@ -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()
|
||||||
|
@ -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)]
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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')
|
||||||
|
@ -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]
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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))
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
110
sugar/logger.py
110
sugar/logger.py
@ -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
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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()
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
Loading…
Reference in New Issue
Block a user