Initial commit
This commit is contained in:
commit
17011ea9f7
10 changed files with 510 additions and 0 deletions
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
/target
|
||||||
|
**/*.rs.bk
|
||||||
|
Cargo.lock
|
||||||
76
.travis.yml
Normal file
76
.travis.yml
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
language: rust
|
||||||
|
|
||||||
|
# only cache cargo subcommand binaries and wayland libs .so
|
||||||
|
# the build artifacts take a lot of space and are slower to
|
||||||
|
# cache than to actually rebuild anyway...
|
||||||
|
# We need to cache the whole .cargo directory to keep the
|
||||||
|
# .crates.toml file.
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
- /home/travis/.cargo
|
||||||
|
# But don't cache the cargo registry
|
||||||
|
before_cache:
|
||||||
|
- rm -rf /home/travis/.cargo/registry
|
||||||
|
|
||||||
|
dist: trusty
|
||||||
|
|
||||||
|
sudo: required
|
||||||
|
|
||||||
|
rust:
|
||||||
|
- stable
|
||||||
|
- beta
|
||||||
|
- nightly
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
allow_failures:
|
||||||
|
- rust: nightly
|
||||||
|
include:
|
||||||
|
- rust: stable
|
||||||
|
env: BUILD_FMT=1
|
||||||
|
- rust: stable
|
||||||
|
env: BUILD_DOC=1
|
||||||
|
|
||||||
|
branches:
|
||||||
|
only:
|
||||||
|
- master
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
- cargo fetch
|
||||||
|
- |
|
||||||
|
if [ -n "$BUILD_FMT" ]; then
|
||||||
|
rustup component add rustfmt-preview
|
||||||
|
elif [ -n "$BUILD_DOC" ]; then
|
||||||
|
echo "Building doc, nothing to install..."
|
||||||
|
fi
|
||||||
|
os:
|
||||||
|
- linux
|
||||||
|
|
||||||
|
script:
|
||||||
|
- |
|
||||||
|
if [ -n "$BUILD_FMT" ]; then
|
||||||
|
cargo fmt -- --check
|
||||||
|
elif [ -n "$BUILD_DOC" ]; then
|
||||||
|
cargo doc --no-deps --all-features
|
||||||
|
fi
|
||||||
|
after_success:
|
||||||
|
- |
|
||||||
|
if [ -n "$BUILD_DOC" ]; then
|
||||||
|
cp ./doc_index.html ./target/doc/index.html
|
||||||
|
fi
|
||||||
|
deploy:
|
||||||
|
provider: pages
|
||||||
|
skip_cleanup: true
|
||||||
|
github_token: $GITHUB_TOKEN
|
||||||
|
local_dir: "target/doc"
|
||||||
|
on:
|
||||||
|
branch: master
|
||||||
|
rust: stable
|
||||||
|
condition: $BUILD_DOC = 1
|
||||||
|
|
||||||
|
notifications:
|
||||||
|
webhooks:
|
||||||
|
urls:
|
||||||
|
- "https://scalar.vector.im/api/neb/services/hooks/dHJhdmlzLWNpLyU0MGxldmFucyUzQXNhZmFyYWRlZy5uZXQvJTIxRkt4aGprSUNwakJWelZlQ2RGJTNBc2FmYXJhZGVnLm5ldA"
|
||||||
|
on_success: change
|
||||||
|
on_failure: always
|
||||||
|
on_start: never
|
||||||
0
CHANGELOG.md
Normal file
0
CHANGELOG.md
Normal file
9
CONTRIBUTING.md
Normal file
9
CONTRIBUTING.md
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
# Contributing
|
||||||
|
|
||||||
|
Smithay Wayland Clipboard is open to contributions from anyone.
|
||||||
|
|
||||||
|
## Smithay Project
|
||||||
|
|
||||||
|
There is a Matrix room dedicated to the Smithay project:
|
||||||
|
[#smithay:matrix.org](https://matrix.to/#/#smithay:matrix.org). If you don't want to use matrix, this room is
|
||||||
|
also bridged to gitter: https://gitter.im/smithay/Lobby.
|
||||||
11
Cargo.toml
Normal file
11
Cargo.toml
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
[package]
|
||||||
|
name = "smithay-wayland-clipboard"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Lucas Timmins <timmins.s.lucas@gmail.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
sctk = { package = "smithay-client-toolkit", version = "0.5" }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
andrew = "0.2"
|
||||||
19
LICENSE
Normal file
19
LICENSE
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
Copyright (c) 2018 Lucas Timmins & Victor Berger
|
||||||
|
|
||||||
|
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.
|
||||||
13
README.md
Normal file
13
README.md
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
[](https://crates.io/crates/smithay-wayland-clipboard)
|
||||||
|
[](https://travis-ci.org/Smithay/wayland-clipboard)
|
||||||
|
|
||||||
|
|
||||||
|
# Smithay Wayland Clipboard
|
||||||
|
|
||||||
|
This crate provides access to the wayland clipboard with only requirement being a WlDisplay object.
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
The documentation for the master branch is [available online](https://smithay.github.io/wayland-clipboard/).
|
||||||
|
|
||||||
|
The documentation for the releases can be found on [docs.rs](https://docs.rs/smithay-wayland-clipboard).
|
||||||
6
doc_index.html
Normal file
6
doc_index.html
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv=refresh content=0;url=smithay_wayland_clipboard/index.html />
|
||||||
|
</head>
|
||||||
|
</html>
|
||||||
214
examples/clipboard.rs
Normal file
214
examples/clipboard.rs
Normal file
|
|
@ -0,0 +1,214 @@
|
||||||
|
use std::io::{Read, Seek, SeekFrom, Write};
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
use sctk::keyboard::{map_keyboard_auto, Event as KbEvent, KeyState};
|
||||||
|
use sctk::utils::{DoubleMemPool, MemPool};
|
||||||
|
use sctk::window::{ConceptFrame, Event as WEvent, Window};
|
||||||
|
use sctk::Environment;
|
||||||
|
|
||||||
|
use sctk::reexports::client::protocol::{wl_shm, wl_surface};
|
||||||
|
use sctk::reexports::client::{Display, NewProxy};
|
||||||
|
|
||||||
|
use andrew::shapes::rectangle;
|
||||||
|
use andrew::text;
|
||||||
|
use andrew::text::fontconfig;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let (display, mut event_queue) =
|
||||||
|
Display::connect_to_env().expect("Failed to connect to the wayland server.");
|
||||||
|
let env = Environment::from_display(&*display, &mut event_queue).unwrap();
|
||||||
|
|
||||||
|
let mut clipboard = wayland_clipboard::WaylandClipboard::new_threaded(
|
||||||
|
display.get_display_ptr() as *mut std::ffi::c_void,
|
||||||
|
);
|
||||||
|
let cb_contents = Arc::new(Mutex::new(String::new()));
|
||||||
|
|
||||||
|
let seat = env
|
||||||
|
.manager
|
||||||
|
.instantiate_range(1, 6, NewProxy::implement_dummy)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let cb_contents_clone = cb_contents.clone();
|
||||||
|
map_keyboard_auto(&seat, move |event: KbEvent, _| {
|
||||||
|
if let KbEvent::Key {
|
||||||
|
state: KeyState::Pressed,
|
||||||
|
utf8: Some(text),
|
||||||
|
..
|
||||||
|
} = event
|
||||||
|
{
|
||||||
|
if text == " " {
|
||||||
|
*cb_contents_clone.lock().unwrap() = dbg!(clipboard.load());
|
||||||
|
} else if text == "s" {
|
||||||
|
clipboard
|
||||||
|
.store("This is an example text thats been copied to the wayland clipboard :)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut dimensions = (320u32, 240u32);
|
||||||
|
let surface = env
|
||||||
|
.compositor
|
||||||
|
.create_surface(NewProxy::implement_dummy)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let next_action = Arc::new(Mutex::new(None::<WEvent>));
|
||||||
|
|
||||||
|
let waction = next_action.clone();
|
||||||
|
let mut window = Window::<ConceptFrame>::init_from_env(&env, surface, dimensions, move |evt| {
|
||||||
|
let mut next_action = waction.lock().unwrap();
|
||||||
|
// Keep last event in priority order : Close > Configure > Refresh
|
||||||
|
let replace = match (&evt, &*next_action) {
|
||||||
|
(_, &None)
|
||||||
|
| (_, &Some(WEvent::Refresh))
|
||||||
|
| (&WEvent::Configure { .. }, &Some(WEvent::Configure { .. }))
|
||||||
|
| (&WEvent::Close, _) => true,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
if replace {
|
||||||
|
*next_action = Some(evt);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.expect("Failed to create a window !");
|
||||||
|
|
||||||
|
window.new_seat(&seat);
|
||||||
|
window.set_title("Clipboard".to_string());
|
||||||
|
|
||||||
|
let mut pools = DoubleMemPool::new(&env.shm, || {}).expect("Failed to create a memory pool !");
|
||||||
|
|
||||||
|
let mut font_data = Vec::new();
|
||||||
|
std::fs::File::open(
|
||||||
|
&fontconfig::FontConfig::new()
|
||||||
|
.unwrap()
|
||||||
|
.get_regular_family_fonts("sans")
|
||||||
|
.unwrap()[0],
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.read_to_end(&mut font_data)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
if !env.shell.needs_configure() {
|
||||||
|
// initial draw to bootstrap on wl_shell
|
||||||
|
if let Some(pool) = pools.pool() {
|
||||||
|
redraw(
|
||||||
|
pool,
|
||||||
|
window.surface(),
|
||||||
|
dimensions,
|
||||||
|
&font_data,
|
||||||
|
"".to_string(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
window.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
loop {
|
||||||
|
match next_action.lock().unwrap().take() {
|
||||||
|
Some(WEvent::Close) => break,
|
||||||
|
Some(WEvent::Refresh) => {
|
||||||
|
window.refresh();
|
||||||
|
window.surface().commit();
|
||||||
|
}
|
||||||
|
Some(WEvent::Configure { new_size, .. }) => {
|
||||||
|
if let Some((w, h)) = new_size {
|
||||||
|
window.resize(w, h);
|
||||||
|
dimensions = (w, h)
|
||||||
|
}
|
||||||
|
window.refresh();
|
||||||
|
if let Some(pool) = pools.pool() {
|
||||||
|
redraw(
|
||||||
|
pool,
|
||||||
|
window.surface(),
|
||||||
|
dimensions,
|
||||||
|
&font_data,
|
||||||
|
cb_contents.lock().unwrap().clone(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
event_queue.dispatch().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn redraw(
|
||||||
|
pool: &mut MemPool,
|
||||||
|
surface: &wl_surface::WlSurface,
|
||||||
|
dimensions: (u32, u32),
|
||||||
|
font_data: &[u8],
|
||||||
|
cb_contents: String,
|
||||||
|
) {
|
||||||
|
let (buf_x, buf_y) = (dimensions.0 as usize, dimensions.1 as usize);
|
||||||
|
|
||||||
|
pool.resize(4 * buf_x * buf_y)
|
||||||
|
.expect("Failed to resize the memory pool.");
|
||||||
|
|
||||||
|
let mut buf: Vec<u8> = vec![0; 4 * buf_x * buf_y];
|
||||||
|
let mut canvas =
|
||||||
|
andrew::Canvas::new(&mut buf, buf_x, buf_y, 4 * buf_x, andrew::Endian::native());
|
||||||
|
|
||||||
|
let bg = rectangle::Rectangle::new((0, 0), (buf_x, buf_y), None, Some([255, 170, 20, 45]));
|
||||||
|
canvas.draw(&bg);
|
||||||
|
|
||||||
|
let text_box = rectangle::Rectangle::new(
|
||||||
|
(buf_x / 30, buf_y / 35),
|
||||||
|
(buf_x - 2 * (buf_x / 30), (buf_x as f32 / 14.) as usize),
|
||||||
|
Some((3, [255, 255, 255, 255], rectangle::Sides::ALL, Some(4))),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
canvas.draw(&text_box);
|
||||||
|
|
||||||
|
let helper_text = text::Text::new(
|
||||||
|
(buf_x / 25, buf_y / 30),
|
||||||
|
[255, 255, 255, 255],
|
||||||
|
font_data,
|
||||||
|
buf_x as f32 / 40.,
|
||||||
|
2.0,
|
||||||
|
"Press space to draw clipboard contents",
|
||||||
|
);
|
||||||
|
canvas.draw(&helper_text);
|
||||||
|
|
||||||
|
let helper_text = text::Text::new(
|
||||||
|
(buf_x / 25, buf_y / 15),
|
||||||
|
[255, 255, 255, 255],
|
||||||
|
font_data,
|
||||||
|
buf_x as f32 / 40.,
|
||||||
|
2.0,
|
||||||
|
"Press 's' to store example text to clipboard",
|
||||||
|
);
|
||||||
|
canvas.draw(&helper_text);
|
||||||
|
|
||||||
|
for i in (0..cb_contents.len()).step_by(36) {
|
||||||
|
let content = if cb_contents.len() < i + 36 {
|
||||||
|
cb_contents[i..].to_string()
|
||||||
|
} else {
|
||||||
|
cb_contents[i..i + 36].to_string()
|
||||||
|
};
|
||||||
|
let text = text::Text::new(
|
||||||
|
(
|
||||||
|
buf_x / 10,
|
||||||
|
buf_y / 8 + (i as f32 * buf_y as f32 / 1000.) as usize,
|
||||||
|
),
|
||||||
|
[255, 255, 255, 255],
|
||||||
|
font_data,
|
||||||
|
buf_x as f32 / 40.,
|
||||||
|
2.0,
|
||||||
|
content,
|
||||||
|
);
|
||||||
|
canvas.draw(&text);
|
||||||
|
}
|
||||||
|
|
||||||
|
pool.seek(SeekFrom::Start(0)).unwrap();
|
||||||
|
pool.write_all(canvas.buffer).unwrap();
|
||||||
|
pool.flush().unwrap();
|
||||||
|
|
||||||
|
let new_buffer = pool.buffer(
|
||||||
|
0,
|
||||||
|
buf_x as i32,
|
||||||
|
buf_y as i32,
|
||||||
|
4 * buf_x as i32,
|
||||||
|
wl_shm::Format::Argb8888,
|
||||||
|
);
|
||||||
|
surface.attach(Some(&new_buffer), 0, 0);
|
||||||
|
surface.commit();
|
||||||
|
}
|
||||||
159
src/lib.rs
Normal file
159
src/lib.rs
Normal file
|
|
@ -0,0 +1,159 @@
|
||||||
|
//! Smithay Wayland Clipboard
|
||||||
|
//!
|
||||||
|
//! Provides access to the wayland clipboard with only requirement being a WlDisplay
|
||||||
|
//! object
|
||||||
|
//!
|
||||||
|
//! ```no_run
|
||||||
|
//! let (display, mut event_queue) =
|
||||||
|
//! Display::connect_to_env().expect("Failed to connect to the wayland server.");
|
||||||
|
//! let mut clipboard = wayland_clipboard::WaylandClipboard::new_threaded(
|
||||||
|
//! display.get_display_ptr() as *mut std::ffi::c_void,
|
||||||
|
//! );
|
||||||
|
//! clipboard.store("Test data");
|
||||||
|
//! println!(clipboard.load());
|
||||||
|
//! ```
|
||||||
|
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
|
use std::io::{Read, Write};
|
||||||
|
use std::os::raw::c_void;
|
||||||
|
use std::sync::mpsc;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
use std::thread::sleep;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use sctk::data_device::DataDevice;
|
||||||
|
use sctk::data_device::DataSource;
|
||||||
|
use sctk::data_device::DataSourceEvent;
|
||||||
|
use sctk::keyboard::{map_keyboard_auto, Event as KbEvent};
|
||||||
|
use sctk::reexports::client::Display;
|
||||||
|
use sctk::wayland_client::sys::client::wl_display;
|
||||||
|
use sctk::Environment;
|
||||||
|
|
||||||
|
enum WaylandRequest {
|
||||||
|
Store(String),
|
||||||
|
Load,
|
||||||
|
Kill,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Object representing the Wayland clipboard
|
||||||
|
pub struct WaylandClipboard {
|
||||||
|
request_send: mpsc::Sender<WaylandRequest>,
|
||||||
|
load_recv: mpsc::Receiver<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for WaylandClipboard {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.request_send.send(WaylandRequest::Kill).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WaylandClipboard {
|
||||||
|
/// Creates a new WaylandClipboard object
|
||||||
|
///
|
||||||
|
/// Spawns a new thread to dispatch messages to the wayland server every
|
||||||
|
/// 50ms to ensure the server can read stored data
|
||||||
|
pub fn new_threaded(wayland_display: *mut c_void) -> Self {
|
||||||
|
let (request_send, request_recv) = mpsc::channel::<WaylandRequest>();
|
||||||
|
let (load_send, load_recv) = mpsc::channel();
|
||||||
|
|
||||||
|
let wayland_display = unsafe { (wayland_display as *mut wl_display).as_mut().unwrap() };
|
||||||
|
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
let (display, mut event_queue) =
|
||||||
|
unsafe { Display::from_external_display(wayland_display as *mut wl_display) };
|
||||||
|
let env = Environment::from_display(&*display, &mut event_queue).unwrap();
|
||||||
|
|
||||||
|
let seat = env
|
||||||
|
.manager
|
||||||
|
.instantiate_range(1, 6, |seat| seat.implement_dummy())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let device = DataDevice::init_for_seat(&env.data_device_manager, &seat, |_| {});
|
||||||
|
|
||||||
|
let enter_serial = Arc::new(Mutex::new(None));
|
||||||
|
let my_enter_serial = enter_serial.clone();
|
||||||
|
let _keyboard = map_keyboard_auto(&seat, move |event, _| {
|
||||||
|
if let KbEvent::Enter { serial, .. } = event {
|
||||||
|
*(my_enter_serial.lock().unwrap()) = Some(serial);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if let Ok(request) = request_recv.try_recv() {
|
||||||
|
match request {
|
||||||
|
WaylandRequest::Load => {
|
||||||
|
// Load
|
||||||
|
let mut reader = None;
|
||||||
|
device.with_selection(|offer| {
|
||||||
|
if let Some(offer) = offer {
|
||||||
|
offer.with_mime_types(|types| {
|
||||||
|
for t in types {
|
||||||
|
if t == "text/plain;charset=utf-8" {
|
||||||
|
reader = Some(
|
||||||
|
offer
|
||||||
|
.receive("text/plain;charset=utf-8".into())
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
event_queue.sync_roundtrip().unwrap();
|
||||||
|
if let Some(mut reader) = reader {
|
||||||
|
let mut contents = String::new();
|
||||||
|
reader.read_to_string(&mut contents).unwrap();
|
||||||
|
load_send.send(contents).unwrap();
|
||||||
|
} else {
|
||||||
|
load_send.send("".to_string()).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WaylandRequest::Store(contents) => {
|
||||||
|
let data_source = DataSource::new(
|
||||||
|
&env.data_device_manager,
|
||||||
|
&["text/plain;charset=utf-8"],
|
||||||
|
move |source_event| {
|
||||||
|
if let DataSourceEvent::Send { mut pipe, .. } = source_event {
|
||||||
|
write!(pipe, "{}", contents).unwrap();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if let Some(enter_serial) = *enter_serial.lock().unwrap() {
|
||||||
|
device.set_selection(&Some(data_source), enter_serial);
|
||||||
|
}
|
||||||
|
event_queue.sync_roundtrip().unwrap();
|
||||||
|
}
|
||||||
|
WaylandRequest::Kill => break,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
event_queue.dispatch_pending().unwrap();
|
||||||
|
sleep(Duration::from_millis(50));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
WaylandClipboard {
|
||||||
|
request_send,
|
||||||
|
load_recv,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns text from the wayland clipboard
|
||||||
|
///
|
||||||
|
/// Only works when the window connected to the WlDisplay has
|
||||||
|
/// keyboard focus
|
||||||
|
pub fn load(&mut self) -> String {
|
||||||
|
self.request_send.send(WaylandRequest::Load).unwrap();
|
||||||
|
self.load_recv.recv().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stores text in the wayland clipboard
|
||||||
|
///
|
||||||
|
/// Only works when the window connected to the WlDisplay has
|
||||||
|
/// keyboard focus
|
||||||
|
pub fn store<S: Into<String>>(&mut self, text: S) {
|
||||||
|
self.request_send
|
||||||
|
.send(WaylandRequest::Store(text.into()))
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue