Support resize

This commit is contained in:
Keith Winstein
2011-02-03 22:18:27 -05:00
parent 5a3c4a201b
commit 2812c7beaf
5 changed files with 115 additions and 6 deletions
+50 -3
View File
@@ -15,6 +15,8 @@
#include <typeinfo> #include <typeinfo>
#include <sys/stat.h> #include <sys/stat.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/signalfd.h>
#include <termios.h>
#include "parser.hpp" #include "parser.hpp"
#include "terminal.hpp" #include "terminal.hpp"
@@ -117,9 +119,31 @@ int main( int argc,
void emulate_terminal( int fd, int debug_fd ) void emulate_terminal( int fd, int debug_fd )
{ {
/* establish WINCH fd and start listening for signal */
sigset_t signal_mask;
assert( sigemptyset( &signal_mask ) == 0 );
assert( sigaddset( &signal_mask, SIGWINCH ) == 0 );
/* stop "ignoring" WINCH signal */
assert( sigprocmask( SIG_BLOCK, &signal_mask, NULL ) == 0 );
int winch_fd = signalfd( -1, &signal_mask, 0 );
if ( winch_fd < 0 ) {
perror( "signalfd" );
return;
}
/* get current window size */
struct winsize window_size;
if ( ioctl( STDIN_FILENO, TIOCGWINSZ, &window_size ) < 0 ) {
perror( "ioctl TIOCGWINSZ" );
return;
}
/* open parser and terminal */
Parser::UTF8Parser parser; Parser::UTF8Parser parser;
Terminal::Emulator terminal( 80, 24 ); Terminal::Emulator terminal( window_size.ws_col, window_size.ws_row );
struct pollfd pollfds[ 2 ]; struct pollfd pollfds[ 3 ];
pollfds[ 0 ].fd = STDIN_FILENO; pollfds[ 0 ].fd = STDIN_FILENO;
pollfds[ 0 ].events = POLLIN; pollfds[ 0 ].events = POLLIN;
@@ -127,10 +151,13 @@ void emulate_terminal( int fd, int debug_fd )
pollfds[ 1 ].fd = fd; pollfds[ 1 ].fd = fd;
pollfds[ 1 ].events = POLLIN; pollfds[ 1 ].events = POLLIN;
pollfds[ 2 ].fd = winch_fd;
pollfds[ 2 ].events = POLLIN;
swrite( STDOUT_FILENO, terminal.open().c_str() ); swrite( STDOUT_FILENO, terminal.open().c_str() );
while ( 1 ) { while ( 1 ) {
int active_fds = poll( pollfds, 2, -1 ); int active_fds = poll( pollfds, 3, -1 );
if ( active_fds <= 0 ) { if ( active_fds <= 0 ) {
perror( "poll" ); perror( "poll" );
break; break;
@@ -144,6 +171,26 @@ void emulate_terminal( int fd, int debug_fd )
if ( termemu( fd, fd, false, debug_fd, &parser, &terminal ) < 0 ) { if ( termemu( fd, fd, false, debug_fd, &parser, &terminal ) < 0 ) {
break; break;
} }
} else if ( pollfds[ 2 ].revents & POLLIN ) {
/* resize */
struct signalfd_siginfo info;
assert( read( winch_fd, &info, sizeof( info ) ) == sizeof( info ) );
assert( info.ssi_signo == SIGWINCH );
/* get new size */
if ( ioctl( STDIN_FILENO, TIOCGWINSZ, &window_size ) < 0 ) {
perror( "ioctl TIOCGWINSZ" );
return;
}
/* tell emulator */
terminal.resize( window_size.ws_col, window_size.ws_row );
/* tell child process */
if ( ioctl( fd, TIOCSWINSZ, &window_size ) < 0 ) {
perror( "ioctl TIOCSWINSZ" );
return;
}
} else if ( (pollfds[ 0 ].revents | pollfds[ 1 ].revents) } else if ( (pollfds[ 0 ].revents | pollfds[ 1 ].revents)
& (POLLERR | POLLHUP | POLLNVAL) ) { & (POLLERR | POLLHUP | POLLNVAL) ) {
break; break;
+11 -1
View File
@@ -34,7 +34,7 @@ void Emulator::print( Parser::Print *act )
Cell *this_cell = fb.get_cell(); Cell *this_cell = fb.get_cell();
Cell *combining_cell = fb.get_combining_cell(); Cell *combining_cell = fb.get_combining_cell(); /* can be null if we were resized */
switch ( chwidth ) { switch ( chwidth ) {
case 1: /* normal character */ case 1: /* normal character */
@@ -68,6 +68,11 @@ void Emulator::print( Parser::Print *act )
act->handled = true; act->handled = true;
break; break;
case 0: /* combining character */ case 0: /* combining character */
if ( combining_cell == NULL ) { /* character is now offscreen */
act->handled = true;
break;
}
if ( combining_cell->contents.size() == 0 ) { if ( combining_cell->contents.size() == 0 ) {
/* cell starts with combining character */ /* cell starts with combining character */
assert( this_cell == combining_cell ); assert( this_cell == combining_cell );
@@ -195,3 +200,8 @@ std::string Emulator::close( void )
char ansimode[ 6 ] = { 0x1b, '[', '?', '1', 'l', 0 }; char ansimode[ 6 ] = { 0x1b, '[', '?', '1', 'l', 0 };
return std::string( ansimode ); return std::string( ansimode );
} }
void Emulator::resize( size_t s_width, size_t s_height )
{
fb.resize( s_width, s_height );
}
+3
View File
@@ -46,6 +46,9 @@ namespace Terminal {
std::string open( void ); /* put user cursor keys in application mode */ std::string open( void ); /* put user cursor keys in application mode */
std::string close( void ); /* restore user cursor keys */ std::string close( void ); /* restore user cursor keys */
void resize( size_t s_width, size_t s_height );
}; };
} }
+47 -2
View File
@@ -56,7 +56,10 @@ DrawState::DrawState( int s_width, int s_height )
Framebuffer::Framebuffer( int s_width, int s_height ) Framebuffer::Framebuffer( int s_width, int s_height )
: rows( s_height, Row( s_width ) ), window_title(), ds( s_width, s_height ) : rows( s_height, Row( s_width ) ), window_title(), ds( s_width, s_height )
{} {
assert( s_height > 0 );
assert( s_width > 0 );
}
void Framebuffer::scroll( int N ) void Framebuffer::scroll( int N )
{ {
@@ -183,6 +186,11 @@ Cell *Framebuffer::get_cell( int row, int col )
Cell *Framebuffer::get_combining_cell( void ) Cell *Framebuffer::get_combining_cell( void )
{ {
if ( (ds.get_combining_char_row() >= ds.get_width())
|| (ds.get_combining_char_col() >= ds.get_height()) ) {
return NULL;
} /* can happen if a resize came in between */
return &rows[ ds.get_combining_char_row() ].cells[ ds.get_combining_char_col() ]; return &rows[ ds.get_combining_char_row() ].cells[ ds.get_combining_char_col() ];
} }
@@ -280,7 +288,7 @@ void DrawState::restore_cursor( void )
auto_wrap_mode = save.auto_wrap_mode; auto_wrap_mode = save.auto_wrap_mode;
origin_mode = save.origin_mode; origin_mode = save.origin_mode;
snap_cursor_to_border(); snap_cursor_to_border(); /* we could have resized in between */
new_grapheme(); new_grapheme();
} }
@@ -352,3 +360,40 @@ void Framebuffer::soft_reset( void )
ds.clear_renditions(); ds.clear_renditions();
ds.clear_saved_cursor(); ds.clear_saved_cursor();
} }
void Framebuffer::resize( int s_width, int s_height )
{
assert( s_width > 0 );
assert( s_height > 0 );
rows.resize( s_height, Row( ds.get_width() ) );
for ( std::deque<Row>::iterator i = rows.begin();
i != rows.end();
i++ ) {
(*i).cells.resize( s_width, Cell() );
}
ds.resize( s_width, s_height );
}
void DrawState::resize( int s_width, int s_height )
{
width = s_width;
height = s_height;
snap_cursor_to_border();
if ( scrolling_region_top_row >= height ) {
scrolling_region_top_row = 0;
}
if ( scrolling_region_bottom_row >= height ) {
scrolling_region_bottom_row = height - 1;
}
tabs.resize( width );
/* saved cursor will be snapped to border on restore */
/* combining char cell can now be offscreen */
}
+4
View File
@@ -106,6 +106,8 @@ namespace Terminal {
void restore_cursor( void ); void restore_cursor( void );
void clear_saved_cursor( void ) { save = SavedCursor(); } void clear_saved_cursor( void ) { save = SavedCursor(); }
void resize( int s_width, int s_height );
DrawState( int s_width, int s_height ); DrawState( int s_width, int s_height );
}; };
@@ -139,6 +141,8 @@ namespace Terminal {
void set_window_title( std::vector<wchar_t> s ) { window_title = s; } void set_window_title( std::vector<wchar_t> s ) { window_title = s; }
std::vector<wchar_t> get_window_title( void ) { return window_title; } std::vector<wchar_t> get_window_title( void ) { return window_title; }
void resize( int s_width, int s_height );
}; };
} }