Refactor the directory structure to match the packages
This commit is contained in:
		
							parent
							
								
									1f057e0d0b
								
							
						
					
					
						commit
						f6491e6afc
					
				
							
								
								
									
										11
									
								
								Makefile.am
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								Makefile.am
									
									
									
									
									
								
							@ -1,10 +1 @@
 | 
			
		||||
SUBDIRS = chat browser shell
 | 
			
		||||
 | 
			
		||||
bin_SCRIPTS = sugar
 | 
			
		||||
 | 
			
		||||
sugardir = $(pythondir)/sugar
 | 
			
		||||
sugar_PYTHON =			\
 | 
			
		||||
	__init__.py		\
 | 
			
		||||
	sugar_globals.py
 | 
			
		||||
 | 
			
		||||
EXTRA_DIST = sugar
 | 
			
		||||
SUBDIRS = sugar
 | 
			
		||||
 | 
			
		||||
@ -1,24 +0,0 @@
 | 
			
		||||
sugardir = $(pythondir)/sugar
 | 
			
		||||
sugar_PYTHON = browser.py
 | 
			
		||||
 | 
			
		||||
icondir = $(pkgdatadir)
 | 
			
		||||
icon_DATA =		\
 | 
			
		||||
	fold.png	\
 | 
			
		||||
	unfold.png
 | 
			
		||||
 | 
			
		||||
# Dbus service file
 | 
			
		||||
servicedir = $(datadir)/dbus-1/services
 | 
			
		||||
service_in_files = com.redhat.Sugar.Browser.service.in
 | 
			
		||||
service_DATA = $(service_in_files:.service.in=.service)
 | 
			
		||||
 
 | 
			
		||||
# Rule to make the service file with bindir expanded
 | 
			
		||||
$(service_DATA): $(service_in_files) Makefile
 | 
			
		||||
	@sed -e "s|\@bindir\@|$(bindir)|" $< > $@
 | 
			
		||||
 | 
			
		||||
EXTRA_DIST =			\
 | 
			
		||||
	$(service_in_files)	\
 | 
			
		||||
	$(service_DATA)         \
 | 
			
		||||
	$(icon_DATA)
 | 
			
		||||
 | 
			
		||||
DISTCLEANFILES =		\
 | 
			
		||||
	$(service_DATA)
 | 
			
		||||
@ -1,289 +0,0 @@
 | 
			
		||||
#!/usr/bin/env python
 | 
			
		||||
 | 
			
		||||
import dbus
 | 
			
		||||
import dbus.service
 | 
			
		||||
import dbus.glib
 | 
			
		||||
 | 
			
		||||
import pygtk
 | 
			
		||||
pygtk.require('2.0')
 | 
			
		||||
import gtk
 | 
			
		||||
 | 
			
		||||
import geckoembed
 | 
			
		||||
 | 
			
		||||
import sys
 | 
			
		||||
 | 
			
		||||
try:
 | 
			
		||||
	import activity
 | 
			
		||||
	from sugar_globals import *
 | 
			
		||||
except ImportError:
 | 
			
		||||
	from sugar import activity
 | 
			
		||||
	from sugar.sugar_globals import *
 | 
			
		||||
 | 
			
		||||
class AddressToolbar(gtk.Toolbar):
 | 
			
		||||
	def __init__(self):
 | 
			
		||||
		gtk.Toolbar.__init__(self)
 | 
			
		||||
 | 
			
		||||
		address_item = AddressItem(self.__open_address_cb)		
 | 
			
		||||
		self.insert(address_item, 0)
 | 
			
		||||
		address_item.show()
 | 
			
		||||
 | 
			
		||||
	def __open_address_cb(self, address):
 | 
			
		||||
		BrowserShell.get_instance().open_browser(address)
 | 
			
		||||
 | 
			
		||||
class AddressItem(gtk.ToolItem):
 | 
			
		||||
	def __init__(self, callback):
 | 
			
		||||
		gtk.ToolItem.__init__(self)
 | 
			
		||||
	
 | 
			
		||||
		address_entry = AddressEntry(callback)
 | 
			
		||||
		self.add(address_entry)
 | 
			
		||||
		address_entry.show()
 | 
			
		||||
 | 
			
		||||
class AddressEntry(gtk.HBox):
 | 
			
		||||
	def __init__(self, callback):
 | 
			
		||||
		gtk.HBox.__init__(self)
 | 
			
		||||
 | 
			
		||||
		self.callback = callback
 | 
			
		||||
		self.folded = True
 | 
			
		||||
		
 | 
			
		||||
		label = gtk.Label("Open")
 | 
			
		||||
		self.pack_start(label, False)
 | 
			
		||||
		label.show()
 | 
			
		||||
		
 | 
			
		||||
		self.button = gtk.Button()
 | 
			
		||||
		self.button.set_relief(gtk.RELIEF_NONE)
 | 
			
		||||
		self.button.connect("clicked", self.__button_clicked_cb)
 | 
			
		||||
		self.pack_start(self.button, False)
 | 
			
		||||
		self.button.show()
 | 
			
		||||
		
 | 
			
		||||
		self.entry = gtk.Entry()
 | 
			
		||||
		self.entry.connect("activate", self.__activate_cb)
 | 
			
		||||
		self.pack_start(self.entry, False)
 | 
			
		||||
		self.entry.show()
 | 
			
		||||
 | 
			
		||||
		self._update_folded_state()
 | 
			
		||||
	
 | 
			
		||||
	def _update_folded_state(self):
 | 
			
		||||
		if self.folded:
 | 
			
		||||
			image = gtk.Image()
 | 
			
		||||
			image.set_from_file(data_dir + "/unfold.png")
 | 
			
		||||
			self.button.set_image(image)
 | 
			
		||||
			image.show()
 | 
			
		||||
 | 
			
		||||
			self.entry.hide()
 | 
			
		||||
		else:
 | 
			
		||||
			image = gtk.Image()
 | 
			
		||||
			image.set_from_file(data_dir + "/fold.png")
 | 
			
		||||
			self.button.set_image(image)
 | 
			
		||||
			image.show()
 | 
			
		||||
 | 
			
		||||
			self.entry.show()
 | 
			
		||||
			self.entry.grab_focus()
 | 
			
		||||
	
 | 
			
		||||
	def get_folded(self):
 | 
			
		||||
		return self.folded
 | 
			
		||||
	
 | 
			
		||||
	def set_folded(self, folded):
 | 
			
		||||
		self.folded = not self.folded
 | 
			
		||||
		self._update_folded_state()		
 | 
			
		||||
	
 | 
			
		||||
	def __button_clicked_cb(self, button):
 | 
			
		||||
		self.set_folded(not self.get_folded())
 | 
			
		||||
 | 
			
		||||
	def __activate_cb(self, entry):
 | 
			
		||||
		self.callback(entry.get_text())
 | 
			
		||||
		self.set_folded(True)
 | 
			
		||||
 | 
			
		||||
class NavigationToolbar(gtk.Toolbar):
 | 
			
		||||
	def __init__(self, embed):
 | 
			
		||||
		gtk.Toolbar.__init__(self)
 | 
			
		||||
		self.embed = embed
 | 
			
		||||
		
 | 
			
		||||
		self.set_style(gtk.TOOLBAR_ICONS)
 | 
			
		||||
		
 | 
			
		||||
		self.back = gtk.ToolButton(gtk.STOCK_GO_BACK)
 | 
			
		||||
		self.back.connect("clicked", self.__go_back_cb)
 | 
			
		||||
		self.insert(self.back, -1)
 | 
			
		||||
		self.back.show()
 | 
			
		||||
 | 
			
		||||
		self.forward = gtk.ToolButton(gtk.STOCK_GO_FORWARD)
 | 
			
		||||
		self.forward.connect("clicked", self.__go_forward_cb)
 | 
			
		||||
		self.insert(self.forward, -1)
 | 
			
		||||
		self.forward.show()
 | 
			
		||||
 | 
			
		||||
		self.reload = gtk.ToolButton(gtk.STOCK_REFRESH)
 | 
			
		||||
		self.reload.connect("clicked", self.__reload_cb)
 | 
			
		||||
		self.insert(self.reload, -1)
 | 
			
		||||
		self.reload.show()
 | 
			
		||||
 | 
			
		||||
		separator = gtk.SeparatorToolItem()
 | 
			
		||||
		self.insert(separator, -1)
 | 
			
		||||
		separator.show()
 | 
			
		||||
 | 
			
		||||
		share = gtk.ToolButton("Share")
 | 
			
		||||
		share.connect("clicked", self.__share_cb)
 | 
			
		||||
		self.insert(share, -1)
 | 
			
		||||
		share.show()
 | 
			
		||||
 | 
			
		||||
		separator = gtk.SeparatorToolItem()
 | 
			
		||||
		self.insert(separator, -1)
 | 
			
		||||
		separator.show()
 | 
			
		||||
		
 | 
			
		||||
		address_item = AddressItem(self.__open_address_cb)		
 | 
			
		||||
		self.insert(address_item, -1)
 | 
			
		||||
		address_item.show()
 | 
			
		||||
 | 
			
		||||
		self._update_sensitivity()
 | 
			
		||||
 | 
			
		||||
		self.embed.connect("location", self.__location_changed)
 | 
			
		||||
 | 
			
		||||
	def _update_sensitivity(self):
 | 
			
		||||
		self.back.set_sensitive(self.embed.can_go_back())
 | 
			
		||||
		self.forward.set_sensitive(self.embed.can_go_forward())
 | 
			
		||||
		
 | 
			
		||||
	def __go_back_cb(self, button):
 | 
			
		||||
		self.embed.go_back()
 | 
			
		||||
	
 | 
			
		||||
	def __go_forward_cb(self, button):
 | 
			
		||||
		self.embed.go_forward()
 | 
			
		||||
		
 | 
			
		||||
	def __reload_cb(self, button):
 | 
			
		||||
		self.embed.reload()
 | 
			
		||||
 | 
			
		||||
	def __share_cb(self, button):
 | 
			
		||||
		pass
 | 
			
		||||
 | 
			
		||||
	def __location_changed(self, embed):
 | 
			
		||||
		self._update_sensitivity()
 | 
			
		||||
 | 
			
		||||
	def __open_address_cb(self, address):
 | 
			
		||||
		self.embed.load_address(address)
 | 
			
		||||
 | 
			
		||||
class BrowserActivity(activity.Activity):
 | 
			
		||||
	def __init__(self, uri):
 | 
			
		||||
		activity.Activity.__init__(self)
 | 
			
		||||
		self.uri = uri
 | 
			
		||||
	
 | 
			
		||||
	def activity_on_connected_to_shell(self):
 | 
			
		||||
		self.activity_set_ellipsize_tab(True)
 | 
			
		||||
		self.activity_set_can_close(True)
 | 
			
		||||
		self.activity_set_tab_text("Web Page")
 | 
			
		||||
		self.activity_set_tab_icon_name("web-browser")
 | 
			
		||||
		self.activity_show_icon(True)
 | 
			
		||||
 | 
			
		||||
		vbox = gtk.VBox()
 | 
			
		||||
 | 
			
		||||
		self.embed = geckoembed.Embed()
 | 
			
		||||
		self.embed.connect("title", self.__title_cb)
 | 
			
		||||
		vbox.pack_start(self.embed)
 | 
			
		||||
		
 | 
			
		||||
		self.embed.show()
 | 
			
		||||
		self.embed.load_address(self.uri)
 | 
			
		||||
		
 | 
			
		||||
		nav_toolbar = NavigationToolbar(self.embed)
 | 
			
		||||
		vbox.pack_start(nav_toolbar, False)
 | 
			
		||||
		nav_toolbar.show()
 | 
			
		||||
 | 
			
		||||
		plug = self.activity_get_gtk_plug()		
 | 
			
		||||
		plug.add(vbox)
 | 
			
		||||
		plug.show()
 | 
			
		||||
 | 
			
		||||
		vbox.show()
 | 
			
		||||
	
 | 
			
		||||
	def get_embed(self):
 | 
			
		||||
		return self.embed
 | 
			
		||||
	
 | 
			
		||||
	def __title_cb(self, embed):
 | 
			
		||||
		self.activity_set_tab_text(embed.get_title())
 | 
			
		||||
 | 
			
		||||
	def activity_on_close_from_user(self):
 | 
			
		||||
		self.activity_shutdown()
 | 
			
		||||
 | 
			
		||||
class WebActivity(activity.Activity):
 | 
			
		||||
	def __init__(self):
 | 
			
		||||
		activity.Activity.__init__(self)
 | 
			
		||||
	
 | 
			
		||||
	def activity_on_connected_to_shell(self):
 | 
			
		||||
		self.activity_set_tab_text("Web Browser")
 | 
			
		||||
		self.activity_set_tab_icon_name("web-browser")
 | 
			
		||||
		self.activity_show_icon(True)
 | 
			
		||||
 | 
			
		||||
		vbox = gtk.VBox()
 | 
			
		||||
			
 | 
			
		||||
		self.embed = geckoembed.Embed()
 | 
			
		||||
		self.embed.connect("open-address", self.__open_address);		
 | 
			
		||||
		vbox.pack_start(self.embed)
 | 
			
		||||
		self.embed.show()
 | 
			
		||||
 | 
			
		||||
		address_toolbar = AddressToolbar()
 | 
			
		||||
		vbox.pack_start(address_toolbar, False)
 | 
			
		||||
		address_toolbar.show()
 | 
			
		||||
		
 | 
			
		||||
		plug = self.activity_get_gtk_plug()		
 | 
			
		||||
		plug.add(vbox)
 | 
			
		||||
		plug.show()
 | 
			
		||||
 | 
			
		||||
		vbox.show()
 | 
			
		||||
		
 | 
			
		||||
		self.embed.load_address("http://www.google.com")
 | 
			
		||||
		
 | 
			
		||||
	def __open_address(self, embed, uri, data=None):
 | 
			
		||||
		if uri.startswith("http://www.google.com"):
 | 
			
		||||
			return False
 | 
			
		||||
		else:
 | 
			
		||||
			BrowserShell.get_instance().open_browser(uri)
 | 
			
		||||
			return True
 | 
			
		||||
 | 
			
		||||
	def activity_on_disconnected_from_shell(self):
 | 
			
		||||
		gtk.main_quit()
 | 
			
		||||
		gc.collect()
 | 
			
		||||
 | 
			
		||||
class BrowserShell(dbus.service.Object):
 | 
			
		||||
	instance = None
 | 
			
		||||
 | 
			
		||||
	def get_instance():
 | 
			
		||||
		if not BrowserShell.instance:
 | 
			
		||||
			BrowserShell.instance = BrowserShell()
 | 
			
		||||
		return BrowserShell.instance
 | 
			
		||||
		
 | 
			
		||||
	get_instance = staticmethod(get_instance)
 | 
			
		||||
 | 
			
		||||
	def __init__(self):
 | 
			
		||||
		session_bus = dbus.SessionBus()
 | 
			
		||||
		bus_name = dbus.service.BusName('com.redhat.Sugar.Browser', bus=session_bus)
 | 
			
		||||
		object_path = '/com/redhat/Sugar/Browser'
 | 
			
		||||
 | 
			
		||||
		dbus.service.Object.__init__(self, bus_name, object_path)
 | 
			
		||||
 | 
			
		||||
		self.__browsers = []
 | 
			
		||||
 | 
			
		||||
	def open_web_activity(self):
 | 
			
		||||
		web_activity = WebActivity()
 | 
			
		||||
		web_activity.activity_connect_to_shell()
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method('com.redhat.Sugar.BrowserShell')
 | 
			
		||||
	def get_links(self):
 | 
			
		||||
		links = []
 | 
			
		||||
		for browser in self.__browsers:
 | 
			
		||||
			embed = browser.get_embed()
 | 
			
		||||
			link = {}
 | 
			
		||||
			link['title'] = embed.get_title()
 | 
			
		||||
			link['address'] = embed.get_address()
 | 
			
		||||
			links.append(link)
 | 
			
		||||
		return links
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method('com.redhat.Sugar.BrowserShell')
 | 
			
		||||
	def open_browser(self, uri):
 | 
			
		||||
		browser = BrowserActivity(uri)
 | 
			
		||||
		self.__browsers.append(browser)
 | 
			
		||||
		browser.activity_connect_to_shell()
 | 
			
		||||
 | 
			
		||||
def main():
 | 
			
		||||
	BrowserShell.get_instance().open_web_activity()
 | 
			
		||||
	
 | 
			
		||||
	try:
 | 
			
		||||
		gtk.main()
 | 
			
		||||
	except KeyboardInterrupt:
 | 
			
		||||
		pass
 | 
			
		||||
 | 
			
		||||
if __name__=="__main__":
 | 
			
		||||
		main()
 | 
			
		||||
@ -1,3 +0,0 @@
 | 
			
		||||
[D-BUS Service]
 | 
			
		||||
Name=com.redhat.Sugar.Browser
 | 
			
		||||
Exec=@bindir@/sugar browser
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								browser/fold.png
									
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								browser/fold.png
									
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 156 B  | 
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 157 B  | 
@ -1,121 +0,0 @@
 | 
			
		||||
# -*- tab-width: 4; indent-tabs-mode: t -*- 
 | 
			
		||||
 | 
			
		||||
import presence
 | 
			
		||||
import avahi
 | 
			
		||||
 | 
			
		||||
ACTION_BUDDY_ADDED = "added"
 | 
			
		||||
