From d639ad0ffe74ac1a768756ae11f93d84d052e167 Mon Sep 17 00:00:00 2001 From: Wez Furlong Date: Sat, 23 Feb 2019 22:04:58 -0800 Subject: [PATCH] factor out the paint logic --- src/gliumwindows.rs | 60 ++++++++++++-------------------- src/guicommon/window.rs | 69 ++++++++++++++++++++++++++++++++++-- src/guiloop/glutinloop.rs | 1 + src/guiloop/x11.rs | 1 + src/xwindows/xwin.rs | 73 +++++++++++---------------------------- 5 files changed, 112 insertions(+), 92 deletions(-) diff --git a/src/gliumwindows.rs b/src/gliumwindows.rs index 4d1ba8b65..1ae0d619c 100644 --- a/src/gliumwindows.rs +++ b/src/gliumwindows.rs @@ -14,6 +14,7 @@ use clipboard::{ClipboardContext, ClipboardProvider}; use glium; use glium::glutin::dpi::{LogicalPosition, LogicalSize, PhysicalPosition}; use glium::glutin::{self, ElementState, MouseCursor}; +use std::cell::RefMut; use std::io::Write; use std::rc::Rc; use term::KeyCode; @@ -212,7 +213,10 @@ pub struct GliumTerminalWindow { } impl TerminalWindow for GliumTerminalWindow { - fn get_tabs(&mut self) -> &mut Tabs { + fn get_tabs(&self) -> &Tabs { + &self.tabs + } + fn get_tabs_mut(&mut self) -> &mut Tabs { &mut self.tabs } @@ -220,6 +224,23 @@ impl TerminalWindow for GliumTerminalWindow { self.host.display.gl_window().set_title(title); Ok(()) } + + fn frame(&self) -> glium::Frame { + self.host.display.draw() + } + + fn renderer(&mut self) -> &mut Renderer { + &mut self.renderer + } + fn recreate_texture_atlas(&mut self, size: u32) -> Result<(), Error> { + self.renderer.recreate_atlas(&self.host.display, size) + } + fn renderer_and_terminal(&mut self) -> (&mut Renderer, RefMut) { + ( + &mut self.renderer, + self.tabs.get_active().unwrap().terminal(), + ) + } } impl GliumTerminalWindow { @@ -333,14 +354,6 @@ impl GliumTerminalWindow { Ok(()) } - pub fn activate_tab_relative(&mut self, delta: isize) -> Result<(), Error> { - let max = self.tabs.len(); - let active = self.tabs.get_active_idx() as isize; - let tab = active + delta; - let tab = if tab < 0 { max as isize + tab } else { tab }; - self.activate_tab(tab as usize % max) - } - pub fn window_id(&self) -> glutin::WindowId { self.host.display.gl_window().id() } @@ -353,35 +366,6 @@ impl GliumTerminalWindow { .try_clone() } - pub fn paint(&mut self) -> Result<(), Error> { - let tab = match self.tabs.get_active() { - Some(tab) => tab, - None => return Ok(()), - }; - let mut target = self.host.display.draw(); - let res = self.renderer.paint(&mut target, &mut tab.terminal()); - // Ensure that we finish() the target before we let the - // error bubble up, otherwise we lose the context. - target.finish().unwrap(); - - // The only error we want to catch is texture space related; - // when that happens we need to blow our glyph cache and - // allocate a newer bigger texture. - match res { - Err(err) => { - if let Some(&OutOfTextureSpace { size }) = err.downcast_ref::() { - eprintln!("out of texture space, allocating {}", size); - self.renderer.recreate_atlas(&self.host.display, size)?; - tab.terminal().make_all_lines_dirty(); - // Recursively initiate a new paint - return self.paint(); - } - Err(err) - } - Ok(_) => Ok(()), - } - } - pub fn process_data_read_from_pty(&mut self, data: &[u8], tab_id: usize) -> Result<(), Error> { let tab = self.tabs.get_by_id(tab_id)?; diff --git a/src/guicommon/window.rs b/src/guicommon/window.rs index 160c71c33..749daea90 100644 --- a/src/guicommon/window.rs +++ b/src/guicommon/window.rs @@ -1,19 +1,37 @@ use crate::guicommon::tabs::Tabs; +use crate::opengl::render::Renderer; +use crate::opengl::textureatlas::OutOfTextureSpace; use failure::Error; +use glium; +use glium::backend::Facade; +use std::cell::RefMut; pub trait TerminalWindow { - fn get_tabs(&mut self) -> &mut Tabs; + fn get_tabs_mut(&mut self) -> &mut Tabs; + fn get_tabs(&self) -> &Tabs; fn set_window_title(&mut self, title: &str) -> Result<(), Error>; + fn frame(&self) -> glium::Frame; + fn renderer(&mut self) -> &mut Renderer; + fn renderer_and_terminal(&mut self) -> (&mut Renderer, RefMut); + fn recreate_texture_atlas(&mut self, size: u32) -> Result<(), Error>; fn activate_tab(&mut self, tab_idx: usize) -> Result<(), Error> { let max = self.get_tabs().len(); if tab_idx < max { - self.get_tabs().set_active(tab_idx); + self.get_tabs_mut().set_active(tab_idx); self.update_title(); } Ok(()) } + fn activate_tab_relative(&mut self, delta: isize) -> Result<(), Error> { + let max = self.get_tabs().len(); + let active = self.get_tabs().get_active_idx() as isize; + let tab = active + delta; + let tab = if tab < 0 { max as isize + tab } else { tab }; + self.activate_tab(tab as usize % max) + } + fn update_title(&mut self) { let num_tabs = self.get_tabs().len(); @@ -34,4 +52,51 @@ pub trait TerminalWindow { .ok(); } } + + fn paint_if_needed(&mut self) -> Result<(), Error> { + let tab = match self.get_tabs().get_active() { + Some(tab) => tab, + None => return Ok(()), + }; + if tab.terminal().has_dirty_lines() { + self.paint()?; + } + Ok(()) + } + + fn paint(&mut self) -> Result<(), Error> { + let mut target = self.frame(); + + let res = { + let (renderer, mut terminal) = self.renderer_and_terminal(); + renderer.paint(&mut target, &mut terminal) + }; + + // Ensure that we finish() the target before we let the + // error bubble up, otherwise we lose the context. + target + .finish() + .expect("target.finish failed and we don't know how to recover"); + + // The only error we want to catch is texture space related; + // when that happens we need to blow our glyph cache and + // allocate a newer bigger texture. + match res { + Err(err) => { + if let Some(&OutOfTextureSpace { size }) = err.downcast_ref::() { + eprintln!("out of texture space, allocating {}", size); + self.recreate_texture_atlas(size)?; + self.get_tabs_mut() + .get_active() + .unwrap() + .terminal() + .make_all_lines_dirty(); + // Recursively initiate a new paint + return self.paint(); + } + Err(err) + } + Ok(_) => Ok(()), + } + } } diff --git a/src/guiloop/glutinloop.rs b/src/guiloop/glutinloop.rs index e694ac929..f7a41935e 100644 --- a/src/guiloop/glutinloop.rs +++ b/src/guiloop/glutinloop.rs @@ -2,6 +2,7 @@ use super::GuiSystem; use crate::futurecore; use crate::gliumwindows; pub use crate::gliumwindows::GliumTerminalWindow; +use crate::guicommon::window::TerminalWindow; use crate::guiloop::SessionTerminated; use crate::{Child, MasterPty}; use failure::Error; diff --git a/src/guiloop/x11.rs b/src/guiloop/x11.rs index 03831af15..fca9af92a 100644 --- a/src/guiloop/x11.rs +++ b/src/guiloop/x11.rs @@ -3,6 +3,7 @@ use crate::config::Config; use crate::font::FontConfiguration; use crate::futurecore; use crate::guicommon::tabs::TabId; +use crate::guicommon::window::TerminalWindow; use crate::xwindows::xwin::X11TerminalWindow; use crate::xwindows::Connection; use crate::{spawn_window_impl, Child, MasterPty}; diff --git a/src/xwindows/xwin.rs b/src/xwindows/xwin.rs index 937741a1a..619b9caac 100644 --- a/src/xwindows/xwin.rs +++ b/src/xwindows/xwin.rs @@ -13,6 +13,7 @@ use crate::{openpty, MasterPty}; use clipboard::{ClipboardContext, ClipboardProvider}; use failure::Error; use futures; +use std::cell::RefMut; use std::io::{self, Read, Write}; use std::rc::Rc; use term::{self, KeyCode, KeyModifiers, MouseButton, MouseEvent, MouseEventKind}; @@ -162,7 +163,10 @@ impl<'a> term::TerminalHost for TabHost<'a> { } impl TerminalWindow for X11TerminalWindow { - fn get_tabs(&mut self) -> &mut Tabs { + fn get_tabs(&self) -> &Tabs { + &self.tabs + } + fn get_tabs_mut(&mut self) -> &mut Tabs { &mut self.tabs } @@ -170,6 +174,22 @@ impl TerminalWindow for X11TerminalWindow { self.host.window.set_title(title); Ok(()) } + fn frame(&self) -> glium::Frame { + self.host.window.draw() + } + + fn renderer(&mut self) -> &mut Renderer { + &mut self.renderer + } + fn recreate_texture_atlas(&mut self, size: u32) -> Result<(), Error> { + self.renderer.recreate_atlas(&self.host.window, size) + } + fn renderer_and_terminal(&mut self) -> (&mut Renderer, RefMut) { + ( + &mut self.renderer, + self.tabs.get_active().unwrap().terminal(), + ) + } } impl X11TerminalWindow { @@ -284,49 +304,6 @@ impl X11TerminalWindow { self.paint() } - pub fn paint(&mut self) -> Result<(), Error> { - let tab = match self.tabs.get_active() { - Some(tab) => tab, - None => return Ok(()), - }; - - let mut target = self.host.window.draw(); - let res = self.renderer.paint(&mut target, &mut tab.terminal()); - // Ensure that we finish() the target before we let the - // error bubble up, otherwise we lose the context. - target - .finish() - .expect("target.finish failed and we don't know how to recover"); - - // The only error we want to catch is texture space related; - // when that happens we need to blow our glyph cache and - // allocate a newer bigger texture. - match res { - Err(err) => { - if let Some(&OutOfTextureSpace { size }) = err.downcast_ref::() { - eprintln!("out of texture space, allocating {}", size); - self.renderer.recreate_atlas(&self.host.window, size)?; - tab.terminal().make_all_lines_dirty(); - // Recursively initiate a new paint - return self.paint(); - } - Err(err) - } - Ok(_) => Ok(()), - } - } - - pub fn paint_if_needed(&mut self) -> Result<(), Error> { - let tab = match self.tabs.get_active() { - Some(tab) => tab, - None => return Ok(()), - }; - if tab.terminal().has_dirty_lines() { - self.paint()?; - } - Ok(()) - } - pub fn tabs<'a>(&'a self) -> &'a Tabs { &self.tabs } @@ -536,12 +513,4 @@ impl X11TerminalWindow { Ok(tab_id) } - - pub fn activate_tab_relative(&mut self, delta: isize) -> Result<(), Error> { - let max = self.tabs.len(); - let active = self.tabs.get_active_idx() as isize; - let tab = active + delta; - let tab = if tab < 0 { max as isize + tab } else { tab }; - self.activate_tab(tab as usize % max) - } }