[peralta] Chat State Notifications inital patch. I assume that every wm will focus-out before iconify. If that is not the case I am going to use window-state-changed too [to be tested]
This commit is contained in:
		
							parent
							
								
									cc7c233e0d
								
							
						
					
					
						commit
						d6c9c7cbc6
					
				
					 5 changed files with 139 additions and 14 deletions
				
			
		| 
						 | 
				
			
			@ -218,6 +218,7 @@ class Connection:
 | 
			
		|||
		tim = time.strptime(tim, '%Y%m%dT%H:%M:%S')
 | 
			
		||||
		tim = time.localtime(timegm(tim))
 | 
			
		||||
		encrypted = False
 | 
			
		||||
		chatstate_tag = None
 | 
			
		||||
		xtags = msg.getTags('x')
 | 
			
		||||
		encTag = None
 | 
			
		||||
		decmsg = ''
 | 
			
		||||
| 
						 | 
				
			
			@ -225,6 +226,14 @@ class Connection:
 | 
			
		|||
			if xtag.getNamespace() == common.xmpp.NS_ENCRYPTED:
 | 
			
		||||
				encTag = xtag
 | 
			
		||||
				break
 | 
			
		||||
 | 
			
		||||
		# chatstates - look for chatstate tags in a message
 | 
			
		||||
		children = msg.getChildren()
 | 
			
		||||
		for child in children:
 | 
			
		||||
			if child.getNamespace() == 'http://jabber.org/protocol/chatstates':
 | 
			
		||||
				chatstate_tag = child.getName()
 | 
			
		||||
				break
 | 
			
		||||
			
 | 
			
		||||
		if encTag and USE_GPG:
 | 
			
		||||
			#decrypt
 | 
			
		||||
			encmsg = encTag.getData()
 | 
			
		||||
| 
						 | 
				
			
			@ -253,9 +262,9 @@ class Connection:
 | 
			
		|||
			gajim.logger.write('incoming', log_msgtxt, str(msg.getFrom()),
 | 
			
		||||
				tim = tim)
 | 
			
		||||
			self.dispatch('MSG', (str(msg.getFrom()), msgtxt, tim, encrypted,
 | 
			
		||||
				mtype, subject))
 | 
			
		||||
				mtype, subject, None))
 | 
			
		||||
		else: # it's type 'chat'
 | 
			
		||||
			if not msg.getTag('body'): #no <body>
 | 
			
		||||
			if not msg.getTag('body') and chatstate_tag is None: #no <body>
 | 
			
		||||
				return
 | 
			
		||||
			log_msgtxt = msgtxt
 | 
			
		||||
			if subject:
 | 
			
		||||
| 
						 | 
				
			
			@ -263,7 +272,7 @@ class Connection:
 | 
			
		|||
			gajim.logger.write('incoming', log_msgtxt, str(msg.getFrom()),
 | 
			
		||||
				tim = tim)
 | 
			
		||||
			self.dispatch('MSG', (str(msg.getFrom()), msgtxt, tim, encrypted,
 | 
			
		||||
				mtype, subject))
 | 
			
		||||
				mtype, subject, chatstate_tag))
 | 
			
		||||
	# END messageCB
 | 
			
		||||
 | 
			
		||||
	def _presenceCB(self, con, prs):
 | 
			
		||||
| 
						 | 
				
			
			@ -859,10 +868,10 @@ class Connection:
 | 
			
		|||
				self.connection.send(p)
 | 
			
		||||
			self.dispatch('STATUS', show)
 | 
			
		||||
 | 
			
		||||
	def send_message(self, jid, msg, keyID, type = 'chat', subject=''):
 | 
			
		||||
	def send_message(self, jid, msg, keyID, type = 'chat', subject='', chatstate = None):
 | 
			
		||||
		if not self.connection:
 | 
			
		||||
			return
 | 
			
		||||
		if not msg:
 | 
			
		||||
		if not msg and chatstate is None:
 | 
			
		||||
			return
 | 
			
		||||
		msgtxt = msg
 | 
			
		||||
		msgenc = ''
 | 
			
		||||
| 
						 | 
				
			
			@ -886,6 +895,12 @@ class Connection:
 | 
			
		|||
					typ = 'normal')
 | 
			
		||||
		if msgenc:
 | 
			
		||||
			msg_iq.setTag(common.xmpp.NS_ENCRYPTED + ' x').setData(msgenc)
 | 
			
		||||
 | 
			
		||||
		# chatstates - if peer supports jep85, send chatstates
 | 
			
		||||
		# please note that the only valid tag inside a message containing a <body> tag is the active event
 | 
			
		||||
		if chatstate != None:
 | 
			
		||||
			msg_iq.setTag(chatstate, {}, namespace='http://jabber.org/protocol/chatstates')
 | 
			
		||||
		
 | 
			
		||||
		self.to_be_sent.append(msg_iq)
 | 
			
		||||
		gajim.logger.write('outgoing', msg, jid)
 | 
			
		||||
		self.dispatch('MSGSENT', (jid, msg, keyID))
 | 
			
		||||
| 
						 | 
				
			
			@ -939,7 +954,7 @@ class Connection:
 | 
			
		|||
			{'agent': agent})
 | 
			
		||||
		return
 | 
			
		||||
 | 
			
		||||
	def update_user(self, jid, name, groups):
 | 
			
		||||
	def update_contact(self, jid, name, groups):
 | 
			
		||||
		if self.connection:
 | 
			
		||||
			self.connection.getRoster().setItem(jid = jid, name = name,
 | 
			
		||||
				groups = groups)
 | 
			
		||||
| 
						 | 
				
			
			@ -1150,6 +1165,7 @@ class Connection:
 | 
			
		|||
			typ = ptype, show = show, status = status))
 | 
			
		||||
 | 
			
		||||
	def gc_set_role(self, room_jid, nick, role, reason = ''):
 | 
			
		||||
		'''role is for all the life of the room so it's based on nick'''
 | 
			
		||||
		if not self.connection:
 | 
			
		||||
			return
 | 
			
		||||
		iq = common.xmpp.Iq(typ = 'set', to = room_jid, queryNS =\
 | 
			
		||||
| 
						 | 
				
			
			@ -1162,6 +1178,7 @@ class Connection:
 | 
			
		|||
		self.to_be_sent.append(iq)
 | 
			
		||||
 | 
			
		||||
	def gc_set_affiliation(self, room_jid, jid, affiliation, reason = ''):
 | 
			
		||||
		'''affiliation is for all the life of the room so it's based on jid'''
 | 
			
		||||
		if not self.connection:
 | 
			
		||||
			return
 | 
			
		||||
		iq = common.xmpp.Iq(typ = 'set', to = room_jid, queryNS =\
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										14
									
								
								src/gajim.py
									
										
									
									
									
								
							
							
						
						
									
										14
									
								
								src/gajim.py
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -344,9 +344,10 @@ class Interface:
 | 
			
		|||
				self.remote.raise_signal('GCPresence', (account, array))
 | 
			
		||||
 | 
			
		||||
	def handle_event_msg(self, account, array):
 | 
			
		||||
		#('MSG', account, (contact, msg, time, encrypted, msg_type, subject))
 | 
			
		||||
		#('MSG', account, (contact, msg, time, encrypted, msg_type, subject, chatstate_tag))
 | 
			
		||||
		jid = array[0].split('/')[0]
 | 
			
		||||
		msg_type = array[4]
 | 
			
		||||
		chatstate_tag = array[6]
 | 
			
		||||
		if jid.find('@') <= 0:
 | 
			
		||||
			jid = jid.replace('@', '')
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -406,6 +407,17 @@ class Interface:
 | 
			
		|||
			self.play_sound('next_message_received')
 | 
			
		||||
		if self.remote:
 | 
			
		||||
			self.remote.raise_signal('NewMessage', (account, array))
 | 
			
		||||
		if self.windows[account]['chats'].has_key(jid):
 | 
			
		||||
			chat_win = self.windows[account]['chats'][jid]
 | 
			
		||||
			# chatstates - display jep85 events in window
 | 
			
		||||
			if chatstate_tag != None:
 | 
			
		||||
				if chat_win.chatstates[jid] == 'ask':
 | 
			
		||||
					chat_win.chatstates[jid] = 'active'
 | 
			
		||||
				chat_win.print_conversation(jid + ' is now ' + chatstate_tag, jid, 'status', tim = array[2])
 | 
			
		||||
			else:
 | 
			
		||||
				# got no valid jep85 answer, peer does not support it
 | 
			
		||||
				chat_win.chatstates[jid] = -1
 | 
			
		||||
				
 | 
			
		||||
		
 | 
			
		||||
	def handle_event_msgerror(self, account, array):
 | 
			
		||||
		#('MSGERROR', account, (jid, error_code, error_msg, msg, time))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9932,7 +9932,6 @@ Custom</property>
 | 
			
		|||
  <signal name="event" handler="on_tabbed_chat_window_event"/>
 | 
			
		||||
  <signal name="button_press_event" handler="on_tabbed_chat_window_button_press_event" last_modification_time="Fri, 24 Jun 2005 23:54:20 GMT"/>
 | 
			
		||||
  <signal name="focus_out_event" handler="on_tabbed_chat_window_focus_out_event" last_modification_time="Mon, 18 Jul 2005 22:07:30 GMT"/>
 | 
			
		||||
  <signal name="window_state_event" handler="on_tabbed_chat_window_state_changed" last_modification_time="Mon, 18 Jul 2005 22:21:37 GMT"/>
 | 
			
		||||
 | 
			
		||||
  <child>
 | 
			
		||||
    <widget class="GtkNotebook" id="chat_notebook">
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -309,9 +309,30 @@ class RosterWindow:
 | 
			
		|||
			'show_offline_contacts_menuitem')
 | 
			
		||||
		profile_avatar_menuitem = self.xml.get_widget('profile_avatar_menuitem')
 | 
			
		||||
		
 | 
			
		||||
		
 | 
			
		||||
		xm = gtk.glade.XML(GTKGUI_GLADE, 'advanced_menuitem_menu', APP)
 | 
			
		||||
		advanced_menuitem_menu = xm.get_widget('advanced_menuitem_menu')
 | 
			
		||||
 | 
			
		||||
		ui_description = """
 | 
			
		||||
<ui>
 | 
			
		||||
	<menu action='advanced_menuitem_menu'>
 | 
			
		||||
		<menu action='A'>
 | 
			
		||||
			%(menu)s
 | 
			
		||||
		</menu>
 | 
			
		||||
		<menu action='B'>
 | 
			
		||||
			%(menu)s
 | 
			
		||||
		</menu>
 | 
			
		||||
		<menu action='C'>
 | 
			
		||||
			%(menu)s
 | 
			
		||||
		</menu>
 | 
			
		||||
		<menuitem action="Quit" />
 | 
			
		||||
	</menu>
 | 
			
		||||
</ui>"""
 | 
			
		||||
 | 
			
		||||
		menu_description = """
 | 
			
		||||
			<menuitem action='Send Single Message' />
 | 
			
		||||
			<menuitem action='XML Console' />
 | 
			
		||||
			<separator />
 | 
			
		||||
			<menuitem action='Administrator' />
 | 
			
		||||
			<menuitem action='Test5' />
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
		if self.add_new_contact_handler_id:
 | 
			
		||||
			add_new_contact_menuitem.handler_disconnect(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -44,6 +44,7 @@ class TabbedChatWindow(chat.Chat):
 | 
			
		|||
	def __init__(self, user, plugin, account):
 | 
			
		||||
		chat.Chat.__init__(self, plugin, account, 'tabbed_chat_window')
 | 
			
		||||
		self.users = {}
 | 
			
		||||
		self.chatstates = {}
 | 
			
		||||
		self.new_user(user)
 | 
			
		||||
		self.show_title()
 | 
			
		||||
		self.xml.signal_connect('on_tabbed_chat_window_destroy',
 | 
			
		||||
| 
						 | 
				
			
			@ -52,6 +53,8 @@ class TabbedChatWindow(chat.Chat):
 | 
			
		|||
			self.on_tabbed_chat_window_delete_event)
 | 
			
		||||
		self.xml.signal_connect('on_tabbed_chat_window_focus_in_event',
 | 
			
		||||
			self.on_tabbed_chat_window_focus_in_event)
 | 
			
		||||
		self.xml.signal_connect('on_tabbed_chat_window_focus_out_event',
 | 
			
		||||
			self.on_tabbed_chat_window_focus_out_event)
 | 
			
		||||
		self.xml.signal_connect('on_tabbed_chat_window_button_press_event',
 | 
			
		||||
			self.on_chat_window_button_press_event)
 | 
			
		||||
		self.xml.signal_connect('on_chat_notebook_key_press_event',
 | 
			
		||||
| 
						 | 
				
			
			@ -60,7 +63,7 @@ class TabbedChatWindow(chat.Chat):
 | 
			
		|||
			self.on_chat_notebook_switch_page)
 | 
			
		||||
 | 
			
		||||
		if gajim.config.get('saveposition'):
 | 
			
		||||
		# get window position and size from config
 | 
			
		||||
			# get window position and size from config
 | 
			
		||||
			self.window.move(gajim.config.get('chat-x-position'),
 | 
			
		||||
					gajim.config.get('chat-y-position'))
 | 
			
		||||
			self.window.resize(gajim.config.get('chat-width'),
 | 
			
		||||
| 
						 | 
				
			
			@ -197,7 +200,7 @@ class TabbedChatWindow(chat.Chat):
 | 
			
		|||
					return True #stop the propagation of the event
 | 
			
		||||
 | 
			
		||||
		if gajim.config.get('saveposition'):
 | 
			
		||||
		# save the window size and position
 | 
			
		||||
			# save the window size and position
 | 
			
		||||
			x, y = self.window.get_position()
 | 
			
		||||
			gajim.config.set('chat-x-position', x)
 | 
			
		||||
			gajim.config.set('chat-y-position', y)
 | 
			
		||||
| 
						 | 
				
			
			@ -207,10 +210,28 @@ class TabbedChatWindow(chat.Chat):
 | 
			
		|||
 | 
			
		||||
	def on_tabbed_chat_window_destroy(self, widget):
 | 
			
		||||
		#clean self.plugin.windows[self.account]['chats']
 | 
			
		||||
		# on window destroy, send 'gone' chatstate
 | 
			
		||||
		self.send_chatstate('gone')
 | 
			
		||||
		chat.Chat.on_window_destroy(self, widget, 'chats')
 | 
			
		||||
 | 
			
		||||
	def on_tabbed_chat_window_focus_in_event(self, widget, event):
 | 
			
		||||
		chat.Chat.on_chat_window_focus_in_event(self, widget, event)
 | 
			
		||||
		# on focus in, send 'active' chatstate
 | 
			
		||||
		self.send_chatstate('active')
 | 
			
		||||
 | 
			
		||||
	def on_tabbed_chat_window_focus_out_event(self, widget, event):
 | 
			
		||||
		gobject.timeout_add(500, self.check_window_state, widget)
 | 
			
		||||
 | 
			
		||||
	def check_window_state(self, widget):
 | 
			
		||||
		''' we want: "minimized" or "focus-out"
 | 
			
		||||
      not "focus-out, minimized" or "focus-out" '''
 | 
			
		||||
		new_state = widget.window.get_state()
 | 
			
		||||
		if new_state & gtk.gdk.WINDOW_STATE_ICONIFIED:
 | 
			
		||||
			print 'iconify'
 | 
			
		||||
			self.send_chatstate('inactive')
 | 
			
		||||
		else:
 | 
			
		||||
			print 'just focus-out'
 | 
			
		||||
			self.send_chatstate('paused')
 | 
			
		||||
 | 
			
		||||
	def on_chat_notebook_key_press_event(self, widget, event):
 | 
			
		||||
		chat.Chat.on_chat_notebook_key_press_event(self, widget, event)
 | 
			
		||||
| 
						 | 
				
			
			@ -237,6 +258,9 @@ class TabbedChatWindow(chat.Chat):
 | 
			
		|||
			if dialog.get_response() != gtk.RESPONSE_OK:
 | 
			
		||||
				return
 | 
			
		||||
 | 
			
		||||
		# chatstates - window is destroyed, send gone
 | 
			
		||||
		self.send_chatstate('gone')
 | 
			
		||||
		
 | 
			
		||||
		chat.Chat.remove_tab(self, jid, 'chats')
 | 
			
		||||
		if len(self.xmls) > 0:
 | 
			
		||||
			del self.users[jid]
 | 
			
		||||
| 
						 | 
				
			
			@ -275,6 +299,9 @@ class TabbedChatWindow(chat.Chat):
 | 
			
		|||
		gajim.connections[self.account].request_vcard(user.jid)
 | 
			
		||||
		self.childs[user.jid].show_all()
 | 
			
		||||
 | 
			
		||||
		# chatstates
 | 
			
		||||
		self.chatstates[user.jid] = None
 | 
			
		||||
 | 
			
		||||
	def on_message_textview_key_press_event(self, widget, event):
 | 
			
		||||
		"""When a key is pressed:
 | 
			
		||||
		if enter is pressed without the shift key, message (if not empty) is sent
 | 
			
		||||
| 
						 | 
				
			
			@ -326,7 +353,45 @@ class TabbedChatWindow(chat.Chat):
 | 
			
		|||
			if event.state & gtk.gdk.CONTROL_MASK: #Ctrl+Down
 | 
			
		||||
				self.sent_messages_scroll(jid, 'down', widget.get_buffer())
 | 
			
		||||
				return True # override the default gtk+ thing for ctrl+down
 | 
			
		||||
			
 | 
			
		||||
		else:
 | 
			
		||||
			# chatstates
 | 
			
		||||
			# if composing, send chatstate
 | 
			
		||||
			self.send_chatstate('composing')
 | 
			
		||||
 | 
			
		||||
	def send_chatstate(self, state):
 | 
			
		||||
		# please read jep-85 to get an idea of this
 | 
			
		||||
		# we keep track of jep85 support by the peer by three extra states: None, -1 and 'ask'
 | 
			
		||||
		# None if no info about peer
 | 
			
		||||
		# -1 if peer does not support jep85
 | 
			
		||||
		# 'ask' if we sent 'active' chatstate and are waiting for reply
 | 
			
		||||
 | 
			
		||||
		jid = self.get_active_jid()
 | 
			
		||||
 | 
			
		||||
		# print jid, self.chatstates[jid], state
 | 
			
		||||
		if self.chatstates[jid] == -1:
 | 
			
		||||
			return
 | 
			
		||||
 | 
			
		||||
		# if current state equals last state, return
 | 
			
		||||
		if self.chatstates[jid] == state:
 | 
			
		||||
			return
 | 
			
		||||
 | 
			
		||||
		if self.chatstates[jid] is None:
 | 
			
		||||
			# state = 'ask'
 | 
			
		||||
			# send and return
 | 
			
		||||
			return
 | 
			
		||||
 | 
			
		||||
		if self.chatstates[jid] == 'ask':
 | 
			
		||||
			return
 | 
			
		||||
		
 | 
			
		||||
		# if last state was composing, don't send active
 | 
			
		||||
		if self.chatstates[jid] == 'composing' and state == 'active':
 | 
			
		||||
			return
 | 
			
		||||
 | 
			
		||||
		self.chatstates[jid] = state
 | 
			
		||||
		gajim.connections[self.account].send_message(jid, None, None, chatstate = state)
 | 
			
		||||
		
 | 
			
		||||
		
 | 
			
		||||
	def send_message(self, message):
 | 
			
		||||
		"""Send the message given to the active tab"""
 | 
			
		||||
		if not message:
 | 
			
		||||
| 
						 | 
				
			
			@ -350,7 +415,18 @@ class TabbedChatWindow(chat.Chat):
 | 
			
		|||
			if self.xmls[jid].get_widget('gpg_togglebutton').get_active():
 | 
			
		||||
				keyID = self.users[jid].keyID
 | 
			
		||||
				encrypted = True
 | 
			
		||||
			gajim.connections[self.account].send_message(jid, message, keyID)
 | 
			
		||||
 | 
			
		||||
			# chatstates - if no info about peer, discover
 | 
			
		||||
			if self.chatstates[jid] is None:
 | 
			
		||||
				
 | 
			
		||||
				gajim.connections[self.account].send_message(jid, message, keyID, chatstate = 'active')
 | 
			
		||||
				self.chatstates[jid] = 'ask'
 | 
			
		||||
			# if peer supports jep85, send 'active'
 | 
			
		||||
			elif self.chatstates[jid] != -1:
 | 
			
		||||
				gajim.connections[self.account].send_message(jid, message, keyID, chatstate = 'active')
 | 
			
		||||
			else:
 | 
			
		||||
				gajim.connections[self.account].send_message(jid, message, keyID)
 | 
			
		||||
				print self.chatstates[jid]
 | 
			
		||||
			message_buffer.set_text('', -1)
 | 
			
		||||
			self.print_conversation(message, jid, jid, encrypted = encrypted)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue