Merge branch 'muc-chatstate' into 'master'
Implement chatstate in MUC, as defined in XEP-0085 §5.5 See merge request !11
This commit is contained in:
		
						commit
						a1565040bd
					
				
					 6 changed files with 172 additions and 111 deletions
				
			
		| 
						 | 
				
			
			@ -188,14 +188,7 @@ class ChatControl(ChatControlBase):
 | 
			
		|||
        self.bigger_avatar_window = None
 | 
			
		||||
        self.show_avatar()
 | 
			
		||||
 | 
			
		||||
        # chatstate timers and state
 | 
			
		||||
        self.reset_kbd_mouse_timeout_vars()
 | 
			
		||||
        self._schedule_activity_timers()
 | 
			
		||||
 | 
			
		||||
        # Hook up signals
 | 
			
		||||
        id_ = self.parent_win.window.connect('motion-notify-event',
 | 
			
		||||
            self._on_window_motion_notify)
 | 
			
		||||
        self.handlers[id_] = self.parent_win.window
 | 
			
		||||
        message_tv_buffer = self.msg_textview.get_buffer()
 | 
			
		||||
        id_ = message_tv_buffer.connect('changed',
 | 
			
		||||
            self._on_message_tv_buffer_changed)
 | 
			
		||||
| 
						 | 
				
			
			@ -672,21 +665,6 @@ class ChatControl(ChatControlBase):
 | 
			
		|||
        cursor = gtkgui_helpers.get_cursor('HAND2')
 | 
			
		||||
        self.parent_win.window.get_window().set_cursor(cursor)
 | 
			
		||||
 | 
			
		||||
    def _on_window_motion_notify(self, widget, event):
 | 
			
		||||
        """
 | 
			
		||||
        It gets called no matter if it is the active window or not
 | 
			
		||||
        """
 | 
			
		||||
        if self.parent_win.get_active_jid() == self.contact.jid:
 | 
			
		||||
            # if window is the active one, change vars assisting chatstate
 | 
			
		||||
            self.mouse_over_in_last_5_secs = True
 | 
			
		||||
            self.mouse_over_in_last_30_secs = True
 | 
			
		||||
 | 
			
		||||
    def _schedule_activity_timers(self):
 | 
			
		||||
        self.possible_paused_timeout_id = GLib.timeout_add_seconds(5,
 | 
			
		||||
                self.check_for_possible_paused_chatstate, None)
 | 
			
		||||
        self.possible_inactive_timeout_id = GLib.timeout_add_seconds(30,
 | 
			
		||||
                self.check_for_possible_inactive_chatstate, None)
 | 
			
		||||
 | 
			
		||||
    def update_ui(self):
 | 
			
		||||
        # The name banner is drawn here
 | 
			
		||||
        ChatControlBase.update_ui(self)
 | 
			
		||||
| 
						 | 
				
			
			@ -976,9 +954,6 @@ class ChatControl(ChatControlBase):
 | 
			
		|||
        if message in ('', None, '\n'):
 | 
			
		||||
            return None
 | 
			
		||||
 | 
			
		||||
        # refresh timers
 | 
			
		||||
        self.reset_kbd_mouse_timeout_vars()
 | 
			
		||||
 | 
			
		||||
        contact = self.contact
 | 
			
		||||
 | 
			
		||||
        encrypted = bool(self.session) and self.session.enable_encryption
 | 
			
		||||
| 
						 | 
				
			
			@ -990,10 +965,8 @@ class ChatControl(ChatControlBase):
 | 
			
		|||
            if not keyID:
 | 
			
		||||
                keyID = 'UNKNOWN'
 | 
			
		||||
 | 
			
		||||
        chatstates_on = gajim.config.get('outgoing_chat_state_notifications') != \
 | 
			
		||||
                'disabled'
 | 
			
		||||
        chatstate_to_send = None
 | 
			
		||||
        if chatstates_on and contact is not None:
 | 
			
		||||
        if contact is not None:
 | 
			
		||||
            if contact.supports(NS_CHATSTATES):
 | 
			
		||||
                # send active chatstate on every message (as XEP says)
 | 
			
		||||
                chatstate_to_send = 'active'
 | 
			
		||||
| 
						 | 
				
			
			@ -1031,65 +1004,6 @@ class ChatControl(ChatControlBase):
 | 
			
		|||
            process_commands=process_commands,
 | 
			
		||||
            attention=attention)
 | 
			
		||||
 | 
			
		||||
    def check_for_possible_paused_chatstate(self, arg):
 | 
			
		||||
        """
 | 
			
		||||
        Did we move mouse of that window or write something in message textview
 | 
			
		||||
        in the last 5 seconds? If yes - we go active for mouse, composing for
 | 
			
		||||
        kbd.  If not - we go paused if we were previously composing
 | 
			
		||||
        """
 | 
			
		||||
        contact = self.contact
 | 
			
		||||
        jid = contact.jid
 | 
			
		||||
        current_state = contact.our_chatstate
 | 
			
		||||
        if current_state is False:  # jid doesn't support chatstates
 | 
			
		||||
            return False  # stop looping
 | 
			
		||||
 | 
			
		||||
        message_buffer = self.msg_textview.get_buffer()
 | 
			
		||||
        if (self.kbd_activity_in_last_5_secs and
 | 
			
		||||
                message_buffer.get_char_count()):
 | 
			
		||||
            # Only composing if the keyboard activity was in text entry
 | 
			
		||||
            self.send_chatstate('composing', self.contact)
 | 
			
		||||
        elif (self.mouse_over_in_last_5_secs and
 | 
			
		||||
              current_state == 'inactive' and
 | 
			
		||||
                jid == self.parent_win.get_active_jid()):
 | 
			
		||||
            self.send_chatstate('active', self.contact)
 | 
			
		||||
        else:
 | 
			
		||||
            if current_state == 'composing':
 | 
			
		||||
                self.send_chatstate('paused', self.contact)  # pause composing
 | 
			
		||||
 | 
			
		||||
        # assume no activity and let the motion-notify or 'insert-text' make them
 | 
			
		||||
        # True refresh 30 seconds vars too or else it's 30 - 5 = 25 seconds!
 | 
			
		||||
        self.reset_kbd_mouse_timeout_vars()
 | 
			
		||||
        return True  # loop forever
 | 
			
		||||
 | 
			
		||||
    def check_for_possible_inactive_chatstate(self, arg):
 | 
			
		||||
        """
 | 
			
		||||
        Did we move mouse over that window or wrote something in message textview
 | 
			
		||||
        in the last 30 seconds? if yes - we go active. If no - we go inactive
 | 
			
		||||
        """
 | 
			
		||||
        contact = self.contact
 | 
			
		||||
 | 
			
		||||
        current_state = contact.our_chatstate
 | 
			
		||||
        if current_state is False: # jid doesn't support chatstates
 | 
			
		||||
            return False # stop looping
 | 
			
		||||
 | 
			
		||||
        if self.mouse_over_in_last_5_secs or self.kbd_activity_in_last_5_secs:
 | 
			
		||||
            return True # loop forever
 | 
			
		||||
 | 
			
		||||
        if not self.mouse_over_in_last_30_secs or \
 | 
			
		||||
        self.kbd_activity_in_last_30_secs:
 | 
			
		||||
            self.send_chatstate('inactive', contact)
 | 
			
		||||
 | 
			
		||||
        # assume no activity and let the motion-notify or 'insert-text' make them
 | 
			
		||||
        # True refresh 30 seconds too or else it's 30 - 5 = 25 seconds!
 | 
			
		||||
        self.reset_kbd_mouse_timeout_vars()
 | 
			
		||||
        return True # loop forever
 | 
			
		||||
 | 
			
		||||
    def reset_kbd_mouse_timeout_vars(self):
 | 
			
		||||
        self.kbd_activity_in_last_5_secs = False
 | 
			
		||||
        self.mouse_over_in_last_5_secs = False
 | 
			
		||||
        self.mouse_over_in_last_30_secs = False
 | 
			
		||||
        self.kbd_activity_in_last_30_secs = False
 | 
			
		||||
 | 
			
		||||
    def on_cancel_session_negotiation(self):
 | 
			
		||||
        msg = _('Session negotiation cancelled')
 | 
			
		||||
        ChatControlBase.print_conversation_line(self, msg, 'status', '', None)
 | 
			
		||||
