configmgr/source/components.cxx | 6 +++ configmgr/source/node.cxx | 18 ++++++++++- configmgr/source/node.hxx | 4 ++ include/salhelper/simplereferenceobject.hxx | 29 ++++++++++++++---- include/vcl/scheduler.hxx | 6 +++ sc/source/ui/app/inputhdl.cxx | 14 ++++++++ sc/source/ui/inc/tabvwsh.hxx | 1 sfx2/qa/cppunit/view.cxx | 23 ++++++++++++++ sfx2/source/view/lokhelper.cxx | 41 ++++++++++++++++++++------ svx/source/svdraw/svdmrkv.cxx | 3 + sw/source/uibase/lingu/olmenu.cxx | 7 ++-- vcl/source/app/scheduler.cxx | 44 ++++++++++++++++++++++++++++ 12 files changed, 176 insertions(+), 20 deletions(-)
New commits: commit 1b794a18d46de7d58c60eaffd4233aa819bc2d70 Author: Caolán McNamara <[email protected]> AuthorDate: Wed Feb 12 21:12:37 2025 +0000 Commit: Andras Timar <[email protected]> CommitDate: Sat Feb 15 16:30:49 2025 +0100 lok: encourage even more sharing of config Node pages. some properties, e.g. the localized user strings for "uno commands" as used by vcl::CommandInfoProvider::GetCommandProperties are cloned, so the inserted clones are not staticized. Profiles persisted in show many probe:do_wp_page events from salhelper::SimpleReferenceObject::acquire in configmgr::Access::getUnmodifiedChild https: //raw.githubusercontent.com/caolanm/profiles/585ce8645ff6ea1e3de1b3cc6f11a16f325fb0d9/do_wp_page/Demo.eu-2025-02-12T04%3A36%3A21.759836.svg Change-Id: I3eaccbbd7e9af0c312ed1d7da68e64ffb96d3292 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/181513 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Miklos Vajna <[email protected]> diff --git a/configmgr/source/node.cxx b/configmgr/source/node.cxx index 3c8387cfaf43..cd20189387c3 100644 --- a/configmgr/source/node.cxx +++ b/configmgr/source/node.cxx @@ -80,7 +80,10 @@ Node::Node(int layer): layer_(layer), finalized_(Data::NO_LAYER) Node::Node(const Node & other): SimpleReferenceObject(), layer_(other.layer_), finalized_(other.finalized_) -{} +{ + if (CreateStaticizedNodes) + staticize(); +} Node::~Node() {} commit e762002ccd7965a105e017f74636ed0f061c9970 Author: Michael Meeks <[email protected]> AuthorDate: Sat Oct 19 16:57:44 2024 +0100 Commit: Andras Timar <[email protected]> CommitDate: Sat Feb 15 16:30:24 2025 +0100 lok: encourage more sharing of config Node pages. Profiles show lots of probe:do_wp_page events from things like configmgr::Access::getUnmodifiedChild - as when we read we touch lots of Node reference counts - un-necessarily. So - reduce un-necessary reference counting thrash here in the lok case through the environment variable. Quite possibly this would also be safe and beneficial for the desktop app - needs measurement. measuring with coolmap and an empty hello-world.odt before & after: before: unshared 3634 (14536kB) unshared 3631 (14524kB) unshared 3605 (14420kB) after: unshared 3578 (14312kB) unshared 3613 (14452kB) unshared 3599 (14396kB) Not hugely encouraging, perhaps there is another page touch underneath we'll find when this is addressed. Change-Id: I8ac74c5fcd17f8699139e914a7076a7848456e2a Signed-off-by: Michael Meeks <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/175197 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Noel Grandin <[email protected]> diff --git a/configmgr/source/components.cxx b/configmgr/source/components.cxx index 86f2d0928dc6..e5dbe8ca908f 100644 --- a/configmgr/source/components.cxx +++ b/configmgr/source/components.cxx @@ -495,6 +495,10 @@ Components::Components( { assert(context.is()); lock_ = lock(); + + bool staticize = !!getenv("SAL_CONFIG_STATICIZE"); + Node::setStaticizedFlag(staticize); + OUString conf(expand(u"${CONFIGURATION_LAYERS}"_ustr)); int layer = 0; for (sal_Int32 i = 0;;) { @@ -632,6 +636,8 @@ Components::Components( } i = n; } + + Node::setStaticizedFlag(false); } Components::~Components() diff --git a/configmgr/source/node.cxx b/configmgr/source/node.cxx index fdb166f146b8..3c8387cfaf43 100644 --- a/configmgr/source/node.cxx +++ b/configmgr/source/node.cxx @@ -65,7 +65,18 @@ rtl::Reference< Node > Node::getMember(OUString const & name) { return i == members.end() ? rtl::Reference< Node >() : i->second; } -Node::Node(int layer): layer_(layer), finalized_(Data::NO_LAYER) {} +bool Node::CreateStaticizedNodes = false; + +void Node::setStaticizedFlag(bool staticized) +{ + CreateStaticizedNodes = staticized; +} + +Node::Node(int layer): layer_(layer), finalized_(Data::NO_LAYER) +{ + if (CreateStaticizedNodes) + staticize(); +} Node::Node(const Node & other): SimpleReferenceObject(), layer_(other.layer_), finalized_(other.finalized_) diff --git a/configmgr/source/node.hxx b/configmgr/source/node.hxx index df5a127cdbb5..304307677176 100644 --- a/configmgr/source/node.hxx +++ b/configmgr/source/node.hxx @@ -50,6 +50,9 @@ public: void setLayer(int layer); int getLayer() const { return layer_;} + /// when @staticized is set all new nodes will not ref-count + static void setStaticizedFlag(bool staticized); + void setFinalized(int layer); int getFinalized() const { return finalized_;} @@ -67,6 +70,7 @@ private: int layer_; int finalized_; OUString description_; + static bool CreateStaticizedNodes; }; } commit a570bdc7753aa4d790d65f6e55d62990b05fbd09 Author: Michael Meeks <[email protected]> AuthorDate: Thu Oct 17 07:24:10 2024 +0200 Commit: Andras Timar <[email protected]> CommitDate: Sat Feb 15 16:29:46 2025 +0100 SimpleReferenceObject: add ability to staticize the ref-count. Useful for when we allocate data at startup and want to share it across multiple threads. Also potentiall useful for turning extreme cases of ref-count wrap-around into a more benign leak. Change-Id: I04e6a62dbd366d294d86ab72036c3498402357f0 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/175196 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Noel Grandin <[email protected]> diff --git a/include/salhelper/simplereferenceobject.hxx b/include/salhelper/simplereferenceobject.hxx index ac721ad3da98..59a2baf83bc6 100644 --- a/include/salhelper/simplereferenceobject.hxx +++ b/include/salhelper/simplereferenceobject.hxx @@ -60,20 +60,28 @@ namespace salhelper { */ class SALHELPER_DLLPUBLIC SimpleReferenceObject { + static const size_t nStaticFlag = 0x80000000; + public: SimpleReferenceObject(): m_nCount(0) {} /** @attention - The results are undefined if, for any individual instance of - SimpleReferenceObject, the total number of calls to acquire() exceeds - the total number of calls to release() by a platform dependent amount - (which, hopefully, is quite large). + If, for any individual instance of SimpleReferenceObject, the total + number of calls to acquire() exceeds the total number of calls to + release() by 2^31 - the object will never subsequently be released. */ void acquire() - { osl_atomic_increment(&m_nCount); } + { + if (!(m_nCount & nStaticFlag)) + osl_atomic_increment(&m_nCount); + } void release() - { if (osl_atomic_decrement(&m_nCount) == 0) delete this; } + { + if (!(m_nCount & nStaticFlag) && + osl_atomic_decrement(&m_nCount) == 0) + delete this; + } /** see general class documentation */ @@ -95,6 +103,15 @@ public: protected: virtual ~SimpleReferenceObject() COVERITY_NOEXCEPT_FALSE; + /** mark reference count as not to be touched, and the + * related object as having an indefinite lifespan. + * NB. do not use if you have a non-empty destructor. + */ + void staticize() + { + m_nCount |= nStaticFlag; + } + oslInterlockedCount m_nCount; private: commit 059287a77d5454b4df9c1096280e80846bc61819 Author: Miklos Vajna <[email protected]> AuthorDate: Fri Feb 14 14:20:21 2025 +0100 Commit: Andras Timar <[email protected]> CommitDate: Sat Feb 15 16:29:20 2025 +0100 cool#11064 vcl lok: expose info about the scheduler A LOK client can interrupt the vcl main loop in its 'any input' callback. When making that decision, it's useful in case it can know what's the priority of the most urgent job, for example it may want core to still finish high priority tasks, but not idle ones. Add a LOK API to expose this info. Keep it minimal, so it's realistic to call this frequently from a LOK client. Change-Id: Id51668eb8156067e60d6fd0f33606c65858008a9 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/181668 Reviewed-by: Michael Meeks <[email protected]> Tested-by: Jenkins CollaboraOffice <[email protected]> diff --git a/include/vcl/scheduler.hxx b/include/vcl/scheduler.hxx index 0181e52c33d2..36af96ded55e 100644 --- a/include/vcl/scheduler.hxx +++ b/include/vcl/scheduler.hxx @@ -23,6 +23,10 @@ #include <vcl/dllapi.h> struct ImplSchedulerContext; +namespace tools +{ +class JsonWriter; +} class VCL_DLLPUBLIC Scheduler final { @@ -88,6 +92,8 @@ public: IdlesLockGuard(); ~IdlesLockGuard(); }; + + static void dumpAsJSON(tools::JsonWriter& rJsonWriter); }; #endif // INCLUDED_VCL_SCHEDULER_HXX diff --git a/sfx2/qa/cppunit/view.cxx b/sfx2/qa/cppunit/view.cxx index 8c5be5920a07..dad9e4a51f45 100644 --- a/sfx2/qa/cppunit/view.cxx +++ b/sfx2/qa/cppunit/view.cxx @@ -221,6 +221,29 @@ CPPUNIT_TEST_FIXTURE(Sfx2ViewTest, testSignatureSerialize) // provided parameters. CPPUNIT_ASSERT_EQUAL(1, pPdfDocument->getSignatureCount()); } + +CPPUNIT_TEST_FIXTURE(Sfx2ViewTest, testScheduler) +{ + // Given an empty document: + mxComponent = loadFromDesktop("private:factory/swriter", "com.sun.star.text.TextDocument"); + + // When asking for the state of the scheduler: + tools::JsonWriter aWriter; + SfxLokHelper::getCommandValues(aWriter, ".uno:Scheduler"); + OString aJson = aWriter.finishAndGetAsOString(); + + // Then make sure we get an int priority: + CPPUNIT_ASSERT(SfxLokHelper::supportsCommand(u"Scheduler")); + std::stringstream aStream{ std::string(aJson) }; + boost::property_tree::ptree aTree; + boost::property_tree::read_json(aStream, aTree); + auto it = aTree.find("mostUrgentPriority"); + // Without the accompanying fix in place, this test would have failed, this JSON key was + // missing. + CPPUNIT_ASSERT(it != aTree.not_found()); + // This returns TaskPriority::HIGH_IDLE, but just make sure we get an int. + it->second.get_value<int>(); +} #endif CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sfx2/source/view/lokhelper.cxx b/sfx2/source/view/lokhelper.cxx index 0ea04c16238f..5d034da1da3e 100644 --- a/sfx2/source/view/lokhelper.cxx +++ b/sfx2/source/view/lokhelper.cxx @@ -44,6 +44,7 @@ #include <tools/json_writer.hxx> #include <svl/cryptosign.hxx> #include <tools/urlobj.hxx> +#include <vcl/scheduler.hxx> #include <boost/property_tree/json_parser.hpp> @@ -996,7 +997,8 @@ void SfxLokHelper::addCertificates(const std::vector<std::string>& rCerts) bool SfxLokHelper::supportsCommand(std::u16string_view rCommand) { - static const std::initializer_list<std::u16string_view> vSupport = { u"Signature" }; + static const std::initializer_list<std::u16string_view> vSupport + = { u"Signature", u"Scheduler" }; return std::find(vSupport.begin(), vSupport.end(), rCommand) != vSupport.end(); } @@ -1028,14 +1030,11 @@ std::map<OUString, OUString> SfxLokHelper::parseCommandParameters(std::u16string return aMap; } -void SfxLokHelper::getCommandValues(tools::JsonWriter& rJsonWriter, std::string_view rCommand) +namespace +{ +/// Implements getCommandValues(".uno:Signature"). +void GetSignature(tools::JsonWriter& rJsonWriter, std::string_view rCommand) { - static constexpr OString aSignature(".uno:Signature"_ostr); - if (!o3tl::starts_with(rCommand, aSignature)) - { - return; - } - SfxObjectShell* pObjectShell = SfxObjectShell::Current(); if (!pObjectShell) { @@ -1053,7 +1052,7 @@ void SfxLokHelper::getCommandValues(tools::JsonWriter& rJsonWriter, std::string_ } pObjectShell->SignDocumentContentUsingCertificate(aSigningContext); // Set commandName, this is a reply to a request. - rJsonWriter.put("commandName", aSignature); + rJsonWriter.put("commandName", ".uno:Signature"); auto aCommandValues = rJsonWriter.startNode("commandValues"); rJsonWriter.put("signatureTime", aSigningContext.m_nSignatureTime); @@ -1064,6 +1063,30 @@ void SfxLokHelper::getCommandValues(tools::JsonWriter& rJsonWriter, std::string_ rJsonWriter.put("digest", aBuffer.makeStringAndClear()); } +/// Implements getCommandValues(".uno:Scheduler"). +void GetScheduler(tools::JsonWriter& rJsonWriter) +{ + Scheduler::dumpAsJSON(rJsonWriter); +} +} + +void SfxLokHelper::getCommandValues(tools::JsonWriter& rJsonWriter, std::string_view rCommand) +{ + static constexpr OString aSignature(".uno:Signature"_ostr); + static constexpr OString aScheduler(".uno:Scheduler"_ostr); + if (o3tl::starts_with(rCommand, aSignature)) + { + GetSignature(rJsonWriter, rCommand); + return; + } + + if (o3tl::starts_with(rCommand, aScheduler)) + { + GetScheduler(rJsonWriter); + return; + } +} + void SfxLokHelper::notifyUpdate(SfxViewShell const* pThisView, int nType) { if (DisableCallbacks::disabled() || !pThisView) diff --git a/vcl/source/app/scheduler.cxx b/vcl/source/app/scheduler.cxx index eaca69adafa1..61814364d22e 100644 --- a/vcl/source/app/scheduler.cxx +++ b/vcl/source/app/scheduler.cxx @@ -38,6 +38,7 @@ #include <saltimer.hxx> #include <salinst.hxx> #include <comphelper/profilezone.hxx> +#include <tools/json_writer.hxx> #include <schedulerimpl.hxx> namespace { @@ -298,6 +299,49 @@ Scheduler::IdlesLockGuard::~IdlesLockGuard() osl_atomic_decrement(&rSchedCtx.mnIdlesLockCount); } +void Scheduler::dumpAsJSON(tools::JsonWriter& rJsonWriter) +{ + // Similar to Scheduler::CallbackTaskScheduling(), figure out the most urgent priority, but + // don't actually invoke any task. + int nMostUrgentPriority = -1; + ImplSVData* pSVData = ImplGetSVData(); + ImplSchedulerContext& rSchedCtx = pSVData->maSchedCtx; + if (!rSchedCtx.mbActive || rSchedCtx.mnTimerPeriod == InfiniteTimeoutMs) + { + rJsonWriter.put("mostUrgentPriority", nMostUrgentPriority); + return; + } + + sal_uInt64 nTime = tools::Time::GetSystemTicks(); + if (nTime < rSchedCtx.mnTimerStart + rSchedCtx.mnTimerPeriod - 1) + { + rJsonWriter.put("mostUrgentPriority", nMostUrgentPriority); + return; + } + + for (int nTaskPriority = 0; nTaskPriority < PRIO_COUNT; ++nTaskPriority) + { + ImplSchedulerData* pSchedulerData = rSchedCtx.mpFirstSchedulerData[nTaskPriority]; + while (pSchedulerData) + { + Task* pTask = pSchedulerData->mpTask; + if (pTask && pTask->IsActive()) + { + // Const, doesn't modify the task. + sal_uInt64 nReadyPeriod = pTask->UpdateMinPeriod(nTime); + if (nReadyPeriod == ImmediateTimeoutMs) + { + nMostUrgentPriority = nTaskPriority; + rJsonWriter.put("mostUrgentPriority", nMostUrgentPriority); + return; + } + } + pSchedulerData = pSchedulerData->mpNext; + } + } + rJsonWriter.put("mostUrgentPriority", nMostUrgentPriority); +} + inline void Scheduler::UpdateSystemTimer( ImplSchedulerContext &rSchedCtx, const sal_uInt64 nMinPeriod, const bool bForce, const sal_uInt64 nTime ) commit 26d52ed6fb7e03e907e7da3169d14b7490298b18 Author: Rashesh <[email protected]> AuthorDate: Wed Feb 5 17:07:07 2025 +0530 Commit: Andras Timar <[email protected]> CommitDate: Sat Feb 15 16:29:13 2025 +0100 sw: lokit: add new `isCropMode` property to LOK_CALLBACK_TEXT_VIEW_SELECTION Change-Id: I788d0b56bfba2c150401a906c7442652e50da58e Reviewed-on: https://gerrit.libreoffice.org/c/core/+/181160 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Gökay ŞATIR <[email protected]> diff --git a/svx/source/svdraw/svdmrkv.cxx b/svx/source/svdraw/svdmrkv.cxx index 0e24fe898e3f..5c9db14b5402 100644 --- a/svx/source/svdraw/svdmrkv.cxx +++ b/svx/source/svdraw/svdmrkv.cxx @@ -985,6 +985,9 @@ void SdrMarkView::SetMarkHandlesForLOKit(tools::Rectangle const & rRect, const S + OString::number(p.getY())); } + if (meDragMode == SdrDragMode::Crop) + aExtraInfo.append(", \"isCropMode\": true"); + if (bWriterGraphic) { aExtraInfo.append(", \"isWriterGraphic\": true"); commit e9e8f61cd12641d18d9c781117538c6e2a077aa1 Author: Gökay Şatır <[email protected]> AuthorDate: Thu Jan 30 19:04:38 2025 +0300 Commit: Andras Timar <[email protected]> CommitDate: Sat Feb 15 16:28:54 2025 +0100 cool#11072: Send current cell's decimal separator. Calc: In a file with a language that uses "," as the decimal separator, using a keyboard with a layout that uses "." as decimal separator is difficult. Numbers are considered as string when it happens. Users should be able to use NumPad decimal separator regardless of the cell's current decimal separator. Signed-off-by: Gökay Şatır <[email protected]> Change-Id: I35623661acb0f505597458b7ce55cfc2c3a4dace Reviewed-on: https://gerrit.libreoffice.org/c/core/+/180961 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Miklos Vajna <[email protected]> diff --git a/sc/source/ui/app/inputhdl.cxx b/sc/source/ui/app/inputhdl.cxx index dece0aa45cec..5a4eedc22c88 100644 --- a/sc/source/ui/app/inputhdl.cxx +++ b/sc/source/ui/app/inputhdl.cxx @@ -47,6 +47,7 @@ #include <sfx2/printer.hxx> #include <svl/numformat.hxx> #include <svl/zforlist.hxx> +#include <svtools/langtab.hxx> #include <unotools/localedatawrapper.hxx> #include <unotools/charclass.hxx> #include <utility> @@ -1858,6 +1859,18 @@ void ScTabViewShell::LOKSendFormulabarUpdate(EditView* pActiveView, maSendFormulabarUpdate.m_aText = rText; maSendFormulabarUpdate.m_aSelection = aSelection; maSendFormulabarUpdate.m_nTimeStamp = now; + + ScViewData& rViewData = this->GetViewData(); + const ScDocument& rDoc = rViewData.GetDocShell()->GetDocument(); + const ScPatternAttr* pPattern = rDoc.GetPattern(rViewData.GetCurX(), rViewData.GetCurY(), rViewData.GetRefTabNo()); + + if (pPattern) + { + SvNumberFormatter* pFormatter = rDoc.GetFormatTable(); + sal_uInt32 nFormat = pPattern->GetNumberFormat( pFormatter ); + maSendFormulabarUpdate.m_separator = pFormatter->GetFormatDecimalSep(nFormat); + } + maSendFormulabarUpdate.Send(); } @@ -1867,6 +1880,7 @@ void ScTabViewShell::SendFormulabarUpdate::Send() (*pData)["action_type"_ostr] = "setText"; (*pData)["text"_ostr] = m_aText; (*pData)["selection"_ostr] = m_aSelection; + (*pData)["separator"_ostr] = m_separator; OUString sWindowId = OUString::number(m_nShellId) + "formulabar"; jsdialog::SendAction(sWindowId, u"sc_input_window"_ustr, std::move(pData)); } diff --git a/sc/source/ui/inc/tabvwsh.hxx b/sc/source/ui/inc/tabvwsh.hxx index 842474dd7af7..5a562431f473 100644 --- a/sc/source/ui/inc/tabvwsh.hxx +++ b/sc/source/ui/inc/tabvwsh.hxx @@ -110,6 +110,7 @@ private: OUString m_aText; OUString m_aSelection; sal_uInt64 m_nShellId; + OUString m_separator; std::chrono::steady_clock::time_point m_nTimeStamp; SendFormulabarUpdate() commit 0c84518bfea8a5b440e911dffc870f275259f7c2 Author: Rashesh <[email protected]> AuthorDate: Fri Jan 31 14:00:21 2025 +0530 Commit: Andras Timar <[email protected]> CommitDate: Sat Feb 15 16:28:46 2025 +0100 sw: lokit: don't activate standard.dic - in online, standard.dic is not required and causes confusion to the user Change-Id: I79a66e3479a35a0ace90dc4c30f3c479526f0fb7 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/180979 Tested-by: Jenkins CollaboraOffice <[email protected]> Tested-by: Caolán McNamara <[email protected]> Reviewed-by: Caolán McNamara <[email protected]> diff --git a/sw/source/uibase/lingu/olmenu.cxx b/sw/source/uibase/lingu/olmenu.cxx index b501bd45fc14..101d970c7f99 100644 --- a/sw/source/uibase/lingu/olmenu.cxx +++ b/sw/source/uibase/lingu/olmenu.cxx @@ -320,7 +320,7 @@ SwSpellPopup::SwSpellPopup( // words could be added. uno::Reference< linguistic2::XDictionary > xDic( LinguMgr::GetStandardDic() ); if (xDic.is()) - xDic->setActive( true ); + xDic->setActive(!comphelper::LibreOfficeKit::isActive()); m_aDics = xDicList->getDictionaries(); @@ -362,8 +362,9 @@ SwSpellPopup::SwSpellPopup( } } - m_xPopupMenu->EnableItem(m_nAddMenuId, (nItemId - MN_DICTIONARIES_START) > 1); - m_xPopupMenu->EnableItem(m_nAddId, (nItemId - MN_DICTIONARIES_START) == 1); + sal_uInt16 nDiff = nItemId - MN_DICTIONARIES_START; + m_xPopupMenu->EnableItem(m_nAddMenuId, nDiff > 2); + m_xPopupMenu->EnableItem(m_nAddId, nDiff == 2); //ADD NEW LANGUAGE MENU ITEM
