add XEP-0224 support (/attention command, persistant popup and special sound). F

ixes #3465
This commit is contained in:
Yann Leboulanger 2012-04-09 13:38:28 +02:00
parent 51cfe177a1
commit 75c495979c
12 changed files with 86 additions and 44 deletions

BIN
data/sounds/attention.wav Normal file

Binary file not shown.

View file

@ -863,7 +863,7 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
def send_message(self, message, keyID='', type_='chat', chatstate=None, def send_message(self, message, keyID='', type_='chat', chatstate=None,
msg_id=None, resource=None, xhtml=None, callback=None, callback_args=[], msg_id=None, resource=None, xhtml=None, callback=None, callback_args=[],
process_commands=True): process_commands=True, attention=False):
""" """
Send the given message to the active tab. Doesn't return None if error Send the given message to the active tab. Doesn't return None if error
""" """
@ -880,7 +880,7 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
keyID=keyID, type_=type_, chatstate=chatstate, msg_id=msg_id, keyID=keyID, type_=type_, chatstate=chatstate, msg_id=msg_id,
resource=resource, user_nick=self.user_nick, xhtml=xhtml, resource=resource, user_nick=self.user_nick, xhtml=xhtml,
label=label, callback=callback, callback_args=callback_args, label=label, callback=callback, callback_args=callback_args,
control=self)) control=self, attention=attention))
# Record the history of sent messages # Record the history of sent messages
self.save_message(message, 'sent') self.save_message(message, 'sent')
@ -2235,7 +2235,7 @@ class ChatControl(ChatControlBase):
dialogs.ESessionInfoWindow(self.session) dialogs.ESessionInfoWindow(self.session)
def send_message(self, message, keyID='', chatstate=None, xhtml=None, def send_message(self, message, keyID='', chatstate=None, xhtml=None,
process_commands=True): process_commands=True, attention=False):
""" """
Send a message to contact Send a message to contact
""" """
@ -2286,7 +2286,8 @@ class ChatControl(ChatControlBase):
ChatControlBase.send_message(self, message, keyID, type_='chat', ChatControlBase.send_message(self, message, keyID, type_='chat',
chatstate=chatstate_to_send, xhtml=xhtml, callback=_on_sent, chatstate=chatstate_to_send, xhtml=xhtml, callback=_on_sent,
callback_args=[contact, message, encrypted, xhtml, callback_args=[contact, message, encrypted, xhtml,
self.get_seclabel()], process_commands=process_commands) self.get_seclabel()], process_commands=process_commands,
attention=attention)
def check_for_possible_paused_chatstate(self, arg): def check_for_possible_paused_chatstate(self, arg):
""" """

View file

@ -230,6 +230,11 @@ class StandardCommonChatCommands(CommandContainer):
state = self._video_button.get_active() state = self._video_button.get_active()
self._video_button.set_active(not state) self._video_button.set_active(not state)
@command(raw=True)
@doc(_("Send a message to the contact that will attract his (her) attention"))
def attention(self, message):
self.send_message(message, process_commands=False, attention=True)
class StandardChatCommands(CommandContainer): class StandardChatCommands(CommandContainer):
""" """
This command container contains standard commands which are unique This command container contains standard commands which are unique

View file

@ -300,6 +300,7 @@ class Config:
'stun_server': [opt_str, '', _('STUN server to use when using jingle')], 'stun_server': [opt_str, '', _('STUN server to use when using jingle')],
'show_affiliation_in_groupchat': [opt_bool, True, _('If True, Gajim will show affiliation of groupchat occupants by adding a colored square to the status icon')], 'show_affiliation_in_groupchat': [opt_bool, True, _('If True, Gajim will show affiliation of groupchat occupants by adding a colored square to the status icon')],
'global_proxy': [opt_str, '', _('Proxy used for all outgoing connections if the account does not have a specific proxy configured')], 'global_proxy': [opt_str, '', _('Proxy used for all outgoing connections if the account does not have a specific proxy configured')],
'ignore_incoming_attention': [opt_bool, False, _('If True, Gajim will ignore incoming attention requestd ("wizz").')],
} }
__options_per_key = { __options_per_key = {
@ -497,6 +498,7 @@ class Config:
} }
soundevents_default = { soundevents_default = {
'attention_received': [True, 'attention.wav'],
'first_message_received': [ True, 'message1.wav' ], 'first_message_received': [ True, 'message1.wav' ],
'next_message_received_focused': [ True, 'message2.wav' ], 'next_message_received_focused': [ True, 'message2.wav' ],
'next_message_received_unfocused': [ True, 'message2.wav' ], 'next_message_received_unfocused': [ True, 'message2.wav' ],

View file

@ -253,7 +253,7 @@ class CommonConnection:
def _prepare_message(self, jid, msg, keyID, type_='chat', subject='', def _prepare_message(self, jid, msg, keyID, type_='chat', subject='',
chatstate=None, msg_id=None, resource=None, user_nick=None, xhtml=None, chatstate=None, msg_id=None, resource=None, user_nick=None, xhtml=None,
session=None, forward_from=None, form_node=None, label=None, session=None, forward_from=None, form_node=None, label=None,
original_message=None, delayed=None, callback=None): original_message=None, delayed=None, attention=False, callback=None):
if not self.connection or self.connected < 2: if not self.connection or self.connected < 2:
return 1 return 1
try: try:
@ -304,7 +304,8 @@ class CommonConnection:
msgtxt, original_message, fjid, resource, msgtxt, original_message, fjid, resource,
jid, xhtml, subject, chatstate, msg_id, jid, xhtml, subject, chatstate, msg_id,
label, forward_from, delayed, session, label, forward_from, delayed, session,
form_node, user_nick, keyID, callback) form_node, user_nick, keyID, attention,
callback)
gajim.nec.push_incoming_event(GPGTrustKeyEvent(None, gajim.nec.push_incoming_event(GPGTrustKeyEvent(None,
conn=self, callback=_on_always_trust)) conn=self, callback=_on_always_trust))
else: else:
@ -312,7 +313,7 @@ class CommonConnection:
original_message, fjid, resource, jid, xhtml, original_message, fjid, resource, jid, xhtml,
subject, chatstate, msg_id, label, forward_from, subject, chatstate, msg_id, label, forward_from,
delayed, session, form_node, user_nick, keyID, delayed, session, form_node, user_nick, keyID,
callback) attention, callback)
gajim.thread_interface(encrypt_thread, [msg, keyID, False], gajim.thread_interface(encrypt_thread, [msg, keyID, False],
_on_encrypted, []) _on_encrypted, [])
return return
@ -320,18 +321,18 @@ class CommonConnection:
self._message_encrypted_cb(('', error), type_, msg, msgtxt, self._message_encrypted_cb(('', error), type_, msg, msgtxt,
original_message, fjid, resource, jid, xhtml, subject, original_message, fjid, resource, jid, xhtml, subject,
chatstate, msg_id, label, forward_from, delayed, session, chatstate, msg_id, label, forward_from, delayed, session,
form_node, user_nick, keyID, callback) form_node, user_nick, keyID, attention, callback)
return return
self._on_continue_message(type_, msg, msgtxt, original_message, fjid, self._on_continue_message(type_, msg, msgtxt, original_message, fjid,
resource, jid, xhtml, subject, msgenc, keyID, chatstate, msg_id, resource, jid, xhtml, subject, msgenc, keyID, chatstate, msg_id,
label, forward_from, delayed, session, form_node, user_nick, label, forward_from, delayed, session, form_node, user_nick,
callback) attention, callback)
def _message_encrypted_cb(self, output, type_, msg, msgtxt, def _message_encrypted_cb(self, output, type_, msg, msgtxt,
original_message, fjid, resource, jid, xhtml, subject, chatstate, msg_id, original_message, fjid, resource, jid, xhtml, subject, chatstate, msg_id,
label, forward_from, delayed, session, form_node, user_nick, keyID, label, forward_from, delayed, session, form_node, user_nick, keyID,
callback): attention, callback):
msgenc, error = output msgenc, error = output
if msgenc and not error: if msgenc and not error:
@ -344,7 +345,7 @@ class CommonConnection:
self._on_continue_message(type_, msg, msgtxt, original_message, self._on_continue_message(type_, msg, msgtxt, original_message,
fjid, resource, jid, xhtml, subject, msgenc, keyID, fjid, resource, jid, xhtml, subject, msgenc, keyID,
chatstate, msg_id, label, forward_from, delayed, session, chatstate, msg_id, label, forward_from, delayed, session,
form_node, user_nick, callback) form_node, user_nick, attention, callback)
return return
# Encryption failed, do not send message # Encryption failed, do not send message
tim = localtime() tim = localtime()
@ -353,7 +354,8 @@ class CommonConnection:
def _on_continue_message(self, type_, msg, msgtxt, original_message, fjid, def _on_continue_message(self, type_, msg, msgtxt, original_message, fjid,
resource, jid, xhtml, subject, msgenc, keyID, chatstate, msg_id, resource, jid, xhtml, subject, msgenc, keyID, chatstate, msg_id,
label, forward_from, delayed, session, form_node, user_nick, callback): label, forward_from, delayed, session, form_node, user_nick, attention,
callback):
if type_ == 'chat': if type_ == 'chat':
msg_iq = common.xmpp.Message(to=fjid, body=msgtxt, typ=type_, msg_iq = common.xmpp.Message(to=fjid, body=msgtxt, typ=type_,
xhtml=xhtml) xhtml=xhtml)
@ -424,6 +426,10 @@ class CommonConnection:
if session.enable_encryption: if session.enable_encryption:
msg_iq = session.encrypt_stanza(msg_iq) msg_iq = session.encrypt_stanza(msg_iq)
# XEP-0224
if attention:
msg_iq.setTag('attention', namespace=common.xmpp.NS_ATTENTION)
if callback: if callback:
callback(jid, msg, keyID, forward_from, session, original_message, callback(jid, msg, keyID, forward_from, session, original_message,
subject, type_, msg_iq, xhtml) subject, type_, msg_iq, xhtml)
@ -1794,8 +1800,8 @@ class Connection(CommonConnection, ConnectionHandlers):
def send_message(self, jid, msg, keyID=None, type_='chat', subject='', def send_message(self, jid, msg, keyID=None, type_='chat', subject='',
chatstate=None, msg_id=None, resource=None, user_nick=None, xhtml=None, chatstate=None, msg_id=None, resource=None, user_nick=None, xhtml=None,
label=None, session=None, forward_from=None, form_node=None, label=None, session=None, forward_from=None, form_node=None,
original_message=None, delayed=None, callback=None, callback_args=[], original_message=None, delayed=None, attention=False, callback=None,
now=False): callback_args=[], now=False):
def cb(jid, msg, keyID, forward_from, session, original_message, def cb(jid, msg, keyID, forward_from, session, original_message,
subject, type_, msg_iq, xhtml): subject, type_, msg_iq, xhtml):
@ -1813,7 +1819,8 @@ class Connection(CommonConnection, ConnectionHandlers):
chatstate=chatstate, msg_id=msg_id, resource=resource, chatstate=chatstate, msg_id=msg_id, resource=resource,
user_nick=user_nick, xhtml=xhtml, label=label, session=session, user_nick=user_nick, xhtml=xhtml, label=label, session=session,
forward_from=forward_from, form_node=form_node, forward_from=forward_from, form_node=form_node,
original_message=original_message, delayed=delayed, callback=cb) original_message=original_message, delayed=delayed,
attention=attention, callback=cb)
def _nec_message_outgoing(self, obj): def _nec_message_outgoing(self, obj):
if obj.account != self.name: if obj.account != self.name:
@ -1838,7 +1845,7 @@ class Connection(CommonConnection, ConnectionHandlers):
resource=obj.resource, user_nick=obj.user_nick, xhtml=obj.xhtml, resource=obj.resource, user_nick=obj.user_nick, xhtml=obj.xhtml,
label=obj.label, session=obj.session, forward_from=obj.forward_from, label=obj.label, session=obj.session, forward_from=obj.forward_from,
form_node=obj.form_node, original_message=obj.original_message, form_node=obj.form_node, original_message=obj.original_message,
delayed=obj.delayed, callback=cb) delayed=obj.delayed, attention=obj.attention, callback=cb)
def send_contacts(self, contacts, jid): def send_contacts(self, contacts, jid):
""" """

