This commit is contained in:
Dan Williams 2006-07-07 11:02:48 -04:00
commit fdd2ded8d8
21 changed files with 891 additions and 270 deletions

12
.gitignore vendored
View File

@ -19,4 +19,16 @@ missing
py-compile py-compile
stamp-h1 stamp-h1
intltool-extract
intltool-extract.in
intltool-merge
intltool-merge.in
intltool-update
intltool-update.in
mkinstalldirs
po/Makefile.in.in
po/POTFILES
po/stamp-it
po/sugar.pot
sugar/__installed__.py sugar/__installed__.py

View File

@ -23,11 +23,12 @@ class BrowserActivity(Activity):
FOLLOWING = 2 FOLLOWING = 2
LEADING = 3 LEADING = 3
def __init__(self, uri, mode = SOLO): def __init__(self, args):
Activity.__init__(self, _BROWSER_ACTIVITY_TYPE) Activity.__init__(self, _BROWSER_ACTIVITY_TYPE)
self.uri = uri
self._mode = mode self.uri = args[0]
self._mode = BrowserActivity.SOLO
self._share_service = None self._share_service = None
self._model_service = None self._model_service = None
self._notif_service = None self._notif_service = None

View File

@ -1,51 +0,0 @@
import dbus
import geckoembed
import pygtk
pygtk.require('2.0')
import gtk
import gobject
import sugar.env
from sugar.presence import Service
from BrowserActivity import BrowserActivity
class BrowserShell(dbus.service.Object):
def __init__(self, bus_name, object_path = '/com/redhat/Sugar/Browser'):
dbus.service.Object.__init__(self, bus_name, object_path)
geckoembed.set_profile_path(sugar.env.get_user_dir())
self.__browsers = []
def start(self):
gtk.main()
@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
def _start_browser_cb(self, browser, service):
browser.connect_to_shell(service)
@dbus.service.method('com.redhat.Sugar.BrowserShell')
def open_browser(self, uri, serialized_service=None):
service = None
if serialized_service is not None:
service = Service.deserialize(serialized_service)
browser = BrowserActivity(uri)
self.__browsers.append(browser)
gobject.idle_add(self._start_browser_cb, browser, service)
@dbus.service.method('com.redhat.Sugar.BrowserShell')
def open_browser_from_service_foobar(self, uri, serialized_service):
service = Service.deserialize(serialized_service)
browser = BrowserActivity(uri)
self.__browsers.append(browser)
gobject.idle_add(self._start_browser_cb, browser, service)

View File

@ -2,6 +2,8 @@ import pygtk
pygtk.require('2.0') pygtk.require('2.0')
import gtk import gtk
from gettext import gettext as _
from AddressItem import AddressItem from AddressItem import AddressItem
class NavigationToolbar(gtk.Toolbar): class NavigationToolbar(gtk.Toolbar):
@ -12,19 +14,19 @@ class NavigationToolbar(gtk.Toolbar):
self.set_style(gtk.TOOLBAR_BOTH_HORIZ) self.set_style(gtk.TOOLBAR_BOTH_HORIZ)
self.back = gtk.ToolButton(None, 'Back') self.back = gtk.ToolButton(None, _('Back'))
self.back.set_icon_name('back') self.back.set_icon_name('back')
self.back.connect("clicked", self.__go_back_cb) self.back.connect("clicked", self.__go_back_cb)
self.insert(self.back, -1) self.insert(self.back, -1)
self.back.show() self.back.show()
self.forward = gtk.ToolButton(None, 'Forward') self.forward = gtk.ToolButton(None, _('Forward'))
self.forward.set_icon_name('forward') self.forward.set_icon_name('forward')
self.forward.connect("clicked", self.__go_forward_cb) self.forward.connect("clicked", self.__go_forward_cb)
self.insert(self.forward, -1) self.insert(self.forward, -1)
self.forward.show() self.forward.show()
self.reload = gtk.ToolButton(None, 'Reload') self.reload = gtk.ToolButton(None, _('Reload'))
self.reload.set_icon_name('reload') self.reload.set_icon_name('reload')
self.reload.connect("clicked", self.__reload_cb) self.reload.connect("clicked", self.__reload_cb)
self.insert(self.reload, -1) self.insert(self.reload, -1)

View File

@ -1,2 +1,3 @@
[Activity] [Activity]
python_class = browser name = com.redhat.Sugar.BrowserActivity
class = BrowserActivity.BrowserActivity

View File

@ -1,19 +0,0 @@
#!/usr/bin/env python
import pygtk
pygtk.require('2.0')
import gtk
import dbus
import sugar.env
from sugar.LogWriter import LogWriter
from BrowserShell import BrowserShell
log_writer = LogWriter("Web")
log_writer.start()
session_bus = dbus.SessionBus()
bus_name = dbus.service.BusName('com.redhat.Sugar.Browser', bus=session_bus)
shell = BrowserShell(bus_name)
shell.start()

View File

