From a344a941026852fc64921a4414e5db775f421346 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Philipp=20H=C3=B6rist?= <forenjunkie@chello.at>
Date: Fri, 15 Dec 2017 23:00:15 +0100
Subject: [PATCH] Fix chatstate flood

The new Placeholder text inside MessageTextView was causing many
buffer changed events.

- Add a method that lets us know if there is user input
- Add logging
---
 gajim/chat_control.py      |  2 ++
 gajim/chat_control_base.py | 32 ++++++++++++++------------------
 gajim/message_textview.py  | 10 ++++++++--
 3 files changed, 24 insertions(+), 20 deletions(-)

diff --git a/gajim/chat_control.py b/gajim/chat_control.py
index 4b473213aa..634ace5a84 100644
--- a/gajim/chat_control.py
+++ b/gajim/chat_control.py
@@ -1116,12 +1116,14 @@ class ChatControl(ChatControlBase):
         # if wel're inactive prevent composing (XEP violation)
         if contact.our_chatstate == 'inactive' and state == 'composing':
             # go active before
+            app.log('chatstates').info('%-10s - %s', 'active', self.contact.jid)
             app.nec.push_outgoing_event(MessageOutgoingEvent(None,
                 account=self.account, jid=self.contact.jid, chatstate='active',
                 control=self))
             contact.our_chatstate = 'active'
             self.reset_kbd_mouse_timeout_vars()
 
+        app.log('chatstates').info('%-10s - %s', state, self.contact.jid)
         app.nec.push_outgoing_event(MessageOutgoingEvent(None,
             account=self.account, jid=self.contact.jid, chatstate=state,
             control=self))
diff --git a/gajim/chat_control_base.py b/gajim/chat_control_base.py
index 2be8a21f74..78bb334203 100644
--- a/gajim/chat_control_base.py
+++ b/gajim/chat_control_base.py
@@ -797,18 +797,16 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
             self.possible_paused_timeout_id = None
             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
+        if current_state == 'composing':
+            if not self.kbd_activity_in_last_5_secs:
+                if self.msg_textview.has_text():
+                    self.send_chatstate('paused', self.contact)
+                else:
+                    self.send_chatstate('active', self.contact)
+        elif current_state == 'inactive':
+            if (self.mouse_over_in_last_5_secs and
+                    jid == self.parent_win.get_active_jid()):
+                self.send_chatstate('active', self.contact)
 
         # 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!
@@ -870,10 +868,9 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
     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)
+        if not self.msg_textview.has_text():
+            return
+        self.send_chatstate('composing', self.contact)
 
     def save_message(self, message, msg_type):
         # save the message, so user can scroll though the list with key up/down
@@ -1146,8 +1143,7 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
                     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():
+            if self.msg_textview.has_text():
                 self.send_chatstate('paused', self.contact)
             else:
                 self.send_chatstate('active', self.contact)
diff --git a/gajim/message_textview.py b/gajim/message_textview.py
index f9bb99c291..f76fdc603f 100644
--- a/gajim/message_textview.py
+++ b/gajim/message_textview.py
@@ -100,10 +100,16 @@ class MessageTextView(Gtk.TextView):
         buf = self.get_buffer()
         start, end = buf.get_bounds()
         text = buf.get_text(start, end, True)
-        return text != self.PLACEHOLDER
+        return text != self.PLACEHOLDER and text != ''
+
+    def is_placeholder(self):
+        buf = self.get_buffer()
+        start, end = buf.get_bounds()
+        text = buf.get_text(start, end, True)
+        return text == self.PLACEHOLDER
 
     def _on_focus_in(self, *args):
-        if not self.has_text():
+        if self.is_placeholder():
             self.get_buffer().set_text('')
         self.toggle_speller(True)
 
-- 
GitLab