1
# -*- coding: utf-8 -*-
3
# This file is part of emesene.
5
# emesene is free software; you can redistribute it and/or modify
6
# it under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 3 of the License, or
8
# (at your option) any later version.
10
# emesene is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
15
# You should have received a copy of the GNU General Public License
16
# along with emesene; if not, write to the Free Software
17
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
32
from BaseTray import BaseTray
34
class TrayIcon(gtk.StatusIcon, BaseTray):
36
A widget that implements the tray icon of emesene for gtk
39
DESCRIPTION = 'The gtk tray icon'
40
AUTHOR = 'Mariano Guerra'
41
WEBSITE = 'www.emesene.org'
43
def __init__(self, handler, main_window=None):
47
handler -- a e3common.Handler.TrayIconHandler object
49
BaseTray.__init__(self)
51
gtk.StatusIcon.__init__(self)
52
self.handler = handler
54
self.main_window = main_window
55
self.last_new_message = None
57
self.connect('activate', self._on_activate)
58
self.connect('popup-menu', self._on_popup)
61
self.set_visible(True)
63
self.set_tooltip("emesene")
67
method called to set the state to the login window
69
self.menu = LoginMenu(self.handler, self.main_window)
71
self.set_from_file(self.handler.theme.logo)
73
def set_main(self, session):
75
method called to set the state to the main window
77
self.handler.session = session
78
self.handler.session.signals.status_change_succeed.subscribe(
79
self._on_change_status)
80
self.handler.session.signals.conv_message.subscribe(self._on_message)
81
self.handler.session.signals.message_read.subscribe(self._on_read)
82
self.menu = MainMenu(self.handler, self.main_window)
84
self.set_tooltip("emesene - " + self.handler.session.account.account)
86
def _on_message(self, cid, account, msgobj, cedict={}):
88
Blink tray icon and save newest unread message
91
conv_manager = self._get_conversation_manager(cid, account)
93
if conv_manager and not conv_manager.is_active():
94
self.set_blinking(True)
95
self.last_new_message = cid
97
def _on_read(self, conv):
99
Stop tray blinking and resets the newest unread message reference
101
self.set_blinking(False)
102
self.last_new_message = None
104
def _on_activate(self, trayicon):
106
callback called when the status icon is activated
107
(includes clicking the icon)
110
if self.last_new_message is not None and self.get_blinking():
111
# show the tab with the latest message
112
cid = self.last_new_message
113
conv_manager = self._get_conversation_manager(cid)
116
conversation = conv_manager.conversations[cid]
117
conv_manager.present(conversation)
119
self.handler.on_hide_show_mainwindow(self.main_window)
121
def _on_change_status(self,stat):
123
change the icon in the tray according to user's state
125
if stat not in status.ALL or stat == -1:
127
self.set_from_file(self.handler.theme.status_icons_panel[stat])
129
def _on_popup(self, trayicon, button, activate_time):
131
callback called when the popup of the status icon is activated
132
(usually through right-clicking the status icon)
135
if os.name == 'posix':
136
position = gtk.status_icon_position_menu
137
self.menu.popup(None, None, position, button, activate_time, trayicon)
139
class LoginMenu(gtk.Menu):
141
a widget that represents the menu displayed on the trayicon on the
145
def __init__(self, handler, main_window=None):
149
handler -- a e3common.Handler.TrayIconHandler object
151
gtk.Menu.__init__(self)
152
self.handler = handler
153
self.hide_show_mainwindow = gtk.MenuItem(_('Hide/Show emesene'))
154
self.hide_show_mainwindow.connect('activate',
155
lambda *args: self.handler.on_hide_show_mainwindow(main_window))
156
self.quit = gtk.ImageMenuItem(gtk.STOCK_QUIT)
157
self.quit.connect('activate',
158
lambda *args: self.handler.on_quit_selected())
160
self.append(self.hide_show_mainwindow)
161
self.append(self.quit)
163
class MainMenu(gtk.Menu):
165
a widget that represents the menu displayed on the trayicon on the
169
def __init__(self, handler, main_window=None):
173
handler -- a e3common.Handler.TrayIconHandler object
175
gtk.Menu.__init__(self)
176
self.handler = handler
178
StatusMenu = extension.get_default('menu status')
179
self.status = gtk.ImageMenuItem(_('Status'))
180
self.status.set_image(gtk.image_new_from_stock(gtk.STOCK_CONVERT,
182
self.status_menu = StatusMenu(handler.on_status_selected)
183
self.status.set_submenu(self.status_menu)
185
self.list = gtk.MenuItem(_('Contacts'))
186
self.list_contacts = ContactsMenu(handler, main_window)
187
self.list.set_submenu(self.list_contacts)
189
self.hide_show_mainwindow = gtk.MenuItem(_('Hide/Show emesene'))
190
self.hide_show_mainwindow.connect('activate',
191
lambda *args: self.handler.on_hide_show_mainwindow(main_window))
193
self.disconnect = gtk.ImageMenuItem(gtk.STOCK_DISCONNECT)
194
self.disconnect.connect('activate',
195
lambda *args: self.handler.on_disconnect_selected())
196
self.quit = gtk.ImageMenuItem(gtk.STOCK_QUIT)
197
self.quit.connect('activate',
198
lambda *args: self.handler.on_quit_selected())
200
self.append(self.hide_show_mainwindow)
201
self.append(self.status)
202
self.append(self.list)
203
self.append(self.disconnect)
204
self.append(gtk.SeparatorMenuItem())
205
self.append(self.quit)
207
class ContactsMenu(gtk.Menu):
209
a gtk menu that contains session's contacts
211
NAME = 'Contacts Menu'
212
DESCRIPTION = _('A menu with sessions\' contacts')
213
AUTHOR = 'Riccardo (C10uD)'
214
WEBSITE = 'www.emesene.org'
216
def __init__(self, handler, main_window=None):
220
gtk.Menu.__init__(self)
221
self.handler = handler
222
self.main_window = main_window
223
self.item_to_contacts = {}
224
self.contacts_to_item = {}
225
self.avatar_size = 32
227
self.contactmanager = self.handler.session.contacts
229
for contact in self.contactmanager.get_online_list():
230
self.__append_contact(contact)
232
self.handler.session.signals.contact_attr_changed.subscribe(self._on_contact_change_something)
234
# TODO: find out why gtk ImageMenuItem does not work as expected
236
def __append_contact(self, contact):
238
appends a contact to our submenu
240
#item = gtk.ImageMenuItem()
241
item = gtk.MenuItem()
242
item.set_label(Renderers.msnplus_to_plain_text(contact.nick))
243
#pict = self.__get_contact_pixbuf_or_default(contact)
244
#item.set_image(pict)
245
item.connect('activate', self._on_contact_clicked)
246
self.item_to_contacts[item] = contact
247
self.contacts_to_item[contact.account] = item
252
def _on_contact_change_something(self, *args):
254
update the menu when contacts change something
257
account, type_change, value_change = args
259
account, type_change, value_change, do_notify = args
261
if type_change == 'status':
263
if account in self.contacts_to_item:
265
self.__append_contact(self.contactmanager.get(account))
267
if account in self.contacts_to_item:
268
self.remove(self.contacts_to_item[account])
269
del self.item_to_contacts[self.contacts_to_item[account]]
270
del self.contacts_to_item[account]
272
if type_change == 'nick':
273
if account in self.contacts_to_item:
274
nick = self.item_to_contacts[self.contacts_to_item[account]].nick
275
self.contacts_to_item[account].set_label(nick)
277
if type_change == 'picture':
280
if account in self.contacts_to_item:
281
contact = self.item_to_contacts[self.contacts_to_item[account]]
282
pict = self.__get_contact_pixbuf_or_default(contact)
283
self.contacts_to_item[account].set_image(pict)
285
def _on_contact_clicked(self, menu_item):
287
called when contacts are clicked
289
acc = self.item_to_contacts[menu_item].account
291
self.main_window.content.on_new_conversation(cid, [acc], other_started=False)
292
self.handler.session.new_conversation(acc, cid)
294
def __get_contact_pixbuf_or_default(self, contact):
295
'''try to return a pixbuf of the user picture or the default
300
animation = gtk.gdk.PixbufAnimation(contact.picture)
301
except gobject.GError:
302
pix = utils.safe_gtk_pixbuf_load(gui.theme.user,
303
(self.avatar_size, self.avatar_size))
304
picture = gtk.image_new_from_pixbuf(pix)
307
if animation.is_static_image():
308
pix = utils.safe_gtk_pixbuf_load(contact.picture,
309
(self.avatar_size, self.avatar_size))
310
picture = gtk.image_new_from_pixbuf(pix)
312
picture = gtk.image_new_from_animation(animation)
315
pix = utils.safe_gtk_pixbuf_load(gui.theme.user,
316
(self.avatar_size, self.avatar_size))
317
picture = gtk.image_new_from_pixbuf(pix)