Refactor dbus out of Activity objects so that we're sure when

This commit is contained in:
Dan Williams 2006-06-02 14:52:20 -04:00
parent f96fbfc10b
commit 4c7f15f694
5 changed files with 261 additions and 218 deletions

View File

@ -52,16 +52,18 @@ class BrowserActivity(activity.Activity):
self.set_mode(BrowserActivity.FOLLOWING)
self._model.add_listener(self.__shared_location_changed_cb)
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)
def on_connected_to_shell(self):
activity.Activity.on_connected_to_shell(self)
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()
self._notif_bar = NotificationBar()
self._notif_bar = NotificationBar.NotificationBar()
vbox.pack_start(self._notif_bar, False)
self._notif_bar.connect('action', self.__notif_bar_action_cb)
@ -72,11 +74,11 @@ class BrowserActivity(activity.Activity):
self.embed.show()
self.embed.load_address(self.uri)
nav_toolbar = NavigationToolbar(self)
nav_toolbar = NavigationToolbar.NavigationToolbar(self)
vbox.pack_start(nav_toolbar, False)
nav_toolbar.show()
plug = self.activity_get_gtk_plug()
plug = self.gtk_plug()
plug.add(vbox)
plug.show()
@ -104,10 +106,10 @@ class BrowserActivity(activity.Activity):
'">' + escaped_title + '</link></richtext>')
def __title_cb(self, embed):
self.activity_set_tab_text(embed.get_title())
self.set_tab_text(embed.get_title())
def __shared_location_changed_cb(self, model, key):
self.activity_set_has_changes(True)
self.set_has_changes(True)
self._notify_shared_location_change()
def _notify_shared_location_change(self):
@ -119,6 +121,3 @@ class BrowserActivity(activity.Activity):
self._notif_bar.set_action('goto_shared_location', 'Go There')
self._notif_bar.set_icon('stock_right')
self._notif_bar.show()
def activity_on_close_from_user(self):
self.activity_shutdown()

View File

@ -1,5 +1,6 @@
import dbus
import geckoembed
import threading
import sugar.env
@ -9,12 +10,14 @@ from sugar.browser.BrowserActivity import BrowserActivity
class BrowserShell(dbus.service.Object):
instance = None
_lock = threading.Lock()
def get_instance():
BrowserShell._lock.acquire()
if not BrowserShell.instance:
BrowserShell.instance = BrowserShell()
BrowserShell._lock.release()
return BrowserShell.instance
get_instance = staticmethod(get_instance)
def __init__(self):
@ -31,7 +34,7 @@ class BrowserShell(dbus.service.Object):
def open_web_activity(self):
web_activity = WebActivity(self)
web_activity.activity_connect_to_shell()
web_activity.connect_to_shell()
@dbus.service.method('com.redhat.Sugar.BrowserShell')
def get_links(self):
@ -48,4 +51,4 @@ class BrowserShell(dbus.service.Object):
def open_browser(self, uri):
browser = BrowserActivity(self._group, uri)
self.__browsers.append(browser)
browser.activity_connect_to_shell()
browser.connect_to_shell()

View File

@ -24,10 +24,12 @@ class WebActivity(activity.Activity):
activity.Activity.__init__(self)
self._shell = shell
def activity_on_connected_to_shell(self):
self.activity_set_tab_text("Web")
self.activity_set_tab_icon_name("web-browser")
self.activity_show_icon(True)
def on_connected_to_shell(self):
activity.Activity.on_connected_to_shell(self)
self.set_tab_text("Web")
self.set_tab_icon(name="web-browser")
self.set_show_tab_icon(True)
vbox = gtk.VBox()
@ -40,7 +42,7 @@ class WebActivity(activity.Activity):
vbox.pack_start(address_toolbar, False)
address_toolbar.show()
plug = self.activity_get_gtk_plug()
plug = self.gtk_plug()
plug.add(vbox)
plug.show()
@ -55,5 +57,6 @@ class WebActivity(activity.Activity):
self._shell.open_browser(uri)
return True
def activity_on_disconnected_from_shell(self):
def on_disconnected_from_shell(self):
activity.Activity.on_disconnected_from_shell(self)
gtk.main_quit()

