diff --git a/gajim/chat_control.py b/gajim/chat_control.py index 4500cb9cd..7f81dc6e8 100644 --- a/gajim/chat_control.py +++ b/gajim/chat_control.py @@ -134,11 +134,6 @@ class ChatControl(ChatControlBase): self.show_avatar() # Hook up signals - 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 - widget = self.xml.get_object('avatar_eventbox') widget.set_property('height-request', AvatarSize.CHAT) @@ -680,7 +675,11 @@ class ChatControl(ChatControlBase): status_escaped = GLib.markup_escape_text(status_reduced) st = app.config.get('displayed_chat_state_notifications') - cs = app.contacts.get_combined_chatstate(self.account, self.contact.jid) + if self.TYPE_ID == 'pm': + cs = self.gc_contact.chatstate + else: + cs = app.contacts.get_combined_chatstate( + self.account, self.contact.jid) if cs and st in ('composing_only', 'all'): if contact.show == 'offline': chatstate = '' @@ -1152,13 +1151,21 @@ class ChatControl(ChatControlBase): if event.account != self.account: return - if event.jid != self.contact.jid: - return + if self.TYPE_ID == 'pm': + if event.contact != self.gc_contact: + return + else: + if event.contact.jid != self.contact.jid: + return self.draw_banner_text() + # update chatstate in tab for this chat - chatstate = app.contacts.get_combined_chatstate( - self.account, self.contact.jid) + if event.contact.is_gc_contact: + chatstate = event.contact.chatstate + else: + chatstate = app.contacts.get_combined_chatstate( + self.account, self.contact.jid) self.parent_win.redraw_tab(self, chatstate) def _nec_caps_received(self, obj): @@ -1239,12 +1246,6 @@ class ChatControl(ChatControlBase): dialogs.TransformChatToMUC(self.account, [c.jid], [dropped_jid]) - def _on_message_tv_buffer_changed(self, textbuffer): - super()._on_message_tv_buffer_changed(textbuffer) - if textbuffer.get_char_count() and self.encryption: - app.plugin_manager.extension_point( - 'typing' + self.encryption, self) - def restore_conversation(self): jid = self.contact.jid # don't restore lines if it's a transport diff --git a/gajim/chat_control_base.py b/gajim/chat_control_base.py index 794597445..770df9529 100644 --- a/gajim/chat_control_base.py +++ b/gajim/chat_control_base.py @@ -341,10 +341,9 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools): con = app.connections[self.account] con.get_module('Chatstate').set_active(self.contact.jid) - message_tv_buffer = self.msg_textview.get_buffer() - id_ = message_tv_buffer.connect('changed', + id_ = self.msg_textview.connect('text-changed', self._on_message_tv_buffer_changed) - self.handlers[id_] = message_tv_buffer + self.handlers[id_] = self.msg_textview if parent_win is not None: id_ = parent_win.window.connect('motion-notify-event', self._on_window_motion_notify) @@ -837,10 +836,14 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools): con = app.connections[self.account] con.get_module('Chatstate').set_mouse_activity(self.contact) - def _on_message_tv_buffer_changed(self, *args): + def _on_message_tv_buffer_changed(self, textview, textbuffer): + if textbuffer.get_char_count() and self.encryption: + app.plugin_manager.extension_point( + 'typing' + self.encryption, self) + con = app.connections[self.account] con.get_module('Chatstate').set_keyboard_activity(self.contact) - if not self.msg_textview.has_text(): + if not textview.has_text(): con.get_module('Chatstate').set_chatstate(self.contact, Chatstate.ACTIVE) return diff --git a/gajim/common/modules/chatstates.py b/gajim/common/modules/chatstates.py index 19ced72be..8015e66dd 100644 --- a/gajim/common/modules/chatstates.py +++ b/gajim/common/modules/chatstates.py @@ -103,13 +103,21 @@ class Chatstate: # Dont show chatstates from our own resources return + if event.mtype == 'groupchat': + # Not implemented yet + return + chatstate = parse_chatstate(event.stanza) if chatstate is None: return - contact = app.contacts.get_contact_from_full_jid( - self._account, event.fjid) - if contact is None or contact.is_gc_contact: + if event.muc_pm: + contact = app.contacts.get_gc_contact( + self._account, event.jid, event.resource) + else: + contact = app.contacts.get_contact_from_full_jid( + self._account, event.fjid) + if contact is None: return contact.chatstate = chatstate @@ -117,7 +125,7 @@ class Chatstate: app.nec.push_outgoing_event( NetworkEvent('chatstate-received', account=self._account, - jid=event.jid)) + contact=contact)) def _check_last_interaction(self) -> GLib.SOURCE_CONTINUE: setting = app.config.get('outgoing_chat_state_notifications') @@ -129,10 +137,10 @@ class Chatstate: current_state = self._chatstates.get(jid) if current_state is None: self._last_mouse_activity.pop(jid, None) - return GLib.SOURCE_CONTINUE + continue if current_state in (State.GONE, State.INACTIVE): - return GLib.SOURCE_CONTINUE + continue new_chatstate = None if now - time_ > INACTIVE_AFTER: @@ -147,9 +155,15 @@ class Chatstate: if self._chatstates.get(jid) != new_chatstate: contact = app.contacts.get_contact(self._account, jid) if contact is None: - self._last_mouse_activity.pop(jid, None) - return GLib.SOURCE_CONTINUE - self.set_chatstate(contact, new_chatstate) + room, nick = app.get_room_and_nick_from_fjid(jid) + contact = app.contacts.get_gc_contact( + self._account, room, nick) + if contact is not None: + contact = contact.as_contact() + else: + self._last_mouse_activity.pop(jid, None) + continue + self.set_chatstate(contact, new_chatstate) return GLib.SOURCE_CONTINUE @@ -196,8 +210,9 @@ class Chatstate: if not contact.is_groupchat(): # Dont leak presence to contacts # which are not allowed to see our status - if contact and contact.sub in ('to', 'none'): - return + if not contact.is_pm_contact: + if contact and contact.sub in ('to', 'none'): + return if contact.show == 'offline': return diff --git a/gajim/message_textview.py b/gajim/message_textview.py index b0790a25c..32836271c 100644 --- a/gajim/message_textview.py +++ b/gajim/message_textview.py @@ -21,6 +21,7 @@ import gc from gi.repository import Gtk from gi.repository import GLib +from gi.repository import GObject from gi.repository import Pango from gajim.common import app @@ -36,6 +37,10 @@ class MessageTextView(Gtk.TextView): Class for the message textview (where user writes new messages) for chat/groupchat windows """ + __gsignals__ = { + 'text-changed': (GObject.SIGNAL_RUN_LAST, None, (Gtk.TextBuffer,)) + } + UNDO_LIMIT = 20 PLACEHOLDER = _('Write a messageā€¦') @@ -60,6 +65,9 @@ class MessageTextView(Gtk.TextView): self.undo_pressed = False buffer_ = self.get_buffer() + buffer_.connect('changed', self._on_buffer_changed) + self._last_text = '' + self.begin_tags = {} self.end_tags = {} self.color_tags = [] @@ -94,6 +102,16 @@ class MessageTextView(Gtk.TextView): buffer_.insert_with_tags( start, self.PLACEHOLDER, self.placeholder_tag) + def _on_buffer_changed(self, *args): + text = self.get_text() + # Because of inserting and removing PLACEHOLDER text + # the signal becomes unreliable when determining if the user + # typed in new text. So we send our own signal depending on if + # there is real new text that is not the PLACEHOLDER + if text != self._last_text: + self.emit('text-changed', self.get_buffer()) + self._last_text = text + def has_text(self): buf = self.get_buffer() start, end = buf.get_bounds() diff --git a/gajim/remote_control.py b/gajim/remote_control.py index 82cf0b020..2c2bd997f 100644 --- a/gajim/remote_control.py +++ b/gajim/remote_control.py @@ -324,9 +324,14 @@ class GajimRemote(Server): self.on_message_sent) def on_chatstate_received(self, obj): - chatstate = app.contacts.get_combined_chatstate( - obj.account, obj.jid) - self.raise_signal('ChatState', (obj.account, [obj.jid, chatstate])) + if obj.contact.is_gc_contact: + jid = obj.contact.get_full_jid() + chatstate = obj.contact.chatstate + else: + jid = obj.contact.jid + chatstate = app.contacts.get_combined_chatstate( + obj.account, obj.contact.jid) + self.raise_signal('ChatState', (obj.account, [jid, chatstate])) def on_message_sent(self, obj): try: