Kaydet (Commit) 068f2442 authored tarafından Milian Wolff's avatar Milian Wolff Kaydeden (comit) Thorsten Behrens

gtk3_kde5: port away from boost::process

While this uglifies the code, it removes a dependency on newer
boost 1.64+ which ships boost::process. This helps on systems
where LO is linked against system boost and an older version
of boost is used.

Additionally, and this is the main motivation, this makes it
easier to backport these changes to 5.2, where the bundled boost
is also only at 1.60.

To keep the required changes at a minimum, the osl_* API for
reading from/writing to the stdout/stdin of the helper process,
we buffer the responses on a line-by-line basis. Note that one
cannot simply reuse osl_readLine on the non-seekable oslFileHandle.
Instead, we have to roll our own simplistic readLine implementation...

Change-Id: I1197e38cb2416e926d8ba985accd6c10d78bcc52
Reviewed-on: https://gerrit.libreoffice.org/48490Tested-by: 's avatarJenkins <ci@libreoffice.org>
Reviewed-by: 's avatarThorsten Behrens <Thorsten.Behrens@CIB.de>
üst 390fad39
...@@ -42,13 +42,6 @@ ...@@ -42,13 +42,6 @@
#include <strings.hrc> #include <strings.hrc>
#include <future>
#include <boost/filesystem/path.hpp>
#include <boost/process/environment.hpp>
#include <boost/process/search_path.hpp>
#include <boost/process/io.hpp>
using namespace ::com::sun::star; using namespace ::com::sun::star;
using namespace ::com::sun::star::ui::dialogs; using namespace ::com::sun::star::ui::dialogs;
using namespace ::com::sun::star::ui::dialogs::TemplateDescription; using namespace ::com::sun::star::ui::dialogs::TemplateDescription;
...@@ -57,8 +50,6 @@ using namespace ::com::sun::star::ui::dialogs::CommonFilePickerElementIds; ...@@ -57,8 +50,6 @@ using namespace ::com::sun::star::ui::dialogs::CommonFilePickerElementIds;
using namespace ::com::sun::star::lang; using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::beans; using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::uno; using namespace ::com::sun::star::uno;
namespace bp = boost::process;
namespace bf = boost::filesystem;
// helper functions // helper functions
......
...@@ -32,9 +32,6 @@ ...@@ -32,9 +32,6 @@
#include <rtl/ustrbuf.hxx> #include <rtl/ustrbuf.hxx>
#include <boost/process/child.hpp>
#include <boost/process/pipe.hpp>
#include "gtk3_kde5_filepicker_ipc.hxx" #include "gtk3_kde5_filepicker_ipc.hxx"
#include <functional> #include <functional>
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <strings.hrc> #include <strings.hrc>
#include <future> #include <future>
#include <system_error>
#include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp> #include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
...@@ -41,38 +42,33 @@ ...@@ -41,38 +42,33 @@
#include <unx/gtk/gtkdata.hxx> #include <unx/gtk/gtkdata.hxx>
#include <boost/filesystem/path.hpp> #include <boost/filesystem/path.hpp>
#include <boost/process/environment.hpp>
#include <boost/process/search_path.hpp>
#include <boost/process/io.hpp>
using namespace ::com::sun::star::ui::dialogs; using namespace ::com::sun::star::ui::dialogs;
namespace bp = boost::process;
namespace bf = boost::filesystem;
// helper functions // helper functions
namespace namespace
{ {
bf::path applicationDirPath() OUString applicationDirPath()
{ {
OUString applicationFilePath; OUString applicationFilePath;
osl_getExecutableFile(&applicationFilePath.pData); osl_getExecutableFile(&applicationFilePath.pData);
OUString applicationSystemPath; OUString applicationSystemPath;
osl_getSystemPathFromFileURL(applicationFilePath.pData, &applicationSystemPath.pData); osl_getSystemPathFromFileURL(applicationFilePath.pData, &applicationSystemPath.pData);
auto sysPath = applicationSystemPath.toUtf8(); const auto utf8Path = applicationSystemPath.toUtf8();
auto ret = bf::path(sysPath.getStr(), sysPath.getStr() + sysPath.getLength()); auto ret = boost::filesystem::path(utf8Path.getStr(), utf8Path.getStr() + utf8Path.getLength());
ret.remove_filename(); ret.remove_filename();
return ret; return OUString::fromUtf8(OString(ret.c_str(), ret.size()));
} }
bf::path findPickerExecutable() OUString findPickerExecutable()
{ {
auto paths = boost::this_process::path(); const auto path = applicationDirPath();
paths.insert(paths.begin(), applicationDirPath()); const OUString app("lo_kde5filepicker");
auto ret = bp::search_path("lo_kde5filepicker", paths); OUString ret;
if (ret.empty()) osl_searchFileURL(app.pData, path.pData, &ret.pData);
throw bp::process_error(std::make_error_code(std::errc::no_such_file_or_directory), if (ret.isEmpty())
throw std::system_error(std::make_error_code(std::errc::no_such_file_or_directory),
"could not find lo_kde5filepicker executable"); "could not find lo_kde5filepicker executable");
return ret; return ret;
} }
...@@ -113,16 +109,34 @@ OUString getResString(const char* pResId) ...@@ -113,16 +109,34 @@ OUString getResString(const char* pResId)
// Gtk3KDE5FilePicker // Gtk3KDE5FilePicker
Gtk3KDE5FilePickerIpc::Gtk3KDE5FilePickerIpc() Gtk3KDE5FilePickerIpc::Gtk3KDE5FilePickerIpc()
// workaround: specify some non-empty argument, otherwise the Qt app will see argc == 0
: m_process(findPickerExecutable(), "dummy", bp::std_out > m_stdout, bp::std_in < m_stdin)
{ {
const auto exe = findPickerExecutable();
oslProcessError result;
oslSecurity pSecurity = osl_getCurrentSecurity();
result = osl_executeProcess_WithRedirectedIO(exe.pData, nullptr, 0, osl_Process_NORMAL,
pSecurity, nullptr, nullptr, 0, &m_process,
&m_inputWrite, &m_outputRead, nullptr);
osl_freeSecurityHandle(pSecurity);
if (result != osl_Process_E_None)
throw std::system_error(std::make_error_code(std::errc::no_such_process),
"could not start lo_kde5filepicker executable");
} }
Gtk3KDE5FilePickerIpc::~Gtk3KDE5FilePickerIpc() Gtk3KDE5FilePickerIpc::~Gtk3KDE5FilePickerIpc()
{ {
if (!m_process)
return;
sendCommand(Commands::Quit); sendCommand(Commands::Quit);
if (m_process.running()) TimeValue timeValue(std::chrono::milliseconds(100));
m_process.wait_for(std::chrono::milliseconds(100)); if (osl_joinProcessWithTimeout(m_process, &timeValue) != osl_Process_E_None)
osl_terminateProcess(m_process);
if (m_inputWrite)
osl_closeFile(m_inputWrite);
if (m_outputRead)
osl_closeFile(m_outputRead);
osl_freeProcessHandle(m_process);
} }
sal_Int16 Gtk3KDE5FilePickerIpc::execute() sal_Int16 Gtk3KDE5FilePickerIpc::execute()
...@@ -198,4 +212,48 @@ void Gtk3KDE5FilePickerIpc::await(const std::future<void>& future) ...@@ -198,4 +212,48 @@ void Gtk3KDE5FilePickerIpc::await(const std::future<void>& future)
} }
} }
void Gtk3KDE5FilePickerIpc::writeResponseLine(const std::string& line)
{
sal_uInt64 bytesWritten = 0;
osl_writeFile(m_inputWrite, line.c_str(), line.size(), &bytesWritten);
}
std::string Gtk3KDE5FilePickerIpc::readResponseLine()
{
if (!m_responseBuffer.empty()) // check whether we have a line in our buffer
{
auto it = m_responseBuffer.find('\n');
if (it != std::string::npos)
{
auto ret = m_responseBuffer.substr(0, it);
m_responseBuffer.erase(0, it);
return ret;
}
}
const sal_uInt64 BUF_SIZE = 1024;
char buffer[BUF_SIZE];
while (true)
{
sal_uInt64 bytesRead = 0;
auto err = osl_readFile(m_outputRead, buffer, BUF_SIZE, &bytesRead);
auto it = std::find(buffer, buffer + bytesRead, '\n');
if (it != buffer + bytesRead) // check whether the chunk we read contains an EOL
{
// if so, append that part to the buffer and return it
std::string ret = m_responseBuffer.append(buffer, it);
// but keep anything else we may have read in our buffer
++it;
m_responseBuffer.assign(it, buffer + bytesRead);
return ret;
}
// otherwise append everything we read to the buffer and try again
m_responseBuffer.append(buffer, bytesRead);
if (err != osl_File_E_None && err != osl_File_E_AGAIN)
break;
}
return {};
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
...@@ -23,32 +23,33 @@ ...@@ -23,32 +23,33 @@
#include <osl/conditn.hxx> #include <osl/conditn.hxx>
#include <osl/mutex.hxx> #include <osl/mutex.hxx>
#include <osl/process.h>
#include <rtl/ustrbuf.hxx> #include <rtl/ustrbuf.hxx>
#include <boost/process/child.hpp>
#include <boost/process/pipe.hpp>
#include "filepicker_ipc_commands.hxx" #include "filepicker_ipc_commands.hxx"
#include <functional> #include <functional>
#include <future> #include <future>
#include <mutex> #include <mutex>
#include <thread> #include <thread>
#include <sstream>
OUString getResString(const char* pResId); OUString getResString(const char* pResId);
class Gtk3KDE5FilePickerIpc class Gtk3KDE5FilePickerIpc
{ {
protected: protected:
boost::process::ipstream m_stdout; oslProcess m_process;
boost::process::opstream m_stdin; oslFileHandle m_inputWrite;
boost::process::child m_process; oslFileHandle m_outputRead;
// simple multiplexing: every command gets it's own ID that can be used to // simple multiplexing: every command gets it's own ID that can be used to
// read the corresponding response // read the corresponding response
uint64_t m_msgId = 1; uint64_t m_msgId = 1;
std::mutex m_mutex; std::mutex m_mutex;
uint64_t m_incomingResponse = 0; uint64_t m_incomingResponse = 0;
std::string m_responseBuffer;
std::stringstream m_responseStream;
public: public:
explicit Gtk3KDE5FilePickerIpc(); explicit Gtk3KDE5FilePickerIpc();
...@@ -56,14 +57,20 @@ public: ...@@ -56,14 +57,20 @@ public:
sal_Int16 execute(); sal_Int16 execute();
void writeResponseLine(const std::string& line);
template <typename... Args> uint64_t sendCommand(Commands command, const Args&... args) template <typename... Args> uint64_t sendCommand(Commands command, const Args&... args)
{ {
auto id = m_msgId; auto id = m_msgId;
++m_msgId; ++m_msgId;
sendIpcArgs(m_stdin, id, command, args...); std::stringstream stream;
sendIpcArgs(stream, id, command, args...);
writeResponseLine(stream.str());
return id; return id;
} }
std::string readResponseLine();
template <typename... Args> void readResponse(uint64_t id, Args&... args) template <typename... Args> void readResponse(uint64_t id, Args&... args)
{ {
// read synchronously from a background thread and run the eventloop until the value becomes available // read synchronously from a background thread and run the eventloop until the value becomes available
...@@ -76,12 +83,16 @@ public: ...@@ -76,12 +83,16 @@ public:
// check if we need to read (and potentially wait) a response ID // check if we need to read (and potentially wait) a response ID
if (m_incomingResponse == 0) if (m_incomingResponse == 0)
readIpcArgs(m_stdout, m_incomingResponse); {
m_responseStream.clear();
m_responseStream.str(readResponseLine());
readIpcArgs(m_responseStream, m_incomingResponse);
}
if (m_incomingResponse == id) if (m_incomingResponse == id)
{ {
// the response we are waiting for came in // the response we are waiting for came in
readIpcArgs(m_stdout, args...); readIpcArgs(m_responseStream, args...);
m_incomingResponse = 0; m_incomingResponse = 0;
break; break;
} }
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
#include "gtk3_kde5_filepicker.hxx" #include "gtk3_kde5_filepicker.hxx"
#include "gtk3_kde5_folderpicker.hxx" #include "gtk3_kde5_folderpicker.hxx"
#include <boost/process/exception.hpp> #include <system_error>
uno::Reference<ui::dialogs::XFilePicker2> uno::Reference<ui::dialogs::XFilePicker2>
GtkInstance::createFilePicker(const uno::Reference<uno::XComponentContext>& xMSF) GtkInstance::createFilePicker(const uno::Reference<uno::XComponentContext>& xMSF)
...@@ -31,7 +31,7 @@ GtkInstance::createFilePicker(const uno::Reference<uno::XComponentContext>& xMSF ...@@ -31,7 +31,7 @@ GtkInstance::createFilePicker(const uno::Reference<uno::XComponentContext>& xMSF
{ {
return uno::Reference<ui::dialogs::XFilePicker2>(new Gtk3KDE5FilePicker(xMSF)); return uno::Reference<ui::dialogs::XFilePicker2>(new Gtk3KDE5FilePicker(xMSF));
} }
catch (const boost::process::process_error& error) catch (const std::system_error& error)
{ {
OSL_FAIL(error.what()); OSL_FAIL(error.what());
return { nullptr }; return { nullptr };
...@@ -45,7 +45,7 @@ GtkInstance::createFolderPicker(const uno::Reference<uno::XComponentContext>& xM ...@@ -45,7 +45,7 @@ GtkInstance::createFolderPicker(const uno::Reference<uno::XComponentContext>& xM
{ {
return uno::Reference<ui::dialogs::XFolderPicker2>(new Gtk3KDE5FolderPicker(xMSF)); return uno::Reference<ui::dialogs::XFolderPicker2>(new Gtk3KDE5FolderPicker(xMSF));
} }
catch (const boost::process::process_error& error) catch (const std::system_error& error)
{ {
OSL_FAIL(error.what()); OSL_FAIL(error.what());
return { nullptr }; return { nullptr };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment