diff options
Diffstat (limited to 'alacritty_terminal/src')
-rw-r--r-- | alacritty_terminal/src/clipboard.rs | 90 | ||||
-rw-r--r-- | alacritty_terminal/src/display.rs | 6 | ||||
-rw-r--r-- | alacritty_terminal/src/event.rs | 11 | ||||
-rw-r--r-- | alacritty_terminal/src/input.rs | 26 | ||||
-rw-r--r-- | alacritty_terminal/src/lib.rs | 1 | ||||
-rw-r--r-- | alacritty_terminal/src/term/mod.rs | 56 | ||||
-rw-r--r-- | alacritty_terminal/src/url.rs | 4 | ||||
-rw-r--r-- | alacritty_terminal/src/window.rs | 15 |
8 files changed, 161 insertions, 48 deletions
diff --git a/alacritty_terminal/src/clipboard.rs b/alacritty_terminal/src/clipboard.rs new file mode 100644 index 00000000..ca70c3bf --- /dev/null +++ b/alacritty_terminal/src/clipboard.rs @@ -0,0 +1,90 @@ +// Copyright 2016 Joe Wilm, The Alacritty Project Contributors +// +// 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. + +#[cfg(not(any(target_os = "macos", target_os = "windows")))] +use std::ffi::c_void; + +use clipboard::nop_clipboard::NopClipboardContext; +#[cfg(not(any(target_os = "macos", target_os = "windows")))] +use clipboard::wayland_clipboard::WaylandClipboardContext; +#[cfg(not(any(target_os = "macos", target_os = "windows")))] +use clipboard::x11_clipboard::{Primary as X11SecondaryClipboard, X11ClipboardContext}; +use clipboard::{ClipboardContext, ClipboardProvider}; + +pub struct Clipboard { + primary: Box<ClipboardProvider>, + secondary: Option<Box<ClipboardProvider>>, +} + +impl Clipboard { + #[cfg(any(target_os = "macos", target_os = "windows"))] + pub fn new() -> Self { + Self::default() + } + + #[cfg(not(any(target_os = "macos", target_os = "windows")))] + pub fn new(display: Option<*mut c_void>) -> Self { + if let Some(display) = display { + return Self { + primary: unsafe { Box::new(WaylandClipboardContext::new_from_external(display)) }, + secondary: None, + }; + } + + Self { + primary: Box::new(ClipboardContext::new().unwrap()), + secondary: Some(Box::new(X11ClipboardContext::<X11SecondaryClipboard>::new().unwrap())), + } + } + + // Use for tests and ref-tests + pub fn new_nop() -> Self { + Self { primary: Box::new(NopClipboardContext::new().unwrap()), secondary: None } + } +} + +impl Default for Clipboard { + fn default() -> Self { + Self { primary: Box::new(ClipboardContext::new().unwrap()), secondary: None } + } +} + +#[derive(Debug)] +pub enum ClipboardType { + Primary, + Secondary, +} + +impl Clipboard { + pub fn store(&mut self, ty: ClipboardType, text: impl Into<String>) { + let clipboard = match (ty, &mut self.secondary) { + (ClipboardType::Secondary, Some(provider)) => provider, + (ClipboardType::Secondary, None) => return, + _ => &mut self.primary, + }; + + clipboard.set_contents(text.into()).unwrap_or_else(|err| { + warn!("Error storing selection to clipboard. {}", err); + }); + } + + pub fn load(&mut self, ty: ClipboardType) -> Result<String, Box<std::error::Error>> { + let clipboard = match (ty, &mut self.secondary) { + (ClipboardType::Secondary, Some(provider)) => provider, + _ => &mut self.primary, + }; + + clipboard.get_contents() + } +} diff --git a/alacritty_terminal/src/display.rs b/alacritty_terminal/src/display.rs index 1d5799f6..4cb023af 100644 --- a/alacritty_terminal/src/display.rs +++ b/alacritty_terminal/src/display.rs @@ -15,6 +15,7 @@ //! The display subsystem including window management, font rasterization, and //! GPU drawing. use std::f64; +use std::ffi::c_void; use std::sync::mpsc; use glutin::dpi::{PhysicalPosition, PhysicalSize}; @@ -557,4 +558,9 @@ impl Display { self.window().set_ime_spot(PhysicalPosition::from((nspot_x, nspot_y)).to_logical(dpr)); } + + #[cfg(not(any(target_os = "macos", target_os = "windows")))] + pub fn get_wayland_display(&self) -> Option<*mut c_void> { + self.window.get_wayland_display() + } } diff --git a/alacritty_terminal/src/event.rs b/alacritty_terminal/src/event.rs index 1f3e9ca5..f27a6caa 100644 --- a/alacritty_terminal/src/event.rs +++ b/alacritty_terminal/src/event.rs @@ -8,13 +8,13 @@ use std::io::Write; use std::sync::mpsc; use std::time::Instant; -use copypasta::{Buffer as ClipboardBuffer, Clipboard, Load, Store}; use glutin::dpi::PhysicalSize; use glutin::{self, ElementState, Event, ModifiersState, MouseButton}; use parking_lot::MutexGuard; use serde_json as json; use crate::cli::Options; +use crate::clipboard::ClipboardType; use crate::config::{self, Config}; use crate::display::OnResize; use crate::grid::Scroll; @@ -26,7 +26,6 @@ use crate::term::cell::Cell; use crate::term::{SizeInfo, Term}; #[cfg(unix)] use crate::tty; -use crate::util::fmt::Red; use crate::util::{limit, start_daemon}; use crate::window::Window; @@ -70,14 +69,10 @@ impl<'a, N: Notify + 'a> input::ActionContext for ActionContext<'a, N> { } } - fn copy_selection(&self, buffer: ClipboardBuffer) { + fn copy_selection(&mut self, ty: ClipboardType) { if let Some(selected) = self.terminal.selection_to_string() { if !selected.is_empty() { - Clipboard::new() - .and_then(|mut clipboard| clipboard.store(selected, buffer)) - .unwrap_or_else(|err| { - warn!("Error storing selection to clipboard. {}", Red(err)); - }); + self.terminal.clipboard().store(ty, selected); } } } diff --git a/alacritty_terminal/src/input.rs b/alacritty_terminal/src/input.rs index fc79b398..0a5cd42b 100644 --- a/alacritty_terminal/src/input.rs +++ b/alacritty_terminal/src/input.rs @@ -23,7 +23,6 @@ use std::mem; use std::ops::RangeInclusive; use std::time::Instant; -use copypasta::{Buffer as ClipboardBuffer, Clipboard, Load}; use glutin::{ ElementState, KeyboardInput, ModifiersState, MouseButton, MouseCursor, MouseScrollDelta, TouchPhase, @@ -31,6 +30,7 @@ use glutin::{ use unicode_width::UnicodeWidthStr; use crate::ansi::{ClearMode, Handler}; +use crate::clipboard::ClipboardType; use crate::config::{self, Key}; use crate::event::{ClickState, Mouse}; use crate::grid::Scroll; @@ -63,7 +63,7 @@ pub struct Processor<'a, A: 'a> { pub trait ActionContext { fn write_to_pty<B: Into<Cow<'static, [u8]>>>(&mut self, _: B); fn size_info(&self) -> SizeInfo; - fn copy_selection(&self, _: ClipboardBuffer); + fn copy_selection(&mut self, _: ClipboardType); fn clear_selection(&mut self); fn update_selection(&mut self, point: Point, side: Side); fn simple_selection(&mut self, point: Point, side: Side); @@ -279,11 +279,12 @@ impl Action { ctx.write_to_pty(s.clone().into_bytes()) }, Action::Copy => { - ctx.copy_selection(ClipboardBuffer::Primary); + ctx.copy_selection(ClipboardType::Primary); }, Action::Paste => { - Clipboard::new() - .and_then(|clipboard| clipboard.load_primary()) + ctx.terminal_mut() + .clipboard() + .load(ClipboardType::Primary) .map(|contents| self.paste(ctx, &contents)) .unwrap_or_else(|err| { error!("Error loading data from clipboard: {}", Red(err)); @@ -292,8 +293,9 @@ impl Action { Action::PasteSelection => { // Only paste if mouse events are not captured by an application if !mouse_mode { - Clipboard::new() - .and_then(|clipboard| clipboard.load_selection()) + ctx.terminal_mut() + .clipboard() + .load(ClipboardType::Secondary) .map(|contents| self.paste(ctx, &contents)) .unwrap_or_else(|err| { error!("Error loading data from clipboard: {}", Red(err)); @@ -952,9 +954,9 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> { /// Copy text selection. fn copy_selection(&mut self) { if self.save_to_clipboard { - self.ctx.copy_selection(ClipboardBuffer::Primary); + self.ctx.copy_selection(ClipboardType::Primary); } - self.ctx.copy_selection(ClipboardBuffer::Selection); + self.ctx.copy_selection(ClipboardType::Secondary); } } @@ -965,6 +967,7 @@ mod tests { use glutin::{ElementState, Event, ModifiersState, MouseButton, VirtualKeyCode, WindowEvent}; + use crate::clipboard::{Clipboard, ClipboardType}; use crate::config::{self, ClickHandler, Config}; use crate::event::{ClickState, Mouse, WindowChanges}; use crate::grid::Scroll; @@ -974,7 +977,6 @@ mod tests { use crate::term::{SizeInfo, Term, TermMode}; use super::{Action, Binding, Processor}; - use copypasta::Buffer as ClipboardBuffer; const KEY: VirtualKeyCode = VirtualKeyCode::Key0; @@ -1004,7 +1006,7 @@ mod tests { fn simple_selection(&mut self, _point: Point, _side: Side) {} - fn copy_selection(&self, _buffer: ClipboardBuffer) {} + fn copy_selection(&mut self, _: ClipboardType) {} fn clear_selection(&mut self) {} @@ -1095,7 +1097,7 @@ mod tests { dpr: 1.0, }; - let mut terminal = Term::new(&config, size, MessageBuffer::new()); + let mut terminal = Term::new(&config, size, MessageBuffer::new(), Clipboard::new_nop()); let mut mouse = Mouse::default(); mouse.click_state = $initial_state; diff --git a/alacritty_terminal/src/lib.rs b/alacritty_terminal/src/lib.rs index ab1ba35e..182d7811 100644 --- a/alacritty_terminal/src/lib.rs +++ b/alacritty_terminal/src/lib.rs @@ -30,6 +30,7 @@ extern crate objc; pub mod macros; pub mod ansi; pub mod cli; +pub mod clipboard; pub mod config; mod cursor; pub mod display; diff --git a/alacritty_terminal/src/term/mod.rs b/alacritty_terminal/src/term/mod.rs index 84a23eca..cca6d2de 100644 --- a/alacritty_terminal/src/term/mod.rs +++ b/alacritty_terminal/src/term/mod.rs @@ -18,7 +18,6 @@ use std::ops::{Index, IndexMut, Range, RangeInclusive}; use std::time::{Duration, Instant}; use std::{io, mem, ptr}; -use copypasta::{Clipboard, Load, Store}; use font::{self, RasterizedGlyph, Size}; use glutin::MouseCursor; use unicode_width::UnicodeWidthChar; @@ -26,6 +25,7 @@ use unicode_width::UnicodeWidthChar; use crate::ansi::{ self, Attr, CharsetIndex, Color, CursorStyle, Handler, NamedColor, StandardCharset, }; +use crate::clipboard::{Clipboard, ClipboardType}; use crate::config::{Config, VisualBellAnimation}; use crate::cursor; use crate::grid::{ @@ -756,6 +756,9 @@ pub struct Term { /// Hint that Alacritty should be closed should_exit: bool, + + /// Clipboard access coupled to the active window + clipboard: Clipboard, } /// Terminal size info @@ -843,7 +846,12 @@ impl Term { self.next_mouse_cursor.take() } - pub fn new(config: &Config, size: SizeInfo, message_buffer: MessageBuffer) -> Term { + pub fn new( + config: &Config, + size: SizeInfo, + message_buffer: MessageBuffer, + clipboard: Clipboard, + ) -> Term { let num_cols = size.cols(); let num_lines = size.lines(); @@ -889,6 +897,7 @@ impl Term { auto_scroll: config.scrolling().auto_scroll, message_buffer, should_exit: false, + clipboard, } } @@ -1317,6 +1326,10 @@ impl Term { self.grid.url_highlight = None; self.dirty = true; } + + pub fn clipboard(&mut self) -> &mut Clipboard { + &mut self.clipboard + } } impl ansi::TermInfo for Term { @@ -1835,11 +1848,7 @@ impl ansi::Handler for Term { /// Set the clipboard #[inline] fn set_clipboard(&mut self, string: &str) { - Clipboard::new().and_then(|mut clipboard| clipboard.store_primary(string)).unwrap_or_else( - |err| { - warn!("Error storing selection to clipboard: {}", err); - }, - ); + self.clipboard.store(ClipboardType::Primary, string); } #[inline] @@ -2120,20 +2129,20 @@ impl IndexMut<Column> for TabStops { #[cfg(test)] mod tests { - use serde_json; + use std::mem; - use super::{Cell, SizeInfo, Term}; - use crate::term::cell; + use font::Size; + use serde_json; use crate::ansi::{self, CharsetIndex, Handler, StandardCharset}; + use crate::clipboard::Clipboard; use crate::config::Config; use crate::grid::{Grid, Scroll}; use crate::index::{Column, Line, Point, Side}; use crate::input::FONT_SIZE_STEP; use crate::message_bar::MessageBuffer; use crate::selection::Selection; - use font::Size; - use std::mem; + use crate::term::{cell, Cell, SizeInfo, Term}; #[test] fn semantic_selection_works() { @@ -2146,7 +2155,8 @@ mod tests { padding_y: 0.0, dpr: 1.0, }; - let mut term = Term::new(&Default::default(), size, MessageBuffer::new()); + let mut term = + Term::new(&Default::default(), size, MessageBuffer::new(), Clipboard::new_nop()); let mut grid: Grid<Cell> = Grid::new(Line(3), Column(5), 0, Cell::default()); for i in 0..5 { for j in 0..2 { @@ -2190,7 +2200,8 @@ mod tests { padding_y: 0.0, dpr: 1.0, }; - let mut term = Term::new(&Default::default(), size, MessageBuffer::new()); + let mut term = + Term::new(&Default::default(), size, MessageBuffer::new(), Clipboard::new_nop()); let mut grid: Grid<Cell> = Grid::new(Line(1), Column(5), 0, Cell::default()); for i in 0..5 { grid[Line(0)][Column(i)].c = 'a'; @@ -2215,7 +2226,8 @@ mod tests { padding_y: 0.0, dpr: 1.0, }; - let mut term = Term::new(&Default::default(), size, MessageBuffer::new()); + let mut term = + Term::new(&Default::default(), size, MessageBuffer::new(), Clipboard::new_nop()); let mut grid: Grid<Cell> = Grid::new(Line(3), Column(3), 0, Cell::default()); for l in 0..3 { if l != 1 { @@ -2259,7 +2271,8 @@ mod tests { padding_y: 0.0, dpr: 1.0, }; - let mut term = Term::new(&Default::default(), size, MessageBuffer::new()); + let mut term = + Term::new(&Default::default(), size, MessageBuffer::new(), Clipboard::new_nop()); let cursor = Point::new(Line(0), Column(0)); term.configure_charset(CharsetIndex::G0, StandardCharset::SpecialCharacterAndLineDrawing); term.input('a'); @@ -2278,7 +2291,7 @@ mod tests { dpr: 1.0, }; let config: Config = Default::default(); - let mut term: Term = Term::new(&config, size, MessageBuffer::new()); + let mut term: Term = Term::new(&config, size, MessageBuffer::new(), Clipboard::new_nop()); term.change_font_size(font_size); let expected_font_size: Size = config.font().size() + Size::new(font_size); @@ -2307,7 +2320,7 @@ mod tests { dpr: 1.0, }; let config: Config = Default::default(); - let mut term: Term = Term::new(&config, size, MessageBuffer::new()); + let mut term: Term = Term::new(&config, size, MessageBuffer::new(), Clipboard::new_nop()); term.change_font_size(-100.0); @@ -2327,7 +2340,7 @@ mod tests { dpr: 1.0, }; let config: Config = Default::default(); - let mut term: Term = Term::new(&config, size, MessageBuffer::new()); + let mut term: Term = Term::new(&config, size, MessageBuffer::new(), Clipboard::new_nop()); term.change_font_size(10.0); term.reset_font_size(); @@ -2348,7 +2361,7 @@ mod tests { dpr: 1.0, }; let config: Config = Default::default(); - let mut term: Term = Term::new(&config, size, MessageBuffer::new()); + let mut term: Term = Term::new(&config, size, MessageBuffer::new(), Clipboard::new_nop()); // Add one line of scrollback term.grid.scroll_up(&(Line(0)..Line(1)), Line(1), &Cell::default()); @@ -2373,6 +2386,7 @@ mod benches { use std::mem; use std::path::Path; + use crate::clipboard::Clipboard; use crate::config::Config; use crate::grid::Grid; use crate::message_bar::MessageBuffer; @@ -2416,7 +2430,7 @@ mod benches { let config = Config::default(); - let mut terminal = Term::new(&config, size, MessageBuffer::new()); + let mut terminal = Term::new(&config, size, MessageBuffer::new(), Clipboard::new_nop()); mem::swap(&mut terminal.grid, &mut grid); let metrics = font::Metrics { diff --git a/alacritty_terminal/src/url.rs b/alacritty_terminal/src/url.rs index d3caf9fc..088cf657 100644 --- a/alacritty_terminal/src/url.rs +++ b/alacritty_terminal/src/url.rs @@ -148,6 +148,7 @@ mod tests { use unicode_width::UnicodeWidthChar; + use crate::clipboard::Clipboard; use crate::grid::Grid; use crate::index::{Column, Line, Point}; use crate::message_bar::MessageBuffer; @@ -166,7 +167,8 @@ mod tests { }; let width = input.chars().map(|c| if c.width() == Some(2) { 2 } else { 1 }).sum(); - let mut term = Term::new(&Default::default(), size, MessageBuffer::new()); + let mut term = + Term::new(&Default::default(), size, MessageBuffer::new(), Clipboard::new_nop()); let mut grid: Grid<Cell> = Grid::new(Line(1), Column(width), 0, Cell::default()); let mut i = 0; diff --git a/alacritty_terminal/src/window.rs b/alacritty_terminal/src/window.rs index a929a1b7..5c1457e5 100644 --- a/alacritty_terminal/src/window.rs +++ b/alacritty_terminal/src/window.rs @@ -12,12 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. use std::convert::From; +use std::ffi::c_void; use std::fmt::Display; use crate::gl; use glutin::dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize}; +#[cfg(target_os = "macos")] +use glutin::os::macos::WindowExt; #[cfg(not(any(target_os = "macos", windows)))] -use glutin::os::unix::EventsLoopExt; +use glutin::os::unix::{EventsLoopExt, WindowExt}; #[cfg(not(target_os = "macos"))] use glutin::Icon; use glutin::{ @@ -362,13 +365,11 @@ impl Window { target_os = "openbsd" ))] pub fn set_urgent(&self, is_urgent: bool) { - use glutin::os::unix::WindowExt; self.window().set_urgent(is_urgent); } #[cfg(target_os = "macos")] pub fn set_urgent(&self, is_urgent: bool) { - use glutin::os::macos::WindowExt; self.window().request_user_attention(is_urgent); } @@ -381,8 +382,6 @@ impl Window { #[cfg(not(any(target_os = "macos", target_os = "windows")))] pub fn get_window_id(&self) -> Option<usize> { - use glutin::os::unix::WindowExt; - match self.window().get_xlib_window() { Some(xlib_window) => Some(xlib_window as usize), None => None, @@ -416,6 +415,11 @@ impl Window { self.window().set_simple_fullscreen(fullscreen); } + #[cfg(not(any(target_os = "macos", target_os = "windows")))] + pub fn get_wayland_display(&self) -> Option<*mut c_void> { + self.window().get_wayland_display() + } + fn window(&self) -> &glutin::Window { self.windowed_context.window() } @@ -441,7 +445,6 @@ impl OsExtensions for Window {} ))] impl OsExtensions for Window { fn run_os_extensions(&self) { - use glutin::os::unix::WindowExt; use libc::getpid; use std::ffi::CStr; use std::ptr; |