View File

@ -6,6 +6,7 @@ import sha
import dbus
import dbus.service
import dbus.glib
import threading
import pygtk
pygtk.require('2.0')
@ -48,9 +49,10 @@ class Chat(activity.Activity):
proxy_obj = bus.get_object('com.redhat.Sugar.Browser', '/com/redhat/Sugar/Browser')
self._browser_shell = dbus.Interface(proxy_obj, 'com.redhat.Sugar.BrowserShell')
def activity_on_connected_to_shell(self):
self.activity_set_tab_text(self._act_name)
self._plug = self.activity_get_gtk_plug()
def on_connected_to_shell(self):
activity.Activity.on_connected_to_shell(self)
self.set_tab_text(self._act_name)
self._ui_setup(self._plug)
self._plug.show_all()
@ -276,10 +278,6 @@ class Chat(activity.Activity):
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 _scroll_chat_view_to_bottom(self):
# Only scroll to bottom if the view is already close to the bottom
vadj = self._chat_sw.get_vadjustment()
@ -434,18 +432,18 @@ class BuddyChat(Chat):
self._act_name = "Chat: %s" % buddy.get_nick_name()
Chat.__init__(self, controller)
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)
def on_connected_to_shell(self):
Chat.on_connected_to_shell(self)
self.set_can_close(True)
self.set_tab_icon(icon_name="im")
self.set_show_tab_icon(True)
self._stream_writer = self._controller.new_buddy_writer(self._buddy)
def recv_message(self, sender, msg):
Chat.recv_message(self, self._buddy, msg)
def activity_on_close_from_user(self):
Chat.activity_on_close_from_user(self)
def on_close_from_user(self):
Chat.on_close_from_user(self)
del self._chats[self._buddy]
@ -573,16 +571,16 @@ class GroupChat(Chat):
self._plug.show_all()
def activity_on_connected_to_shell(self):
Chat.activity_on_connected_to_shell(self)
def on_connected_to_shell(self):
Chat.on_connected_to_shell(self)
self.activity_set_tab_icon_name("stock_help-chat")
self.activity_show_icon(True)
self.set_tab_icon(name="stock_help-chat")
self.set_show_tab_icon(True)
self._start()
def activity_on_disconnected_from_shell(self):
Chat.activity_on_disconnected_from_shell(self)
def on_disconnected_from_shell(self):
Chat.on_disconnected_from_shell(self)
gtk.main_quit()
def _on_buddyList_buddy_selected(self, widget, *args):
@ -669,30 +667,37 @@ class GroupChat(Chat):
chat = self._chats[buddy]
chat.recv_message(buddy, 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):
class ChatShellDbusService(dbus.service.Object):
def __init__(self, parent):
self._parent = parent
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):
self._group_chat = GroupChat()
self._group_chat.activity_connect_to_shell()
@dbus.service.method('com.redhat.Sugar.ChatShell')
def send_text_message(self, message):
self._group_chat.send_text_message(message)
self._parent.send_text_message(message)
class ChatShell(object):
instance = None
_lock = threading.Lock()
def get_instance():
ChatShell._lock.acquire()
if not ChatShell.instance:
ChatShell.instance = ChatShell()
ChatShell._lock.release()
return ChatShell.instance
get_instance = staticmethod(get_instance)
def open_group_chat(self):
self._group_chat = GroupChat()
self._group_chat.connect_to_shell()
def send_text_message(self, message):
self._group_chat.send_text_message(message)
log_writer = LogWriter("Chat")
log_writer.start()

View File