@ -8,7 +8,6 @@ import gtk
import gobject import gobject
from sugar.activity.Activity import Activity from sugar.activity.Activity import Activity
from sugar.LogWriter import LogWriter
from sugar.presence import Service from sugar.presence import Service
from sugar.chat.Chat import Chat from sugar.chat.Chat import Chat
from sugar.chat.BuddyChat import BuddyChat from sugar.chat.BuddyChat import BuddyChat
@ -51,15 +50,7 @@ class ChatShellDbusService(dbus.service.Object):
def open_chat(self, serialized_service): def open_chat(self, serialized_service):
self._parent.open_chat(Service.deserialize(serialized_service)) self._parent.open_chat(Service.deserialize(serialized_service))
class ChatShell: class ChatListener:
instance = None
def get_instance():
if not ChatShell.instance:
ChatShell.instance = ChatShell()
return ChatShell.instance
get_instance = staticmethod(get_instance)
def __init__(self): def __init__(self):
ChatShellDbusService(self) ChatShellDbusService(self)
@ -105,10 +96,6 @@ class ChatShell:
chat.connect_to_shell() chat.connect_to_shell()
return False return False
log_writer = LogWriter("Chat") def start():
log_writer.start() chat_listener = ChatListener()
chat_listener.start()
chat_shell = ChatShell.get_instance()
chat_shell.start()
gtk.main()

View File

@ -1,2 +1,3 @@
[Activity] [Activity]
python_class = ChatActivity name = com.redhat.Sugar.ChatActivity
class = ChatActivity.ChatActivity

View File

@ -11,6 +11,16 @@ AM_MAINTAINER_MODE
AM_PATH_PYTHON AM_PATH_PYTHON
#
# Setup GETTEXT
#
ALL_LINGUAS="it"
GETTEXT_PACKAGE=sugar
AC_PROG_INTLTOOL([0.33])
AC_SUBST(GETTEXT_PACKAGE)
AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE", [Gettext package])
AM_GLIB_GNU_GETTEXT
AC_OUTPUT([ AC_OUTPUT([
Makefile Makefile
activities/Makefile activities/Makefile
@ -27,4 +37,5 @@ sugar/chat/sketchpad/Makefile
sugar/p2p/Makefile sugar/p2p/Makefile
sugar/p2p/model/Makefile sugar/p2p/model/Makefile
sugar/presence/Makefile sugar/presence/Makefile
po/Makefile.in
]) ])

5
po/POTFILES.in Normal file
View File

@ -0,0 +1,5 @@
shell/PresenceWindow.py
shell/StartPage.py
activities/browser/NavigationToolbar.py
shell/shell.py
sugar/chat/ChatEditor.py

29
po/it.po Normal file
View File

@ -0,0 +1,29 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2006-07-05 16:53+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
#: ../shell/PresenceWindow.py:62
msgid "Chi c'è intorno:"
msgstr ""
#: ../shell/PresenceWindow.py:104
msgid "Condividi"
msgstr ""
#: ../shell/StartPage.py:201
msgid "Cerca"
msgstr ""

167
shell/ActivityContainer.py Normal file
View File

