Use custom process library for notifications

Instead of using Boost.Process here. Last usage of Boost.Process is for
launching the child process.
This commit is contained in:
Robbert van der Helm
2022-04-11 14:55:22 +02:00
parent b80a30ba2a
commit a324042695
3 changed files with 48 additions and 22 deletions
+23 -1
View File
@@ -115,7 +115,7 @@ std::optional<int> Process::Handle::wait() const noexcept {
Process::Process(std::string command) : command_(command) {} Process::Process(std::string command) : command_(command) {}
Process::StringResult Process::spawn_get_stdout_line() { Process::StringResult Process::spawn_get_stdout_line() const {
/// We'll read the results from a pipe. The child writes to the second pipe, /// We'll read the results from a pipe. The child writes to the second pipe,
/// we'll read from the first one. /// we'll read from the first one.
int output_pipe[2]; int output_pipe[2];
@@ -167,6 +167,28 @@ Process::StringResult Process::spawn_get_stdout_line() {
} }
} }
Process::StatusResult Process::spawn_get_status() const {
const auto argv = build_argv();
const auto envp = env_ ? env_->make_environ() : environ;
pid_t child_pid = 0;
const auto result = posix_spawnp(&child_pid, command_.c_str(), nullptr,
nullptr, argv, envp);
if (result == 2) {
return Process::CommandNotFound{};
} else if (result != 0) {
return std::error_code(result, std::system_category());
}
int status = 0;
assert(waitpid(child_pid, &status, 0) > 0);
if (!WIFEXITED(status) || WEXITSTATUS(status) == 127) {
return Process::CommandNotFound{};
} else {
return WEXITSTATUS(status);
}
}
char* const* Process::build_argv() const { char* const* Process::build_argv() const {
argv_.clear(); argv_.clear();
+8 -1
View File
@@ -164,7 +164,14 @@ class Process {
* non-zero exit code. Uses `posix_spawn()`, leaves file descriptors in * non-zero exit code. Uses `posix_spawn()`, leaves file descriptors in
* tact. * tact.
*/ */
StringResult spawn_get_stdout_line(); StringResult spawn_get_stdout_line() const;
/**
* Spawn the process, leave STDOUT, STDIN and STDERR alone, and return an
* empty string if the program ran successfully. Uses `posix_spawn()`,
* leaves file descriptors in tact.
*/
StatusResult spawn_get_status() const;
private: private:
/** /**
+17 -20
View File
@@ -132,7 +132,7 @@ std::string PluginInfo::wine_version() const {
process.arg("--version"); process.arg("--version");
process.environment(create_host_env_2()); process.environment(create_host_env_2());
auto result = process.spawn_get_stdout_line(); const auto result = process.spawn_get_stdout_line();
return std::visit( return std::visit(
overload{ overload{
[](std::string version_string) -> std::string { [](std::string version_string) -> std::string {
@@ -462,13 +462,6 @@ Configuration load_config_for(const fs::path& yabridge_path) {
bool send_notification(const std::string& title, bool send_notification(const std::string& title,
const std::string body, const std::string body,
bool append_origin) { bool append_origin) {
// FIXME: Replace Boost.Filesystem
const boost::filesystem::path notify_send_path =
bp::search_path("notify-send");
if (notify_send_path.empty()) {
return false;
}
// I think there's a zero chance that we're going to call this function with // I think there's a zero chance that we're going to call this function with
// anything that even somewhat resembles HTML, but we should still do a // anything that even somewhat resembles HTML, but we should still do a
// basic XML escape anyways. // basic XML escape anyways.
@@ -493,16 +486,20 @@ bool send_notification(const std::string& title,
} }
} }
// TODO: Also use a custom process here, and wrap the above code in a Process process("notify-send");
// class process.arg("--urgency=normal");
try { process.arg("--app-name=yabridge");
return bp::system(notify_send_path, "--urgency=normal", process.arg(title);
"--expire-time=15000", "--app-name=yabridge", title, process.arg(formatted_body.str());
formatted_body.str(),
bp::posix::use_vfork) == EXIT_SUCCESS; // We will have printed the message to the terminal anyways, so if the user
} catch (const boost::process::process_error&) { // doesn't have libnotify installed we'll just fail silently
// We will have printed the message to the terminal anyways, so if the const auto result = process.spawn_get_status();
// user doesn't have libnotify installed we'll just fail silently return std::visit(
return false; overload{
} [](int status) -> bool { return status == EXIT_SUCCESS; },
[](const Process::CommandNotFound&) -> bool { return false; },
[](const std::error_code&) -> bool { return false; },
},
result);
} }