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 @@
#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::ui::dialogs;
using namespace ::com::sun::star::ui::dialogs::TemplateDescription;
......@@ -57,8 +50,6 @@ using namespace ::com::sun::star::ui::dialogs::CommonFilePickerElementIds;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::uno;
namespace bp = boost::process;
namespace bf = boost::filesystem;
// helper functions
......
......@@ -32,9 +32,6 @@
#include <rtl/ustrbuf.hxx>
#include <boost/process/child.hpp>
#include <boost/process/pipe.hpp>
#include "gtk3_kde5_filepicker_ipc.hxx"
#include <functional>
......
......@@ -26,6 +26,7 @@
#include <strings.hrc>
#include <future>
#include <system_error>
#include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
......@@ -41,38 +42,33 @@
#include <unx/gtk/gtkdata.hxx>
#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;
namespace bp = boost::process;
namespace bf = boost::filesystem;
// helper functions
namespace
{
bf::path applicationDirPath()
OUString applicationDirPath()
{
OUString applicationFilePath;
osl_getExecutableFile(&applicationFilePath.pData);
OUString applicationSystemPath;
osl_getSystemPathFromFileURL(applicationFilePath.pData, &applicationSystemPath.pData);
auto sysPath = applicationSystemPath.toUtf8();
auto ret = bf::path(sysPath.getStr(), sysPath.getStr() + sysPath.getLength());
const auto utf8Path = applicationSystemPath.toUtf8();
auto ret = boost::filesystem::path(utf8Path.getStr(), utf8Path.getStr() + utf8Path.getLength());
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();
paths.insert(paths.begin(), applicationDirPath());
auto ret = bp::search_path("lo_kde5filepicker", paths);
if (ret.empty())
throw bp::process_error(std::make_error_code(std::errc::no_such_file_or_directory),
const auto path = applicationDirPath();
const OUString app("lo_kde5filepicker");
OUString ret;
osl_searchFileURL(app.pData, path.pData, &ret.pData);
if (ret.isEmpty())
throw std::system_error(std::make_error_code(std::errc::no_such_file_or_directory),
"could not find lo_kde5filepicker executable");
return ret;
}
......@@ -113,16 +109,34 @@ OUString getResString(const char* pResId)
// Gtk3KDE5FilePicker
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()
{
if (!m_process)
return;
sendCommand(Commands::Quit);
if (m_process.running())
m_process.wait_for(std::chrono::milliseconds(100));
TimeValue timeValue(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()
......@@ -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: */
......@@ -23,32 +23,33 @@
#include <osl/conditn.hxx>
#include <osl/mutex.hxx>
#include <osl/process.h>
#include <rtl/ustrbuf.hxx>
#include <boost/process/child.hpp>
#include <boost/process/pipe.hpp>
#include "filepicker_ipc_commands.hxx"
#include <functional>
#include <future>
#include <mutex>
#include <thread>
#include <sstream>
OUString getResString(const char* pResId);
class Gtk3KDE5FilePickerIpc
{
protected:
boost::process::ipstream m_stdout;
boost::process::opstream m_stdin;
boost::process::child m_process;
oslProcess m_process;
oslFileHandle m_inputWrite;
oslFileHandle m_outputRead;
// simple multiplexing: every command gets it's own ID that can be used to
// read the corresponding response
uint64_t m_msgId = 1;
std::mutex m_mutex;
uint64_t m_incomingResponse = 0;
std::string m_responseBuffer;
std::stringstream m_responseStream;
public:
explicit Gtk3KDE5FilePickerIpc();
......@@ -56,14 +57,20 @@ public:
sal_Int16 execute();
void writeResponseLine(const std::string& line);
template <typename... Args> uint64_t sendCommand(Commands command, const Args&... args)
{
auto id = m_msgId;
++m_msgId;
sendIpcArgs(m_stdin, id, command, args...);
std::stringstream stream;
sendIpcArgs(stream, id, command, args...);
writeResponseLine(stream.str());
return id;
}
std::string readResponseLine();
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
......@@ -76,12 +83,16 @@ public:
// check if we need to read (and potentially wait) a response ID
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)
{
// the response we are waiting for came in
readIpcArgs(m_stdout, args...);
readIpcArgs(m_responseStream, args...);
m_incomingResponse = 0;
break;
}
......
......@@ -22,7 +22,7 @@
#include "gtk3_kde5_filepicker.hxx"
#include "gtk3_kde5_folderpicker.hxx"
#include <boost/process/exception.hpp>
#include <system_error>
uno::Reference<ui::dialogs::XFilePicker2>
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));
}
catch (const boost::process::process_error& error)
catch (const std::system_error& error)
{
OSL_FAIL(error.what());
return { nullptr };
......@@ -45,7 +45,7 @@ GtkInstance::createFolderPicker(const uno::Reference<uno::XComponentContext>& xM
{
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());
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