aboutsummaryrefslogtreecommitdiff
path: root/copypasta/src
diff options
context:
space:
mode:
Diffstat (limited to 'copypasta/src')
-rw-r--r--copypasta/src/common.rs24
-rw-r--r--copypasta/src/lib.rs69
-rw-r--r--copypasta/src/nop_clipboard.rs42
-rw-r--r--copypasta/src/osx_clipboard.rs84
-rw-r--r--copypasta/src/wayland_clipboard.rs70
-rw-r--r--copypasta/src/windows_clipboard.rs36
-rw-r--r--copypasta/src/x11_clipboard.rs72
7 files changed, 397 insertions, 0 deletions
diff --git a/copypasta/src/common.rs b/copypasta/src/common.rs
new file mode 100644
index 00000000..79cf1fb7
--- /dev/null
+++ b/copypasta/src/common.rs
@@ -0,0 +1,24 @@
+// Copyright 2016 Avraham Weinstock
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use std::error::Error;
+
+// TODO: come up with some platform-agnostic API for richer types
+/// Trait for clipboard access
+pub trait ClipboardProvider: Send {
+ /// Method to get the clipboard contents as a String
+ fn get_contents(&mut self) -> Result<String, Box<dyn Error>>;
+ /// Method to set the clipboard contents as a String
+ fn set_contents(&mut self, String) -> Result<(), Box<dyn Error>>;
+}
diff --git a/copypasta/src/lib.rs b/copypasta/src/lib.rs
new file mode 100644
index 00000000..64b44219
--- /dev/null
+++ b/copypasta/src/lib.rs
@@ -0,0 +1,69 @@
+// Copyright 2016 Avraham Weinstock
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#![crate_name = "copypasta"]
+#![crate_type = "lib"]
+#![crate_type = "dylib"]
+#![crate_type = "rlib"]
+
+#[cfg(all(unix, not(any(target_os = "macos", target_os = "android", target_os = "emscripten"))))]
+extern crate smithay_clipboard;
+#[cfg(all(unix, not(any(target_os = "macos", target_os = "android", target_os = "emscripten"))))]
+extern crate wayland_client;
+#[cfg(all(unix, not(any(target_os = "macos", target_os = "android", target_os = "emscripten"))))]
+extern crate x11_clipboard as x11_clipboard_crate;
+
+#[cfg(windows)]
+extern crate clipboard_win;
+
+#[cfg(target_os = "macos")]
+#[macro_use]
+extern crate objc;
+#[cfg(target_os = "macos")]
+extern crate objc_foundation;
+#[cfg(target_os = "macos")]
+extern crate objc_id;
+
+mod common;
+pub use common::ClipboardProvider;
+
+#[cfg(all(unix, not(any(target_os = "macos", target_os = "android", target_os = "emscripten"))))]
+pub mod wayland_clipboard;
+#[cfg(all(unix, not(any(target_os = "macos", target_os = "android", target_os = "emscripten"))))]
+pub mod x11_clipboard;
+
+#[cfg(windows)]
+pub mod windows_clipboard;
+
+#[cfg(target_os = "macos")]
+pub mod osx_clipboard;
+
+pub mod nop_clipboard;
+
+#[cfg(all(unix, not(any(target_os = "macos", target_os = "android", target_os = "emscripten"))))]
+pub type ClipboardContext = x11_clipboard::X11ClipboardContext;
+#[cfg(windows)]
+pub type ClipboardContext = windows_clipboard::WindowsClipboardContext;
+#[cfg(target_os = "macos")]
+pub type ClipboardContext = osx_clipboard::OSXClipboardContext;
+#[cfg(target_os = "android")]
+pub type ClipboardContext = nop_clipboard::NopClipboardContext; // TODO: implement AndroidClipboardContext
+#[cfg(not(any(
+ unix,
+ windows,
+ target_os = "macos",
+ target_os = "android",
+ target_os = "emscripten"
+)))]
+pub type ClipboardContext = nop_clipboard::NopClipboardContext;
diff --git a/copypasta/src/nop_clipboard.rs b/copypasta/src/nop_clipboard.rs
new file mode 100644
index 00000000..bdb79e20
--- /dev/null
+++ b/copypasta/src/nop_clipboard.rs
@@ -0,0 +1,42 @@
+// Copyright 2016 Avraham Weinstock
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use common::ClipboardProvider;
+use std::error::Error;
+
+pub struct NopClipboardContext;
+
+impl NopClipboardContext {
+ pub fn new() -> Result<NopClipboardContext, Box<dyn Error>> {
+ Ok(NopClipboardContext)
+ }
+}
+
+impl ClipboardProvider for NopClipboardContext {
+ fn get_contents(&mut self) -> Result<String, Box<dyn Error>> {
+ println!(
+ "Attempting to get the contents of the clipboard, which hasn't yet been implemented \
+ on this platform."
+ );
+ Ok("".to_string())
+ }
+
+ fn set_contents(&mut self, _: String) -> Result<(), Box<dyn Error>> {
+ println!(
+ "Attempting to set the contents of the clipboard, which hasn't yet been implemented \
+ on this platform."
+ );
+ Ok(())
+ }
+}
diff --git a/copypasta/src/osx_clipboard.rs b/copypasta/src/osx_clipboard.rs
new file mode 100644
index 00000000..0d65679d
--- /dev/null
+++ b/copypasta/src/osx_clipboard.rs
@@ -0,0 +1,84 @@
+// Copyright 2016 Avraham Weinstock
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use common::*;
+use objc::runtime::{Class, Object};
+use objc_foundation::{INSArray, INSObject, INSString};
+use objc_foundation::{NSArray, NSDictionary, NSObject, NSString};
+use objc_id::{Id, Owned};
+use std::error::Error;
+use std::mem::transmute;
+
+pub struct OSXClipboardContext {
+ pasteboard: Id<Object>,
+}
+
+// required to bring NSPasteboard into the path of the class-resolver
+#[link(name = "AppKit", kind = "framework")]
+extern "C" {}
+
+impl OSXClipboardContext {
+ pub fn new() -> Result<OSXClipboardContext, Box<dyn Error>> {
+ let cls = Class::get("NSPasteboard").ok_or("Class::get(\"NSPasteboard\")")?;
+ let pasteboard: *mut Object = unsafe { msg_send![cls, generalPasteboard] };
+ if pasteboard.is_null() {
+ return Err("NSPasteboard#generalPasteboard returned null".into());
+ }
+ let pasteboard: Id<Object> = unsafe { Id::from_ptr(pasteboard) };
+ Ok(OSXClipboardContext { pasteboard })
+ }
+}
+
+impl ClipboardProvider for OSXClipboardContext {
+ fn get_contents(&mut self) -> Result<String, Box<dyn Error>> {
+ let string_class: Id<NSObject> = {
+ let cls: Id<Class> = unsafe { Id::from_ptr(class("NSString")) };
+ unsafe { transmute(cls) }
+ };
+ let classes: Id<NSArray<NSObject, Owned>> = NSArray::from_vec(vec![string_class]);
+ let options: Id<NSDictionary<NSObject, NSObject>> = NSDictionary::new();
+ let string_array: Id<NSArray<NSString>> = unsafe {
+ let obj: *mut NSArray<NSString> =
+ msg_send![self.pasteboard, readObjectsForClasses:&*classes options:&*options];
+ if obj.is_null() {
+ return Err("pasteboard#readObjectsForClasses:options: returned null".into());
+ }
+ Id::from_ptr(obj)
+ };
+ if string_array.count() == 0 {
+ Err("pasteboard#readObjectsForClasses:options: returned empty".into())
+ } else {
+ Ok(string_array[0].as_str().to_owned())
+ }
+ }
+
+ fn set_contents(&mut self, data: String) -> Result<(), Box<dyn Error>> {
+ let string_array = NSArray::from_vec(vec![NSString::from_str(&data)]);
+ let _: usize = unsafe { msg_send![self.pasteboard, clearContents] };
+ let success: bool = unsafe { msg_send![self.pasteboard, writeObjects: string_array] };
+ return if success {
+ Ok(())
+ } else {
+ Err("NSPasteboard#writeObjects: returned false".into())
+ };
+ }
+}
+
+// this is a convenience function that both cocoa-rs and
+// glutin define, which seems to depend on the fact that
+// Option::None has the same representation as a null pointer
+#[inline]
+pub fn class(name: &str) -> *mut Class {
+ unsafe { transmute(Class::get(name)) }
+}
diff --git a/copypasta/src/wayland_clipboard.rs b/copypasta/src/wayland_clipboard.rs
new file mode 100644
index 00000000..cb450725
--- /dev/null
+++ b/copypasta/src/wayland_clipboard.rs
@@ -0,0 +1,70 @@
+// Copyright 2017 Avraham Weinstock
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use std::error::Error;
+use std::ffi::c_void;
+use std::marker::PhantomData;
+
+use smithay_clipboard::WaylandClipboard;
+use wayland_client::sys::client::wl_display;
+use wayland_client::Display;
+
+use common::ClipboardProvider;
+
+pub trait ClipboardType: Send {}
+
+pub struct Clipboard;
+impl ClipboardType for Clipboard {}
+
+pub struct Primary;
+impl ClipboardType for Primary {}
+
+pub struct WaylandClipboardContext<T: ClipboardType>(WaylandClipboard, PhantomData<T>);
+
+impl<T: ClipboardType> WaylandClipboardContext<T> {
+ /// Create a new clipboard context.
+ pub fn new(display: &Display) -> Self {
+ WaylandClipboardContext(WaylandClipboard::new(display), PhantomData)
+ }
+
+ /// Create a new clipboard context from an external pointer.
+ pub unsafe fn new_from_external(display: *mut c_void) -> Self {
+ WaylandClipboardContext(
+ WaylandClipboard::new_from_external(display as *mut wl_display),
+ PhantomData,
+ )
+ }
+}
+
+impl ClipboardProvider for WaylandClipboardContext<Clipboard> {
+ fn get_contents(&mut self) -> Result<String, Box<dyn Error>> {
+ Ok(self.0.load(None))
+ }
+
+ fn set_contents(&mut self, data: String) -> Result<(), Box<dyn Error>> {
+ self.0.store(None, data);
+ Ok(())
+ }
+}
+
+impl ClipboardProvider for WaylandClipboardContext<Primary> {
+ fn get_contents(&mut self) -> Result<String, Box<dyn Error>> {
+ Ok(self.0.load_primary(None))
+ }
+
+ fn set_contents(&mut self, data: String) -> Result<(), Box<dyn Error>> {
+ self.0.store_primary(None, data);
+ Ok(())
+ }
+}
diff --git a/copypasta/src/windows_clipboard.rs b/copypasta/src/windows_clipboard.rs
new file mode 100644
index 00000000..e35d3130
--- /dev/null
+++ b/copypasta/src/windows_clipboard.rs
@@ -0,0 +1,36 @@
+// Copyright 2016 Avraham Weinstock
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use clipboard_win::{get_clipboard_string, set_clipboard_string};
+
+use common::ClipboardProvider;
+use std::error::Error;
+
+pub struct WindowsClipboardContext;
+
+impl WindowsClipboardContext {
+ pub fn new() -> Result<Self, Box<dyn Error>> {
+ Ok(WindowsClipboardContext)
+ }
+}
+
+impl ClipboardProvider for WindowsClipboardContext {
+ fn get_contents(&mut self) -> Result<String, Box<dyn Error>> {
+ Ok(get_clipboard_string()?)
+ }
+
+ fn set_contents(&mut self, data: String) -> Result<(), Box<dyn Error>> {
+ Ok(set_clipboard_string(&data)?)
+ }
+}
diff --git a/copypasta/src/x11_clipboard.rs b/copypasta/src/x11_clipboard.rs
new file mode 100644
index 00000000..1b7bdff4
--- /dev/null
+++ b/copypasta/src/x11_clipboard.rs
@@ -0,0 +1,72 @@
+// Copyright 2017 Avraham Weinstock
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use common::*;
+use std::error::Error;
+use std::marker::PhantomData;
+use std::time::Duration;
+use x11_clipboard_crate::xcb::xproto::Atom;
+use x11_clipboard_crate::Atoms;
+use x11_clipboard_crate::Clipboard as X11Clipboard;
+
+pub trait Selection: Send {
+ fn atom(atoms: &Atoms) -> Atom;
+}
+
+pub struct Primary;
+
+impl Selection for Primary {
+ fn atom(atoms: &Atoms) -> Atom {
+ atoms.primary
+ }
+}
+
+pub struct Clipboard;
+
+impl Selection for Clipboard {
+ fn atom(atoms: &Atoms) -> Atom {
+ atoms.clipboard
+ }
+}
+
+pub struct X11ClipboardContext<S = Clipboard>(X11Clipboard, PhantomData<S>)
+where
+ S: Selection;
+
+impl<S> X11ClipboardContext<S>
+where
+ S: Selection,
+{
+ pub fn new() -> Result<X11ClipboardContext<S>, Box<dyn Error>> {
+ Ok(X11ClipboardContext(X11Clipboard::new()?, PhantomData))
+ }
+}
+
+impl<S> ClipboardProvider for X11ClipboardContext<S>
+where
+ S: Selection,
+{
+ fn get_contents(&mut self) -> Result<String, Box<dyn Error>> {
+ Ok(String::from_utf8(self.0.load(
+ S::atom(&self.0.getter.atoms),
+ self.0.getter.atoms.utf8_string,
+ self.0.getter.atoms.property,
+ Duration::from_secs(3),
+ )?)?)
+ }
+
+ fn set_contents(&mut self, data: String) -> Result<(), Box<dyn Error>> {
+ Ok(self.0.store(S::atom(&self.0.setter.atoms), self.0.setter.atoms.utf8_string, data)?)
+ }
+}