├── .builds ├── freebsd.yml └── linux.yml ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE.apache2 ├── LICENSE.mit ├── README.md ├── examples ├── hello_world.rs └── primary_selection.rs ├── rustfmt.toml └── src ├── common.rs ├── lib.rs ├── nop_clipboard.rs ├── osx_clipboard.rs ├── wayland_clipboard.rs ├── windows_clipboard.rs └── x11_clipboard.rs /.builds/freebsd.yml: -------------------------------------------------------------------------------- 1 | image: freebsd/latest 2 | 3 | packages: 4 | - lang/python3 5 | - lang/gcc 6 | - x11/libxcb 7 | - x11/libxkbcommon 8 | 9 | sources: 10 | - https://github.com/alacritty/copypasta 11 | 12 | environment: 13 | PATH: /home/build/.cargo/bin:/bin:/usr/bin:/usr/local/bin 14 | RUSTFLAGS: -L /usr/local/lib 15 | 16 | tasks: 17 | - rustup: | 18 | curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain stable --profile minimal 19 | - test: | 20 | cd copypasta 21 | cargo test 22 | - clippy: | 23 | cd copypasta 24 | rustup component add clippy 25 | cargo clippy --all-targets 26 | - oldstable: | 27 | cd copypasta 28 | rustup toolchain install --profile minimal 1.71.0 29 | cargo +1.71.0 test 30 | -------------------------------------------------------------------------------- /.builds/linux.yml: -------------------------------------------------------------------------------- 1 | image: archlinux 2 | 3 | packages: 4 | - libxcb 5 | - libxkbcommon 6 | 7 | sources: 8 | - https://github.com/alacritty/copypasta 9 | 10 | environment: 11 | PATH: /home/build/.cargo/bin:/usr/bin/ 12 | 13 | tasks: 14 | - rustup: | 15 | curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain stable --profile minimal 16 | - test: | 17 | cd copypasta 18 | cargo test 19 | - rustfmt: | 20 | cd copypasta 21 | rustup toolchain install nightly -c rustfmt 22 | cargo +nightly fmt -- --check 23 | - clippy: | 24 | cd copypasta 25 | rustup component add clippy 26 | cargo clippy --all-targets 27 | - oldstable: | 28 | cd copypasta 29 | rustup toolchain install --profile minimal 1.71.0 30 | cargo +1.71.0 test 31 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request] 4 | 5 | env: 6 | CARGO_TERM_COLOR: always 7 | 8 | jobs: 9 | build: 10 | strategy: 11 | matrix: 12 | os: [windows-latest, macos-latest] 13 | 14 | runs-on: ${{ matrix.os }} 15 | 16 | steps: 17 | - uses: actions/checkout@v2 18 | - name: Stable 19 | run: cargo test 20 | - name: Clippy 21 | run: | 22 | rustup component add clippy 23 | cargo clippy --all-targets 24 | - name: Oldstable 25 | run: | 26 | rustup default 1.71.0 27 | cargo clean 28 | cargo test 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## 0.10.2 9 | 10 | ### Packaging 11 | 12 | - Minimum Rust version was bumped to `1.71.0` 13 | - Switched from `objc` to `objc2` 14 | - New default `wayland-dlopen` feature, to control `libwayland` linking 15 | 16 | ## 0.10.1 17 | 18 | ### Packaging 19 | 20 | - Minimum rust version was bumped to `1.66.0` 21 | - `x11_clipboard` was bumped to `0.9.1` 22 | 23 | ## 0.10.0 24 | 25 | ### Changed 26 | 27 | - Use `String` in `ClipboardProvider::set_contents` for trait to be *object-safe* 28 | 29 | ## 0.9.0 30 | 31 | - Bump minimum supported Rust version to `1.65.0` 32 | - Change `ClipboardProvider::set_contents` parameter type to `AsRef` 33 | - Prefer file's path over text on macOS 34 | 35 | ## 0.8.2 36 | 37 | ### Packaging 38 | 39 | - Minimum rust version was bumped to `1.60.0` 40 | 41 | ### Fixed 42 | 43 | - `x11_clipboard` was bumped to `0.7.0` droping `quick-xml` from the deps tree 44 | 45 | 46 | ## 0.8.1 47 | 48 | ### Fixed 49 | 50 | - Crash on use-after-free on macOS 51 | 52 | ## 0.8.0 53 | 54 | ### Packaging 55 | 56 | - Minimum rust version was bumped to `1.57.0` 57 | 58 | ### Fixed 59 | 60 | - Memory leak on macOS 61 | 62 | ## 0.7.1 63 | 64 | ### Changed 65 | 66 | - Updated `smithay-clipboard` to 0.6.0 67 | 68 | ## 0.7.0 69 | 70 | ### Packaging 71 | 72 | - Minimum rust version was bumped to `1.41.0` 73 | 74 | ### Removed 75 | 76 | - Ability to create a Wayland clipboard from Display type directly using `create_clipboard` 77 | 78 | ## 0.6.3 79 | 80 | ### Added 81 | 82 | - Features `x11` and `wayland` for picking the linux backends 83 | 84 | ## 0.6.2 85 | 86 | ### Fixed 87 | 88 | - Compilation on iOS, using the no-op clipboard 89 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "copypasta" 3 | version = "0.10.2" 4 | authors = ["Christian Duerr "] 5 | description = "copypasta is a cross-platform library for getting and setting the contents of the OS-level clipboard." 6 | repository = "https://github.com/alacritty/copypasta" 7 | documentation = "https://docs.rs/copypasta" 8 | readme = "README.md" 9 | license = "MIT / Apache-2.0" 10 | keywords = ["clipboard"] 11 | exclude = ["/.travis.yml"] 12 | edition = "2021" 13 | rust-version = "1.71.0" 14 | 15 | [features] 16 | default = ["x11", "wayland", "wayland-dlopen"] 17 | x11 = ["x11-clipboard"] 18 | wayland = ["smithay-clipboard"] 19 | wayland-dlopen = ["smithay-clipboard/dlopen"] 20 | 21 | [target.'cfg(windows)'.dependencies] 22 | clipboard-win = { version = "5.4.0", features = ["std"]} 23 | 24 | [target.'cfg(target_os = "macos")'.dependencies] 25 | objc2 = "0.6.1" 26 | objc2-foundation = { version = "0.3.1", default-features = false, features = [ 27 | "std", 28 | "NSArray", 29 | "NSString", 30 | "NSURL", 31 | ] } 32 | objc2-app-kit = { version = "0.3.1", default-features = false, features = [ 33 | "std", 34 | "NSPasteboard", 35 | ] } 36 | 37 | [target.'cfg(all(unix, not(any(target_os="macos", target_os="android", target_os="ios", target_os="emscripten"))))'.dependencies] 38 | x11-clipboard = { version = "0.9.1", optional = true } 39 | smithay-clipboard = { version = "0.7.0", default-features = false, optional = true } 40 | -------------------------------------------------------------------------------- /LICENSE.apache2: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. -------------------------------------------------------------------------------- /LICENSE.mit: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 Avraham Weinstock 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # copypasta 2 | 3 | copypasta is a [rust-clipboard](https://github.com/aweinstock314/rust-clipboard) fork, adding support for the Wayland clipboard. 4 | 5 | rust-clipboard is a cross-platform library for getting and setting the contents of the OS-level clipboard. 6 | 7 | ## Example 8 | 9 | ```rust 10 | extern crate copypasta; 11 | 12 | use copypasta::{ClipboardContext, ClipboardProvider}; 13 | 14 | fn main() { 15 | let mut ctx = ClipboardContext::new().unwrap(); 16 | 17 | let msg = "Hello, world!"; 18 | ctx.set_contents(msg.to_owned()).unwrap(); 19 | 20 | let content = ctx.get_contents().unwrap(); 21 | 22 | println!("{}", content); 23 | } 24 | ``` 25 | 26 | ## API 27 | 28 | The `ClipboardProvider` trait has the following functions: 29 | 30 | ```rust 31 | fn get_contents(&mut self) -> Result>; 32 | fn set_contents(&mut self, String) -> Result<(), Box>; 33 | ``` 34 | 35 | `ClipboardContext` is a type alias for one of {`WindowsClipboardContext`, `OSXClipboardContext`, `X11ClipboardContext`, `NopClipboardContext`}, all of which implement `ClipboardProvider`. Which concrete type is chosen for `ClipboardContext` depends on the OS (via conditional compilation). 36 | 37 | ## License 38 | 39 | `rust-clipboard` is dual-licensed under MIT and Apache2. 40 | -------------------------------------------------------------------------------- /examples/hello_world.rs: -------------------------------------------------------------------------------- 1 | use copypasta::{ClipboardContext, ClipboardProvider}; 2 | 3 | fn main() { 4 | let mut ctx = ClipboardContext::new().unwrap(); 5 | 6 | let msg = "Hello, world!"; 7 | ctx.set_contents(msg.to_owned()).unwrap(); 8 | 9 | let content = ctx.get_contents().unwrap(); 10 | 11 | println!("{}", content); 12 | } 13 | -------------------------------------------------------------------------------- /examples/primary_selection.rs: -------------------------------------------------------------------------------- 1 | #[cfg(target_os = "linux")] 2 | use copypasta::x11_clipboard::{Primary, X11ClipboardContext}; 3 | #[cfg(target_os = "linux")] 4 | use copypasta::ClipboardProvider; 5 | 6 | #[cfg(target_os = "linux")] 7 | fn main() { 8 | let mut ctx = X11ClipboardContext::::new().unwrap(); 9 | 10 | let the_string = "Hello, world!"; 11 | 12 | ctx.set_contents(the_string.to_owned()).unwrap(); 13 | } 14 | 15 | #[cfg(not(target_os = "linux"))] 16 | fn main() { 17 | println!("Primary selection is only available under linux!"); 18 | } 19 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | format_code_in_doc_comments = true 2 | match_block_trailing_comma = true 3 | condense_wildcard_suffixes = true 4 | use_field_init_shorthand = true 5 | overflow_delimited_expr = true 6 | use_small_heuristics = "Max" 7 | normalize_comments = true 8 | reorder_impl_items = true 9 | use_try_shorthand = true 10 | newline_style = "Unix" 11 | format_strings = true 12 | wrap_comments = true 13 | comment_width = 100 14 | -------------------------------------------------------------------------------- /src/common.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Avraham Weinstock 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | use std::error::Error; 16 | 17 | pub type Result = std::result::Result>; 18 | 19 | // TODO: come up with some platform-agnostic API for richer types 20 | /// Trait for clipboard access 21 | pub trait ClipboardProvider: Send { 22 | /// Method to get the clipboard contents as a String 23 | fn get_contents(&mut self) -> Result; 24 | /// Method to set the clipboard contents as a String 25 | fn set_contents(&mut self, _: String) -> Result<()>; 26 | } 27 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Avraham Weinstock 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | #![deny(clippy::all, clippy::if_not_else, clippy::enum_glob_use)] 15 | 16 | mod common; 17 | pub use crate::common::ClipboardProvider; 18 | 19 | #[cfg(all( 20 | unix, 21 | not(any( 22 | target_os = "macos", 23 | target_os = "android", 24 | target_os = "ios", 25 | target_os = "emscripten" 26 | )) 27 | ))] 28 | #[cfg(feature = "wayland")] 29 | pub mod wayland_clipboard; 30 | #[cfg(all( 31 | unix, 32 | not(any( 33 | target_os = "macos", 34 | target_os = "android", 35 | target_os = "ios", 36 | target_os = "emscripten" 37 | )) 38 | ))] 39 | #[cfg(feature = "x11")] 40 | pub mod x11_clipboard; 41 | 42 | #[cfg(windows)] 43 | pub mod windows_clipboard; 44 | 45 | #[cfg(target_os = "macos")] 46 | pub mod osx_clipboard; 47 | 48 | pub mod nop_clipboard; 49 | 50 | #[cfg(all( 51 | unix, 52 | not(any( 53 | target_os = "macos", 54 | target_os = "android", 55 | target_os = "ios", 56 | target_os = "emscripten" 57 | )) 58 | ))] 59 | #[cfg(feature = "x11")] 60 | pub type ClipboardContext = x11_clipboard::X11ClipboardContext; 61 | #[cfg(windows)] 62 | pub type ClipboardContext = windows_clipboard::WindowsClipboardContext; 63 | #[cfg(target_os = "macos")] 64 | pub type ClipboardContext = osx_clipboard::OSXClipboardContext; 65 | #[cfg(target_os = "android")] 66 | pub type ClipboardContext = nop_clipboard::NopClipboardContext; // TODO: implement AndroidClipboardContext 67 | #[cfg(target_os = "ios")] 68 | pub type ClipboardContext = nop_clipboard::NopClipboardContext; // TODO: implement IOSClipboardContext 69 | #[cfg(not(any( 70 | unix, 71 | windows, 72 | target_os = "macos", 73 | target_os = "android", 74 | target_os = "ios", 75 | target_os = "emscripten" 76 | )))] 77 | pub type ClipboardContext = nop_clipboard::NopClipboardContext; 78 | -------------------------------------------------------------------------------- /src/nop_clipboard.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Avraham Weinstock 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | use crate::common::{ClipboardProvider, Result}; 16 | 17 | pub struct NopClipboardContext; 18 | 19 | impl NopClipboardContext { 20 | pub fn new() -> Result { 21 | Ok(NopClipboardContext) 22 | } 23 | } 24 | 25 | impl ClipboardProvider for NopClipboardContext { 26 | fn get_contents(&mut self) -> Result { 27 | println!( 28 | "Attempting to get the contents of the clipboard, which hasn't yet been implemented \ 29 | on this platform." 30 | ); 31 | Ok("".to_string()) 32 | } 33 | 34 | fn set_contents(&mut self, _: String) -> Result<()> { 35 | println!( 36 | "Attempting to set the contents of the clipboard, which hasn't yet been implemented \ 37 | on this platform." 38 | ); 39 | Ok(()) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/osx_clipboard.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Avraham Weinstock 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | use std::panic::RefUnwindSafe; 16 | use std::panic::UnwindSafe; 17 | 18 | use objc2::rc::{autoreleasepool, Retained}; 19 | use objc2::runtime::ProtocolObject; 20 | use objc2::{msg_send, ClassType}; 21 | use objc2_app_kit::{NSPasteboard, NSPasteboardTypeFileURL, NSPasteboardTypeString}; 22 | use objc2_foundation::{NSArray, NSString, NSURL}; 23 | 24 | use crate::common::*; 25 | 26 | pub struct OSXClipboardContext { 27 | pasteboard: Retained, 28 | } 29 | 30 | unsafe impl Send for OSXClipboardContext {} 31 | unsafe impl Sync for OSXClipboardContext {} 32 | impl UnwindSafe for OSXClipboardContext {} 33 | impl RefUnwindSafe for OSXClipboardContext {} 34 | 35 | impl OSXClipboardContext { 36 | pub fn new() -> Result { 37 | // Use `msg_send_id!` instead of `NSPasteboard::generalPasteboard()` 38 | // in the off case that it will return NULL (even though it's 39 | // documented not to). 40 | let pasteboard: Option> = 41 | unsafe { msg_send![NSPasteboard::class(), generalPasteboard] }; 42 | let pasteboard = pasteboard.ok_or("NSPasteboard#generalPasteboard returned null")?; 43 | Ok(OSXClipboardContext { pasteboard }) 44 | } 45 | } 46 | 47 | impl ClipboardProvider for OSXClipboardContext { 48 | fn get_contents(&mut self) -> Result { 49 | autoreleasepool(|_| { 50 | let types = unsafe { self.pasteboard.types() }.unwrap(); 51 | let has_file = unsafe { types.containsObject(NSPasteboardTypeFileURL) }; 52 | let has_str = unsafe { types.containsObject(NSPasteboardTypeString) }; 53 | 54 | if !has_str { 55 | return Err("NSPasteboard#types doesn't contain NSPasteboardTypeString".into()); 56 | } 57 | 58 | let text = if has_file { 59 | let file_url_string = 60 | unsafe { self.pasteboard.stringForType(NSPasteboardTypeFileURL) } 61 | .ok_or("NSPasteboard#stringForType returned null")?; 62 | 63 | let file_url = unsafe { NSURL::URLWithString(&file_url_string) } 64 | .ok_or("NSURL#URLWithString returned null")?; 65 | unsafe { file_url.path() }.ok_or("NSURL#path returned null")? 66 | } else { 67 | unsafe { self.pasteboard.stringForType(NSPasteboardTypeString) } 68 | .ok_or("NSPasteboard#stringForType returned null")? 69 | }; 70 | 71 | Ok(text.to_string()) 72 | }) 73 | } 74 | 75 | fn set_contents(&mut self, data: String) -> Result<()> { 76 | let string_array = NSArray::from_retained_slice(&[ProtocolObject::from_retained( 77 | NSString::from_str(&data), 78 | )]); 79 | unsafe { self.pasteboard.clearContents() }; 80 | let success = unsafe { self.pasteboard.writeObjects(&string_array) }; 81 | if success { 82 | Ok(()) 83 | } else { 84 | Err("NSPasteboard#writeObjects: returned false".into()) 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/wayland_clipboard.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Avraham Weinstock 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | use std::ffi::c_void; 16 | use std::sync::{Arc, Mutex}; 17 | 18 | use smithay_clipboard::Clipboard as WaylandClipboard; 19 | 20 | use crate::common::{ClipboardProvider, Result}; 21 | 22 | pub struct Clipboard { 23 | context: Arc>, 24 | } 25 | 26 | pub struct Primary { 27 | context: Arc>, 28 | } 29 | 30 | /// Create new clipboard from a raw display pointer. 31 | /// 32 | /// # Safety 33 | /// 34 | /// Since the type of the display is a raw pointer, it's the responsibility of the callee to make 35 | /// sure that the passed pointer is a valid Wayland display. 36 | pub unsafe fn create_clipboards_from_external(display: *mut c_void) -> (Primary, Clipboard) { 37 | let context = Arc::new(Mutex::new(WaylandClipboard::new(display))); 38 | 39 | (Primary { context: context.clone() }, Clipboard { context }) 40 | } 41 | 42 | impl ClipboardProvider for Clipboard { 43 | fn get_contents(&mut self) -> Result { 44 | Ok(self.context.lock().unwrap().load()?) 45 | } 46 | 47 | fn set_contents(&mut self, data: String) -> Result<()> { 48 | self.context.lock().unwrap().store(data); 49 | 50 | Ok(()) 51 | } 52 | } 53 | 54 | impl ClipboardProvider for Primary { 55 | fn get_contents(&mut self) -> Result { 56 | Ok(self.context.lock().unwrap().load_primary()?) 57 | } 58 | 59 | fn set_contents(&mut self, data: String) -> Result<()> { 60 | self.context.lock().unwrap().store_primary(data); 61 | 62 | Ok(()) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/windows_clipboard.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Avraham Weinstock 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | use clipboard_win::{get_clipboard_string, set_clipboard_string}; 16 | 17 | use crate::common::{ClipboardProvider, Result}; 18 | 19 | pub struct WindowsClipboardContext; 20 | 21 | impl WindowsClipboardContext { 22 | pub fn new() -> Result { 23 | Ok(WindowsClipboardContext) 24 | } 25 | } 26 | 27 | impl ClipboardProvider for WindowsClipboardContext { 28 | fn get_contents(&mut self) -> Result { 29 | Ok(get_clipboard_string()?) 30 | } 31 | 32 | fn set_contents(&mut self, data: String) -> Result<()> { 33 | Ok(set_clipboard_string(&data)?) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/x11_clipboard.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Avraham Weinstock 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | use std::marker::PhantomData; 16 | use std::time::Duration; 17 | 18 | use x11_clipboard::Atom; 19 | use x11_clipboard::{Atoms, Clipboard as X11Clipboard}; 20 | 21 | use crate::common::*; 22 | 23 | pub trait Selection: Send { 24 | fn atom(atoms: &Atoms) -> Atom; 25 | } 26 | 27 | pub struct Primary; 28 | 29 | impl Selection for Primary { 30 | fn atom(atoms: &Atoms) -> Atom { 31 | atoms.primary 32 | } 33 | } 34 | 35 | pub struct Clipboard; 36 | 37 | impl Selection for Clipboard { 38 | fn atom(atoms: &Atoms) -> Atom { 39 | atoms.clipboard 40 | } 41 | } 42 | 43 | pub struct X11ClipboardContext(X11Clipboard, PhantomData) 44 | where 45 | S: Selection; 46 | 47 | impl X11ClipboardContext 48 | where 49 | S: Selection, 50 | { 51 | pub fn new() -> Result> { 52 | Ok(X11ClipboardContext(X11Clipboard::new()?, PhantomData)) 53 | } 54 | } 55 | 56 | impl ClipboardProvider for X11ClipboardContext 57 | where 58 | S: Selection, 59 | { 60 | fn get_contents(&mut self) -> Result { 61 | Ok(String::from_utf8(self.0.load( 62 | S::atom(&self.0.getter.atoms), 63 | self.0.getter.atoms.utf8_string, 64 | self.0.getter.atoms.property, 65 | Duration::from_secs(3), 66 | )?)?) 67 | } 68 | 69 | fn set_contents(&mut self, data: String) -> Result<()> { 70 | Ok(self.0.store(S::atom(&self.0.setter.atoms), self.0.setter.atoms.utf8_string, data)?) 71 | } 72 | } 73 | --------------------------------------------------------------------------------