Make Terminal::Framebuffer::Rows shared and copy-on-write.
* Support both std:: and std::tr1:: shared_ptr. FreeBSD 10 now uses C++11 by default. * Remove Framebuffer pointers in STMClient
This commit is contained in:
@@ -206,6 +206,9 @@ AC_CHECK_HEADERS([endian.h sys/endian.h])
|
|||||||
AC_CHECK_HEADERS([utmpx.h])
|
AC_CHECK_HEADERS([utmpx.h])
|
||||||
AC_CHECK_HEADERS([termio.h])
|
AC_CHECK_HEADERS([termio.h])
|
||||||
AC_CHECK_HEADERS([sys/uio.h])
|
AC_CHECK_HEADERS([sys/uio.h])
|
||||||
|
AC_LANG_PUSH(C++)
|
||||||
|
AC_CHECK_HEADERS([tr1/memory])
|
||||||
|
AC_LANG_POP(C++)
|
||||||
|
|
||||||
# Checks for typedefs, structures, and compiler characteristics.
|
# Checks for typedefs, structures, and compiler characteristics.
|
||||||
AC_HEADER_STDBOOL
|
AC_HEADER_STDBOOL
|
||||||
@@ -371,6 +374,32 @@ public:
|
|||||||
[AC_MSG_RESULT([no])])
|
[AC_MSG_RESULT([no])])
|
||||||
AC_LANG_POP(C++)
|
AC_LANG_POP(C++)
|
||||||
|
|
||||||
|
AC_MSG_CHECKING([whether std::shared_ptr is available])
|
||||||
|
AC_LANG_PUSH(C++)
|
||||||
|
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <memory>
|
||||||
|
class T {
|
||||||
|
public:
|
||||||
|
std::shared_ptr<int> Fun( void ) { return std::shared_ptr<int>( new int ( 0 ) ); } };]],
|
||||||
|
[[T x; return !!x.Fun();]])],
|
||||||
|
[AC_DEFINE([HAVE_STD_SHARED_PTR], [1],
|
||||||
|
[Define if std::shared_ptr is available.])
|
||||||
|
AC_MSG_RESULT([yes])],
|
||||||
|
[AC_MSG_RESULT([no])])
|
||||||
|
AC_LANG_POP(C++)
|
||||||
|
|
||||||
|
AC_MSG_CHECKING([whether std::tr1::shared_ptr is available])
|
||||||
|
AC_LANG_PUSH(C++)
|
||||||
|
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <tr1/memory>
|
||||||
|
class T {
|
||||||
|
public:
|
||||||
|
std::tr1::shared_ptr<int> Fun( void ) { return std::tr1::shared_ptr<int>( new int ( 0 ) ); } };]],
|
||||||
|
[[T x; return !!x.Fun();]])],
|
||||||
|
[AC_DEFINE([HAVE_STD_TR1_SHARED_PTR], [1],
|
||||||
|
[Define if std::tr1::shared_ptr is available.])
|
||||||
|
AC_MSG_RESULT([yes])],
|
||||||
|
[AC_MSG_RESULT([no])])
|
||||||
|
AC_LANG_POP(C++)
|
||||||
|
|
||||||
AC_CHECK_DECLS([__builtin_bswap64, __builtin_ctz])
|
AC_CHECK_DECLS([__builtin_bswap64, __builtin_ctz])
|
||||||
|
|
||||||
AC_CHECK_DECL([mach_absolute_time],
|
AC_CHECK_DECL([mach_absolute_time],
|
||||||
|
|||||||
+10
-13
@@ -237,11 +237,11 @@ void STMClient::main_init( void )
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* local state */
|
/* local state */
|
||||||
local_framebuffer = new Terminal::Framebuffer( window_size.ws_col, window_size.ws_row );
|
local_framebuffer = Terminal::Framebuffer( window_size.ws_col, window_size.ws_row );
|
||||||
new_state = new Terminal::Framebuffer( 1, 1 );
|
new_state = Terminal::Framebuffer( 1, 1 );
|
||||||
|
|
||||||
/* initialize screen */
|
/* initialize screen */
|
||||||
string init = display.new_frame( false, *local_framebuffer, *local_framebuffer );
|
string init = display.new_frame( false, local_framebuffer, local_framebuffer );
|
||||||
swrite( STDOUT_FILENO, init.data(), init.size() );
|
swrite( STDOUT_FILENO, init.data(), init.size() );
|
||||||
|
|
||||||
/* open network */
|
/* open network */
|
||||||
@@ -263,26 +263,23 @@ void STMClient::output_new_frame( void )
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* fetch target state */
|
/* fetch target state */
|
||||||
*new_state = network->get_latest_remote_state().state.get_fb();
|
new_state = network->get_latest_remote_state().state.get_fb();
|
||||||
|
|
||||||
/* apply local overlays */
|
/* apply local overlays */
|
||||||
overlays.apply( *new_state );
|
overlays.apply( new_state );
|
||||||
|
|
||||||
/* apply any mutations */
|
/* apply any mutations */
|
||||||
display.downgrade( *new_state );
|
display.downgrade( new_state );
|
||||||
|
|
||||||
/* calculate minimal difference from where we are */
|
/* calculate minimal difference from where we are */
|
||||||
const string diff( display.new_frame( !repaint_requested,
|
const string diff( display.new_frame( !repaint_requested,
|
||||||
*local_framebuffer,
|
local_framebuffer,
|
||||||
*new_state ) );
|
new_state ) );
|
||||||
swrite( STDOUT_FILENO, diff.data(), diff.size() );
|
swrite( STDOUT_FILENO, diff.data(), diff.size() );
|
||||||
|
|
||||||
repaint_requested = false;
|
repaint_requested = false;
|
||||||
|
|
||||||
/* switch pointers */
|
local_framebuffer = new_state;
|
||||||
Terminal::Framebuffer *tmp = new_state;
|
|
||||||
new_state = local_framebuffer;
|
|
||||||
local_framebuffer = tmp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void STMClient::process_network_input( void )
|
void STMClient::process_network_input( void )
|
||||||
@@ -318,7 +315,7 @@ bool STMClient::process_user_input( int fd )
|
|||||||
for ( int i = 0; i < bytes_read; i++ ) {
|
for ( int i = 0; i < bytes_read; i++ ) {
|
||||||
char the_byte = buf[ i ];
|
char the_byte = buf[ i ];
|
||||||
|
|
||||||
overlays.get_prediction_engine().new_user_byte( the_byte, *local_framebuffer );
|
overlays.get_prediction_engine().new_user_byte( the_byte, local_framebuffer );
|
||||||
|
|
||||||
if ( quit_sequence_started ) {
|
if ( quit_sequence_started ) {
|
||||||
if ( the_byte == '.' ) { /* Quit sequence is Ctrl-^ . */
|
if ( the_byte == '.' ) { /* Quit sequence is Ctrl-^ . */
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ private:
|
|||||||
|
|
||||||
struct winsize window_size;
|
struct winsize window_size;
|
||||||
|
|
||||||
Terminal::Framebuffer *local_framebuffer, *new_state;
|
Terminal::Framebuffer local_framebuffer, new_state;
|
||||||
Overlay::OverlayManager overlays;
|
Overlay::OverlayManager overlays;
|
||||||
Network::Transport< Network::UserStream, Terminal::Complete > *network;
|
Network::Transport< Network::UserStream, Terminal::Complete > *network;
|
||||||
Terminal::Display display;
|
Terminal::Display display;
|
||||||
@@ -89,8 +89,8 @@ public:
|
|||||||
escape_requires_lf( false ), escape_key_help( L"?" ),
|
escape_requires_lf( false ), escape_key_help( L"?" ),
|
||||||
saved_termios(), raw_termios(),
|
saved_termios(), raw_termios(),
|
||||||
window_size(),
|
window_size(),
|
||||||
local_framebuffer( NULL ),
|
local_framebuffer( 1, 1 ),
|
||||||
new_state( NULL ),
|
new_state( 1, 1 ),
|
||||||
overlays(),
|
overlays(),
|
||||||
network( NULL ),
|
network( NULL ),
|
||||||
display( true ), /* use TERM environment var to initialize display */
|
display( true ), /* use TERM environment var to initialize display */
|
||||||
@@ -122,14 +122,6 @@ public:
|
|||||||
|
|
||||||
~STMClient()
|
~STMClient()
|
||||||
{
|
{
|
||||||
if ( local_framebuffer != NULL ) {
|
|
||||||
delete local_framebuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( new_state != NULL ) {
|
|
||||||
delete new_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( network != NULL ) {
|
if ( network != NULL ) {
|
||||||
delete network;
|
delete network;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -143,25 +143,20 @@ std::string Display::new_frame( bool initialized, const Framebuffer &last, const
|
|||||||
}
|
}
|
||||||
|
|
||||||
int frame_y = 0;
|
int frame_y = 0;
|
||||||
Row blankrow( 0, 0 );
|
Framebuffer::row_pointer blank_row;
|
||||||
Framebuffer::rows_p_type rows(frame.last_frame.get_p_rows());
|
Framebuffer::rows_type rows( frame.last_frame.get_rows() );
|
||||||
/* Extend rows if we've gotten a resize and new is wider than old */
|
/* Extend rows if we've gotten a resize and new is wider than old */
|
||||||
if ( frame.last_frame.ds.get_width() < f.ds.get_width() ) {
|
if ( frame.last_frame.ds.get_width() < f.ds.get_width() ) {
|
||||||
for ( Framebuffer::rows_p_type::iterator p = rows.begin(); p != rows.end(); p++ ) {
|
for ( Framebuffer::rows_type::iterator p = rows.begin(); p != rows.end(); p++ ) {
|
||||||
Row *bigger_row = new Row( **p );
|
*p = Framebuffer::row_pointer( new Row( **p ) );
|
||||||
bigger_row->cells.resize( f.ds.get_width(), Cell( f.ds.get_background_rendition() ) );
|
(*p)->cells.resize( f.ds.get_width(), Cell( f.ds.get_background_rendition() ) );
|
||||||
*p = bigger_row;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Add rows if we've gotten a resize and new is taller than old */
|
/* Add rows if we've gotten a resize and new is taller than old */
|
||||||
if ( static_cast<int>( rows.size() ) < f.ds.get_height() ) {
|
if ( static_cast<int>( rows.size() ) < f.ds.get_height() ) {
|
||||||
size_t orig_size = rows.size();
|
|
||||||
// get a proper blank row
|
// get a proper blank row
|
||||||
blankrow = Row( f.ds.get_width(), 0 );
|
blank_row = Framebuffer::row_pointer( new Row( f.ds.get_width(), 0 ) );
|
||||||
rows.resize( f.ds.get_height() );
|
rows.resize( f.ds.get_height(), blank_row );
|
||||||
for ( Framebuffer::rows_p_type::iterator p = rows.begin() + orig_size; p != rows.end(); p++ ) {
|
|
||||||
*p = new Row( blankrow );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* shortcut -- has display moved up by a certain number of lines? */
|
/* shortcut -- has display moved up by a certain number of lines? */
|
||||||
@@ -171,7 +166,7 @@ std::string Display::new_frame( bool initialized, const Framebuffer &last, const
|
|||||||
|
|
||||||
for ( int row = 0; row < f.ds.get_height(); row++ ) {
|
for ( int row = 0; row < f.ds.get_height(); row++ ) {
|
||||||
const Row *new_row = f.get_row( 0 );
|
const Row *new_row = f.get_row( 0 );
|
||||||
const Row *old_row = rows.at( row );
|
const Row *old_row = &*rows.at( row );
|
||||||
if ( new_row == old_row || *new_row == *old_row ) {
|
if ( new_row == old_row || *new_row == *old_row ) {
|
||||||
/* if row 0, we're looking at ourselves and probably didn't scroll */
|
/* if row 0, we're looking at ourselves and probably didn't scroll */
|
||||||
if ( row == 0 ) {
|
if ( row == 0 ) {
|
||||||
@@ -201,6 +196,10 @@ std::string Display::new_frame( bool initialized, const Framebuffer &last, const
|
|||||||
frame_y = scroll_height;
|
frame_y = scroll_height;
|
||||||
|
|
||||||
if ( lines_scrolled ) {
|
if ( lines_scrolled ) {
|
||||||
|
/* Now we need a proper blank row. */
|
||||||
|
if ( blank_row.get() == NULL ) {
|
||||||
|
blank_row = Framebuffer::row_pointer( new Row( f.ds.get_width(), 0 ) );
|
||||||
|
}
|
||||||
frame.update_rendition( initial_rendition(), true );
|
frame.update_rendition( initial_rendition(), true );
|
||||||
|
|
||||||
int top_margin = 0;
|
int top_margin = 0;
|
||||||
@@ -234,15 +233,12 @@ std::string Display::new_frame( bool initialized, const Framebuffer &last, const
|
|||||||
frame.cursor_x = frame.cursor_y = -1;
|
frame.cursor_x = frame.cursor_y = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create a full-width blank row to represent newly-scrolled area */
|
|
||||||
blankrow = Row( f.ds.get_width(), 0 );
|
|
||||||
|
|
||||||
/* do the move in our local index */
|
/* do the move in our local index */
|
||||||
for ( int i = top_margin; i <= bottom_margin; i++ ) {
|
for ( int i = top_margin; i <= bottom_margin; i++ ) {
|
||||||
if ( i + lines_scrolled <= bottom_margin ) {
|
if ( i + lines_scrolled <= bottom_margin ) {
|
||||||
rows.at( i ) = rows.at( i + lines_scrolled );
|
rows.at( i ) = rows.at( i + lines_scrolled );
|
||||||
} else {
|
} else {
|
||||||
rows.at( i ) = &blankrow;
|
rows.at( i ) = blank_row;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,12 +84,31 @@ 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, 0 ) ), icon_name(), window_title(), bell_count( 0 ), title_initialized( false ), ds( s_width, s_height )
|
: rows( s_height, row_pointer(new Row( s_width, 0 ))), icon_name(), window_title(), bell_count( 0 ), title_initialized( false ), ds( s_width, s_height )
|
||||||
{
|
{
|
||||||
assert( s_height > 0 );
|
assert( s_height > 0 );
|
||||||
assert( s_width > 0 );
|
assert( s_width > 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Framebuffer::Framebuffer( const Framebuffer &other )
|
||||||
|
: rows( other.rows ), icon_name( other.icon_name ), window_title( other.window_title ),
|
||||||
|
bell_count( other.bell_count ), title_initialized( other.title_initialized ), ds( other.ds )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Framebuffer & Framebuffer::operator=( const Framebuffer &other )
|
||||||
|
{
|
||||||
|
if ( this != &other ) {
|
||||||
|
rows = other.rows;
|
||||||
|
icon_name = other.icon_name;
|
||||||
|
window_title = other.window_title;
|
||||||
|
bell_count = other.bell_count;
|
||||||
|
title_initialized = other.title_initialized;
|
||||||
|
ds = other.ds;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
void Framebuffer::scroll( int N )
|
void Framebuffer::scroll( int N )
|
||||||
{
|
{
|
||||||
if ( N >= 0 ) {
|
if ( N >= 0 ) {
|
||||||
@@ -286,14 +305,9 @@ void Framebuffer::insert_line( int before_row, int count )
|
|||||||
// delete old rows
|
// delete old rows
|
||||||
rows_type::iterator start = rows.begin() + ds.get_scrolling_region_bottom_row() + 1 - count;
|
rows_type::iterator start = rows.begin() + ds.get_scrolling_region_bottom_row() + 1 - count;
|
||||||
rows.erase( start, start + count );
|
rows.erase( start, start + count );
|
||||||
// insert a block of dummy rows
|
// insert new rows
|
||||||
start = rows.begin() + before_row;
|
start = rows.begin() + before_row;
|
||||||
rows.insert( start, count, Row( 0, 0 ) );
|
rows.insert( start, count, newrow());
|
||||||
// then replace with real new rows
|
|
||||||
start = rows.begin() + before_row;
|
|
||||||
for (rows_type::iterator i = start; i < start + count; i++) {
|
|
||||||
*i = newrow();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Framebuffer::delete_line( int row, int count )
|
void Framebuffer::delete_line( int row, int count )
|
||||||
@@ -317,12 +331,7 @@ void Framebuffer::delete_line( int row, int count )
|
|||||||
rows.erase( start, start + count );
|
rows.erase( start, start + count );
|
||||||
// insert a block of dummy rows
|
// insert a block of dummy rows
|
||||||
start = rows.begin() + ds.get_scrolling_region_bottom_row() + 1 - count;
|
start = rows.begin() + ds.get_scrolling_region_bottom_row() + 1 - count;
|
||||||
rows.insert( start, count, Row( 0, 0 ) );
|
rows.insert( start, count, newrow());
|
||||||
// then replace with real new rows
|
|
||||||
start = rows.begin() + ds.get_scrolling_region_bottom_row() + 1 - count;
|
|
||||||
for (rows_type::iterator i = start; i < start + count; i++) {
|
|
||||||
*i = newrow();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Row::Row( size_t s_width, color_type background_color )
|
Row::Row( size_t s_width, color_type background_color )
|
||||||
@@ -355,12 +364,12 @@ void Row::delete_cell( int col, color_type background_color )
|
|||||||
|
|
||||||
void Framebuffer::insert_cell( int row, int col )
|
void Framebuffer::insert_cell( int row, int col )
|
||||||
{
|
{
|
||||||
rows.at( row ).insert_cell( col, ds.get_background_rendition() );
|
get_mutable_row( row )->insert_cell( col, ds.get_background_rendition() );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Framebuffer::delete_cell( int row, int col )
|
void Framebuffer::delete_cell( int row, int col )
|
||||||
{
|
{
|
||||||
rows.at( row ).delete_cell( col, ds.get_background_rendition() );
|
get_mutable_row( row )->delete_cell( col, ds.get_background_rendition() );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Framebuffer::reset( void )
|
void Framebuffer::reset( void )
|
||||||
@@ -388,8 +397,8 @@ void Framebuffer::posterize( void )
|
|||||||
for ( rows_type::iterator i = rows.begin();
|
for ( rows_type::iterator i = rows.begin();
|
||||||
i != rows.end();
|
i != rows.end();
|
||||||
i++ ) {
|
i++ ) {
|
||||||
for ( Row::cells_type::iterator j = i->cells.begin();
|
for ( Row::cells_type::iterator j = (*i)->cells.begin();
|
||||||
j != i->cells.end();
|
j != (*i)->cells.end();
|
||||||
j++ ) {
|
j++ ) {
|
||||||
j->renditions.posterize();
|
j->renditions.posterize();
|
||||||
}
|
}
|
||||||
@@ -401,15 +410,23 @@ void Framebuffer::resize( int s_width, int s_height )
|
|||||||
assert( s_width > 0 );
|
assert( s_width > 0 );
|
||||||
assert( s_height > 0 );
|
assert( s_height > 0 );
|
||||||
|
|
||||||
|
int oldheight = ds.get_height();
|
||||||
|
int oldwidth = ds.get_width();
|
||||||
ds.resize( s_width, s_height );
|
ds.resize( s_width, s_height );
|
||||||
|
|
||||||
rows.resize( s_height, newrow() );
|
row_pointer blankrow( newrow());
|
||||||
|
if ( oldheight != s_height ) {
|
||||||
|
rows.resize( s_height, blankrow );
|
||||||
|
}
|
||||||
|
if (oldwidth == s_width) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
for ( rows_type::iterator i = rows.begin();
|
for ( rows_type::iterator i = rows.begin();
|
||||||
i != rows.end();
|
i != rows.end() && *i != blankrow;
|
||||||
i++ ) {
|
i++ ) {
|
||||||
i->set_wrap( false );
|
*i = Framebuffer::row_pointer( new Row( **i ) );
|
||||||
i->cells.resize( s_width, Cell( ds.get_background_rendition() ) );
|
(*i)->set_wrap( false );
|
||||||
|
(*i)->cells.resize( s_width, Cell( ds.get_background_rendition() ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,9 +42,12 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
|
#include "shared.h"
|
||||||
|
|
||||||
/* Terminal framebuffer */
|
/* Terminal framebuffer */
|
||||||
|
|
||||||
namespace Terminal {
|
namespace Terminal {
|
||||||
|
using shared::shared_ptr;
|
||||||
typedef uint16_t color_type;
|
typedef uint16_t color_type;
|
||||||
|
|
||||||
class Renditions {
|
class Renditions {
|
||||||
@@ -288,41 +291,48 @@ namespace Terminal {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class Framebuffer {
|
class Framebuffer {
|
||||||
|
// To minimize copying of rows and cells, we use shared_ptr to
|
||||||
|
// share unchanged rows between multiple Framebuffers. If we
|
||||||
|
// write to a row in a Framebuffer and it is shared with other
|
||||||
|
// owners, we copy it first. The shared_ptr naturally manages the
|
||||||
|
// usage of the actual rows themselves.
|
||||||
|
//
|
||||||
|
// We gain a couple of free extras by doing this:
|
||||||
|
//
|
||||||
|
// * A quick check for equality between rows in different
|
||||||
|
// Framebuffers is to simply compare the pointer values. If they
|
||||||
|
// are equal, then the rows are obviously identical.
|
||||||
|
// * If no row is shared, the frame has not been modified.
|
||||||
public:
|
public:
|
||||||
typedef std::vector<wchar_t> title_type;
|
typedef std::vector<wchar_t> title_type;
|
||||||
typedef std::vector<const Row *> rows_p_type;
|
typedef shared_ptr<Row> row_pointer;
|
||||||
|
typedef std::vector<row_pointer> rows_type; /* can be either std::vector or std::deque */
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef std::vector<Row> rows_type;
|
|
||||||
rows_type rows;
|
rows_type rows;
|
||||||
title_type icon_name;
|
title_type icon_name;
|
||||||
title_type window_title;
|
title_type window_title;
|
||||||
unsigned int bell_count;
|
unsigned int bell_count;
|
||||||
bool title_initialized; /* true if the window title has been set via an OSC */
|
bool title_initialized; /* true if the window title has been set via an OSC */
|
||||||
|
|
||||||
Row newrow( void ) { return Row( ds.get_width(), ds.get_background_rendition() ); }
|
row_pointer newrow( void ) { return row_pointer( new Row( ds.get_width(), ds.get_background_rendition())); }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Framebuffer( int s_width, int s_height );
|
Framebuffer( int s_width, int s_height );
|
||||||
|
Framebuffer( const Framebuffer &other );
|
||||||
|
Framebuffer &operator=( const Framebuffer &other );
|
||||||
DrawState ds;
|
DrawState ds;
|
||||||
|
|
||||||
|
const rows_type &get_rows() const { return rows; }
|
||||||
|
|
||||||
void scroll( int N );
|
void scroll( int N );
|
||||||
void move_rows_autoscroll( int rows );
|
void move_rows_autoscroll( int rows );
|
||||||
|
|
||||||
rows_p_type get_p_rows() const
|
inline const Row *get_row( int row ) const
|
||||||
{
|
|
||||||
rows_p_type retval;
|
|
||||||
for ( size_t i = 0; i < rows.size(); i++ ) {
|
|
||||||
retval.push_back( &rows.at(i) );
|
|
||||||
}
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Row *get_row( int row ) const
|
|
||||||
{
|
{
|
||||||
if ( row == -1 ) row = ds.get_cursor_row();
|
if ( row == -1 ) row = ds.get_cursor_row();
|
||||||
|
|
||||||
return &rows.at( row );
|
return rows.at( row ).get();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const Cell *get_cell( int row = -1, int col = -1 ) const
|
inline const Cell *get_cell( int row = -1, int col = -1 ) const
|
||||||
@@ -330,17 +340,26 @@ namespace Terminal {
|
|||||||
if ( row == -1 ) row = ds.get_cursor_row();
|
if ( row == -1 ) row = ds.get_cursor_row();
|
||||||
if ( col == -1 ) col = ds.get_cursor_col();
|
if ( col == -1 ) col = ds.get_cursor_col();
|
||||||
|
|
||||||
return &rows.at( row ).cells.at( col );
|
return &rows.at( row )->cells.at( col );
|
||||||
}
|
}
|
||||||
|
|
||||||
Row *get_mutable_row( int row )
|
Row *get_mutable_row( int row )
|
||||||
{
|
{
|
||||||
return const_cast<Row *>(get_row( row ));
|
if ( row == -1 ) row = ds.get_cursor_row();
|
||||||
|
row_pointer &mutable_row = rows.at( row );
|
||||||
|
// If the row is shared, copy it.
|
||||||
|
if (!mutable_row.unique()) {
|
||||||
|
mutable_row = row_pointer( new Row( *mutable_row ));
|
||||||
|
}
|
||||||
|
return mutable_row.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Cell *get_mutable_cell( int row = -1, int col = -1 )
|
Cell *get_mutable_cell( int row = -1, int col = -1 )
|
||||||
{
|
{
|
||||||
return const_cast<Cell *>(get_cell( row, col ));
|
if ( row == -1 ) row = ds.get_cursor_row();
|
||||||
|
if ( col == -1 ) col = ds.get_cursor_col();
|
||||||
|
|
||||||
|
return &get_mutable_row( row )->cells.at( col );
|
||||||
}
|
}
|
||||||
|
|
||||||
Cell *get_combining_cell( void );
|
Cell *get_combining_cell( void );
|
||||||
|
|||||||
@@ -2,4 +2,4 @@ AM_CXXFLAGS = $(WARNING_CXXFLAGS) $(PICKY_CXXFLAGS) $(HARDEN_CFLAGS) $(MISC_CXXF
|
|||||||
|
|
||||||
noinst_LIBRARIES = libmoshutil.a
|
noinst_LIBRARIES = libmoshutil.a
|
||||||
|
|
||||||
libmoshutil_a_SOURCES = locale_utils.cc locale_utils.h swrite.cc swrite.h dos_assert.h fatal_assert.h select.h select.cc timestamp.h timestamp.cc pty_compat.cc pty_compat.h
|
libmoshutil_a_SOURCES = locale_utils.cc locale_utils.h swrite.cc swrite.h dos_assert.h fatal_assert.h select.h select.cc timestamp.h timestamp.cc pty_compat.cc pty_compat.h shared.h
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
Mosh: the mobile shell
|
||||||
|
Copyright 2012 Keith Winstein
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
In addition, as a special exception, the copyright holders give
|
||||||
|
permission to link the code of portions of this program with the
|
||||||
|
OpenSSL library under certain conditions as described in each
|
||||||
|
individual source file, and distribute linked combinations including
|
||||||
|
the two.
|
||||||
|
|
||||||
|
You must obey the GNU General Public License in all respects for all
|
||||||
|
of the code used other than OpenSSL. If you modify file(s) with this
|
||||||
|
exception, you may extend this exception to your version of the
|
||||||
|
file(s), but you are not obligated to do so. If you do not wish to do
|
||||||
|
so, delete this exception statement from your version. If you delete
|
||||||
|
this exception statement from all source files in the program, then
|
||||||
|
also delete it here.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SHARED_HPP
|
||||||
|
#define SHARED_HPP
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_TR1_MEMORY
|
||||||
|
#include <tr1/memory>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace shared {
|
||||||
|
#ifdef HAVE_STD_SHARED_PTR
|
||||||
|
using std::shared_ptr;
|
||||||
|
#else
|
||||||
|
#ifdef HAVE_STD_TR1_SHARED_PTR
|
||||||
|
using std::tr1::shared_ptr;
|
||||||
|
#else
|
||||||
|
#error Need a shared_ptr class. Try Boost::TR1.
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user