diff options
Diffstat (limited to 'desktop/source/lib/init.cxx')
-rw-r--r-- | desktop/source/lib/init.cxx | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx index ccb27c1bd398..caa6cd2fe62a 100644 --- a/desktop/source/lib/init.cxx +++ b/desktop/source/lib/init.cxx @@ -430,6 +430,203 @@ LibLODocument_Impl::~LibLODocument_Impl() mxComponent->dispose(); } +CallbackFlushHandler::CallbackFlushHandler(LibreOfficeKitCallback pCallback, void* pData) + : Idle( "lokit timer callback" ), + m_pCallback(pCallback), + m_pData(pData), + m_bPartTilePainting(false) +{ + SetPriority(SchedulerPriority::POST_PAINT); + + // Add the states that are safe to skip duplicates on, + // even when not consequent. + m_states.emplace(LOK_CALLBACK_TEXT_SELECTION_START, "NIL"); + 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_INVALIDATE_VISIBLE_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_FORMULA, "NIL"); + m_states.emplace(LOK_CALLBACK_CURSOR_VISIBLE, "NIL"); + m_states.emplace(LOK_CALLBACK_SET_PART, "NIL"); + + Start(); +} + +CallbackFlushHandler::~CallbackFlushHandler() +{ + Stop(); + + // We might have important notification (.uno:save?). + flush(); +} + +void CallbackFlushHandler::Invoke() +{ + flush(); +} + +void CallbackFlushHandler::callback(const int type, const char* payload, void* data) +{ + CallbackFlushHandler* self = static_cast<CallbackFlushHandler*>(data); + if (self) + { + self->queue(type, payload); + } +} + +void CallbackFlushHandler::queue(const int type, const char* data) +{ + const std::string payload(data ? data : "(nil)"); + if (m_bPartTilePainting) + { + // We drop notifications when this is set, except for important ones. + // When we issue a complex command (such as .uno:InsertAnnotation) + // there will be multiple notifications. On the first invalidation + // we will start painting, but other events will get fired + // while the complex command in question executes. + // We don't want to supress everything here on the wrong assumption + // that no new events are fired during painting. + if (type != LOK_CALLBACK_STATE_CHANGED && + type != LOK_CALLBACK_INVALIDATE_TILES && + type != LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR && + type != LOK_CALLBACK_CURSOR_VISIBLE && + type != LOK_CALLBACK_TEXT_SELECTION) + { + //SAL_WARN("lokevt", "Skipping while painting [" + std::to_string(type) + "]: [" + payload + "]."); + return; + } + } + + // Supress invalid payloads. + if (type == LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR && + payload.find(", 0, 0, ") != std::string::npos) + { + // The cursor position is often the relative coordinates of the widget + // issueing it, instead of the absolute one that we expect. + // This is temporary however, and, once the control is created and initialized + // correctly, it eventually emits the correct absolute coordinates. + //SAL_WARN("lokevt", "Skipping invalid event [" + std::to_string(type) + "]: [" + payload + "]."); + return; + } + + std::unique_lock<std::mutex> lock(m_mutex); + + 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("lokevt", "Skipping duplicate [" + std::to_string(type) + "]: [" + payload + "]."); + return; + } + + stateIt->second = payload; + } + + 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] = ""; + } + + m_queue.emplace_back(type, payload); + + // These are safe to use the latest state and ignore previous + // ones (if any) since the last overrides previous ones. + switch (type) + { + 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_MOUSE_POINTER: + case LOK_CALLBACK_CELL_CURSOR: + case LOK_CALLBACK_CELL_FORMULA: + case LOK_CALLBACK_CURSOR_VISIBLE: + case LOK_CALLBACK_SET_PART: + case LOK_CALLBACK_STATUS_INDICATOR_SET_VALUE: + removeAllButLast(type, false); + break; + + // These come with rects, so drop earlier + // only when the latter includes former ones. + case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR: + case LOK_CALLBACK_INVALIDATE_TILES: + if (payload.empty()) + { + // Invalidating everything means previously + // invalidated tiles can be dropped. + removeAllButLast(type, false); + } + else + { + removeAllButLast(type, true); + } + + break; + } + + lock.unlock(); + if (!IsActive()) + { + Start(); + } +} + +void CallbackFlushHandler::setPartTilePainting(const bool bPartPainting) +{ + m_bPartTilePainting = bPartPainting; +} + +bool CallbackFlushHandler::isPartTilePainting() const +{ + return m_bPartTilePainting; +} + +void CallbackFlushHandler::flush() +{ + if (m_pCallback) + { + std::unique_lock<std::mutex> lock(m_mutex); + for (auto& pair : m_queue) + { + m_pCallback(pair.first, pair.second.c_str(), m_pData); + } + + m_queue.clear(); + } +} + +void CallbackFlushHandler::removeAllButLast(const int type, const bool identical) +{ + int i = m_queue.size() - 1; + std::string payload; + for (; i >= 0; --i) + { + if (m_queue[i].first == type) + { + payload = m_queue[i].second; + //SAL_WARN("lokevt", "Found [" + std::to_string(type) + "] at " + std::to_string(i) + ": [" + payload + "]."); + break; + } + } + + for (--i; i >= 0; --i) + { + if (m_queue[i].first == type && + (!identical || m_queue[i].second == payload)) + { + //SAL_WARN("lokevt", "Removing [" + std::to_string(type) + "] at " + std::to_string(i) + ": " + m_queue[i].second + "]."); + m_queue.erase(m_queue.begin() + i); + } + } +} + static void doc_destroy(LibreOfficeKitDocument *pThis) { LibLODocument_Impl *pDocument = static_cast<LibLODocument_Impl*>(pThis); |