| 
						 | 
				
			
			@ -1391,9 +1305,6 @@ class ChatControl(ChatControlBase):
 | 
			
		|||
        if self.session:
 | 
			
		||||
            self.session.control = None
 | 
			
		||||
 | 
			
		||||
        # Disconnect timer callbacks
 | 
			
		||||
        GLib.source_remove(self.possible_paused_timeout_id)
 | 
			
		||||
        GLib.source_remove(self.possible_inactive_timeout_id)
 | 
			
		||||
        # Remove bigger avatar window
 | 
			
		||||
        if self.bigger_avatar_window:
 | 
			
		||||
            self.bigger_avatar_window.destroy()
 | 
			
		||||
| 
						 | 
				
			
			@ -1482,20 +1393,6 @@ class ChatControl(ChatControlBase):
 | 
			
		|||
 | 
			
		||||
    def set_control_active(self, state):
 | 
			
		||||
        ChatControlBase.set_control_active(self, state)
 | 
			
		||||
        # send chatstate inactive to the one we're leaving
 | 
			
		||||
        # and active to the one we visit
 | 
			
		||||
        if state:
 | 
			
		||||
            message_buffer = self.msg_textview.get_buffer()
 | 
			
		||||
            if message_buffer.get_char_count():
 | 
			
		||||
                self.send_chatstate('paused', self.contact)
 | 
			
		||||
            else:
 | 
			
		||||
                self.send_chatstate('active', self.contact)
 | 
			
		||||
            self.reset_kbd_mouse_timeout_vars()
 | 
			
		||||
            GLib.source_remove(self.possible_paused_timeout_id)
 | 
			
		||||
            GLib.source_remove(self.possible_inactive_timeout_id)
 | 
			
		||||
            self._schedule_activity_timers()
 | 
			
		||||
        else:
 | 
			
		||||
            self.send_chatstate('inactive', self.contact)
 | 
			
		||||
        # Hide bigger avatar window
 | 
			
		||||
        if self.bigger_avatar_window:
 | 
			
		||||
            self.bigger_avatar_window.destroy()
 | 
			
		||||
