desktop/inc/lib/init.hxx    |    2 +
 desktop/source/lib/init.cxx |   49 +++++++++++++++++++++++++++++++++++---------
 2 files changed, 42 insertions(+), 9 deletions(-)

New commits:
commit 876be07b6dd61eb323428aca6c31c3e58a8488fd
Author:     Michael Meeks <michael.me...@collabora.com>
AuthorDate: Tue Jan 18 17:04:15 2022 +0000
Commit:     Michael Meeks <michael.me...@collabora.com>
CommitDate: Mon Feb 7 13:09:07 2022 +0100

    lok: avoid duplicate emission of statechanged: messages.
    
    We tend to get many of these per keystroke, with the same state.
    
    Change-Id: I9d759f54aee8d6dabcef094997e8f352dd608ec3
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/128578
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Ashod Nakashian <a...@collabora.com>

diff --git a/desktop/inc/lib/init.hxx b/desktop/inc/lib/init.hxx
index bb560264743b..b2ba47239f2f 100644
--- a/desktop/inc/lib/init.hxx
+++ b/desktop/inc/lib/init.hxx
@@ -85,6 +85,7 @@ namespace desktop {
         static tools::Rectangle CheckedRectangle(const tools::Rectangle& rect);
     };
 
+    /// One instance of this per view, handles flushing callbacks
     class DESKTOP_DLLPUBLIC CallbackFlushHandler final : public Idle, public 
SfxLokCallbackInterface
     {
     public:
@@ -190,6 +191,7 @@ namespace desktop {
         queue_type1 m_queue1;
         queue_type2 m_queue2;
         std::map<int, std::string> m_states;
+        std::unordered_map<std::string, std::string> m_lastStateChange;
         std::unordered_map<int, std::unordered_map<int, std::string>> 
m_viewStates;
 
         // For some types only the last message matters (see isUpdatedType()) 
or only the last message
diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index 4693e79ec3f6..2ae5fc89f731 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -1350,6 +1350,7 @@ void CallbackFlushHandler::TimeoutIdle::Invoke()
     mHandler->Invoke();
 }
 
+// One of these is created per view to handle events cf. doc_registerCallback
 CallbackFlushHandler::CallbackFlushHandler(LibreOfficeKitDocument* pDocument, 
LibreOfficeKitCallback pCallback, void* pData)
     : Idle( "lokit idle callback" ),
       m_pDocument(pDocument),
@@ -2151,22 +2152,52 @@ void CallbackFlushHandler::Invoke()
         const auto& payload = it2->getPayload();
         const int viewId = lcl_isViewCallbackType(type) ? it2->getViewId() : 
-1;
 
+        SAL_INFO("lok", "processing event: [" << type << ',' << viewId << "]: 
[" << payload << "].");
+
+        // common code-path for events on this view:
         if (viewId == -1)
         {
-            const auto stateIt = m_states.find(type);
-            if (stateIt != m_states.end())
+            size_t idx;
+            // key-value pairs
+            if (type == LOK_CALLBACK_STATE_CHANGED &&
+                (idx = payload.find('=')) != std::string::npos)
             {
-                // If the state didn't change, it's safe to ignore.
-                if (stateIt->second == payload)
+                std::string key = payload.substr(0, idx);
+                std::string value = payload.substr(idx+1);
+                const auto stateIt = m_lastStateChange.find(key);
+                if (stateIt != m_lastStateChange.end())
                 {
-                    SAL_INFO("lok", "Skipping duplicate [" << type << "]: [" 
<< payload << "].");
-                    continue;
+                    // If the value didn't change, it's safe to ignore.
+                    if (stateIt->second == value)
+                    {
+                        SAL_INFO("lok", "Skipping new state duplicate: [" << 
type << "]: [" << payload << "].");
+                        continue;
+                    }
+                    SAL_INFO("lok", "Replacing a state element [" << type << 
"]: [" << payload << "].");
+                    stateIt->second = value;
+                }
+                else
+                {
+                    SAL_INFO("lok", "Inserted a new state element: [" << type 
<< "]: [" << payload << "]");
+                    m_lastStateChange.emplace(key, value);
+                }
+            }
+            else
+            {
+                const auto stateIt = m_states.find(type);
+                if (stateIt != m_states.end())
+                {
+                    // If the state didn't change, it's safe to ignore.
+                    if (stateIt->second == payload)
+                    {
+                        SAL_INFO("lok", "Skipping duplicate [" << type << "]: 
[" << payload << "].");
+                        continue;
+                    }
+                    stateIt->second = payload;
                 }
-
-                stateIt->second = payload;
             }
         }
-        else
+        else // less common path for events relating to other views
         {
             const auto statesIt = m_viewStates.find(viewId);
             if (statesIt != m_viewStates.end())

Reply via email to