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