summaryrefslogtreecommitdiff
path: root/desktop
diff options
context:
space:
mode:
Diffstat (limited to 'desktop')
-rw-r--r--desktop/inc/lib/init.hxx23
-rw-r--r--desktop/source/lib/init.cxx144
2 files changed, 167 insertions, 0 deletions
diff --git a/desktop/inc/lib/init.hxx b/desktop/inc/lib/init.hxx
index bc090fc208a9..01620a4f02ac 100644
--- a/desktop/inc/lib/init.hxx
+++ b/desktop/inc/lib/init.hxx
@@ -104,6 +104,8 @@ namespace desktop {
virtual void libreOfficeKitViewCallback(int nType, const char* pPayload) override;
virtual void libreOfficeKitViewCallbackWithViewId(int nType, const char* pPayload, int nViewId) override;
virtual void libreOfficeKitViewInvalidateTilesCallback(const tools::Rectangle* pRect, int nPart) override;
+ virtual void libreOfficeKitViewUpdatedCallback(int nType) override;
+ virtual void libreOfficeKitViewUpdatedCallbackPerViewId(int nType, int nViewId, int nSourceViewId) override;
private:
struct CallbackData
@@ -171,6 +173,8 @@ namespace desktop {
queue_type2::iterator toQueue2(queue_type1::iterator);
queue_type2::reverse_iterator toQueue2(queue_type1::reverse_iterator);
void queue(const int type, CallbackData& data);
+ void enqueueUpdatedTypes();
+ void enqueueUpdatedType( int type, SfxViewShell* sourceViewShell, int viewId );
/** we frequently want to scan the queue, and mostly when we do so, we only care about the element type
so we split the queue in 2 to make the scanning cache friendly. */
@@ -178,6 +182,25 @@ namespace desktop {
queue_type2 m_queue2;
std::map<int, std::string> m_states;
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
+ // per each viewId value matters (see isUpdatedTypePerViewId()), so instead of using push model
+ // where we'd get flooded by repeated messages (which might be costly to generate and process),
+ // the preferred way is that libreOfficeKitViewUpdatedCallback()
+ // or libreOfficeKitViewUpdatedCallbackPerViewId() get called to notify about such a message being
+ // needed, and we'll set a flag here to fetch the actual message before flushing.
+ void setUpdatedType( int nType, bool value );
+ void setUpdatedTypePerViewId( int nType, int nViewId, int nSourceViewId, bool value );
+ void resetUpdatedType( int nType);
+ void resetUpdatedTypePerViewId( int nType, int nViewId );
+ std::vector<bool> m_updatedTypes; // index is type, value is if set
+ struct PerViewIdData
+ {
+ bool set; // value is if set
+ int sourceViewId;
+ };
+ std::unordered_map<int, std::vector<PerViewIdData>> m_updatedTypesPerViewId; // key is view, index is type
+
LibreOfficeKitDocument* m_pDocument;
int m_viewId = -1; // view id of the associated SfxViewShell
LibreOfficeKitCallback m_pCallback;
diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index ba3315306464..c38a6dd8d754 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -698,6 +698,23 @@ static bool lcl_isViewCallbackType(const int type)
}
}
+static bool isUpdatedType(int /*type*/)
+{
+ return false;
+}
+
+static bool isUpdatedTypePerViewId(int type)
+{
+ switch (type)
+ {
+ case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR:
+ case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR:
+ return true;
+ default:
+ return false;
+ }
+}
+
static int lcl_getViewId(const std::string& payload)
{
// this is a cheap way how to get the viewId from a JSON message; proper
@@ -1455,6 +1472,48 @@ CallbackFlushHandler::queue_type2::reverse_iterator CallbackFlushHandler::toQueu
return m_queue2.rbegin() + delta;
}
+void CallbackFlushHandler::setUpdatedType( int nType, bool value )
+{
+ assert(isUpdatedType(nType));
+ if( m_updatedTypes.size() <= o3tl::make_unsigned( nType ))
+ m_updatedTypes.resize( nType + 1 ); // new are default-constructed, i.e. false
+ m_updatedTypes[ nType ] = value;
+}
+
+void CallbackFlushHandler::resetUpdatedType( int nType )
+{
+ setUpdatedType( nType, false );
+}
+
+void CallbackFlushHandler::setUpdatedTypePerViewId( int nType, int nViewId, int nSourceViewId, bool value )
+{
+ assert(isUpdatedTypePerViewId(nType));
+ std::vector<PerViewIdData>& types = m_updatedTypesPerViewId[ nViewId ];
+ if( types.size() <= o3tl::make_unsigned( nType ))
+ types.resize( nType + 1 ); // new are default-constructed, i.e. false
+ types[ nType ] = PerViewIdData{ value, nSourceViewId };
+}
+
+void CallbackFlushHandler::resetUpdatedTypePerViewId( int nType, int nViewId )
+{
+ assert(isUpdatedTypePerViewId(nType));
+ bool allViewIds = false;
+ // Handle specially messages that do not have viewId for backwards compatibility.
+ if( nType == LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR && !comphelper::LibreOfficeKit::isViewIdForVisCursorInvalidation())
+ allViewIds = true;
+ if( !allViewIds )
+ {
+ setUpdatedTypePerViewId( nType, nViewId, -1, false );
+ return;
+ }
+ for( auto& it : m_updatedTypesPerViewId )
+ {
+ std::vector<PerViewIdData>& types = it.second;
+ if( types.size() >= o3tl::make_unsigned( nType ))
+ types[ nType ].set = false;
+ }
+}
+
void CallbackFlushHandler::libreOfficeKitViewCallback(int nType, const char* pPayload)
{
CallbackData callbackData(pPayload);
@@ -1473,6 +1532,22 @@ void CallbackFlushHandler::libreOfficeKitViewInvalidateTilesCallback(const tools
queue(LOK_CALLBACK_INVALIDATE_TILES, callbackData);
}
+void CallbackFlushHandler::libreOfficeKitViewUpdatedCallback(int nType)
+{
+ assert(isUpdatedType( nType ));
+ std::unique_lock<std::mutex> lock(m_mutex);
+ SAL_INFO("lok", "Updated: [" << nType << "]");
+ setUpdatedType(nType, true);
+}
+
+void CallbackFlushHandler::libreOfficeKitViewUpdatedCallbackPerViewId(int nType, int nViewId, int nSourceViewId)
+{
+ assert(isUpdatedTypePerViewId( nType ));
+ std::unique_lock<std::mutex> lock(m_mutex);
+ SAL_INFO("lok", "Updated: [" << nType << "]");
+ setUpdatedTypePerViewId(nType, nViewId, nSourceViewId, true);
+}
+
void CallbackFlushHandler::queue(const int type, const char* data)
{
CallbackData callbackData(data);
@@ -1536,6 +1611,20 @@ void CallbackFlushHandler::queue(const int type, CallbackData& aCallbackData)
std::unique_lock<std::mutex> lock(m_mutex);
+ // Update types should be received via the updated callbacks for performance,
+ // getting them as normal callbacks is technically not wrong, but probably should be avoided.
+ // Reset the updated flag if we get a normal message.
+ if(isUpdatedType(type))
+ {
+ SAL_INFO("lok", "Received event with updated type [" << type << "] as normal callback");
+ resetUpdatedType(type);
+ }
+ if(isUpdatedTypePerViewId(type))
+ {
+ SAL_INFO("lok", "Received event with updated type [" << type << "] as normal callback");
+ resetUpdatedTypePerViewId(type, aCallbackData.getViewId());
+ }
+
// drop duplicate callbacks for the listed types
switch (type)
{
@@ -2028,6 +2117,58 @@ bool CallbackFlushHandler::processWindowEvent(int type, CallbackData& aCallbackD
return false;
}
+void CallbackFlushHandler::enqueueUpdatedTypes()
+{
+ if( m_updatedTypes.empty() && m_updatedTypesPerViewId.empty())
+ return;
+ SfxViewShell* viewShell = SfxViewShell::GetFirst( false,
+ [this](const SfxViewShell* shell) { return shell->GetViewShellId().get() == m_viewId; } );
+ assert(viewShell != nullptr);
+ for( size_t type = 0; type < m_updatedTypes.size(); ++type )
+ {
+ if(m_updatedTypes[ type ])
+ {
+ assert(isUpdatedType( type ));
+ enqueueUpdatedType( type, viewShell, m_viewId );
+ }
+ }
+ for( const auto& it : m_updatedTypesPerViewId )
+ {
+ int viewId = it.first;
+ const std::vector<PerViewIdData>& types = it.second;
+ for( size_t type = 0; type < types.size(); ++type )
+ {
+ if(types[ type ].set)
+ {
+ assert(isUpdatedTypePerViewId( type ));
+ SfxViewShell* sourceViewShell = viewShell;
+ const int sourceViewId = types[ type ].sourceViewId;
+ if( sourceViewId != m_viewId )
+ sourceViewShell = SfxViewShell::GetFirst( false,
+ [sourceViewId](const SfxViewShell* shell) { return shell->GetViewShellId().get() == sourceViewId; } );
+ if(sourceViewShell == nullptr)
+ {
+ SAL_INFO("lok", "View #" << sourceViewId << " no longer found for updated event [" << type << "]");
+ continue; // View removed, probably cleaning up.
+ }
+ enqueueUpdatedType( type, sourceViewShell, viewId );
+ }
+ }
+ }
+ m_updatedTypes.clear();
+ m_updatedTypesPerViewId.clear();
+}
+
+void CallbackFlushHandler::enqueueUpdatedType( int type, SfxViewShell* viewShell, int viewId )
+{
+ OString payload = viewShell->getLOKPayload( type, viewId );
+ CallbackData callbackData(payload.getStr(), viewId);
+ m_queue1.emplace_back(type);
+ m_queue2.emplace_back(callbackData);
+ SAL_INFO("lok", "Queued updated [" << type << "]: [" << callbackData.getPayload()
+ << "] to have " << m_queue1.size() << " entries.");
+}
+
void CallbackFlushHandler::Invoke()
{
comphelper::ProfileZone aZone("CallbackFlushHandler::Invoke");
@@ -2045,6 +2186,9 @@ void CallbackFlushHandler::Invoke()
std::scoped_lock<std::mutex> lock(m_mutex);
+ // Append messages for updated types, fetch them only now.
+ enqueueUpdatedTypes();
+
SAL_INFO("lok", "Flushing " << m_queue1.size() << " elements.");
auto it1 = m_queue1.begin();
auto it2 = m_queue2.begin();