ACTION_BUDDY_REMOVED = "removed"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Buddy(object):
 | 
			
		||||
	def __init__(self, nick, realname, servicename, host, address, port, key=None):
 | 
			
		||||
		self._nick = nick
 | 
			
		||||
		self._realname = realname
 | 
			
		||||
		self._servicename = servicename
 | 
			
		||||
		self._key = key
 | 
			
		||||
		self._host = host
 | 
			
		||||
		self._address = str(address)
 | 
			
		||||
		self._port = int(port)
 | 
			
		||||
		self._chat = None
 | 
			
		||||
 | 
			
		||||
	def set_chat(self, chat):
 | 
			
		||||
		self._chat = chat
 | 
			
		||||
 | 
			
		||||
	def chat(self):
 | 
			
		||||
		return self._chat
 | 
			
		||||
 | 
			
		||||
	def nick(self):
 | 
			
		||||
		return self._nick
 | 
			
		||||
 | 
			
		||||
	def realname(self):
 | 
			
		||||
		return self._realname
 | 
			
		||||
 | 
			
		||||
	def servicename(self):
 | 
			
		||||
		return self._servicename
 | 
			
		||||
 | 
			
		||||
	def host(self):
 | 
			
		||||
		return self._host
 | 
			
		||||
 | 
			
		||||
	def address(self):
 | 
			
		||||
		return self._address
 | 
			
		||||
 | 
			
		||||
	def port(self):
 | 
			
		||||
		return self._port
 | 
			
		||||
 | 
			
		||||
	def key(self):
 | 
			
		||||
		return self._key
 | 
			
		||||
 | 
			
		||||
class BuddyList(object):
 | 
			
		||||
	""" Manage a list of buddies """
 | 
			
		||||
 | 
			
		||||
	def __init__(self, servicename):
 | 
			
		||||
		self._listeners = []
 | 
			
		||||
		self._buddies = {}
 | 
			
		||||
		self._servicename = servicename
 | 
			
		||||
		self._pdiscovery = presence.PresenceDiscovery()
 | 
			
		||||
		self._pdiscovery.add_service_listener(self._on_service_change)
 | 
			
		||||
 | 
			
		||||
	def start(self):
 | 
			
		||||
		self._pdiscovery.start()
 | 
			
		||||
 | 
			
		||||
	def add_buddy_listener(self, listener):
 | 
			
		||||
		self._listeners.append(listener)
 | 
			
		||||
 | 
			
		||||
	def _add_buddy(self, host, address, port, servicename, data):
 | 
			
		||||
		# Ignore ourselves
 | 
			
		||||
		if servicename == self._servicename:
 | 
			
		||||
			return
 | 
			
		||||
 | 
			
		||||
		if len(data) > 0 and 'name' in data.keys():
 | 
			
		||||
			buddy = self._find_buddy_by_service_name(servicename)
 | 
			
		||||
			if not buddy:
 | 
			
		||||
				buddy = Buddy(data['name'], data['realname'], servicename, host, address, port)
 | 
			
		||||
				self._buddies[data['name']] = buddy
 | 
			
		||||
				self._notify_listeners(ACTION_BUDDY_ADDED, buddy)
 | 
			
		||||
 | 
			
		||||
	def _remove_buddy(self, buddy):
 | 
			
		||||
		nick = buddy.nick()
 | 
			
		||||
		self._notify_listeners(ACTION_BUDDY_REMOVED, buddy)
 | 
			
		||||
		del self._buddies[nick]
 | 
			
		||||
 | 
			
		||||
	def _find_buddy_by_service_name(self, servicename):
 | 
			
		||||
		for buddy in self._buddies.values():
 | 
			
		||||
			if buddy.servicename() == servicename:
 | 
			
		||||
				return buddy
 | 
			
		||||
		return None
 | 
			
		||||
 | 
			
		||||
	def find_buddy_by_address(self, address):
 | 
			
		||||
		for buddy_name in self._buddies.keys():
 | 
			
		||||
			buddy = self._buddies[buddy_name]
 | 
			
		||||
			if buddy.address() == address:
 | 
			
		||||
				return buddy
 | 
			
		||||
		return None
 | 
			
		||||
 | 
			
		||||
	def _notify_listeners(self, action, buddy):
 | 
			
		||||
		for listener in self._listeners:
 | 
			
		||||
			listener(action, buddy)
 | 
			
		||||
 | 
			
		||||
	def _on_service_change(self, action, interface, protocol, name, stype, domain, flags):
 | 
			
		||||
		if stype != presence.OLPC_CHAT_SERVICE:
 | 
			
		||||
			return
 | 
			
		||||
		if action == presence.ACTION_SERVICE_NEW:
 | 
			
		||||
			self._pdiscovery.resolve_service(interface, protocol, name, stype, domain, self._on_service_resolved)
 | 
			
		||||
		elif action == presence.ACTION_SERVICE_REMOVED:
 | 
			
		||||
			buddy = self._find_buddy_by_service_name(name)
 | 
			
		||||
			if buddy:
 | 
			
		||||
				self._remove_buddy(buddy)
 | 
			
		||||
 | 
			
		||||
	def _pair_to_dict(self, l):
 | 
			
		||||
		res = {}
 | 
			
		||||
		for el in l:
 | 
			
		||||
			tmp = el.split('=', 1)
 | 
			
		||||
			if len(tmp) > 1:
 | 
			
		||||
				res[tmp[0]] = tmp[1]
 | 
			
		||||
			else:
 | 
			
		||||
				res[tmp[0]] = ''
 | 
			
		||||
		return res
 | 
			
		||||
 | 
			
		||||
	def _on_service_resolved(self, interface, protocol, name, stype, domain, host, aprotocol, address, port, txt, flags):
 | 
			
		||||
		data = self._pair_to_dict(avahi.txt_array_to_string_array(txt))
 | 
			
		||||
		self._add_buddy(host, address, port, name, data)
 | 
			
		||||
 | 
			
		||||
@ -1,11 +0,0 @@
 | 
			
		||||
sugardir = $(pythondir)/sugar
 | 
			
		||||
sugar_PYTHON =		\
 | 
			
		||||
	chat.py		\
 | 
			
		||||
	richtext.py
 | 
			
		||||
 | 
			
		||||
icondir = $(pkgdatadir)
 | 
			
		||||
icon_DATA =			\
 | 
			
		||||
	bubble.png		\
 | 
			
		||||
	bubbleOutline.png
 | 
			
		||||
 | 
			
		||||
EXTRA_DIST = $(icon_DATA)
 | 
			
		||||
							
								
								
									
										1069
									
								
								chat/SVGdraw.py
									
									
									
									
									
								
							
							
						
						
									
										1069
									
								
								chat/SVGdraw.py
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								chat/bubble.png
									
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								chat/bubble.png
									
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 255 B  | 
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 284 B  | 
							
								
								
									
										409
									
								
								chat/chat.py
									
									
									
									
									
								
							
							
						
						
									
										409
									
								
								chat/chat.py
									
									
									
									
									
								
							@ -1,409 +0,0 @@
 | 
			
		||||
#!/usr/bin/python -t
 | 
			
		||||
# -*- tab-width: 4; indent-tabs-mode: t -*- 
 | 
			
		||||
 | 
			
		||||
import dbus
 | 
			
		||||
import dbus.service
 | 
			
		||||
import dbus.glib
 | 
			
		||||
 | 
			
		||||
import pygtk
 | 
			
		||||
pygtk.require('2.0')
 | 
			
		||||
import gtk, gobject
 | 
			
		||||
 | 
			
		||||
import sys
 | 
			
		||||
 | 
			
		||||
try:
 | 
			
		||||
	import activity
 | 
			
		||||
	from Group import *
 | 
			
		||||
	from StreamReader import *
 | 
			
		||||
	from StreamWriter import *
 | 
			
		||||
	from sugar_globals import *
 | 
			
		||||
except ImportError:
 | 
			
		||||
	from sugar import activity
 | 
			
		||||
	from sugar.Group import *
 | 
			
		||||
	from sugar.sugar_globals import *
 | 
			
		||||
 | 
			
		||||
import richtext
 | 
			
		||||
 | 
			
		||||
CHAT_SERVICE_TYPE = "_olpc_chat._tcp"
 | 
			
		||||
CHAT_SERVICE_PORT = 6100
 | 
			
		||||
 | 
			
		||||
GROUP_CHAT_SERVICE_TYPE = "_olpc_group_chat._udp"
 | 
			
		||||
GROUP_CHAT_SERVICE_ADDRESS = "224.0.0.221"
 | 
			
		||||
GROUP_CHAT_SERVICE_PORT = 6200
 | 
			
		||||
 | 
			
		||||
class Chat(activity.Activity):
 | 
			
		||||
	def __init__(self, controller):
 | 
			
		||||
		self._controller = controller
 | 
			
		||||
		activity.Activity.__init__(self)
 | 
			
		||||
 | 
			
		||||
	def activity_on_connected_to_shell(self):
 | 
			
		||||
		self.activity_set_tab_text(self._act_name)
 | 
			
		||||
		self._plug = self.activity_get_gtk_plug()
 | 
			
		||||
		self._ui_setup(self._plug)
 | 
			
		||||
		self._plug.show_all()
 | 
			
		||||
		
 | 
			
		||||
	def _create_chat(self):
 | 
			
		||||
		chat_vbox = gtk.VBox()
 | 
			
		||||
		chat_vbox.set_spacing(6)
 | 
			
		||||
 | 
			
		||||
		sw = gtk.ScrolledWindow()
 | 
			
		||||
		sw.set_shadow_type(gtk.SHADOW_IN)
 | 
			
		||||
		sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
 | 
			
		||||
		self._chat_view = richtext.RichTextView()
 | 
			
		||||
		self._chat_view.connect("link-clicked", self.__link_clicked_cb)
 | 
			
		||||
		self._chat_view.set_editable(False)
 | 
			
		||||
		self._chat_view.set_cursor_visible(False)
 | 
			
		||||
		sw.add(self._chat_view)
 | 
			
		||||
		self._chat_view.show()
 | 
			
		||||
		chat_vbox.pack_start(sw)
 | 
			
		||||
		sw.show()
 | 
			
		||||
 | 
			
		||||
		chat_view_sw = gtk.ScrolledWindow()
 | 
			
		||||
		chat_view_sw.set_shadow_type(gtk.SHADOW_IN)
 | 
			
		||||
		chat_view_sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
 | 
			
		||||
		self._editor = richtext.RichTextView()
 | 
			
		||||
		self._editor.connect("key-press-event", self.__key_press_event_cb)
 | 
			
		||||
		self._editor.set_size_request(-1, 50)
 | 
			
		||||
		chat_view_sw.add(self._editor)
 | 
			
		||||
		self._editor.show()
 | 
			
		||||
 | 
			
		||||
		chat_vbox.pack_start(chat_view_sw, False)
 | 
			
		||||
		chat_view_sw.show()
 | 
			
		||||
		
 | 
			
		||||
		return chat_vbox, self._editor.get_buffer()
 | 
			
		||||
 | 
			
		||||
	def _ui_setup(self, base):
 | 
			
		||||
		vbox = gtk.VBox(False, 6)
 | 
			
		||||
 | 
			
		||||
		self._hbox = gtk.HBox(False, 12)
 | 
			
		||||
		self._hbox.set_border_width(12)
 | 
			
		||||
 | 
			
		||||
		[chat_vbox, buffer] = self._create_chat()
 | 
			
		||||
		self._hbox.pack_start(chat_vbox)
 | 
			
		||||
		chat_vbox.show()
 | 
			
		||||
		
 | 
			
		||||
		vbox.pack_start(self._hbox)
 | 
			
		||||
		self._hbox.show()
 | 
			
		||||
 | 
			
		||||
		toolbar = self._create_toolbar(buffer)
 | 
			
		||||
		vbox.pack_start(toolbar, False)
 | 
			
		||||
		toolbar.show()
 | 
			
		||||
 | 
			
		||||
		base.add(vbox)
 | 
			
		||||
		vbox.show()
 | 
			
		||||
 | 
			
		||||
	def __link_clicked_cb(self, view, address):
 | 
			
		||||
		self._browser_shell.open_browser(address)
 | 
			
		||||
 | 
			
		||||
	def __key_press_event_cb(self, text_view, event):
 | 
			
		||||
		if event.keyval == gtk.keysyms.Return:
 | 
			
		||||
			buf = text_view.get_buffer()
 | 
			
		||||
			
 | 
			
		||||
			serializer = richtext.RichTextSerializer()
 | 
			
		||||
			text = serializer.serialize(buf)
 | 
			
		||||
			self.send_message(text)
 | 
			
		||||
 | 
			
		||||
			buf.set_text("")
 | 
			
		||||
			buf.place_cursor(buf.get_start_iter())
 | 
			
		||||
 | 
			
		||||
			return True
 | 
			
		||||
 | 
			
		||||
	def _create_toolbar(self, rich_buf):
 | 
			
		||||
		toolbar = richtext.RichTextToolbar(rich_buf)
 | 
			
		||||
 | 
			
		||||
		item = gtk.MenuToolButton(None, "Links")
 | 
			
		||||
		item.set_menu(gtk.Menu())
 | 
			
		||||
		item.connect("show-menu", self.__show_link_menu_cb)
 | 
			
		||||
		toolbar.insert(item, -1)
 | 
			
		||||
		item.show()
 | 
			
		||||
		
 | 
			
		||||
		return toolbar
 | 
			
		||||
 | 
			
		||||
	def __link_activate_cb(self, item, link):
 | 
			
		||||
		buf = self._editor.get_buffer()
 | 
			
		||||
		buf.append_link(link['title'], link['address'])
 | 
			
		||||
 | 
			
		||||
	def __show_link_menu_cb(self, button):
 | 
			
		||||
		menu = gtk.Menu()
 | 
			
		||||
		
 | 
			
		||||
		links = self._browser_shell.get_links()
 | 
			
		||||
 | 
			
		||||
		for link in links:
 | 
			
		||||
			item = gtk.MenuItem(link['title'], False)
 | 
			
		||||
			item.connect("activate", self.__link_activate_cb, link)
 | 
			
		||||
			menu.append(item)
 | 
			
		||||
			item.show()
 | 
			
		||||
		
 | 
			
		||||
		button.set_menu(menu)
 | 
			
		||||
		
 | 
			
		||||
	def activity_on_close_from_user(self):
 | 
			
		||||
		print "act %d: in activity_on_close_from_user"%self.activity_get_id()
 | 
			
		||||
		self.activity_shutdown()
 | 
			
		||||
 | 
			
		||||
	def activity_on_lost_focus(self):
 | 
			
		||||
		print "act %d: in activity_on_lost_focus"%self.activity_get_id()
 | 
			
		||||
 | 
			
		||||
	def activity_on_got_focus(self):
 | 
			
		||||
		print "act %d: in activity_on_got_focus"%self.activity_get_id()
 | 
			
		||||
		self._controller.notify_activate(self)
 | 
			
		||||
 | 
			
		||||
	def recv_message(self, buddy, msg):
 | 
			
		||||
		self._insert_rich_message(buddy.get_nick_name(), msg)
 | 
			
		||||
		self._controller.notify_new_message(self, buddy)
 | 
			
		||||
 | 
			
		||||
	def _insert_rich_message(self, nick, msg):
 | 
			
		||||
		buffer = self._chat_view.get_buffer()
 | 
			
		||||
		aniter = buffer.get_end_iter()
 | 
			
		||||
		buffer.insert(aniter, nick + ": ")
 | 
			
		||||
		
 | 
			
		||||
		serializer = richtext.RichTextSerializer()
 | 
			
		||||
		serializer.deserialize(msg, buffer)
 | 
			
		||||
 | 
			
		||||
		aniter = buffer.get_end_iter()
 | 
			
		||||
		buffer.insert(aniter, "\n")
 | 
			
		||||
 | 
			
		||||
	def _local_message(self, success, text):
 | 
			
		||||
		if not success:
 | 
			
		||||
			message = "Error: %s\n" % text
 | 
			
		||||
			buffer = self._chat_view.get_buffer()
 | 
			
		||||
			aniter = buffer.get_end_iter()
 | 
			
		||||
			buffer.insert(aniter, message)
 | 
			
		||||
		else:
 | 
			
		||||
			owner = self._controller.get_group().get_owner()
 | 
			
		||||
			self._insert_rich_message(owner.get_nick_name(), text)
 | 
			
		||||
 | 
			
		||||
class BuddyChat(Chat):
 | 
			
		||||
	def __init__(self, controller, buddy):
 | 
			
		||||
		self._buddy = buddy
 | 
			
		||||
		self._act_name = "Chat: %s" % buddy.get_nick_name()
 | 
			
		||||
		Chat.__init__(self, controller)
 | 
			
		||||
 | 
			
		||||
	def _start(self):
 | 
			
		||||
		group = self._controller.get_group()
 | 
			
		||||
		buddy_name = self._buddy.get_service_name()
 | 
			
		||||
		service = group.get_service(buddy_name, CHAT_SERVICE_TYPE)
 | 
			
		||||
		self._stream_writer = StreamWriter(group, service)
 | 
			
		||||
 | 
			
		||||
	def activity_on_connected_to_shell(self):
 | 
			
		||||
		Chat.activity_on_connected_to_shell(self)
 | 
			
		||||
		self.activity_set_can_close(True)
 | 
			
		||||
		self.activity_set_tab_icon_name("im")
 | 
			
		||||
		self.activity_show_icon(True)
 | 
			
		||||
		self._start()
 | 
			
		||||
		
 | 
			
		||||
	def recv_message(self, sender, msg):
 | 
			
		||||
		Chat.recv_message(self, self._buddy, msg)
 | 
			
		||||
 | 
			
		||||
	def send_message(self, text):
 | 
			
		||||
		if len(text) > 0:
 | 
			
		||||
			self._stream_writer.write(text)
 | 
			
		||||
			self._local_message(True, text)
 | 
			
		||||
 | 
			
		||||
	def activity_on_close_from_user(self):
 | 
			
		||||
		Chat.activity_on_close_from_user(self)
 | 
			
		||||
		del self._chats[self._buddy]
 | 
			
		||||
			
 | 
			
		||||
class GroupChat(Chat):
 | 
			
		||||
 | 
			
		||||
	_MODEL_COL_NICK = 0
 | 
			
		||||
	_MODEL_COL_ICON = 1
 | 
			
		||||
	_MODEL_COL_BUDDY = 2
 | 
			
		||||
	
 | 
			
		||||
	def __init__(self):
 | 
			
		||||
		self._act_name = "Chat"
 | 
			
		||||
		self._chats = {}
 | 
			
		||||
		
 | 
			
		||||
		bus = dbus.SessionBus()
 | 
			
		||||
		proxy_obj = bus.get_object('com.redhat.Sugar.Browser', '/com/redhat/Sugar/Browser')
 | 
			
		||||
		self._browser_shell = dbus.Interface(proxy_obj, 'com.redhat.Sugar.BrowserShell')
 | 
			
		||||
 | 
			
		||||
		Chat.__init__(self, self)
 | 
			
		||||
 | 
			
		||||
	def get_group(self):
 | 
			
		||||
		return self._group
 | 
			
		||||
 | 
			
		||||
	def _start(self):
 | 
			
		||||
		self._group = LocalGroup()
 | 
			
		||||
		self._group.add_presence_listener(self._on_group_event)
 | 
			
		||||
		self._group.join()
 | 
			
		||||
		
 | 
			
		||||
		name = self._group.get_owner().get_service_name()
 | 
			
		||||
		service = Service(name, CHAT_SERVICE_TYPE, '', CHAT_SERVICE_PORT)
 | 
			
		||||
		self._buddy_reader = StreamReader(self._group, service)
 | 
			
		||||
		self._buddy_reader.set_listener(self._buddy_recv_message)
 | 
			
		||||
		service.register(self._group)
 | 
			
		||||
 | 
			
		||||
		service = Service(name, GROUP_CHAT_SERVICE_TYPE,
 | 
			
		||||
						  GROUP_CHAT_SERVICE_ADDRESS,
 | 
			
		||||
						  GROUP_CHAT_SERVICE_PORT, True)
 | 
			
		||||
		self._group.add_service(service)				  
 | 
			
		||||
		
 | 
			
		||||
		self._buddy_reader = StreamReader(self._group, service)
 | 
			
		||||
		self._buddy_reader.set_listener(self.recv_message)
 | 
			
		||||
		
 | 
			
		||||
		self._stream_writer = StreamWriter(self._group, service)
 | 
			
		||||
 | 
			
		||||
	def _create_sidebar(self):
 | 
			
		||||
		vbox = gtk.VBox(False, 6)
 | 
			
		||||
		
 | 
			
		||||
		label = gtk.Label("Who's around:")
 | 
			
		||||
		label.set_alignment(0.0, 0.5)
 | 
			
		||||
		vbox.pack_start(label, False)
 | 
			
		||||
		label.show()
 | 
			
		||||
 | 
			
		||||
		self._buddy_list_model = gtk.ListStore(gobject.TYPE_STRING, gtk.gdk.Pixbuf, gobject.TYPE_PYOBJECT)
 | 
			
		||||
 | 
			
		||||
		self._pixbuf_active_chat = gtk.gdk.pixbuf_new_from_file(data_dir + "/bubbleOutline.png")
 | 
			
		||||
		self._pixbuf_new_message = gtk.gdk.pixbuf_new_from_file(data_dir + "/bubble.png")
 | 
			
		||||
 | 
			
		||||
		sw = gtk.ScrolledWindow()
 | 
			
		||||
		sw.set_shadow_type(gtk.SHADOW_IN)
 | 
			
		||||
		sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
 | 
			
		||||
 | 
			
		||||
		self._buddy_list_view = gtk.TreeView(self._buddy_list_model)
 | 
			
		||||
		self._buddy_list_view.set_headers_visible(False)
 | 
			
		||||
		self._buddy_list_view.connect("cursor-changed", self._on_buddyList_buddy_selected)
 | 
			
		||||
		self._buddy_list_view.connect("row-activated", self._on_buddyList_buddy_double_clicked)
 | 
			
		||||
 | 
			
		||||
		sw.set_size_request(120, -1)
 | 
			
		||||
		sw.add(self._buddy_list_view)
 | 
			
		||||
		self._buddy_list_view.show()
 | 
			
		||||
 | 
			
		||||
		renderer = gtk.CellRendererPixbuf()
 | 
			
		||||
		column = gtk.TreeViewColumn("", renderer, pixbuf=self._MODEL_COL_ICON)
 | 
			
		||||
		column.set_resizable(False)
 | 
			
		||||
		column.set_expand(False);
 | 
			
		||||
		self._buddy_list_view.append_column(column)
 | 
			
		||||
 | 
			
		||||
		renderer = gtk.CellRendererText()
 | 
			
		||||
		column = gtk.TreeViewColumn("", renderer, text=self._MODEL_COL_NICK)
 | 
			
		||||
		column.set_resizable(True)
 | 
			
		||||
		column.set_sizing("GTK_TREE_VIEW_COLUMN_GROW_ONLY");
 | 
			
		||||
		column.set_expand(True);
 | 
			
		||||
		self._buddy_list_view.append_column(column)
 | 
			
		||||
 | 
			
		||||
		vbox.pack_start(sw)
 | 
			
		||||
		sw.show()
 | 
			
		||||
 | 
			
		||||
		return vbox
 | 
			
		||||
 | 
			
		||||
	def _ui_setup(self, base):
 | 
			
		||||
		Chat._ui_setup(self, base)
 | 
			
		||||
 | 
			
		||||
		sidebar = self._create_sidebar()
 | 
			
		||||
		self._hbox.pack_start(sidebar, False)
 | 
			
		||||
		sidebar.show()
 | 
			
		||||
		self._plug.show_all()
 | 
			
		||||
 | 
			
		||||
	def activity_on_connected_to_shell(self):
 | 
			
		||||
		Chat.activity_on_connected_to_shell(self)
 | 
			
		||||
		
 | 
			
		||||
		self.activity_set_tab_icon_name("stock_help-chat")
 | 
			
		||||
		self.activity_show_icon(True)
 | 
			
		||||
 | 
			
		||||
		aniter = self._buddy_list_model.append(None)
 | 
			
		||||
		self._buddy_list_model.set(aniter, self._MODEL_COL_NICK, "Group",
 | 
			
		||||
				self._MODEL_COL_ICON, self._pixbuf_active_chat, self._MODEL_COL_BUDDY, None)
 | 
			
		||||
		self._start()
 | 
			
		||||
 | 
			
		||||
	def activity_on_disconnected_from_shell(self):
 | 
			
		||||
		Chat.activity_on_disconnected_from_shell(self)
 | 
			
		||||
		gtk.main_quit()
 | 
			
		||||
 | 
			
		||||
	def _on_buddyList_buddy_selected(self, widget, *args):
 | 
			
		||||
		(model, aniter) = widget.get_selection().get_selected()
 | 
			
		||||
		name = self._buddy_list_model.get(aniter, self._MODEL_COL_NICK)
 | 
			
		||||
		print "Selected %s" % name
 | 
			
		||||
 | 
			
		||||
	def _on_buddyList_buddy_double_clicked(self, widget, *args):
 | 
			
		||||
		""" Select the chat for this buddy or group """
 | 
			
		||||
		(model, aniter) = widget.get_selection().get_selected()
 | 
			
		||||
		chat = None
 | 
			
		||||
		buddy = self._buddy_list_model.get_value(aniter, self._MODEL_COL_BUDDY)
 | 
			
		||||
		if buddy and not self._chats.has_key(buddy):
 | 
			
		||||
			chat = BuddyChat(self, buddy)
 | 
			
		||||
			self._chats[buddy] = chat
 | 
			
		||||
			chat.activity_connect_to_shell()
 | 
			
		||||
 | 
			
		||||
	def _on_group_event(self, action, buddy):
 | 
			
		||||
		if buddy.get_nick_name() == self._group.get_owner().get_nick_name():
 | 
			
		||||
			# Do not show ourself in the buddy list
 | 
			
		||||
			pass
 | 
			
		||||
		elif action == BUDDY_JOIN:
 | 
			
		||||
			aniter = self._buddy_list_model.append(None)
 | 
			
		||||
			self._buddy_list_model.set(aniter, self._MODEL_COL_NICK, buddy.get_nick_name(),
 | 
			
		||||
					self._MODEL_COL_ICON, None, self._MODEL_COL_BUDDY, buddy)
 | 
			
		||||
		elif action == BUDDY_LEAVE:
 | 
			
		||||
			aniter = self._get_iter_for_buddy(buddy)
 | 
			
		||||
			if aniter:
 | 
			
		||||
				self._buddy_list_model.remove(aniter)
 | 
			
		||||
 | 
			
		||||
	def _get_iter_for_buddy(self, buddy):
 | 
			
		||||
		aniter = self._buddy_list_model.get_iter_first()
 | 
			
		||||
		while aniter:
 | 
			
		||||
			list_buddy = self._buddy_list_model.get_value(aniter, self._MODEL_COL_BUDDY)
 | 
			
		||||
			if buddy == list_buddy:
 | 
			
		||||
				return aniter
 | 
			
		||||
			aniter = self._buddy_list_model.iter_next(aniter)
 | 
			
		||||
 | 
			
		||||
	def notify_new_message(self, chat, buddy):
 | 
			
		||||
		aniter = self._get_iter_for_buddy(buddy)
 | 
			
		||||
		self._buddy_list_model.set(aniter, self._MODEL_COL_ICON, self._pixbuf_new_message)
 | 
			
		||||
 | 
			
		||||
	def notify_activate(self, chat):
 | 
			
		||||
		aniter = self._get_iter_for_buddy(buddy)
 | 
			
		||||
		self._buddy_list_model.set(aniter, self._MODEL_COL_ICON, self._pixbuf_active_chat)
 | 
			
		||||
 | 
			
		||||
	def send_message(self, text):
 | 
			
		||||
		if len(text) > 0:
 | 
			
		||||
			self._stream_writer.write(text)
 | 
			
		||||
		self._local_message(True, text)
 | 
			
		||||
 | 
			
		||||
	def recv_message(self, buddy, msg):
 | 
			
		||||
		if buddy:
 | 
			
		||||
			self._insert_rich_message(buddy.get_nick_name(), msg)
 | 
			
		||||
			self._controller.notify_new_message(self, None)
 | 
			
		||||
 | 
			
		||||
	def _buddy_recv_message(self, sender, msg):
 | 
			
		||||
		if not self._chats.has_key(sender):
 | 
			
		||||
			chat = BuddyChat(self, sender)
 | 
			
		||||
			self._chats[sender] = chat
 | 
			
		||||
			chat.activity_connect_to_shell()
 | 
			
		||||
		else:
 | 
			
		||||
			chat = self._chats[sender]
 | 
			
		||||
		chat.recv_message(sender, msg)
 | 
			
		||||
 | 
			
		||||
class ChatShell(dbus.service.Object):
 | 
			
		||||
	instance = None
 | 
			
		||||
 | 
			
		||||
	def get_instance():
 | 
			
		||||
		if not ChatShell.instance:
 | 
			
		||||
			ChatShell.instance = ChatShell()
 | 
			
		||||
		return ChatShell.instance
 | 
			
		||||
		
 | 
			
		||||
	get_instance = staticmethod(get_instance)
 | 
			
		||||
 | 
			
		||||
	def __init__(self):
 | 
			
		||||
		session_bus = dbus.SessionBus()
 | 
			
		||||
		bus_name = dbus.service.BusName('com.redhat.Sugar.Chat', bus=session_bus)
 | 
			
		||||
		object_path = '/com/redhat/Sugar/Chat'
 | 
			
		||||
 | 
			
		||||
		dbus.service.Object.__init__(self, bus_name, object_path)
 | 
			
		||||
 | 
			
		||||
	def open_group_chat(self):
 | 
			
		||||
		group_chat = GroupChat()
 | 
			
		||||
		group_chat.activity_connect_to_shell()
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method('com.redhat.Sugar.ChatShell')
 | 
			
		||||
	def send_message(self, message):
 | 
			
		||||
		pass
 | 
			
		||||
		
 | 
			
		||||
def main():
 | 
			
		||||
	ChatShell.get_instance().open_group_chat()
 | 
			
		||||
	try:
 | 
			
		||||
		gtk.main()
 | 
			
		||||
	except KeyboardInterrupt:
 | 
			
		||||
		pass
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
	main()
 | 
			
		||||
							
								
								
									
										374
									
								
								chat/richtext.py
									
									
									
									
									
								
							
							
						
						
									
										374
									
								
								chat/richtext.py
									
									
									
									
									
								
							@ -1,374 +0,0 @@
 | 
			
		||||
#!/usr/bin/env python
 | 
			
		||||
 | 
			
		||||
import pygtk
 | 
			
		||||
import gobject
 | 
			
		||||
pygtk.require('2.0')
 | 
			
		||||
import gtk
 | 
			
		||||
import pango
 | 
			
		||||
import xml.sax
 | 
			
		||||
 | 
			
		||||
class RichTextView(gtk.TextView):
 | 
			
		||||
	
 | 
			
		||||
	__gsignals__ = {
 | 
			
		||||
		'link-clicked': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
 | 
			
		||||
					    ([gobject.TYPE_STRING]))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	def __init__(self):
 | 
			
		||||
		gtk.TextView.__init__(self, RichTextBuffer())
 | 
			
		||||
		self.connect("motion-notify-event", self.__motion_notify_cb)
 | 
			
		||||
		self.connect("button-press-event", self.__button_press_cb)
 | 
			
		||||
		self.__hover_link = False
 | 
			
		||||
 | 
			
		||||
	def _set_hover_link(self, hover_link):
 | 
			
		||||
		if hover_link != self.__hover_link:
 | 
			
		||||
			self.__hover_link = hover_link
 | 
			
		||||
			display = self.get_toplevel().get_display()
 | 
			
		||||
			child_window = self.get_window(gtk.TEXT_WINDOW_TEXT)
 | 
			
		||||
			
 | 
			
		||||
			if hover_link:
 | 
			
		||||
				cursor = gtk.gdk.Cursor(display, gtk.gdk.HAND2)
 | 
			
		||||
			else:
 | 
			
		||||
				cursor = gtk.gdk.Cursor(display, gtk.gdk.XTERM)
 | 
			
		||||
				
 | 
			
		||||
			child_window.set_cursor(cursor)
 | 
			
		||||
			gtk.gdk.flush()
 | 
			
		||||
	
 | 
			
		||||
	def __iter_is_link(self, it):
 | 
			
		||||
		item = self.get_buffer().get_tag_table().lookup("link")
 | 
			
		||||
		if item:
 | 
			
		||||
			return it.has_tag(item)
 | 
			
		||||
		return False
 | 
			
		||||
 | 
			
		||||
	def __get_event_iter(self, event):
 | 
			
		||||
		return self.get_iter_at_location(int(event.x), int(event.y))
 | 
			
		||||
 | 
			
		||||
	def __motion_notify_cb(self, widget, event):
 | 
			
		||||
		if event.is_hint:
 | 
			
		||||
			[x, y, state] = event.window.get_pointer();
 | 
			
		||||
		
 | 
			
		||||
		it = self.__get_event_iter(event)
 | 
			
		||||
		if it:
 | 
			
		||||
			hover_link = self.__iter_is_link(it)
 | 
			
		||||
		else:
 | 
			
		||||
			hover_link = False
 | 
			
		||||
 | 
			
		||||
		self._set_hover_link(hover_link)
 | 
			
		||||
		
 | 
			
		||||
	def __button_press_cb(self, widget, event):
 | 
			
		||||
		it = self.__get_event_iter(event)
 | 
			
		||||
		if it and self.__iter_is_link(it):
 | 
			
		||||
			buf = self.get_buffer()
 | 
			
		||||
			address_tag = buf.get_tag_table().lookup("link-address")
 | 
			
		||||
 | 
			
		||||
			address_end = it.copy()
 | 
			
		||||
			address_end.backward_to_tag_toggle(address_tag)
 | 
			
		||||
			
 | 
			
		||||
			address_start = address_end.copy()
 | 
			
		||||
			address_start.backward_to_tag_toggle(address_tag)
 | 
			
		||||
			
 | 
			
		||||
			address = buf.get_text(address_start, address_end)
 | 
			
		||||
			self.emit("link-clicked", address)
 | 
			
		||||
 | 
			
		||||
class RichTextBuffer(gtk.TextBuffer):
 | 
			
		||||
	def __init__(self):
 | 
			
		||||
		gtk.TextBuffer.__init__(self)
 | 
			
		||||
 | 
			
		||||
		self.connect_after("insert-text", self.__insert_text_cb)
 | 
			
		||||
		
 | 
			
		||||
		self.__create_tags()
 | 
			
		||||
		self.active_tags = []
 | 
			
		||||
 | 
			
		||||
	def append_link(self, title, address):
 | 
			
		||||
		it = self.get_iter_at_mark(self.get_insert())
 | 
			
		||||
		self.insert_with_tags_by_name(it, address, "link", "link-address")
 | 
			
		||||
		self.insert_with_tags_by_name(it, title, "link")
 | 
			
		||||
		
 | 
			
		||||
	def apply_tag(self, tag_name):
 | 
			
		||||
		self.active_tags.append(tag_name)
 | 
			
		||||
		
 | 
			
		||||
		bounds = self.get_selection_bounds()
 | 
			
		||||
		if bounds:
 | 
			
		||||
			[start, end] = bounds
 | 
			
		||||
			self.apply_tag_by_name(tag_name, start, end)
 | 
			
		||||
 | 
			
		||||
	def unapply_tag(self, tag_name):
 | 
			
		||||
		self.active_tags.remove(tag_name)
 | 
			
		||||
 | 
			
		||||
		bounds = self.get_selection_bounds()
 | 
			
		||||
		if bounds:
 | 
			
		||||
			[start, end] = bounds
 | 
			
		||||
			self.remove_tag_by_name(tag_name, start, end)
 | 
			
		||||
	
 | 
			
		||||
	def __create_tags(self):
 | 
			
		||||
		tag = self.create_tag("link")
 | 
			
		||||
		tag.set_property("underline", pango.UNDERLINE_SINGLE)
 | 
			
		||||
		tag.set_property("foreground", "#0000FF")
 | 
			
		||||
 | 
			
		||||
		tag = self.create_tag("link-address")
 | 
			
		||||
		tag.set_property("invisible", True)
 | 
			
		||||
 | 
			
		||||
		tag = self.create_tag("bold")
 | 
			
		||||
		tag.set_property("weight", pango.WEIGHT_BOLD)
 | 
			
		||||
		
 | 
			
		||||
		tag = self.create_tag("italic")
 | 
			
		||||
		tag.set_property("style", pango.STYLE_ITALIC)
 | 
			
		||||
 | 
			
		||||
		tag = self.create_tag("font-size-xx-small")
 | 
			
		||||
		tag.set_property("scale", pango.SCALE_XX_SMALL)
 | 
			
		||||
 | 
			
		||||
		tag = self.create_tag("font-size-x-small")
 | 
			
		||||
		tag.set_property("scale", pango.SCALE_X_SMALL)
 | 
			
		||||
 | 
			
		||||
		tag = self.create_tag("font-size-small")
 | 
			
		||||
		tag.set_property("scale", pango.SCALE_SMALL)
 | 
			
		||||
 | 
			
		||||
		tag = self.create_tag("font-size-large")
 | 
			
		||||
		tag.set_property("scale", pango.SCALE_LARGE)
 | 
			
		||||
 | 
			
		||||
		tag = self.create_tag("font-size-x-large")
 | 
			
		||||
		tag.set_property("scale", pango.SCALE_X_LARGE)
 | 
			
		||||
 | 
			
		||||
		tag = self.create_tag("font-size-xx-large")
 | 
			
		||||
		tag.set_property("scale", pango.SCALE_XX_LARGE)
 | 
			
		||||
	
 | 
			
		||||
	def __insert_text_cb(self, widget, pos, text, length):
 | 
			
		||||
		for tag in self.active_tags:
 | 
			
		||||
				pos_end = pos.copy()
 | 
			
		||||
				pos_end.backward_chars(length)
 | 
			
		||||
				self.apply_tag_by_name(tag, pos, pos_end)
 | 
			
		||||
		
 | 
			
		||||
class RichTextToolbar(gtk.Toolbar):
 | 
			
		||||
	def __init__(self, buf):
 | 
			
		||||
		gtk.Toolbar.__init__(self)
 | 
			
		||||
		
 | 
			
		||||
		self.buf = buf
 | 
			
		||||
		
 | 
			
		||||
		self.set_style(gtk.TOOLBAR_ICONS)
 | 
			
		||||
		
 | 
			
		||||
		self._font_size = "normal"
 | 
			
		||||
		self._font_scales = [ "xx-small", "x-small", "small",	\
 | 
			
		||||
							  "normal",							\
 | 
			
		||||
							  "large", "x-large", "xx-large" ]
 | 
			
		||||
		
 | 
			
		||||
		item = gtk.ToggleToolButton(gtk.STOCK_BOLD)
 | 
			
		||||
		item.connect("toggled", self.__toggle_style_cb, "bold")
 | 
			
		||||
		self.insert(item, -1)
 | 
			
		||||
		item.show()
 | 
			
		||||
 | 
			
		||||
		item = gtk.ToggleToolButton(gtk.STOCK_ITALIC)
 | 
			
		||||
		item.connect("toggled", self.__toggle_style_cb, "italic")
 | 
			
		||||
		self.insert(item, -1)
 | 
			
		||||
		item.show()
 | 
			
		||||
 | 
			
		||||
		self._font_size_up = gtk.ToolButton(gtk.STOCK_GO_UP)
 | 
			
		||||
		self._font_size_up.connect("clicked", self.__font_size_up_cb)
 | 
			
		||||
		self.insert(self._font_size_up, -1)
 | 
			
		||||
		self._font_size_up.show()
 | 
			
		||||
 | 
			
		||||
		self._font_size_down = gtk.ToolButton(gtk.STOCK_GO_DOWN)
 | 
			
		||||
		self._font_size_down.connect("clicked", self.__font_size_down_cb)
 | 
			
		||||
		self.insert(self._font_size_down, -1)
 | 
			
		||||
		self._font_size_down.show()
 | 
			
		||||
	
 | 
			
		||||
	def _get_font_size_index(self):
 | 
			
		||||
		return self._font_scales.index(self._font_size);
 | 
			
		||||
	
 | 
			
		||||
	def __toggle_style_cb(self, toggle, tag_name):
 | 
			
		||||
		if toggle.get_active():
 | 
			
		||||
			self.buf.apply_tag(tag_name)
 | 
			
		||||
		else:
 | 
			
		||||
			self.buf.unapply_tag(tag_name)
 | 
			
		||||
 | 
			
		||||
	def _set_font_size(self, font_size):
 | 
			
		||||
		if self._font_size != "normal":
 | 
			
		||||
			self.buf.unapply_tag("font-size-" + self._font_size)
 | 
			
		||||
		if font_size != "normal":
 | 
			
		||||
			self.buf.apply_tag("font-size-" + font_size)
 | 
			
		||||
			
 | 
			
		||||
		self._font_size = font_size
 | 
			
		||||
		
 | 
			
		||||
		can_up = self._get_font_size_index() < len(self._font_scales) - 1
 | 
			
		||||
		can_down = self._get_font_size_index() > 0
 | 
			
		||||
		self._font_size_up.set_sensitive(can_up)
 | 
			
		||||
		self._font_size_down.set_sensitive(can_down)
 | 
			
		||||
 | 
			
		||||
	def __font_size_up_cb(self, button): 
 | 
			
		||||
		index = self._get_font_size_index()
 | 
			
		||||
		if index + 1 < len(self._font_scales):
 | 
			
		||||
			self._set_font_size(self._font_scales[index + 1])
 | 
			
		||||
 | 
			
		||||
	def __font_size_down_cb(self, button):
 | 
			
		||||
		index = self._get_font_size_index()
 | 
			
		||||
		if index > 0:
 | 
			
		||||
			self._set_font_size(self._font_scales[index - 1])
 | 
			
		||||
			
 | 
			
		||||
class RichTextHandler(xml.sax.handler.ContentHandler):
 | 
			
		||||
	def __init__(self, serializer, buf):
 | 
			
		||||
		self.buf = buf
 | 
			
		||||
		self.serializer = serializer
 | 
			
		||||
		self.tags = []
 | 
			
		||||
 | 
			
		||||
	def startElement(self, name, attrs):
 | 
			
		||||
		if name != "richtext":
 | 
			
		||||
			tag = self.serializer.deserialize_element(name, attrs)
 | 
			
		||||
			self.tags.append(tag)
 | 
			
		||||
		if name == "link":
 | 
			
		||||
			self.href = attrs['href']
 | 
			
		||||
 
 | 
			
		||||
	def characters(self, data):
 | 
			
		||||
		start_it = it = self.buf.get_end_iter()
 | 
			
		||||
		mark = self.buf.create_mark(None, start_it, True)
 | 
			
		||||
		self.buf.insert(it, data)
 | 
			
		||||
		start_it = self.buf.get_iter_at_mark(mark)
 | 
			
		||||
 | 
			
		||||
		for tag in self.tags:
 | 
			
		||||
			self.buf.apply_tag_by_name(tag, start_it, it)
 | 
			
		||||
			if tag == "link":
 | 
			
		||||
				self.buf.insert_with_tags_by_name(start_it, self.href,
 | 
			
		||||
											      "link", "link-address")
 | 
			
		||||
 
 | 
			
		||||
	def endElement(self, name):
 | 
			
		||||
		if name != "richtext":
 | 
			
		||||
			self.tags.pop()
 | 
			
		||||
 | 
			
		||||
class RichTextSerializer:
 | 
			
		||||
	def __init__(self):
 | 
			
		||||
		self._open_tags = []
 | 
			
		||||
 | 
			
		||||
	def deserialize_element(self, el_name, attributes):
 | 
			
		||||
		if el_name == "bold":
 | 
			
		||||
			return "bold"
 | 
			
		||||
		elif el_name == "italic":
 | 
			
		||||
			return "italic"
 | 
			
		||||
		elif el_name == "font":
 | 
			
		||||
			return "font-size-" + attributes["size"]
 | 
			
		||||
		elif el_name == "link":
 | 
			
		||||
			return "link"
 | 
			
		||||
		else:
 | 
			
		||||
			return None
 | 
			
		||||
 | 
			
		||||
	def serialize_tag_start(self, tag, it):
 | 
			
		||||
		name = tag.get_property("name")
 | 
			
		||||
		if name == "bold":
 | 
			
		||||
			return "<bold>"
 | 
			
		||||
		elif name == "italic":
 | 
			
		||||
			return "<italic>"
 | 
			
		||||
		elif name == "link":
 | 
			
		||||
			address_tag = self.buf.get_tag_table().lookup("link-address")
 | 
			
		||||
			end = it.copy()
 | 
			
		||||
			end.forward_to_tag_toggle(address_tag)
 | 
			
		||||
			address = self.buf.get_text(it, end)
 | 
			
		||||
			return "<link " + "href=\"" + address + "\">"
 | 
			
		||||
		elif name == "link-address":
 | 
			
		||||
			return ""
 | 
			
		||||
		elif name.startswith("font-size-"):
 | 
			
		||||
			tag_name = name.replace("font-size-", "", 1)
 | 
			
		||||
			return "<font size=\"" + tag_name + "\">"
 | 
			
		||||
		else:
 | 
			
		||||
			return "<unknown>"
 | 
			
		||||
 | 
			
		||||
	def serialize_tag_end(self, tag):
 | 
			
		||||
		name = tag.get_property("name")
 | 
			
		||||
		if name == "bold":
 | 
			
		||||
			return "</bold>"
 | 
			
		||||
		elif name == "italic":
 | 
			
		||||
			return "</italic>"
 | 
			
		||||
		elif name == "link":
 | 
			
		||||
			return "</link>"
 | 
			
		||||
		elif name == "link-address":
 | 
			
		||||
			return ""
 | 
			
		||||
		elif name.startswith("font-size-"):
 | 
			
		||||
			return "</font>"
 | 
			
		||||
		else:
 | 
			
		||||
			return "</unknown>"
 | 
			
		||||
	
 | 
			
		||||
	def serialize(self, buf):
 | 
			
		||||
		self.buf = buf
 | 
			
		||||
		
 | 
			
		||||
		xml = "<richtext>"
 | 
			
		||||
 | 
			
		||||
		next_it = buf.get_start_iter()
 | 
			
		||||
		while not next_it.is_end():
 | 
			
		||||
			it = next_it.copy()
 | 
			
		||||
			if not next_it.forward_to_tag_toggle(None):
 | 
			
		||||
				next_it = buf.get_end_iter()
 | 
			
		||||
 | 
			
		||||
			tags_to_reopen = []
 | 
			
		||||
 | 
			
		||||
			for tag in it.get_toggled_tags(False):
 | 
			
		||||
				while 1:
 | 
			
		||||
					open_tag = self._open_tags.pop()
 | 
			
		||||
					xml += self.serialize_tag_end(tag)
 | 
			
		||||
					if open_tag == tag:
 | 
			
		||||
						break						
 | 
			
		||||
					tags_to_reopen.append(open_tag)
 | 
			
		||||
					
 | 
			
		||||
			for tag in tags_to_reopen:
 | 
			
		||||
				self._open_tags.append(tag)
 | 
			
		||||
				xml += self.serialize_tag_start(tag, it)
 | 
			
		||||
			
 | 
			
		||||
			for tag in it.get_toggled_tags(True):
 | 
			
		||||
				self._open_tags.append(tag)
 | 
			
		||||
				xml += self.serialize_tag_start(tag, it)
 | 
			
		||||
			
 | 
			
		||||
			xml += buf.get_text(it, next_it, False)
 | 
			
		||||
 | 
			
		||||
		if next_it.is_end():
 | 
			
		||||
			self._open_tags.reverse()
 | 
			
		||||
			for tag in self._open_tags:
 | 
			
		||||
				xml += self.serialize_tag_end(tag)
 | 
			
		||||
		
 | 
			
		||||
		xml += "</richtext>"
 | 
			
		||||
		
 | 
			
		||||
		return xml
 | 
			
		||||
 | 
			
		||||
	def deserialize(self, xml_string, buf):
 | 
			
		||||
		parser = xml.sax.make_parser()
 | 
			
		||||
		handler = RichTextHandler(self, buf)
 | 
			
		||||
		parser.setContentHandler(handler)
 | 
			
		||||
		parser.feed(xml_string)
 | 
			
		||||
		parser.close()
 | 
			
		||||
 | 
			
		||||
def test_quit(window, rich_buf):
 | 
			
		||||
	print RichTextSerializer().serialize(rich_buf)
 | 
			
		||||
	gtk.main_quit()
 | 
			
		||||
	
 | 
			
		||||
def link_clicked(view, address):
 | 
			
		||||
	print "Link clicked " + address
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
	window = gtk.Window()
 | 
			
		||||
	window.set_default_size(400, 300)
 | 
			
		||||
	
 | 
			
		||||
	vbox = gtk.VBox()
 | 
			
		||||
	
 | 
			
		||||
	view = RichTextView()
 | 
			
		||||
	view.connect("link-clicked", link_clicked)
 | 
			
		||||
	vbox.pack_start(view)
 | 
			
		||||
	view.show()
 | 
			
		||||
 | 
			
		||||
	rich_buf = view.get_buffer()
 | 
			
		||||
	
 | 
			
		||||
	xml_string = "<richtext>"	
 | 
			
		||||
 | 
			
		||||
	xml_string += "<bold><italic>Test</italic>one</bold>\n"
 | 
			
		||||
	xml_string += "<bold><italic>Test two</italic></bold>"
 | 
			
		||||
	xml_string += "<font size=\"xx-small\">Test three</font>"
 | 
			
		||||
	xml_string += "<link href=\"http://www.gnome.org\">Test link</link>"
 | 
			
		||||
	xml_string += "</richtext>"
 | 
			
		||||
 | 
			
		||||
	RichTextSerializer().deserialize(xml_string, rich_buf)
 | 
			
		||||
	
 | 
			
		||||
	toolbar = RichTextToolbar(rich_buf)
 | 
			
		||||
	vbox.pack_start(toolbar, False)
 | 
			
		||||
	toolbar.show()
 | 
			
		||||
	
 | 
			
		||||
	window.add(vbox)
 | 
			
		||||
	vbox.show()
 | 
			
		||||
	
 | 
			
		||||
	window.show()
 | 
			
		||||
	
 | 
			
		||||
	window.connect("destroy", test_quit, rich_buf)
 | 
			
		||||
 | 
			
		||||
	gtk.main()
 | 
			
		||||
							
								
								
									
										11
									
								
								configure.ac
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								configure.ac
									
									
									
									
									
								
							@ -17,9 +17,10 @@ AC_SUBST(PYGTK_LIBS)
 | 
			
		||||
 | 
			
		||||
AC_OUTPUT([
 | 
			
		||||
Makefile
 | 
			
		||||
sugar_globals.py
 | 
			
		||||
browser/Makefile
 | 
			
		||||
chat/Makefile
 | 
			
		||||
shell/Makefile
 | 
			
		||||
shell/src/Makefile
 | 
			
		||||
sugar/Makefile
 | 
			
		||||
sugar/__installed__.py
 | 
			
		||||
sugar/browser/Makefile
 | 
			
		||||
sugar/chat/Makefile
 | 
			
		||||
sugar/p2p/Makefile
 | 
			
		||||
sugar/shell/Makefile
 | 
			
		||||
])
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										133
									
								
								legacy/legacy.py
									
									
									
									
									
								
							
							
						
						
									
										133
									
								
								legacy/legacy.py
									
									
									
									
									
								
							@ -1,133 +0,0 @@
 | 
			
		||||
#!/usr/bin/python -t
 | 
			
		||||
# -*- tab-width: 4; indent-tabs-mode: t -*- 
 | 
			
		||||
 | 
			
		||||
import dbus
 | 
			
		||||
import dbus.service
 | 
			
		||||
import dbus.glib
 | 
			
		||||
 | 
			
		||||
import pygtk
 | 
			
		||||
pygtk.require('2.0')
 | 
			
		||||
import gtk, gobject
 | 
			
		||||
 | 
			
		||||
import sys
 | 
			
		||||
import os
 | 
			
		||||
import pwd
 | 
			
		||||
import gc
 | 
			
		||||
import socket
 | 
			
		||||
import types
 | 
			
		||||
import select
 | 
			
		||||
import string
 | 
			
		||||
import time
 | 
			
		||||
 | 
			
		||||
sys.path.append(os.getcwd())
 | 
			
		||||
sys.path.append('../shell/example-activity/')
 | 
			
		||||
import activity
 | 
			
		||||
 | 
			
		||||
XEPHYR_PATH = "/usr/bin/Xephyr"
 | 
			
		||||
MATCHBOX_PATH = "/usr/bin/matchbox-window-manager"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class LegacyActivity(activity.Activity):
 | 
			
		||||
 | 
			
		||||
	def __init__(self, args):
 | 
			
		||||
		activity.Activity.__init__(self)
 | 
			
		||||
		self._act_name = os.path.basename(args[1])
 | 
			
		||||
		self._display = 5
 | 
			
		||||
		self._args = args[1:]
 | 
			
		||||
		self._act_pid = None
 | 
			
		||||
		self._matchbox_pid = None
 | 
			
		||||
		self._xephyr_pid = None
 | 
			
		||||
 | 
			
		||||
	def _xephyr_function(self, pid, condition, data=None):
 | 
			
		||||
		print "Xephyr: PID: %d, condition: %s" % (pid, condition)
 | 
			
		||||
 | 
			
		||||
	def _matchbox_function(self, pid, condition, data=None):
 | 
			
		||||
		print "WM: PID: %d, condition: %s" % (pid, condition)
 | 
			
		||||
 | 
			
		||||
	def _act_function(self, pid, condition, data=None):
 | 
			
		||||
		print "ACT: PID: %d, condition: %s" % (pid, condition)
 | 
			
		||||
		if condition == 0:
 | 
			
		||||
			self._act_pid = None
 | 
			
		||||
			gtk.main_quit()
 | 
			
		||||
 | 
			
		||||
	def __key_press_event_cb(self, widget, event):
 | 
			
		||||
		print event
 | 
			
		||||
 | 
			
		||||
	def _start(self):
 | 
			
		||||
		args = string.split("%s :%d -ac -parent %d -host-cursor" % (XEPHYR_PATH, self._display, self._plug.get_id()))
 | 
			
		||||
		(self._xephyr_pid, a, b, c) = gobject.spawn_async(args, standard_output=sys.stdout, standard_error=sys.stderr)
 | 
			
		||||
		self._xephyr_watch = gobject.child_watch_add(self._xephyr_pid, self._xephyr_function)
 | 
			
		||||
 | 
			
		||||
		envp = ["DISPLAY=:%d" % self._display]
 | 
			
		||||
		envp.append("INPUTRC=/etc/inputrc")
 | 
			
		||||
		envp.append("XMODIFIERS=@im=SCIM")
 | 
			
		||||
		envp.append("GTK_IM_MODULE=scim")
 | 
			
		||||
		try:
 | 
			
		||||
			envp.append("LANG=%s" % os.environ['LANG'])
 | 
			
		||||
		except:
 | 
			
		||||
			envp.append("LANG=en_US.UTF-8")
 | 
			
		||||
 | 
			
		||||
		args = string.split("%s" % MATCHBOX_PATH)
 | 
			
		||||
		(self._matchbox_pid, a, b, c) = gobject.spawn_async(args, envp=envp, standard_output=sys.stdout, standard_error=sys.stderr)
 | 
			
		||||
		gobject.child_watch_add(self._matchbox_pid, self._matchbox_function)
 | 
			
		||||
 | 
			
		||||
		args = [os.path.abspath(self._args[0])]
 | 
			
		||||
		for arg in self._args[1:]:
 | 
			
		||||
			args.append(arg)
 | 
			
		||||
		(self._act_pid, a, b, c) = gobject.spawn_async(args, envp=envp, standard_output=sys.stdout, standard_error=sys.stderr)
 | 
			
		||||
		gobject.child_watch_add(self._act_pid, self._act_function)
 | 
			
		||||
 | 
			
		||||
	def activity_on_connected_to_shell(self):
 | 
			
		||||
		print "act %d: in activity_on_connected_to_shell" % self.activity_get_id()
 | 
			
		||||
		self.activity_set_tab_text(self._act_name)
 | 
			
		||||
		self._plug = self.activity_get_gtk_plug()
 | 
			
		||||
		self._plug.add_events(gtk.gdk.ALL_EVENTS_MASK)
 | 
			
		||||
		self._plug.connect("key-press-event", self.__key_press_event_cb)
 | 
			
		||||
		self._plug.show()
 | 
			
		||||
		self._start()
 | 
			
		||||
		self._plug.grab_focus()
 | 
			
		||||
 | 
			
		||||
	def activity_on_disconnected_from_shell(self):
 | 
			
		||||
		print "act %d: in activity_on_disconnected_from_shell"%self.activity_get_id()
 | 
			
		||||
		print "act %d: Shell disappeared..."%self.activity_get_id()
 | 
			
		||||
		gc.collect()
 | 
			
		||||
 | 
			
		||||
	def activity_on_close_from_user(self):
 | 
			
		||||
		print "act %d: in activity_on_close_from_user"%self.activity_get_id()
 | 
			
		||||
		self.activity_shutdown()
 | 
			
		||||
 | 
			
		||||
	def activity_on_lost_focus(self):
 | 
			
		||||
		print "act %d: in activity_on_lost_focus"%self.activity_get_id()
 | 
			
		||||
 | 
			
		||||
	def activity_on_got_focus(self):
 | 
			
		||||
		print "act %d: in activity_on_got_focus"%self.activity_get_id()
 | 
			
		||||
		self._plug.grab_focus()
 | 
			
		||||
 | 
			
		||||
	def cleanup(self):
 | 
			
		||||
		try:
 | 
			
		||||
			if self._act_pid:
 | 
			
		||||
				os.kill(self._act_pid, 9)
 | 
			
		||||
				time.sleep(0.2)
 | 
			
		||||
			if self._xephyr_pid:
 | 
			
		||||
				os.kill(self._xephyr_pid, 9)
 | 
			
		||||
				time.sleep(0.2)
 | 
			
		||||
			if self._matchbox_pid:
 | 
			
		||||
				os.kill(self._matchbox_pid, 9)
 | 
			
		||||
				time.sleep(0.2)
 | 
			
		||||
		except OSError, e:
 | 
			
		||||
			pass
 | 
			
		||||
 | 
			
		||||
	def run(self):
 | 
			
		||||
		try:
 | 
			
		||||
			gtk.main()
 | 
			
		||||
		except KeyboardInterrupt:
 | 
			
		||||
			pass
 | 
			
		||||
 | 
			
		||||
def main(args):
 | 
			
		||||
	app = LegacyActivity(args)
 | 
			
		||||
	app.activity_connect_to_shell()
 | 
			
		||||
	app.run()
 | 
			
		||||
	app.cleanup()
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
	main(sys.argv)
 | 
			
		||||
							
								
								
									
										34
									
								
								p2p/Buddy.py
									
									
									
									
									
								
							
							
						
						
									
										34
									
								
								p2p/Buddy.py
									
									
									
									
									
								
							@ -1,34 +0,0 @@
 | 
			
		||||
import pwd
 | 
			
		||||
import os
 | 
			
		||||
 | 
			
		||||
from Service import *
 | 
			
		||||
 | 
			
		||||
PRESENCE_SERVICE_TYPE = "_olpc_presence._tcp"
 | 
			
		||||
PRESENCE_SERVICE_PORT = 6000
 | 
			
		||||
 | 
			
		||||
class Buddy:
 | 
			
		||||
	def __init__(self, service, nick_name):
 | 
			
		||||
		self._service = service
 | 
			
		||||
		self._nick_name = nick_name
 | 
			
		||||
		
 | 
			
		||||
	def get_service_name(self):
 | 
			
		||||
		return self._service.get_name()
 | 
			
		||||
		
 | 
			
		||||
	def get_nick_name(self):
 | 
			
		||||
		return self._nick_name
 | 
			
		||||
		
 | 
			
		||||
class Owner(Buddy):
 | 
			
		||||
	def __init__(self, group):
 | 
			
		||||
		self._group = group
 | 
			
		||||
	
 | 
			
		||||
		nick = pwd.getpwuid(os.getuid())[0]
 | 
			
		||||
		if not nick or not len(nick):
 | 
			
		||||
			nick = "n00b"
 | 
			
		||||
 | 
			
		||||
		service = Service(nick, PRESENCE_SERVICE_TYPE,
 | 
			
		||||
						  '', PRESENCE_SERVICE_PORT)
 | 
			
		||||
 | 
			
		||||
		Buddy.__init__(self, service, nick)
 | 
			
		||||
		
 | 
			
		||||
	def register(self):
 | 
			
		||||
		self._service.register(self._group)
 | 
			
		||||
							
								
								
									
										102
									
								
								p2p/Group.py
									
									
									
									
									
								
							
							
						
						
									
										102
									
								
								p2p/Group.py
									
									
									
									
									
								
							@ -1,102 +0,0 @@
 | 
			
		||||
import avahi
 | 
			
		||||
 | 
			
		||||
import presence
 | 
			
		||||
from Buddy import *
 | 
			
		||||
from Service import *
 | 
			
		||||
 | 
			
		||||
SERVICE_ADDED = "service_added"
 | 
			
		||||
SERVICE_REMOVED = "service_removed"
 | 
			
		||||
 | 
			
		||||
BUDDY_JOIN = "buddy_join"
 | 
			
		||||
BUDDY_LEAVE = "buddy_leave"
 | 
			
		||||
 | 
			
		||||
class Group:
 | 
			
		||||
	def __init__(self):
 | 
			
		||||
		self._service_listeners = []
 | 
			
		||||
		self._presence_listeners = []
 | 
			
		||||
	
 | 
			
		||||
	def join(self, buddy):
 | 
			
		||||
		pass
 | 
			
		||||
	
 | 
			
		||||
	def add_service_listener(self, listener):
 | 
			
		||||
		self._service_listeners.append(listener)
 | 
			
		||||
 | 
			
		||||
	def add_presence_listener(self, listener):
 | 
			
		||||
		self._presence_listeners.append(listener)
 | 
			
		||||
		
 | 
			
		||||
	def _notify_service_added(self, service):
 | 
			
		||||
		for listener in self._service_listeners:
 | 
			
		||||
			listener(SERVICE_ADDED, buddy)
 | 
			
		||||
	
 | 
			
		||||
	def _notify_service_removed(self, service):
 | 
			
		||||
		for listener in self._service_listeners:
 | 
			
		||||
			listener(SERVICE_REMOVED,buddy)
 | 
			
		||||
 | 
			
		||||
	def _notify_buddy_join(self, buddy):
 | 
			
		||||
		for listener in self._presence_listeners:
 | 
			
		||||
			listener(BUDDY_JOIN, buddy)
 | 
			
		||||
	
 | 
			
		||||
	def _notify_buddy_leave(self, buddy):
 | 
			
		||||
		for listener in self._presence_listeners:
 | 
			
		||||
			listener(BUDDY_LEAVE, buddy)
 | 
			
		||||
 | 
			
		||||
class LocalGroup(Group):
 | 
			
		||||
	def __init__(self):
 | 
			
		||||
		Group.__init__(self)
 | 
			
		||||
 | 
			
		||||
		self._services = {}
 | 
			
		||||
		self._buddies = {}
 | 
			
		||||
 | 
			
		||||
		self._pdiscovery = presence.PresenceDiscovery()
 | 
			
		||||
		self._pdiscovery.add_service_listener(self._on_service_change)
 | 
			
		||||
		self._pdiscovery.start()
 | 
			
		||||
 | 
			
		||||
	def get_owner(self):
 | 
			
		||||
		return self._owner
 | 
			
		||||
 | 
			
		||||
	def add_service(self, service):
 | 
			
		||||
		sid = (service.get_name(), service.get_type())
 | 
			
		||||
		self._services[sid] = service
 | 
			
		||||
		self._notify_service_added(service)
 | 
			
		||||
 | 
			
		||||
	def remove_service(self, sid):
 | 
			
		||||
		self._notify_service_removed(service)
 | 
			
		||||
		del self._services[sid]
 | 
			
		||||
 | 
			
		||||
	def join(self):
 | 
			
		||||
		self._owner = Owner(self)
 | 
			
		||||
		self._owner.register()
 | 
			
		||||
 | 
			
		||||
	def get_service(self, name, stype):
 | 
			
		||||
		return self._services[(name, stype)]
 | 
			
		||||
 | 
			
		||||
	def get_buddy(self, name):
 | 
			
		||||
		return self._buddies[name]
 | 
			
		||||
	
 | 
			
		||||
	def _add_buddy(self, buddy):
 | 
			
		||||
		bid = buddy.get_nick_name()
 | 
			
		||||
		if not self._buddies.has_key(bid):
 | 
			
		||||
			self._buddies[bid] = buddy
 | 
			
		||||
			self._notify_buddy_join(buddy)
 | 
			
		||||
 | 
			
		||||
	def _remove_buddy(self, buddy):
 | 
			
		||||
		self._notify_buddy_leave(buddy)
 | 
			
		||||
		del self._buddies[buddy.get_nick_name()]
 | 
			
		||||
	
 | 
			
		||||
	def _on_service_change(self, action, interface, protocol, name, stype, domain, flags):
 | 
			
		||||
		if action == presence.ACTION_SERVICE_NEW:
 | 
			
		||||
			self._pdiscovery.resolve_service(interface, protocol, name, stype, domain,
 | 
			
		||||
											 self._on_service_resolved)
 | 
			
		||||
		elif action == presence.ACTION_SERVICE_REMOVED:
 | 
			
		||||
			if stype == PRESENCE_SERVICE_TYPE:
 | 
			
		||||
				self._remove_buddy(name)
 | 
			
		||||
			elif stype.startswith("_olpc"):
 | 
			
		||||
				self.remove_service((name, stype))
 | 
			
		||||
						
 | 
			
		||||
	def _on_service_resolved(self, interface, protocol, name, stype, domain,
 | 
			
		||||
							 host, aprotocol, address, port, txt, flags):
 | 
			
		||||
			service = Service(name, stype, address, port)
 | 
			
		||||
			if stype == PRESENCE_SERVICE_TYPE:
 | 
			
		||||
				self._add_buddy(Buddy(service, name))
 | 
			
		||||
			elif stype.startswith("_olpc"):
 | 
			
		||||
				self.add_service(service)
 | 
			
		||||
@ -1,31 +0,0 @@
 | 
			
		||||
import presence
 | 
			
		||||
 | 
			
		||||
class Service(object):
 | 
			
		||||
	def __init__(self, name, stype, address, port, multicast=False):
 | 
			
		||||
		self._name = name
 | 
			
		||||
		self._stype = stype
 | 
			
		||||
		self._address = str(address)
 | 
			
		||||
		self._port = int(port)
 | 
			
		||||
		self._multicast = multicast
 | 
			
		||||
 | 
			
		||||
	def get_name(self):
 | 
			
		||||
		return self._name
 | 
			
		||||
	
 | 
			
		||||
	def get_type(self):
 | 
			
		||||
		return self._stype
 | 
			
		||||
 | 
			
		||||
	def get_address(self):
 | 
			
		||||
		return self._address
 | 
			
		||||
 | 
			
		||||
	def get_port(self):
 | 
			
		||||
		return self._port
 | 
			
		||||
 | 
			
		||||
	def set_port(self, port):
 | 
			
		||||
		self._port = port
 | 
			
		||||
		
 | 
			
		||||
	def is_multicast(self):
 | 
			
		||||
		return self._multicast
 | 
			
		||||
	
 | 
			
		||||
	def register(self, group):	
 | 
			
		||||
		pannounce = presence.PresenceAnnounce()
 | 
			
		||||
		pannounce.register_service(self._name, self._port, self._stype)
 | 
			
		||||
@ -1,51 +0,0 @@
 | 
			
		||||
import network
 | 
			
		||||
 | 
			
		||||
class StreamReaderRequestHandler(object):
 | 
			
		||||
	def __init__(self, reader):
 | 
			
		||||
		self._reader = reader
 | 
			
		||||
 | 
			
		||||
	def message(self, nick_name, message):
 | 
			
		||||
		address = network.get_authinfo()
 | 
			
		||||
		self._reader.recv(nick_name, message)
 | 
			
		||||
		return True
 | 
			
		||||
 | 
			
		||||
class StreamReader:
 | 
			
		||||
	def __init__(self, group, service):
 | 
			
		||||
		self._group = group
 | 
			
		||||
		self._service = service
 | 
			
		||||
		
 | 
			
		||||
		if self._service.is_multicast():
 | 
			
		||||
			self._setup_multicast()
 | 
			
		||||
		else:
 | 
			
		||||
			self._setup_unicast()
 | 
			
		||||
 | 
			
		||||
	def set_listener(self, callback):
 | 
			
		||||
		self._callback = callback
 | 
			
		||||
 | 
			
		||||
	def _setup_multicast(self):
 | 
			
		||||
		address = self._service.get_address()
 | 
			
		||||
		port = self._service.get_port()
 | 
			
		||||
		server = network.GroupServer(address, port, self._recv_multicast)
 | 
			
		||||
		server.start()
 | 
			
		||||
		
 | 
			
		||||
	def _setup_unicast(self):
 | 
			
		||||
		started = False
 | 
			
		||||
		tries = 10
 | 
			
		||||
		port = self._service.get_port()
 | 
			
		||||
		while not started and tries > 0:
 | 
			
		||||
			try:
 | 
			
		||||
				p2p_server = network.GlibXMLRPCServer(("", port))
 | 
			
		||||
				p2p_server.register_instance(StreamReaderRequestHandler(self))
 | 
			
		||||
				started = True
 | 
			
		||||
			except:
 | 
			
		||||
				port = port + 1
 | 
			
		||||
				tries = tries - 1
 | 
			
		||||
		self._service.set_port(port)
 | 
			
		||||
		
 | 
			
		||||
	def _recv_multicast(self, msg):
 | 
			
		||||
		[ nick_name, data ] = msg['data'].split(" |**| ", 2)
 | 
			
		||||
		self.recv(nick_name, data)
 | 
			
		||||
	
 | 
			
		||||
	def recv(self, nick_name, data):
 | 
			
		||||
		if nick_name != self._group.get_owner().get_nick_name():
 | 
			
		||||
			self._callback(self._group.get_buddy(nick_name), data)
 | 
			
		||||
@ -1,43 +0,0 @@
 | 
			
		||||
import xmlrpclib
 | 
			
		||||
import traceback
 | 
			
		||||
import socket
 | 
			
		||||
 | 
			
		||||
import network
 | 
			
		||||
 | 
			
		||||
class StreamWriter:
 | 
			
		||||
	def __init__(self, group, service):
 | 
			
		||||
		self._group = group
 | 
			
		||||
		self._service = service
 | 
			
		||||
		self._address = self._service.get_address()
 | 
			
		||||
		self._port = self._service.get_port()
 | 
			
		||||
 | 
			
		||||
		if self._service.is_multicast():
 | 
			
		||||
			self._setup_multicast()
 | 
			
		||||
		else:
 | 
			
		||||
			self._setup_unicast()
 | 
			
		||||
		
 | 
			
		||||
	def write(self, data):
 | 
			
		||||
		if self._service.is_multicast():
 | 
			
		||||
			self._multicast_write(data)
 | 
			
		||||
		else:
 | 
			
		||||
			self._unicast_write(data)
 | 
			
		||||
 | 
			
		||||
	def _setup_unicast(self):
 | 
			
		||||
		xmlrpc_addr = "http://%s:%d" % (self._address, self._port)
 | 
			
		||||
		self._uclient = xmlrpclib.ServerProxy(xmlrpc_addr)
 | 
			
		||||
 | 
			
		||||
	def _unicast_write(self, data):
 | 
			
		||||
		try:
 | 
			
		||||
			nick_name = self._group.get_owner().get_nick_name()
 | 
			
		||||
			self._uclient.message(nick_name, data)
 | 
			
		||||
			return True
 | 
			
		||||
		except (socket.error, xmlrpclib.Fault, xmlrpclib.ProtocolError), e:
 | 
			
		||||
			traceback.print_exc()
 | 
			
		||||
			return False
 | 
			
		||||
 | 
			
		||||
	def _setup_multicast(self):
 | 
			
		||||
		self._mclient = network.GroupClient(self._address, self._port)
 | 
			
		||||
		
 | 
			
		||||
	def _multicast_write(self, data):
 | 
			
		||||
		nick_name = self._group.get_owner().get_nick_name()
 | 
			
		||||
		self._mclient.send_msg(nick_name + " |**| " + data)
 | 
			
		||||
							
								
								
									
										176
									
								
								p2p/network.py
									
									
									
									
									
								
							
							
						
						
									
										176
									
								
								p2p/network.py
									
									
									
									
									
								
							@ -1,176 +0,0 @@
 | 
			
		||||
# -*- tab-width: 4; indent-tabs-mode: t -*- 
 | 
			
		||||
 | 
			
		||||
import socket
 | 
			
		||||
import threading
 | 
			
		||||
import traceback
 | 
			
		||||
import select
 | 
			
		||||
import time
 | 
			
		||||
import xmlrpclib
 | 
			
		||||
import sys
 | 
			
		||||
 | 
			
		||||
import gobject
 | 
			
		||||
import SimpleXMLRPCServer
 | 
			
		||||
import SocketServer
 | 
			
		||||
 | 
			
		||||
__authinfos = {}
 | 
			
		||||
 | 
			
		||||
def _add_authinfo(authinfo):
 | 
			
		||||
	__authinfos[threading.currentThread()] = authinfo
 | 
			
		||||
 | 
			
		||||
def get_authinfo():
 | 
			
		||||
	return __authinfos.get(threading.currentThread())
 | 
			
		||||
 | 
			
		||||
def _del_authinfo():
 | 
			
		||||
	del __authinfos[threading.currentThread()]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class GlibTCPServer(SocketServer.TCPServer):
 | 
			
		||||
	"""GlibTCPServer
 | 
			
		||||
 | 
			
		||||
	Integrate socket accept into glib mainloop.
 | 
			
		||||
	"""
 | 
			
		||||
 | 
			
		||||
	allow_reuse_address = True
 | 
			
		||||
	request_queue_size = 20
 | 
			
		||||
 | 
			
		||||
	def __init__(self, server_address, RequestHandlerClass):
 | 
			
		||||
		SocketServer.TCPServer.__init__(self, server_address, RequestHandlerClass)
 | 
			
		||||
		self.socket.setblocking(0)  # Set nonblocking
 | 
			
		||||
 | 
			
		||||
		# Watch the listener socket for data
 | 
			
		||||
		gobject.io_add_watch(self.socket, gobject.IO_IN, self._handle_accept)
 | 
			
		||||
 | 
			
		||||
	def _handle_accept(self, source, condition):
 | 
			
		||||
		if not (condition & gobject.IO_IN):
 | 
			
		||||
			return True
 | 
			
		||||
		self.handle_request()
 | 
			
		||||
		return True
 | 
			
		||||
 | 
			
		||||
class GlibXMLRPCRequestHandler(SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
 | 
			
		||||
	""" GlibXMLRPCRequestHandler
 | 
			
		||||
	
 | 
			
		||||
	The stock SimpleXMLRPCRequestHandler and server don't allow any way to pass
 | 
			
		||||
	the client's address and/or SSL certificate into the function that actually
 | 
			
		||||
	_processes_ the request.  So we have to store it in a thread-indexed dict.
 | 
			
		||||
	"""
 | 
			
		||||
 | 
			
		||||
	def do_POST(self):
 | 
			
		||||
		_add_authinfo(self.client_address)
 | 
			
		||||
		try:
 | 
			
		||||
			SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.do_POST(self)
 | 
			
		||||
		except socket.timeout:
 | 
			
		||||
			pass
 | 
			
		||||
		except socket.error, e:
 | 
			
		||||
			print "Error (%s): socket error - '%s'" % (self.client_address, e)
 | 
			
		||||
		except:
 | 
			
		||||
			print "Error while processing POST:"
 | 
			
		||||
			traceback.print_exc()
 | 
			
		||||
		_del_authinfo()
 | 
			
		||||
 | 
			
		||||
class GlibXMLRPCServer(GlibTCPServer, SimpleXMLRPCServer.SimpleXMLRPCDispatcher):
 | 
			
		||||
	"""GlibXMLRPCServer
 | 
			
		||||
	
 | 
			
		||||
	Use nonblocking sockets and handle the accept via glib rather than
 | 
			
		||||
	blocking on accept().
 | 
			
		||||
	"""
 | 
			
		||||
 | 
			
		||||
	def __init__(self, addr, requestHandler=GlibXMLRPCRequestHandler, logRequests=1):
 | 
			
		||||
		self.logRequests = logRequests
 | 
			
		||||
 | 
			
		||||
		SimpleXMLRPCServer.SimpleXMLRPCDispatcher.__init__(self)
 | 
			
		||||
		GlibTCPServer.__init__(self, addr, requestHandler)
 | 
			
		||||
 | 
			
		||||
	def _marshaled_dispatch(self, data, dispatch_method = None):
 | 
			
		||||
		"""Dispatches an XML-RPC method from marshalled (XML) data.
 | 
			
		||||
 | 
			
		||||
		XML-RPC methods are dispatched from the marshalled (XML) data
 | 
			
		||||
		using the _dispatch method and the result is returned as
 | 
			
		||||
		marshalled data. For backwards compatibility, a dispatch
 | 
			
		||||
		function can be provided as an argument (see comment in
 | 
			
		||||
		SimpleXMLRPCRequestHandler.do_POST) but overriding the
 | 
			
		||||
		existing method through subclassing is the prefered means
 | 
			
		||||
		of changing method dispatch behavior.
 | 
			
		||||
		"""
 | 
			
		||||
 | 
			
		||||
		params, method = xmlrpclib.loads(data)
 | 
			
		||||
 | 
			
		||||
		# generate response
 | 
			
		||||
		try:
 | 
			
		||||
			if dispatch_method is not None:
 | 
			
		||||
				response = dispatch_method(method, params)
 | 
			
		||||
			else:
 | 
			
		||||
				response = self._dispatch(method, params)
 | 
			
		||||
			# wrap response in a singleton tuple
 | 
			
		||||
			response = (response,)
 | 
			
		||||
			response = xmlrpclib.dumps(response, methodresponse=1)
 | 
			
		||||
		except xmlrpclib.Fault, fault:
 | 
			
		||||
			response = xmlrpclib.dumps(fault)
 | 
			
		||||
		except:
 | 
			
		||||
			print "Exception while processing request:"
 | 
			
		||||
			traceback.print_exc()
 | 
			
		||||
 | 
			
		||||
			# report exception back to server
 | 
			
		||||
			response = xmlrpclib.dumps(
 | 
			
		||||
				xmlrpclib.Fault(1, "%s:%s" % (sys.exc_type, sys.exc_value))
 | 
			
		||||
				)
 | 
			
		||||
 | 
			
		||||
		return response
 | 
			
		||||
 | 
			
		||||
class GroupServer(object):
 | 
			
		||||
 | 
			
		||||
	_MAX_MSG_SIZE = 500
 | 
			
		||||
 | 
			
		||||
	def __init__(self, address, port, data_cb):
 | 
			
		||||
		self._address = address
 | 
			
		||||
		self._port = port
 | 
			
		||||
		self._data_cb = data_cb
 | 
			
		||||
 | 
			
		||||
		self._setup_listener()
 | 
			
		||||
 | 
			
		||||
	def _setup_listener(self):
 | 
			
		||||
		# Listener socket
 | 
			
		||||
		self._listen_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
 | 
			
		||||
 | 
			
		||||
		# Set some options to make it multicast-friendly
 | 
			
		||||
		self._listen_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
 | 
			
		||||
		try:
 | 
			
		||||
			self._listen_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
 | 
			
		||||
		except:
 | 
			
		||||
			pass
 | 
			
		||||
		self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_TTL, 20)
 | 
			
		||||
		self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_LOOP, 1)
 | 
			
		||||
 | 
			
		||||
	def start(self):
 | 
			
		||||
		# Set some more multicast options
 | 
			
		||||
		self._listen_sock.bind(('', self._port))
 | 
			
		||||
		self._listen_sock.settimeout(2)
 | 
			
		||||
		intf = socket.gethostbyname(socket.gethostname())
 | 
			
		||||
		self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_IF, socket.inet_aton(intf) + socket.inet_aton('0.0.0.0'))
 | 
			
		||||
		self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_ADD_MEMBERSHIP, socket.inet_aton(self._address) + socket.inet_aton('0.0.0.0'))
 | 
			
		||||
 | 
			
		||||
		# Watch the listener socket for data
 | 
			
		||||
		gobject.io_add_watch(self._listen_sock, gobject.IO_IN, self._handle_incoming_data)
 | 
			
		||||
 | 
			
		||||
	def _handle_incoming_data(self, source, condition):
 | 
			
		||||
		if not (condition & gobject.IO_IN):
 | 
			
		||||
			return True
 | 
			
		||||
		msg = {}
 | 
			
		||||
		msg['data'], (msg['addr'], msg['port']) = source.recvfrom(self._MAX_MSG_SIZE)
 | 
			
		||||
		if self._data_cb:
 | 
			
		||||
			self._data_cb(msg)
 | 
			
		||||
		return True
 | 
			
		||||
 | 
			
		||||
class GroupClient(object):
 | 
			
		||||
 | 
			
		||||
	_MAX_MSG_SIZE = 500
 | 
			
		||||
 | 
			
		||||
	def __init__(self, address, port):
 | 
			
		||||
		self._address = address
 | 
			
		||||
		self._port = port
 | 
			
		||||
 | 
			
		||||
		self._send_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
 | 
			
		||||
		# Make the socket multicast-aware, and set TTL.
 | 
			
		||||
		self._send_sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 20) # Change TTL (=20) to suit
 | 
			
		||||
 | 
			
		||||
	def send_msg(self, data):
 | 
			
		||||
		self._send_sock.sendto(data, (self._address, self._port))
 | 
			
		||||
@ -1,92 +0,0 @@
 | 
			
		||||
# -*- tab-width: 4; indent-tabs-mode: t -*- 
 | 
			
		||||
 | 
			
		||||
import avahi, dbus, dbus.glib
 | 
			
		||||
 | 
			
		||||
ACTION_SERVICE_NEW = 'new'
 | 
			
		||||
ACTION_SERVICE_REMOVED = 'removed'
 | 
			
		||||
 | 
			
		||||
class PresenceDiscovery(object):
 | 
			
		||||
	def __init__(self):
 | 
			
		||||
		self.bus = dbus.SystemBus()
 | 
			
		||||
		self.server = dbus.Interface(self.bus.get_object(avahi.DBUS_NAME, avahi.DBUS_PATH_SERVER), avahi.DBUS_INTERFACE_SERVER)
 | 
			
		||||
		self._service_browsers = {}
 | 
			
		||||
		self._service_type_browsers = {}
 | 
			
		||||
		self._service_listeners = []
 | 
			
		||||
 | 
			
		||||
	def add_service_listener(self, listener):
 | 
			
		||||
		self._service_listeners.append(listener)
 | 
			
		||||
 | 
			
		||||
	def start(self):
 | 
			
		||||
		# Always browse .local
 | 
			
		||||
		self.browse_domain(avahi.IF_UNSPEC, avahi.PROTO_UNSPEC, "local")
 | 
			
		||||
		db = dbus.Interface(self.bus.get_object(avahi.DBUS_NAME, self.server.DomainBrowserNew(avahi.IF_UNSPEC, avahi.PROTO_UNSPEC, "", avahi.DOMAIN_BROWSER_BROWSE, dbus.UInt32(0))), avahi.DBUS_INTERFACE_DOMAIN_BROWSER)
 | 
			
		||||
		db.connect_to_signal('ItemNew', self.new_domain)	
 | 
			
		||||
 | 
			
		||||
	def _error_handler(self, err):
 | 
			
		||||
		print "Error resolving: %s" % err
 | 
			
		||||
 | 
			
		||||
	def resolve_service(self, interface, protocol, name, stype, domain, reply_handler, error_handler=None):
 | 
			
		||||
		if not error_handler:
 | 
			
		||||
			error_handler = self._error_handler
 | 
			
		||||
		self.server.ResolveService(int(interface), int(protocol), name, stype, domain, avahi.PROTO_UNSPEC, dbus.UInt32(0), reply_handler=reply_handler, error_handler=error_handler)
 | 
			
		||||
 | 
			
		||||
	def new_service(self, interface, protocol, name, stype, domain, flags):
 | 
			
		||||
#		print "Found service '%s' (%d) of type '%s' in domain '%s' on %i.%i." % (name, flags, stype, domain, interface, protocol)
 | 
			
		||||
		for listener in self._service_listeners:
 | 
			
		||||
			listener(ACTION_SERVICE_NEW, interface, protocol, name, stype, domain, flags)
 | 
			
		||||
 | 
			
		||||
	def remove_service(self, interface, protocol, name, stype, domain, flags):
 | 
			
		||||
#		print "Service '%s' of type '%s' in domain '%s' on %i.%i disappeared." % (name, stype, domain, interface, protocol)
 | 
			
		||||
		for listener in self._service_listeners:
 | 
			
		||||
			listener(ACTION_SERVICE_REMOVED, interface, protocol, name, stype, domain, flags)
 | 
			
		||||
 
 | 
			
		||||
	def new_service_type(self, interface, protocol, stype, domain, flags):
 | 
			
		||||
		# Are we already browsing this domain for this type? 
 | 
			
		||||
		if self._service_browsers.has_key((interface, protocol, stype, domain)):
 | 
			
		||||
			return
 | 
			
		||||
 | 
			
		||||
#		print "Browsing for services of type '%s' in domain '%s' on %i.%i ..." % (stype, domain, interface, protocol)
 | 
			
		||||
 | 
			
		||||
		b = dbus.Interface(self.bus.get_object(avahi.DBUS_NAME, self.server.ServiceBrowserNew(interface, protocol, stype, domain, dbus.UInt32(0))),  avahi.DBUS_INTERFACE_SERVICE_BROWSER)
 | 
			
		||||
		b.connect_to_signal('ItemNew', self.new_service)
 | 
			
		||||
		b.connect_to_signal('ItemRemove', self.remove_service)
 | 
			
		||||
 | 
			
		||||
		self._service_browsers[(interface, protocol, stype, domain)] = b
 | 
			
		||||
 | 
			
		||||
	def browse_domain(self, interface, protocol, domain):
 | 
			
		||||
		# Are we already browsing this domain?
 | 
			
		||||
		if self._service_type_browsers.has_key((interface, protocol, domain)):
 | 
			
		||||
			return
 | 
			
		||||
 | 
			
		||||
#		print "Browsing domain '%s' on %i.%i ..." % (domain, interface, protocol)
 | 
			
		||||
    
 | 
			
		||||
		b = dbus.Interface(self.bus.get_object(avahi.DBUS_NAME, self.server.ServiceTypeBrowserNew(interface, protocol, domain, dbus.UInt32(0))),  avahi.DBUS_INTERFACE_SERVICE_TYPE_BROWSER)
 | 
			
		||||
		b.connect_to_signal('ItemNew', self.new_service_type)
 | 
			
		||||
 | 
			
		||||
		self._service_type_browsers[(interface, protocol, domain)] = b
 | 
			
		||||
 | 
			
		||||
	def new_domain(self,interface, protocol, domain, flags):
 | 
			
		||||
		if domain != "local":
 | 
			
		||||
			return
 | 
			
		||||
		self.browse_domain(interface, protocol, domain)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class PresenceAnnounce(object):
 | 
			
		||||
	def __init__(self):
 | 
			
		||||
		self.bus = dbus.SystemBus()
 | 
			
		||||
		self.server = dbus.Interface(self.bus.get_object(avahi.DBUS_NAME, avahi.DBUS_PATH_SERVER), avahi.DBUS_INTERFACE_SERVER)
 | 
			
		||||
		self._hostname = None
 | 
			
		||||
 | 
			
		||||
	def register_service(self, rs_name, rs_port, rs_service, **kwargs):
 | 
			
		||||
		g = dbus.Interface(self.bus.get_object(avahi.DBUS_NAME, self.server.EntryGroupNew()), avahi.DBUS_INTERFACE_ENTRY_GROUP)
 | 
			
		||||
		if rs_name is None:
 | 
			
		||||
			if self._hostname is None:
 | 
			
		||||
				self._hostname = "%s:%s" % (self.server.GetHostName(), rs_port)
 | 
			
		||||
				rs_name = self._hostname
 | 
			
		||||
 | 
			
		||||
		info = ["%s=%s" % (k,v) for k,v in kwargs.items()]
 | 
			
		||||
		g.AddService(avahi.IF_UNSPEC, avahi.PROTO_UNSPEC, 0, rs_name, rs_service,
 | 
			
		||||
				"", "", # domain, host (let the system figure it out)
 | 
			
		||||
				dbus.UInt16(rs_port), info,)
 | 
			
		||||
		g.Commit()
 | 
			
		||||
		return g
 | 
			
		||||
@ -1,9 +1,3 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
 | 
			
		||||
export PYTHONPATH=`pwd`/p2p
 | 
			
		||||
 | 
			
		||||
# for activity.py
 | 
			
		||||
export PYTHONPATH=$PYTHONPATH:`pwd`/shell/src/
 | 
			
		||||
 | 
			
		||||
# for sugar_globals.py
 | 
			
		||||
export PYTHONPATH=$PYTHONPATH:`pwd`/
 | 
			
		||||
export PYTHONPATH=`pwd`
 | 
			
		||||
 | 
			
		||||
@ -1,9 +1,3 @@
 | 
			
		||||
#!/bin/tcsh
 | 
			
		||||
 | 
			
		||||
setenv PYTHONPATH `pwd`/p2p/
 | 
			
		||||
 | 
			
		||||
# for activity.py
 | 
			
		||||
setenv PYTHONPATH "$PYTHONPATH":`pwd`/shell/src/
 | 
			
		||||
 | 
			
		||||
# for sugar_globals.py
 | 
			
		||||
setenv PYTHONPATH "$PYTHONPATH":`pwd`/
 | 
			
		||||
setenv PYTHONPATH `pwd`
 | 
			
		||||
 | 
			
		||||
@ -1 +0,0 @@
 | 
			
		||||
SUBDIRS = src
 | 
			
		||||
@ -1,82 +0,0 @@
 | 
			
		||||
#!/usr/bin/python
 | 
			
		||||
# -*- tab-width: 4; indent-tabs-mode: t -*- 
 | 
			
		||||
 | 
			
		||||
import string
 | 
			
		||||
 | 
			
		||||
import gc
 | 
			
		||||
import dbus
 | 
			
		||||
import dbus.service
 | 
			
		||||
import dbus.glib
 | 
			
		||||
import gobject
 | 
			
		||||
import pygtk
 | 
			
		||||
pygtk.require('2.0')
 | 
			
		||||
import gtk,sys
 | 
			
		||||
 | 
			
		||||
import activity
 | 
			
		||||
 | 
			
		||||
def my_exit():
 | 
			
		||||
	sys.exit(0)
 | 
			
		||||
 | 
			
		||||
def deferred_exit():
 | 
			
		||||
	gobject.timeout_add(0, my_exit)
 | 
			
		||||
 | 
			
		||||
################################################################################
 | 
			
		||||
 | 
			
		||||
class ExampleActivity(activity.Activity):
 | 
			
		||||
 | 
			
		||||
	def __init__(self, name):
 | 
			
		||||
		self.name = name
 | 
			
		||||
 | 
			
		||||
	def entry_changed(self, entry):
 | 
			
		||||
		self.activity_set_tab_text(entry.get_text())
 | 
			
		||||
	
 | 
			
		||||
	def activity_on_connected_to_shell(self):
 | 
			
		||||
		print "act %d: in activity_on_connected_to_shell"%self.activity_get_id()
 | 
			
		||||
 | 
			
		||||
		self.activity_set_tab_text(self.name)
 | 
			
		||||
 | 
			
		||||
		plug = self.activity_get_gtk_plug()
 | 
			
		||||
		self.entry = gtk.Entry()
 | 
			
		||||
		self.entry.set_text(self.name)
 | 
			
		||||
		self.entry.connect("changed", self.entry_changed)
 | 
			
		||||
		plug.add(self.entry)
 | 
			
		||||
		plug.show_all()
 | 
			
		||||
 | 
			
		||||
	    icon_theme = gtk.icon_theme_get_default()
 | 
			
		||||
		pixbuf = icon_theme.load_icon("gnome-dev-cdrom", gtk.ICON_SIZE_MENU, gtk.ICON_LOOKUP_USE_BUILTIN)
 | 
			
		||||
		self.activity_set_icon(pixbuf)
 | 
			
		||||
		self.activity_show_icon(True)
 | 
			
		||||
 | 
			
		||||
	def activity_on_disconnected_from_shell(self):
 | 
			
		||||
		print "act %d: in activity_on_disconnected_from_shell"%self.activity_get_id()
 | 
			
		||||
		print "act %d: Shell disappeared..."%self.activity_get_id()
 | 
			
		||||
 | 
			
		||||
		gc.collect()
 | 
			
		||||
 | 
			
		||||
	def activity_on_close_from_user(self):
 | 
			
		||||
		print "act %d: in activity_on_close_from_user"%self.activity_get_id()
 | 
			
		||||
		self.activity_shutdown()
 | 
			
		||||
 | 
			
		||||
	def activity_on_lost_focus(self):
 | 
			
		||||
		print "act %d: in activity_on_lost_focus"%self.activity_get_id()
 | 
			
		||||
 | 
			
		||||
	def activity_on_got_focus(self):
 | 
			
		||||
		print "act %d: in activity_on_got_focus"%self.activity_get_id()
 | 
			
		||||
 | 
			
		||||
	def __del__(self):
 | 
			
		||||
		print "in __del__ for ExampleActivity"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if len(sys.argv) != 2:
 | 
			
		||||
	print "usage: example-activity.py <name_of_activity>"
 | 
			
		||||
	sys.exit(1)
 | 
			
		||||
 | 
			
		||||
gc.set_debug(gc.DEBUG_LEAK)
 | 
			
		||||
 | 
			
		||||
example_activity = ExampleActivity(sys.argv[1])
 | 
			
		||||
example_activity.activity_connect_to_shell()
 | 
			
		||||
example_activity = None
 | 
			
		||||
 | 
			
		||||
gtk.main()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,20 +0,0 @@
 | 
			
		||||
sugardir = $(pythondir)/sugar
 | 
			
		||||
sugar_PYTHON =		\
 | 
			
		||||
	activity.py	\
 | 
			
		||||
	shell.py
 | 
			
		||||
 | 
			
		||||
# Dbus service file
 | 
			
		||||
servicedir = $(datadir)/dbus-1/services
 | 
			
		||||
service_in_files = com.redhat.Sugar.Shell.service.in
 | 
			
		||||
service_DATA = $(service_in_files:.service.in=.service)
 | 
			
		||||
 
 | 
			
		||||
# Rule to make the service file with bindir expanded
 | 
			
		||||
$(service_DATA): $(service_in_files) Makefile
 | 
			
		||||
	@sed -e "s|\@bindir\@|$(bindir)|" $< > $@
 | 
			
		||||
 | 
			
		||||
EXTRA_DIST =			\
 | 
			
		||||
	$(service_in_files)	\
 | 
			
		||||
	$(service_DATA)
 | 
			
		||||
 | 
			
		||||
DISTCLEANFILES =		\
 | 
			
		||||
	$(service_DATA)
 | 
			
		||||
@ -1,178 +0,0 @@
 | 
			
		||||
# -*- tab-width: 4; indent-tabs-mode: t -*- 
 | 
			
		||||
 | 
			
		||||
import string
 | 
			
		||||
 | 
			
		||||
import gc
 | 
			
		||||
import dbus
 | 
			
		||||
import dbus.service
 | 
			
		||||
import dbus.glib
 | 
			
		||||
import gobject
 | 
			
		||||
import pygtk
 | 
			
		||||
pygtk.require('2.0')
 | 
			
		||||
import gtk,sys
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Activity(dbus.service.Object):
 | 
			
		||||
	""" Base Sugar activity object from which all other Activities should inherit """
 | 
			
		||||
 | 
			
		||||
	def __init__(self):
 | 
			
		||||
		pass
 | 
			
		||||
 | 
			
		||||
	def name_owner_changed(self, service_name, old_service_name, new_service_name):
 | 
			
		||||
		#print "in name_owner_changed: svc=%s oldsvc=%s newsvc=%s"%(service_name, old_service_name, new_service_name)
 | 
			
		||||
		if service_name == "com.redhat.Sugar.Shell" and new_service_name == "":
 | 
			
		||||
			self.activity_on_disconnected_from_shell()
 | 
			
		||||
		#elif service_name == "com.redhat.Sugar.Shell" and old_service_name == "":
 | 
			
		||||
		#	self.activity_on_shell_reappeared()
 | 
			
		||||
 | 
			
		||||
	def activity_connect_to_shell(self):
 | 
			
		||||
		self.__bus = dbus.SessionBus()
 | 
			
		||||
 | 
			
		||||
		self.__bus.add_signal_receiver(self.name_owner_changed, dbus_interface = "org.freedesktop.DBus", signal_name = "NameOwnerChanged")
 | 
			
		||||
 | 
			
		||||
		self.__activity_container_object = self.__bus.get_object("com.redhat.Sugar.Shell", \
 | 
			
		||||
															   "/com/redhat/Sugar/Shell/ActivityContainer")
 | 
			
		||||
		self.__activity_container = dbus.Interface(self.__activity_container_object, \
 | 
			
		||||
												   "com.redhat.Sugar.Shell.ActivityContainer")
 | 
			
		||||
 | 
			
		||||
		self.__activity_id = self.__activity_container.add_activity("")
 | 
			
		||||
		self.__object_path = "/com/redhat/Sugar/Shell/Activities/%d"%self.__activity_id
 | 
			
		||||
 | 
			
		||||
		print "object_path = %s"%self.__object_path
 | 
			
		||||
 | 
			
		||||
		self.__activity_object = dbus.Interface(self.__bus.get_object("com.redhat.Sugar.Shell", self.__object_path), \
 | 
			
		||||
											  "com.redhat.Sugar.Shell.ActivityHost")
 | 
			
		||||
		self.__window_id = self.__activity_object.get_host_xembed_id()
 | 
			
		||||
 | 
			
		||||
		print "XEMBED window_id = %d"%self.__window_id
 | 
			
		||||
 | 
			
		||||
		self.__plug = gtk.Plug(self.__window_id)
 | 
			
		||||
 | 
			
		||||
		# Now let the Activity register a peer service so the Shell can poke it
 | 
			
		||||
		self.__peer_service_name = "com.redhat.Sugar.Activity%d"%self.__activity_id
 | 
			
		||||
		self.__peer_object_name = "/com/redhat/Sugar/Activity/%d"%self.__activity_id
 | 
			
		||||
		self.__service = dbus.service.BusName(self.__peer_service_name, bus=self.__bus)
 | 
			
		||||
		dbus.service.Object.__init__(self, self.__service, self.__peer_object_name)
 | 
			
		||||
 | 
			
		||||
		self.__activity_object.set_peer_service_name(self.__peer_service_name, self.__peer_object_name)
 | 
			
		||||
 | 
			
		||||
		self.activity_on_connected_to_shell()
 | 
			
		||||
 | 
			
		||||
	def activity_get_gtk_plug(self):
 | 
			
		||||
		return self.__plug
 | 
			
		||||
 | 
			
		||||
	def activity_set_ellipsize_tab(self, ellipsize):
 | 
			
		||||
		self.__activity_object.set_ellipsize_tab(ellipsize)
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method("com.redhat.Sugar.Activity", \
 | 
			
		||||
						 in_signature="", \
 | 
			
		||||
						 out_signature="")
 | 
			
		||||
 | 
			
		||||
	def activity_set_can_close(self, can_close):
 | 
			
		||||
		self.__activity_object.set_can_close(can_close)
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method("com.redhat.Sugar.Activity", \
 | 
			
		||||
						 in_signature="", \
 | 
			
		||||
						 out_signature="")
 | 
			
		||||
 | 
			
		||||
	def activity_show_icon(self, show_icon):
 | 
			
		||||
		self.__activity_object.set_tab_show_icon(show_icon)
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method("com.redhat.Sugar.Activity", \
 | 
			
		||||
						 in_signature="", \
 | 
			
		||||
						 out_signature="")
 | 
			
		||||
 | 
			
		||||
	def activity_set_icon(self, pixbuf):
 | 
			
		||||
		pixarray = []
 | 
			
		||||
		pixstr = pixbuf.get_pixels();
 | 
			
		||||
		for c in pixstr:
 | 
			
		||||
				pixarray.append(c)
 | 
			
		||||
		self.__activity_object.set_tab_icon(pixarray, \
 | 
			
		||||
											pixbuf.get_colorspace(), \
 | 
			
		||||
											pixbuf.get_has_alpha(),  \
 | 
			
		||||
											pixbuf.get_bits_per_sample(), \
 | 
			
		||||
											pixbuf.get_width(), \
 | 
			
		||||
											pixbuf.get_height(), \
 | 
			
		||||
											pixbuf.get_rowstride())
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method("com.redhat.Sugar.Activity", \
 | 
			
		||||
						 in_signature="", \
 | 
			
		||||
						 out_signature="")
 | 
			
		||||
						 
 | 
			
		||||
	def activity_set_tab_text(self, text):
 | 
			
		||||
		self.__activity_object.set_tab_text(text)
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method("com.redhat.Sugar.Activity", \
 | 
			
		||||
						 in_signature="", \
 | 
			
		||||
						 out_signature="")
 | 
			
		||||
						 
 | 
			
		||||
	def activity_set_tab_icon_name(self, icon_name):
 | 
			
		||||
		icon_theme = gtk.icon_theme_get_default()
 | 
			
		||||
		icon_info = icon_theme.lookup_icon(icon_name, gtk.ICON_SIZE_MENU, 0)
 | 
			
		||||
		pixbuf = icon_info.load_icon()
 | 
			
		||||
		scaled_pixbuf = pixbuf.scale_simple(16, 16, gtk.gdk.INTERP_BILINEAR)
 | 
			
		||||
		self.activity_set_icon(scaled_pixbuf)
 | 
			
		||||
 | 
			
		||||
	def lost_focus(self):
 | 
			
		||||
		self.activity_on_lost_focus()
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method("com.redhat.Sugar.Activity", \
 | 
			
		||||
						 in_signature="", \
 | 
			
		||||
						 out_signature="")
 | 
			
		||||
	def got_focus(self):
 | 
			
		||||
		self.activity_on_got_focus()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method("com.redhat.Sugar.Activity", \
 | 
			
		||||
						 in_signature="", \
 | 
			
		||||
						 out_signature="")
 | 
			
		||||
	def close_from_user(self):
 | 
			
		||||
		self.activity_on_close_from_user()
 | 
			
		||||
 | 
			
		||||
	def activity_get_id(self):
 | 
			
		||||
		return self.__activity_id
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	def __shutdown_reply_cb(self):
 | 
			
		||||
		print "in __reply_cb"
 | 
			
		||||
 | 
			
		||||
		self.__plug.destroy()
 | 
			
		||||
		self.__plug = None
 | 
			
		||||
 | 
			
		||||
		self.__bus = None
 | 
			
		||||
		self.__activity_container_object = None
 | 
			
		||||
		self.__activity_container = None
 | 
			
		||||
		self.__activity_object = None
 | 
			
		||||
		self.__service = None
 | 
			
		||||
 | 
			
		||||
		self.__bus.remove_signal_receiver(self.name_owner_changed, dbus_interface = "org.freedesktop.DBus", signal_name = "NameOwnerChanged")
 | 
			
		||||
 | 
			
		||||
		self.activity_on_disconnected_from_shell()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		del self
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	def __shutdown_error_cb(self, error):
 | 
			
		||||
		print "in __error_cb"
 | 
			
		||||
 | 
			
		||||
	def activity_shutdown(self):
 | 
			
		||||
		self.__activity_object.shutdown(reply_handler = self.__shutdown_reply_cb, error_handler = self.__shutdown_error_cb)
 | 
			
		||||
 | 
			
		||||
	# pure virtual methods
 | 
			
		||||
 | 
			
		||||
	def activity_on_connected_to_shell(self):
 | 
			
		||||
		print "act %d: you need to override activity_on_connected_to_shell"%self.activity_get_id()
 | 
			
		||||
 | 
			
		||||
	def activity_on_disconnected_from_shell(self):
 | 
			
		||||
		print "act %d: you need to override activity_on_disconnected_from_shell"%self.activity_get_id()
 | 
			
		||||
 | 
			
		||||
	def activity_on_close_from_user(self):
 | 
			
		||||
		print "act %d: you need to override activity_on_close_from_user"%self.activity_get_id()
 | 
			
		||||
 | 
			
		||||
	def activity_on_lost_focus(self):
 | 
			
		||||
		print "act %d: you need to override activity_on_lost_focus"%self.activity_get_id()
 | 
			
		||||
 | 
			
		||||
	def activity_on_got_focus(self):
 | 
			
		||||
		print "act %d: you need to override activity_on_got_focus"%self.activity_get_id()
 | 
			
		||||
@ -1,3 +0,0 @@
 | 
			
		||||
[D-BUS Service]
 | 
			
		||||
Name=com.redhat.Sugar.Shell
 | 
			
		||||
Exec=@bindir@/sugar shell
 | 
			
		||||
@ -1,305 +0,0 @@
 | 
			
		||||
#!/usr/bin/python
 | 
			
		||||
# -*- tab-width: 4; indent-tabs-mode: t -*- 
 | 
			
		||||
 | 
			
		||||
import string
 | 
			
		||||
 | 
			
		||||
import dbus
 | 
			
		||||
import dbus.service
 | 
			
		||||
import dbus.glib
 | 
			
		||||
import gobject
 | 
			
		||||
import pygtk
 | 
			
		||||
pygtk.require('2.0')
 | 
			
		||||
import gtk
 | 
			
		||||
import pango
 | 
			
		||||
 | 
			
		||||
activity_counter = 0
 | 
			
		||||
 | 
			
		||||
