Skip to content

Commit

Permalink
Use hollow block cursor for non-focused terminals
Browse files Browse the repository at this point in the history
  • Loading branch information
snaggen authored and jackpot51 committed Jan 23, 2025
1 parent 75787a8 commit 23a5851
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 29 deletions.
61 changes: 37 additions & 24 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,8 @@ pub enum Message {
UseBrightBold(bool),
WindowClose,
WindowNew,
WindowFocused,
WindowUnfocused,
ZoomIn,
ZoomOut,
ZoomReset,
Expand Down Expand Up @@ -575,7 +577,8 @@ impl App {
fn update_focus(&self) -> Task<Message> {
if self.find {
widget::text_input::focus(self.find_search_id.clone())
} else if let Some(terminal_id) = self.terminal_ids.get(&self.pane_model.focus).cloned() {
} else if let Some(terminal_id) = self.terminal_ids.get(&self.pane_model.focused()).cloned()
{
widget::text_input::focus(terminal_id)
} else {
Task::none()
Expand All @@ -584,7 +587,7 @@ impl App {

// Call this any time the tab changes
fn update_title(&mut self, pane: Option<pane_grid::Pane>) -> Task<Message> {
let pane = pane.unwrap_or(self.pane_model.focus);
let pane = pane.unwrap_or(self.pane_model.focused());
if let Some(tab_model) = self.pane_model.panes.get(pane) {
let (header_title, window_title) = match tab_model.text(tab_model.active()) {
Some(tab_title) => (
Expand Down Expand Up @@ -1221,7 +1224,7 @@ impl App {
pane: pane_grid::Pane,
profile_id_opt: Option<ProfileId>,
) -> Task<Message> {
self.pane_model.focus = pane;
self.pane_model.set_focus(pane);
match &self.term_event_tx_opt {
Some(term_event_tx) => {
let colors = self
Expand All @@ -1238,7 +1241,7 @@ impl App {
});
match colors {
Some(colors) => {
let current_pane = self.pane_model.focus;
let current_pane = self.pane_model.focused();
if let Some(tab_model) = self.pane_model.active_mut() {
// Use the startup options, profile options, or defaults
let (options, tab_title_override) = match self.startup_options.take() {
Expand Down Expand Up @@ -1482,7 +1485,7 @@ impl Application for App {

let pane_model = TerminalPaneGrid::new(segmented_button::ModelBuilder::default().build());
let mut terminal_ids = HashMap::new();
terminal_ids.insert(pane_model.focus, widget::Id::unique());
terminal_ids.insert(pane_model.focused(), widget::Id::unique());

let mut app = Self {
core,
Expand Down Expand Up @@ -1949,7 +1952,7 @@ impl Application for App {
}
}
Message::Drop(Some((pane, entity, data))) => {
self.pane_model.focus = pane;
self.pane_model.set_focus(pane);
if let Ok(value) = shlex::try_join(data.paths.iter().filter_map(|p| p.to_str())) {
return Task::batch([
self.update_focus(),
Expand Down Expand Up @@ -2012,7 +2015,7 @@ impl Application for App {
self.find_search_value = value;
}
Message::MiddleClick(pane, entity_opt) => {
self.pane_model.focus = pane;
self.pane_model.set_focus(pane);
return Task::batch([
self.update_focus(),
clipboard::read_primary().map(move |value_opt| match value_opt {
Expand Down Expand Up @@ -2040,20 +2043,20 @@ impl Application for App {
self.modifiers = modifiers;
}
Message::MouseEnter(pane) => {
self.pane_model.focus = pane;
self.pane_model.set_focus(pane);
return self.update_focus();
}
Message::Opacity(opacity) => {
config_set!(opacity, cmp::min(100, opacity));
}
Message::PaneClicked(pane) => {
self.pane_model.focus = pane;
self.pane_model.set_focus(pane);
return self.update_title(Some(pane));
}
Message::PaneSplit(axis) => {
let result = self.pane_model.panes.split(
axis,
self.pane_model.focus,
self.pane_model.focused(),
segmented_button::ModelBuilder::default().build(),
);
if let Some((pane, _)) = result {
Expand All @@ -2068,17 +2071,17 @@ impl Application for App {
if self.pane_model.panes.maximized().is_some() {
self.pane_model.panes.restore();
} else {
self.pane_model.panes.maximize(self.pane_model.focus);
self.pane_model.panes.maximize(self.pane_model.focused());
}
return self.update_focus();
}
Message::PaneFocusAdjacent(direction) => {
if let Some(adjacent) = self
.pane_model
.panes
.adjacent(self.pane_model.focus, direction)
.adjacent(self.pane_model.focused(), direction)
{
self.pane_model.focus = adjacent;
self.pane_model.set_focus(adjacent);
return self.update_title(Some(adjacent));
}
}
Expand Down Expand Up @@ -2154,7 +2157,8 @@ impl Application for App {
return self.save_profiles();
}
Message::ProfileOpen(profile_id) => {
return self.create_and_focus_new_terminal(self.pane_model.focus, Some(profile_id));
return self
.create_and_focus_new_terminal(self.pane_model.focused(), Some(profile_id));
}
Message::ProfileRemove(profile_id) => {
// Reset matching terminals to default profile
Expand Down Expand Up @@ -2292,10 +2296,10 @@ impl Application for App {
// If that was the last tab, close current pane
if tab_model.iter().next().is_none() {
if let Some((_state, sibling)) =
self.pane_model.panes.close(self.pane_model.focus)
self.pane_model.panes.close(self.pane_model.focused())
{
self.terminal_ids.remove(&self.pane_model.focus);
self.pane_model.focus = sibling;
self.terminal_ids.remove(&self.pane_model.focused());
self.pane_model.set_focus(sibling);
} else {
//Last pane, closing window
if let Some(window_id) = self.core.main_window_id() {
Expand Down Expand Up @@ -2343,17 +2347,17 @@ impl Application for App {

// Shift focus to the pane / terminal
// with the context menu
self.pane_model.focus = pane;
self.pane_model.set_focus(pane);
return self.update_title(Some(pane));
}
Message::TabNew => {
return self.create_and_focus_new_terminal(
self.pane_model.focus,
self.pane_model.focused(),
self.get_default_profile(),
)
}
Message::TabNewNoProfile => {
return self.create_and_focus_new_terminal(self.pane_model.focus, None)
return self.create_and_focus_new_terminal(self.pane_model.focused(), None)
}
Message::TabNext => {
if let Some(tab_model) = self.pane_model.active() {
Expand Down Expand Up @@ -2500,10 +2504,10 @@ impl Application for App {

// First, close other panes
while let Some((_state, sibling)) =
self.pane_model.panes.close(self.pane_model.focus)
self.pane_model.panes.close(self.pane_model.focused())
{
self.terminal_ids.remove(&self.pane_model.focus);
self.pane_model.focus = sibling;
self.terminal_ids.remove(&self.pane_model.focused());
self.pane_model.set_focus(sibling);
}

// Next, close all tabs in the active pane
Expand Down Expand Up @@ -2573,6 +2577,13 @@ impl Application for App {
log::error!("failed to get current executable path: {}", err);
}
},
Message::WindowFocused => {
self.pane_model.update_terminal_focus();
return self.update_focus();
}
Message::WindowUnfocused => {
self.pane_model.unfocus_all_terminals();
}
Message::ZoomIn => {
return self.update_render_active_pane_zoom(message);
}
Expand Down Expand Up @@ -2673,6 +2684,8 @@ impl Application for App {
})
.on_middle_click(move || Message::MiddleClick(pane, Some(entity_middle_click)))
.on_open_hyperlink(Some(Box::new(Message::LaunchUrl)))
.on_window_focused(|| Message::WindowFocused)
.on_window_unfocused(|| Message::WindowUnfocused)
.opacity(self.config.opacity_ratio())
.padding(space_xxs)
.show_headerbar(self.config.show_headerbar);
Expand All @@ -2697,7 +2710,7 @@ impl Application for App {
}

//Only draw find in the currently focused pane
if self.find && pane == self.pane_model.focus {
if self.find && pane == self.pane_model.focused() {
let find_input = widget::text_input::text_input(
fl!("find-placeholder"),
&self.find_search_value,
Expand Down
38 changes: 34 additions & 4 deletions src/terminal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ use alacritty_terminal::{
Term,
};
use cosmic::{
iced::advanced::graphics::text::font_system,
iced::mouse::ScrollDelta,
iced::{advanced::graphics::text::font_system, mouse::ScrollDelta},
widget::{pane_grid, segmented_button},
};
use cosmic_text::{
Expand All @@ -31,7 +30,7 @@ use std::{
io, mem,
sync::{
atomic::{AtomicU32, Ordering},
Arc, Weak,
Arc, Mutex, Weak,
},
time::Instant,
};
Expand Down Expand Up @@ -155,7 +154,7 @@ type TabModel = segmented_button::Model<segmented_button::SingleSelect>;
pub struct TerminalPaneGrid {
pub panes: pane_grid::State<TabModel>,
pub panes_created: usize,
pub focus: pane_grid::Pane,
focus: pane_grid::Pane,
}

impl TerminalPaneGrid {
Expand All @@ -176,6 +175,34 @@ impl TerminalPaneGrid {
pub fn active_mut(&mut self) -> Option<&mut TabModel> {
self.panes.get_mut(self.focus)
}
pub fn set_focus(&mut self, pane: pane_grid::Pane) {
self.focus = pane;
self.update_terminal_focus();
}
pub fn focused(&self) -> pane_grid::Pane {
self.focus
}

pub fn update_terminal_focus(&self) {
for (pane, tab_model) in self.panes.panes.iter() {
let entity = tab_model.active();
if let Some(terminal) = tab_model.data::<Mutex<Terminal>>(entity) {
let mut terminal = terminal.lock().unwrap();
terminal.is_focused = self.focus == *pane;
terminal.update();
}
}
}
pub fn unfocus_all_terminals(&self) {
for (_pane, tab_model) in self.panes.panes.iter() {
let entity = tab_model.active();
if let Some(terminal) = tab_model.data::<Mutex<Terminal>>(entity) {
let mut terminal = terminal.lock().unwrap();
terminal.is_focused = false;
terminal.update();
}
}
}
}

#[derive(Debug, PartialEq, Eq, Hash, Clone)]
Expand Down Expand Up @@ -219,6 +246,7 @@ pub struct Terminal {
pub active_regex_match: Option<alacritty_terminal::term::search::Match>,
bold_font_weight: Weight,
buffer: Arc<Buffer>,
is_focused: bool,
colors: Colors,
default_attrs: Attrs<'static>,
dim_font_weight: Weight,
Expand Down Expand Up @@ -324,6 +352,7 @@ impl Terminal {
term,
use_bright_bold,
zoom_adj: Default::default(),
is_focused: true,
})
}

Expand Down Expand Up @@ -787,6 +816,7 @@ impl Terminal {
// Change color if cursor
if indexed.point == grid.cursor.point
&& term.renderable_content().cursor.shape == CursorShape::Block
&& self.is_focused
{
//Use specific cursor color if requested
if term.colors()[NamedColor::Cursor].is_some() {
Expand Down
53 changes: 52 additions & 1 deletion src/terminal_box.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ pub struct TerminalBox<'a, Message> {
mouse_inside_boundary: Option<bool>,
on_middle_click: Option<Box<dyn Fn() -> Message + 'a>>,
on_open_hyperlink: Option<Box<dyn Fn(String) -> Message + 'a>>,
on_window_focused: Option<Box<dyn Fn() -> Message + 'a>>,
on_window_unfocused: Option<Box<dyn Fn() -> Message + 'a>>,
key_binds: HashMap<KeyBind, Action>,
}

Expand All @@ -82,6 +84,8 @@ where
on_middle_click: None,
key_binds: key_binds(),
on_open_hyperlink: None,
on_window_focused: None,
on_window_unfocused: None,
}
}

Expand Down Expand Up @@ -145,6 +149,16 @@ where
self.on_open_hyperlink = on_open_hyperlink;
self
}

pub fn on_window_focused(mut self, on_window_focused: impl Fn() -> Message + 'a) -> Self {
self.on_window_focused = Some(Box::new(on_window_focused));
self
}

pub fn on_window_unfocused(mut self, on_window_unfocused: impl Fn() -> Message + 'a) -> Self {
self.on_window_unfocused = Some(Box::new(on_window_unfocused));
self
}
}

pub fn terminal_box<Message>(terminal: &Mutex<Terminal>) -> TerminalBox<'_, Message>
Expand Down Expand Up @@ -662,7 +676,30 @@ where
};
renderer.fill_quad(quad, color);
}
CursorShape::HollowBlock => {} // TODO not sure when this would even be activated
CursorShape::Block if !state.is_focused => {
let quad = Quad {
bounds: Rectangle::new(top_left, Size::new(width, height)),
border: Border {
width: 1.0,
color,
..Default::default()
},
..Default::default()
};
renderer.fill_quad(quad, Color::TRANSPARENT);
}
CursorShape::HollowBlock => {
let quad = Quad {
bounds: Rectangle::new(top_left, Size::new(width, height)),
border: Border {
width: 1.0,
color,
..Default::default()
},
..Default::default()
};
renderer.fill_quad(quad, Color::TRANSPARENT);
}
CursorShape::Block | CursorShape::Hidden => {} // Block is handled seperately
}
}
Expand Down Expand Up @@ -691,6 +728,20 @@ where
let is_mouse_mode = terminal.term.lock().mode().intersects(TermMode::MOUSE_MODE);
let mut status = Status::Ignored;
match event {
Event::Window(event) => match event {
cosmic::iced::window::Event::Focused => {
if let Some(on_window_focused) = &self.on_window_focused {
shell.publish(on_window_focused());
}
}
cosmic::iced::window::Event::Unfocused => {
state.is_focused = false;
if let Some(on_window_unfocused) = &self.on_window_unfocused {
shell.publish(on_window_unfocused());
}
}
_ => {}
},
Event::Keyboard(KeyEvent::KeyPressed {
key: Key::Named(named),
modified_key: Key::Named(modified_named),
Expand Down

0 comments on commit 23a5851

Please sign in to comment.