@ -7,183 +7,216 @@ import pygtk
pygtk.require('2.0')
import gtk
SHELL_SERVICE_NAME = "com.redhat.Sugar.Shell"
SHELL_SERVICE_PATH = "/com/redhat/Sugar/Shell"
class Activity(dbus.service.Object):
""" Base Sugar activity object from which all other Activities should inherit """
ACTIVITY_SERVICE_NAME = "com.redhat.Sugar.Activity"
ACTIVITY_SERVICE_PATH = "/com/redhat/Sugar/Activity"
def __init__(self):
self._has_focus = False
def get_has_focus(self):
return self._has_focus
class ActivityDbusService(dbus.service.Object):
"""Base dbus service object that each Activity uses to export dbus methods.
The dbus service is separate from the actual Activity object so that we can
tightly control what stuff passes through the dbus python bindings."""
def __init__(self, activity):
self._activity = activity
self._activity_id = None
self._activity_object = None
self._service = None
self._bus = dbus.SessionBus()
self._bus.add_signal_receiver(self.name_owner_changed, dbus_interface = "org.freedesktop.DBus", signal_name = "NameOwnerChanged")
def __del__(self):
if self._activity_id:
del self._service
del self._activity_container
del self._activity_conainer_object
del self._activity_object
self._bus.remove_signal_receiver(self.name_owner_changed, dbus_interface="org.freedesktop.DBus", signal_name="NameOwnerChanged")
del self._bus
def connect_to_shell(self):
"""Register with the shell via dbus, getting an activity ID and
and XEMBED window ID in which to display the Activity."""
self._activity_container_object = self._bus.get_object(SHELL_SERVICE_NAME, \
SHELL_SERVICE_PATH + "/ActivityContainer")
self._activity_container = dbus.Interface(self._activity_container_object, \
SHELL_SERVICE_NAME + ".ActivityContainer")
self._activity_id = self._activity_container.add_activity("")
self._object_path = SHELL_SERVICE_PATH + "/Activities/%d" % self._activity_id
print "ActivityDbusService: object path is '%s'" % self._object_path
self._activity_object = dbus.Interface(self._bus.get_object(SHELL_SERVICE_NAME, self._object_path), \
SHELL_SERVICE_NAME + ".ActivityHost")
# Now let us register a peer service so the Shell can poke it
self._peer_service_name = ACTIVITY_SERVICE_NAME + "%d" % self._activity_id
self._peer_object_path = ACTIVITY_SERVICE_PATH + "/%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_path)
self._activity_object.set_peer_service_name(self._peer_service_name, self._peer_object_path)
return (self._activity_object, self._activity_id)
def _shutdown_reply_cb(self):
"""Shutdown was successful, tell the Activity that we're disconnected."""
self._activity.on_disconnected_from_shell()
def _shutdown_error_cb(self, error):
print "ActivityDbusService: error during shutdown - '%s'" % error
def shutdown(self):
"""Notify the shell that we are shutting down."""
self._activity_object.shutdown(reply_handler=self._shutdown_reply_cb, error_handler=self._shutdown_error_cb)
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()
"""Handle dbus NameOwnerChanged signals."""
if not self._activity_id:
# Do nothing if we're not connected yet
return
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_has_changes(self, has_changes):
if not self.get_has_focus() and has_changes:
self.__activity_object.set_has_changes(True)
else:
self.__activity_object.set_has_changes(False)
@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)
if icon_info:
pixbuf = icon_info.load_icon()
scaled_pixbuf = pixbuf.scale_simple(16, 16, gtk.gdk.INTERP_BILINEAR)
self.activity_set_icon(scaled_pixbuf)
@dbus.service.method("com.redhat.Sugar.Activity", \
in_signature="", \
out_signature="")
if service_name == SHELL_SERVICE_NAME and not len(new_service_name):
self._activity.on_disconnected_from_shell()
elif service_name == SHELL_SERVICE_NAME and not len(old_service_name):
self._activity.on_reconnected_to_shell()
@dbus.service.method(ACTIVITY_SERVICE_NAME)
def lost_focus(self):
self.activity_on_lost_focus()
"""Called by the shell to notify us that we've lost focus."""
self._activity.on_lost_focus()
@dbus.service.method("com.redhat.Sugar.Activity", \
in_signature="", \
out_signature="")
@dbus.service.method(ACTIVITY_SERVICE_NAME)
def got_focus(self):
self.activity_on_got_focus()
"""Called by the shell to notify us that the user gave us focus."""
self._activity.on_got_focus()
@dbus.service.method("com.redhat.Sugar.Activity", \
in_signature="", \
out_signature="")
@dbus.service.method(ACTIVITY_SERVICE_NAME)
def close_from_user(self):
self.activity_on_close_from_user()
"""Called by the shell to notify us that the user closed us."""
self._activity.on_close_from_user()
class Activity(object):
"""Base Activity class that all other Activities derive from."""
def __init__(self):
self._dbus_service = self._get_new_dbus_service()
self._has_focus = False
self._plug = None
self._activity_object = None
def _cleanup(self):
if self._plug:
self._plug.destroy()
self._plug = None
if self._dbus_service:
del self._dbus_service
self._dbus_service = None
def __del__(self):
self._cleanup()
def _get_new_dbus_service(self):
"""Create and return a new dbus service object for this Activity.
Allows subclasses to use their own dbus service object if they choose."""
return ActivityDbusService(self)
def has_focus(self):
"""Return whether or not this Activity is visible to the user."""
return self._has_focus
def connect_to_shell(self):
"""Called by our controller to tell us to initialize and connect
to the shell."""
(self._activity_object, self._activity_id) = self._dbus_service.connect_to_shell()
self.on_connected_to_shell()
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)
def set_tab_text(self, text):
"""Sets this Activity's tab text."""
self._activity_object.set_tab_text(text)
def set_can_close(self, can_close):
"""Sets whether or not this Activity can be closed by the user."""
self._activity_object.set_can_close(can_close)
def set_show_tab_icon(self, show_icon):
"""Sets whether or not an icon is shown in this Activity's tab."""
self._activity_object.set_tab_show_icon(show_icon)
def set_tab_icon(self, pixbuf=None, name=None):
"""Set the Activity's tab icon, either from pixbuf data
or by an icon theme icon name."""
if name:
icon_theme = gtk.icon_theme_get_default()
icon_info = icon_theme.lookup_icon(name, gtk.ICON_SIZE_MENU, 0)
if icon_info:
orig_pixbuf = icon_info.load_icon()
pixbuf = orig_pixbuf.scale_simple(16, 16, gtk.gdk.INTERP_BILINEAR)
if pixbuf:
# Dump the pixel data into an array and shove it through dbus
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())
def set_has_changes(self, has_changes):
"""Marks this Activity as having changes. This usually means
that this Activity's tab turns a red color or something else
to notify the user that this Activity needs attention."""
if not self.get_has_focus() and has_changes:
self._activity_object.set_has_changes(True)
else:
self._activity_object.set_has_changes(False)
def activity_get_id(self):
return self.__activity_id
return self._activity_id
def shutdown(self):
"""Disconnect from the shell and clean up."""
self._dbus_service.shutdown()
def __shutdown_reply_cb(self):
print "in __reply_cb"
self.__plug.destroy()
self.__plug = 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()
self.__bus = None
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)
def activity_on_lost_focus(self):
def on_lost_focus(self):
"""Triggered when this Activity loses focus."""
self._has_focus = False;
def activity_on_got_focus(self):
print 'got focus'
def on_got_focus(self):
"""Triggered when this Activity gets focus."""
self._has_focus = True
self.activity_set_has_changes(False)
self.set_has_changes(False)
# pure virtual methods
def on_disconnected_from_shell(self):
"""Triggered when we disconnect from the shell."""
self._cleanup()
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 on_reconnected_to_shell(self):
"""Triggered when the shell's service comes back."""
pass
def activity_on_close_from_user(self):
print "act %d: you need to override activity_on_close_from_user" % self.activity_get_id()
def on_connected_to_shell(self):
"""Triggered when this Activity has successfully connected to the shell."""
self._window_id = self._activity_object.get_host_xembed_id()
print "Activity: XEMBED window ID is %d" % self._window_id
self._plug = gtk.Plug(self._window_id)
def on_close_from_user(self):
"""Triggered when this Activity is closed by the user."""
self.shutdown()