diff options
-rw-r--r-- | desktop/inc/lib/init.hxx | 5 | ||||
-rw-r--r-- | desktop/source/lib/init.cxx | 197 |
2 files changed, 168 insertions, 34 deletions
diff --git a/desktop/inc/lib/init.hxx b/desktop/inc/lib/init.hxx index 0d019975a090..db281688c2f9 100644 --- a/desktop/inc/lib/init.hxx +++ b/desktop/inc/lib/init.hxx @@ -11,6 +11,7 @@ #define INCLUDED_DESKTOP_INC_LIB_INIT_HXX #include <map> +#include <unordered_map> #include <memory> #include <mutex> @@ -46,6 +47,9 @@ namespace desktop { void setPartTilePainting(const bool bPartPainting) { m_bPartTilePainting = bPartPainting; } bool isPartTilePainting() const { return m_bPartTilePainting; } + void addViewStates(int viewId); + void removeViewStates(int viewId); + typedef std::vector<std::pair<int, std::string>> queue_type; private: @@ -54,6 +58,7 @@ namespace desktop { queue_type m_queue; std::map<int, std::string> m_states; + std::unordered_map<int, std::unordered_map<int, std::string>> m_viewStates; LibreOfficeKitDocument* m_pDocument; LibreOfficeKitCallback m_pCallback; void *m_pData; diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx index ffd0732b0d38..0a839418c397 100644 --- a/desktop/source/lib/init.cxx +++ b/desktop/source/lib/init.cxx @@ -324,6 +324,8 @@ static boost::property_tree::ptree unoAnyToPropertyTree(const uno::Any& anyItem) return aTree; } +namespace { + Rectangle lcl_ParseRect(const std::string& payload) { std::istringstream iss(payload); @@ -334,6 +336,32 @@ Rectangle lcl_ParseRect(const std::string& payload) return rc; } +bool lcl_isViewCallbackType(const int type) +{ + switch (type) + { + case LOK_CALLBACK_CELL_VIEW_CURSOR: + case LOK_CALLBACK_GRAPHIC_VIEW_SELECTION: + case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR: + case LOK_CALLBACK_TEXT_VIEW_SELECTION: + case LOK_CALLBACK_VIEW_CURSOR_VISIBLE: + return true; + + default: + return false; + } +} + +int lcl_getViewId(const std::string& payload) +{ + boost::property_tree::ptree aTree; + std::stringstream aStream(payload); + boost::property_tree::read_json(aStream, aTree); + return aTree.get<int>("viewId"); +} + +} // end anonymous namespace + extern "C" { @@ -487,18 +515,13 @@ CallbackFlushHandler::CallbackFlushHandler(LibreOfficeKitDocument* pDocument, Li m_states.emplace(LOK_CALLBACK_TEXT_SELECTION_END, "NIL"); m_states.emplace(LOK_CALLBACK_TEXT_SELECTION, "NIL"); m_states.emplace(LOK_CALLBACK_GRAPHIC_SELECTION, "NIL"); - m_states.emplace(LOK_CALLBACK_GRAPHIC_VIEW_SELECTION, "NIL"); m_states.emplace(LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR, "NIL"); - m_states.emplace(LOK_CALLBACK_INVALIDATE_VIEW_CURSOR , "NIL"); m_states.emplace(LOK_CALLBACK_STATE_CHANGED, "NIL"); m_states.emplace(LOK_CALLBACK_MOUSE_POINTER, "NIL"); m_states.emplace(LOK_CALLBACK_CELL_CURSOR, "NIL"); - m_states.emplace(LOK_CALLBACK_CELL_VIEW_CURSOR, "NIL"); m_states.emplace(LOK_CALLBACK_CELL_FORMULA, "NIL"); m_states.emplace(LOK_CALLBACK_CURSOR_VISIBLE, "NIL"); - m_states.emplace(LOK_CALLBACK_VIEW_CURSOR_VISIBLE, "NIL"); m_states.emplace(LOK_CALLBACK_SET_PART, "NIL"); - m_states.emplace(LOK_CALLBACK_TEXT_VIEW_SELECTION, "NIL"); Start(); } @@ -564,24 +587,49 @@ void CallbackFlushHandler::queue(const int type, const char* data) std::unique_lock<std::mutex> lock(m_mutex); - const auto stateIt = m_states.find(type); - if (stateIt != m_states.end()) + // drop duplicate callbacks for the listed types + switch (type) { - // If the state didn't change, it's safe to ignore. - if (stateIt->second == payload) + case LOK_CALLBACK_TEXT_SELECTION_START: + case LOK_CALLBACK_TEXT_SELECTION_END: + case LOK_CALLBACK_TEXT_SELECTION: + case LOK_CALLBACK_GRAPHIC_SELECTION: + case LOK_CALLBACK_GRAPHIC_VIEW_SELECTION: + case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR: + case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR : + case LOK_CALLBACK_STATE_CHANGED: + case LOK_CALLBACK_MOUSE_POINTER: + case LOK_CALLBACK_CELL_CURSOR: + case LOK_CALLBACK_CELL_VIEW_CURSOR: + case LOK_CALLBACK_CELL_FORMULA: + case LOK_CALLBACK_CURSOR_VISIBLE: + case LOK_CALLBACK_VIEW_CURSOR_VISIBLE: + case LOK_CALLBACK_SET_PART: + case LOK_CALLBACK_TEXT_VIEW_SELECTION: { - //SAL_WARN("lok", "Skipping duplicate [" + std::to_string(type) + "]: [" + payload + "]."); - return; - } + const auto& pos = std::find_if(m_queue.rbegin(), m_queue.rend(), + [type] (const queue_type::value_type& elem) { return (elem.first == type); }); - stateIt->second = payload; + if (pos != m_queue.rend() && pos->second == payload) + { + //SAL_WARN("lok", "Skipping queue duplicate [" + std::to_string(type) + "]: [" + payload + "]."); + return; + } + } + break; } if (type == LOK_CALLBACK_TEXT_SELECTION && payload.empty()) { - // Removing text selection invalidates the start and end as well. - m_states[LOK_CALLBACK_TEXT_SELECTION_START] = ""; - m_states[LOK_CALLBACK_TEXT_SELECTION_END] = ""; + const auto& posStart = std::find_if(m_queue.rbegin(), m_queue.rend(), + [] (const queue_type::value_type& elem) { return (elem.first == LOK_CALLBACK_TEXT_SELECTION_START); }); + if (posStart != m_queue.rend()) + posStart->second = ""; + + const auto& posEnd = std::find_if(m_queue.rbegin(), m_queue.rend(), + [] (const queue_type::value_type& elem) { return (elem.first == LOK_CALLBACK_TEXT_SELECTION_END); }); + if (posEnd != m_queue.rend()) + posEnd->second = ""; } // When payload is empty discards any previous state. @@ -629,25 +677,10 @@ void CallbackFlushHandler::queue(const int type, const char* data) case LOK_CALLBACK_TEXT_VIEW_SELECTION: case LOK_CALLBACK_VIEW_CURSOR_VISIBLE: { - boost::property_tree::ptree aTree; - std::stringstream aStream(payload); - boost::property_tree::read_json(aStream, aTree); - const int nViewId = aTree.get<int>("viewId"); - + const int nViewId = lcl_getViewId(payload); removeAll( [type, nViewId] (const queue_type::value_type& elem) { - if (elem.first == type) - { - boost::property_tree::ptree aElemTree; - std::stringstream aElemStream(elem.second); - boost::property_tree::read_json(aElemStream, aElemTree); - int nElemViewId = aElemTree.get<int>("viewId"); - return (nViewId == nElemViewId); - } - else - { - return false; - } + return (elem.first == type && nViewId == lcl_getViewId(elem.second)); } ); } @@ -716,9 +749,56 @@ void CallbackFlushHandler::flush() if (m_pCallback && !m_bEventLatch) { std::unique_lock<std::mutex> lock(m_mutex); + for (auto& pair : m_queue) { - m_pCallback(pair.first, pair.second.c_str(), m_pData); + const int type = pair.first; + const auto& payload = pair.second; + const int viewId = lcl_isViewCallbackType(type) ? lcl_getViewId(payload) : -1; + + if (viewId == -1) + { + 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_WARN("lok", "Skipping duplicate [" + std::to_string(type) + "]: [" + payload + "]."); + continue; + } + + stateIt->second = payload; + } + } + else + { + const auto statesIt = m_viewStates.find(viewId); + if (statesIt != m_viewStates.end()) + { + auto& states = statesIt->second; + const auto stateIt = states.find(type); + if (stateIt != states.end()) + { + // If the state didn't change, it's safe to ignore. + if (stateIt->second == payload) + { + //SAL_WARN("lok", "Skipping view duplicate [" + std::to_string(type) + "," + std::to_string(viewId) + "]: [" + payload + "]."); + continue; + } + + stateIt->second = payload; + //SAL_WARN("lok", "Replacing an element in view states [" + std::to_string(type) + "," + std::to_string(viewId) + "]: [" + payload + "]."); + } + else + { + states.emplace(type, payload); + //SAL_WARN("lok", "Inserted a new element in view states: [" + std::to_string(type) + "," + std::to_string(viewId) + "]: [" + payload + "]"); + } + } + } + + m_pCallback(type, payload.c_str(), m_pData); } m_queue.clear(); @@ -731,6 +811,20 @@ void CallbackFlushHandler::removeAll(const std::function<bool (const CallbackFlu m_queue.erase(newEnd, m_queue.end()); } +void CallbackFlushHandler::addViewStates(int viewId) +{ + const auto& result = m_viewStates.emplace(viewId, decltype(m_viewStates)::mapped_type()); + if (!result.second && result.first != m_viewStates.end()) + { + result.first->second.clear(); + } +} + +void CallbackFlushHandler::removeViewStates(int viewId) +{ + m_viewStates.erase(viewId); +} + static void doc_destroy(LibreOfficeKitDocument *pThis) { @@ -1472,8 +1566,43 @@ static void doc_registerCallback(LibreOfficeKitDocument* pThis, if (nView < 0) return; + if (pCallback != nullptr) + { + size_t nId = nView; + for (auto& pair : pDocument->mpCallbackFlushHandlers) + { + if (pair.first == nId) + continue; + + pair.second->addViewStates(nView); + } + } + else + { + size_t nId = nView; + for (auto& pair : pDocument->mpCallbackFlushHandlers) + { + if (pair.first == nId) + continue; + + pair.second->removeViewStates(nView); + } + } + pDocument->mpCallbackFlushHandlers[nView].reset(new CallbackFlushHandler(pThis, pCallback, pData)); + if (pCallback != nullptr) + { + size_t nId = nView; + for (const auto& pair : pDocument->mpCallbackFlushHandlers) + { + if (pair.first == nId) + continue; + + pDocument->mpCallbackFlushHandlers[nView]->addViewStates(pair.first); + } + } + if (SfxViewShell* pViewShell = SfxViewFrame::Current()->GetViewShell()) pViewShell->registerLibreOfficeKitViewCallback(CallbackFlushHandler::callback, pDocument->mpCallbackFlushHandlers[nView].get()); } |