| 
						 | 
				
			
			@ -1580,11 +1477,8 @@ class ChatControl(ChatControlBase):
 | 
			
		|||
        dialogs.TransformChatToMUC(self.account, [c.jid], [dropped_jid])
 | 
			
		||||
 | 
			
		||||
    def _on_message_tv_buffer_changed(self, textbuffer):
 | 
			
		||||
        self.kbd_activity_in_last_5_secs = True
 | 
			
		||||
        self.kbd_activity_in_last_30_secs = True
 | 
			
		||||
        super()._on_message_tv_buffer_changed(textbuffer)
 | 
			
		||||
        if textbuffer.get_char_count():
 | 
			
		||||
            self.send_chatstate('composing', self.contact)
 | 
			
		||||
 | 
			
		||||
            e2e_is_active = self.session and \
 | 
			
		||||
                    self.session.enable_encryption
 | 
			
		||||
            e2e_pref = gajim.config.get_per('accounts', self.account,
 | 
			
		||||
| 
						 | 
				
			
			@ -1600,8 +1494,6 @@ class ChatControl(ChatControlBase):
 | 
			
		|||
            elif (not self.session or not self.session.status) and \
 | 
			
		||||
            gajim.connections[self.account].archiving_136_supported:
 | 
			
		||||
                self.begin_archiving_negotiation()
 | 
			
		||||
        else:
 | 
			
		||||
            self.send_chatstate('active', self.contact)
 | 
			
		||||
 | 
			
		||||
    def restore_conversation(self):
 | 
			
		||||
        jid = self.contact.jid
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -383,6 +383,18 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
 | 
			
		|||
        self.command_hits = []
 | 
			
		||||
        self.last_key_tabs = False
 | 
			
		||||
 | 
			
		||||
        # chatstate timers and state
 | 
			
		||||
        self.reset_kbd_mouse_timeout_vars()
 | 
			
		||||
        self._schedule_activity_timers()
 | 
			
		||||
        message_tv_buffer = self.msg_textview.get_buffer()
 | 
			
		||||
        id_ = message_tv_buffer.connect('changed',
 | 
			
		||||
            self._on_message_tv_buffer_changed)
 | 
			
		||||
        self.handlers[id_] = message_tv_buffer
 | 
			
		||||
        if parent_win is not None:
 | 
			
		||||
            id_ = parent_win.window.connect('motion-notify-event',
 | 
			
		||||
                self._on_window_motion_notify)
 | 
			
		||||
            self.handlers[id_] = parent_win.window
 | 
			
		||||
 | 
			
		||||
        # PluginSystem: adding GUI extension point for ChatControlBase
 | 
			
		||||
        # instance object (also subclasses, eg. ChatControl or GroupchatControl)
 | 
			
		||||
        gajim.plugin_manager.gui_extension_point('chat_control_base', self)
 | 
			
		||||
| 
						 | 
				
			
			@ -448,6 +460,9 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
 | 
			
		|||
 | 
			
		||||
    def shutdown(self):
 | 
			
		||||
        super(ChatControlBase, self).shutdown()
 | 
			
		||||
        # Disconnect timer callbacks
 | 
			
		||||
        GLib.source_remove(self.possible_paused_timeout_id)
 | 
			
		||||
        GLib.source_remove(self.possible_inactive_timeout_id)
 | 
			
		||||
        # PluginSystem: removing GUI extension points connected with ChatControlBase
 | 
			
		||||
        # instance object
 | 
			
		||||
        gajim.plugin_manager.remove_gui_extension_point('chat_control_base',
 | 
			
		||||
| 
						 | 
				
			
			@ -683,6 +698,12 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
 | 
			
		|||
        if process_commands and self.process_as_command(message):
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        # refresh timers
 | 
			
		||||
        self.reset_kbd_mouse_timeout_vars()
 | 
			
		||||
 | 
			
		||||
        if gajim.config.get('outgoing_chat_state_notifications') == 'disabled':
 | 
			
		||||
            chatstate = None
 | 
			
		||||
 | 
			
		||||
        label = self.get_seclabel()
 | 
			
		||||
 | 
			
		||||
        def _cb(obj, msg, cb, *cb_args):
 | 
			
		||||
| 
						 | 
				
			
			@ -712,6 +733,88 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
 | 
			
		|||
        message_buffer = self.msg_textview.get_buffer()
 | 
			
		||||
        message_buffer.set_text('') # clear message buffer (and tv of course)
 | 
			
		||||
 | 
			
		||||
    def check_for_possible_paused_chatstate(self, arg):
 | 
			
		||||
        """
 | 
			
		||||
        Did we move mouse of that window or write something in message textview
 | 
			
		||||
        in the last 5 seconds? If yes - we go active for mouse, composing for
 | 
			
		||||
        kbd.  If not - we go paused if we were previously composing
 | 
			
		||||
        """
 | 
			
		||||
        contact = self.contact
 | 
			
		||||
        jid = contact.jid
 | 
			
		||||
        current_state = contact.our_chatstate
 | 
			
		||||
        if current_state is False:  # jid doesn't support chatstates
 | 
			
		||||
            return False  # stop looping
 | 
			
		||||
 | 
			
		||||
        message_buffer = self.msg_textview.get_buffer()
 | 
			
		||||
        if (self.kbd_activity_in_last_5_secs and
 | 
			
		||||
                message_buffer.get_char_count()):
 | 
			
		||||
            # Only composing if the keyboard activity was in text entry
 | 
			
		||||
            self.send_chatstate('composing', self.contact)
 | 
			
		||||
        elif (self.mouse_over_in_last_5_secs and
 | 
			
		||||
              current_state == 'inactive' and
 | 
			
		||||
                jid == self.parent_win.get_active_jid()):
 | 
			
		||||
            self.send_chatstate('active', self.contact)
 | 
			
		||||
        else:
 | 
			
		||||
            if current_state == 'composing':
 | 
			
		||||
                self.send_chatstate('paused', self.contact)  # pause composing
 | 
			
		||||
 | 
			
		||||
        # assume no activity and let the motion-notify or 'insert-text' make them
 | 
			
		||||
        # True refresh 30 seconds vars too or else it's 30 - 5 = 25 seconds!
 | 
			
		||||
        self.reset_kbd_mouse_timeout_vars()
 | 
			
		||||
        return True  # loop forever
 | 
			
		||||
 | 
			
		||||
    def check_for_possible_inactive_chatstate(self, arg):
 | 
			
		||||
        """
 | 
			
		||||
        Did we move mouse over that window or wrote something in message textview
 | 
			
		||||
        in the last 30 seconds? if yes - we go active. If no - we go inactive
 | 
			
		||||
        """
 | 
			
		||||
        contact = self.contact
 | 
			
		||||
 | 
			
		||||
        current_state = contact.our_chatstate
 | 
			
		||||
        if current_state is False: # jid doesn't support chatstates
 | 
			
		||||
            return False # stop looping
 | 
			
		||||
 | 
			
		||||
        if self.mouse_over_in_last_5_secs or self.kbd_activity_in_last_5_secs:
 | 
			
		||||
            return True # loop forever
 | 
			
		||||
 | 
			
		||||
        if not self.mouse_over_in_last_30_secs or \
 | 
			
		||||
        self.kbd_activity_in_last_30_secs:
 | 
			
		||||
            self.send_chatstate('inactive', contact)
 | 
			
		||||
 | 
			
		||||
        # assume no activity and let the motion-notify or 'insert-text' make them
 | 
			
		||||
        # True refresh 30 seconds too or else it's 30 - 5 = 25 seconds!
 | 
			
		||||
        self.reset_kbd_mouse_timeout_vars()
 | 
			
		||||
        return True # loop forever
 | 
			
		||||
 | 
			
		||||
    def _schedule_activity_timers(self):
 | 
			
		||||
        self.possible_paused_timeout_id = GLib.timeout_add_seconds(5,
 | 
			
		||||
                self.check_for_possible_paused_chatstate, None)
 | 
			
		||||
        self.possible_inactive_timeout_id = GLib.timeout_add_seconds(30,
 | 
			
		||||
                self.check_for_possible_inactive_chatstate, None)
 | 
			
		||||
 | 
			
		||||
    def reset_kbd_mouse_timeout_vars(self):
 | 
			
		||||
        self.kbd_activity_in_last_5_secs = False
 | 
			
		||||
        self.mouse_over_in_last_5_secs = False
 | 
			
		||||
        self.mouse_over_in_last_30_secs = False
 | 
			
		||||
        self.kbd_activity_in_last_30_secs = False
 | 
			
		||||
 | 
			
		||||
    def _on_window_motion_notify(self, widget, event):
 | 
			
		||||
        """
 | 
			
		||||
        It gets called no matter if it is the active window or not
 | 
			
		||||
        """
 | 
			
		||||
        if self.parent_win.get_active_jid() == self.contact.jid:
 | 
			
		||||
            # if window is the active one, change vars assisting chatstate
 | 
			
		||||
            self.mouse_over_in_last_5_secs = True
 | 
			
		||||
            self.mouse_over_in_last_30_secs = True
 | 
			
		||||
 | 
			
		||||
    def _on_message_tv_buffer_changed(self, textbuffer):
 | 
			
		||||
        self.kbd_activity_in_last_5_secs = True
 | 
			
		||||
        self.kbd_activity_in_last_30_secs = True
 | 
			
		||||
        if textbuffer.get_char_count():
 | 
			
		||||
            self.send_chatstate('composing', self.contact)
 | 
			
		||||
        else:
 | 
			
		||||
            self.send_chatstate('active', self.contact)
 | 
			
		||||
 | 
			
		||||
    def save_message(self, message, msg_type):
 | 
			
		||||
        # save the message, so user can scroll though the list with key up/down
 | 
			
		||||
        if msg_type == 'sent':
 | 
			
		||||
| 
						 | 
				
			
			@ -982,6 +1085,19 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
 | 
			
		|||
                types=type_):
 | 
			
		||||
                    # There were events to remove
 | 
			
		||||
                    self.redraw_after_event_removed(jid)
 | 
			
		||||
            # send chatstate inactive to the one we're leaving
 | 
			
		||||
            # and active to the one we visit
 | 
			
		||||
            message_buffer = self.msg_textview.get_buffer()
 | 
			
		||||
            if message_buffer.get_char_count():
 | 
			
		||||
                self.send_chatstate('paused', self.contact)
 | 
			
		||||
            else:
 | 
			
		||||
                self.send_chatstate('active', self.contact)
 | 
			
		||||
            self.reset_kbd_mouse_timeout_vars()
 | 
			
		||||
            GLib.source_remove(self.possible_paused_timeout_id)
 | 
			
		||||
            GLib.source_remove(self.possible_inactive_timeout_id)
 | 
			
		||||
            self._schedule_activity_timers()
 | 
			
		||||
        else:
 | 
			
		||||
            self.send_chatstate('inactive', self.contact)
 | 
			
		||||
 | 
			
		||||
    def scroll_to_end_iter(self):
 | 
			
		||||
        self.conv_textview.scroll_to_end_iter()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2719,6 +2719,8 @@ class Connection(CommonConnection, ConnectionHandlers):
 | 
			
		|||
            obj.xhtml = create_xhtml(obj.message)
 | 
			
		||||
        msg_iq = nbxmpp.Message(obj.jid, obj.message, typ='groupchat',
 | 
			
		||||
                                xhtml=obj.xhtml)
 | 
			
		||||
        if obj.chatstate:
 | 
			
		||||
            msg_iq.setTag(obj.chatstate, namespace=nbxmpp.NS_CHATSTATES)
 | 
			
		||||
        if obj.label is not None:
 | 
			
		||||
            msg_iq.addChild(node=obj.label)
 | 
			
		||||
        gajim.nec.push_incoming_event(GcStanzaMessageOutgoingEvent(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2769,6 +2769,7 @@ class GcMessageOutgoingEvent(nec.NetworkOutgoingEvent):
 | 
			
		|||
    def init(self):
 | 
			
		||||
        self.additional_data = {}
 | 
			
		||||
        self.message = ''
 | 
			
		||||
        self.chatstate = None
 | 
			
		||||
        self.xhtml = None
 | 
			
		||||
        self.label = None
 | 
			
		||||
        self.callback = None
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -343,7 +343,7 @@ class GroupchatControl(ChatControlBase):
 | 
			
		|||
            img.set_from_icon_name('document-open-recent', Gtk.IconSize.MENU)
 | 
			
		||||
 | 
			
		||||
        self.current_tooltip = None
 | 
			
		||||
        if parent_win:
 | 
			
		||||
        if parent_win is not None:
 | 
			
		||||
            # On AutoJoin with minimize Groupchats are created without parent
 | 
			
		||||
            # Tooltip Window has to be created with parent
 | 
			
		||||
            self.set_tooltip()
 | 
			
		||||
| 
						 | 
				
			
			@ -2035,6 +2035,53 @@ class GroupchatControl(ChatControlBase):
 | 
			
		|||
 | 
			
		||||
        del win._controls[self.account][self.contact.jid]
 | 
			
		||||
 | 
			
		||||
    def send_chatstate(self, state, contact):
 | 
			
		||||
        """
 | 
			
		||||
        Send OUR chatstate as STANDLONE chat state message (eg. no body)
 | 
			
		||||
        to contact only if new chatstate is different from the previous one
 | 
			
		||||
        if jid is not specified, send to active tab
 | 
			
		||||
        """
 | 
			
		||||
        # JEP 85 does not allow resending the same chatstate
 | 
			
		||||
        # this function checks for that and just returns so it's safe to call it
 | 
			
		||||
        # with same state.
 | 
			
		||||
 | 
			
		||||
        # This functions also checks for violation in state transitions
 | 
			
		||||
        # and raises RuntimeException with appropriate message
 | 
			
		||||
        # more on that http://xmpp.org/extensions/xep-0085.html#statechart
 | 
			
		||||
 | 
			
		||||
        # do not send if we have chat state notifications disabled
 | 
			
		||||
        # that means we won't reply to the <active/> from other peer
 | 
			
		||||
        # so we do not broadcast jep85 capabalities
 | 
			
		||||
        chatstate_setting = gajim.config.get('outgoing_chat_state_notifications')
 | 
			
		||||
        if chatstate_setting == 'disabled':
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        elif chatstate_setting == 'composing_only' and state != 'active' and\
 | 
			
		||||
                state != 'composing':
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        # if the new state we wanna send (state) equals
 | 
			
		||||
        # the current state (contact.our_chatstate) then return
 | 
			
		||||
        if contact.our_chatstate == state:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        # if wel're inactive prevent composing (XEP violation)
 | 
			
		||||
        if contact.our_chatstate == 'inactive' and state == 'composing':
 | 
			
		||||
            # go active before
 | 
			
		||||
            gajim.nec.push_outgoing_event(GcMessageOutgoingEvent(None,
 | 
			
		||||
                account=self.account, jid=self.contact.jid, chatstate='active',
 | 
			
		||||
                control=self))
 | 
			
		||||
            contact.our_chatstate = 'active'
 | 
			
		||||
            self.reset_kbd_mouse_timeout_vars()
 | 
			
		||||
 | 
			
		||||
        gajim.nec.push_outgoing_event(GcMessageOutgoingEvent(None,
 | 
			
		||||
            account=self.account, jid=self.contact.jid, chatstate=state,
 | 
			
		||||
            control=self))
 | 
			
		||||
 | 
			
		||||
        contact.our_chatstate = state
 | 
			
		||||
        if state == 'active':
 | 
			
		||||
            self.reset_kbd_mouse_timeout_vars()
 | 
			
		||||
 | 
			
		||||
    def shutdown(self, status='offline'):
 | 
			
		||||
        # PluginSystem: calling shutdown of super class (ChatControlBase)
 | 
			
		||||
        # to let it remove it's GUI extension points
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3215,6 +3215,9 @@ class RosterWindow:
 | 
			
		|||
        if not mw:
 | 
			
		||||
            mw = gajim.interface.msg_win_mgr.create_window(ctrl.contact,
 | 
			
		||||
                ctrl.account, ctrl.type_id)
 | 
			
		||||
            id_ = mw.window.connect('motion-notify-event',
 | 
			
		||||
                ctrl._on_window_motion_notify)
 | 
			
		||||
            ctrl.handlers[id_] = mw.window
 | 
			
		||||
        ctrl.parent_win = mw
 | 
			
		||||
        ctrl.set_tooltip()
 | 
			
		||||
        mw.new_tab(ctrl)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue