feat(clipboard): implement clipboard on X11 systems
This commit is contained in:
parent
32b1de8ddc
commit
aa64f11950
|
@ -7,7 +7,7 @@ build="build.rs"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
# If the wayland feature is enabled, all X11 dependencies will be dropped
|
# If the wayland feature is enabled, all X11 dependencies will be dropped
|
||||||
# and only EVDEV-based methods will be supported.
|
# and wayland support will be enabled
|
||||||
wayland = []
|
wayland = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
|
@ -49,16 +49,13 @@ fn cc_config() {
|
||||||
.file("src/x11/native/clip/clip_x11.cpp")
|
.file("src/x11/native/clip/clip_x11.cpp")
|
||||||
.file("src/x11/native/clip/image.cpp")
|
.file("src/x11/native/clip/image.cpp")
|
||||||
.file("src/x11/native/native.cpp")
|
.file("src/x11/native/native.cpp")
|
||||||
.define("CLIP_X11_WITH_PNG", None)
|
|
||||||
.compile("espansoclipboardx11");
|
.compile("espansoclipboardx11");
|
||||||
|
|
||||||
println!("cargo:rustc-link-search=native=/usr/lib/x86_64-linux-gnu/");
|
println!("cargo:rustc-link-search=native=/usr/lib/x86_64-linux-gnu/");
|
||||||
println!("cargo:rustc-link-lib=static=espansoclipboardx11");
|
println!("cargo:rustc-link-lib=static=espansoclipboardx11");
|
||||||
|
|
||||||
// TODO: link xcb, libpng?
|
|
||||||
|
|
||||||
println!("cargo:rustc-link-lib=dylib=xcb");
|
println!("cargo:rustc-link-lib=dylib=xcb");
|
||||||
//println!("cargo:rustc-link-lib=dylib=X11");
|
} else {
|
||||||
|
// TODO: wayland
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,14 +30,12 @@ mod win32;
|
||||||
mod x11;
|
mod x11;
|
||||||
|
|
||||||
//#[cfg(target_os = "linux")]
|
//#[cfg(target_os = "linux")]
|
||||||
//mod evdev;
|
//#[cfg(feature = "wayland")]
|
||||||
|
//mod wayland;
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
mod mac;
|
mod mac;
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate lazy_static;
|
|
||||||
|
|
||||||
pub trait Clipboard {
|
pub trait Clipboard {
|
||||||
fn get_text(&self) -> Option<String>;
|
fn get_text(&self) -> Option<String>;
|
||||||
fn set_text(&self, text: &str) -> Result<()>;
|
fn set_text(&self, text: &str) -> Result<()>;
|
||||||
|
@ -69,7 +67,7 @@ pub fn get_injector(_options: InjectorCreationOptions) -> Result<Box<dyn Injecto
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
#[cfg(not(feature = "wayland"))]
|
#[cfg(not(feature = "wayland"))]
|
||||||
pub fn get_clipboard(options: ClipboardOptions) -> Result<Box<dyn Clipboard>> {
|
pub fn get_clipboard(_: ClipboardOptions) -> Result<Box<dyn Clipboard>> {
|
||||||
info!("using X11NativeClipboard");
|
info!("using X11NativeClipboard");
|
||||||
Ok(Box::new(x11::native::X11NativeClipboard::new()?))
|
Ok(Box::new(x11::native::X11NativeClipboard::new()?))
|
||||||
}
|
}
|
||||||
|
|
20
espanso-clipboard/src/x11/mod.rs
Normal file
20
espanso-clipboard/src/x11/mod.rs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* This file is part of espanso.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019-2021 Federico Terzi
|
||||||
|
*
|
||||||
|
* espanso is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* espanso is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
pub mod native;
|
4
espanso-clipboard/src/x11/native/README.md
Normal file
4
espanso-clipboard/src/x11/native/README.md
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
The X11NativeClipboard modules uses the wonderful [clip](https://github.com/dacap/clip) library
|
||||||
|
by David Capello to manipulate the clipboard.
|
||||||
|
|
||||||
|
At the time of writing, the library is MIT licensed.
|
20
espanso-clipboard/src/x11/native/clip/LICENSE.txt
Normal file
20
espanso-clipboard/src/x11/native/clip/LICENSE.txt
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
Copyright (c) 2015-2020 David Capello
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
174
espanso-clipboard/src/x11/native/clip/clip.cpp
Normal file
174
espanso-clipboard/src/x11/native/clip/clip.cpp
Normal file
|
@ -0,0 +1,174 @@
|
||||||
|
// Clip Library
|
||||||
|
// Copyright (c) 2015-2018 David Capello
|
||||||
|
//
|
||||||
|
// This file is released under the terms of the MIT license.
|
||||||
|
// Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
#include "clip.h"
|
||||||
|
#include "clip_lock_impl.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
namespace clip {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
void default_error_handler(ErrorCode code) {
|
||||||
|
static const char* err[] = {
|
||||||
|
"Cannot lock clipboard",
|
||||||
|
"Image format is not supported"
|
||||||
|
};
|
||||||
|
throw std::runtime_error(err[static_cast<int>(code)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
error_handler g_error_handler = default_error_handler;
|
||||||
|
|
||||||
|
lock::lock(void* native_window_handle)
|
||||||
|
: p(new impl(native_window_handle)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
lock::~lock() = default;
|
||||||
|
|
||||||
|
bool lock::locked() const {
|
||||||
|
return p->locked();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool lock::clear() {
|
||||||
|
return p->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool lock::is_convertible(format f) const {
|
||||||
|
return p->is_convertible(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool lock::set_data(format f, const char* buf, size_t length) {
|
||||||
|
return p->set_data(f, buf, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool lock::get_data(format f, char* buf, size_t len) const {
|
||||||
|
return p->get_data(f, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t lock::get_data_length(format f) const {
|
||||||
|
return p->get_data_length(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool lock::set_image(const image& img) {
|
||||||
|
return p->set_image(img);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool lock::get_image(image& img) const {
|
||||||
|
return p->get_image(img);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool lock::get_image_spec(image_spec& spec) const {
|
||||||
|
return p->get_image_spec(spec);
|
||||||
|
}
|
||||||
|
|
||||||
|
format empty_format() { return 0; }
|
||||||
|
format text_format() { return 1; }
|
||||||
|
format image_format() { return 2; }
|
||||||
|
|
||||||
|
bool has(format f) {
|
||||||
|
lock l;
|
||||||
|
if (l.locked())
|
||||||
|
return l.is_convertible(f);
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool clear() {
|
||||||
|
lock l;
|
||||||
|
if (l.locked())
|
||||||
|
return l.clear();
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool set_text(const std::string& value) {
|
||||||
|
lock l;
|
||||||
|
if (l.locked()) {
|
||||||
|
l.clear();
|
||||||
|
return l.set_data(text_format(), value.c_str(), value.size());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get_text(std::string& value) {
|
||||||
|
lock l;
|
||||||
|
if (!l.locked())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
format f = text_format();
|
||||||
|
if (!l.is_convertible(f))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
size_t len = l.get_data_length(f);
|
||||||
|
if (len > 0) {
|
||||||
|
std::vector<char> buf(len);
|
||||||
|
l.get_data(f, &buf[0], len);
|
||||||
|
value = &buf[0];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
value.clear();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool set_image(const image& img) {
|
||||||
|
lock l;
|
||||||
|
if (l.locked()) {
|
||||||
|
l.clear();
|
||||||
|
return l.set_image(img);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get_image(image& img) {
|
||||||
|
lock l;
|
||||||
|
if (!l.locked())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
format f = image_format();
|
||||||
|
if (!l.is_convertible(f))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return l.get_image(img);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get_image_spec(image_spec& spec) {
|
||||||
|
lock l;
|
||||||
|
if (!l.locked())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
format f = image_format();
|
||||||
|
if (!l.is_convertible(f))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return l.get_image_spec(spec);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_error_handler(error_handler handler) {
|
||||||
|
g_error_handler = handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_handler get_error_handler() {
|
||||||
|
return g_error_handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_XCB_XLIB_H
|
||||||
|
static int g_x11_timeout = 1000;
|
||||||
|
void set_x11_wait_timeout(int msecs) { g_x11_timeout = msecs; }
|
||||||
|
int get_x11_wait_timeout() { return g_x11_timeout; }
|
||||||
|
#else
|
||||||
|
void set_x11_wait_timeout(int) { }
|
||||||
|
int get_x11_wait_timeout() { return 1000; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace clip
|
178
espanso-clipboard/src/x11/native/clip/clip.h
Normal file
178
espanso-clipboard/src/x11/native/clip/clip.h
Normal file
|
@ -0,0 +1,178 @@
|
||||||
|
// Clip Library
|
||||||
|
// Copyright (c) 2015-2018 David Capello
|
||||||
|
//
|
||||||
|
// This file is released under the terms of the MIT license.
|
||||||
|
// Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
#ifndef CLIP_H_INCLUDED
|
||||||
|
#define CLIP_H_INCLUDED
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace clip {
|
||||||
|
|
||||||
|
// ======================================================================
|
||||||
|
// Low-level API to lock the clipboard/pasteboard and modify it
|
||||||
|
// ======================================================================
|
||||||
|
|
||||||
|
// Clipboard format identifier.
|
||||||
|
typedef size_t format;
|
||||||
|
|
||||||
|
class image;
|
||||||
|
struct image_spec;
|
||||||
|
|
||||||
|
class lock {
|
||||||
|
public:
|
||||||
|
// You can give your current HWND as the "native_window_handle."
|
||||||
|
// Windows clipboard functions use this handle to open/close
|
||||||
|
// (lock/unlock) the clipboard. From the MSDN documentation we
|
||||||
|
// need this handler so SetClipboardData() doesn't fail after a
|
||||||
|
// EmptyClipboard() call. Anyway it looks to work just fine if we
|
||||||
|
// call OpenClipboard() with a null HWND.
|
||||||
|
lock(void* native_window_handle = nullptr);
|
||||||
|
~lock();
|
||||||
|
|
||||||
|
// Returns true if we've locked the clipboard successfully in
|
||||||
|
// lock() constructor.
|
||||||
|
bool locked() const;
|
||||||
|
|
||||||
|
// Clears the clipboard content. If you don't clear the content,
|
||||||
|
// previous clipboard content (in unknown formats) could persist
|
||||||
|
// after the unlock.
|
||||||
|
bool clear();
|
||||||
|
|
||||||
|
// Returns true if the clipboard can be converted to the given
|
||||||
|
// format.
|
||||||
|
bool is_convertible(format f) const;
|
||||||
|
bool set_data(format f, const char* buf, size_t len);
|
||||||
|
bool get_data(format f, char* buf, size_t len) const;
|
||||||
|
size_t get_data_length(format f) const;
|
||||||
|
|
||||||
|
// For images
|
||||||
|
bool set_image(const image& image);
|
||||||
|
bool get_image(image& image) const;
|
||||||
|
bool get_image_spec(image_spec& spec) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
class impl;
|
||||||
|
std::unique_ptr<impl> p;
|
||||||
|
};
|
||||||
|
|
||||||
|
format register_format(const std::string& name);
|
||||||
|
|
||||||
|
// This format is when the clipboard has no content.
|
||||||
|
format empty_format();
|
||||||
|
|
||||||
|
// When the clipboard has UTF8 text.
|
||||||
|
format text_format();
|
||||||
|
|
||||||
|
// When the clipboard has an image.
|
||||||
|
format image_format();
|
||||||
|
|
||||||
|
// Returns true if the clipboard has content of the given type.
|
||||||
|
bool has(format f);
|
||||||
|
|
||||||
|
// Clears the clipboard content.
|
||||||
|
bool clear();
|
||||||
|
|
||||||
|
// ======================================================================
|
||||||
|
// Error handling
|
||||||
|
// ======================================================================
|
||||||
|
|
||||||
|
enum class ErrorCode {
|
||||||
|
CannotLock,
|
||||||
|
ImageNotSupported,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void (*error_handler)(ErrorCode code);
|
||||||
|
|
||||||
|
void set_error_handler(error_handler f);
|
||||||
|
error_handler get_error_handler();
|
||||||
|
|
||||||
|
// ======================================================================
|
||||||
|
// Text
|
||||||
|
// ======================================================================
|
||||||
|
|
||||||
|
// High-level API to put/get UTF8 text in/from the clipboard. These
|
||||||
|
// functions returns false in case of error.
|
||||||
|
bool set_text(const std::string& value);
|
||||||
|
bool get_text(std::string& value);
|
||||||
|
|
||||||
|
// ======================================================================
|
||||||
|
// Image
|
||||||
|
// ======================================================================
|
||||||
|
|
||||||
|
struct image_spec {
|
||||||
|
unsigned long width = 0;
|
||||||
|
unsigned long height = 0;
|
||||||
|
unsigned long bits_per_pixel = 0;
|
||||||
|
unsigned long bytes_per_row = 0;
|
||||||
|
unsigned long red_mask = 0;
|
||||||
|
unsigned long green_mask = 0;
|
||||||
|
unsigned long blue_mask = 0;
|
||||||
|
unsigned long alpha_mask = 0;
|
||||||
|
unsigned long red_shift = 0;
|
||||||
|
unsigned long green_shift = 0;
|
||||||
|
unsigned long blue_shift = 0;
|
||||||
|
unsigned long alpha_shift = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// The image data must contain straight RGB values
|
||||||
|
// (non-premultiplied by alpha). The image retrieved from the
|
||||||
|
// clipboard will be non-premultiplied too. Basically you will be
|
||||||
|
// always dealing with straight alpha images.
|
||||||
|
//
|
||||||
|
// Details: Windows expects premultiplied images on its clipboard
|
||||||
|
// content, so the library code make the proper conversion
|
||||||
|
// automatically. macOS handles straight alpha directly, so there is
|
||||||
|
// no conversion at all. Linux/X11 images are transferred in
|
||||||
|
// image/png format which are specified in straight alpha.
|
||||||
|
class image {
|
||||||
|
public:
|
||||||
|
image();
|
||||||
|
image(const image_spec& spec);
|
||||||
|
image(const void* data, const image_spec& spec);
|
||||||
|
image(const image& image);
|
||||||
|
image(image&& image);
|
||||||
|
~image();
|
||||||
|
|
||||||
|
image& operator=(const image& image);
|
||||||
|
image& operator=(image&& image);
|
||||||
|
|
||||||
|
char* data() const { return m_data; }
|
||||||
|
const image_spec& spec() const { return m_spec; }
|
||||||
|
|
||||||
|
bool is_valid() const { return m_data != nullptr; }
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void copy_image(const image& image);
|
||||||
|
void move_image(image&& image);
|
||||||
|
|
||||||
|
bool m_own_data;
|
||||||
|
char* m_data;
|
||||||
|
image_spec m_spec;
|
||||||
|
};
|
||||||
|
|
||||||
|
// High-level API to set/get an image in/from the clipboard. These
|
||||||
|
// functions returns false in case of error.
|
||||||
|
bool set_image(const image& img);
|
||||||
|
bool get_image(image& img);
|
||||||
|
bool get_image_spec(image_spec& spec);
|
||||||
|
|
||||||
|
// ======================================================================
|
||||||
|
// Platform-specific
|
||||||
|
// ======================================================================
|
||||||
|
|
||||||
|
// Only for X11: Sets the time (in milliseconds) that we must wait
|
||||||
|
// for the selection/clipboard owner to receive the content. This
|
||||||
|
// value is 1000 (one second) by default.
|
||||||
|
void set_x11_wait_timeout(int msecs);
|
||||||
|
int get_x11_wait_timeout();
|
||||||
|
|
||||||
|
} // namespace clip
|
||||||
|
|
||||||
|
#endif // CLIP_H_INCLUDED
|
76
espanso-clipboard/src/x11/native/clip/clip_common.h
Normal file
76
espanso-clipboard/src/x11/native/clip/clip_common.h
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
// Clip Library
|
||||||
|
// Copyright (C) 2020 David Capello
|
||||||
|
//
|
||||||
|
// This file is released under the terms of the MIT license.
|
||||||
|
// Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
#ifndef CLIP_COMMON_H_INCLUDED
|
||||||
|
#define CLIP_COMMON_H_INCLUDED
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace clip {
|
||||||
|
namespace details {
|
||||||
|
|
||||||
|
inline void divide_rgb_by_alpha(image& img,
|
||||||
|
bool hasAlphaGreaterThanZero = false) {
|
||||||
|
const image_spec& spec = img.spec();
|
||||||
|
|
||||||
|
bool hasValidPremultipliedAlpha = true;
|
||||||
|
|
||||||
|
for (unsigned long y=0; y<spec.height; ++y) {
|
||||||
|
const uint32_t* dst = (uint32_t*)(img.data()+y*spec.bytes_per_row);
|
||||||
|
for (unsigned long x=0; x<spec.width; ++x, ++dst) {
|
||||||
|
const uint32_t c = *dst;
|
||||||
|
const int r = ((c & spec.red_mask ) >> spec.red_shift );
|
||||||
|
const int g = ((c & spec.green_mask) >> spec.green_shift);
|
||||||
|
const int b = ((c & spec.blue_mask ) >> spec.blue_shift );
|
||||||
|
const int a = ((c & spec.alpha_mask) >> spec.alpha_shift);
|
||||||
|
|
||||||
|
if (a > 0)
|
||||||
|
hasAlphaGreaterThanZero = true;
|
||||||
|
if (r > a || g > a || b > a)
|
||||||
|
hasValidPremultipliedAlpha = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned long y=0; y<spec.height; ++y) {
|
||||||
|
uint32_t* dst = (uint32_t*)(img.data()+y*spec.bytes_per_row);
|
||||||
|
for (unsigned long x=0; x<spec.width; ++x, ++dst) {
|
||||||
|
const uint32_t c = *dst;
|
||||||
|
int r = ((c & spec.red_mask ) >> spec.red_shift );
|
||||||
|
int g = ((c & spec.green_mask) >> spec.green_shift);
|
||||||
|
int b = ((c & spec.blue_mask ) >> spec.blue_shift );
|
||||||
|
int a = ((c & spec.alpha_mask) >> spec.alpha_shift);
|
||||||
|
|
||||||
|
// If all alpha values = 0, we make the image opaque.
|
||||||
|
if (!hasAlphaGreaterThanZero) {
|
||||||
|
a = 255;
|
||||||
|
|
||||||
|
// We cannot change the image spec (e.g. spec.alpha_mask=0) to
|
||||||
|
// make the image opaque, because the "spec" of the image is
|
||||||
|
// read-only. The image spec used by the client is the one
|
||||||
|
// returned by get_image_spec().
|
||||||
|
}
|
||||||
|
// If there is alpha information and it's pre-multiplied alpha
|
||||||
|
else if (hasValidPremultipliedAlpha) {
|
||||||
|
if (a > 0) {
|
||||||
|
// Convert it to straight alpha
|
||||||
|
r = r * 255 / a;
|
||||||
|
g = g * 255 / a;
|
||||||
|
b = b * 255 / a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*dst =
|
||||||
|
(r << spec.red_shift ) |
|
||||||
|
(g << spec.green_shift) |
|
||||||
|
(b << spec.blue_shift ) |
|
||||||
|
(a << spec.alpha_shift);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace details
|
||||||
|
} // namespace clip
|
||||||
|
|
||||||
|
#endif // CLIP_H_INCLUDED
|
33
espanso-clipboard/src/x11/native/clip/clip_lock_impl.h
Normal file
33
espanso-clipboard/src/x11/native/clip/clip_lock_impl.h
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
// Clip Library
|
||||||
|
// Copyright (c) 2015-2018 David Capello
|
||||||
|
//
|
||||||
|
// This file is released under the terms of the MIT license.
|
||||||
|
// Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
#ifndef CLIP_LOCK_IMPL_H_INCLUDED
|
||||||
|
#define CLIP_LOCK_IMPL_H_INCLUDED
|
||||||
|
|
||||||
|
namespace clip {
|
||||||
|
|
||||||
|
class lock::impl {
|
||||||
|
public:
|
||||||
|
impl(void* native_window_handle);
|
||||||
|
~impl();
|
||||||
|
|
||||||
|
bool locked() const { return m_locked; }
|
||||||
|
bool clear();
|
||||||
|
bool is_convertible(format f) const;
|
||||||
|
bool set_data(format f, const char* buf, size_t len);
|
||||||
|
bool get_data(format f, char* buf, size_t len) const;
|
||||||
|
size_t get_data_length(format f) const;
|
||||||
|
bool set_image(const image& image);
|
||||||
|
bool get_image(image& image) const;
|
||||||
|
bool get_image_spec(image_spec& spec) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_locked;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace clip
|
||||||
|
|
||||||
|
#endif
|
1091
espanso-clipboard/src/x11/native/clip/clip_x11.cpp
Normal file
1091
espanso-clipboard/src/x11/native/clip/clip_x11.cpp
Normal file
File diff suppressed because it is too large
Load Diff
226
espanso-clipboard/src/x11/native/clip/clip_x11_png.h
Normal file
226
espanso-clipboard/src/x11/native/clip/clip_x11_png.h
Normal file
|
@ -0,0 +1,226 @@
|
||||||
|
// Clip Library
|
||||||
|
// Copyright (c) 2018 David Capello
|
||||||
|
//
|
||||||
|
// This file is released under the terms of the MIT license.
|
||||||
|
// Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
#include "clip.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "png.h"
|
||||||
|
|
||||||
|
namespace clip {
|
||||||
|
namespace x11 {
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
// Functions to convert clip::image into png data to store it in the
|
||||||
|
// clipboard.
|
||||||
|
|
||||||
|
void write_data_fn(png_structp png, png_bytep buf, png_size_t len) {
|
||||||
|
std::vector<uint8_t>& output = *(std::vector<uint8_t>*)png_get_io_ptr(png);
|
||||||
|
const size_t i = output.size();
|
||||||
|
output.resize(i+len);
|
||||||
|
std::copy(buf, buf+len, output.begin()+i);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool write_png(const image& image,
|
||||||
|
std::vector<uint8_t>& output) {
|
||||||
|
png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING,
|
||||||
|
nullptr, nullptr, nullptr);
|
||||||
|
if (!png)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
png_infop info = png_create_info_struct(png);
|
||||||
|
if (!info) {
|
||||||
|
png_destroy_write_struct(&png, nullptr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setjmp(png_jmpbuf(png))) {
|
||||||
|
png_destroy_write_struct(&png, &info);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
png_set_write_fn(png,
|
||||||
|
(png_voidp)&output,
|
||||||
|
write_data_fn,
|
||||||
|
nullptr); // No need for a flush function
|
||||||
|
|
||||||
|
const image_spec& spec = image.spec();
|
||||||
|
int color_type = (spec.alpha_mask ?
|
||||||
|
PNG_COLOR_TYPE_RGB_ALPHA:
|
||||||
|
PNG_COLOR_TYPE_RGB);
|
||||||
|
|
||||||
|
png_set_IHDR(png, info,
|
||||||
|
spec.width, spec.height, 8, color_type,
|
||||||
|
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
|
||||||
|
png_write_info(png, info);
|
||||||
|
png_set_packing(png);
|
||||||
|
|
||||||
|
png_bytep row =
|
||||||
|
(png_bytep)png_malloc(png, png_get_rowbytes(png, info));
|
||||||
|
|
||||||
|
for (png_uint_32 y=0; y<spec.height; ++y) {
|
||||||
|
const uint32_t* src =
|
||||||
|
(const uint32_t*)(((const uint8_t*)image.data())
|
||||||
|
+ y*spec.bytes_per_row);
|
||||||
|
uint8_t* dst = row;
|
||||||
|
unsigned int x, c;
|
||||||
|
|
||||||
|
for (x=0; x<spec.width; x++) {
|
||||||
|
c = *(src++);
|
||||||
|
*(dst++) = (c & spec.red_mask ) >> spec.red_shift;
|
||||||
|
*(dst++) = (c & spec.green_mask) >> spec.green_shift;
|
||||||
|
*(dst++) = (c & spec.blue_mask ) >> spec.blue_shift;
|
||||||
|
if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
|
||||||
|
*(dst++) = (c & spec.alpha_mask) >> spec.alpha_shift;
|
||||||
|
}
|
||||||
|
|
||||||
|
png_write_rows(png, &row, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
png_free(png, row);
|
||||||
|
png_write_end(png, info);
|
||||||
|
png_destroy_write_struct(&png, &info);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
// Functions to convert png data stored in the clipboard to a
|
||||||
|
// clip::image.
|
||||||
|
|
||||||
|
struct read_png_io {
|
||||||
|
const uint8_t* buf;
|
||||||
|
size_t len;
|
||||||
|
size_t pos;
|
||||||
|
};
|
||||||
|
|
||||||
|
void read_data_fn(png_structp png, png_bytep buf, png_size_t len) {
|
||||||
|
read_png_io& io = *(read_png_io*)png_get_io_ptr(png);
|
||||||
|
if (io.pos < io.len) {
|
||||||
|
size_t n = std::min(len, io.len-io.pos);
|
||||||
|
if (n > 0) {
|
||||||
|
std::copy(io.buf+io.pos,
|
||||||
|
io.buf+io.pos+n,
|
||||||
|
buf);
|
||||||
|
io.pos += n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool read_png(const uint8_t* buf,
|
||||||
|
const size_t len,
|
||||||
|
image* output_image,
|
||||||
|
image_spec* output_spec) {
|
||||||
|
png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING,
|
||||||
|
nullptr, nullptr, nullptr);
|
||||||
|
if (!png)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
png_infop info = png_create_info_struct(png);
|
||||||
|
if (!info) {
|
||||||
|
png_destroy_read_struct(&png, nullptr, nullptr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setjmp(png_jmpbuf(png))) {
|
||||||
|
png_destroy_read_struct(&png, &info, nullptr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
read_png_io io = { buf, len, 0 };
|
||||||
|
png_set_read_fn(png, (png_voidp)&io, read_data_fn);
|
||||||
|
|
||||||
|
png_read_info(png, info);
|
||||||
|
|
||||||
|
png_uint_32 width, height;
|
||||||
|
int bit_depth, color_type, interlace_type;
|
||||||
|
png_get_IHDR(png, info, &width, &height,
|
||||||
|
&bit_depth, &color_type,
|
||||||
|
&interlace_type,
|
||||||
|
nullptr, nullptr);
|
||||||
|
|
||||||
|
image_spec spec;
|
||||||
|
spec.width = width;
|
||||||
|
spec.height = height;
|
||||||
|
spec.bits_per_pixel = 32;
|
||||||
|
spec.bytes_per_row = png_get_rowbytes(png, info);
|
||||||
|
|
||||||
|
spec.red_mask = 0x000000ff;
|
||||||
|
spec.green_mask = 0x0000ff00;
|
||||||
|
spec.blue_mask = 0x00ff0000;
|
||||||
|
spec.red_shift = 0;
|
||||||
|
spec.green_shift = 8;
|
||||||
|
spec.blue_shift = 16;
|
||||||
|
|
||||||
|
// TODO indexed images with alpha
|
||||||
|
if (color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
|
||||||
|
color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
|
||||||
|
spec.alpha_mask = 0xff000000;
|
||||||
|
spec.alpha_shift = 24;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
spec.alpha_mask = 0;
|
||||||
|
spec.alpha_shift = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (output_spec)
|
||||||
|
*output_spec = spec;
|
||||||
|
|
||||||
|
if (output_image &&
|
||||||
|
width > 0 &&
|
||||||
|
height > 0) {
|
||||||
|
image img(spec);
|
||||||
|
|
||||||
|
// We want RGB 24-bit or RGBA 32-bit as a result
|
||||||
|
png_set_strip_16(png); // Down to 8-bit (TODO we might support 16-bit values)
|
||||||
|
png_set_packing(png); // Use one byte if color depth < 8-bit
|
||||||
|
png_set_expand_gray_1_2_4_to_8(png);
|
||||||
|
png_set_palette_to_rgb(png);
|
||||||
|
png_set_gray_to_rgb(png);
|
||||||
|
png_set_tRNS_to_alpha(png);
|
||||||
|
|
||||||
|
int number_passes = png_set_interlace_handling(png);
|
||||||
|
png_read_update_info(png, info);
|
||||||
|
|
||||||
|
png_bytepp rows = (png_bytepp)png_malloc(png, sizeof(png_bytep)*height);
|
||||||
|
png_uint_32 y;
|
||||||
|
for (y=0; y<height; ++y)
|
||||||
|
rows[y] = (png_bytep)png_malloc(png, spec.bytes_per_row);
|
||||||
|
|
||||||
|
for (int pass=0; pass<number_passes; ++pass)
|
||||||
|
for (y=0; y<height; ++y)
|
||||||
|
png_read_rows(png, rows+y, nullptr, 1);
|
||||||
|
|
||||||
|
for (y=0; y<height; ++y) {
|
||||||
|
const uint8_t* src = rows[y];
|
||||||
|
uint32_t* dst = (uint32_t*)(img.data() + y*spec.bytes_per_row);
|
||||||
|
unsigned int x, r, g, b, a = 255;
|
||||||
|
|
||||||
|
for (x=0; x<width; x++) {
|
||||||
|
r = *(src++);
|
||||||
|
g = *(src++);
|
||||||
|
b = *(src++);
|
||||||
|
if (spec.alpha_mask)
|
||||||
|
a = *(src++);
|
||||||
|
*(dst++) =
|
||||||
|
(r << spec.red_shift) |
|
||||||
|
(g << spec.green_shift) |
|
||||||
|
(b << spec.blue_shift) |
|
||||||
|
(a << spec.alpha_shift);
|
||||||
|
}
|
||||||
|
png_free(png, rows[y]);
|
||||||
|
}
|
||||||
|
png_free(png, rows);
|
||||||
|
|
||||||
|
std::swap(*output_image, img);
|
||||||
|
}
|
||||||
|
|
||||||
|
png_destroy_read_struct(&png, &info, nullptr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace x11
|
||||||
|
} // namespace clip
|
83
espanso-clipboard/src/x11/native/clip/image.cpp
Normal file
83
espanso-clipboard/src/x11/native/clip/image.cpp
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
// Clip Library
|
||||||
|
// Copyright (c) 2015-2018 David Capello
|
||||||
|
//
|
||||||
|
// This file is released under the terms of the MIT license.
|
||||||
|
// Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
#include "clip.h"
|
||||||
|
|
||||||
|
namespace clip {
|
||||||
|
|
||||||
|
image::image()
|
||||||
|
: m_own_data(false),
|
||||||
|
m_data(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
image::image(const image_spec& spec)
|
||||||
|
: m_own_data(true),
|
||||||
|
m_data(new char[spec.bytes_per_row*spec.height]),
|
||||||
|
m_spec(spec) {
|
||||||
|
}
|
||||||
|
|
||||||
|
image::image(const void* data, const image_spec& spec)
|
||||||
|
: m_own_data(false),
|
||||||
|
m_data((char*)data),
|
||||||
|
m_spec(spec) {
|
||||||
|
}
|
||||||
|
|
||||||
|
image::image(const image& image)
|
||||||
|
: m_own_data(false),
|
||||||
|
m_data(nullptr),
|
||||||
|
m_spec(image.m_spec) {
|
||||||
|
copy_image(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
image::image(image&& image)
|
||||||
|
: m_own_data(false),
|
||||||
|
m_data(nullptr) {
|
||||||
|
move_image(std::move(image));
|
||||||
|
}
|
||||||
|
|
||||||
|
image::~image() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
image& image::operator=(const image& image) {
|
||||||
|
copy_image(image);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
image& image::operator=(image&& image) {
|
||||||
|
move_image(std::move(image));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void image::reset() {
|
||||||
|
if (m_own_data) {
|
||||||
|
delete[] m_data;
|
||||||
|
m_own_data = false;
|
||||||
|
m_data = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void image::copy_image(const image& image) {
|
||||||
|
reset();
|
||||||
|
|
||||||
|
m_spec = image.spec();
|
||||||
|
std::size_t n = m_spec.bytes_per_row*m_spec.height;
|
||||||
|
|
||||||
|
m_own_data = true;
|
||||||
|
m_data = new char[n];
|
||||||
|
std::copy(image.data(),
|
||||||
|
image.data()+n,
|
||||||
|
m_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void image::move_image(image&& image) {
|
||||||
|
std::swap(m_own_data, image.m_own_data);
|
||||||
|
std::swap(m_data, image.m_data);
|
||||||
|
std::swap(m_spec, image.m_spec);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace clip
|
28
espanso-clipboard/src/x11/native/ffi.rs
Normal file
28
espanso-clipboard/src/x11/native/ffi.rs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* This file is part of espanso.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019-2021 Federico Terzi
|
||||||
|
*
|
||||||
|
* espanso is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* espanso is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use std::os::raw::c_char;
|
||||||
|
|
||||||
|
#[link(name = "espansoclipboardx11", kind = "static")]
|
||||||
|
extern "C" {
|
||||||
|
pub fn clipboard_x11_get_text(buffer: *mut c_char, buffer_size: i32) -> i32;
|
||||||
|
pub fn clipboard_x11_set_text(text: *const c_char) -> i32;
|
||||||
|
pub fn clipboard_x11_set_html(html: *const c_char, fallback_text: *const c_char) -> i32;
|
||||||
|
pub fn clipboard_x11_set_image(buffer: *const u8, buffer_size: i32) -> i32;
|
||||||
|
}
|
106
espanso-clipboard/src/x11/native/mod.rs
Normal file
106
espanso-clipboard/src/x11/native/mod.rs
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
/*
|
||||||
|
* This file is part of espanso.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019-2021 Federico Terzi
|
||||||
|
*
|
||||||
|
* espanso is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* espanso is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use std::{ffi::{CStr, CString}, io::Read, path::PathBuf};
|
||||||
|
|
||||||
|
use crate::Clipboard;
|
||||||
|
use anyhow::Result;
|
||||||
|
use libc::c_char;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
mod ffi;
|
||||||
|
|
||||||
|
pub struct X11NativeClipboard {}
|
||||||
|
|
||||||
|
impl X11NativeClipboard {
|
||||||
|
pub fn new() -> Result<Self> {
|
||||||
|
Ok(Self {})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clipboard for X11NativeClipboard {
|
||||||
|
fn get_text(&self) -> Option<String> {
|
||||||
|
let mut buffer: [c_char; 2048] = [0; 2048];
|
||||||
|
let native_result =
|
||||||
|
unsafe { ffi::clipboard_x11_get_text(buffer.as_mut_ptr(), (buffer.len() - 1) as i32) };
|
||||||
|
if native_result > 0 {
|
||||||
|
let string = unsafe { CStr::from_ptr(buffer.as_ptr()) };
|
||||||
|
Some(string.to_string_lossy().to_string())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_text(&self, text: &str) -> anyhow::Result<()> {
|
||||||
|
let string = CString::new(text)?;
|
||||||
|
let native_result = unsafe { ffi::clipboard_x11_set_text(string.as_ptr()) };
|
||||||
|
if native_result > 0 {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(X11NativeClipboardError::SetOperationFailed().into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_image(&self, image_path: &std::path::Path) -> anyhow::Result<()> {
|
||||||
|
if !image_path.exists() || !image_path.is_file() {
|
||||||
|
return Err(X11NativeClipboardError::ImageNotFound(image_path.to_path_buf()).into());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load the image data
|
||||||
|
let mut file = std::fs::File::open(image_path)?;
|
||||||
|
let mut data = Vec::new();
|
||||||
|
file.read_to_end(&mut data)?;
|
||||||
|
|
||||||
|
let native_result = unsafe {
|
||||||
|
ffi::clipboard_x11_set_image(data.as_ptr(), data.len() as i32)
|
||||||
|
};
|
||||||
|
|
||||||
|
if native_result > 0 {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(X11NativeClipboardError::SetOperationFailed().into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_html(&self, html: &str, fallback_text: Option<&str>) -> anyhow::Result<()> {
|
||||||
|
let html_string = CString::new(html)?;
|
||||||
|
let fallback_string = CString::new(fallback_text.unwrap_or_default())?;
|
||||||
|
let fallback_ptr = if fallback_text.is_some() {
|
||||||
|
fallback_string.as_ptr()
|
||||||
|
} else {
|
||||||
|
std::ptr::null()
|
||||||
|
};
|
||||||
|
|
||||||
|
let native_result = unsafe { ffi::clipboard_x11_set_html(html_string.as_ptr(), fallback_ptr) };
|
||||||
|
if native_result > 0 {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(X11NativeClipboardError::SetOperationFailed().into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum X11NativeClipboardError {
|
||||||
|
#[error("clipboard set operation failed")]
|
||||||
|
SetOperationFailed(),
|
||||||
|
|
||||||
|
#[error("image not found: `{0}`")]
|
||||||
|
ImageNotFound(PathBuf),
|
||||||
|
}
|
76
espanso-clipboard/src/x11/native/native.cpp
Normal file
76
espanso-clipboard/src/x11/native/native.cpp
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
/*
|
||||||
|
* This file is part of espanso.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019-2021 Federico Terzi
|
||||||
|
*
|
||||||
|
* espanso is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* espanso is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "native.h"
|
||||||
|
#include "clip/clip.h"
|
||||||
|
#include "string.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
clip::format html_format = clip::register_format("text/html");
|
||||||
|
clip::format png_format = clip::register_format("image/png");
|
||||||
|
|
||||||
|
int32_t clipboard_x11_get_text(char * buffer, int32_t buffer_size) {
|
||||||
|
std::string value;
|
||||||
|
if (!clip::get_text(value)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value.length() == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy(buffer, value.c_str(), buffer_size - 1);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t clipboard_x11_set_text(char * text) {
|
||||||
|
if (!clip::set_text(text)) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t clipboard_x11_set_html(char * html, char * fallback_text) {
|
||||||
|
clip::lock l;
|
||||||
|
if (!l.clear()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!l.set_data(html_format, html, strlen(html))) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (fallback_text) {
|
||||||
|
// Best effort to set the fallback
|
||||||
|
l.set_data(clip::text_format(), fallback_text, strlen(fallback_text));
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t clipboard_x11_set_image(char * buffer, int32_t size) {
|
||||||
|
clip::lock l;
|
||||||
|
if (!l.clear()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!l.set_data(png_format, buffer, size)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
31
espanso-clipboard/src/x11/native/native.h
Normal file
31
espanso-clipboard/src/x11/native/native.h
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* This file is part of espanso.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019-2021 Federico Terzi
|
||||||
|
*
|
||||||
|
* espanso is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* espanso is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ESPANSO_X11_CLIPBOARD_H
|
||||||
|
#define ESPANSO_X11_CLIPBOARD_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
extern "C" int32_t clipboard_x11_get_text(char * buffer, int32_t buffer_size);
|
||||||
|
|
||||||
|
extern "C" int32_t clipboard_x11_set_text(char * text);
|
||||||
|
extern "C" int32_t clipboard_x11_set_html(char * html, char * fallback_text);
|
||||||
|
extern "C" int32_t clipboard_x11_set_image(char * buffer, int32_t buffer_size);
|
||||||
|
|
||||||
|
#endif //ESPANSO_X11_CLIPBOARD_H
|
|
@ -11,7 +11,7 @@ edition = "2018"
|
||||||
[features]
|
[features]
|
||||||
# If the wayland feature is enabled, all X11 dependencies will be dropped
|
# If the wayland feature is enabled, all X11 dependencies will be dropped
|
||||||
# and only EVDEV-based methods will be supported.
|
# and only EVDEV-based methods will be supported.
|
||||||
wayland = ["espanso-detect/wayland", "espanso-inject/wayland"]
|
wayland = ["espanso-detect/wayland", "espanso-inject/wayland", "espanso-clipboard/wayland"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
espanso-detect = { path = "../espanso-detect" }
|
espanso-detect = { path = "../espanso-detect" }
|
||||||
|
|
Loading…
Reference in New Issue
Block a user