mirror of
https://github.com/wez/wezterm.git
synced 2024-11-28 01:06:37 +03:00
move Tabs -> Mux windows hash
This commit is contained in:
parent
a1bdddd8e5
commit
e69290715b
@ -4,11 +4,12 @@ use crate::config::Config;
|
|||||||
use crate::failure::Error;
|
use crate::failure::Error;
|
||||||
use crate::font::FontConfiguration;
|
use crate::font::FontConfiguration;
|
||||||
use crate::guicommon::host::{HostHelper, HostImpl, TabHost};
|
use crate::guicommon::host::{HostHelper, HostImpl, TabHost};
|
||||||
use crate::guicommon::tabs::Tabs;
|
|
||||||
use crate::guicommon::window::{Dimensions, TerminalWindow};
|
use crate::guicommon::window::{Dimensions, TerminalWindow};
|
||||||
use crate::guiloop::glutinloop::GuiEventLoop;
|
use crate::guiloop::glutinloop::GuiEventLoop;
|
||||||
use crate::guiloop::SessionTerminated;
|
use crate::guiloop::SessionTerminated;
|
||||||
use crate::mux::tab::{Tab, TabId};
|
use crate::mux::tab::{Tab, TabId};
|
||||||
|
use crate::mux::window::WindowId;
|
||||||
|
use crate::mux::Mux;
|
||||||
use crate::opengl::render::Renderer;
|
use crate::opengl::render::Renderer;
|
||||||
use glium;
|
use glium;
|
||||||
use glium::glutin::dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize};
|
use glium::glutin::dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize};
|
||||||
@ -82,17 +83,15 @@ pub struct GliumTerminalWindow {
|
|||||||
last_mouse_coords: PhysicalPosition,
|
last_mouse_coords: PhysicalPosition,
|
||||||
last_modifiers: KeyModifiers,
|
last_modifiers: KeyModifiers,
|
||||||
allow_received_character: bool,
|
allow_received_character: bool,
|
||||||
tabs: Tabs,
|
mux_window_id: WindowId,
|
||||||
have_pending_resize_check: bool,
|
have_pending_resize_check: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TerminalWindow for GliumTerminalWindow {
|
impl TerminalWindow for GliumTerminalWindow {
|
||||||
fn get_tabs(&self) -> &Tabs {
|
fn get_mux_window_id(&self) -> WindowId {
|
||||||
&self.tabs
|
self.mux_window_id
|
||||||
}
|
|
||||||
fn get_tabs_mut(&mut self) -> &mut Tabs {
|
|
||||||
&mut self.tabs
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn config(&self) -> &Arc<Config> {
|
fn config(&self) -> &Arc<Config> {
|
||||||
&self.config
|
&self.config
|
||||||
}
|
}
|
||||||
@ -115,9 +114,6 @@ impl TerminalWindow for GliumTerminalWindow {
|
|||||||
fn recreate_texture_atlas(&mut self, size: u32) -> Result<(), Error> {
|
fn recreate_texture_atlas(&mut self, size: u32) -> Result<(), Error> {
|
||||||
self.renderer.recreate_atlas(&self.host.display, size)
|
self.renderer.recreate_atlas(&self.host.display, size)
|
||||||
}
|
}
|
||||||
fn renderer_and_tab(&mut self) -> (&mut Renderer, &Rc<Tab>) {
|
|
||||||
(&mut self.renderer, self.tabs.get_active().unwrap())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tab_was_created(&mut self, tab: &Rc<Tab>) -> Result<(), Error> {
|
fn tab_was_created(&mut self, tab: &Rc<Tab>) -> Result<(), Error> {
|
||||||
self.event_loop.register_tab(tab)
|
self.event_loop.register_tab(tab)
|
||||||
@ -242,6 +238,9 @@ impl GliumTerminalWindow {
|
|||||||
let height = height as u16;
|
let height = height as u16;
|
||||||
let renderer = Renderer::new(&host.display, width, height, fonts, palette)?;
|
let renderer = Renderer::new(&host.display, width, height, fonts, palette)?;
|
||||||
|
|
||||||
|
let mux = Mux::get().unwrap();
|
||||||
|
let mux_window_id = mux.add_new_window_with_tab(tab)?;
|
||||||
|
|
||||||
Ok(GliumTerminalWindow {
|
Ok(GliumTerminalWindow {
|
||||||
host,
|
host,
|
||||||
event_loop: Rc::clone(event_loop),
|
event_loop: Rc::clone(event_loop),
|
||||||
@ -255,7 +254,7 @@ impl GliumTerminalWindow {
|
|||||||
last_mouse_coords: PhysicalPosition::new(0.0, 0.0),
|
last_mouse_coords: PhysicalPosition::new(0.0, 0.0),
|
||||||
last_modifiers: Default::default(),
|
last_modifiers: Default::default(),
|
||||||
allow_received_character: false,
|
allow_received_character: false,
|
||||||
tabs: Tabs::new(tab),
|
mux_window_id,
|
||||||
have_pending_resize_check: false,
|
have_pending_resize_check: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -286,7 +285,8 @@ impl GliumTerminalWindow {
|
|||||||
position: PhysicalPosition,
|
position: PhysicalPosition,
|
||||||
modifiers: glium::glutin::ModifiersState,
|
modifiers: glium::glutin::ModifiersState,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let tab = match self.tabs.get_active() {
|
let mux = Mux::get().unwrap();
|
||||||
|
let tab = match mux.get_active_tab_for_window(self.get_mux_window_id()) {
|
||||||
Some(tab) => tab,
|
Some(tab) => tab,
|
||||||
None => return Ok(()),
|
None => return Ok(()),
|
||||||
};
|
};
|
||||||
@ -326,7 +326,8 @@ impl GliumTerminalWindow {
|
|||||||
button: glutin::MouseButton,
|
button: glutin::MouseButton,
|
||||||
modifiers: glium::glutin::ModifiersState,
|
modifiers: glium::glutin::ModifiersState,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let tab = match self.tabs.get_active() {
|
let mux = Mux::get().unwrap();
|
||||||
|
let tab = match mux.get_active_tab_for_window(self.get_mux_window_id()) {
|
||||||
Some(tab) => tab,
|
Some(tab) => tab,
|
||||||
None => return Ok(()),
|
None => return Ok(()),
|
||||||
};
|
};
|
||||||
@ -391,7 +392,8 @@ impl GliumTerminalWindow {
|
|||||||
_ => return Ok(()),
|
_ => return Ok(()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let tab = match self.tabs.get_active() {
|
let mux = Mux::get().unwrap();
|
||||||
|
let tab = match mux.get_active_tab_for_window(self.get_mux_window_id()) {
|
||||||
Some(tab) => tab,
|
Some(tab) => tab,
|
||||||
None => return Ok(()),
|
None => return Ok(()),
|
||||||
};
|
};
|
||||||
@ -610,7 +612,8 @@ impl GliumTerminalWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn key_event(&mut self, event: glium::glutin::KeyboardInput) -> Result<(), Error> {
|
fn key_event(&mut self, event: glium::glutin::KeyboardInput) -> Result<(), Error> {
|
||||||
let tab = match self.tabs.get_active() {
|
let mux = Mux::get().unwrap();
|
||||||
|
let tab = match mux.get_active_tab_for_window(self.get_mux_window_id()) {
|
||||||
Some(tab) => tab,
|
Some(tab) => tab,
|
||||||
None => return Ok(()),
|
None => return Ok(()),
|
||||||
};
|
};
|
||||||
@ -626,7 +629,7 @@ impl GliumTerminalWindow {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.host.process_gui_shortcuts(&**tab, mods, key)? {
|
if self.host.process_gui_shortcuts(&*tab, mods, key)? {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -678,7 +681,8 @@ impl GliumTerminalWindow {
|
|||||||
// eprintln!("ReceivedCharacter {} {:?}", c as u32, c);
|
// eprintln!("ReceivedCharacter {} {:?}", c as u32, c);
|
||||||
if self.allow_received_character {
|
if self.allow_received_character {
|
||||||
self.allow_received_character = false;
|
self.allow_received_character = false;
|
||||||
let tab = match self.tabs.get_active() {
|
let mux = Mux::get().unwrap();
|
||||||
|
let tab = match mux.get_active_tab_for_window(self.get_mux_window_id()) {
|
||||||
Some(tab) => tab,
|
Some(tab) => tab,
|
||||||
None => return Ok(()),
|
None => return Ok(()),
|
||||||
};
|
};
|
||||||
|
@ -3,7 +3,6 @@ use crate::mux::tab::{alloc_tab_id, Tab, TabId};
|
|||||||
use crate::{Child, MasterPty};
|
use crate::{Child, MasterPty};
|
||||||
use failure::Error;
|
use failure::Error;
|
||||||
use std::cell::{RefCell, RefMut};
|
use std::cell::{RefCell, RefMut};
|
||||||
use std::rc::Rc;
|
|
||||||
use term::{KeyCode, KeyModifiers, MouseEvent, Terminal, TerminalHost};
|
use term::{KeyCode, KeyModifiers, MouseEvent, Terminal, TerminalHost};
|
||||||
|
|
||||||
pub struct LocalTab {
|
pub struct LocalTab {
|
||||||
@ -99,74 +98,3 @@ impl Drop for LocalTab {
|
|||||||
self.process.borrow_mut().wait().ok();
|
self.process.borrow_mut().wait().ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Tabs {
|
|
||||||
tabs: Vec<Rc<Tab>>,
|
|
||||||
active: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Tabs {
|
|
||||||
pub fn new(tab: &Rc<Tab>) -> Self {
|
|
||||||
Self {
|
|
||||||
tabs: vec![Rc::clone(tab)],
|
|
||||||
active: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push(&mut self, tab: &Rc<Tab>) {
|
|
||||||
self.tabs.push(Rc::clone(tab))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
|
||||||
self.tabs.is_empty()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
|
||||||
self.tabs.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_by_idx(&self, idx: usize) -> Option<&Rc<Tab>> {
|
|
||||||
self.tabs.get(idx)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn idx_by_id(&self, id: TabId) -> Option<usize> {
|
|
||||||
for (idx, t) in self.tabs.iter().enumerate() {
|
|
||||||
if t.tab_id() == id {
|
|
||||||
return Some(idx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn remove_by_id(&mut self, id: TabId) {
|
|
||||||
if let Some(idx) = self.idx_by_id(id) {
|
|
||||||
self.tabs.remove(idx);
|
|
||||||
let len = self.tabs.len();
|
|
||||||
if len > 0 && self.active == idx && idx >= len {
|
|
||||||
self.set_active(len - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_active(&self) -> Option<&Rc<Tab>> {
|
|
||||||
self.get_by_idx(self.active)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn get_active_idx(&self) -> usize {
|
|
||||||
self.active
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_active(&mut self, idx: usize) {
|
|
||||||
assert!(idx < self.tabs.len());
|
|
||||||
self.active = idx;
|
|
||||||
self.get_by_idx(idx)
|
|
||||||
.unwrap()
|
|
||||||
.renderer()
|
|
||||||
.make_all_lines_dirty();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn iter(&self) -> impl Iterator<Item = &Rc<Tab>> {
|
|
||||||
self.tabs.iter()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::font::FontConfiguration;
|
use crate::font::FontConfiguration;
|
||||||
use crate::guicommon::tabs::{LocalTab, Tabs};
|
use crate::guicommon::tabs::LocalTab;
|
||||||
use crate::mux::tab::{Tab, TabId};
|
use crate::mux::tab::{Tab, TabId};
|
||||||
|
use crate::mux::window::WindowId;
|
||||||
|
use crate::mux::Mux;
|
||||||
use crate::opengl::render::Renderer;
|
use crate::opengl::render::Renderer;
|
||||||
use crate::opengl::textureatlas::OutOfTextureSpace;
|
use crate::opengl::textureatlas::OutOfTextureSpace;
|
||||||
use crate::openpty;
|
use crate::openpty;
|
||||||
@ -25,12 +27,10 @@ pub struct Dimensions {
|
|||||||
/// A number of methods need to be provided by the window in order to
|
/// A number of methods need to be provided by the window in order to
|
||||||
/// unlock the use of the provided methods towards the bottom of the trait.
|
/// unlock the use of the provided methods towards the bottom of the trait.
|
||||||
pub trait TerminalWindow {
|
pub trait TerminalWindow {
|
||||||
fn get_tabs_mut(&mut self) -> &mut Tabs;
|
|
||||||
fn get_tabs(&self) -> &Tabs;
|
|
||||||
fn set_window_title(&mut self, title: &str) -> Result<(), Error>;
|
fn set_window_title(&mut self, title: &str) -> Result<(), Error>;
|
||||||
|
fn get_mux_window_id(&self) -> WindowId;
|
||||||
fn frame(&self) -> glium::Frame;
|
fn frame(&self) -> glium::Frame;
|
||||||
fn renderer(&mut self) -> &mut Renderer;
|
fn renderer(&mut self) -> &mut Renderer;
|
||||||
fn renderer_and_tab(&mut self) -> (&mut Renderer, &Rc<Tab>);
|
|
||||||
fn recreate_texture_atlas(&mut self, size: u32) -> Result<(), Error>;
|
fn recreate_texture_atlas(&mut self, size: u32) -> Result<(), Error>;
|
||||||
fn advise_renderer_that_scaling_has_changed(
|
fn advise_renderer_that_scaling_has_changed(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -49,31 +49,51 @@ pub trait TerminalWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn activate_tab(&mut self, tab_idx: usize) -> Result<(), Error> {
|
fn activate_tab(&mut self, tab_idx: usize) -> Result<(), Error> {
|
||||||
let max = self.get_tabs().len();
|
let mux = Mux::get().unwrap();
|
||||||
|
let mut window = mux
|
||||||
|
.get_window_mut(self.get_mux_window_id())
|
||||||
|
.ok_or_else(|| format_err!("no such window"))?;
|
||||||
|
|
||||||
|
let max = window.len();
|
||||||
if tab_idx < max {
|
if tab_idx < max {
|
||||||
self.get_tabs_mut().set_active(tab_idx);
|
window.set_active(tab_idx);
|
||||||
|
|
||||||
|
drop(window);
|
||||||
self.update_title();
|
self.update_title();
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn activate_tab_relative(&mut self, delta: isize) -> Result<(), Error> {
|
fn activate_tab_relative(&mut self, delta: isize) -> Result<(), Error> {
|
||||||
let max = self.get_tabs().len();
|
let mux = Mux::get().unwrap();
|
||||||
let active = self.get_tabs().get_active_idx() as isize;
|
let window = mux
|
||||||
|
.get_window(self.get_mux_window_id())
|
||||||
|
.ok_or_else(|| format_err!("no such window"))?;
|
||||||
|
|
||||||
|
let max = window.len();
|
||||||
|
let active = window.get_active_idx() as isize;
|
||||||
let tab = active + delta;
|
let tab = active + delta;
|
||||||
let tab = if tab < 0 { max as isize + tab } else { tab };
|
let tab = if tab < 0 { max as isize + tab } else { tab };
|
||||||
|
drop(window);
|
||||||
self.activate_tab(tab as usize % max)
|
self.activate_tab(tab as usize % max)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_title(&mut self) {
|
fn update_title(&mut self) {
|
||||||
let num_tabs = self.get_tabs().len();
|
let mux = Mux::get().unwrap();
|
||||||
|
let window = match mux.get_window(self.get_mux_window_id()) {
|
||||||
|
Some(window) => window,
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
let num_tabs = window.len();
|
||||||
|
|
||||||
if num_tabs == 0 {
|
if num_tabs == 0 {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let tab_no = self.get_tabs().get_active_idx();
|
let tab_no = window.get_active_idx();
|
||||||
|
|
||||||
let title = self.get_tabs().get_active().unwrap().get_title();
|
let title = window.get_active().unwrap().get_title();
|
||||||
|
|
||||||
|
drop(window);
|
||||||
|
|
||||||
if num_tabs == 1 {
|
if num_tabs == 1 {
|
||||||
self.set_window_title(&title).ok();
|
self.set_window_title(&title).ok();
|
||||||
@ -84,7 +104,8 @@ pub trait TerminalWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn paint_if_needed(&mut self) -> Result<(), Error> {
|
fn paint_if_needed(&mut self) -> Result<(), Error> {
|
||||||
let tab = match self.get_tabs().get_active() {
|
let mux = Mux::get().unwrap();
|
||||||
|
let tab = match mux.get_active_tab_for_window(self.get_mux_window_id()) {
|
||||||
Some(tab) => tab,
|
Some(tab) => tab,
|
||||||
None => return Ok(()),
|
None => return Ok(()),
|
||||||
};
|
};
|
||||||
@ -98,8 +119,14 @@ pub trait TerminalWindow {
|
|||||||
fn paint(&mut self) -> Result<(), Error> {
|
fn paint(&mut self) -> Result<(), Error> {
|
||||||
let mut target = self.frame();
|
let mut target = self.frame();
|
||||||
|
|
||||||
|
let mux = Mux::get().unwrap();
|
||||||
|
let tab = match mux.get_active_tab_for_window(self.get_mux_window_id()) {
|
||||||
|
Some(tab) => tab,
|
||||||
|
None => return Ok(()),
|
||||||
|
};
|
||||||
|
|
||||||
let res = {
|
let res = {
|
||||||
let (renderer, tab) = self.renderer_and_tab();
|
let renderer = self.renderer();
|
||||||
renderer.paint(&mut target, &mut *tab.renderer())
|
renderer.paint(&mut target, &mut *tab.renderer())
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -117,11 +144,7 @@ pub trait TerminalWindow {
|
|||||||
if let Some(&OutOfTextureSpace { size }) = err.downcast_ref::<OutOfTextureSpace>() {
|
if let Some(&OutOfTextureSpace { size }) = err.downcast_ref::<OutOfTextureSpace>() {
|
||||||
eprintln!("out of texture space, allocating {}", size);
|
eprintln!("out of texture space, allocating {}", size);
|
||||||
self.recreate_texture_atlas(size)?;
|
self.recreate_texture_atlas(size)?;
|
||||||
self.get_tabs_mut()
|
tab.renderer().make_all_lines_dirty();
|
||||||
.get_active()
|
|
||||||
.unwrap()
|
|
||||||
.renderer()
|
|
||||||
.make_all_lines_dirty();
|
|
||||||
// Recursively initiate a new paint
|
// Recursively initiate a new paint
|
||||||
return self.paint();
|
return self.paint();
|
||||||
}
|
}
|
||||||
@ -145,6 +168,8 @@ pub trait TerminalWindow {
|
|||||||
let process = slave.spawn_command(cmd)?;
|
let process = slave.spawn_command(cmd)?;
|
||||||
eprintln!("spawned: {:?}", process);
|
eprintln!("spawned: {:?}", process);
|
||||||
|
|
||||||
|
let mux = Mux::get().unwrap();
|
||||||
|
|
||||||
let terminal = term::Terminal::new(
|
let terminal = term::Terminal::new(
|
||||||
rows,
|
rows,
|
||||||
cols,
|
cols,
|
||||||
@ -155,8 +180,13 @@ pub trait TerminalWindow {
|
|||||||
let tab: Rc<Tab> = Rc::new(LocalTab::new(terminal, process, pty));
|
let tab: Rc<Tab> = Rc::new(LocalTab::new(terminal, process, pty));
|
||||||
let tab_id = tab.tab_id();
|
let tab_id = tab.tab_id();
|
||||||
|
|
||||||
self.get_tabs_mut().push(&tab);
|
let len = {
|
||||||
let len = self.get_tabs().len();
|
let mut window = mux
|
||||||
|
.get_window_mut(self.get_mux_window_id())
|
||||||
|
.ok_or_else(|| format_err!("no such window!?"))?;
|
||||||
|
window.push(&tab);
|
||||||
|
window.len()
|
||||||
|
};
|
||||||
self.activate_tab(len - 1)?;
|
self.activate_tab(len - 1)?;
|
||||||
|
|
||||||
self.tab_was_created(&tab)?;
|
self.tab_was_created(&tab)?;
|
||||||
@ -179,8 +209,11 @@ pub trait TerminalWindow {
|
|||||||
let rows = ((height as usize + 1) / dims.cell_height) as u16;
|
let rows = ((height as usize + 1) / dims.cell_height) as u16;
|
||||||
let cols = ((width as usize + 1) / dims.cell_width) as u16;
|
let cols = ((width as usize + 1) / dims.cell_width) as u16;
|
||||||
|
|
||||||
let tabs = self.get_tabs();
|
let mux = Mux::get().unwrap();
|
||||||
for tab in tabs.iter() {
|
let window = mux
|
||||||
|
.get_window(self.get_mux_window_id())
|
||||||
|
.ok_or_else(|| format_err!("no such window!?"))?;
|
||||||
|
for tab in window.iter() {
|
||||||
tab.resize(rows, cols, width as u16, height as u16)?;
|
tab.resize(rows, cols, width as u16, height as u16)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,9 +238,12 @@ pub trait TerminalWindow {
|
|||||||
"TerminalWindow::scaling_changed dpi_scale={} font_scale={}",
|
"TerminalWindow::scaling_changed dpi_scale={} font_scale={}",
|
||||||
dpi_scale, font_scale
|
dpi_scale, font_scale
|
||||||
);
|
);
|
||||||
if let Some(tab) = self.get_tabs().get_active() {
|
let mux = Mux::get().unwrap();
|
||||||
|
let tab = match mux.get_active_tab_for_window(self.get_mux_window_id()) {
|
||||||
|
Some(tab) => tab,
|
||||||
|
None => return Ok(()),
|
||||||
|
};
|
||||||
tab.renderer().make_all_lines_dirty();
|
tab.renderer().make_all_lines_dirty();
|
||||||
}
|
|
||||||
fonts.change_scaling(font_scale, dpi_scale);
|
fonts.change_scaling(font_scale, dpi_scale);
|
||||||
|
|
||||||
let metrics = fonts.default_font_metrics()?;
|
let metrics = fonts.default_font_metrics()?;
|
||||||
@ -217,13 +253,7 @@ pub trait TerminalWindow {
|
|||||||
// so we query for that information here.
|
// so we query for that information here.
|
||||||
// If the backend supports `resize_if_not_full_screen` then we'll try
|
// If the backend supports `resize_if_not_full_screen` then we'll try
|
||||||
// to resize the window to match the new cell metrics.
|
// to resize the window to match the new cell metrics.
|
||||||
let (rows, cols) = {
|
let (rows, cols) = { tab.renderer().physical_dimensions() };
|
||||||
self.get_tabs()
|
|
||||||
.get_active()
|
|
||||||
.unwrap()
|
|
||||||
.renderer()
|
|
||||||
.physical_dimensions()
|
|
||||||
};
|
|
||||||
|
|
||||||
self.advise_renderer_that_scaling_has_changed(
|
self.advise_renderer_that_scaling_has_changed(
|
||||||
cell_width.ceil() as usize,
|
cell_width.ceil() as usize,
|
||||||
@ -239,16 +269,28 @@ pub trait TerminalWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn tab_did_terminate(&mut self, tab_id: TabId) {
|
fn tab_did_terminate(&mut self, tab_id: TabId) {
|
||||||
self.get_tabs_mut().remove_by_id(tab_id);
|
let mux = Mux::get().unwrap();
|
||||||
if let Some(active) = self.get_tabs().get_active() {
|
let mut window = match mux.get_window_mut(self.get_mux_window_id()) {
|
||||||
|
Some(window) => window,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
window.remove_by_id(tab_id);
|
||||||
|
|
||||||
|
if let Some(active) = window.get_active() {
|
||||||
active.renderer().make_all_lines_dirty();
|
active.renderer().make_all_lines_dirty();
|
||||||
self.update_title();
|
|
||||||
}
|
}
|
||||||
|
drop(window);
|
||||||
|
self.update_title();
|
||||||
self.deregister_tab(tab_id).ok();
|
self.deregister_tab(tab_id).ok();
|
||||||
}
|
}
|
||||||
fn test_for_child_exit(&mut self) -> bool {
|
fn test_for_child_exit(&mut self) -> bool {
|
||||||
let tabs = self.get_tabs();
|
let mux = Mux::get().unwrap();
|
||||||
let dead_tabs: Vec<Rc<Tab>> = tabs
|
let window = match mux.get_window(self.get_mux_window_id()) {
|
||||||
|
Some(window) => window,
|
||||||
|
None => return true,
|
||||||
|
};
|
||||||
|
let dead_tabs: Vec<Rc<Tab>> = window
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|tab| {
|
.filter_map(|tab| {
|
||||||
if tab.is_dead() {
|
if tab.is_dead() {
|
||||||
@ -258,9 +300,14 @@ pub trait TerminalWindow {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
drop(window);
|
||||||
for tab in dead_tabs {
|
for tab in dead_tabs {
|
||||||
self.tab_did_terminate(tab.tab_id());
|
self.tab_did_terminate(tab.tab_id());
|
||||||
}
|
}
|
||||||
self.get_tabs().is_empty()
|
let empty = match mux.get_window(self.get_mux_window_id()) {
|
||||||
|
Some(window) => window.is_empty(),
|
||||||
|
None => true,
|
||||||
|
};
|
||||||
|
empty
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use failure::Error;
|
use failure::Error;
|
||||||
use promise::{Executor, Future};
|
use promise::{Executor, Future};
|
||||||
use std::cell::RefCell;
|
use std::cell::{Ref, RefCell, RefMut};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
@ -10,12 +10,15 @@ use termwiz::hyperlink::Hyperlink;
|
|||||||
|
|
||||||
pub mod renderable;
|
pub mod renderable;
|
||||||
pub mod tab;
|
pub mod tab;
|
||||||
|
pub mod window;
|
||||||
|
|
||||||
use crate::mux::tab::{Tab, TabId};
|
use crate::mux::tab::{Tab, TabId};
|
||||||
|
use crate::mux::window::{Window, WindowId};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Mux {
|
pub struct Mux {
|
||||||
tabs: RefCell<HashMap<TabId, Rc<Tab>>>,
|
tabs: RefCell<HashMap<TabId, Rc<Tab>>>,
|
||||||
|
windows: RefCell<HashMap<WindowId, Window>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_from_tab_pty(executor: Box<Executor>, tab_id: TabId, mut reader: Box<std::io::Read>) {
|
fn read_from_tab_pty(executor: Box<Executor>, tab_id: TabId, mut reader: Box<std::io::Read>) {
|
||||||
@ -127,6 +130,36 @@ impl Mux {
|
|||||||
self.tabs.borrow_mut().remove(&tab_id);
|
self.tabs.borrow_mut().remove(&tab_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_window(&self, window_id: WindowId) -> Option<Ref<Window>> {
|
||||||
|
if !self.windows.borrow().contains_key(&window_id) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(Ref::map(self.windows.borrow(), |windows| {
|
||||||
|
windows.get(&window_id).unwrap()
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_window_mut(&self, window_id: WindowId) -> Option<RefMut<Window>> {
|
||||||
|
if !self.windows.borrow().contains_key(&window_id) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(RefMut::map(self.windows.borrow_mut(), |windows| {
|
||||||
|
windows.get_mut(&window_id).unwrap()
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_active_tab_for_window(&self, window_id: WindowId) -> Option<Rc<Tab>> {
|
||||||
|
let window = self.get_window(window_id)?;
|
||||||
|
window.get_active().map(Rc::clone)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_new_window_with_tab(&self, tab: &Rc<Tab>) -> Result<WindowId, Error> {
|
||||||
|
let window = Window::new(tab);
|
||||||
|
let window_id = window.window_id();
|
||||||
|
self.windows.borrow_mut().insert(window_id, window);
|
||||||
|
Ok(window_id)
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.tabs.borrow().is_empty()
|
self.tabs.borrow().is_empty()
|
||||||
|
82
src/mux/window.rs
Normal file
82
src/mux/window.rs
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
use crate::mux::{Tab, TabId};
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
static WIN_ID: ::std::sync::atomic::AtomicUsize = ::std::sync::atomic::ATOMIC_USIZE_INIT;
|
||||||
|
pub type WindowId = usize;
|
||||||
|
|
||||||
|
pub struct Window {
|
||||||
|
id: WindowId,
|
||||||
|
tabs: Vec<Rc<Tab>>,
|
||||||
|
active: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Window {
|
||||||
|
pub fn new(tab: &Rc<Tab>) -> Self {
|
||||||
|
Self {
|
||||||
|
id: WIN_ID.fetch_add(1, ::std::sync::atomic::Ordering::Relaxed),
|
||||||
|
tabs: vec![Rc::clone(tab)],
|
||||||
|
active: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn window_id(&self) -> WindowId {
|
||||||
|
self.id
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push(&mut self, tab: &Rc<Tab>) {
|
||||||
|
self.tabs.push(Rc::clone(tab))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.tabs.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.tabs.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_by_idx(&self, idx: usize) -> Option<&Rc<Tab>> {
|
||||||
|
self.tabs.get(idx)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn idx_by_id(&self, id: TabId) -> Option<usize> {
|
||||||
|
for (idx, t) in self.tabs.iter().enumerate() {
|
||||||
|
if t.tab_id() == id {
|
||||||
|
return Some(idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_by_id(&mut self, id: TabId) {
|
||||||
|
if let Some(idx) = self.idx_by_id(id) {
|
||||||
|
self.tabs.remove(idx);
|
||||||
|
let len = self.tabs.len();
|
||||||
|
if len > 0 && self.active == idx && idx >= len {
|
||||||
|
self.set_active(len - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_active(&self) -> Option<&Rc<Tab>> {
|
||||||
|
self.get_by_idx(self.active)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_active_idx(&self) -> usize {
|
||||||
|
self.active
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_active(&mut self, idx: usize) {
|
||||||
|
assert!(idx < self.tabs.len());
|
||||||
|
self.active = idx;
|
||||||
|
self.get_by_idx(idx)
|
||||||
|
.unwrap()
|
||||||
|
.renderer()
|
||||||
|
.make_all_lines_dirty();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter(&self) -> impl Iterator<Item = &Rc<Tab>> {
|
||||||
|
self.tabs.iter()
|
||||||
|
}
|
||||||
|
}
|
@ -4,11 +4,13 @@ use super::{Connection, Window};
|
|||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::font::FontConfiguration;
|
use crate::font::FontConfiguration;
|
||||||
use crate::guicommon::host::{HostHelper, HostImpl, TabHost};
|
use crate::guicommon::host::{HostHelper, HostImpl, TabHost};
|
||||||
use crate::guicommon::tabs::{Tab, TabId, Tabs};
|
|
||||||
use crate::guicommon::window::{Dimensions, TerminalWindow};
|
use crate::guicommon::window::{Dimensions, TerminalWindow};
|
||||||
use crate::guiloop::x11::{GuiEventLoop, WindowId};
|
use crate::guiloop::x11::{GuiEventLoop, WindowId as X11WindowId};
|
||||||
use crate::guiloop::SessionTerminated;
|
use crate::guiloop::SessionTerminated;
|
||||||
use crate::mux::renderable::Renderable;
|
use crate::mux::renderable::Renderable;
|
||||||
|
use crate::mux::tab::{Tab, TabId};
|
||||||
|
use crate::mux::window::WindowId;
|
||||||
|
use crate::mux::Mux;
|
||||||
use failure::Error;
|
use failure::Error;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@ -43,16 +45,13 @@ pub struct X11TerminalWindow {
|
|||||||
height: u16,
|
height: u16,
|
||||||
cell_height: usize,
|
cell_height: usize,
|
||||||
cell_width: usize,
|
cell_width: usize,
|
||||||
tabs: Tabs,
|
|
||||||
have_pending_resize: Option<(u16, u16)>,
|
have_pending_resize: Option<(u16, u16)>,
|
||||||
|
mux_window_id: WindowId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TerminalWindow for X11TerminalWindow {
|
impl TerminalWindow for X11TerminalWindow {
|
||||||
fn get_tabs(&self) -> &Tabs {
|
fn get_mux_window_id(&self) -> WindowId {
|
||||||
&self.tabs
|
self.mux_window_id
|
||||||
}
|
|
||||||
fn get_tabs_mut(&mut self) -> &mut Tabs {
|
|
||||||
&mut self.tabs
|
|
||||||
}
|
}
|
||||||
fn config(&self) -> &Arc<Config> {
|
fn config(&self) -> &Arc<Config> {
|
||||||
&self.host.config
|
&self.host.config
|
||||||
@ -75,9 +74,6 @@ impl TerminalWindow for X11TerminalWindow {
|
|||||||
fn recreate_texture_atlas(&mut self, size: u32) -> Result<(), Error> {
|
fn recreate_texture_atlas(&mut self, size: u32) -> Result<(), Error> {
|
||||||
self.renderer.recreate_atlas(&self.host.window, size)
|
self.renderer.recreate_atlas(&self.host.window, size)
|
||||||
}
|
}
|
||||||
fn renderer_and_tab(&mut self) -> (&mut Renderer, &Tab) {
|
|
||||||
(&mut self.renderer, self.tabs.get_active().unwrap())
|
|
||||||
}
|
|
||||||
fn tab_was_created(&mut self, tab: &Rc<Tab>) -> Result<(), Error> {
|
fn tab_was_created(&mut self, tab: &Rc<Tab>) -> Result<(), Error> {
|
||||||
self.host.event_loop.register_tab(tab)
|
self.host.event_loop.register_tab(tab)
|
||||||
}
|
}
|
||||||
@ -158,7 +154,8 @@ impl X11TerminalWindow {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let renderer = Renderer::new(&host.window, width, height, fonts, palette)?;
|
let renderer = Renderer::new(&host.window, width, height, fonts, palette)?;
|
||||||
|
let mux = Mux::get().unwrap();
|
||||||
|
let mux_window_id = mux.add_new_window_with_tab(tab)?;
|
||||||
host.window.show();
|
host.window.show();
|
||||||
|
|
||||||
Ok(X11TerminalWindow {
|
Ok(X11TerminalWindow {
|
||||||
@ -169,12 +166,12 @@ impl X11TerminalWindow {
|
|||||||
height,
|
height,
|
||||||
cell_height,
|
cell_height,
|
||||||
cell_width,
|
cell_width,
|
||||||
tabs: Tabs::new(tab),
|
|
||||||
have_pending_resize: None,
|
have_pending_resize: None,
|
||||||
|
mux_window_id,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn window_id(&self) -> WindowId {
|
pub fn window_id(&self) -> X11WindowId {
|
||||||
self.host.window.window.window_id
|
self.host.window.window.window_id
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,7 +184,8 @@ impl X11TerminalWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn mouse_event(&mut self, event: MouseEvent) -> Result<(), Error> {
|
fn mouse_event(&mut self, event: MouseEvent) -> Result<(), Error> {
|
||||||
let tab = match self.tabs.get_active() {
|
let mux = Mux::get().unwrap();
|
||||||
|
let tab = match mux.get_active_tab_for_window(self.get_mux_window_id()) {
|
||||||
Some(tab) => tab,
|
Some(tab) => tab,
|
||||||
None => return Ok(()),
|
None => return Ok(()),
|
||||||
};
|
};
|
||||||
@ -212,7 +210,8 @@ impl X11TerminalWindow {
|
|||||||
}
|
}
|
||||||
xcb::KEY_PRESS => {
|
xcb::KEY_PRESS => {
|
||||||
let key_press: &xcb::KeyPressEvent = unsafe { xcb::cast_event(event) };
|
let key_press: &xcb::KeyPressEvent = unsafe { xcb::cast_event(event) };
|
||||||
let tab = match self.tabs.get_active() {
|
let mux = Mux::get().unwrap();
|
||||||
|
let tab = match mux.get_active_tab_for_window(self.get_mux_window_id()) {
|
||||||
Some(tab) => tab,
|
Some(tab) => tab,
|
||||||
None => return Ok(()),
|
None => return Ok(()),
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user