Revert the work to get rid of tabs from master. I realized

it's too much work to do in a few hours, so I created a
branch for it.
This commit is contained in:
Marco Pesenti Gritti 2006-07-09 01:04:40 +02:00
parent d4cb9a2714
commit e6a8860f3e
10 changed files with 892 additions and 211 deletions

View File

@ -26,10 +26,7 @@ class BrowserActivity(Activity):
def __init__(self, args):
Activity.__init__(self, _BROWSER_ACTIVITY_TYPE)
if len(args) > 0:
self.uri = args[0]
else:
self.uri = 'http://www.google.com'
self.uri = args[0]
self._mode = BrowserActivity.SOLO
self._share_service = None
@ -79,7 +76,11 @@ class BrowserActivity(Activity):
self._notif_bar.show()
def on_connected_to_shell(self):
self.set_title("Web Page")
self.set_ellipsize_tab(True)
self.set_can_close(True)
self.set_tab_text("Web Page")
self.set_tab_icon(name="web-browser")
self.set_show_tab_icon(True)
vbox = gtk.VBox()
@ -98,7 +99,10 @@ class BrowserActivity(Activity):
vbox.pack_start(nav_toolbar, False)
nav_toolbar.show()
self.add(vbox)
plug = self.gtk_plug()
plug.add(vbox)
plug.show()
vbox.show()
logging.debug('Start presence service')

View File

@ -33,23 +33,46 @@ class ActivityContainerSignalHelper(gobject.GObject):
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)
self._current_activity = None
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")
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, 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)
@ -57,14 +80,19 @@ class ActivityContainer(dbus.service.Object):
wm.set_key(gtk.keysyms.F1)
self._chat_window = ChatWindow()
chat_wm = WindowManager(self._chat_window)
chat_wm.set_animation(WindowManager.ANIMATION_SLIDE_IN)
chat_wm.set_type(WindowManager.TYPE_POPUP)
chat_wm.set_geometry(0.28, 0.1, 0.5, 0.9)
chat_wm.set_key(gtk.keysyms.F1)
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)
@ -75,28 +103,65 @@ class ActivityContainer(dbus.service.Object):
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):
for owner, activity in self._activities[:]:
#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.activities.remove((owner, activity))
#self.__print_activities()
@dbus.service.method("com.redhat.Sugar.Shell.ActivityContainer")
def add_activity(self, default_type):
activity = ActivityHost(self._service, default_type)
self._activities.append(activity)
activity_id = activity.get_id()
@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.set_current_activity(activity)
self.current_activity = activity
return activity_id
@dbus.service.method("com.redhat.Sugar.Shell.ActivityContainer")
def add_activity_with_id(self, default_type, activity_id):
activity = ActivityHost(self._service, default_type, activity_id)
self._activities.append(activity)
@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

View File

@ -2,10 +2,6 @@ import dbus
import gtk
import gobject
from sugar.chat.ActivityChat import ActivityChat
from WindowManager import WindowManager
import sugar.util
class ActivityHostSignalHelper(gobject.GObject):
__gsignals__ = {
'shared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([]))
@ -19,22 +15,72 @@ class ActivityHostSignalHelper(gobject.GObject):
self.emit('shared')
class ActivityHost(dbus.service.Object):
def __init__(self, bus_name, default_type, activity_id = None):
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, bus_name, self.dbus_object_name)
self._signal_helper = ActivityHostSignalHelper(self)
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)
@ -51,26 +97,31 @@ class ActivityHost(dbus.service.Object):
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_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 get_shared(self):
"""Return True if this activity is shared, False if
it has not been shared yet."""
@ -80,30 +131,71 @@ class ActivityHost(dbus.service.Object):
self._shared = True
self._signal_helper.emit_shared()
@dbus.service.method("com.redhat.Sugar.Shell.ActivityHost")
@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
session_bus = dbus.SessionBus()
self.peer_service = dbus.Interface(session_bus.get_object( \
self.peer_service = dbus.Interface(self.activity_container.bus.get_object( \
self.__peer_service_name, self.__peer_object_name), \
"com.redhat.Sugar.Activity")
session_bus.add_signal_receiver(self._shared_signal,
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")
@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):
pass
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")
def set_title(self, text):
pass
@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")
def set_icon(self, data, colorspace, has_alpha, bits_per_sample, width, height, rowstride):
@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
@ -112,11 +204,15 @@ class ActivityHost(dbus.service.Object):
c += 256
pixstr += chr(c)
pixbuf = gtk.gdk.pixbuf_new_from_data(pixstr, colorspace, has_alpha,
bits_per_sample, width, height, rowstride)
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")
@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))
@ -124,7 +220,50 @@ class ActivityHost(dbus.service.Object):
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()

View File

@ -1,29 +0,0 @@
import dbus
class ActivityInfo:
def __init__(self, name, title):
self._name = name
self._title = title
def get_name(self):
return self._name
def get_title(self):
return self._title
class ActivityRegistry(dbus.service.Object):
"""Dbus service that tracks the available activities"""
def __init__(self):
self._activities = []
bus = dbus.SessionBus()
bus_name = dbus.service.BusName('com.redhat.Sugar.ActivityRegistry', bus = bus)
dbus.service.Object.__init__(self, bus_name, '/com/redhat/Sugar/ActivityRegistry')
@dbus.service.method("com.redhat.Sugar.ActivityRegistry")
def add(self, name, title):
self._activities.append(ActivityInfo(name, title))
def list_activities(self):
return self._activities

View File

@ -24,7 +24,6 @@ class ConsoleLogger(dbus.service.Object):
console_wm = WindowManager(self._window)
console_wm.set_type(WindowManager.TYPE_POPUP)
console_wm.set_geometry(0.1, 0.1, 0.8, 0.8)
console_wm.set_key(gtk.keysyms.F3)
def _create_console(self, application):
sw = gtk.ScrolledWindow()

View File

@ -1,50 +0,0 @@
from gettext import gettext as _
import gtk
from sugar.activity import Activity
class NewActivityButton(gtk.MenuToolButton):
def __init__(self, shell):
gtk.MenuToolButton.__init__(self, None, _('New Activity'))
self._shell = shell
self.set_menu(gtk.Menu())
self.connect("show-menu", self.__show_menu_cb)
def __show_menu_cb(self, button):
menu = gtk.Menu()
for activity_info in self._shell.get_registry().list_activities():
item = gtk.MenuItem(activity_info.get_title(), False)
name = activity_info.get_name()
item.connect('activate', self.__menu_item_activate_cb, name)
menu.append(item)
item.show()
self.set_menu(menu)
def __menu_item_activate_cb(self, item, name):
Activity.create(name)
class Toolbar(gtk.Toolbar):
def __init__(self, shell):
gtk.Toolbar.__init__(self)
new_activity_button = NewActivityButton(shell)
self.insert(new_activity_button, -1)
new_activity_button.show()
class HomeWindow(gtk.Window):
def __init__(self, shell):
gtk.Window.__init__(self)
vbox = gtk.VBox()
toolbar = Toolbar(shell)
vbox.pack_start(toolbar, False)
toolbar.show()
self.add(vbox)
vbox.show()

View File

@ -1,13 +1,10 @@
import dbus
import gtk
import gobject
from sugar.LogWriter import LogWriter
from WindowManager import WindowManager
from ConsoleLogger import ConsoleLogger
from ActivityContainer import ActivityContainer
from ActivityRegistry import ActivityRegistry
from HomeWindow import HomeWindow
class Shell(gobject.GObject):
__gsignals__ = {
@ -24,29 +21,18 @@ class Shell(gobject.GObject):
log_writer = LogWriter("Shell", False)
log_writer.start()
self._registry = ActivityRegistry()
root_window = gtk.Window()
root_window.set_title('Sugar')
wm = WindowManager(root_window)
wm.set_type(WindowManager.TYPE_ROOT)
wm.show()
home_window = HomeWindow(self)
home_window.set_transient_for(root_window)
wm = WindowManager(home_window)
wm.set_type(WindowManager.TYPE_POPUP)
wm.set_animation(WindowManager.ANIMATION_SLIDE_IN)
wm.set_geometry(0.1, 0.1, 0.8, 0.8)
wm.set_key(gtk.keysyms.F2)
wm.show()
session_bus = dbus.SessionBus()
service = dbus.service.BusName("com.redhat.Sugar.Shell", bus=session_bus)
activity_container = ActivityContainer(service, session_bus)
def get_registry(self):
return self._registry
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()

View File

@ -63,9 +63,8 @@ class SlidingHelper:
class WindowManager:
__managers_list = []
TYPE_ROOT = 0
TYPE_ACTIVITY = 1
TYPE_POPUP = 2
TYPE_ACTIVITY = 0
TYPE_POPUP = 1
ANIMATION_NONE = 0
ANIMATION_SLIDE_IN = 1
@ -135,7 +134,7 @@ class WindowManager:
screen_height = DEFAULT_HEIGHT
for manager in WindowManager.__managers_list:
if manager._window_type == WindowManager.TYPE_ROOT:
if manager._window_type == WindowManager.TYPE_ACTIVITY:
screen_width = manager._window.allocation.width
screen_height = manager._window.allocation.height
@ -144,7 +143,7 @@ class WindowManager:
def _get_screen_position(self):
result = (0, 0)
for manager in WindowManager.__managers_list:
if manager._window_type == WindowManager.TYPE_ROOT:
if manager._window_type == WindowManager.TYPE_ACTIVITY:
result = manager._window.get_position()
return result
@ -172,8 +171,7 @@ class WindowManager:
self._window.set_skip_taskbar_hint(True)
def _update_size(self):
if (self._window_type == WindowManager.TYPE_ACTIVITY) or \
(self._window_type == WindowManager.TYPE_ROOT):
if self._window_type == WindowManager.TYPE_ACTIVITY:
self._window.resize(DEFAULT_WIDTH, DEFAULT_HEIGHT)
else:
(width, height) = self._transform_dimensions()

574
shell/shell.py Executable file
View File

@ -0,0 +1,574 @@
import dbus
import dbus.service
import dbus.glib
import pygtk
pygtk.require('2.0')
import gtk
import pango
import gobject
import sugar.util
from sugar.chat.ChatWindow import ChatWindow
from sugar.chat.ActivityChat import ActivityChat
from sugar.chat.MeshChat import MeshChat
from sugar.LogWriter import LogWriter
from Owner import ShellOwner
from StartPage import StartPage
from WindowManager import WindowManager
from PresenceWindow import PresenceWindow
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):
if self.peer_service != None:
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()
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, 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)
self._presence_window.set_decorated(False)
self._presence_window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DOCK)
self._presence_window.set_skip_taskbar_hint(True)
wm = WindowManager(self._presence_window)
wm.set_width(170, WindowManager.ABSOLUTE)
wm.set_height(1.0, WindowManager.SCREEN_RELATIVE)
wm.set_position(WindowManager.LEFT)
wm.manage()
self._chat_window = ChatWindow()
self._chat_window.set_transient_for(self.window)
self._chat_window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DOCK)
self._chat_window.set_decorated(False)
self._chat_window.set_skip_taskbar_hint(True)
self._chat_wm = WindowManager(self._chat_window)
self._chat_wm.set_width(420, WindowManager.ABSOLUTE)
self._chat_wm.set_height(380, WindowManager.ABSOLUTE)
self._chat_wm.set_position(WindowManager.TOP)
self._chat_wm.manage()
self._mesh_chat = MeshChat()
def show(self):
self.window.show()
def set_current_activity(self, activity):
if self.current_activity != None:
self.current_activity.lost_focus()
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)
# For some reason the substitution screw up window position
self._chat_wm.update()
if self.current_activity != None:
self.current_activity.got_focus()
def notebook_tab_changed(self, notebook, page, page_number):
new_activity = notebook.get_nth_page(page_number).get_data("sugar-activity")
self.set_current_activity(new_activity)
def switch_to_activity(self, activity_id):
found = False
for owner, activity in self.activities:
if activity.get_host_activity_id() == activity_id:
found = True
break
if not found:
return
# Find the activity in the notebook
activity_page = None
npages = self.notebook.get_n_pages()
for pageno in range(1, npages):
activity = self.notebook.get_nth_page(pageno).get_data("sugar-activity")
if activity and activity.get_host_activity_id() == activity_id:
activity_page = pageno
break
if not activity_page:
return
print "switching to activity page %d" % activity_page
self.notebook.set_current_page(activity_page)
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()
def have_activity(self, activity_id):
for owner, activity in self.activities:
list_activity_id = activity.get_host_activity_id()
if activity_id == list_activity_id:
return True
return False
@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
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.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DOCK)
self._window.set_decorated(False)
self._window.set_skip_taskbar_hint(True)
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_width(0.7, WindowManager.SCREEN_RELATIVE)
console_wm.set_height(0.9, WindowManager.SCREEN_RELATIVE)
console_wm.set_position(WindowManager.BOTTOM)
console_wm.manage()
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)
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.set_width(640, WindowManager.ABSOLUTE)
wm.set_height(480, WindowManager.ABSOLUTE)
wm.set_position(WindowManager.CENTER)
wm.show()
wm.manage()
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

@ -68,8 +68,8 @@ class ActivityFactory(dbus.service.Object):
gobject.idle_add(self._start_activity_cb, activity, service)
@dbus.service.method("com.redhat.Sugar.ActivityFactory")
def create(self):
self.create_with_service(None, [])
def create(self, args):
self.create_with_service(None, args)
def _start_activity_cb(self, activity, service):
activity.connect_to_shell(service)
@ -84,21 +84,11 @@ def create(activity_name, service = None, args = None):
proxy_obj = bus.get_object(factory_name, factory_path)
factory = dbus.Interface(proxy_obj, "com.redhat.Sugar.ActivityFactory")
if service and args:
if service:
serialized_service = service.serialize(service)
factory.create_with_service(serialized_service, args)
else:
factory.create()
def _get_registry():
bus = dbus.SessionBus()
proxy_obj = bus.get_object("com.redhat.Sugar.ActivityRegistry",
"/com/redhat/Sugar/ActivityRegistry")
return dbus.Interface(proxy_obj, "com.redhat.Sugar.ActivityRegistry")
def list_activities():
registry = _get_registry()
return registry.list_activities()
factory.create(args)
def main(activity_name, activity_class):
"""Starts the activity main loop."""
@ -107,9 +97,6 @@ def main(activity_name, activity_class):
factory = ActivityFactory(activity_name, activity_class)
registry = _get_registry()
registry.add(activity_name, activity_name)
gtk.main()
class ActivityDbusService(dbus.service.Object):
@ -168,10 +155,10 @@ class ActivityDbusService(dbus.service.Object):
SHELL_SERVICE_NAME + ".ActivityContainer")
if service is None:
self._activity_id = self._activity_container.add_activity(self._activity.default_type())
self._activity_id = self._activity_container.add_activity("", self._activity.default_type())
else:
self._activity_id = service.get_activity_id()
self._activity_container.add_activity_with_id(self._activity.default_type(), self._activity_id)
self._activity_container.add_activity_with_id("", self._activity.default_type(), self._activity_id)
self._object_path = SHELL_SERVICE_PATH + "/Activities/%s" % self._activity_id
@ -236,12 +223,10 @@ class ActivityDbusService(dbus.service.Object):
def ActivityShared(self):
pass
class Activity(gtk.Window):
class Activity(object):
"""Base Activity class that all other Activities derive from."""
def __init__(self, default_type):
gtk.Window.__init__(self)
self._dbus_service = self._get_new_dbus_service()
self._dbus_service.register_callback(ON_CONNECTED_TO_SHELL_CB, self._internal_on_connected_to_shell_cb)
self._dbus_service.register_callback(ON_DISCONNECTED_FROM_SHELL_CB, self._internal_on_disconnected_from_shell_cb)
@ -251,6 +236,7 @@ class Activity(gtk.Window):
self._dbus_service.register_callback(ON_LOST_FOCUS_CB, self._internal_on_lost_focus_cb)
self._dbus_service.register_callback(ON_GOT_FOCUS_CB, self._internal_on_got_focus_cb)
self._has_focus = False
self._plug = None
self._initial_service = None
self._activity_object = None
self._shared = False
@ -259,6 +245,9 @@ class Activity(gtk.Window):
self._default_type = default_type
def _cleanup(self):
if self._plug:
self._plug.destroy()
self._plug = None
if self._dbus_service:
del self._dbus_service
self._dbus_service = None
@ -290,13 +279,15 @@ class Activity(gtk.Window):
def connect_to_shell(self, service = None):
"""Called by our controller to tell us to initialize and connect
to the shell."""
self.show()
self._dbus_service.connect_to_shell(service)
def _internal_on_connected_to_shell_cb(self, activity_object, activity_id, service=None):
"""Callback when the dbus service object has connected to the shell."""
self._activity_object = activity_object
self._activity_id = activity_id
self._window_id = self._activity_object.get_host_xembed_id()
print "Activity: XEMBED window ID is %s" % self._window_id
self._plug = gtk.Plug(self._window_id)
self._initial_service = service
if service:
self.set_shared()
@ -331,6 +322,10 @@ class Activity(gtk.Window):
self.set_has_changes(False)
self.on_got_focus()
def gtk_plug(self):
"""Return our GtkPlug widget."""
return self._plug
def set_ellipsize_tab(self, ellipsize):
"""Sets this Activity's tab text to be ellipsized or not."""
self._activity_object.set_ellipsize_tab(ellipsize)