@ -0,0 +1,167 @@
import dbus
import gobject
import gtk
from gettext import gettext as _
from sugar.chat.ChatWindow import ChatWindow
from sugar.chat.MeshChat import MeshChat
from ActivityHost import ActivityHost
from PresenceWindow import PresenceWindow
from WindowManager import WindowManager
from StartPage import StartPage
from Owner import ShellOwner
class ActivityContainerSignalHelper(gobject.GObject):
"""A gobject whose sole purpose is to distribute signals for
an ActivityContainer object."""
__gsignals__ = {
'local-activity-started': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT])),
'local-activity-ended': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT]))
}
def __init__(self, parent):
gobject.GObject.__init__(self)
self._parent = parent
def activity_started(self, activity_id):
self.emit('local-activity-started', self._parent, activity_id)
def activity_ended(self, activity_id):
self.emit('local-activity-ended', self._parent, activity_id)
class ActivityContainer(dbus.service.Object):
def __init__(self, service, bus):
self.activities = []
self.bus = bus
self.service = service
self._signal_helper = ActivityContainerSignalHelper(self)
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.connect("key-press-event", self.__key_press_event_cb)
self.window.set_title("OLPC Sugar")
self._fullscreen = False
self.notebook = gtk.Notebook()
self.notebook.set_scrollable(True)
tab_label = gtk.Label(_("Everyone"))
self._start_page = StartPage(self._signal_helper)
self.notebook.append_page(self._start_page, tab_label)
self._start_page.show()
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.current_activity = None
# Create our owner service
self._owner = ShellOwner()
self._presence_window = PresenceWindow(self)
self._presence_window.set_transient_for(self.window)
wm = WindowManager(self._presence_window)
wm.set_type(WindowManager.TYPE_POPUP)
wm.set_animation(WindowManager.ANIMATION_SLIDE_IN)
wm.set_geometry(0.02, 0.1, 0.25, 0.9)
wm.set_key(gtk.keysyms.F1)
self._chat_window = ChatWindow()
self._chat_window.set_transient_for(self.window)
self._chat_wm = WindowManager(self._chat_window)
self._chat_wm.set_animation(WindowManager.ANIMATION_SLIDE_IN)
self._chat_wm.set_type(WindowManager.TYPE_POPUP)
self._chat_wm.set_geometry(0.28, 0.1, 0.5, 0.9)
self._chat_wm.set_key(gtk.keysyms.F1)
self._mesh_chat = MeshChat()
def show(self):
self.window.show()
def set_current_activity(self, activity):
self.current_activity = activity
self._presence_window.set_activity(activity)
if activity:
host_chat = activity.get_chat()
self._chat_window.set_chat(host_chat)
else:
self._chat_window.set_chat(self._mesh_chat)
def notebook_tab_changed(self, notebook, page, page_number):
new_activity = notebook.get_nth_page(page_number).get_data("sugar-activity")
if self.current_activity != None:
self.current_activity.lost_focus()
self.set_current_activity(new_activity)
if self.current_activity != None:
self.current_activity.got_focus()
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:
activity_id = activity.get_host_activity_id()
self._signal_helper.activity_ended(activity_id)
self.activities.remove((owner, activity))
#self.__print_activities()
@dbus.service.method("com.redhat.Sugar.Shell.ActivityContainer", \
in_signature="ss", \
out_signature="s", \
sender_keyword="sender")
def add_activity(self, activity_name, default_type, sender):
#print "hello world, activity_name = '%s', sender = '%s'"%(activity_name, sender)
activity = ActivityHost(self, activity_name, default_type)
self.activities.append((sender, activity))
activity_id = activity.get_host_activity_id()
self._signal_helper.activity_started(activity_id)
self.current_activity = activity
return activity_id
@dbus.service.method("com.redhat.Sugar.Shell.ActivityContainer", \
in_signature="sss", \
sender_keyword="sender")
def add_activity_with_id(self, activity_name, default_type, activity_id, sender):
activity = ActivityHost(self, activity_name, default_type, activity_id)
self.activities.append((sender, activity))
activity_id = activity.get_host_activity_id()
self._signal_helper.activity_started(activity_id)
self.current_activity = activity
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 __key_press_event_cb(self, window, event):
if event.keyval == gtk.keysyms.F11:
if self._fullscreen:
window.unfullscreen()
self._fullscreen = False
else:
window.fullscreen()
self._fullscreen = True

269
shell/ActivityHost.py Normal file
View File

@ -0,0 +1,269 @@
import dbus
import gtk
import gobject
class ActivityHostSignalHelper(gobject.GObject):
__gsignals__ = {
'shared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([]))
}
def __init__(self, parent):
gobject.GObject.__init__(self)
self._parent = parent
def emit_shared(self):
self.emit('shared')
class ActivityHost(dbus.service.Object):
def __init__(self, activity_container, activity_name, default_type, activity_id = None):
self.peer_service = None
self.activity_name = activity_name
self.ellipsize_tab = False
self._shared = False
self._signal_helper = ActivityHostSignalHelper(self)
self.activity_container = activity_container
if activity_id is None:
self.activity_id = sugar.util.unique_id()
else:
self.activity_id = activity_id
self._default_type = default_type
self.dbus_object_name = "/com/redhat/Sugar/Shell/Activities/%s" % self.activity_id
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()
self._create_chat()
notebook = self.activity_container.notebook
index = notebook.append_page(self.socket, hbox)
notebook.set_current_page(index)
def _create_chat(self):
self._activity_chat = ActivityChat(self)
def got_focus(self):
if self.peer_service != None:
self.peer_service.got_focus()
def lost_focus(self):
self.peer_service.lost_focus()
def get_chat(self):
return self._activity_chat
def get_default_type(self):
return self._default_type
def __close_button_clicked_reply_cb(self):
pass
def __close_button_clicked_error_cb(self, error):
pass
def publish(self):
self._activity_chat.publish()
self.peer_service.publish()
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
def connect(self, signal, func):
self._signal_helper.connect(signal, func)
def get_shared(self):
"""Return True if this activity is shared, False if
it has not been shared yet."""
return self._shared
def _shared_signal(self):
self._shared = True
self._signal_helper.emit_shared()
@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")
self.activity_container.bus.add_signal_receiver(self._shared_signal,
signal_name="ActivityShared",
dbus_interface="com.redhat.Sugar.Activity",
named_service=self.__peer_service_name,
path=self.__peer_object_name)
@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="b", \
out_signature="")
def set_has_changes(self, has_changes):
if has_changes:
attrs = pango.AttrList()
attrs.insert(pango.AttrForeground(50000, 0, 0, 0, -1))
attrs.insert(pango.AttrWeight(pango.WEIGHT_BOLD, 0, -1))
self.tab_label.set_attributes(attrs)
else:
self.tab_label.set_attributes(pango.AttrList())
@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:
# Work around for a bug in dbus < 0.61 where integers
# are not correctly marshalled
if c < 0:
c += 256
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):
"""Real function that the shell should use for getting the
activity's ID."""
return self.activity_id
def get_id(self):
"""Interface-type function to match activity.Activity's
get_id() function."""
return self.activity_id
def default_type(self):
"""Interface-type function to match activity.Activity's
default_type() function."""
return self._default_type
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()

54
shell/ConsoleLogger.py Normal file
View File

@ -0,0 +1,54 @@
import gtk
import dbus
from WindowManager import WindowManager
from ActivityContainer import ActivityContainer
class ConsoleLogger(dbus.service.Object):
def __init__(self):
session_bus = dbus.SessionBus()
bus_name = dbus.service.BusName('com.redhat.Sugar.Logger', bus=session_bus)
object_path = '/com/redhat/Sugar/Logger'
dbus.service.Object.__init__(self, bus_name, object_path)
self._window = gtk.Window()
self._window.set_title("Console")
self._window.connect("delete_event", lambda w, e: w.hide_on_delete())
self._nb = gtk.Notebook()
self._window.add(self._nb)
self._nb.show()
self._consoles = {}
console_wm = WindowManager(self._window)
console_wm.set_type(WindowManager.TYPE_POPUP)
console_wm.set_geometry(0.1, 0.1, 0.8, 0.8)
def _create_console(self, application):
sw = gtk.ScrolledWindow()
sw.set_policy(gtk.POLICY_AUTOMATIC,
gtk.POLICY_AUTOMATIC)
console = gtk.TextView()
console.set_wrap_mode(gtk.WRAP_WORD)
sw.add(console)
console.show()
self._nb.append_page(sw, gtk.Label(application))
sw.show()
return console
@dbus.service.method('com.redhat.Sugar.Logger')
def log(self, application, message):
if self._consoles.has_key(application):
console = self._consoles[application]
else:
console = self._create_console(application)
self._consoles[application] = console
buf = console.get_buffer()
buf.insert(buf.get_end_iter(), message)

View File

@ -8,6 +8,8 @@ from sugar.presence.PresenceService import PresenceService
from sugar.presence.Service import Service from sugar.presence.Service import Service
from sugar.chat.BuddyChat import BuddyChat from sugar.chat.BuddyChat import BuddyChat
from gettext import gettext as _
class PresenceWindow(gtk.Window): class PresenceWindow(gtk.Window):
_MODEL_COL_NICK = 0 _MODEL_COL_NICK = 0
_MODEL_COL_ICON = 1 _MODEL_COL_ICON = 1
@ -57,7 +59,7 @@ class PresenceWindow(gtk.Window):
vbox = gtk.VBox(False, 6) vbox = gtk.VBox(False, 6)
vbox.set_border_width(12) vbox.set_border_width(12)
label = gtk.Label("Who's around:") label = gtk.Label(_("Who's around:"))
label.set_alignment(0.0, 0.5) label.set_alignment(0.0, 0.5)
vbox.pack_start(label, False) vbox.pack_start(label, False)
label.show() label.show()
@ -99,7 +101,7 @@ class PresenceWindow(gtk.Window):
button_box = gtk.HButtonBox() button_box = gtk.HButtonBox()
self._share_button = gtk.Button('Share') self._share_button = gtk.Button(_('Share'))
self._share_button.connect('clicked', self._share_button_clicked_cb) self._share_button.connect('clicked', self._share_button_clicked_cb)
button_box.pack_start(self._share_button) button_box.pack_start(self._share_button)
self._share_button.show() self._share_button.show()

43
shell/Shell.py Executable file
View File

@ -0,0 +1,43 @@
import dbus
import gobject
from sugar.LogWriter import LogWriter
from WindowManager import WindowManager
from ConsoleLogger import ConsoleLogger
from ActivityContainer import ActivityContainer
class Shell(gobject.GObject):
__gsignals__ = {
'close': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([])),
}
def __init__(self):
gobject.GObject.__init__(self)
def start(self):
console = ConsoleLogger()
log_writer = LogWriter("Shell", False)
log_writer.start()
session_bus = dbus.SessionBus()
service = dbus.service.BusName("com.redhat.Sugar.Shell", bus=session_bus)
activity_container = ActivityContainer(service, session_bus)
activity_container.window.connect('destroy', self.__activity_container_destroy_cb)
activity_container.show()
wm = WindowManager(activity_container.window)
wm.show()
def __activity_container_destroy_cb(self, activity_container):
self.emit('close')
if __name__ == "__main__":
shell = Shell()
shell.start()
try:
gtk.main()
except KeyboardInterrupt:
print 'Ctrl+c pressed, exiting...'

View File

@ -2,7 +2,6 @@ import pygtk
pygtk.require('2.0') pygtk.require('2.0')
import gtk import gtk
import pango import pango
import dbus
import cgi import cgi
import xml.sax.saxutils import xml.sax.saxutils
import gobject import gobject
@ -11,6 +10,9 @@ import socket
import dbus_bindings import dbus_bindings
from google import google from google import google
from sugar.presence.PresenceService import PresenceService from sugar.presence.PresenceService import PresenceService
from sugar.activity import Activity
from gettext import gettext as _
_BROWSER_ACTIVITY_TYPE = "_web_olpc._udp" _BROWSER_ACTIVITY_TYPE = "_web_olpc._udp"
@ -150,10 +152,6 @@ class ActivitiesView(gtk.TreeView):
self._owner = owner self._owner = owner
def _row_activated_cb(self, treeview, path, column): def _row_activated_cb(self, treeview, path, column):
bus = dbus.SessionBus()
proxy_obj = bus.get_object('com.redhat.Sugar.Browser', '/com/redhat/Sugar/Browser')
browser_shell = dbus.Interface(proxy_obj, 'com.redhat.Sugar.BrowserShell')
model = self.get_model() model = self.get_model()
address = model.get_value(model.get_iter(path), _COLUMN_ADDRESS) address = model.get_value(model.get_iter(path), _COLUMN_ADDRESS)
service = model.get_value(model.get_iter(path), _COLUMN_SERVICE) service = model.get_value(model.get_iter(path), _COLUMN_SERVICE)
@ -173,13 +171,9 @@ class ActivitiesView(gtk.TreeView):
self._activity_controller.switch_to_activity(service_act_id) self._activity_controller.switch_to_activity(service_act_id)
return return
# Start a new activity Activity.create('com.redhat.Sugar.BrowserActivity', service, [ address ])
serialized_service = service.serialize(self._owner)
try: >>>>>>> 63c93e4f2da2a5f8935835da876d118bdc99c495/shell/StartPage.py
browser_shell.open_browser(address, serialized_service)
except dbus_bindings.DBusException, exc:
pass
class StartPage(gtk.HBox): class StartPage(gtk.HBox):
def __init__(self, activity_controller, ac_signal_object): def __init__(self, activity_controller, ac_signal_object):
gtk.HBox.__init__(self) gtk.HBox.__init__(self)
@ -210,7 +204,7 @@ class StartPage(gtk.HBox):
search_box.pack_start(self._search_entry) search_box.pack_start(self._search_entry)
self._search_entry.show() self._search_entry.show()
search_button = gtk.Button("Search") search_button = gtk.Button(_("Search"))
search_button.connect('clicked', self._search_button_clicked_cb) search_button.connect('clicked', self._search_button_clicked_cb)
search_box.pack_start(search_button, False) search_box.pack_start(search_button, False)
search_button.show() search_button.show()

View File

