diff --git a/src/main.rs b/src/main.rs index 55a1aa5..43d1734 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,6 +13,7 @@ use cosmic::{ clipboard, event, futures::SinkExt, keyboard::{Event as KeyEvent, KeyCode, Modifiers}, + mouse::{Button as MouseButton, Event as MouseEvent}, subscription::{self, Subscription}, window, Alignment, Event, Length, Padding, Point, }, @@ -165,6 +166,8 @@ pub struct Flags { #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum Action { Copy, + #[cfg(target_family = "unix")] + CopyPrimary, Find, PaneFocusDown, PaneFocusLeft, @@ -203,6 +206,8 @@ impl Action { pub fn message(self, entity_opt: Option) -> Message { match self { Action::Copy => Message::Copy(entity_opt), + #[cfg(target_family = "unix")] + Action::CopyPrimary => Message::CopyPrimary(entity_opt), Action::Find => Message::Find(true), Action::PaneFocusDown => Message::PaneFocusAdjacent(pane_grid::Direction::Down), Action::PaneFocusLeft => Message::PaneFocusAdjacent(pane_grid::Direction::Left), @@ -245,6 +250,7 @@ pub enum Message { AppTheme(AppTheme), Config(Config), Copy(Option), + CopyPrimary(Option), DefaultFont(usize), DefaultFontSize(usize), DefaultFontStretch(usize), @@ -257,6 +263,8 @@ pub enum Message { FindNext, FindPrevious, FindSearchValueChanged(String), + #[cfg(target_family = "unix")] + MiddleClick(pane_grid::Pane, Option), PaneClicked(pane_grid::Pane), PaneSplit(pane_grid::Axis), PaneToggleMaximized, @@ -916,6 +924,20 @@ impl Application for App { log::warn!("Failed to get focused pane"); } } + Message::CopyPrimary(entity_opt) => { + if let Some(tab_model) = self.pane_model.active() { + let entity = entity_opt.unwrap_or_else(|| tab_model.active()); + if let Some(terminal) = tab_model.data::>(entity) { + let terminal = terminal.lock().unwrap(); + let term = terminal.term.lock(); + if let Some(text) = term.selection_to_string() { + return clipboard::write_primary(text); + } + } + } else { + log::warn!("Failed to get focused pane"); + } + } Message::DefaultFont(index) => { match self.font_names.get(index) { Some(font_name) => { @@ -1050,6 +1072,17 @@ impl Application for App { Message::FindSearchValueChanged(value) => { self.find_search_value = value; } + #[cfg(target_family = "unix")] + Message::MiddleClick(pane, entity_opt) => { + self.pane_model.focus = pane; + return Command::batch([ + self.update_focus(), + clipboard::read_primary(move |value_opt| match value_opt { + Some(value) => message::app(Message::PasteValue(entity_opt, value)), + None => message::none(), + }), + ]); + } Message::Modifiers(modifiers) => { self.modifiers = modifiers; } @@ -1409,6 +1442,7 @@ impl Application for App { } let entity = tab_model.active(); + let entity_middle_click = tab_model.active(); let terminal_id = self .terminal_ids .get(&pane) @@ -1416,10 +1450,17 @@ impl Application for App { .unwrap_or_else(widget::Id::unique); match tab_model.data::>(entity) { Some(terminal) => { - let terminal_box = terminal_box(terminal).id(terminal_id).on_context_menu( + let mut terminal_box = terminal_box(terminal).id(terminal_id).on_context_menu( move |position_opt| Message::TabContextMenu(entity, position_opt), ); + #[cfg(target_family = "unix")] + { + terminal_box = terminal_box.on_middle_click(move || { + Message::MiddleClick(pane, Some(entity_middle_click)) + }); + } + let context_menu = { let terminal = terminal.lock().unwrap(); terminal.context_menu @@ -1529,6 +1570,9 @@ impl Application for App { Event::Keyboard(KeyEvent::ModifiersChanged(modifiers)) => { Some(Message::Modifiers(modifiers)) } + Event::Mouse(MouseEvent::ButtonReleased(MouseButton::Left)) => { + Some(Message::CopyPrimary(None)) + } _ => None, }), subscription::channel( diff --git a/src/terminal_box.rs b/src/terminal_box.rs index b1afe61..b5ce7fb 100644 --- a/src/terminal_box.rs +++ b/src/terminal_box.rs @@ -47,6 +47,7 @@ pub struct TerminalBox<'a, Message> { click_timing: Duration, context_menu: Option, on_context_menu: Option) -> Message + 'a>>, + on_middle_click: Option Message + 'a>>, } impl<'a, Message> TerminalBox<'a, Message> @@ -61,6 +62,7 @@ where click_timing: Duration::from_millis(500), context_menu: None, on_context_menu: None, + on_middle_click: None, } } @@ -91,6 +93,11 @@ where self.on_context_menu = Some(Box::new(on_context_menu)); self } + + pub fn on_middle_click(mut self, on_middle_click: impl Fn() -> Message + 'a) -> Self { + self.on_middle_click = Some(Box::new(on_middle_click)); + self + } } pub fn terminal_box<'a, Message>(terminal: &'a Mutex) -> TerminalBox<'a, Message> @@ -575,7 +582,7 @@ where layout: Layout<'_>, cursor_position: mouse::Cursor, _renderer: &Renderer, - clipboard: &mut dyn Clipboard, + _clipboard: &mut dyn Clipboard, shell: &mut Shell<'_, Message>, _viewport: &Rectangle, ) -> Status { @@ -977,10 +984,9 @@ where } } } - } else if let Button::Middle = button { - #[cfg(target_family = "unix")] - if let Some(value) = clipboard.read_primary() { - terminal.paste(value); + } else if button == Button::Middle { + if let Some(on_middle_click) = &self.on_middle_click { + shell.publish(on_middle_click()); } } @@ -999,13 +1005,6 @@ where } } Event::Mouse(MouseEvent::ButtonReleased(Button::Left)) => { - #[cfg(target_family = "unix")] - if let Some(Dragging::Buffer) = state.dragging { - let term = terminal.term.lock(); - if let Some(text) = term.selection_to_string() { - clipboard.write_primary(text); - } - } state.dragging = None; status = Status::Captured; }