View file

@ -1192,6 +1192,7 @@ class DecryptedMessageReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
self.sent = self.msg_obj.sent self.sent = self.msg_obj.sent
self.popup = False self.popup = False
self.msg_id = None # id in log database self.msg_id = None # id in log database
self.attention = False # XEP-0224
self.receipt_request_tag = self.stanza.getTag('request', self.receipt_request_tag = self.stanza.getTag('request',
namespace=xmpp.NS_RECEIPTS) namespace=xmpp.NS_RECEIPTS)
@ -1206,6 +1207,9 @@ class DecryptedMessageReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
if self.seclabel: if self.seclabel:
self.displaymarking = self.seclabel.getTag('displaymarking') self.displaymarking = self.seclabel.getTag('displaymarking')
if self.stanza.getTag('attention', namespace=xmpp.NS_ATTENTION):
self.attention = True
self.form_node = self.stanza.getTag('x', namespace=xmpp.NS_DATA) self.form_node = self.stanza.getTag('x', namespace=xmpp.NS_DATA)
if gajim.config.get('ignore_incoming_xhtml'): if gajim.config.get('ignore_incoming_xhtml'):
@ -2062,7 +2066,19 @@ class NotificationEvent(nec.NetworkIncomingEvent):
# we're online or chat # we're online or chat
self.do_popup = True self.do_popup = True
if self.first_unread and helpers.allow_sound_notification( if msg_obj.attention and not gajim.config.get(
'ignore_incoming_attention'):
self.popup_timeout = 0
self.do_popup = True
else:
self.popup_timeout = gajim.config.get('notification_timeout')
if msg_obj.attention and not gajim.config.get(
'ignore_incoming_attention') and gajim.config.get_per('soundevents',
'attention_received', 'enabled'):
self.sound_event = 'attention_received'
self.do_sound = True
elif self.first_unread and helpers.allow_sound_notification(
self.conn.name, 'first_message_received'): self.conn.name, 'first_message_received'):
self.do_sound = True self.do_sound = True
elif not self.first_unread and self.control_focused and \ elif not self.first_unread and self.control_focused and \
@ -2175,6 +2191,8 @@ class NotificationEvent(nec.NetworkIncomingEvent):
self.popup_image = gtkgui_helpers.get_path_to_generic_or_avatar( self.popup_image = gtkgui_helpers.get_path_to_generic_or_avatar(
img_path, jid=self.jid, suffix=suffix) img_path, jid=self.jid, suffix=suffix)
self.popup_timeout = gajim.config.get('notification_timeout')
if event == 'status_change': if event == 'status_change':
self.popup_title = _('%(nick)s Changed Status') % \ self.popup_title = _('%(nick)s Changed Status') % \
{'nick': gajim.get_name_from_jid(account, self.jid)} {'nick': gajim.get_name_from_jid(account, self.jid)}
@ -2219,6 +2237,7 @@ class NotificationEvent(nec.NetworkIncomingEvent):
self.popup_event_type = '' self.popup_event_type = ''
self.popup_msg_type = '' self.popup_msg_type = ''
self.popup_image = '' self.popup_image = ''
self.popup_timeout = -1
self.do_command = False self.do_command = False
self.command = '' self.command = ''
@ -2261,6 +2280,7 @@ class MessageOutgoingEvent(nec.NetworkOutgoingEvent):
self.now = False self.now = False
self.is_loggable = True self.is_loggable = True
self.control = None self.control = None
self.attention = False
def generate(self): def generate(self):
return True return True

View file

@ -40,6 +40,7 @@ NS_ARCHIVE_MANAGE = NS_ARCHIVE + ':manage' # XEP-0136
NS_ARCHIVE_MANUAL = NS_ARCHIVE + ':manual' # XEP-0136 NS_ARCHIVE_MANUAL = NS_ARCHIVE + ':manual' # XEP-0136
NS_ARCHIVE_PREF = NS_ARCHIVE + ':pref' NS_ARCHIVE_PREF = NS_ARCHIVE + ':pref'
NS_ATOM = 'http://www.w3.org/2005/Atom' NS_ATOM = 'http://www.w3.org/2005/Atom'
NS_ATTENTION = 'urn:xmpp:attention:0' # XEP-0224
NS_AUTH = 'jabber:iq:auth' NS_AUTH = 'jabber:iq:auth'
NS_AVATAR = 'http://www.xmpp.org/extensions/xep-0084.html#ns-metadata' NS_AVATAR = 'http://www.xmpp.org/extensions/xep-0084.html#ns-metadata'
NS_BIND = 'urn:ietf:params:xml:ns:xmpp-bind' NS_BIND = 'urn:ietf:params:xml:ns:xmpp-bind'

View file

@ -336,8 +336,8 @@ class ConnectionZeroconf(CommonConnection, ConnectionHandlersZeroconf):
def send_message(self, jid, msg, keyID, type_='chat', subject='', def send_message(self, jid, msg, keyID, type_='chat', subject='',
chatstate=None, msg_id=None, resource=None, user_nick=None, xhtml=None, chatstate=None, msg_id=None, resource=None, user_nick=None, xhtml=None,
label=None, session=None, forward_from=None, form_node=None, label=None, session=None, forward_from=None, form_node=None,
original_message=None, delayed=None, callback=None, callback_args=[], original_message=None, delayed=None, attention=False, callback=None,
now=True): callback_args=[], now=True):
def on_send_ok(msg_id): def on_send_ok(msg_id):
gajim.nec.push_incoming_event(MessageSentEvent(None, conn=self, gajim.nec.push_incoming_event(MessageSentEvent(None, conn=self,
@ -370,7 +370,8 @@ class ConnectionZeroconf(CommonConnection, ConnectionHandlersZeroconf):
chatstate=chatstate, msg_id=msg_id, resource=resource, chatstate=chatstate, msg_id=msg_id, resource=resource,
user_nick=user_nick, xhtml=xhtml, session=session, user_nick=user_nick, xhtml=xhtml, session=session,
forward_from=forward_from, form_node=form_node, forward_from=forward_from, form_node=form_node,
original_message=original_message, delayed=delayed, callback=cb) original_message=original_message, delayed=delayed,
attention=attention, callback=cb)
def _nec_message_outgoing(self, obj): def _nec_message_outgoing(self, obj):
if obj.account != self.name: if obj.account != self.name:
@ -411,7 +412,7 @@ class ConnectionZeroconf(CommonConnection, ConnectionHandlersZeroconf):
resource=obj.resource, user_nick=obj.user_nick, xhtml=obj.xhtml, resource=obj.resource, user_nick=obj.user_nick, xhtml=obj.xhtml,
label=obj.label, session=obj.session, forward_from=obj.forward_from, label=obj.label, session=obj.session, forward_from=obj.forward_from,
form_node=obj.form_node, original_message=obj.original_message, form_node=obj.form_node, original_message=obj.original_message,
delayed=obj.delayed, callback=cb) delayed=obj.delayed, attention=obj.attention, callback=cb)
def send_stanza(self, stanza): def send_stanza(self, stanza):
# send a stanza untouched # send a stanza untouched

View file

@ -4188,6 +4188,7 @@ class ManageSoundsWindow:
# NOTE: sounds_ui_names MUST have all items of # NOTE: sounds_ui_names MUST have all items of
# sounds = gajim.config.get_per('soundevents') as keys # sounds = gajim.config.get_per('soundevents') as keys
sounds_dict = { sounds_dict = {
'attention_received': _('Attention Message Received'),
'first_message_received': _('First Message Received'), 'first_message_received': _('First Message Received'),
'next_message_received_focused': _('Next Message Received Focused'), 'next_message_received_focused': _('Next Message Received Focused'),
'next_message_received_unfocused': 'next_message_received_unfocused':

View file

@ -2745,7 +2745,7 @@ class ChangePasswordDialog:
class PopupNotificationWindow: class PopupNotificationWindow:
def __init__(self, event_type, jid, account, msg_type='', def __init__(self, event_type, jid, account, msg_type='',
path_to_image=None, title=None, text=None): path_to_image=None, title=None, text=None, timeout=-1):
self.account = account self.account = account
self.jid = jid self.jid = jid
self.msg_type = msg_type self.msg_type = msg_type
@ -2765,8 +2765,8 @@ class PopupNotificationWindow:
title = '' title = ''
event_type_label.set_markup( event_type_label.set_markup(
'<span foreground="black" weight="bold">%s</span>' % '<span foreground="black" weight="bold">%s</span>' %
gobject.markup_escape_text(title)) gobject.markup_escape_text(title))
# set colors [ http://www.pitt.edu/~nisg/cis/web/cgi/rgb.html ] # set colors [ http://www.pitt.edu/~nisg/cis/web/cgi/rgb.html ]
self.window.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('black')) self.window.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('black'))
@ -2787,7 +2787,7 @@ class PopupNotificationWindow:
elif event_type == _('File Transfer Error'): elif event_type == _('File Transfer Error'):
bg_color = gajim.config.get('notif_fterror_color') bg_color = gajim.config.get('notif_fterror_color')
elif event_type in (_('File Transfer Completed'), elif event_type in (_('File Transfer Completed'),
_('File Transfer Stopped')): _('File Transfer Stopped')):
bg_color = gajim.config.get('notif_ftcomplete_color') bg_color = gajim.config.get('notif_ftcomplete_color')
elif event_type == _('Groupchat Invitation'): elif event_type == _('Groupchat Invitation'):
bg_color = gajim.config.get('notif_invite_color') bg_color = gajim.config.get('notif_invite_color')
@ -2813,13 +2813,13 @@ class PopupNotificationWindow:
pos_y = gajim.config.get('notification_position_y') pos_y = gajim.config.get('notification_position_y')
if pos_y < 0: if pos_y < 0:
pos_y = gtk.gdk.screen_height() - \ pos_y = gtk.gdk.screen_height() - \
gajim.interface.roster.popups_notification_height + pos_y + 1 gajim.interface.roster.popups_notification_height + pos_y + 1
self.window.move(pos_x, pos_y) self.window.move(pos_x, pos_y)
xml.connect_signals(self) xml.connect_signals(self)
self.window.show_all() self.window.show_all()
timeout = gajim.config.get('notification_timeout') if timeout > 0:
gobject.timeout_add_seconds(timeout, self.on_timeout) gobject.timeout_add_seconds(timeout, self.on_timeout)
def on_close_button_clicked(self, widget): def on_close_button_clicked(self, widget):
self.adjust_height_and_move_popup_notification_windows() self.adjust_height_and_move_popup_notification_windows()

View file

@ -212,7 +212,8 @@ class PrivateChatControl(ChatControl):
self.parent_win.redraw_tab(self) self.parent_win.redraw_tab(self)
self.update_ui() self.update_ui()
def send_message(self, message, xhtml=None, process_commands=True): def send_message(self, message, xhtml=None, process_commands=True,
attention=False):
""" """
Call this method to send the message Call this method to send the message
""" """
@ -237,7 +238,7 @@ class PrivateChatControl(ChatControl):
return return
ChatControl.send_message(self, message, xhtml=xhtml, ChatControl.send_message(self, message, xhtml=xhtml,
process_commands=process_commands) process_commands=process_commands, attention=attention)
def update_ui(self): def update_ui(self):
if self.contact.show == 'offline': if self.contact.show == 'offline':

View file

@ -73,7 +73,7 @@ def get_show_in_systray(event, account, contact, type_=None):
return gajim.config.get('trayicon_notification_on_events') return gajim.config.get('trayicon_notification_on_events')
def popup(event_type, jid, account, msg_type='', path_to_image=None, title=None, def popup(event_type, jid, account, msg_type='', path_to_image=None, title=None,
text=None): text=None, timeout=-1):
""" """
Notify a user of an event. It first tries to a valid implementation of Notify a user of an event. It first tries to a valid implementation of
the Desktop Notification Specification. If that fails, then we fall back to the Desktop Notification Specification. If that fails, then we fall back to
@ -83,11 +83,14 @@ text=None):
if not path_to_image: if not path_to_image:
path_to_image = gtkgui_helpers.get_icon_path('gajim-chat_msg_recv', 48) path_to_image = gtkgui_helpers.get_icon_path('gajim-chat_msg_recv', 48)
if timeout < 0:
timeout = gajim.config.get('notification_timeout')
# Try to show our popup via D-Bus and notification daemon # Try to show our popup via D-Bus and notification daemon
if gajim.config.get('use_notif_daemon') and dbus_support.supported: if gajim.config.get('use_notif_daemon') and dbus_support.supported:
try: try:
DesktopNotification(event_type, jid, account, msg_type, DesktopNotification(event_type, jid, account, msg_type,
path_to_image, title, gobject.markup_escape_text(text)) path_to_image, title, gobject.markup_escape_text(text), timeout)
return # sucessfully did D-Bus Notification procedure! return # sucessfully did D-Bus Notification procedure!
except dbus.DBusException, e: except dbus.DBusException, e:
# Connection to D-Bus failed # Connection to D-Bus failed
@ -112,8 +115,7 @@ text=None):
_title = title _title = title
notification = pynotify.Notification(_title, _text) notification = pynotify.Notification(_title, _text)
timeout = gajim.config.get('notification_timeout') * 1000 # make it ms notification.set_timeout(timeout*1000)
notification.set_timeout(timeout)
notification.set_category(event_type) notification.set_category(event_type)
notification.set_data('event_type', event_type) notification.set_data('event_type', event_type)
@ -134,7 +136,7 @@ text=None):
# Either nothing succeeded or the user wants old-style notifications # Either nothing succeeded or the user wants old-style notifications
instance = PopupNotificationWindow(event_type, jid, account, msg_type, instance = PopupNotificationWindow(event_type, jid, account, msg_type,
path_to_image, title, text) path_to_image, title, text, timeout)
gajim.interface.roster.popup_notification_windows.append(instance) gajim.interface.roster.popup_notification_windows.append(instance)
def on_pynotify_notification_clicked(notification, action): def on_pynotify_notification_clicked(notification, action):
@ -157,7 +159,8 @@ class Notification:
if obj.do_popup: if obj.do_popup:
popup(obj.popup_event_type, obj.jid, obj.conn.name, popup(obj.popup_event_type, obj.jid, obj.conn.name,
obj.popup_msg_type, path_to_image=obj.popup_image, obj.popup_msg_type, path_to_image=obj.popup_image,
title=obj.popup_title, text=obj.popup_text) title=obj.popup_title, text=obj.popup_text,
timeout=obj.popup_timeout)
if obj.do_sound: if obj.do_sound:
if obj.sound_file: if obj.sound_file:
@ -235,11 +238,12 @@ class DesktopNotification:
""" """
def __init__(self, event_type, jid, account, msg_type='', def __init__(self, event_type, jid, account, msg_type='',
path_to_image=None, title=None, text=None): path_to_image=None, title=None, text=None, timeout=-1):
self.path_to_image = os.path.abspath(path_to_image) self.path_to_image = os.path.abspath(path_to_image)
self.event_type = event_type self.event_type = event_type
self.title = title self.title = title
self.text = text self.text = text
self.timeout = timeout
# 0.3.1 is the only version of notification daemon that has no way # 0.3.1 is the only version of notification daemon that has no way
# to determine which version it is. If no method exists, it means # to determine which version it is. If no method exists, it means
# they're using that one. # they're using that one.
@ -302,7 +306,6 @@ class DesktopNotification:
self.get_version() self.get_version()
def attempt_notify(self): def attempt_notify(self):
timeout = gajim.config.get('notification_timeout') # in seconds
ntype = self.ntype ntype = self.ntype
if self.kde_notifications: if self.kde_notifications:
notification_text = ('<html><img src="%(image)s" align=left />' \ notification_text = ('<html><img src="%(image)s" align=left />' \
@ -320,8 +323,8 @@ class DesktopNotification:
# actions (stringlist) # actions (stringlist)
(dbus.String('default'), dbus.String(self.event_type), (dbus.String('default'), dbus.String(self.event_type),
dbus.String('ignore'), dbus.String(_('Ignore'))), dbus.String('ignore'), dbus.String(_('Ignore'))),
[], # hints (not used in KDE yet) [], # hints (not used in KDE yet)
dbus.UInt32(timeout*1000), # timeout (int), in ms dbus.UInt32(self.timeout*1000), # timeout (int), in ms
reply_handler=self.attach_by_id, reply_handler=self.attach_by_id,
error_handler=self.notify_another_way) error_handler=self.notify_another_way)
return return
@ -345,7 +348,7 @@ class DesktopNotification:
actions, actions,
[''], [''],
True, True,
dbus.UInt32(timeout), dbus.UInt32(self.timeout),
reply_handler=self.attach_by_id, reply_handler=self.attach_by_id,
error_handler=self.notify_another_way) error_handler=self.notify_another_way)
except AttributeError: except AttributeError:
@ -392,7 +395,7 @@ class DesktopNotification:
dbus.String(text), dbus.String(text),
actions, actions,
hints, hints,
dbus.UInt32(timeout*1000), dbus.UInt32(self.timeout*1000),
reply_handler=self.attach_by_id, reply_handler=self.attach_by_id,
error_handler=self.notify_another_way) error_handler=self.notify_another_way)
except Exception, e: except Exception, e:
@ -407,7 +410,7 @@ class DesktopNotification:
dbus.String(self.text), dbus.String(self.text),
dbus.String(''), dbus.String(''),
hints, hints,
dbus.UInt32(timeout*1000), dbus.UInt32(self.timeout*1000),
reply_handler=self.attach_by_id, reply_handler=self.attach_by_id,
error_handler=self.notify_another_way) error_handler=self.notify_another_way)
except Exception, e: except Exception, e:
@ -422,7 +425,7 @@ class DesktopNotification:
str(e)) str(e))
instance = PopupNotificationWindow(self.event_type, self.jid, instance = PopupNotificationWindow(self.event_type, self.jid,
self.account, self.msg_type, self.path_to_image, self.title, self.account, self.msg_type, self.path_to_image, self.title,
self.text) self.text, self.timeout)
gajim.interface.roster.popup_notification_windows.append(instance) gajim.interface.roster.popup_notification_windows.append(instance)
def on_action_invoked(self, id_, reason): def on_action_invoked(self, id_, reason):