@ -1,169 +1,204 @@
import pygtk import time
pygtk.require('2.0') import logging
import gtk import gtk
import gobject import gobject
SM_SPACE_PROPORTIONAL = 0 DEFAULT_WIDTH = 640
SM_STEP = 1 DEFAULT_HEIGHT = 480
SLIDING_TIMEOUT = 50 SLIDING_TIME = 0.8
SLIDING_MODE = SM_SPACE_PROPORTIONAL
#SLIDING_TIMEOUT = 10 class SlidingHelper:
#SLIDING_MODE = SM_STEP IN = 0
#SLIDING_STEP = 0.05 OUT = 1
def __init__(self, manager, direction):
self._direction = direction
self._cur_time = time.time()
self._target_time = self._cur_time + SLIDING_TIME
self._manager = manager
self._start = True
self._end = False
(x, y, width, height) = manager.get_geometry()
self._orig_y = y
if direction == SlidingHelper.IN:
self._target_y = y
manager.set_geometry(x, y - height, width, height)
else:
self._target_y = y - height
def get_direction(self):
return self._direction
def is_start(self):
return self._start
def is_end(self):
return self._end
def get_next_y(self):
self._start = False
(x, y, width, height) = self._manager.get_geometry()
old_time = self._cur_time
self._cur_time = time.time()
remaining = self._target_time - self._cur_time
if remaining <= 0:
self._end = True
y = self._orig_y
else:
approx_time_step = float(self._cur_time - old_time)
approx_n_steps = remaining / approx_time_step
step = (self._target_y - y) / approx_n_steps
y += step
return y
class WindowManager: class WindowManager:
__managers_list = [] __managers_list = []
CENTER = 0 TYPE_ACTIVITY = 0
LEFT = 1 TYPE_POPUP = 1
RIGHT = 2
TOP = 3 ANIMATION_NONE = 0
BOTTOM = 4 ANIMATION_SLIDE_IN = 1
ABSOLUTE = 0
SCREEN_RELATIVE = 1
def __init__(self, window): def __init__(self, window):
self._window = window self._window = window
self._sliding_pos = 0 self._window_type = WindowManager.TYPE_ACTIVITY
self._animation = WindowManager.ANIMATION_NONE
self._key = 0
self._animating = False
WindowManager.__managers_list.append(self)
window.connect("key-press-event", self.__key_press_event_cb) window.connect("key-press-event", self.__key_press_event_cb)
WindowManager.__managers_list.append(self)
def __key_press_event_cb(self, window, event): def __key_press_event_cb(self, window, event):
manager = None # FIXME we should fix this to work also while animating
if self._animating:
if event.keyval == gtk.keysyms.Left and \ return False
event.state & gtk.gdk.CONTROL_MASK:
for wm in WindowManager.__managers_list:
if wm._position == WindowManager.LEFT:
manager = wm
if event.keyval == gtk.keysyms.Up and \
event.state & gtk.gdk.CONTROL_MASK:
for wm in WindowManager.__managers_list:
if wm._position == WindowManager.TOP:
manager = wm
if event.keyval == gtk.keysyms.Down and \
event.state & gtk.gdk.CONTROL_MASK:
for wm in WindowManager.__managers_list:
if wm._position == WindowManager.BOTTOM:
manager = wm
if manager and manager._window.get_property('visible'):
manager.slide_window_out()
elif manager:
manager.slide_window_in()
def set_width(self, width, width_type): for manager in WindowManager.__managers_list:
if event.keyval == manager._key:
if manager._window.get_property('visible'):
manager.hide()
else:
manager.show()
def get_geometry(self):
return (self._x, self._y, self._width, self._height)
def set_geometry(self, x, y, width, height):
if self._window_type == WindowManager.TYPE_ACTIVITY:
logging.error('The geometry will be ignored for activity windows')
self._x = x
self._y = y
self._width = width self._width = width
self._width_type = width_type
def set_height(self, height, height_type):
self._height = height self._height = height
self._height_type = height_type
def set_animation(self, animation):
self._animation = animation
def set_position(self, position): def set_type(self, window_type):
self._position = position self._window_type = window_type
def set_key(self, key):
self._key = key
def show(self):
self._update_hints()
self._update_size()
if self._animation == WindowManager.ANIMATION_SLIDE_IN:
self._slide_in()
else:
self._update_position()
self._window.show()
def hide(self):
if self._animation == WindowManager.ANIMATION_SLIDE_IN:
self._slide_out()
else:
self._window.hide()
def _get_screen_dimensions(self):
screen_width = DEFAULT_WIDTH
screen_height = DEFAULT_HEIGHT
for manager in WindowManager.__managers_list:
if manager._window_type == WindowManager.TYPE_ACTIVITY:
screen_width = manager._window.allocation.width
screen_height = manager._window.allocation.height
return (screen_width, screen_height)
def _get_screen_position(self):
result = (0, 0)
for manager in WindowManager.__managers_list:
if manager._window_type == WindowManager.TYPE_ACTIVITY:
result = manager._window.get_position()
return result
def _transform_position(self):
(screen_width, screen_height) = self._get_screen_dimensions()
(screen_x, screen_y) = self._get_screen_position()
x = int(screen_width * self._x) + screen_x
y = int(screen_height * self._y) + screen_y
return (x, y)
def _transform_dimensions(self):
(screen_width, screen_height) = self._get_screen_dimensions()
width = int(screen_width * self._width)
height = int(screen_height * self._height)
return (width, height)
def _update_hints(self):
if self._window_type == WindowManager.TYPE_POPUP:
self._window.set_decorated(False)
self._window.set_skip_taskbar_hint(True)
def _update_size(self): def _update_size(self):
screen_width = self._window.get_screen().get_width() if self._window_type == WindowManager.TYPE_ACTIVITY:
screen_height = self._window.get_screen().get_height() self._window.resize(DEFAULT_WIDTH, DEFAULT_HEIGHT)
else:
if self._width_type is WindowManager.ABSOLUTE: (width, height) = self._transform_dimensions()
width = self._width self._window.resize(width, height)
elif self._width_type is WindowManager.SCREEN_RELATIVE:
width = int(screen_width * self._width)
if self._height_type is WindowManager.ABSOLUTE:
height = self._height
elif self._height_type is WindowManager.SCREEN_RELATIVE:
height = int(screen_height * self._height)
self._real_width = width
self._real_height = height
self._window.set_size_request(self._real_width,
self._real_height)
def _update_position(self): def _update_position(self):
screen_width = self._window.get_screen().get_width() if self._window_type == WindowManager.TYPE_POPUP:
screen_height = self._window.get_screen().get_height() (x, y) = self._transform_position()
self._window.move(x, y)
width = self._real_width
height = self._real_height
if self._position is WindowManager.CENTER:
self._x = int((screen_width - width) / 2)
self._y = int((screen_height - height) / 2)
elif self._position is WindowManager.LEFT:
self._x = - int((1.0 - self._sliding_pos) * width)
self._y = int((screen_height - height) / 2)
elif self._position is WindowManager.TOP:
self._x = int(screen_width - width - 10)
self._y = - int((1.0 - self._sliding_pos) * height)
elif self._position is WindowManager.BOTTOM:
self._x = int((screen_width - width) / 2)
self._y = screen_height - int(self._sliding_pos * height)
self._window.move(self._x, self._y)
def __slide_in_timeout_cb(self): def __slide_timeout_cb(self, helper):
if self._sliding_pos == 0: start = helper.is_start()
self._y = helper.get_next_y()
self._update_position()
if start and helper.get_direction() == SlidingHelper.IN:
self._window.show() self._window.show()
elif helper.is_end() and helper.get_direction() == SlidingHelper.OUT:
if SLIDING_MODE == SM_SPACE_PROPORTIONAL:
space_to_go = 1.0 - self._sliding_pos
self._sliding_pos += (space_to_go / 2)
else:
self._sliding_pos += SLIDING_STEP
if self._sliding_pos > .999:
self._sliding_pos = 1.0
self._update_position()
if self._sliding_pos == 1.0:
return False
else:
return True
def __slide_out_timeout_cb(self):
if SLIDING_MODE == SM_SPACE_PROPORTIONAL:
space_to_go = self._sliding_pos
self._sliding_pos -= (space_to_go / 2)
else:
self._sliding_pos -= SLIDING_STEP
if self._sliding_pos < .001:
self._sliding_pos = 0
self._update_position()
if self._sliding_pos == 0:
self._window.hide() self._window.hide()
return False
else:
return True
def slide_window_in(self): self._animating = not helper.is_end()
self._sliding_pos = 0
gobject.timeout_add(SLIDING_TIMEOUT, self.__slide_in_timeout_cb) return not helper.is_end()
def _slide_in(self):
helper = SlidingHelper(self, SlidingHelper.IN)
gobject.idle_add(self.__slide_timeout_cb, helper)
def slide_window_out(self): def _slide_out(self):
self._sliding_pos = 1.0 helper = SlidingHelper(self, SlidingHelper.OUT)
gobject.timeout_add(SLIDING_TIMEOUT, self.__slide_out_timeout_cb) gobject.idle_add(self.__slide_timeout_cb, helper)
def show(self):
self._window.show()
def update(self):
self._update_position()
def manage(self):
self._update_size()
self._update_position()

View File

@ -6,9 +6,11 @@ import pygtk
pygtk.require('2.0') pygtk.require('2.0')
import gtk import gtk
from shell import Shell from sugar.activity import Activity
from sugar import env from sugar import env
from Shell import Shell
class Session: class Session:
def __init__(self): def __init__(self):
self._activity_processes = {} self._activity_processes = {}
@ -42,20 +44,21 @@ class Session:
def _run_activity(self, activity_dir): def _run_activity(self, activity_dir):
env.add_to_python_path(activity_dir) env.add_to_python_path(activity_dir)
activities = []
for filename in os.listdir(activity_dir): for filename in os.listdir(activity_dir):
if filename.endswith(".activity"): if filename.endswith(".activity"):
path = os.path.join(activity_dir, filename) path = os.path.join(activity_dir, filename)
cp = ConfigParser() cp = ConfigParser()
cp.read([path]) cp.read([path])
python_class = cp.get('Activity', "python_class")
activities.append(python_class)
for activity in activities: activity_name = cp.get('Activity', "name")
args = [ 'python', '-m', activity ] activity_class = cp.get('Activity', "class")
pid = os.spawnvp(os.P_NOWAIT, 'python', args)
self._activity_processes[activity] = pid args = [ 'python', '-m', 'sugar/activity/Activity' ]
args.append(activity_name)
args.append(activity_class)
pid = os.spawnvp(os.P_NOWAIT, 'python', args)
self._activity_processes[activity_name] = pid
def _shell_close_cb(self, shell): def _shell_close_cb(self, shell):
self.shutdown() self.shutdown()

View File

@ -1,4 +1,5 @@
# -*- tab-width: 4; indent-tabs-mode: t -*- import sys
import imp
import dbus import dbus
import dbus.service import dbus.service
@ -7,6 +8,8 @@ import pygtk
pygtk.require('2.0') pygtk.require('2.0')
import gtk, gobject import gtk, gobject
from sugar.LogWriter import LogWriter
SHELL_SERVICE_NAME = "com.redhat.Sugar.Shell" SHELL_SERVICE_NAME = "com.redhat.Sugar.Shell"
SHELL_SERVICE_PATH = "/com/redhat/Sugar/Shell" SHELL_SERVICE_PATH = "/com/redhat/Sugar/Shell"
@ -21,6 +24,81 @@ ON_LOST_FOCUS_CB = "lost_focus"
ON_GOT_FOCUS_CB = "got_focus" ON_GOT_FOCUS_CB = "got_focus"
ON_PUBLISH_CB = "publish" ON_PUBLISH_CB = "publish"
def get_path(activity_name):
"""Returns the activity path"""
return '/' + activity_name.replace('.', '/')
def get_factory(activity_name):
"""Returns the activity factory"""
return activity_name + '.Factory'
class ActivityFactory(dbus.service.Object):
"""Dbus service that takes care of creating new instances of an activity"""
def __init__(self, activity_name, activity_class):
splitted_module = activity_class.rsplit('.', 1)
module_name = splitted_module[0]
class_name = splitted_module[1]
(fp, pathname, description) = imp.find_module(module_name)
module = imp.load_module(module_name, fp, pathname, description)
try:
start = getattr(module, 'start')
except:
start = None
if start:
start()
self._class = getattr(module, class_name)
bus = dbus.SessionBus()
factory = get_factory(activity_name)
bus_name = dbus.service.BusName(factory, bus = bus)
dbus.service.Object.__init__(self, bus_name, get_path(factory))
@dbus.service.method("com.redhat.Sugar.ActivityFactory")
def create_with_service(self, serialized_service, args):
service = None
if serialized_service is not None:
service = Service.deserialize(serialized_service)
activity = self._class(args)
gobject.idle_add(self._start_activity_cb, activity, service)
@dbus.service.method("com.redhat.Sugar.ActivityFactory")
def create(self, args):
self.create_with_service(None, args)
def _start_activity_cb(self, activity, service):
activity.connect_to_shell(service)
def create(activity_name, service = None, args = None):
"""Create a new activity from his name."""
bus = dbus.SessionBus()
factory_name = get_factory(activity_name)
factory_path = get_path(factory_name)
proxy_obj = bus.get_object(factory_name, factory_path)
factory = dbus.Interface(proxy_obj, "com.redhat.Sugar.ActivityFactory")
if service:
serialized_service = service.serialize(service)
factory.create_with_service(serialized_service, args)
else:
factory.create(args)
def main(activity_name, activity_class):
"""Starts the activity main loop."""
log_writer = LogWriter(activity_name)
log_writer.start()
factory = ActivityFactory(activity_name, activity_class)
gtk.main()
class ActivityDbusService(dbus.service.Object): class ActivityDbusService(dbus.service.Object):
"""Base dbus service object that each Activity uses to export dbus methods. """Base dbus service object that each Activity uses to export dbus methods.
@ -141,7 +219,7 @@ class ActivityDbusService(dbus.service.Object):
"""Called by the shell to request the activity to publish itself on the network.""" """Called by the shell to request the activity to publish itself on the network."""
self._call_callback(ON_PUBLISH_CB) self._call_callback(ON_PUBLISH_CB)
@dbus.service.signal(ACTIVITY_SERVICE_NAME) @dbus.service.signal(ACTIVITY_SERVICE_NAME)
def ActivityShared(self): def ActivityShared(self):
pass pass
@ -335,3 +413,6 @@ class Activity(object):
def on_close_from_user(self): def on_close_from_user(self):
"""Triggered when this Activity is closed by the user.""" """Triggered when this Activity is closed by the user."""
pass pass
if __name__ == "__main__":
main(sys.argv[1], sys.argv[2])

View File

@ -1,6 +1,7 @@
import pygtk import pygtk
pygtk.require('2.0') pygtk.require('2.0')
import gtk import gtk
from gettext import gettext as _
from sugar.chat.sketchpad.SketchPad import SketchPad from sugar.chat.sketchpad.SketchPad import SketchPad
import richtext import richtext
@ -24,7 +25,6 @@ class ChatEditor(gtk.HBox):
chat_view_sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) chat_view_sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
self._text_view = richtext.RichTextView() self._text_view = richtext.RichTextView()
self._text_view.connect("key-press-event", self.__key_press_event_cb) self._text_view.connect("key-press-event", self.__key_press_event_cb)
self._text_view.connect("button-press-event", self.__button_press_event_cb)
chat_view_sw.add(self._text_view) chat_view_sw.add(self._text_view)
self._text_view.show() self._text_view.show()
@ -38,7 +38,7 @@ class ChatEditor(gtk.HBox):
self.pack_start(self._notebook) self.pack_start(self._notebook)
self._notebook.show() self._notebook.show()
send_button = gtk.Button("Send") send_button = gtk.Button(_("Send"))
send_button.set_size_request(60, -1) send_button.set_size_request(60, -1)
send_button.connect('clicked', self.__send_button_clicked_cb) send_button.connect('clicked', self.__send_button_clicked_cb)
self.pack_start(send_button, False, True) self.pack_start(send_button, False, True)
@ -87,9 +87,3 @@ class ChatEditor(gtk.HBox):
if event.keyval == gtk.keysyms.Return: if event.keyval == gtk.keysyms.Return:
self._send() self._send()
return True return True
def __button_press_event_cb(self, text_view, event):
# Need to explicitly get keyboard focus in the window
# because docks doesn't take it by default.
toplevel = text_view.get_toplevel()
toplevel.window.focus()