Created
October 7, 2024 12:15
-
-
Save JoshuaJakowlew/319f6da495c604b70a3460ca36e698d1 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace { | |
std::string clipboard_file_format() | |
{ | |
enum class DE { | |
Gnome, | |
Mate, | |
Fly, | |
Unknown | |
}; | |
static auto formats = std::unordered_map<DE, std::string>{ | |
{DE::Gnome, "x-special/gnome-copied-files"}, | |
{DE::Mate, "x-special/mate-copied-files"}, | |
{DE::Fly, "x-special/gnome-copied-files"}, | |
{DE::Unknown, "text/uri-list"} | |
}; | |
static std::string env_de = []() -> std::string { | |
auto env = std::getenv("XDG_CURRENT_DESKTOP"); | |
if (!env) { | |
spdlog::error("cannot get value of XDG_CURRENT_DESKTOP envvar, clipboard file format is unknown"); | |
return ""; | |
} | |
return env; | |
}(); | |
const DE current_de = []{ | |
if (env_de.find("GNOME") != std::string::npos) return DE::Gnome; | |
if (env_de.find("MATE" ) != std::string::npos) return DE::Mate; | |
if (env_de.find("fly" ) != std::string::npos) return DE::Fly; | |
return DE::Unknown; | |
}(); | |
spdlog::info( | |
"clipboard: current DE index is {} (from '{}'), file format is {}", | |
static_cast<int>(current_de), | |
env_de, | |
formats[current_de] | |
); | |
return formats[current_de]; | |
} | |
} | |
X11Clipboard::X11Clipboard() | |
{ | |
std::lock_guard lock{m_lock}; | |
m_file_format = clip::register_format(clipboard_file_format()); | |
clip::set_x11_wait_timeout(1000 * 60 * 10); | |
} | |
bool X11Clipboard::pushFile(fs::path const & file) | |
{ | |
std::lock_guard lock{m_lock}; | |
const auto uri = fileUri(file); | |
m_clip.clear(); | |
const auto res = m_clip.set_data(m_file_format, uri.data(), uri.size()); | |
spdlog::info("push {} to clipboard: {}", uri, res); | |
return res; | |
} | |
bool X11Clipboard::pushFiles(path_list const & file) | |
{ | |
std::lock_guard lock{m_lock}; | |
const auto uris = fileUris(file); | |
m_clip.clear(); | |
const auto res = m_clip.set_data(m_file_format, uris.data(), uris.size()); | |
spdlog::info("push {} to clipboard: {}", uris, res); | |
return res; | |
} | |
auto X11Clipboard::extractFiles() -> path_list | |
{ | |
std::lock_guard lock{m_lock}; | |
if (!m_clip.is_convertible(m_file_format)) { | |
spdlog::info("no such format in clipboard"); | |
return {}; | |
} | |
const auto size = m_clip.get_data_length(m_file_format); | |
if (size == 0) { | |
spdlog::info("no files in clipboard"); | |
return {}; | |
} | |
std::string buffer(size, '\0'); | |
if (!m_clip.get_data(m_file_format, buffer.data(), size)) { | |
spdlog::error("failed to get data from clipboard"); | |
return {}; | |
} | |
return parseFileUri(buffer); | |
} | |
std::string X11Clipboard::fileUri(fs::path const & file) | |
{ | |
return fmt::format("copy\nfile://{}\0", file.string()); | |
} | |
std::string X11Clipboard::fileUris(path_list const & files) | |
{ | |
auto uris = files | views::transform([](fs::path const & p){ return fmt::format("file://{}", p.string()); }); | |
return fmt::format("copy\n{}\0", fmt::join(uris, "\n")); | |
} | |
auto X11Clipboard::parseFileUri(std::string const & uri) -> path_list | |
{ | |
const std::string prefix = "file://"; | |
std::istringstream stream(uri); | |
path_list files; | |
std::string line; | |
std::getline(stream, line, '\n'); // skip the first entry ("copy") | |
while (std::getline(stream, line, '\n')) { | |
if (line.find(prefix) == 0) { // Remove the "file://" prefix | |
line = line.substr(prefix.length()); | |
} | |
spdlog::info("parsed file at {}", line); | |
files.emplace_back(std::move(line)); | |
} | |
return files; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class IClipboard | |
{ | |
public: | |
using path_list = std::vector<fs::path>; | |
virtual ~IClipboard() = default; | |
virtual bool pushFile(fs::path const & file) = 0; | |
virtual bool pushFiles(path_list const & file) = 0; | |
virtual path_list extractFiles() = 0; | |
}; | |
class X11Clipboard : public IClipboard | |
{ | |
public: | |
X11Clipboard(); | |
bool pushFile(fs::path const & file) override; | |
bool pushFiles(path_list const & file) override; | |
path_list extractFiles() override; | |
private: | |
clip::format m_file_format; | |
clip::lock m_clip; | |
std::mutex m_lock; | |
static std::string fileUri(fs::path const & file); | |
static std::string fileUris(path_list const & files); | |
static path_list parseFileUri(std::string const & uri); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment