Support resize
This commit is contained in:
+50
-3
@@ -15,6 +15,8 @@
|
||||
#include <typeinfo>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/signalfd.h>
|
||||
#include <termios.h>
|
||||
|
||||
#include "parser.hpp"
|
||||
#include "terminal.hpp"
|
||||
@@ -117,9 +119,31 @@ int main( int argc,
|
||||
|
||||
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;
|
||||
Terminal::Emulator terminal( 80, 24 );
|
||||
struct pollfd pollfds[ 2 ];
|
||||
Terminal::Emulator terminal( window_size.ws_col, window_size.ws_row );
|
||||
struct pollfd pollfds[ 3 ];
|
||||
|
||||
pollfds[ 0 ].fd = STDIN_FILENO;
|
||||
pollfds[ 0 ].events = POLLIN;
|
||||
@@ -127,10 +151,13 @@ void emulate_terminal( int fd, int debug_fd )
|
||||
pollfds[ 1 ].fd = fd;
|
||||
pollfds[ 1 ].events = POLLIN;
|
||||
|
||||
pollfds[ 2 ].fd = winch_fd;
|
||||
pollfds[ 2 ].events = POLLIN;
|
||||
|
||||
swrite( STDOUT_FILENO, terminal.open().c_str() );
|
||||
|
||||
while ( 1 ) {
|
||||
int active_fds = poll( pollfds, 2, -1 );
|
||||
int active_fds = poll( pollfds, 3, -1 );
|
||||
if ( active_fds <= 0 ) {
|
||||
perror( "poll" );
|
||||
break;
|
||||
@@ -144,6 +171,26 @@ void emulate_terminal( int fd, int debug_fd )
|
||||
if ( termemu( fd, fd, false, debug_fd, &parser, &terminal ) < 0 ) {
|
||||
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)
|
||||
& (POLLERR | POLLHUP | POLLNVAL) ) {
|
||||
break;
|
||||
|
||||
+11
-1
@@ -34,7 +34,7 @@ void Emulator::print( Parser::Print *act )
|
||||
|
||||
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 ) {
|
||||
case 1: /* normal character */
|
||||
@@ -68,6 +68,11 @@ void Emulator::print( Parser::Print *act )
|
||||
act->handled = true;
|
||||
break;
|
||||
case 0: /* combining character */
|
||||
if ( combining_cell == NULL ) { /* character is now offscreen */
|
||||
act->handled = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( combining_cell->contents.size() == 0 ) {
|
||||
/* cell starts with combining character */
|
||||
assert( this_cell == combining_cell );
|
||||
@@ -195,3 +200,8 @@ std::string Emulator::close( void )
|
||||
char ansimode[ 6 ] = { 0x1b, '[', '?', '1', 'l', 0 };
|
||||
return std::string( ansimode );
|
||||
}
|
||||
|
||||
void Emulator::resize( size_t s_width, size_t s_height )
|
||||
{
|
||||
fb.resize( s_width, s_height );
|
||||
}
|
||||
|
||||
@@ -46,6 +46,9 @@ namespace Terminal {
|
||||
|
||||
std::string open( void ); /* put user cursor keys in application mode */
|
||||
std::string close( void ); /* restore user cursor keys */
|
||||
|
||||
void resize( size_t s_width, size_t s_height );
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+47
-2
@@ -56,7 +56,10 @@ DrawState::DrawState( 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 )
|
||||
{}
|
||||
{
|
||||
assert( s_height > 0 );
|
||||
assert( s_width > 0 );
|
||||
}
|
||||
|
||||
void Framebuffer::scroll( int N )
|
||||
{
|
||||
@@ -183,6 +186,11 @@ Cell *Framebuffer::get_cell( int row, int col )
|
||||
|
||||
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() ];
|
||||
}
|
||||
|
||||
@@ -280,7 +288,7 @@ void DrawState::restore_cursor( void )
|
||||
auto_wrap_mode = save.auto_wrap_mode;
|
||||
origin_mode = save.origin_mode;
|
||||
|
||||
snap_cursor_to_border();
|
||||
snap_cursor_to_border(); /* we could have resized in between */
|
||||
new_grapheme();
|
||||
}
|
||||
|
||||
@@ -352,3 +360,40 @@ void Framebuffer::soft_reset( void )
|
||||
ds.clear_renditions();
|
||||
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 */
|
||||
}
|
||||
|
||||
@@ -106,6 +106,8 @@ namespace Terminal {
|
||||
void restore_cursor( void );
|
||||
void clear_saved_cursor( void ) { save = SavedCursor(); }
|
||||
|
||||
void resize( 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; }
|
||||
std::vector<wchar_t> get_window_title( void ) { return window_title; }
|
||||
|
||||
void resize( int s_width, int s_height );
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user