From a54cc9d0c4483c36ef799cb1127c4247c5027fcd Mon Sep 17 00:00:00 2001 From: Keith Winstein Date: Sat, 5 Feb 2011 02:55:30 -0500 Subject: [PATCH] Added smarter display routine --- Makefile | 4 +- termemu.cpp | 5 +- terminal.cpp | 2 +- terminal.hpp | 18 +++++ terminaldisplay.cpp | 150 ++++++++++++++++++++++++++++++++++++++++ terminalframebuffer.cpp | 6 +- 6 files changed, 179 insertions(+), 6 deletions(-) create mode 100644 terminaldisplay.cpp diff --git a/Makefile b/Makefile index a70367e..52c38e2 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ -source = parse.cpp parserstate.cpp parser.cpp templates.cpp terminal.cpp termemu.cpp parseraction.cpp terminalfunctions.cpp swrite.cpp terminalframebuffer.cpp terminaldispatcher.cpp terminaluserinput.cpp -objects = parserstate.o parser.o templates.o terminal.o parseraction.o terminalfunctions.o swrite.o terminalframebuffer.o terminaldispatcher.o terminaluserinput.o +source = parse.cpp parserstate.cpp parser.cpp templates.cpp terminal.cpp termemu.cpp parseraction.cpp terminalfunctions.cpp swrite.cpp terminalframebuffer.cpp terminaldispatcher.cpp terminaluserinput.cpp terminaldisplay.cpp +objects = parserstate.o parser.o templates.o terminal.o parseraction.o terminalfunctions.o swrite.o terminalframebuffer.o terminaldispatcher.o terminaluserinput.o terminaldisplay.o repos = templates.rpo executables = parse termemu diff --git a/termemu.cpp b/termemu.cpp index 2a1957d..e4d3546 100644 --- a/termemu.cpp +++ b/termemu.cpp @@ -166,6 +166,7 @@ void emulate_terminal( int fd, int debug_fd ) /* open parser and terminal */ Parser::UTF8Parser parser; Terminal::Emulator terminal( window_size.ws_col, window_size.ws_row ); + struct pollfd pollfds[ 3 ]; pollfds[ 0 ].fd = STDIN_FILENO; @@ -194,6 +195,8 @@ void emulate_terminal( int fd, int debug_fd ) if ( termemu( fd, fd, false, debug_fd, &parser, &terminal ) < 0 ) { break; } + std::string update = terminal.new_frame(); + swrite( STDOUT_FILENO, update.c_str() ); } else if ( pollfds[ 2 ].revents & POLLIN ) { /* resize */ struct signalfd_siginfo info; @@ -269,8 +272,6 @@ int termemu( int host_fd, int src_fd, bool user, int debug_fd, } } - terminal->debug_printout( STDOUT_FILENO ); - /* write writeback */ std::string terminal_to_host = terminal->read_octets_to_host(); return swrite( host_fd, terminal_to_host.c_str(), terminal_to_host.length() ); diff --git a/terminal.cpp b/terminal.cpp index 0de561d..f996d86 100644 --- a/terminal.cpp +++ b/terminal.cpp @@ -10,7 +10,7 @@ using namespace Terminal; Emulator::Emulator( size_t s_width, size_t s_height ) - : fb( s_width, s_height ), dispatch(), user() + : fb( s_width, s_height ), dispatch(), user(), display( s_width, s_height ) {} std::string Emulator::read_octets_to_host( void ) diff --git a/terminal.hpp b/terminal.hpp index b61d9d1..ca6aa25 100644 --- a/terminal.hpp +++ b/terminal.hpp @@ -12,6 +12,21 @@ #include "terminaluserinput.hpp" namespace Terminal { + class Display { + private: + bool initialized; + Framebuffer last_frame; + std::vector current_renditions; + + public: + Display( int width, int height ) + : initialized( false ), last_frame( width, height ), + current_renditions() + {} + + std::string new_frame( Framebuffer &f ); + }; + class Emulator { friend void Parser::Print::act_on_terminal( Emulator * ); friend void Parser::Execute::act_on_terminal( Emulator * ); @@ -30,6 +45,7 @@ namespace Terminal { Framebuffer fb; Dispatcher dispatch; UserInput user; + Display display; /* action methods */ void print( Parser::Print *act ); @@ -48,6 +64,8 @@ namespace Terminal { std::string open( void ); /* put user cursor keys in application mode */ std::string close( void ); /* restore user cursor keys */ + + std::string new_frame( void ) { return display.new_frame( fb ); } }; } diff --git a/terminaldisplay.cpp b/terminaldisplay.cpp new file mode 100644 index 0000000..57af81f --- /dev/null +++ b/terminaldisplay.cpp @@ -0,0 +1,150 @@ +#include "terminal.hpp" + +using namespace Terminal; + +std::string Display::new_frame( Framebuffer &f ) +{ + f.back_color_erase(); + + std::string screen; + bool cursor_was_moved = false; + + /* has window title changed? */ + if ( (!initialized) + || (f.get_window_title() != last_frame.get_window_title()) ) { + /* set window title */ + screen.append( "\033]0;[rtm] " ); + std::vector window_title = f.get_window_title(); + for ( std::vector::iterator i = window_title.begin(); + i != window_title.end(); + i++ ) { + char utf8[ 8 ]; + snprintf( utf8, 8, "%lc", *i ); + screen.append( utf8 ); + } + screen.append( "\033\\" ); + } + + /* has reverse video state changed? */ + if ( (!initialized) + || (f.ds.reverse_video != last_frame.ds.reverse_video) ) { + /* set reverse video */ + char rev[ 8 ]; + snprintf( rev, 8, "\033[?5%c", (f.ds.reverse_video ? 'h' : 'l') ); + screen.append( rev ); + } + + /* has size changed? */ + if ( (!initialized) + || (f.ds.get_width() != last_frame.ds.get_width()) + || (f.ds.get_height() != last_frame.ds.get_height()) ) { + /* clear screen */ + screen.append( "\033[0m;\033[H\033[2J" ); + initialized = false; + cursor_was_moved = true; + current_renditions.clear(); + current_renditions.push_back( 0 ); + } + + /* iterate for every cell */ + for ( int y = 0; y < f.ds.get_height(); y++ ) { + for ( int x = 0; x < f.ds.get_width(); /* let charwidth handle advance */ ) { + std::string cell_string; + Cell *cell = f.get_cell( y, x ); + bool different = false; + + char curmove[ 32 ]; + snprintf( curmove, 32, "\033[%d;%dH", y + 1, x + 1 ); + cell_string.append( curmove ); + + /* have renditions changed? */ + if ( (!initialized) + || (cell->renditions != last_frame.get_cell( y, x )->renditions) ) { + different = true; + } + + std::vector cell_print_renditions; + cell_print_renditions = cell->renditions; + cell_print_renditions.insert( cell_print_renditions.begin(), 0 ); + + if ( cell_print_renditions != current_renditions ) { + /* print renditions */ + cell_string.append( "\033[0" ); + char rendition[ 32 ]; + for ( std::vector::iterator i = cell->renditions.begin(); + i != cell->renditions.end(); + i++ ) { + snprintf( rendition, 32, ";%d", *i ); + cell_string.append( rendition ); + } + cell_string.append( "m" ); + } + + /* clear cell */ + cell_string.append( "\033[X" ); + + /* did fallback status change? */ + if ( (!initialized) + || (cell->fallback != last_frame.get_cell( y, x )->fallback) ) { + different = true; + } + + /* cells that begin with combining character get combiner attached to no-break space */ + if ( cell->fallback ) { + char utf8[ 8 ]; + snprintf( utf8, 8, "%lc", 0xA0 ); + cell_string.append( utf8 ); + } + + /* have cell contents changed? */ + if ( (!initialized) + || (cell->contents != last_frame.get_cell( y, x )->contents) ) { + different = true; + } + + /* always restrike the cell contents if anything changed */ + for ( std::vector::iterator i = cell->contents.begin(); + i != cell->contents.end(); + i++ ) { + char utf8[ 8 ]; + snprintf( utf8, 8, "%lc", *i ); + cell_string.append( utf8 ); + } + + /* if anything changed, redo cell */ + if ( different ) { + screen.append( cell_string ); + cursor_was_moved = true; + current_renditions = cell_print_renditions; + } + + x += cell->width; + } + } + + /* has cursor location changed? */ + if ( (!initialized) + || (f.ds.get_cursor_row() != last_frame.ds.get_cursor_row()) + || (f.ds.get_cursor_col() != last_frame.ds.get_cursor_col()) + || cursor_was_moved ) { + char curmove[ 32 ]; + snprintf( curmove, 32, "\033[%d;%dH", f.ds.get_cursor_row() + 1, + f.ds.get_cursor_col() + 1 ); + screen.append( curmove ); + } + + /* has cursor visibility changed? */ + if ( (!initialized) + || (f.ds.cursor_visible != last_frame.ds.cursor_visible) ) { + if ( f.ds.cursor_visible ) { + screen.append( "\033[25h" ); + } else { + screen.append( "\033[25l" ); + } + } + + last_frame = f; + initialized = true; + + return screen; +} diff --git a/terminalframebuffer.cpp b/terminalframebuffer.cpp index e6632d0..0ab0e5a 100644 --- a/terminalframebuffer.cpp +++ b/terminalframebuffer.cpp @@ -395,7 +395,7 @@ void DrawState::resize( int s_width, int s_height ) int DrawState::get_background_rendition( void ) { - int color = 0; + int color = -1; for ( std::vector::iterator i = renditions.begin(); i != renditions.end(); i++ ) { @@ -412,6 +412,10 @@ void Framebuffer::back_color_erase( void ) { int bg_color = ds.get_background_rendition(); + if ( bg_color < 0 ) { + return; + } + for ( int row = 0; row < ds.get_height(); row++ ) { for ( int col = 0; col < ds.get_width(); col++ ) { Cell *cell = get_cell( row, col );