From a45e7239135c6bc143e8ba5efbdb05eb69155372 Mon Sep 17 00:00:00 2001 From: Tomeu Vizoso Date: Tue, 04 Nov 2008 16:31:44 +0000 Subject: Initial implementation of activity notifications --- diff --git a/bin/sugar-session b/bin/sugar-session index d431312..12e1f9e 100644 --- a/bin/sugar-session +++ b/bin/sugar-session @@ -130,6 +130,10 @@ def show_software_updates_cb(home_window): if os.path.isfile(os.path.expanduser('~/.sugar-update')): home_window.get_home_box().show_software_updates_alert() +def setup_notification_service_cb(): + from jarabe.model import notifications + notifications.init() + def main(): cleanup_logs() logger.start('shell') @@ -165,6 +169,7 @@ def main(): gobject.idle_add(setup_frame_cb) gobject.idle_add(setup_keyhandler_cb) gobject.idle_add(setup_journal_cb) + gobject.idle_add(setup_notification_service_cb) gobject.idle_add(show_software_updates_cb, home_window) try: diff --git a/src/jarabe/frame/frame.py b/src/jarabe/frame/frame.py index a1daced..6ba8814 100644 --- a/src/jarabe/frame/frame.py +++ b/src/jarabe/frame/frame.py @@ -23,6 +23,7 @@ import hippo from sugar.graphics import animator from sugar.graphics import style from sugar.graphics import palettegroup +from sugar import profile from jarabe.frame.eventarea import EventArea from jarabe.frame.activitiestray import ActivitiesTray @@ -32,6 +33,7 @@ from jarabe.frame.devicestray import DevicesTray from jarabe.frame.framewindow import FrameWindow from jarabe.frame.clipboardpanelwindow import ClipboardPanelWindow from jarabe.frame.notification import NotificationIcon, NotificationWindow +from jarabe.model import notifications TOP_RIGHT = 0 TOP_LEFT = 1 @@ -125,9 +127,17 @@ class Frame(object): self._notif_by_icon = {} + notification_service = notifications.get_service() + notification_service.notification_received.connect( + self.__notification_received_cb) + notification_service.notification_cancelled.connect( + self.__notification_cancelled_cb) + def is_visible(self): return self.current_position != 0.0 + visible = property(is_visible, None) + def hide(self): if self._animator: self._animator.stop() @@ -276,7 +286,9 @@ class Frame(object): def notify_key_press(self): self._key_listener.key_press() - def add_notification(self, icon, corner=gtk.CORNER_TOP_LEFT): + def add_notification(self, icon, corner=gtk.CORNER_TOP_LEFT, + duration=_NOTIFICATION_DURATION): + if not isinstance(icon, NotificationIcon): raise TypeError('icon must be a NotificationIcon.') @@ -301,7 +313,7 @@ class Frame(object): self._notif_by_icon[icon] = window - gobject.timeout_add(_NOTIFICATION_DURATION, + gobject.timeout_add(duration, lambda: self.remove_notification(icon)) def remove_notification(self, icon): @@ -316,4 +328,31 @@ class Frame(object): window.destroy() del self._notif_by_icon[icon] - visible = property(is_visible, None) + def __notification_received_cb(self, **kwargs): + logging.debug('__notification_received_cb %r' % kwargs) + icon = NotificationIcon() + + hints = kwargs['hints'] + + icon_file_name = hints.get('x-sugar-icon-file-name', '') + if icon_file_name: + icon.props.icon_filename = icon_file_name + else: + icon.props.icon_name = 'application-octet-stream' + + icon_colors = hints.get('x-sugar-icon-colors', '') + if not icon_colors: + icon_colors = profile.get_color() + icon.props.xo_color = icon_colors + + duration = kwargs.get('expire_timeout', -1) + if duration == -1: + duration = _NOTIFICATION_DURATION + + self.add_notification(icon, gtk.CORNER_TOP_RIGHT, duration) + + def __notification_cancelled_cb(self, **kwargs): + # Do nothing for now. Our notification UI is so simple, there's no + # point yet. + pass + diff --git a/src/jarabe/model/Makefile.am b/src/jarabe/model/Makefile.am index 9ab6779..71ba988 100644 --- a/src/jarabe/model/Makefile.am +++ b/src/jarabe/model/Makefile.am @@ -8,6 +8,7 @@ sugar_PYTHON = \ owner.py \ neighborhood.py \ network.py \ + notifications.py \ shell.py \ screen.py \ session.py \ diff --git a/src/jarabe/model/notifications.py b/src/jarabe/model/notifications.py new file mode 100644 index 0000000..da5c590 --- /dev/null +++ b/src/jarabe/model/notifications.py @@ -0,0 +1,95 @@ +# Copyright (C) 2008 One Laptop Per Child +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +import sys +import logging + +import dbus + +from sugar import dispatch + +from jarabe import config + +_DBUS_SERVICE = "org.freedesktop.Notifications" +_DBUS_IFACE = "org.freedesktop.Notifications" +_DBUS_PATH = "/org/freedesktop/Notifications" + +class NotificationService(dbus.service.Object): + def __init__(self): + bus = dbus.SessionBus() + bus_name = dbus.service.BusName(_DBUS_SERVICE, bus=bus) + dbus.service.Object.__init__(self, bus_name, _DBUS_PATH) + + self._notification_counter = 0 + self.notification_received = dispatch.Signal() + self.notification_cancelled = dispatch.Signal() + + @dbus.service.method(_DBUS_IFACE, + in_signature='susssava{sv}i', out_signature='u') + def Notify(self, app_name, replaces_id, app_icon, summary, body, actions, + hints, expire_timeout): + + logging.debug('Received notification: %r' % ([app_name, replaces_id, + app_icon, summary, body, actions, hints, expire_timeout])) + + if replaces_id > 0: + notification_id = replaces_id + else: + if self._notification_counter == sys.maxint: + self._notification_counter = 1 + else: + self._notification_counter += 1 + notification_id = self._notification_counter + + self.notification_received.send(self, app_name=app_name, + replaces_id=replaces_id, app_icon=app_icon, summary=summary, + body=body, actions=actions, hints=hints, + expire_timeout=expire_timeout) + + return notification_id + + @dbus.service.method(_DBUS_IFACE, in_signature='u', out_signature='') + def CloseNotification(self, notification_id): + self.notification_cancelled.send(self, notification_id=notification_id) + + @dbus.service.method(_DBUS_IFACE, in_signature='', out_signature='as') + def GetCapabilities(self): + return [] + + @dbus.service.method(_DBUS_IFACE, in_signature='', out_signature='sss') + def GetServerInformation(self, name, vendor, version): + return 'Sugar Shell', 'Sugar', config.version + + + @dbus.service.signal(_DBUS_IFACE, signature="uu") + def NotificationClosed(self, notification_id, reason): + pass + + @dbus.service.signal(_DBUS_IFACE, signature="us") + def ActionInvoked(self, notification_id, action_key): + pass + +_instance = None + +def get_service(): + global _instance + if not _instance: + _instance = NotificationService() + return _instance + +def init(): + get_service() + -- cgit v0.9.1