class ActivityHost(dbus.service.Object):
 | 
			
		||||
 | 
			
		||||
	def __init__(self, activity_container, activity_name):
 | 
			
		||||
		global activity_counter
 | 
			
		||||
 | 
			
		||||
		self.activity_name = activity_name
 | 
			
		||||
		self.ellipsize_tab = False
 | 
			
		||||
 | 
			
		||||
		self.activity_container = activity_container
 | 
			
		||||
		
 | 
			
		||||
		self.activity_id = activity_counter
 | 
			
		||||
		activity_counter += 1
 | 
			
		||||
		
 | 
			
		||||
		self.dbus_object_name = "/com/redhat/Sugar/Shell/Activities/%d"%self.activity_id
 | 
			
		||||
		#print "object name = %s"%self.dbus_object_name
 | 
			
		||||
		
 | 
			
		||||
		dbus.service.Object.__init__(self, activity_container.service, self.dbus_object_name)
 | 
			
		||||
		self.socket = gtk.Socket()
 | 
			
		||||
		self.socket.set_data("sugar-activity", self)
 | 
			
		||||
		self.socket.show()
 | 
			
		||||
		
 | 
			
		||||
		hbox = gtk.HBox(False, 4);
 | 
			
		||||
 | 
			
		||||
		self.tab_activity_image = gtk.Image()
 | 
			
		||||
		self.tab_activity_image.set_from_stock(gtk.STOCK_CONVERT, gtk.ICON_SIZE_MENU)
 | 
			
		||||
		hbox.pack_start(self.tab_activity_image)
 | 
			
		||||
		#self.tab_activity_image.show()		
 | 
			
		||||
		
 | 
			
		||||
		self.label_hbox = gtk.HBox(False, 4);
 | 
			
		||||
		self.label_hbox.connect("style-set", self.__tab_label_style_set_cb)
 | 
			
		||||
		hbox.pack_start(self.label_hbox)
 | 
			
		||||
 | 
			
		||||
		self.tab_label = gtk.Label(self.activity_name)
 | 
			
		||||
		self.tab_label.set_single_line_mode(True)
 | 
			
		||||
		self.tab_label.set_alignment(0.0, 0.5)
 | 
			
		||||
		self.tab_label.set_padding(0, 0)
 | 
			
		||||
		self.tab_label.show()
 | 
			
		||||
		
 | 
			
		||||
		close_image = gtk.Image()
 | 
			
		||||
		close_image.set_from_stock (gtk.STOCK_CLOSE, gtk.ICON_SIZE_MENU)
 | 
			
		||||
		close_image.show()
 | 
			
		||||
		
 | 
			
		||||
		self.tab_close_button = gtk.Button()
 | 
			
		||||
		rcstyle = gtk.RcStyle();
 | 
			
		||||
		rcstyle.xthickness = rcstyle.ythickness = 0;
 | 
			
		||||
		self.tab_close_button.modify_style (rcstyle);
 | 
			
		||||
		self.tab_close_button.add(close_image)
 | 
			
		||||
		self.tab_close_button.set_relief(gtk.RELIEF_NONE)
 | 
			
		||||
		self.tab_close_button.set_focus_on_click(False)
 | 
			
		||||
		self.tab_close_button.connect("clicked", self.tab_close_button_clicked)
 | 
			
		||||
		
 | 
			
		||||
		self.label_hbox.pack_start(self.tab_label)
 | 
			
		||||
		self.label_hbox.pack_start(self.tab_close_button, False, False, 0)
 | 
			
		||||
		self.label_hbox.show()
 | 
			
		||||
		
 | 
			
		||||
		hbox.show()
 | 
			
		||||
		
 | 
			
		||||
		notebook = self.activity_container.notebook
 | 
			
		||||
		index = notebook.append_page(self.socket, hbox)
 | 
			
		||||
		notebook.set_current_page(index)
 | 
			
		||||
 | 
			
		||||
	def __close_button_clicked_reply_cb(self):
 | 
			
		||||
		pass
 | 
			
		||||
 | 
			
		||||
	def __close_button_clicked_error_cb(self, error):
 | 
			
		||||
		pass
 | 
			
		||||
		
 | 
			
		||||
	def tab_close_button_clicked(self, button):
 | 
			
		||||
		self.peer_service.close_from_user(reply_handler = self.__close_button_clicked_reply_cb, \
 | 
			
		||||
										  error_handler = self.__close_button_clicked_error_cb)
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method("com.redhat.Sugar.Shell.ActivityHost", \
 | 
			
		||||
							 in_signature="", \
 | 
			
		||||
							 out_signature="t")
 | 
			
		||||
	def get_host_xembed_id(self):
 | 
			
		||||
		window_id = self.socket.get_id()
 | 
			
		||||
		#print "window_id = %d"%window_id
 | 
			
		||||
		return window_id
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method("com.redhat.Sugar.Shell.ActivityHost", \
 | 
			
		||||
			 in_signature="ss", \
 | 
			
		||||
			 out_signature="")
 | 
			
		||||
	def set_peer_service_name(self, peer_service_name, peer_object_name):
 | 
			
		||||
		#print "peer_service_name = %s, peer_object_name = %s"%(peer_service_name, peer_object_name)
 | 
			
		||||
		self.__peer_service_name = peer_service_name
 | 
			
		||||
		self.__peer_object_name = peer_object_name
 | 
			
		||||
		self.peer_service = dbus.Interface(self.activity_container.bus.get_object( \
 | 
			
		||||
				self.__peer_service_name, self.__peer_object_name), \
 | 
			
		||||
										   "com.redhat.Sugar.Activity")
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method("com.redhat.Sugar.Shell.ActivityHost", \
 | 
			
		||||
			 in_signature="b", \
 | 
			
		||||
			 out_signature="")
 | 
			
		||||
	def set_ellipsize_tab(self, ellipsize):
 | 
			
		||||
		self.ellipsize_tab = True
 | 
			
		||||
		self.update_tab_size()
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method("com.redhat.Sugar.Shell.ActivityHost", \
 | 
			
		||||
			 in_signature="b", \
 | 
			
		||||
			 out_signature="")
 | 
			
		||||
	def set_can_close(self, can_close):
 | 
			
		||||
		if can_close:
 | 
			
		||||
			self.tab_close_button.show()
 | 
			
		||||
		else:
 | 
			
		||||
			self.tab_close_button.hide()
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method("com.redhat.Sugar.Shell.ActivityHost", \
 | 
			
		||||
			 in_signature="b", \
 | 
			
		||||
			 out_signature="")
 | 
			
		||||
	def set_tab_show_icon(self, show_icon):
 | 
			
		||||
		if show_icon:
 | 
			
		||||
			self.tab_activity_image.show()
 | 
			
		||||
		else:
 | 
			
		||||
			self.tab_activity_image.hide()
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method("com.redhat.Sugar.Shell.ActivityHost", \
 | 
			
		||||
			 in_signature="s", \
 | 
			
		||||
			 out_signature="")
 | 
			
		||||
	def set_tab_text(self, text):
 | 
			
		||||
		self.tab_label.set_text(text)
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method("com.redhat.Sugar.Shell.ActivityHost", \
 | 
			
		||||
			 in_signature="ayibiiii", \
 | 
			
		||||
			 out_signature="")
 | 
			
		||||
	def set_tab_icon(self, data, colorspace, has_alpha, bits_per_sample, width, height, rowstride):
 | 
			
		||||
	    #print "width=%d, height=%d"%(width, height)
 | 
			
		||||
		#print "  data = ", data
 | 
			
		||||
		pixstr = ""
 | 
			
		||||
		for c in data:
 | 
			
		||||
		    pixstr += chr(c)
 | 
			
		||||
 | 
			
		||||
		pixbuf = gtk.gdk.pixbuf_new_from_data(pixstr, colorspace, has_alpha, bits_per_sample, width, height, rowstride)
 | 
			
		||||
		#print pixbuf
 | 
			
		||||
		self.tab_activity_image.set_from_pixbuf(pixbuf)
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method("com.redhat.Sugar.Shell.ActivityHost", \
 | 
			
		||||
						 in_signature="", \
 | 
			
		||||
						 out_signature="")
 | 
			
		||||
	def shutdown(self):
 | 
			
		||||
		#print "shutdown"
 | 
			
		||||
		for owner, activity in self.activity_container.activities[:]:
 | 
			
		||||
			if activity == self:
 | 
			
		||||
				self.activity_container.activities.remove((owner, activity))
 | 
			
		||||
				
 | 
			
		||||
		for i in range(self.activity_container.notebook.get_n_pages()):
 | 
			
		||||
			child = self.activity_container.notebook.get_nth_page(i)
 | 
			
		||||
			if child == self.socket:
 | 
			
		||||
				#print "found child"
 | 
			
		||||
				self.activity_container.notebook.remove_page(i)
 | 
			
		||||
				break
 | 
			
		||||
 | 
			
		||||
		del self
 | 
			
		||||
 | 
			
		||||
	def get_host_activity_id(self):
 | 
			
		||||
		return self.activity_id
 | 
			
		||||
 | 
			
		||||
	def get_object_path(self):
 | 
			
		||||
		return self.dbus_object_name
 | 
			
		||||
 | 
			
		||||
	def update_tab_size(self):
 | 
			
		||||
		if self.ellipsize_tab:
 | 
			
		||||
			self.tab_label.set_ellipsize(pango.ELLIPSIZE_END)
 | 
			
		||||
 | 
			
		||||
			context = self.label_hbox.get_pango_context()
 | 
			
		||||
			font_desc = self.label_hbox.style.font_desc
 | 
			
		||||
			metrics = context.get_metrics(font_desc, context.get_language())
 | 
			
		||||
			char_width = metrics.get_approximate_digit_width()
 | 
			
		||||
			[w, h] = self.__get_close_icon_size()
 | 
			
		||||
			tab_width = 15 * pango.PIXELS(char_width) + 2 * w
 | 
			
		||||
			self.label_hbox.set_size_request(tab_width, -1);
 | 
			
		||||
		else:
 | 
			
		||||
			self.tab_label.set_ellipsize(pango.ELLIPSIZE_NONE)
 | 
			
		||||
			self.label_hbox.set_size_request(-1, -1)
 | 
			
		||||
 | 
			
		||||
	def __get_close_icon_size(self):
 | 
			
		||||
		settings = self.label_hbox.get_settings()
 | 
			
		||||
		return gtk.icon_size_lookup_for_settings(settings, gtk.ICON_SIZE_MENU)
 | 
			
		||||
 | 
			
		||||
	def __tab_label_style_set_cb(self, widget, previous_style):
 | 
			
		||||
		[w, h] = self.__get_close_icon_size()
 | 
			
		||||
		self.tab_close_button.set_size_request (w + 5, h + 2)
 | 
			
		||||
		self.update_tab_size()
 | 
			
		||||
 | 
			
		||||
class ActivityContainer(dbus.service.Object):
 | 
			
		||||
 | 
			
		||||
	def __init__(self, service, bus):
 | 
			
		||||
 | 
			
		||||
		self.activities = []
 | 
			
		||||
 | 
			
		||||
		self.bus = bus
 | 
			
		||||
		self.service = service
 | 
			
		||||
 | 
			
		||||
		dbus.service.Object.__init__(self, self.service, "/com/redhat/Sugar/Shell/ActivityContainer")
 | 
			
		||||
		bus.add_signal_receiver(self.name_owner_changed, dbus_interface = "org.freedesktop.DBus", signal_name = "NameOwnerChanged")
 | 
			
		||||
 | 
			
		||||
		self.window = gtk.Window()
 | 
			
		||||
		self.window.set_title("OLPC Sugar")
 | 
			
		||||
		self.window.resize(640, 480)
 | 
			
		||||
		self.window.set_geometry_hints(min_width = 640, max_width = 640, min_height = 480, max_height = 480)
 | 
			
		||||
		self.notebook = gtk.Notebook()
 | 
			
		||||
 | 
			
		||||
		#tab_label = gtk.Label("My Laptop")
 | 
			
		||||
		#empty_label = gtk.Label("This activity could launch other activities / be a help page")
 | 
			
		||||
		#empty_label.show()
 | 
			
		||||
		#self.notebook.append_page(empty_label, tab_label)
 | 
			
		||||
 | 
			
		||||
		self.notebook.show()
 | 
			
		||||
		self.notebook.connect("switch-page", self.notebook_tab_changed)
 | 
			
		||||
		self.window.add(self.notebook)
 | 
			
		||||
		
 | 
			
		||||
		self.window.connect("destroy", lambda w: gtk.main_quit())
 | 
			
		||||
		self.window.show()
 | 
			
		||||
		
 | 
			
		||||
		self.current_activity = None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	def __focus_reply_cb(self):
 | 
			
		||||
		pass
 | 
			
		||||
 | 
			
		||||
	def __focus_error_cb(self, error):
 | 
			
		||||
		pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	def notebook_tab_changed(self, notebook, page, page_number):
 | 
			
		||||
		#print "in notebook_tab_changed"
 | 
			
		||||
		#print notebook.get_nth_page(page_number)
 | 
			
		||||
		new_activity = notebook.get_nth_page(page_number).get_data("sugar-activity")
 | 
			
		||||
		#print " Current activity: ", self.current_activity
 | 
			
		||||
		#print " New activity:	 ", new_activity
 | 
			
		||||
 | 
			
		||||
		if self.current_activity != None:
 | 
			
		||||
			if self.has_activity(self.current_activity):
 | 
			
		||||
				self.current_activity.peer_service.lost_focus(reply_handler = self.__focus_reply_cb, error_handler = self.__focus_error_cb)
 | 
			
		||||
				
 | 
			
		||||
				self.current_activity = new_activity
 | 
			
		||||
 | 
			
		||||
		if self.current_activity != None:
 | 
			
		||||
			if self.has_activity(self.current_activity):
 | 
			
		||||
				self.current_activity.peer_service.got_focus(reply_handler = self.__focus_reply_cb, error_handler = self.__focus_error_cb)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	def has_activity(self, activity_to_check_for):
 | 
			
		||||
		for owner, activity in self.activities[:]:
 | 
			
		||||
			if activity_to_check_for == activity:
 | 
			
		||||
				return True
 | 
			
		||||
		return False
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
	def name_owner_changed(self, service_name, old_service_name, new_service_name):
 | 
			
		||||
		#print "in name_owner_changed: svc=%s oldsvc=%s newsvc=%s"%(service_name, old_service_name, new_service_name)
 | 
			
		||||
		for owner, activity in self.activities[:]:
 | 
			
		||||
			if owner == old_service_name:
 | 
			
		||||
				self.activities.remove((owner, activity))
 | 
			
		||||
		#self.__print_activities()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method("com.redhat.Sugar.Shell.ActivityContainer", \
 | 
			
		||||
			 in_signature="s", \
 | 
			
		||||
			 out_signature="i", \
 | 
			
		||||
			 sender_keyword="sender")
 | 
			
		||||
	def add_activity(self, activity_name, sender):
 | 
			
		||||
		#print "hello world, activity_name = '%s', sender = '%s'"%(activity_name, sender)
 | 
			
		||||
		activity = ActivityHost(self, activity_name)
 | 
			
		||||
		self.activities.append((sender, activity))
 | 
			
		||||
 | 
			
		||||
		#self.__print_activities()
 | 
			
		||||
		return activity.get_host_activity_id()
 | 
			
		||||
 | 
			
		||||
	def __print_activities(self):
 | 
			
		||||
		print "__print_activities: %d activities registered"%len(self.activities)
 | 
			
		||||
		i = 0
 | 
			
		||||
		for owner, activity in self.activities:
 | 
			
		||||
			print "  %d: owner=%s activity_object_name=%s"%(i, owner, activity.dbus_object_name)
 | 
			
		||||
			i += 1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def main():
 | 
			
		||||
	session_bus = dbus.SessionBus()
 | 
			
		||||
	service = dbus.service.BusName("com.redhat.Sugar.Shell", bus=session_bus)
 | 
			
		||||
 | 
			
		||||
	activityContainer = ActivityContainer(service, session_bus)
 | 
			
		||||
 | 
			
		||||
	try:
 | 
			
		||||
		gtk.main()
 | 
			
		||||
	except KeyboardInterrupt:
 | 
			
		||||
		pass
 | 
			
		||||
 | 
			
		||||
if __name__=="__main__":
 | 
			
		||||
		main()
 | 
			
		||||
							
								
								
									
										28
									
								
								sugar
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								sugar
									
									
									
									
									
								
							@ -1,28 +0,0 @@
 | 
			
		||||
#!/usr/bin/python
 | 
			
		||||
 | 
			
		||||
import sys
 | 
			
		||||
import os
 | 
			
		||||
 | 
			
		||||
if len(sys.argv) == 1:
 | 
			
		||||
	# FIXME Start a session
 | 
			
		||||
 | 
			
		||||
	# We are lucky and this
 | 
			
		||||
	# currently behave as we want.
 | 
			
		||||
	# The chat depends on the
 | 
			
		||||
	# web browser, so both activities
 | 
			
		||||
	# are spanned. But obviously we
 | 
			
		||||
	# need something better.
 | 
			
		||||
 | 
			
		||||
	import sugar.chat
 | 
			
		||||
	sugar.chat.main()
 | 
			
		||||
elif sys.argv[1] == 'shell':
 | 
			
		||||
	import sugar.shell
 | 
			
		||||
	sugar.shell.main()
 | 
			
		||||
elif sys.argv[1] == 'chat':
 | 
			
		||||
	import sugar.chat
 | 
			
		||||
	sugar.chat.main()
 | 
			
		||||
elif sys.argv[1] == 'browser':
 | 
			
		||||
	import sugar.browser
 | 
			
		||||
	sugar.browser.main()
 | 
			
		||||
else:
 | 
			
		||||
	print "Unknown activity"
 | 
			
		||||
@ -1 +0,0 @@
 | 
			
		||||
data_dir = "@prefix@/share/sugar"
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user