Rebased ref, commits from common ancestor: commit 3ed6eca9409951486c0e0d91467e0d750d8176ec Author: Balazs Varga <balazs.varga.ext...@allotropia.de> AuthorDate: Fri Sep 23 10:57:09 2022 +0200 Commit: Thorsten Behrens <thorsten.behr...@allotropia.de> CommitDate: Tue Nov 8 10:34:29 2022 +0100
WASM pdf conversion through emscripten and qt5 Exporting files to pdf and downloading it from the emscripten virtual memory file system to the local file system with qt5 and emscripten. What is working: 1. Uploading a file from the local file system to the emscripten memory with 'Open file dialoge' and then opening it. In the same time export it to pdf. 2. Load an uploaded document with the LibreOffice Kit command: - lodoc = _libreofficekit_hook(0) - _doc_postUnoCommand(lodoc, allocateUTF8(".uno:Open"), allocateUTF8( "{ \"URL\" : { \"type\":\"string\", \"value\":\"file:///android/default-document/{UPLOADED_FILE_NAME}\" }}"), 0) 3. Export the loaded document to pdf with the ExportDirectlyToPDF UI or with the LibreOffice Kit command: - lodoc = _libreofficekit_hook(0) - _doc_postUnoCommand(lodoc, allocateUTF8(".uno:ExportDirectToPDF"), allocateUTF8(""), 0) 4. alternatively, you can plant a file in the virtual filesystem prior to LibreOffice bootstrap, and export headless, via soffice cmdline args Change-Id: I8f03b0a057155afaa5f1ca0e3e451bb362a99769 diff --git a/include/sfx2/objsh.hxx b/include/sfx2/objsh.hxx index f27948d81b64..47fc46998b4f 100644 --- a/include/sfx2/objsh.hxx +++ b/include/sfx2/objsh.hxx @@ -45,6 +45,13 @@ #include <functional> #include <sfx2/AccessibilityIssue.hxx> +#ifdef EMSCRIPTEN +#include <emscripten.h> +#include <emscripten/bind.h> +#include <emscripten/html5.h> +#include <emscripten/val.h> +#endif + namespace weld {class Button; } class SbxValue; class SbxArray; @@ -435,6 +442,10 @@ public: virtual bool PrepareClose(bool bUI = true); virtual HiddenInformation GetHiddenInformationState( HiddenInformation nStates ); sal_Int16 QueryHiddenInformation( HiddenWarningFact eFact, weld::Window* pParent ); + #ifdef EMSCRIPTEN + void ReadWASMFile(emscripten::val& contentArray, sal_Int32 nRead, css::uno::Sequence<sal_Int8>& aContent); + void WriteWASMFile(emscripten::val& contentArray, const OUString& rFileName); + #endif bool IsSecurityOptOpenReadOnly() const; void SetSecurityOptOpenReadOnly( bool bOpenReadOnly ); diff --git a/sfx2/source/dialog/filedlghelper.cxx b/sfx2/source/dialog/filedlghelper.cxx index 0f9f4739596b..a4f2d1f2ef35 100644 --- a/sfx2/source/dialog/filedlghelper.cxx +++ b/sfx2/source/dialog/filedlghelper.cxx @@ -1628,7 +1628,12 @@ void FileDialogHelper_Impl::getRealFilter( OUString& _rFilter ) const _rFilter = getCurrentFilterUIName(); if ( _rFilter.isEmpty() ) - _rFilter = maCurFilter; + { + if (isShowFilterExtensionEnabled()) + _rFilter = getFilterName(maCurFilter); + else + _rFilter = maCurFilter; + } if ( !_rFilter.isEmpty() && mpMatcher ) { diff --git a/sfx2/source/doc/guisaveas.cxx b/sfx2/source/doc/guisaveas.cxx index 7cce6b515db4..f4dc655513e8 100644 --- a/sfx2/source/doc/guisaveas.cxx +++ b/sfx2/source/doc/guisaveas.cxx @@ -1525,10 +1525,50 @@ bool SfxStoringHelper::GUIStoreModel( const uno::Reference< frame::XModel >& xMo if ( aDenyListIter != aModelData.GetMediaDescr().end() ) aDenyListIter->second >>= aDenyList; + bool bWasmPdfExport = false; +#ifdef EMSCRIPTEN + // Do not create file dialoge for direct pdf export, (just a workaround for WASM pdf export now) + // because that is still buggy on the Qt side + if ( nStoreMode & PDFDIRECTEXPORT_REQUESTED ) + { + // this is a WASM direct pdf export + const OUString aFilterUIName = aFilterPropsHM.getUnpackedValueOrDefault( "UIName", OUString() ); + if (aFilterUIName == "PDF - Portable Document Format") + { + OUString realfiltername; + const OUString aDocServiceName{ aModelData.GetDocServiceName() }; + if ( aDocServiceName == "com.sun.star.drawing.DrawingDocument" ) + realfiltername = "draw_pdf_Export"; + else if ( aDocServiceName == "com.sun.star.presentation.PresentationDocument" ) + realfiltername = "impress_pdf_Export"; + else if ( aDocServiceName == "com.sun.star.text.TextDocument" ) + realfiltername = "writer_pdf_Export"; + else if ( aDocServiceName == "com.sun.star.sheet.SpreadsheetDocument" ) + realfiltername = "calc_pdf_Export"; + + if (realfiltername.endsWith("pdf_Export")) + { + const OUString aRecommendedDir {aModelData.GetRecommendedDir( aSuggestedDir )}; + OUString aAdjustToType = aFilterPropsHM.getUnpackedValueOrDefault( "Type", OUString() ); + const OUString aRecommendedName {aModelData.GetRecommendedName( aSuggestedName, aAdjustToType )}; + OUString aTempURL = aRecommendedDir + aRecommendedName; + INetURLObject aURL2(aTempURL); + aModelData.GetMediaDescr()[OUString("URL")] <<= aURL2.GetMainURL( INetURLObject::DecodeMechanism::NONE ); + aModelData.GetMediaDescr()[sFilterNameString] <<= realfiltername; + bWasmPdfExport = true; + } + } + } +#endif // EMSCRIPTEN + for (;;) { // in case the dialog is opened a second time the folder should be the same as previously navigated to by the user, not what was handed over by initial parameters - bUseFilterOptions = aModelData.OutputFileDialog( nStoreMode, aFilterProps, bSetStandardName, aSuggestedName, bPreselectPassword, aSuggestedDir, nDialog, sStandardDir, aDenyList ); + if (!bWasmPdfExport) + bUseFilterOptions = aModelData.OutputFileDialog( nStoreMode, aFilterProps, bSetStandardName, aSuggestedName, bPreselectPassword, aSuggestedDir, nDialog, sStandardDir, aDenyList ); + else + bUseFilterOptions = true; + if ( nStoreMode == SAVEAS_REQUESTED ) { // in case of saving check filter for possible alien warning @@ -1549,7 +1589,7 @@ bool SfxStoringHelper::GUIStoreModel( const uno::Reference< frame::XModel >& xMo break; } - bDialogUsed = true; + bDialogUsed = !bWasmPdfExport; aFileNameIter = aModelData.GetMediaDescr().find( OUString("URL") ); } else diff --git a/sfx2/source/doc/objstor.cxx b/sfx2/source/doc/objstor.cxx index 6c83b4066466..588e4ab52f93 100644 --- a/sfx2/source/doc/objstor.cxx +++ b/sfx2/source/doc/objstor.cxx @@ -2993,6 +2993,39 @@ bool SfxObjectShell::PreDoSaveAs_Impl(const OUString& rFileName, const OUString& if( bOk ) { +#ifdef EMSCRIPTEN + if (aFilterName.endsWith("pdf_Export")) + { + try + { + sal_Int32 nRead; + Reference<io::XInputStream> aTempInput = pNewFile->GetInputStream(); + sal_Int32 nBufferSize = 32767; + Sequence<sal_Int8> aSequence(nBufferSize); + emscripten::val contentArray = emscripten::val::array(); + + do + { + nRead = aTempInput->readBytes(aSequence, nBufferSize); + if (nRead < nBufferSize) + { + Sequence<sal_Int8> aTempBuf(aSequence.getConstArray(), nRead); + ReadWASMFile(contentArray, nRead, aTempBuf); + } + else + { + ReadWASMFile(contentArray, nRead, aSequence); + } + } while (nRead == nBufferSize); + + WriteWASMFile(contentArray, pNewFile->GetName()); + } + catch (const Exception&) + { + } + } +#endif + if( !bCopyTo ) SetModified( false ); } @@ -3037,6 +3070,46 @@ bool SfxObjectShell::PreDoSaveAs_Impl(const OUString& rFileName, const OUString& return bOk; } +#ifdef EMSCRIPTEN +void SfxObjectShell::ReadWASMFile(emscripten::val& contentArray, sal_Int32 nRead, css::uno::Sequence<sal_Int8>& aContent) +{ + emscripten::val fileContentView = emscripten::val(emscripten::typed_memory_view( + nRead, + reinterpret_cast<const char*>(aContent.getConstArray()))); + emscripten::val fileContentCopy = emscripten::val::global("ArrayBuffer").new_(nRead); + emscripten::val fileContentCopyView = emscripten::val::global("Uint8Array").new_(fileContentCopy); + fileContentCopyView.call<void>("set", fileContentView); + contentArray.call<void>("push", fileContentCopyView); +} + + +void SfxObjectShell::WriteWASMFile(emscripten::val& contentArray, const OUString& rFileName) +{ + INetURLObject aURL(rFileName); + OUString aNewname = aURL.GetLastName(INetURLObject::DecodeMechanism::WithCharset); + + emscripten::val document = emscripten::val::global("document"); + emscripten::val window = emscripten::val::global("window"); + + emscripten::val type = emscripten::val::object(); + type.set("type","application/octet-stream"); + emscripten::val contentBlob = emscripten::val::global("Blob").new_(contentArray, type); + + emscripten::val contentUrl = window["URL"].call<emscripten::val>("createObjectURL", contentBlob); + emscripten::val contentLink = document.call<emscripten::val>("createElement", std::string("a")); + contentLink.set("href", contentUrl); + contentLink.set("download", aNewname.toUtf8().getStr()); + contentLink.set("style", "display:none"); + + emscripten::val body = document["body"]; + body.call<void>("appendChild", contentLink); + contentLink.call<void>("click"); + body.call<void>("removeChild", contentLink); + + window["URL"].call<emscripten::val>("revokeObjectURL", contentUrl); +} +#endif + bool SfxObjectShell::LoadFrom( SfxMedium& /*rMedium*/ ) { diff --git a/sfx2/source/doc/objxtor.cxx b/sfx2/source/doc/objxtor.cxx index c7f34aeadc31..0d89c4b9d482 100644 --- a/sfx2/source/doc/objxtor.cxx +++ b/sfx2/source/doc/objxtor.cxx @@ -867,6 +867,7 @@ void SfxObjectShell::SetCurrentComponent( const Reference< XInterface >& _rxComp if ( _rxComponent == xOldCurrentComp ) // nothing to do return; + rTheCurrentComponent = _rxComponent; // note that "_rxComponent.get() == s_xCurrentComponent.get().get()" is /sufficient/, but not // /required/ for "_rxComponent == s_xCurrentComponent.get()". // In other words, it's still possible that we here do something which is not necessary, @@ -874,7 +875,6 @@ void SfxObjectShell::SetCurrentComponent( const Reference< XInterface >& _rxComp #if HAVE_FEATURE_SCRIPTING BasicManager* pAppMgr = SfxApplication::GetBasicManager(); - rTheCurrentComponent = _rxComponent; if ( !pAppMgr ) return; diff --git a/solenv/gbuild/platform/EMSCRIPTEN_INTEL_GCC.mk b/solenv/gbuild/platform/EMSCRIPTEN_INTEL_GCC.mk index 19ad9b86c887..52ad474f086c 100644 --- a/solenv/gbuild/platform/EMSCRIPTEN_INTEL_GCC.mk +++ b/solenv/gbuild/platform/EMSCRIPTEN_INTEL_GCC.mk @@ -27,7 +27,7 @@ gb_EMSCRIPTEN_LDFLAGS += -s TOTAL_MEMORY=1GB -s PTHREAD_POOL_SIZE=4 # To keep the link time (and memory) down, prevent all rewriting options from wasm-emscripten-finalize # See emscripten.py, finalize_wasm, modify_wasm = True # So we need WASM_BIGINT=1 and ASSERTIONS=1 (2 implies STACK_OVERFLOW_CHECK) -gb_EMSCRIPTEN_LDFLAGS += --bind -s FORCE_FILESYSTEM=1 -s WASM_BIGINT=1 -s ERROR_ON_UNDEFINED_SYMBOLS=1 -s FETCH=1 -s ASSERTIONS=1 -s EXIT_RUNTIME=0 -s EXPORTED_RUNTIME_METHODS=["UTF16ToString","stringToUTF16","UTF8ToString","allocateUTF8","printErr","ccall","cwrap"] +gb_EMSCRIPTEN_LDFLAGS += --bind -s FORCE_FILESYSTEM=1 -s WASM_BIGINT=1 -s ERROR_ON_UNDEFINED_SYMBOLS=1 -s FETCH=1 -s ASSERTIONS=1 -s EXIT_RUNTIME=0 -s EXPORTED_RUNTIME_METHODS=["UTF16ToString","stringToUTF16","UTF8ToString","allocateUTF8","printErr","ccall","cwrap","FS"] gb_EMSCRIPTEN_QTDEFS := -DQT_NO_LINKED_LIST -DQT_NO_JAVA_STYLE_ITERATORS -DQT_NO_EXCEPTIONS -D_LARGEFILE64_SOURCE -D_LARGEFILE_SOURCE -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB gb_Executable_EXT := .html diff --git a/vcl/inc/qt5/QtFilePicker.hxx b/vcl/inc/qt5/QtFilePicker.hxx index 58824adbbd48..96c1dd60c8db 100644 --- a/vcl/inc/qt5/QtFilePicker.hxx +++ b/vcl/inc/qt5/QtFilePicker.hxx @@ -32,6 +32,22 @@ #include <com/sun/star/ui/dialogs/XFolderPicker2.hpp> #include <com/sun/star/uno/XComponentContext.hpp> +#ifdef EMSCRIPTEN +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/frame/XDesktop2.hpp> +#include <com/sun/star/frame/XStorable.hpp> +#include <com/sun/star/lang/XMultiComponentFactory.hpp> + +#include <comphelper/processfactory.hxx> +#include <comphelper/propertysequence.hxx> +#include <comphelper/sequence.hxx> +#include <comphelper/propertyvalue.hxx> + +#include <unotools/mediadescriptor.hxx> + +#include <tools/urlobj.hxx> +#endif + #include <osl/conditn.hxx> #include <osl/mutex.hxx> #include <unotools/resmgr.hxx> @@ -40,6 +56,9 @@ #include <QtCore/QString> #include <QtCore/QStringList> #include <QtCore/QHash> +#ifdef EMSCRIPTEN +#include <QtWidgets/QtWidgets> +#endif #include <QtWidgets/QFileDialog> #include <memory> @@ -173,6 +192,15 @@ private: void prepareExecute(); +#ifdef EMSCRIPTEN + void headlessPdfConversionWASM(); + void exportFileToPDFWASM(const OUString& rfileName); + css::uno::Reference<css::lang::XComponent> + loadFromDesktop(const OUString& rURL, const OUString& rDocService = OUString(), + const css::uno::Sequence<css::beans::PropertyValue>& rExtra_args + = css::uno::Sequence<css::beans::PropertyValue>()); +#endif + private Q_SLOTS: // emit XFilePickerListener controlStateChanged event void filterSelected(const QString&); diff --git a/vcl/qt5/QtFilePicker.cxx b/vcl/qt5/QtFilePicker.cxx index 8a13ec67235c..403e46509031 100644 --- a/vcl/qt5/QtFilePicker.cxx +++ b/vcl/qt5/QtFilePicker.cxx @@ -67,6 +67,10 @@ #include <fpicker/strings.hrc> #include <utility> +#ifdef EMSCRIPTEN +#include <emscripten.h> +#endif + using namespace ::com::sun::star; using namespace ::com::sun::star::ui::dialogs; using namespace ::com::sun::star::ui::dialogs::TemplateDescription; @@ -187,6 +191,128 @@ void QtFilePicker::prepareExecute() xDesktop->addTerminateListener(this); } +#ifdef EMSCRIPTEN +void QtFilePicker::headlessPdfConversionWASM() +{ + QLabel* fileInfo = new QLabel("Opened file:"); + fileInfo->setTextInteractionFlags(Qt::TextSelectableByMouse); + QLabel* fileHash = new QLabel("Sha256:"); + fileHash->setTextInteractionFlags(Qt::TextSelectableByMouse); + auto onFileReady = [=](const QString& fileName, const QByteArray& fileContents) { + if (fileName.isEmpty()) + { + // No file selected + } + else + { + fileInfo->setText( + QString("Opened file: %1 sizei: %2").arg(fileName).arg(fileContents.size())); + auto computeDisplayFileHash = [=]() { + QByteArray hash + = QCryptographicHash::hash(fileContents, QCryptographicHash::Sha256); + fileHash->setText(QString("Sha256: %1").arg(QString(hash.toHex()))); + }; + QTimer::singleShot(100, computeDisplayFileHash); // update UI before computing hash + std::string aFileName = "/android/default-document/" + fileName.toStdString(); + EM_ASM( + { FS.writeFile(UTF8ToString($0), new Uint8Array(Module.HEAPU8.buffer, $1, $2)); }, + aFileName.c_str(), fileContents.data(), fileContents.size()); + + exportFileToPDFWASM(toOUString(fileName)); + } + }; + + QFileDialog::getOpenFileContent("*.*", onFileReady); +} + +void QtFilePicker::exportFileToPDFWASM(const OUString& rfileName) +{ + utl::MediaDescriptor aMediaDescriptor; + // Explicitly enable the usage of the reference XObject markup. + uno::Sequence<beans::PropertyValue> aFilterData( + comphelper::InitPropertySequence({ { "UseReferenceXObject", uno::Any(true) } })); + aMediaDescriptor["FilterData"] <<= aFilterData; + + INetURLObject aURL(OUString("file:///android/default-document/" + rfileName)); + uno::Reference<lang::XComponent> xComponent + = loadFromDesktop(aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE)); + if (xComponent.is()) + { + uno::Reference<frame::XStorable> xStorable(xComponent, uno::UNO_QUERY); + + if (xStorable.is()) + { + OUString realfiltername = "writer_pdf_Export"; + OUString aExt = aURL.getExtension(); + if (aExt != "pdf") + { + if (aExt == "odt" || aExt == "ott") + { + realfiltername = "writer_pdf_Export"; + } + else if (aExt == "ods" || aExt == "ots") + { + realfiltername = "calc_pdf_Export"; + } + else if (aExt == "odp" || aExt == "otp") + { + realfiltername = "impress_pdf_Export"; + } + else if (aExt == "odg" || aExt == "otg") + { + realfiltername = "draw_pdf_Export"; + } + else + { + // other types are not supported; + return; + } + aURL.setExtension(std::u16string_view(u"pdf")); + } + aMediaDescriptor["FilterName"] <<= realfiltername; + aMediaDescriptor["FileName"] + <<= aURL.GetLastName(INetURLObject::DecodeMechanism::WithCharset); + xStorable->storeToURL(aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE), + aMediaDescriptor.getAsConstPropertyValueList()); + } + } +} + +uno::Reference<css::lang::XComponent> +QtFilePicker::loadFromDesktop(const OUString& rURL, const OUString& rDocService, + const uno::Sequence<beans::PropertyValue>& rExtraArgs) +{ + std::vector<beans::PropertyValue> args; + + if (!rDocService.isEmpty()) + { + beans::PropertyValue aValue; + aValue.Name = "DocumentService"; + aValue.Handle = -1; + aValue.Value <<= rDocService; + aValue.State = beans::PropertyState_DIRECT_VALUE; + args.push_back(aValue); + } + + args.insert(args.end(), rExtraArgs.begin(), rExtraArgs.end()); + + css::uno::Reference<css::uno::XComponentContext> xComponentContext; + xComponentContext.set(comphelper::getComponentContext(comphelper::getProcessServiceFactory())); + + css::uno::Reference<css::frame::XDesktop2> xDesktop; + xDesktop.set(frame::Desktop::create(xComponentContext)); + + if (xDesktop.is()) + { + uno::Reference<lang::XComponent> xComponent = xDesktop->loadComponentFromURL( + rURL, "_default", 0, comphelper::containerToSequence(args)); + return xComponent; + } + + return uno::Reference<css::lang::XComponent>(); +} +#endif + void QtFilePicker::finished(int nResult) { SolarMutexGuard g; @@ -217,8 +343,13 @@ sal_Int16 SAL_CALL QtFilePicker::execute() return ret; } +#ifdef EMSCRIPTEN + headlessPdfConversionWASM(); + int result = QFileDialog::Rejected; +#else prepareExecute(); int result = m_pFileDialog->exec(); +#endif if (QFileDialog::Rejected == result) return ExecutableDialogResults::CANCEL; commit c644518de72b1749d17e411d9fcf1f61b0a44460 Author: Thorsten Behrens <thorsten.behr...@allotropia.de> AuthorDate: Sat Aug 13 08:52:43 2022 +0200 Commit: Thorsten Behrens <thorsten.behr...@allotropia.de> CommitDate: Tue Nov 8 10:34:28 2022 +0100 Disable languagetool for WASM build Change-Id: Icd0face05c33bbb1b56230a59015402d5f565422 diff --git a/config_host.mk.in b/config_host.mk.in index 9de974e472f9..ad5c60159573 100644 --- a/config_host.mk.in +++ b/config_host.mk.in @@ -226,6 +226,7 @@ export ENABLE_WASM_STRIP_EPUB=@ENABLE_WASM_STRIP@ export ENABLE_WASM_STRIP_EXTRA=@ENABLE_WASM_STRIP@ export ENABLE_WASM_STRIP_GUESSLANG=@ENABLE_WASM_STRIP@ export ENABLE_WASM_STRIP_HUNSPELL= +export ENABLE_WASM_STRIP_LANGUAGETOOL=@ENABLE_WASM_STRIP@ export ENABLE_WASM_STRIP_LOCALES=@ENABLE_WASM_STRIP@ export ENABLE_WASM_STRIP_PINGUSER=@ENABLE_WASM_STRIP@ export ENABLE_WASM_STRIP_PREMULTIPLY=@ENABLE_WASM_STRIP@ diff --git a/configure.ac b/configure.ac index 9a445fefabc1..04201869eabf 100644 --- a/configure.ac +++ b/configure.ac @@ -3080,6 +3080,7 @@ if test "$enable_wasm_strip" = "yes"; then AC_DEFINE(ENABLE_WASM_STRIP_EXTRA) AC_DEFINE(ENABLE_WASM_STRIP_GUESSLANG) # AC_DEFINE(ENABLE_WASM_STRIP_HUNSPELL) + AC_DEFINE(ENABLE_WASM_STRIP_LANGUAGETOOL) AC_DEFINE(ENABLE_WASM_STRIP_PINGUSER) AC_DEFINE(ENABLE_WASM_STRIP_PREMULTIPLY) AC_DEFINE(ENABLE_WASM_STRIP_RECENT) diff --git a/lingucomponent/Module_lingucomponent.mk b/lingucomponent/Module_lingucomponent.mk index 13f1a829d98a..87e1b1f4d585 100644 --- a/lingucomponent/Module_lingucomponent.mk +++ b/lingucomponent/Module_lingucomponent.mk @@ -25,10 +25,15 @@ $(eval $(call gb_Module_add_targets,lingucomponent,\ )) endif +ifneq ($(ENABLE_WASM_STRIP_LANGUAGETOOL),TRUE) +$(eval $(call gb_Module_add_targets,lingucomponent,\ + Library_LanguageTool \ +)) +endif + $(eval $(call gb_Module_add_targets,lingucomponent,\ $(if $(filter iOS MACOSX,$(OS)),Library_MacOSXSpell) \ Library_numbertext \ - Library_LanguageTool \ )) # vim: set noet sw=4 ts=4: commit 376c74dc248a0090a4bfd08c765191e1332fbf65 Author: TheRock Builder <libo@therock> AuthorDate: Thu Apr 28 14:19:46 2022 +0000 Commit: Thorsten Behrens <thorsten.behr...@allotropia.de> CommitDate: Tue Nov 8 10:34:28 2022 +0100 Hack lokit API to be useable from JS So LOWA users/embeddings can call uno slots diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx index edf3114a2d10..fb94f2b6f018 100644 --- a/desktop/source/lib/init.cxx +++ b/desktop/source/lib/init.cxx @@ -1045,7 +1045,7 @@ static void doc_postWindowGestureEvent(LibreOfficeKitDocument* pThis, int nX, int nY, int nOffset); -static void doc_postUnoCommand(LibreOfficeKitDocument* pThis, +void doc_postUnoCommand(LibreOfficeKitDocument* pThis, const char* pCommand, const char* pArguments, bool bNotifyWhenFinished); @@ -4410,7 +4410,7 @@ void LibLibreOffice_Impl::dumpState(rtl::OStringBuffer &rState) vcl::lok::dumpState(rState); } -static void doc_postUnoCommand(LibreOfficeKitDocument* pThis, const char* pCommand, const char* pArguments, bool bNotifyWhenFinished) +void doc_postUnoCommand(LibreOfficeKitDocument* pThis, const char* pCommand, const char* pArguments, bool bNotifyWhenFinished) { comphelper::ProfileZone aZone("doc_postUnoCommand"); @@ -7206,9 +7206,19 @@ LibreOfficeKit *libreofficekit_hook_2(const char* install_path, const char* user } SAL_JNI_EXPORT -LibreOfficeKit *libreofficekit_hook(const char* install_path) +LibreOfficeKitDocument *libreofficekit_hook(const char*) { - return libreofficekit_hook_2(install_path, nullptr); + if (!gImpl) + { + gImpl = new LibLibreOffice_Impl(); + xContext.set( ::comphelper::getProcessComponentContext(), uno::UNO_SET_THROW ); + } + + uno::Reference<frame::XDesktop> xDesktop = frame::Desktop::create(xContext); + uno::Reference<lang::XComponent> xComponent = xDesktop->getCurrentComponent(); + LibLODocument_Impl* pDocument = new LibLODocument_Impl(xComponent, 0); + + return pDocument; } SAL_JNI_EXPORT commit f8a7f8e3c63b585d33acbaadc692b2d4a5e2bb6e Author: TheRock Builder <libo@therock> AuthorDate: Thu Apr 28 14:19:22 2022 +0000 Commit: Thorsten Behrens <thorsten.behr...@allotropia.de> CommitDate: Tue Nov 8 10:34:28 2022 +0100 Add more functions to export for LOWA diff --git a/desktop/Executable_soffice_bin.mk b/desktop/Executable_soffice_bin.mk index b0711af84952..4e321fa932e9 100644 --- a/desktop/Executable_soffice_bin.mk +++ b/desktop/Executable_soffice_bin.mk @@ -50,7 +50,7 @@ endif ifeq ($(OS),EMSCRIPTEN) $(eval $(call gb_Executable_add_ldflags,soffice_bin,\ - -s EXPORTED_FUNCTIONS=["_main"$(COMMA)"_libreofficekit_hook"$(COMMA)"_libreofficekit_hook_2"$(COMMA)"_lok_preinit"$(COMMA)"_lok_preinit_2"] \ + -s EXPORTED_FUNCTIONS=["_main"$(COMMA)"_libreofficekit_hook"$(COMMA)"_libreofficekit_hook_2"$(COMMA)"_lok_preinit"$(COMMA)"_lok_preinit_2"$(COMMA)"_doc_postUnoCommand"] \ )) endif diff --git a/solenv/gbuild/platform/EMSCRIPTEN_INTEL_GCC.mk b/solenv/gbuild/platform/EMSCRIPTEN_INTEL_GCC.mk index f4ec28673142..19ad9b86c887 100644 --- a/solenv/gbuild/platform/EMSCRIPTEN_INTEL_GCC.mk +++ b/solenv/gbuild/platform/EMSCRIPTEN_INTEL_GCC.mk @@ -27,7 +27,7 @@ gb_EMSCRIPTEN_LDFLAGS += -s TOTAL_MEMORY=1GB -s PTHREAD_POOL_SIZE=4 # To keep the link time (and memory) down, prevent all rewriting options from wasm-emscripten-finalize # See emscripten.py, finalize_wasm, modify_wasm = True # So we need WASM_BIGINT=1 and ASSERTIONS=1 (2 implies STACK_OVERFLOW_CHECK) -gb_EMSCRIPTEN_LDFLAGS += --bind -s FORCE_FILESYSTEM=1 -s WASM_BIGINT=1 -s ERROR_ON_UNDEFINED_SYMBOLS=1 -s FETCH=1 -s ASSERTIONS=1 -s EXIT_RUNTIME=0 -s EXPORTED_RUNTIME_METHODS=["UTF16ToString","stringToUTF16","printErr","ccall","cwrap"] +gb_EMSCRIPTEN_LDFLAGS += --bind -s FORCE_FILESYSTEM=1 -s WASM_BIGINT=1 -s ERROR_ON_UNDEFINED_SYMBOLS=1 -s FETCH=1 -s ASSERTIONS=1 -s EXIT_RUNTIME=0 -s EXPORTED_RUNTIME_METHODS=["UTF16ToString","stringToUTF16","UTF8ToString","allocateUTF8","printErr","ccall","cwrap"] gb_EMSCRIPTEN_QTDEFS := -DQT_NO_LINKED_LIST -DQT_NO_JAVA_STYLE_ITERATORS -DQT_NO_EXCEPTIONS -D_LARGEFILE64_SOURCE -D_LARGEFILE_SOURCE -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB gb_Executable_EXT := .html commit 927cb61564a6b4e6a9f4c0c1ffa60cc786485166 Author: TheRock Builder <libo@therock> AuthorDate: Wed Apr 27 17:01:53 2022 +0000 Commit: Thorsten Behrens <thorsten.behr...@allotropia.de> CommitDate: Tue Nov 8 10:34:28 2022 +0100 Revert "Hack / temp" This reverts commit 66263d549caf2bf2892e9d6c6ca3c2423df38164. diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx index a49db2645b30..edf3114a2d10 100644 --- a/desktop/source/lib/init.cxx +++ b/desktop/source/lib/init.cxx @@ -10,9 +10,6 @@ #include <config_buildconfig.h> #include <config_features.h> -#include <emscripten.h> - - #include <stdio.h> #include <string.h> #include <stdlib.h> @@ -1342,7 +1339,7 @@ static OUString getGenerator() return sGenerator.replaceFirst("%1", os); } -//extern "C" { +extern "C" { CallbackFlushHandler::TimeoutIdle::TimeoutIdle( CallbackFlushHandler* handler ) : Timer( "lokit timer callback" ) @@ -7185,9 +7182,7 @@ static int lo_initialize(LibreOfficeKit* pThis, const char* pAppPath, const char return bInitialized; } -extern "C" { - -EMSCRIPTEN_KEEPALIVE +SAL_JNI_EXPORT LibreOfficeKit *libreofficekit_hook_2(const char* install_path, const char* user_profile_url) { static bool alreadyCalled = false; @@ -7210,7 +7205,7 @@ LibreOfficeKit *libreofficekit_hook_2(const char* install_path, const char* user return static_cast<LibreOfficeKit*>(gImpl); } -EMSCRIPTEN_KEEPALIVE +SAL_JNI_EXPORT LibreOfficeKit *libreofficekit_hook(const char* install_path) { return libreofficekit_hook_2(install_path, nullptr); commit 2667a70033c04d9324df6202a238f4ab62db6ec9 Author: TheRock Builder <libo@therock> AuthorDate: Wed Apr 27 17:01:34 2022 +0000 Commit: Thorsten Behrens <thorsten.behr...@allotropia.de> CommitDate: Tue Nov 8 10:34:28 2022 +0100 Hack / temp diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx index edf3114a2d10..a49db2645b30 100644 --- a/desktop/source/lib/init.cxx +++ b/desktop/source/lib/init.cxx @@ -10,6 +10,9 @@ #include <config_buildconfig.h> #include <config_features.h> +#include <emscripten.h> + + #include <stdio.h> #include <string.h> #include <stdlib.h> @@ -1339,7 +1342,7 @@ static OUString getGenerator() return sGenerator.replaceFirst("%1", os); } -extern "C" { +//extern "C" { CallbackFlushHandler::TimeoutIdle::TimeoutIdle( CallbackFlushHandler* handler ) : Timer( "lokit timer callback" ) @@ -7182,7 +7185,9 @@ static int lo_initialize(LibreOfficeKit* pThis, const char* pAppPath, const char return bInitialized; } -SAL_JNI_EXPORT +extern "C" { + +EMSCRIPTEN_KEEPALIVE LibreOfficeKit *libreofficekit_hook_2(const char* install_path, const char* user_profile_url) { static bool alreadyCalled = false; @@ -7205,7 +7210,7 @@ LibreOfficeKit *libreofficekit_hook_2(const char* install_path, const char* user return static_cast<LibreOfficeKit*>(gImpl); } -SAL_JNI_EXPORT +EMSCRIPTEN_KEEPALIVE LibreOfficeKit *libreofficekit_hook(const char* install_path) { return libreofficekit_hook_2(install_path, nullptr); commit a7c4cbd2759da8b75b9202842d142b66837cbf1c Author: TheRock Builder <libo@therock> AuthorDate: Wed Apr 27 16:51:46 2022 +0000 Commit: Thorsten Behrens <thorsten.behr...@allotropia.de> CommitDate: Tue Nov 8 10:34:28 2022 +0100 More fixup of gbuild diff --git a/desktop/Executable_soffice_bin.mk b/desktop/Executable_soffice_bin.mk index c5e9587d516e..b0711af84952 100644 --- a/desktop/Executable_soffice_bin.mk +++ b/desktop/Executable_soffice_bin.mk @@ -45,14 +45,14 @@ $(eval $(call gb_Executable_add_ldflags,soffice_bin,\ endif +endif + ifeq ($(OS),EMSCRIPTEN) $(eval $(call gb_Executable_add_ldflags,soffice_bin,\ - -sEXPORTED_FUNCTIONS=_main,_libreofficekit_hook,_libreofficekit_hook_2,_lok_preinit,_lok_preinit_2 \ + -s EXPORTED_FUNCTIONS=["_main"$(COMMA)"_libreofficekit_hook"$(COMMA)"_libreofficekit_hook_2"$(COMMA)"_lok_preinit"$(COMMA)"_lok_preinit_2"] \ )) endif -endif - # vim: set ts=4 sw=4 et: diff --git a/solenv/gbuild/platform/EMSCRIPTEN_INTEL_GCC.mk b/solenv/gbuild/platform/EMSCRIPTEN_INTEL_GCC.mk index 5d0ef59d8360..f4ec28673142 100644 --- a/solenv/gbuild/platform/EMSCRIPTEN_INTEL_GCC.mk +++ b/solenv/gbuild/platform/EMSCRIPTEN_INTEL_GCC.mk @@ -24,13 +24,10 @@ gb_EMSCRIPTEN_LDFLAGS := $(gb_EMSCRIPTEN_CPPFLAGS) # Initial memory size and worker thread pool gb_EMSCRIPTEN_LDFLAGS += -s TOTAL_MEMORY=1GB -s PTHREAD_POOL_SIZE=4 -# add a few critical functions to export -gb_EMSCRIPTEN_LDFLAGS += -sEXPORTED_RUNTIME_METHODS=ccall,cwrap - # To keep the link time (and memory) down, prevent all rewriting options from wasm-emscripten-finalize # See emscripten.py, finalize_wasm, modify_wasm = True # So we need WASM_BIGINT=1 and ASSERTIONS=1 (2 implies STACK_OVERFLOW_CHECK) -gb_EMSCRIPTEN_LDFLAGS += --bind -s FORCE_FILESYSTEM=1 -s WASM_BIGINT=1 -s ERROR_ON_UNDEFINED_SYMBOLS=1 -s FETCH=1 -s ASSERTIONS=1 -s EXIT_RUNTIME=0 -s EXPORTED_RUNTIME_METHODS=["UTF16ToString","stringToUTF16","printErr"] +gb_EMSCRIPTEN_LDFLAGS += --bind -s FORCE_FILESYSTEM=1 -s WASM_BIGINT=1 -s ERROR_ON_UNDEFINED_SYMBOLS=1 -s FETCH=1 -s ASSERTIONS=1 -s EXIT_RUNTIME=0 -s EXPORTED_RUNTIME_METHODS=["UTF16ToString","stringToUTF16","printErr","ccall","cwrap"] gb_EMSCRIPTEN_QTDEFS := -DQT_NO_LINKED_LIST -DQT_NO_JAVA_STYLE_ITERATORS -DQT_NO_EXCEPTIONS -D_LARGEFILE64_SOURCE -D_LARGEFILE_SOURCE -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB gb_Executable_EXT := .html commit cb7a2310ef3c40f011e20f0fc481397d7ebb42ac Author: TheRock Builder <libo@therock> AuthorDate: Wed Apr 27 16:19:59 2022 +0000 Commit: Thorsten Behrens <thorsten.behr...@allotropia.de> CommitDate: Tue Nov 8 10:34:28 2022 +0100 Fix logic diff --git a/desktop/Executable_soffice_bin.mk b/desktop/Executable_soffice_bin.mk index d9489bdad098..c5e9587d516e 100644 --- a/desktop/Executable_soffice_bin.mk +++ b/desktop/Executable_soffice_bin.mk @@ -45,7 +45,7 @@ $(eval $(call gb_Executable_add_ldflags,soffice_bin,\ endif -ifeq (TRUE,$(EMSCRIPTEN)) +ifeq ($(OS),EMSCRIPTEN) $(eval $(call gb_Executable_add_ldflags,soffice_bin,\ -sEXPORTED_FUNCTIONS=_main,_libreofficekit_hook,_libreofficekit_hook_2,_lok_preinit,_lok_preinit_2 \ diff --git a/desktop/Library_sofficeapp.mk b/desktop/Library_sofficeapp.mk index efc117424098..c315a113ca89 100644 --- a/desktop/Library_sofficeapp.mk +++ b/desktop/Library_sofficeapp.mk @@ -137,7 +137,7 @@ $(eval $(call gb_Library_add_exception_objects,sofficeapp,\ desktop/source/lib/lokandroid) \ )) else -ifeq ($(filter TRUE,$(USING_X11) $(DISABLE_GUI) $(EMSCRIPTEN)),) +ifneq ($(filter TRUE,$(USING_X11) $(DISABLE_GUI))($filter EMSCRIPTEN,$(OS)),) $(eval $(call gb_Library_add_exception_objects,sofficeapp,\ desktop/source/lib/init \ desktop/source/lib/lokinteractionhandler \ commit 441c06647a4ca17a69cb63fb9cd8ac136833ee8f Author: TheRock Builder <libo@therock> AuthorDate: Wed Apr 27 15:36:25 2022 +0000 Commit: Thorsten Behrens <thorsten.behr...@allotropia.de> CommitDate: Tue Nov 8 10:34:28 2022 +0100 Add LOKit functions and whitelist export for it to WASM For calling into LOWA from native JS, make lokit functions available diff --git a/desktop/Executable_soffice_bin.mk b/desktop/Executable_soffice_bin.mk index a3c3ff258613..d9489bdad098 100644 --- a/desktop/Executable_soffice_bin.mk +++ b/desktop/Executable_soffice_bin.mk @@ -45,6 +45,14 @@ $(eval $(call gb_Executable_add_ldflags,soffice_bin,\ endif +ifeq (TRUE,$(EMSCRIPTEN)) + +$(eval $(call gb_Executable_add_ldflags,soffice_bin,\ + -sEXPORTED_FUNCTIONS=_main,_libreofficekit_hook,_libreofficekit_hook_2,_lok_preinit,_lok_preinit_2 \ +)) + +endif + endif # vim: set ts=4 sw=4 et: diff --git a/desktop/Library_sofficeapp.mk b/desktop/Library_sofficeapp.mk index 70f4b07ea045..efc117424098 100644 --- a/desktop/Library_sofficeapp.mk +++ b/desktop/Library_sofficeapp.mk @@ -137,20 +137,13 @@ $(eval $(call gb_Library_add_exception_objects,sofficeapp,\ desktop/source/lib/lokandroid) \ )) else -ifeq ($(USING_X11),TRUE) +ifeq ($(filter TRUE,$(USING_X11) $(DISABLE_GUI) $(EMSCRIPTEN)),) $(eval $(call gb_Library_add_exception_objects,sofficeapp,\ desktop/source/lib/init \ desktop/source/lib/lokinteractionhandler \ desktop/source/lib/lokclipboard \ )) endif -ifeq ($(DISABLE_GUI),TRUE) -$(eval $(call gb_Library_add_exception_objects,sofficeapp,\ - desktop/source/lib/init \ - desktop/source/lib/lokinteractionhandler \ - desktop/source/lib/lokclipboard \ -)) -endif endif # vim: set ts=4 sw=4 et: diff --git a/solenv/gbuild/platform/EMSCRIPTEN_INTEL_GCC.mk b/solenv/gbuild/platform/EMSCRIPTEN_INTEL_GCC.mk index 61424f72c44f..5d0ef59d8360 100644 --- a/solenv/gbuild/platform/EMSCRIPTEN_INTEL_GCC.mk +++ b/solenv/gbuild/platform/EMSCRIPTEN_INTEL_GCC.mk @@ -24,6 +24,9 @@ gb_EMSCRIPTEN_LDFLAGS := $(gb_EMSCRIPTEN_CPPFLAGS) # Initial memory size and worker thread pool gb_EMSCRIPTEN_LDFLAGS += -s TOTAL_MEMORY=1GB -s PTHREAD_POOL_SIZE=4 +# add a few critical functions to export +gb_EMSCRIPTEN_LDFLAGS += -sEXPORTED_RUNTIME_METHODS=ccall,cwrap + # To keep the link time (and memory) down, prevent all rewriting options from wasm-emscripten-finalize # See emscripten.py, finalize_wasm, modify_wasm = True # So we need WASM_BIGINT=1 and ASSERTIONS=1 (2 implies STACK_OVERFLOW_CHECK) commit ad3b31cd390702c367cf1f00a2f790b91d5afde2 Author: Jan-Marek Glogowski <glo...@fbihome.de> AuthorDate: Tue Apr 26 18:11:55 2022 +0200 Commit: Thorsten Behrens <thorsten.behr...@allotropia.de> CommitDate: Tue Nov 8 10:34:27 2022 +0100 WASM HACK fix NEH build Workaround a toolchain bug. Also see comment in ~Desktop(). Change-Id: I158877b78794d81ccdc74e4d5fc023e2061c1d96 diff --git a/desktop/inc/app.hxx b/desktop/inc/app.hxx index 3372e751dbf1..8eb71d3b13b5 100644 --- a/desktop/inc/app.hxx +++ b/desktop/inc/app.hxx @@ -166,7 +166,7 @@ class Desktop final : public Application BootstrapStatus m_aBootstrapStatus; std::unique_ptr<Lockfile> m_xLockfile; - Timer m_firstRunTimer; + Timer *m_firstRunTimer; std::thread m_aUpdateThread; }; diff --git a/desktop/source/app/app.cxx b/desktop/source/app/app.cxx index 135a5b5fdb1f..11727f8af92e 100644 --- a/desktop/source/app/app.cxx +++ b/desktop/source/app/app.cxx @@ -426,14 +426,16 @@ Desktop::Desktop() , m_bServicesRegistered(false) , m_aBootstrapError(BE_OK) , m_aBootstrapStatus(BS_OK) - , m_firstRunTimer( "desktop::Desktop m_firstRunTimer" ) + , m_firstRunTimer(new Timer("desktop::Desktop m_firstRunTimer")) { - m_firstRunTimer.SetTimeout(3000); // 3 sec. - m_firstRunTimer.SetInvokeHandler(LINK(this, Desktop, AsyncInitFirstRun)); + m_firstRunTimer->SetTimeout(3000); // 3 sec. + m_firstRunTimer->SetInvokeHandler(LINK(this, Desktop, AsyncInitFirstRun)); } Desktop::~Desktop() { +// Uncommenting this delete breaks the WASM output with a runtime error +// delete m_firstRunTimer; } void Desktop::Init() @@ -2560,7 +2562,7 @@ void Desktop::CheckFirstRun( ) // use VCL timer, which won't trigger during shutdown if the // application exits before timeout - m_firstRunTimer.Start(); + m_firstRunTimer->Start(); #ifdef _WIN32 // Check if Quickstarter should be started (on Windows only) commit 1c740c3499eeaf4f0b83e44ed2481a85d52d6add Author: Jan-Marek Glogowski <glo...@fbihome.de> AuthorDate: Sun Feb 20 14:06:54 2022 +0100 Commit: Thorsten Behrens <thorsten.behr...@allotropia.de> CommitDate: Tue Nov 8 10:34:27 2022 +0100 fixme static tests Change-Id: I2aaffa032bd531272257ca40d6f9b9d25c4de5aa diff --git a/sal/cppunittester/cppunittester.cxx b/sal/cppunittester/cppunittester.cxx index 88f59bb64bcf..e48553b2cf6d 100644 --- a/sal/cppunittester/cppunittester.cxx +++ b/sal/cppunittester/cppunittester.cxx @@ -245,6 +245,7 @@ public: , protectors(protectors_) , result(result_) { + (void) args_; } ProtectedFixtureFunctor(const ProtectedFixtureFunctor&) = delete; ProtectedFixtureFunctor& operator=(const ProtectedFixtureFunctor&) = delete; commit c228f61c1aec07d0d3d03bbcd97512cd03ca37ab Author: Jan-Marek Glogowski <glo...@fbihome.de> AuthorDate: Sun Jan 9 14:49:28 2022 +0100 Commit: Thorsten Behrens <thorsten.behr...@allotropia.de> CommitDate: Tue Nov 8 10:34:27 2022 +0100 Add a larger Writer example document Change-Id: I4bc9a82c7f99563af8da62f889b51d1b583df760 diff --git a/android/default-document/example_larger.odt b/android/default-document/example_larger.odt new file mode 100644 index 000000000000..1b3a1dfb877a Binary files /dev/null and b/android/default-document/example_larger.odt differ diff --git a/static/CustomTarget_emscripten_fs_image.mk b/static/CustomTarget_emscripten_fs_image.mk index 61f718a85ae5..6ce38af75cbb 100644 --- a/static/CustomTarget_emscripten_fs_image.mk +++ b/static/CustomTarget_emscripten_fs_image.mk @@ -1389,6 +1389,7 @@ gb_emscripten_fs_image_files += \ $(INSTROOT)/$(LIBO_SHARE_RESOURCE_FOLDER)/common/fonts/opens___.ttf \ $(INSTROOT)/$(LIBO_URE_ETC_FOLDER)/$(call gb_Helper_get_rcfile,uno) \ $(INSTROOT)/$(LIBO_URE_MISC_FOLDER)/services.rdb \ + $(SRCDIR)/android/default-document/example_larger.odt \ $(SRCDIR)/android/default-document/example.odt \ $(SRCDIR)/android/default-document/example_test.ods \ diff --git a/static/emscripten/soffice_args.js b/static/emscripten/soffice_args.js index 7ecf7e8988e8..fa5e9dd4164d 100644 --- a/static/emscripten/soffice_args.js +++ b/static/emscripten/soffice_args.js @@ -2,5 +2,5 @@ Module['arguments'] = [ '--norestore', '--nologo', '--writer', - '/android/default-document/example.odt' + '/android/default-document/example_larger.odt' ]; commit 0b2cd042e4d7eb69c9ded9ce9cbd432f8754c21d Author: Jan-Marek Glogowski <glo...@fbihome.de> AuthorDate: Wed Nov 17 01:57:33 2021 +0100 Commit: Thorsten Behrens <thorsten.behr...@allotropia.de> CommitDate: Tue Nov 8 10:34:27 2022 +0100 WIP: async popup menus A first patch to get some feedback. Asnyc LO popup menus are still buggy, as I'm not sure where to call the PopupMenu::Finish for them. Also the XDialogClosedListener is currently just for convenience and might want some separate notifier. Fun fact, that ImplExecute / ImplPopup is called for submenu, but then doesn't execute. And generally the naming of some variables is IMHO wrong; I might also prefix Menu members with "m_" for easier readability. Change-Id: Id8b413aa6b4699201e58db0113649c6b224d33b6 diff --git a/include/sfx2/dispatch.hxx b/include/sfx2/dispatch.hxx index ee445710b9c0..a1c0f9aa5ad2 100644 --- a/include/sfx2/dispatch.hxx +++ b/include/sfx2/dispatch.hxx @@ -20,6 +20,7 @@ #define INCLUDED_SFX2_DISPATCH_HXX #include <memory> +#include <functional> #include <sal/config.h> #include <sfx2/dllapi.h> #include <sfx2/toolbarids.hxx> @@ -42,6 +43,7 @@ struct SfxDispatcher_Impl; namespace com::sun::star::awt { class XPopupMenu; } namespace vcl { class Window; } +namespace com::sun::star::ui::dialogs { struct DialogClosedEvent; } enum class SfxDispatcherPopFlags { @@ -136,8 +138,14 @@ public: SfxViewFrame* GetFrame() const; SfxModule* GetModule() const; - void ExecutePopup( const OUString &rResName, vcl::Window *pWin = nullptr, const Point *pPos = nullptr ); - static void ExecutePopup( vcl::Window *pWin = nullptr, const Point *pPosPixel = nullptr ); + /** + * @param rCloseFunc + * If this is !nullptr, the popup will be just shown / run async and rCloseFunc will be called on close. + */ + void ExecutePopup(const OUString &rResName, vcl::Window *pWin = nullptr, const Point *pPos = nullptr, + const std::function<void(sal_Int16)>& rCloseFunc = nullptr); + static void ExecutePopup(vcl::Window *pWin = nullptr, const Point *pPosPixel = nullptr, + const std::function<void(sal_Int16)>& rCloseFunc = nullptr); bool IsAppDispatcher() const; bool IsFlushed() const; diff --git a/include/toolkit/awt/vclxmenu.hxx b/include/toolkit/awt/vclxmenu.hxx index 096c370bce82..ffa89e9a8511 100644 --- a/include/toolkit/awt/vclxmenu.hxx +++ b/include/toolkit/awt/vclxmenu.hxx @@ -25,10 +25,11 @@ #include <toolkit/helper/listenermultiplexer.hxx> #include <com/sun/star/awt/XMenuBar.hpp> -#include <com/sun/star/awt/XPopupMenu.hpp> +#include <com/sun/star/awt/XPopupMenuAsync.hpp> #include <com/sun/star/lang/XServiceInfo.hpp> #include <com/sun/star/lang/XTypeProvider.hpp> #include <com/sun/star/lang/XUnoTunnel.hpp> +#include <com/sun/star/ui/dialogs/XDialogClosedListener.hpp> #include <comphelper/servicehelper.hxx> #include <cppuhelper/weak.hxx> @@ -39,6 +40,7 @@ #include <vector> +struct DialogClosedEvent; class Menu; class MenuBar; class PopupMenu; @@ -51,10 +53,11 @@ typedef ::std::vector< typedef void (*MenuUserDataReleaseFunction)(void*); class TOOLKIT_DLLPUBLIC VCLXMenu : public css::awt::XMenuBar, - public css::awt::XPopupMenu, + public css::awt::XPopupMenuAsync, public css::lang::XServiceInfo, public css::lang::XTypeProvider, public css::lang::XUnoTunnel, + public css::ui::dialogs::XDialogClosedListener, public ::cppu::OWeakObject { private: @@ -76,7 +79,6 @@ public: VCLXMenu( Menu* pMenu ); virtual ~VCLXMenu() override; - Menu* GetMenu() const { return mpMenu; } bool IsPopupMenu() const; void setUserValue(sal_uInt16 nItemId, void* nUserValue, MenuUserDataReleaseFunction aFunc); @@ -137,10 +139,20 @@ public: virtual void SAL_CALL setItemImage( ::sal_Int16 nItemId, const css::uno::Reference< css::graphic::XGraphic >& xGraphic, sal_Bool bScale ) override; virtual css::uno::Reference< css::graphic::XGraphic > SAL_CALL getItemImage( ::sal_Int16 nItemId ) override; + // css::awt::XPopupMenuAsync + virtual sal_Bool SAL_CALL popup(const css::uno::Reference< css::awt::XWindowPeer >& Parent, const css::awt::Rectangle& Position, + ::sal_Int16 Direction, const css::uno::Reference<css::ui::dialogs::XDialogClosedListener>& xListener) override; + // css::lang::XServiceInfo virtual OUString SAL_CALL getImplementationName( ) override; virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; + + // css::ui::dialogs::XDialogClosedListener + virtual void SAL_CALL dialogClosed(const css::ui::dialogs::DialogClosedEvent& aEvent) override; + + // XEventListener (base of XDialogClosedListener) + virtual void SAL_CALL disposing(css::lang::EventObject const & Source) override; }; class UNLESS_MERGELIBS(TOOLKIT_DLLPUBLIC) VCLXMenuBar final : public VCLXMenu diff --git a/include/vcl/menu.hxx b/include/vcl/menu.hxx index bb0ef8cee6db..161ee029e2a8 100644 --- a/include/vcl/menu.hxx +++ b/include/vcl/menu.hxx @@ -44,6 +44,7 @@ class Menu; class MenuItemList; class Image; class PopupMenu; +struct PopupMenuFinishState; class KeyEvent; class MenuFloatingWindow; class SalMenu; @@ -54,6 +55,7 @@ enum class FloatWinPopupFlags; enum class VclEventId; namespace com::sun::star::awt { class XPopupMenu; } +namespace com::sun::star::ui::dialogs { class XDialogClosedListener; } namespace com::sun::star::accessibility { class XAccessible; } namespace vcl @@ -494,11 +496,16 @@ class VCL_DLLPUBLIC PopupMenu final : public Menu friend struct MenuItemData; private: + struct PopupMenuFinishState* m_pState; + SAL_DLLPRIVATE MenuFloatingWindow * ImplGetFloatingWindow() const; SAL_DLLPRIVATE bool PrepareRun(const VclPtr<vcl::Window>& pParentWin, tools::Rectangle& rRect, FloatWinPopupFlags& nPopupModeFlags, Menu* pSFrom, bool& bRealExecute, VclPtr<MenuFloatingWindow>&); - SAL_DLLPRIVATE bool Run(const VclPtr<MenuFloatingWindow>&, bool bRealExecute, bool bPreSelectFirst, FloatWinPopupFlags nPopupModeFlags, Menu* pSFrom, const tools::Rectangle& rRect); + SAL_DLLPRIVATE bool Run(const VclPtr<MenuFloatingWindow>&, bool bRealExecute, bool bPreSelectFirst, FloatWinPopupFlags nPopupModeFlags, Menu* pSFrom, const tools::Rectangle& rRect, + const css::uno::Reference<css::ui::dialogs::XDialogClosedListener>* xListener); SAL_DLLPRIVATE void FinishRun(const VclPtr<MenuFloatingWindow>&, const VclPtr<vcl::Window>& pParentWin, bool bRealExecute, bool bIsNativeMenu); SAL_DLLPRIVATE sal_uInt16 ImplExecute(const VclPtr<vcl::Window>& pParentWin, const tools::Rectangle& rRect, FloatWinPopupFlags nPopupModeFlags, Menu* pSFrom, bool bPreSelectFirst); + SAL_DLLPRIVATE bool ImplPopup(const VclPtr<vcl::Window>& pParentWin, const tools::Rectangle& rRect, FloatWinPopupFlags nPopupModeFlags, Menu* pSFrom, bool bPreSelectFirst, + const css::uno::Reference<css::ui::dialogs::XDialogClosedListener>&); SAL_DLLPRIVATE void ImplFlushPendingSelect(); SAL_DLLPRIVATE tools::Long ImplCalcHeight( sal_uInt16 nEntries ) const; SAL_DLLPRIVATE sal_uInt16 ImplCalcVisEntries( tools::Long nMaxHeight, sal_uInt16 nStartEntry, sal_uInt16* pLastVisible = nullptr ) const; @@ -521,6 +528,12 @@ public: sal_uInt16 Execute( vcl::Window* pWindow, const Point& rPopupPos ); sal_uInt16 Execute( vcl::Window* pWindow, const tools::Rectangle& rRect, PopupMenuFlags nFlags = PopupMenuFlags::NONE ); + bool Popup(vcl::Window* pParentWin, const Point& rPopupPos, + const css::uno::Reference<css::ui::dialogs::XDialogClosedListener>&); + bool Popup(vcl::Window* pParentWin, const tools::Rectangle& rRect, + const css::uno::Reference<css::ui::dialogs::XDialogClosedListener>&, PopupMenuFlags = PopupMenuFlags::NONE); + void Finish(); + // for the TestTool void EndExecute(); virtual void SelectItem(sal_uInt16 nId) override; diff --git a/offapi/UnoApi_offapi.mk b/offapi/UnoApi_offapi.mk index 331e5eadaf5f..138c9791bbcc 100644 --- a/offapi/UnoApi_offapi.mk +++ b/offapi/UnoApi_offapi.mk @@ -1859,6 +1859,7 @@ $(eval $(call gb_UnoApi_add_idlfiles,offapi,com/sun/star/awt,\ XPatternField \ XPointer \ XPopupMenu \ + XPopupMenuAsync \ XPrinter \ XPrinterPropertySet \ XPrinterServer \ diff --git a/offapi/com/sun/star/awt/XPopupMenuAsync.idl b/offapi/com/sun/star/awt/XPopupMenuAsync.idl new file mode 100644 index 000000000000..d3f7b317f086 --- /dev/null +++ b/offapi/com/sun/star/awt/XPopupMenuAsync.idl @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ +#ifndef __com_sun_star_awt_XPopupMenuAsync_idl__ +#define __com_sun_star_awt_XPopupMenuAsync_idl__ + +#include <com/sun/star/awt/XPopupMenu.idl> +#include <com/sun/star/ui/dialogs/XDialogClosedListener.idl> + +module com { module sun { module star { module awt { + +/** shows a pop-up menu without blocking. + */ +interface XPopupMenuAsync: XPopupMenu +{ + /** just shows the popup menu without blocking and calls the + XDialogClosedListener when closed, + + @param Parent + the parent window. + + @param Position + a Rectangle representing the coordinates system + where the popup menu should be executed. + + @param Direction + the direction in which a popup menu will grow, as specified + by one of the PopupMenuDirection constants. + + @param xListener + notified, if the popup is closed. + + @return + returns true, if the popup has started to run async. + May fail, if the native backend doesn't implement async popups. + */ + boolean popup([in] XWindowPeer Parent, [in] Rectangle Position, [in] short Direction, + [in] ::com::sun::star::ui::dialogs::XDialogClosedListener xListener); +}; + +}; }; }; }; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/drviews4.cxx b/sd/source/ui/view/drviews4.cxx index b21789c80137..b62f15250aeb 100644 --- a/sd/source/ui/view/drviews4.cxx +++ b/sd/source/ui/view/drviews4.cxx @@ -809,7 +809,7 @@ void DrawViewShell::Command(const CommandEvent& rCEvt, ::sd::Window* pWin) bool bShouldDisableEditHyperlink = ShouldDisableEditHyperlink(); if(rCEvt.IsMouseEvent()) - GetViewFrame()->GetDispatcher()->ExecutePopup( aPopupId ); + GetViewFrame()->GetDispatcher()->ExecutePopup(aPopupId, nullptr, nullptr, [](sal_Int16){}); else { //don't open contextmenu at mouse position if not opened via mouse diff --git a/sfx2/source/control/dispatch.cxx b/sfx2/source/control/dispatch.cxx index 17edf97cc16d..cce1d7d9ec19 100644 --- a/sfx2/source/control/dispatch.cxx +++ b/sfx2/source/control/dispatch.cxx @@ -60,6 +60,7 @@ #include <svl/eitem.hxx> #include <svl/itemiter.hxx> #include <svl/itempool.hxx> +#include <svtools/dialogclosedlistener.hxx> #include <toolkit/awt/vclxmenu.hxx> #include <toolkit/helper/vclunohelper.hxx> #include <tools/debug.hxx> @@ -137,8 +138,12 @@ struct SfxDispatcher_Impl SfxDisableFlags nDisableFlags; bool bFlushed; std::deque< std::deque<SfxToDo_Impl> > aToDoCopyStack; + + static css::uno::Reference<css::frame::XPopupMenuController>* m_pActivePopupController; }; +css::uno::Reference<css::frame::XPopupMenuController>* SfxDispatcher_Impl::m_pActivePopupController = nullptr; + /** This method checks if the stack of the SfxDispatchers is flushed, or if push- or pop- commands are pending. */ @@ -1685,7 +1690,52 @@ bool SfxDispatcher::FillState_(const SfxSlotServer& rSvr, SfxItemSet& rState, return false; } -void SfxDispatcher::ExecutePopup( vcl::Window *pWin, const Point *pPos ) +namespace { + +static void lcl_FinishPopupDispatch(css::uno::Reference<css::frame::XPopupMenuController> xPopupController) +{ + css::uno::Reference<css::lang::XComponent> xComponent(xPopupController, css::uno::UNO_QUERY); + if (xComponent.is()) + xComponent->dispose(); + SfxDispatcher_Impl::m_pActivePopupController = nullptr; +} + +struct SfxDispatcherPopupFinish final +{ + css::uno::Reference<css::frame::XPopupMenuController> m_xPopupController; + std::function<void(sal_Int16)> m_aCloseFunc; + rtl::Reference<::svt::DialogClosedListener> m_xDialogListener; + css::uno::Reference<css::awt::XPopupMenu> m_xPopupMenu; + + DECL_LINK(PopupClosedHdl, css::ui::dialogs::DialogClosedEvent*, void); + + SfxDispatcherPopupFinish(css::uno::Reference<css::frame::XPopupMenuController> xPopupController, + const std::function<void(sal_Int16)>& rCloseFunc, + css::uno::Reference<css::awt::XPopupMenu> xPopupMenu) + : m_xPopupController(xPopupController) + , m_aCloseFunc(rCloseFunc) + , m_xDialogListener(new ::svt::DialogClosedListener()) + , m_xPopupMenu(xPopupMenu) + { + m_xDialogListener->SetDialogClosedLink(LINK(this, SfxDispatcherPopupFinish, PopupClosedHdl)); + } +}; + +IMPL_LINK(SfxDispatcherPopupFinish, PopupClosedHdl, css::ui::dialogs::DialogClosedEvent*, pEvt, void) +{ + assert(m_xPopupController.is()); + if (!comphelper::LibreOfficeKit::isActive()) + assert(SfxDispatcher_Impl::m_pActivePopupController == &m_xPopupController); + if (m_aCloseFunc) + m_aCloseFunc(pEvt ? pEvt->DialogResult : 0); + lcl_FinishPopupDispatch(m_xPopupController); + delete this; +} + +} // anon namespace + +void SfxDispatcher::ExecutePopup(vcl::Window *pWin, const Point *pPos, + const std::function<void(sal_Int16)>& rCloseFunc) { SfxDispatcher &rDisp = *SfxGetpApp()->GetDispatcher_Impl(); sal_uInt16 nShLevel = 0; @@ -1699,7 +1749,7 @@ void SfxDispatcher::ExecutePopup( vcl::Window *pWin, const Point *pPos ) const OUString& rResName = pSh->GetInterface()->GetPopupMenuName(); if ( !rResName.isEmpty() ) { - rDisp.ExecutePopup( rResName, pWin, pPos ); + rDisp.ExecutePopup(rResName, pWin, pPos, rCloseFunc); return; } } @@ -1808,7 +1858,8 @@ boost::property_tree::ptree SfxDispatcher::fillPopupMenu(const css::uno::Referen return ::fillPopupMenu(pVCLMenu); } -void SfxDispatcher::ExecutePopup( const OUString& rResName, vcl::Window* pWin, const Point* pPos ) +void SfxDispatcher::ExecutePopup( const OUString& rResName, vcl::Window* pWin, const Point* pPos, + const std::function<void(sal_Int16)>& rCloseFunc) { css::uno::Sequence< css::uno::Any > aArgs{ css::uno::Any(comphelper::makePropertyValue( "Value", rResName )), @@ -1817,16 +1868,29 @@ void SfxDispatcher::ExecutePopup( const OUString& rResName, vcl::Window* pWin, c }; css::uno::Reference< css::uno::XComponentContext > xContext = comphelper::getProcessComponentContext(); - css::uno::Reference< css::frame::XPopupMenuController > xPopupController( - xContext->getServiceManager()->createInstanceWithArgumentsAndContext( - "com.sun.star.comp.framework.ResourceMenuController", aArgs, xContext ), css::uno::UNO_QUERY ); + + if (!comphelper::LibreOfficeKit::isActive()) + assert(!xImp->m_pActivePopupController); + if (!comphelper::LibreOfficeKit::isActive() && xImp->m_pActivePopupController) + return; + + css::uno::Reference<css::frame::XPopupMenuController> xPopupController = + css::uno::Reference<css::frame::XPopupMenuController>( + xContext->getServiceManager()->createInstanceWithArgumentsAndContext( + "com.sun.star.comp.framework.ResourceMenuController", aArgs, xContext), css::uno::UNO_QUERY); + if (!xPopupController.is()) + return; + SfxDispatcher_Impl::m_pActivePopupController = &xPopupController; css::uno::Reference< css::awt::XPopupMenu > xPopupMenu( xContext->getServiceManager()->createInstanceWithContext( "com.sun.star.awt.PopupMenu", xContext ), css::uno::UNO_QUERY ); - - if ( !xPopupController.is() || !xPopupMenu.is() ) + if (!xPopupMenu.is()) + { + lcl_FinishPopupDispatch(xPopupController); return; + } + struct SfxDispatcherPopupFinish* pFin = nullptr; vcl::Window* pWindow = pWin ? pWin : xImp->pFrame->GetFrame().GetWorkWindow_Impl()->GetWindow(); Point aPos = pPos ? *pPos : pWindow->GetPointerPosPixel(); @@ -1852,14 +1916,22 @@ void SfxDispatcher::ExecutePopup( const OUString& rResName, vcl::Window* pWin, c OUString aMenuURL = "private:resource/popupmenu/" + rResName; if (GetFrame()->GetViewShell()->TryContextMenuInterception(xPopupMenu, aMenuURL, aEvent)) { + const sal_Int16 nFlags = css::awt::PopupMenuDirection::EXECUTE_DOWN; + const css::awt::Rectangle aRect(aPos.X(), aPos.Y(), 1, 1); css::uno::Reference<css::awt::XWindowPeer> xParent(aEvent.SourceWindow, css::uno::UNO_QUERY); - xPopupMenu->execute(xParent, css::awt::Rectangle(aPos.X(), aPos.Y(), 1, 1), css::awt::PopupMenuDirection::EXECUTE_DOWN); + css::uno::Reference<css::awt::XPopupMenuAsync> xAsyncPopup(xPopupMenu, css::uno::UNO_QUERY); + pFin = new SfxDispatcherPopupFinish(xPopupController, rCloseFunc, xPopupMenu); + if (!rCloseFunc || !xAsyncPopup.is() || !xAsyncPopup->popup(xParent, aRect, nFlags, pFin->m_xDialogListener)) + { + delete pFin; + pFin = nullptr; + xPopupMenu->execute(xParent, aRect, nFlags); + } } } - css::uno::Reference< css::lang::XComponent > xComponent( xPopupController, css::uno::UNO_QUERY ); - if ( xComponent.is() ) - xComponent->dispose(); + if (!pFin) + lcl_FinishPopupDispatch(xPopupController); } /** With this method the SfxDispatcher can be locked and released. A locked diff --git a/sw/source/uibase/docvw/edtwin.cxx b/sw/source/uibase/docvw/edtwin.cxx index 46c643a6a43e..7475c1c52e21 100644 --- a/sw/source/uibase/docvw/edtwin.cxx +++ b/sw/source/uibase/docvw/edtwin.cxx @@ -5613,7 +5613,7 @@ void SwEditWin::Command( const CommandEvent& rCEvt ) } } else if ( !m_rView.ExecSpellPopup( aDocPos ) ) - SfxDispatcher::ExecutePopup(this, &aPixPos); + SfxDispatcher::ExecutePopup(this, &aPixPos, [](sal_Int16){}); } else if (m_pApplyTempl->nUndo < rSh.GetDoc()->GetIDocumentUndoRedo().GetUndoActionCount()) { diff --git a/toolkit/inc/helper/unowrapper.hxx b/toolkit/inc/helper/unowrapper.hxx index 03a9b525cc18..fdc65988bb62 100644 --- a/toolkit/inc/helper/unowrapper.hxx +++ b/toolkit/inc/helper/unowrapper.hxx @@ -56,7 +56,7 @@ public: virtual VclPtr<vcl::Window> GetWindow(const css::uno::Reference<css::awt::XWindow>& rxWindow) override; // Menu - virtual css::uno::Reference<css::awt::XPopupMenu> CreateMenuInterface( PopupMenu* pPopupMenu ) override; + virtual css::uno::Reference<css::awt::XPopupMenu> CreateMenuInterface(PopupMenu* pPopupMenu) override; void WindowDestroyed( vcl::Window* pWindow ) override; diff --git a/toolkit/source/awt/vclxmenu.cxx b/toolkit/source/awt/vclxmenu.cxx index b17f32c2aebc..e2f78a2528ed 100644 --- a/toolkit/source/awt/vclxmenu.cxx +++ b/toolkit/source/awt/vclxmenu.cxx @@ -35,6 +35,7 @@ #include <vcl/window.hxx> #include <com/sun/star/awt/KeyModifier.hpp> +#include <com/sun/star/ui/dialogs/DialogClosedEvent.hpp> VCLXMenu::VCLXMenu() : maMenuListeners( *this ) @@ -491,6 +492,33 @@ sal_Int16 VCLXMenu::execute( static_cast<PopupMenuFlags>(nFlags) | PopupMenuFlags::NoMouseUpClose ); } +sal_Bool VCLXMenu::popup( + const css::uno::Reference< css::awt::XWindowPeer >& rxWindowPeer, + const css::awt::Rectangle& rPos, sal_Int16 nFlags, + const css::uno::Reference<css::ui::dialogs::XDialogClosedListener>& xListener) +{ + SolarMutexGuard aSolarGuard; + std::unique_lock aGuard( maMutex ); + + if (!mpMenu || !IsPopupMenu()) + return false; + + return static_cast<PopupMenu*>(mpMenu.get())->Popup(VCLUnoHelper::GetWindow(rxWindowPeer), + VCLRectangle(rPos), xListener.is() ? xListener : this, + static_cast<PopupMenuFlags>(nFlags) | PopupMenuFlags::NoMouseUpClose); +} + +void SAL_CALL VCLXMenu::dialogClosed(const css::ui::dialogs::DialogClosedEvent&) +{ + SolarMutexGuard aSolarGuard; + std::unique_lock aGuard( maMutex ); + + assert(mpMenu && IsPopupMenu()); + if (mpMenu && IsPopupMenu()) + static_cast<PopupMenu*>(mpMenu.get())->Finish(); +} + +void SAL_CALL VCLXMenu::disposing(css::lang::EventObject const&) {} void SAL_CALL VCLXMenu::setCommand( sal_Int16 nItemId, diff --git a/toolkit/source/helper/unowrapper.cxx b/toolkit/source/helper/unowrapper.cxx index 080847154cb2..ad3d28913060 100644 --- a/toolkit/source/helper/unowrapper.cxx +++ b/toolkit/source/helper/unowrapper.cxx @@ -189,7 +189,7 @@ void UnoWrapper::SetWindowInterface( vcl::Window* pWindow, const css::uno::Refer } } -css::uno::Reference<css::awt::XPopupMenu> UnoWrapper::CreateMenuInterface( PopupMenu* pPopupMenu ) +css::uno::Reference<css::awt::XPopupMenu> UnoWrapper::CreateMenuInterface(PopupMenu* pPopupMenu) { return new VCLXPopupMenu(pPopupMenu); } diff --git a/vcl/inc/osx/salmenu.h b/vcl/inc/osx/salmenu.h index 274d1ecd70b2..83068b8d9a7f 100644 --- a/vcl/inc/osx/salmenu.h +++ b/vcl/inc/osx/salmenu.h @@ -67,7 +67,9 @@ public: virtual void SetItemImage( unsigned nPos, SalMenuItem* pSalMenuItem, const Image& rImage) override; virtual void SetAccelerator( unsigned nPos, SalMenuItem* pSalMenuItem, const vcl::KeyCode& rKeyCode, const OUString& rKeyName ) override; virtual void GetSystemMenuData( SystemMenuData* pData ) override; - virtual bool ShowNativePopupMenu(FloatingWindow * pWin, const tools::Rectangle& rRect, FloatWinPopupFlags nFlags) override; + virtual bool ShowNativePopupMenu( + FloatingWindow*, const tools::Rectangle&, FloatWinPopupFlags, + const css::uno::Reference<css::ui::dialogs::XDialogClosedListener>* = nullptr) override; virtual bool AddMenuBarButton( const SalMenuButtonItem& ) override; virtual void RemoveMenuBarButton( sal_uInt16 nId ) override; virtual tools::Rectangle GetMenuBarButtonRectPixel( sal_uInt16 i_nItemId, SalFrame* i_pReferenceFrame ) override; diff --git a/vcl/inc/qt5/QtMenu.hxx b/vcl/inc/qt5/QtMenu.hxx index 6bb0dbcab4ec..501caaf4d089 100644 --- a/vcl/inc/qt5/QtMenu.hxx +++ b/vcl/inc/qt5/QtMenu.hxx @@ -40,7 +40,7 @@ class QtFrame; class QtMenu : public QObject, public SalMenu { Q_OBJECT -private: + std::vector<QtMenuItem*> maItems; VclPtr<Menu> mpVCLMenu; QtMenu* mpParentSalMenu; @@ -53,6 +53,9 @@ private: QMenu* mpQMenu; QButtonGroup* m_pButtonGroup; + css::uno::Reference<css::ui::dialogs::XDialogClosedListener> m_xListener; + FloatingWindow* m_pWin; + void DoFullMenuUpdate(Menu* pMenuBar); static void NativeItemText(OUString& rItemText); @@ -78,8 +81,9 @@ public: virtual void SetSubMenu(SalMenuItem* pSalMenuItem, SalMenu* pSubMenu, unsigned nPos) override; virtual void SetFrame(const SalFrame* pFrame) override; const QtFrame* GetFrame() const; - virtual bool ShowNativePopupMenu(FloatingWindow* pWin, const tools::Rectangle& rRect, - FloatWinPopupFlags nFlags) override; + virtual bool ShowNativePopupMenu( + FloatingWindow*, const tools::Rectangle&, FloatWinPopupFlags, + const css::uno::Reference<css::ui::dialogs::XDialogClosedListener>* = nullptr) override; QtMenu* GetTopLevel(); virtual void SetItemBits(unsigned nPos, MenuItemBits nBits) override; virtual void CheckItem(unsigned nPos, bool bCheck) override; diff --git a/vcl/inc/salmenu.hxx b/vcl/inc/salmenu.hxx index 50c1e9f4bc8a..473a4deebd62 100644 --- a/vcl/inc/salmenu.hxx +++ b/vcl/inc/salmenu.hxx @@ -23,6 +23,7 @@ #include <utility> #include <vcl/menu.hxx> #include <vcl/image.hxx> +#include <com/sun/star/ui/dialogs/XDialogClosedListener.hpp> struct SystemMenuData; class FloatingWindow; @@ -83,7 +84,17 @@ public: virtual void SetItemImage( unsigned nPos, SalMenuItem* pSalMenuItem, const Image& rImage ) = 0; virtual void SetAccelerator( unsigned nPos, SalMenuItem* pSalMenuItem, const vcl::KeyCode& rKeyCode, const OUString& rKeyName ) = 0; virtual void GetSystemMenuData( SystemMenuData* pData ) = 0; - virtual bool ShowNativePopupMenu(FloatingWindow * pWin, const tools::Rectangle& rRect, FloatWinPopupFlags nFlags); + /** + * @param pListener + * if !nullptr, the menu is supposed to be only shown and it'll run async. + * Mainly means, when the menu is hidden, it must call the listener's + * dialogClosed. The listener will destroy the SalMenu! + * + * @return + * true, if the feature is implemented and was successful. + */ + virtual bool ShowNativePopupMenu(FloatingWindow * pWin, const tools::Rectangle& rRect, FloatWinPopupFlags nFlags, + const css::uno::Reference<css::ui::dialogs::XDialogClosedListener>* pListener = nullptr); virtual void ShowCloseButton(bool bShow); virtual bool AddMenuBarButton( const SalMenuButtonItem& ); // return false if not implemented or failure virtual void RemoveMenuBarButton( sal_uInt16 nId ); diff --git a/vcl/inc/unx/gtk/gtksalmenu.hxx b/vcl/inc/unx/gtk/gtksalmenu.hxx index fc8ab760f5f5..f6b83052037d 100644 --- a/vcl/inc/unx/gtk/gtksalmenu.hxx +++ b/vcl/inc/unx/gtk/gtksalmenu.hxx @@ -131,7 +131,8 @@ public: #endif void ReturnFocus(); - virtual bool ShowNativePopupMenu(FloatingWindow * pWin, const tools::Rectangle& rRect, FloatWinPopupFlags nFlags) override; + virtual bool ShowNativePopupMenu(FloatingWindow * pWin, const tools::Rectangle& rRect, FloatWinPopupFlags nFlags, + const css::uno::Reference<css::ui::dialogs::XDialogClosedListener>* = nullptr) override; virtual void ShowCloseButton(bool bShow) override; virtual bool AddMenuBarButton( const SalMenuButtonItem& rNewItem ) override; virtual void RemoveMenuBarButton( sal_uInt16 nId ) override; diff --git a/vcl/osx/salmenu.cxx b/vcl/osx/salmenu.cxx index 60cafca71df4..b1a71f224f65 100644 --- a/vcl/osx/salmenu.cxx +++ b/vcl/osx/salmenu.cxx @@ -282,8 +282,13 @@ AquaSalMenu::~AquaSalMenu() } } -bool AquaSalMenu::ShowNativePopupMenu(FloatingWindow * pWin, const tools::Rectangle& rRect, FloatWinPopupFlags nFlags) +bool AquaSalMenu::ShowNativePopupMenu( + FloatingWindow* pWin, const tools::Rectangle& rRect, FloatWinPopupFlags nFlags, + const css::uno::Reference<css::ui::dialogs::XDialogClosedListener>* pListener) { + if (pListener) + return false; + // set offsets for positioning const float offset = 9.0; diff --git a/vcl/qt5/QtMenu.cxx b/vcl/qt5/QtMenu.cxx index dd259f32f979..758fd1765263 100644 --- a/vcl/qt5/QtMenu.cxx +++ b/vcl/qt5/QtMenu.cxx @@ -108,6 +108,16 @@ void QtMenu::InsertMenuItem(QtMenuItem* pSalMenuItem, unsigned nPos) // no QMenu set, instantiate own one mpOwnedQMenu.reset(new QMenu); mpQMenu = mpOwnedQMenu.get(); + + connect(mpQMenu, &QMenu::aboutToHide, this, [this] { + if (m_pWin && m_xListener.is()) + { + QMenu* pMenu = mpOwnedQMenu.release(); + css::ui::dialogs::DialogClosedEvent aEvent(m_pWin->GetComponentInterface(), 0); + m_xListener->dialogClosed(aEvent); + pMenu->deleteLater(); + } + }); } if (pSalMenuItem->mpSubMenu) @@ -829,7 +839,8 @@ void QtMenu::ShowCloseButton(bool bShow) } bool QtMenu::ShowNativePopupMenu(FloatingWindow* pWin, const tools::Rectangle& rRect, - FloatWinPopupFlags nFlags) + FloatWinPopupFlags nFlags, + const css::uno::Reference<css::ui::dialogs::XDialogClosedListener>* pListener) { assert(mpQMenu); DoFullMenuUpdate(mpVCLMenu); @@ -840,7 +851,19 @@ bool QtMenu::ShowNativePopupMenu(FloatingWindow* pWin, const tools::Rectangle& r assert(pFrame); const tools::Rectangle aFloatRect = FloatingWindow::ImplConvertToAbsPos(xParent, rRect); const QRect aRect = toQRect(aFloatRect, 1 / pFrame->devicePixelRatioF()); - mpQMenu->exec(aRect.topLeft()); + + if (pListener) + { + m_xListener = *pListener; + m_pWin = pWin; + mpQMenu->popup(aRect.topLeft()); + } + else + { + m_xListener = nullptr; + m_pWin = nullptr; + mpQMenu->exec(aRect.topLeft()); + } return true; } diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx index 7af5cccb4e6b..dd150ae524f8 100644 --- a/vcl/source/app/salvtables.cxx +++ b/vcl/source/app/salvtables.cxx @@ -217,7 +217,9 @@ SalObject::~SalObject() {} SalMenu::~SalMenu() {} -bool SalMenu::ShowNativePopupMenu(FloatingWindow*, const tools::Rectangle&, FloatWinPopupFlags) +bool SalMenu::ShowNativePopupMenu( + FloatingWindow*, const tools::Rectangle&, FloatWinPopupFlags, + const css::uno::Reference<css::ui::dialogs::XDialogClosedListener>*) { return false; } diff --git a/vcl/source/control/managedmenubutton.cxx b/vcl/source/control/managedmenubutton.cxx index bf3065e71cdf..0bb521e201dd 100644 --- a/vcl/source/control/managedmenubutton.cxx +++ b/vcl/source/control/managedmenubutton.cxx @@ -13,6 +13,7 @@ #include <managedmenubutton.hxx> #include <vcl/menu.hxx> +#include <com/sun/star/awt/XPopupMenuAsync.hpp> #include <com/sun/star/frame/ModuleManager.hpp> #include <com/sun/star/frame/theDesktop.hpp> #include <com/sun/star/frame/thePopupMenuControllerFactory.hpp> diff --git a/vcl/source/window/menu.cxx b/vcl/source/window/menu.cxx index bf02fab4c698..ec938dd76291 100644 --- a/vcl/source/window/menu.cxx +++ b/vcl/source/window/menu.cxx @@ -2660,6 +2660,7 @@ MenuFloatingWindow * PopupMenu::ImplGetFloatingWindow() const { } PopupMenu::PopupMenu() + : m_pState(nullptr) { mpSalMenu = ImplGetSVData()->mpDefInst->CreateMenu(false, this); } @@ -2672,6 +2673,7 @@ PopupMenu::PopupMenu( const PopupMenu& rMenu ) PopupMenu::~PopupMenu() { + assert(!m_pState); disposeOnce(); } @@ -2769,6 +2771,36 @@ sal_uInt16 PopupMenu::Execute( vcl::Window* pExecWindow, const tools::Rectangle& return ImplExecute( pExecWindow, rRect, lcl_TranslateFlags(nFlags), nullptr, false ); } +struct PopupMenuFinishState final +{ + VclPtr<PopupMenu> pSelf; + VclPtr<vcl::Window> pParentWin; + VclPtr<MenuFloatingWindow> pWin; + bool bRealExecute; + bool bIsNativeMenu; + + void clean() + { + pWin = nullptr; + pParentWin = nullptr; + pSelf = nullptr; + } +}; + +bool PopupMenu::Popup(vcl::Window* pExecWindow, const Point& rPopupPos, + const css::uno::Reference<css::ui::dialogs::XDialogClosedListener>& listener) +{ + return Popup(pExecWindow, tools::Rectangle(rPopupPos, rPopupPos), listener, PopupMenuFlags::ExecuteDown); +} + +bool PopupMenu::Popup(vcl::Window* pExecWindow, const tools::Rectangle& rRect, + const css::uno::Reference<css::ui::dialogs::XDialogClosedListener>& listener, PopupMenuFlags nFlags) +{ + assert(!m_pState); + ENSURE_OR_RETURN(pExecWindow, "PopupMenu::Popup: need a non-NULL window!", false); + return ImplPopup(pExecWindow, rRect, lcl_TranslateFlags(nFlags), nullptr, false, listener); +} + void PopupMenu::ImplFlushPendingSelect() { // is there still Select? @@ -2920,7 +2952,7 @@ bool PopupMenu::PrepareRun(const VclPtr<vcl::Window>& pParentWin, tools::Rectang if (pStartedFrom && pStartedFrom->IsMenuBar()) nMaxHeight -= pParentWin->GetSizePixel().Height(); sal_Int32 nLeft, nTop, nRight, nBottom; - pWindow->GetBorder( nLeft, nTop, nRight, nBottom ); + pWindow->GetBorder(nLeft, nTop, nRight, nBottom); nMaxHeight -= nTop+nBottom; if ( aSz.Height() > nMaxHeight ) { @@ -2936,10 +2968,11 @@ bool PopupMenu::PrepareRun(const VclPtr<vcl::Window>& pParentWin, tools::Rectang } bool PopupMenu::Run(const VclPtr<MenuFloatingWindow>& pWin, const bool bRealExecute, const bool bPreSelectFirst, - const FloatWinPopupFlags nPopupModeFlags, Menu* pSFrom, const tools::Rectangle& rRect) + const FloatWinPopupFlags nPopupModeFlags, Menu* pSFrom, const tools::Rectangle& rRect, + const css::uno::Reference<css::ui::dialogs::XDialogClosedListener>* xListener) { SalMenu* pMenu = ImplGetSalMenu(); - if (pMenu && bRealExecute && pMenu->ShowNativePopupMenu(pWin, rRect, nPopupModeFlags)) + if (pMenu && bRealExecute && pMenu->ShowNativePopupMenu(pWin, rRect, nPopupModeFlags, xListener)) return true; pWin->StartPopupMode(rRect, nPopupModeFlags); @@ -2975,7 +3008,12 @@ bool PopupMenu::Run(const VclPtr<MenuFloatingWindow>& pWin, const bool bRealExec } if (bRealExecute) - pWin->Execute(); + { + if (!xListener) + pWin->Execute(); + else + pWin->Popup(*xListener); + } return false; } @@ -3020,11 +3058,42 @@ sal_uInt16 PopupMenu::ImplExecute(const VclPtr<vcl::Window>& pParentWin, const t VclPtr<MenuFloatingWindow> pWin; if (!PrepareRun(pParentWin, aRect, nPopupModeFlags, pSFrom, bRealExecute, pWin)) return 0; - const bool bNative = Run(pWin, bRealExecute, bPreSelectFirst, nPopupModeFlags, pSFrom, aRect); + const bool bNative = Run(pWin, bRealExecute, bPreSelectFirst, nPopupModeFlags, pSFrom, aRect, nullptr); FinishRun(pWin, pParentWin, bRealExecute, bNative); return nSelectedId; } +bool PopupMenu::ImplPopup(const VclPtr<vcl::Window>& pParentWin, const tools::Rectangle& rRect, + FloatWinPopupFlags nPopupModeFlags, Menu* pSFrom, bool bPreSelectFirst, + const css::uno::Reference<css::ui::dialogs::XDialogClosedListener>& xListener) +{ + // tdf#126054 hold this until after function completes + VclPtr<PopupMenu> xThis(this); + bool bRealExecute = false; + tools::Rectangle aRect(rRect); + VclPtr<MenuFloatingWindow> pWin; + if (!PrepareRun(pParentWin, aRect, nPopupModeFlags, pSFrom, bRealExecute, pWin)) + return false; + assert(!m_pState); + m_pState = new PopupMenuFinishState; + m_pState->bIsNativeMenu = Run(pWin, bRealExecute, bPreSelectFirst, nPopupModeFlags, pSFrom, aRect, &xListener); + m_pState->pWin = pWin; + m_pState->pParentWin = pParentWin; + m_pState->bRealExecute = bRealExecute; + m_pState->pSelf = xThis; + return true; +} + +void PopupMenu::Finish() +{ + if (!m_pState) + return; + FinishRun(m_pState->pWin, m_pState->pParentWin, m_pState->bRealExecute, m_pState->bIsNativeMenu); + m_pState->clean(); + delete m_pState; + m_pState = nullptr; +} + sal_uInt16 PopupMenu::ImplCalcVisEntries( tools::Long nMaxHeight, sal_uInt16 nStartEntry, sal_uInt16* pLastVisible ) const { nMaxHeight -= 2 * ImplGetFloatingWindow()->GetScrollerHeight(); diff --git a/vcl/source/window/menufloatingwindow.cxx b/vcl/source/window/menufloatingwindow.cxx index cfd6a6ae190e..075fb97f5632 100644 --- a/vcl/source/window/menufloatingwindow.cxx +++ b/vcl/source/window/menufloatingwindow.cxx @@ -308,8 +308,15 @@ IMPL_LINK_NOARG(MenuFloatingWindow, PopupEnd, FloatingWindow*, void) pMenu->pStartedFrom->ClosePopup(pMenu); } - if ( pM ) + if (pM) + { pM->pStartedFrom = nullptr; + if (m_xListener.is()) + { + css::ui::dialogs::DialogClosedEvent aEvent(GetComponentInterface(), pM->GetCurItemId()); + m_xListener->dialogClosed(aEvent); + } + } } IMPL_LINK_NOARG(MenuFloatingWindow, AutoScroll, Timer *, void) @@ -443,21 +450,31 @@ void MenuFloatingWindow::End() Window::EndSaveFocus(xFocusId); } + Finish(); + bInExecute = false; } -void MenuFloatingWindow::Execute() +void MenuFloatingWindow::Popup(const css::uno::Reference<css::ui::dialogs::XDialogClosedListener>& xListener) { ImplSVData* pSVData = ImplGetSVData(); - pSVData->maAppData.mpActivePopupMenu = static_cast<PopupMenu*>(pMenu.get()); - + m_xListener = xListener; Start(); +} +void MenuFloatingWindow::Finish() +{ + ImplSVData* pSVData = ImplGetSVData(); + pSVData->maAppData.mpActivePopupMenu = nullptr; +} + +void MenuFloatingWindow::Execute() +{ + Popup(); while (bInExecute && !Application::IsQuit()) Application::Yield(); - - pSVData->maAppData.mpActivePopupMenu = nullptr; + Finish(); } void MenuFloatingWindow::StopExecute() @@ -474,6 +491,7 @@ void MenuFloatingWindow::StopExecute() // notify parent, needed for accessibility if( pMenu && pMenu->pStartedFrom ) pMenu->pStartedFrom->ImplCallEventListeners( VclEventId::MenuSubmenuDeactivate, nPosInParent ); + Finish(); } void MenuFloatingWindow::KillActivePopup( PopupMenu* pThisOnly ) @@ -502,6 +520,7 @@ void MenuFloatingWindow::KillActivePopup( PopupMenu* pThisOnly ) PaintImmediately(); } + pPopup->Finish(); } void MenuFloatingWindow::EndExecute() diff --git a/vcl/source/window/menufloatingwindow.hxx b/vcl/source/window/menufloatingwindow.hxx index f26fb50373ca..b6c8b54738ce 100644 --- a/vcl/source/window/menufloatingwindow.hxx +++ b/vcl/source/window/menufloatingwindow.hxx @@ -46,6 +46,7 @@ private: sal_uInt16 nScrollerHeight; sal_uInt16 nFirstEntry; sal_uInt16 nPosInParent; + css::uno::Reference<css::ui::dialogs::XDialogClosedListener> m_xListener; bool bInExecute : 1; bool bScrollMenu : 1; @@ -67,6 +68,7 @@ private: void Start(); void End(); + static void Finish(); protected: vcl::Region ImplCalcClipRegion() const; @@ -107,6 +109,8 @@ public: bool IsScrollMenu() const { return bScrollMenu; } sal_uInt16 GetScrollerHeight() const { return nScrollerHeight; } + void Popup(const css::uno::Reference<css::ui::dialogs::XDialogClosedListener>& xListener = nullptr); + void Execute(); void StopExecute(); void EndExecute(); diff --git a/vcl/unx/gtk3/gtksalmenu.cxx b/vcl/unx/gtk3/gtksalmenu.cxx index bb4048485db9..f8b5d550a119 100644 --- a/vcl/unx/gtk3/gtksalmenu.cxx +++ b/vcl/unx/gtk3/gtksalmenu.cxx @@ -423,9 +423,13 @@ static void MenuClosed(GtkPopover* pWidget, GMainLoop* pLoop) g_main_loop_quit(pLoop); } -bool GtkSalMenu::ShowNativePopupMenu(FloatingWindow* pWin, const tools::Rectangle& rRect, - FloatWinPopupFlags nFlags) +bool GtkSalMenu::ShowNativePopupMenu + (FloatingWindow* pWin, const tools::Rectangle& rRect, FloatWinPopupFlags nFlags, + const css::uno::Reference<css::ui::dialogs::XDialogClosedListener>* pListener) { + if (pListener) + return false; + VclPtr<vcl::Window> xParent = pWin->ImplGetWindowImpl()->mpRealParent; mpFrame = static_cast<GtkSalFrame*>(xParent->ImplGetFrame()); commit c3c9429cd268b794df91a9221af7d3fe8f727f27 Author: Thorsten Behrens <thorsten.behr...@allotropia.de> AuthorDate: Sat Nov 13 23:12:58 2021 +0100 Commit: Thorsten Behrens <thorsten.behr...@allotropia.de> CommitDate: Tue Nov 8 10:34:27 2022 +0100 WASM default to notebookbar ..and use the full, desktop variant.. Change-Id: Ib00aad8cd130b4a3433209c540fe82970c45c98e diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx index 6008820da1bb..edf3114a2d10 100644 --- a/desktop/source/lib/init.cxx +++ b/desktop/source/lib/init.cxx @@ -6796,7 +6796,11 @@ static void activateNotebookbar(std::u16string_view rApp) if (aAppNode.isValid()) { +#ifdef EMSCRIPTEN + aAppNode.setNodeValue("Active", Any(OUString("notebookbar.ui"))); +#else aAppNode.setNodeValue("Active", Any(OUString("notebookbar_online.ui"))); +#endif aAppNode.commit(); } } @@ -6857,7 +6861,11 @@ static int lo_initialize(LibreOfficeKit* pThis, const char* pAppPath, const char static bool bPreInited = false; static bool bUnipoll = false; static bool bProfileZones = false; +#ifdef EMSCRIPTEN + static bool bNotebookbar = true; +#else static bool bNotebookbar = false; +#endif { // cf. string lifetime for preinit std::vector<OUString> aOpts; commit 8bd4f709faca76716cd0e4cd5a60408878e50d1e Author: Jan-Marek Glogowski <glo...@fbihome.de> AuthorDate: Mon Dec 6 09:24:50 2021 +0100 Commit: Thorsten Behrens <thorsten.behr...@allotropia.de> CommitDate: Tue Nov 8 10:34:27 2022 +0100 gbuild: build static unit tests While this generally works, the setup is not very practical. The unit tests become all very large, if they use components. The best static solution I can imagine is either just somehow linking them on demand, or create a single huge liblibreoffice.so, so keeping everthing almost static. Change-Id: If00f9ac3b3f63b915e3b5dcd931d233681a58006 diff --git a/Repository.mk b/Repository.mk index 35c7a8e25295..9533a987a464 100644 --- a/Repository.mk +++ b/Repository.mk @@ -32,7 +32,7 @@ $(eval $(call gb_Helper_register_executables,NONE, \ cfgex \ concat-deps \ cpp \ - cppunittester \ + $(call gb_CondCppunitMainLibOrExe,,cppunittester) \ gbuildtojson \ $(if $(filter MSC,$(COM)), \ gcc-wrapper \ @@ -581,6 +581,7 @@ $(eval $(call gb_Helper_register_libraries,PLAINLIBS_NONE, \ $(if $(filter MSC,$(COM)),cli_cppuhelper) \ $(if $(filter $(OS),ANDROID),lo-bootstrap) \ $(if $(filter $(OS),MACOSX),OOoSpotlightImporter) \ + $(call gb_CondCppunitMainLibOrExe,cppunitmain) \ )) $(eval $(call gb_Helper_register_libraries_for_install,PLAINLIBS_URE,ure, \ diff --git a/sal/Library_cppunitmain.mk b/sal/Library_cppunitmain.mk new file mode 100644 index 000000000000..07f51e0c4821 --- /dev/null +++ b/sal/Library_cppunitmain.mk @@ -0,0 +1,42 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_Library_Library,cppunitmain)) + +$(eval $(call gb_Library_set_include,cppunitmain,\ + $$(INCLUDE) \ + -I$(SRCDIR)/sal/inc \ +)) + +$(eval $(call gb_Library_use_libraries,cppunitmain,\ + sal \ + unoexceptionprotector \ + unobootstrapprotector \ + vclbootstrapprotector \ +)) + +$(eval $(call gb_Library_use_externals,cppunitmain,\ + boost_headers \ + cppunit \ +)) + +$(eval $(call gb_Library_add_exception_objects,cppunitmain,\ + sal/cppunittester/cppunittester \ +)) + +ifeq ($(COM),MSC) + +$(eval $(call gb_Library_add_ldflags,cppunitmain,\ + /STACK:10000000 \ +)) + +endif + +# vim: set noet sw=4 ts=4: diff --git a/sal/Module_sal.mk b/sal/Module_sal.mk index e0448a5085bf..6c18d6282977 100644 --- a/sal/Module_sal.mk +++ b/sal/Module_sal.mk @@ -10,7 +10,7 @@ $(eval $(call gb_Module_Module,sal)) $(eval $(call gb_Module_add_targets,sal,\ - $(if $(CROSS_COMPILING),,$(if $(filter TRUE,$(DISABLE_DYNLOADING)),,Executable_cppunittester)) \ + $(call gb_CondCppunitMainLibOrExe,Library_cppunitmain,Executable_cppunittester) \ $(if $(filter $(OS),ANDROID), \ Library_lo-bootstrap) \ Library_sal \ diff --git a/sal/cppunittester/cppunittester.cxx b/sal/cppunittester/cppunittester.cxx index 81ddec1568ed..88f59bb64bcf 100644 --- a/sal/cppunittester/cppunittester.cxx +++ b/sal/cppunittester/cppunittester.cxx @@ -231,13 +231,17 @@ class CPPUNIT_API ProtectedFixtureFunctor { private: const std::string &testlib; +#ifndef DISABLE_DYNLOADING const std::string &args; +#endif std::vector<CppUnit::Protector *> &protectors; CppUnit::TestResult &result; public: ProtectedFixtureFunctor(const std::string& testlib_, const std::string &args_, std::vector<CppUnit::Protector*> &protectors_, CppUnit::TestResult &result_) : testlib(testlib_) +#ifndef DISABLE_DYNLOADING , args(args_) +#endif , protectors(protectors_) , result(result_) { diff --git a/solenv/gbuild/Conditions.mk b/solenv/gbuild/Conditions.mk index 0a7b88969557..4cb5688997e9 100644 --- a/solenv/gbuild/Conditions.mk +++ b/solenv/gbuild/Conditions.mk @@ -12,6 +12,10 @@ # just end in two (!) braces, otherwise you may need to use either the $(1) # or the $(2) multiple times. +define gb_CondCppunitMainLibOrExe +$(if $(or $(CROSS_COMPILING),$(DISABLE_DYNLOADING)),$(1),$(2)) +endef + define gb_CondExeLockfile $(if $(and $(filter-out ANDROID MACOSX iOS WNT,$(OS))),$(1),$(2)) endef diff --git a/solenv/gbuild/CppunitTest.mk b/solenv/gbuild/CppunitTest.mk index b16e3d0e5417..6ed65e40e608 100644 --- a/solenv/gbuild/CppunitTest.mk +++ b/solenv/gbuild/CppunitTest.mk @@ -21,6 +21,7 @@ gb_CppunitTest_UNITTESTFAILED ?= $(GBUILDDIR)/platform/unittest-failed-default.sh gb_CppunitTest_PYTHONDEPS ?= $(call gb_Library_get_target,pyuno_wrapper) $(if $(SYSTEM_PYTHON),,$(call gb_Package_get_target,python3)) +gb_CppunitTest_KNOWN := ifneq ($(strip $(CPPUNITTRACE)),) ifneq ($(filter gdb,$(CPPUNITTRACE)),) @@ -70,8 +71,13 @@ endif # defined by platform # gb_CppunitTest_get_filename +ifeq (,$(DISABLE_DYNLOADING)) gb_CppunitTest_RUNTIMEDEPS := $(call gb_Executable_get_runtime_dependencies,cppunittester) gb_CppunitTest_CPPTESTCOMMAND := $(call gb_Executable_get_target_for_build,cppunittester) +else +gb_CppunitTest_RUNTIMEDEPS := +gb_CppunitTest_CPPTESTCOMMAND := +endif # i18npool dlopens localedata_* libraries. gb_CppunitTest_RUNTIMEDEPS += \ @@ -204,6 +210,11 @@ $(call gb_CppunitTest_get_target,$(1)) : EXTRA_ENV_VARS := $(call gb_CppunitTest_get_target,$(1)) : NON_APPLICATION_FONT_USE := $$(eval $$(call gb_Module_register_target,$(call gb_CppunitTest_get_target,$(1)),$(call gb_CppunitTest_get_clean_target,$(1)))) $(call gb_Helper_make_userfriendly_targets,$(1),CppunitTest) +ifeq ($(DISABLE_DYNLOADING),TRUE) +$$(eval $$(call gb_CppunitTest_use_libraries,$(1),cppunitmain)) +$$(eval $$(call gb_CppunitTest_add_defs,$(1),-D__EMSCRIPTEN__)) +endif +$(if $(filter $(1),$(gb_CppunitTest_KNOWN)),,gb_CppunitTest_KNOWN += $(1)) endef diff --git a/solenv/gbuild/TargetLocations.mk b/solenv/gbuild/TargetLocations.mk index 4f3814f2a5d2..849caa8c3079 100644 --- a/solenv/gbuild/TargetLocations.mk +++ b/solenv/gbuild/TargetLocations.mk @@ -53,6 +53,7 @@ gb_CompilerTest_get_target = $(WORKDIR)/CompilerTest/$(1) gb_ComponentTarget_get_target = $(WORKDIR)/ComponentTarget/$(1).component gb_ComponentTarget_get_target_for_build = $(WORKDIR_FOR_BUILD)/ComponentTarget/$(1).component gb_Configuration_get_preparation_target = $(WORKDIR)/Configuration/$(1).prepared +gb_CppunitTest_get_linktargetfile = $(call gb_LinkTarget_get_target,$(call gb_CppunitTest_get_linktarget,$1)) gb_CppunitTest_get_target = $(WORKDIR)/CppunitTest/$(1).test gb_CustomPackage_get_target = $(WORKDIR)/CustomPackage/$(1).filelist gb_CustomTarget_get_repo_target = $(WORKDIR)/CustomTarget/$(2)_$(1).done diff --git a/solenv/gbuild/extensions/post_SpeedUpTargets.mk b/solenv/gbuild/extensions/post_SpeedUpTargets.mk index 44539cc5576d..6d2d401a6232 100644 --- a/solenv/gbuild/extensions/post_SpeedUpTargets.mk +++ b/solenv/gbuild/extensions/post_SpeedUpTargets.mk @@ -52,7 +52,6 @@ endif endif - ifneq (,$(filter build,$(gb_Module_SKIPTARGETS))) gb_Module_add_target = endif diff --git a/solenv/gbuild/gbuild.mk b/solenv/gbuild/gbuild.mk index 075c029b095d..c07ade7b4b18 100644 --- a/solenv/gbuild/gbuild.mk +++ b/solenv/gbuild/gbuild.mk @@ -292,6 +292,7 @@ gb_TEST_ENV_VARS += SAL_DISABLE_SYNCHRONOUS_PRINTER_DETECTION=1 ifeq (,$(SAL_USE_VCLPLUGIN)) gb_TEST_ENV_VARS += SAL_USE_VCLPLUGIN=svp endif +gb_TEST_ENV_VARS += STATIC_UNO_HOME=file://$$I/program # This is used to detect whether LibreOffice is being built (as opposed to building # 3rd-party code). Used for tag deprecation for API we want to diff --git a/solenv/gbuild/platform/unxgcc.mk b/solenv/gbuild/platform/unxgcc.mk index b3388eec436a..b066cdfcba16 100644 --- a/solenv/gbuild/platform/unxgcc.mk +++ b/solenv/gbuild/platform/unxgcc.mk @@ -316,12 +316,18 @@ endef gb_CppunitTest_CPPTESTPRECOMMAND := \ $(call gb_Helper_extend_ld_path,$(WORKDIR)/UnpackedTarball/cppunit/src/cppunit/.libs) -gb_CppunitTest_get_filename = libtest_$(1).so +ifeq (,$(DISABLE_DYNLOADING)) +gb_CppunitTest_get_filename = libtest_$(1)$(gb_Library_PLAINEXT) +else +gb_CppunitTest_get_filename = test_$(1)$(gb_Executable_EXT) +endif gb_CppunitTest_get_ilibfilename = $(gb_CppunitTest_get_filename) gb_CppunitTest_malloc_check := -ex 'set environment MALLOC_CHECK_=2; set environment MALLOC_PERTURB_=153' define gb_CppunitTest_CppunitTest_platform +ifeq (,$(DISABLE_DYNLOADING)) $(call gb_LinkTarget_get_target,$(2)) : RPATH := $(call gb_Library__get_rpath,$(call gb_LinkTarget__get_rpath_for_layer,NONE)) +endif endef diff --git a/solenv/gbuild/static.mk b/solenv/gbuild/static.mk index faa9a73db516..1b7f0214900a 100644 --- a/solenv/gbuild/static.mk +++ b/solenv/gbuild/static.mk @@ -198,6 +198,8 @@ $(foreach lib,$(gb_Library_KNOWNLIBS), \ $(eval $(call gb_LinkTarget__fill_all_deps,$(call gb_Library_get_linktarget,$(lib))))) $(foreach exec,$(gb_Executable_KNOWN), \ $(eval $(call gb_LinkTarget__expand_executable,$(call gb_Executable_get_linktarget,$(exec))))) +$(foreach cppunit,$(gb_CppunitTest_KNOWN), \ + $(eval $(call gb_LinkTarget__expand_executable,$(call gb_CppunitTest_get_linktarget,$(cppunit))))) $(foreach workdir_linktargetname,$(gb_LinkTarget__ALL_TOUCHED), \ $(eval $(call gb_LinkTarget__remove_touch,$(workdir_linktargetname)))) @@ -235,11 +237,14 @@ endef endef # gb_LinkTarget__expand_executable_template ifneq (,$(gb_DEBUG_STATIC)) +$(info $(call gb_LinkTarget__expand_executable_template,CppunitTest)) $(info $(call gb_LinkTarget__expand_executable_template,Executable)) endif +$(eval $(call gb_LinkTarget__expand_executable_template,CppunitTest)) $(eval $(call gb_LinkTarget__expand_executable_template,Executable)) $(foreach exec,$(gb_Executable_KNOWN),$(eval $(call gb_Executable__expand_deps,$(exec)))) +$(foreach cppunit,$(gb_CppunitTest_KNOWN),$(eval $(call gb_CppunitTest__expand_deps,$(cppunit)))) endif # gb_PARTIAL_BUILD endif # gb_FULLDEPS commit 4a19b9f8d5ca5ac3683fcd4f7f468f6c77ee65f0 Author: Jan-Marek Glogowski <glo...@fbihome.de> AuthorDate: Sat Jan 8 22:53:29 2022 +0100 Commit: Thorsten Behrens <thorsten.behr...@allotropia.de> CommitDate: Tue Nov 8 10:34:27 2022 +0100 gbuild: set unorc lookup dir via environment UNO tries hard to find the path of the executable to look at that place for its unorc / uno.ini. All these approaches don't work for static binaries, so just override the lookup with the environment variable STATIC_UNO_HOME. Change-Id: I0d80c91e474d9f869475ba752d708b77c99f8a56 diff --git a/Makefile.in b/Makefile.in index a326701b92eb..87008cea8ba9 100644 --- a/Makefile.in +++ b/Makefile.in @@ -7,6 +7,8 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. # +unexport STATIC_UNO_HOME + gb_Top_MODULE_CHECK_TARGETS := slowcheck unitcheck subsequentcheck perfcheck uicheck screenshot .PHONY : check-if-root bootstrap gbuild build build-non-l10n-only build-l10n-only check clean clean-build clean-host test-install distclean distro-pack-install docs download etags fetch get-submodules id install install-gdb-printers install-strip tags debugrun help showmodules translations packageinfo coverage internal.clean $(gb_Top_MODULE_CHECK_TARGETS) diff --git a/bin/run b/bin/run index 695905e09e6b..882f358403fd 100755 --- a/bin/run +++ b/bin/run @@ -107,6 +107,8 @@ else fi +test "${STATIC_UNO_HOME+set}" = set || export STATIC_UNO_HOME="file://${dir}/instdir/program" + # echo "setting URE_BOOTSTRAP to: ${URE_BOOTSTRAP}" # echo "setting search path to: ${SEARCH_PATH}" # echo "execing: ${exedir}/$1" diff --git a/cppuhelper/source/paths.cxx b/cppuhelper/source/paths.cxx index ece7650ded4c..0c0a3fbd5580 100644 --- a/cppuhelper/source/paths.cxx +++ b/cppuhelper/source/paths.cxx @@ -20,12 +20,14 @@ #include <config_folders.h> #include <sal/config.h> +#include <sal/log.hxx> #include <cassert> #include <com/sun/star/uno/DeploymentException.hpp> #include <osl/file.hxx> #include <osl/module.hxx> +#include <osl/thread.h> #include <rtl/ustring.hxx> #include <sal/types.h> #include <o3tl/string_view.hxx> @@ -65,7 +67,16 @@ OUString cppu::getUnoIniUri() { #elif defined(EMSCRIPTEN) OUString uri("file:///instdir/program"); #else - OUString uri(get_this_libpath()); + + OUString uri; +#ifdef DISABLE_DYNLOADING + static const char* uno_home = getenv("STATIC_UNO_HOME"); + if (uno_home) + uri = OStringToOUString(uno_home, osl_getThreadTextEncoding()); + else +#endif + uri = get_this_libpath(); + #ifdef MACOSX // We keep the URE dylibs directly in "Frameworks" (that is, LIBO_LIB_FOLDER) and unorc in // "Resources/ure/etc" (LIBO_URE_ETC_FOLDER). @@ -75,7 +86,9 @@ OUString cppu::getUnoIniUri() { } #endif #endif - return uri + "/" SAL_CONFIGFILE("uno"); + uri += "/" SAL_CONFIGFILE("uno"); + SAL_INFO("cppuhelper", "expected uno config: " << uri); + return uri; } bool cppu::nextDirectoryItem(osl::Directory & directory, OUString * url) { diff --git a/desktop/scripts/soffice.sh b/desktop/scripts/soffice.sh index 67cc0b89751f..1bfb60682648 100755 --- a/desktop/scripts/soffice.sh +++ b/desktop/scripts/soffice.sh @@ -176,6 +176,8 @@ else unset LC_ALL fi +test "${STATIC_UNO_HOME+set}" = set || export STATIC_UNO_HOME="file://${sd_prog}" + # run soffice.bin directly when you want to get the backtrace if [ -n "$GDBTRACECHECK" ] ; then exec $GDBTRACECHECK "$sd_prog/soffice.bin" "$@" commit f627ac6a579b56876ba6b2cc2325e6166a25d07d Author: Julien Nabet <serval2...@yahoo.fr> AuthorDate: Mon Nov 7 12:47:41 2022 +0100 Commit: Tomaž Vajngerl <qui...@gmail.com> CommitDate: Tue Nov 8 10:24:19 2022 +0100 tdf#151944: error colour export in bmp 4 bits bmp support has been dropped in March 2021 with: a6c6f35ccc78e74cfa76397d649c1b6fc4baad29 "drop 4bpp image formats on a path to simplifying our internal bitmap stuff, aiming to support a smaller set of image formats, but support them in an accelerated fashion. " 1 bit dithered bmp support last remnant has been dropped in April 2020 with: e3cc7b94b13d6cc4e044cfd688e0fcc9dca63987 "loplugin:unusedenumconstants BmpConversion" Change-Id: I958bea6baabb9ef21c5fa71bfc7ff96cba201245 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/142375 Tested-by: Jenkins Reviewed-by: Tomaž Vajngerl <qui...@gmail.com> diff --git a/include/svtools/strings.hrc b/include/svtools/strings.hrc index cbad8f4ed18e..d8bcaae7df6c 100644 --- a/include/svtools/strings.hrc +++ b/include/svtools/strings.hrc @@ -185,9 +185,6 @@ #define STR_SVT_ACC_RULER_VERT_NAME NC_("STR_SVT_ACC_RULER_VERT_NAME", "Vertical Ruler") #define STR_SVT_1BIT_THRESHOLD NC_("STR_SVT_1BIT_THRESHOLD", "1-bit threshold") -#define STR_SVT_1BIT_DITHERED NC_("STR_SVT_1BIT_DITHERED", "1-bit dithered") -#define STR_SVT_4BIT_GRAYSCALE NC_("STR_SVT_4BIT_GRAYSCALE", "4-bit grayscale") -#define STR_SVT_4BIT_COLOR_PALETTE NC_("STR_SVT_4BIT_COLOR_PALETTE", "4-bit color") #define STR_SVT_8BIT_GRAYSCALE NC_("STR_SVT_8BIT_GRAYSCALE", "8-bit grayscale") #define STR_SVT_8BIT_COLOR_PALETTE NC_("STR_SVT_8BIT_COLOR_PALETTE", "8-bit color") #define STR_SVT_24BIT_TRUE_COLOR NC_("STR_SVT_24BIT_TRUE_COLOR", "24-bit true color") diff --git a/svtools/source/filter/exportdialog.cxx b/svtools/source/filter/exportdialog.cxx index 142da3354f7a..d2718b533be7 100644 --- a/svtools/source/filter/exportdialog.cxx +++ b/svtools/source/filter/exportdialog.cxx @@ -525,12 +525,6 @@ sal_uInt32 ExportDialog::GetRawFileSize() const OUString aEntry(mxLbColorDepth->get_active_text()); if ( ms1BitThreshold == aEntry ) nBitsPerPixel = 1; - else if ( ms1BitDithered == aEntry ) - nBitsPerPixel = 1; - else if ( ms4BitGrayscale == aEntry ) - nBitsPerPixel = 4; - else if ( ms4BitColorPalette == aEntry ) - nBitsPerPixel = 8; else if ( ms8BitGrayscale == aEntry ) nBitsPerPixel = 8; else if ( ms8BitColorPalette == aEntry ) @@ -571,9 +565,6 @@ ExportDialog::ExportDialog(FltCallDialogParameter& rPara, , msEstimatedSizePix2(SvtResId(STR_SVT_ESTIMATED_SIZE_PIX_2)) , msEstimatedSizeVec(SvtResId(STR_SVT_ESTIMATED_SIZE_VEC)) , ms1BitThreshold(SvtResId(STR_SVT_1BIT_THRESHOLD)) - , ms1BitDithered(SvtResId(STR_SVT_1BIT_DITHERED)) - , ms4BitGrayscale(SvtResId(STR_SVT_4BIT_GRAYSCALE)) - , ms4BitColorPalette(SvtResId(STR_SVT_4BIT_COLOR_PALETTE)) , ms8BitGrayscale(SvtResId(STR_SVT_8BIT_GRAYSCALE)) , ms8BitColorPalette(SvtResId(STR_SVT_8BIT_COLOR_PALETTE)) , ms24BitColor(SvtResId(STR_SVT_24BIT_TRUE_COLOR)) @@ -820,9 +811,6 @@ void ExportDialog::createFilterOptions() else nColor--; mxLbColorDepth->append_text( ms1BitThreshold ); - mxLbColorDepth->append_text( ms1BitDithered ); - mxLbColorDepth->append_text( ms4BitGrayscale ); - mxLbColorDepth->append_text( ms4BitColorPalette ); mxLbColorDepth->append_text( ms8BitGrayscale ); mxLbColorDepth->append_text( ms8BitColorPalette ); ... etc. - the rest is truncated