Display error messages in top-line overlay.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
proto = userinput.proto transportinstruction.proto
|
||||
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 network.cpp ntester.cpp ocb.cpp base64.cpp encrypt.cpp decrypt.cpp crypto.cpp networktransport.cpp transportfragment.cpp user.cpp userinput.pb.cc completeterminal.cpp stm-server.cpp stm.cpp transportinstruction.pb.cc transportsender.cpp stmclient.cpp
|
||||
objects = parserstate.o parser.o templates.o terminal.o parseraction.o terminalfunctions.o swrite.o terminalframebuffer.o terminaldispatcher.o terminaluserinput.o terminaldisplay.o network.o ocb.o base64.o crypto.o networktransport.o transportfragment.o user.o userinput.pb.o completeterminal.o transportinstruction.pb.o transportsender.o stmclient.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 network.cpp ntester.cpp ocb.cpp base64.cpp encrypt.cpp decrypt.cpp crypto.cpp networktransport.cpp transportfragment.cpp user.cpp userinput.pb.cc completeterminal.cpp stm-server.cpp stm.cpp transportinstruction.pb.cc transportsender.cpp stmclient.cpp terminaloverlay.cpp
|
||||
objects = parserstate.o parser.o templates.o terminal.o parseraction.o terminalfunctions.o swrite.o terminalframebuffer.o terminaldispatcher.o terminaluserinput.o terminaldisplay.o network.o ocb.o base64.o crypto.o networktransport.o transportfragment.o user.o userinput.pb.o completeterminal.o transportinstruction.pb.o transportsender.o stmclient.o terminaloverlay.o
|
||||
repos = templates.rpo
|
||||
executables = parse termemu ntester encrypt decrypt stm-server stm
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ namespace Terminal {
|
||||
std::string act( const Parser::Action *act );
|
||||
|
||||
const Framebuffer & get_fb( void ) const { return terminal.get_fb(); }
|
||||
bool parser_grounded( void ) const { return parser.is_grounded(); }
|
||||
|
||||
/* interface for Network::Transport */
|
||||
void subtract( const Complete * ) {}
|
||||
|
||||
+5
-1
@@ -18,7 +18,7 @@
|
||||
#endif
|
||||
|
||||
namespace Parser {
|
||||
static StateFamily family;
|
||||
static const StateFamily family;
|
||||
|
||||
class Parser {
|
||||
private:
|
||||
@@ -37,6 +37,8 @@ namespace Parser {
|
||||
{
|
||||
return state == x.state;
|
||||
}
|
||||
|
||||
bool is_grounded( void ) const { return state == &family.s_Ground; }
|
||||
};
|
||||
|
||||
static const size_t BUF_SIZE = 8;
|
||||
@@ -57,6 +59,8 @@ namespace Parser {
|
||||
{
|
||||
return parser == x.parser;
|
||||
}
|
||||
|
||||
bool is_grounded( void ) const { return parser.is_grounded(); }
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+38
-14
@@ -11,12 +11,14 @@
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <sys/signalfd.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "stmclient.hpp"
|
||||
#include "swrite.hpp"
|
||||
#include "networktransport.hpp"
|
||||
#include "completeterminal.hpp"
|
||||
#include "user.hpp"
|
||||
#include "network.hpp"
|
||||
|
||||
void STMClient::init( void )
|
||||
{
|
||||
@@ -100,33 +102,44 @@ void STMClient::main_init( void )
|
||||
}
|
||||
|
||||
/* local state */
|
||||
local_terminal = new Terminal::Complete( window_size.ws_col, window_size.ws_row );
|
||||
local_framebuffer = new Terminal::Framebuffer( window_size.ws_col, window_size.ws_row );
|
||||
|
||||
/* initialize screen */
|
||||
string init = Terminal::Display::new_frame( false, local_terminal->get_fb(), local_terminal->get_fb() );
|
||||
string init = Terminal::Display::new_frame( false, *local_framebuffer, *local_framebuffer );
|
||||
swrite( STDOUT_FILENO, init.data(), init.size() );
|
||||
|
||||
/* open network */
|
||||
Network::UserStream blank;
|
||||
network = new Network::Transport< Network::UserStream, Terminal::Complete >( blank, *local_terminal,
|
||||
Terminal::Complete local_terminal( window_size.ws_col, window_size.ws_row );
|
||||
network = new Network::Transport< Network::UserStream, Terminal::Complete >( blank, local_terminal,
|
||||
key.c_str(), ip.c_str(), port );
|
||||
|
||||
/* tell server the size of the terminal */
|
||||
network->get_current_state().push_back( Parser::Resize( window_size.ws_col, window_size.ws_row ) );
|
||||
}
|
||||
|
||||
void STMClient::output_new_frame( void )
|
||||
{
|
||||
/* fetch target state */
|
||||
Terminal::Framebuffer new_state( network->get_latest_remote_state().state.get_fb() );
|
||||
|
||||
/* apply local overlays */
|
||||
overlays.get_notification_engine().render_notification();
|
||||
overlays.apply( new_state );
|
||||
|
||||
/* calculate minimal difference from where we are */
|
||||
string diff = Terminal::Display::new_frame( true,
|
||||
*local_framebuffer,
|
||||
new_state );
|
||||
swrite( STDOUT_FILENO, diff.data(), diff.size() );
|
||||
*local_framebuffer = new_state;
|
||||
}
|
||||
|
||||
bool STMClient::process_network_input( void )
|
||||
{
|
||||
network->recv();
|
||||
|
||||
/* is a new frame available from the terminal? */
|
||||
if ( network->get_remote_state_num() != last_remote_num ) {
|
||||
string diff = Terminal::Display::new_frame( true,
|
||||
local_terminal->get_fb(),
|
||||
network->get_latest_remote_state().state.get_fb() );
|
||||
swrite( STDOUT_FILENO, diff.data(), diff.size() );
|
||||
*local_terminal = network->get_latest_remote_state().state;
|
||||
}
|
||||
overlays.get_notification_engine().server_ping( network->get_latest_remote_state().timestamp );
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -147,7 +160,8 @@ bool STMClient::process_user_input( int fd )
|
||||
|
||||
if ( !network->shutdown_in_progress() ) {
|
||||
for ( int i = 0; i < bytes_read; i++ ) {
|
||||
network->get_current_state().push_back( Parser::UserByte( buf[ i ] ) );
|
||||
char the_byte = buf[ i ];
|
||||
network->get_current_state().push_back( Parser::UserByte( the_byte ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,6 +221,8 @@ void STMClient::main( void )
|
||||
|
||||
while ( 1 ) {
|
||||
try {
|
||||
output_new_frame();
|
||||
|
||||
int active_fds = poll( pollfds, 4, network->wait_time() );
|
||||
if ( active_fds < 0 ) {
|
||||
perror( "poll" );
|
||||
@@ -240,6 +256,7 @@ void STMClient::main( void )
|
||||
}
|
||||
|
||||
if ( network->attached() && (!network->shutdown_in_progress()) ) {
|
||||
overlays.get_notification_engine().set_notification_string( wstring( L"Signal received, shutting down..." ) );
|
||||
network->start_shutdown();
|
||||
} else {
|
||||
break;
|
||||
@@ -256,6 +273,7 @@ void STMClient::main( void )
|
||||
& (POLLERR | POLLHUP | POLLNVAL) ) {
|
||||
/* user problem */
|
||||
if ( network->attached() && (!network->shutdown_in_progress()) ) {
|
||||
overlays.get_notification_engine().set_notification_string( wstring( L"Exiting..." ) );
|
||||
network->start_shutdown();
|
||||
} else {
|
||||
break;
|
||||
@@ -279,8 +297,14 @@ void STMClient::main( void )
|
||||
|
||||
network->tick();
|
||||
} catch ( Network::NetworkException e ) {
|
||||
fprintf( stderr, "%s: %s\r\n", e.function.c_str(), strerror( e.the_errno ) );
|
||||
sleep( 1 );
|
||||
wchar_t tmp[ 128 ];
|
||||
swprintf( tmp, 128, L"%s: %s\r\n", e.function.c_str(), strerror( e.the_errno ) );
|
||||
overlays.get_notification_engine().set_notification_string( wstring( tmp ) );
|
||||
struct timespec req;
|
||||
req.tv_sec = 0;
|
||||
req.tv_nsec = 200000000; /* 0.2 sec */
|
||||
nanosleep( &req, NULL );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+9
-4
@@ -8,6 +8,7 @@
|
||||
#include "completeterminal.hpp"
|
||||
#include "networktransport.hpp"
|
||||
#include "user.hpp"
|
||||
#include "terminaloverlay.hpp"
|
||||
|
||||
class STMClient {
|
||||
private:
|
||||
@@ -20,7 +21,8 @@ private:
|
||||
int winch_fd, shutdown_signal_fd;
|
||||
struct winsize window_size;
|
||||
|
||||
Terminal::Complete *local_terminal;
|
||||
Terminal::Framebuffer *local_framebuffer;
|
||||
Overlay::OverlayManager overlays;
|
||||
Network::Transport< Network::UserStream, Terminal::Complete > *network;
|
||||
uint64_t last_remote_num;
|
||||
|
||||
@@ -29,13 +31,16 @@ private:
|
||||
bool process_user_input( int fd );
|
||||
bool process_resize( void );
|
||||
|
||||
void output_new_frame( void );
|
||||
|
||||
public:
|
||||
STMClient( const char *s_ip, int s_port, const char *s_key )
|
||||
: ip( s_ip ), port( s_port ), key( s_key ),
|
||||
saved_termios(), raw_termios(),
|
||||
winch_fd(), shutdown_signal_fd(),
|
||||
window_size(),
|
||||
local_terminal( NULL ),
|
||||
local_framebuffer( NULL ),
|
||||
overlays(),
|
||||
network( NULL ),
|
||||
last_remote_num( -1 )
|
||||
{}
|
||||
@@ -46,8 +51,8 @@ public:
|
||||
|
||||
~STMClient()
|
||||
{
|
||||
if ( local_terminal != NULL ) {
|
||||
delete local_terminal;
|
||||
if ( local_framebuffer != NULL ) {
|
||||
delete local_framebuffer;
|
||||
}
|
||||
|
||||
if ( network != NULL ) {
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "terminal.hpp"
|
||||
#include "completeterminal.hpp"
|
||||
#include "terminaloverlay.hpp"
|
||||
|
||||
#include "user.hpp"
|
||||
#include "networktransport.cpp"
|
||||
@@ -19,6 +20,7 @@ namespace Parser {
|
||||
using namespace std;
|
||||
using namespace Terminal;
|
||||
using namespace Network;
|
||||
using namespace Overlay;
|
||||
|
||||
template class list<Parser::Action *>;
|
||||
template class vector<Cell>;
|
||||
@@ -38,3 +40,4 @@ template class TransportSender<UserStream>;
|
||||
template class TransportSender<Complete>;
|
||||
|
||||
template class deque<UserEvent>;
|
||||
template class list<OverlayElement *>;
|
||||
|
||||
+18
-9
@@ -84,11 +84,7 @@ std::string Display::new_frame( bool initialized, const Framebuffer &last, const
|
||||
|
||||
if ( lines_scrolled ) {
|
||||
if ( frame.cursor_y != f.ds.get_height() - 1 ) {
|
||||
snprintf( tmp, 64, "\033[%d;%dH", f.ds.get_height(), 1 );
|
||||
frame.append( tmp );
|
||||
|
||||
frame.cursor_y = f.ds.get_height() - 1;
|
||||
frame.cursor_x = 0;
|
||||
frame.append_silent_move( f.ds.get_height() - 1, 0 );
|
||||
}
|
||||
|
||||
if ( frame.current_rendition_string != "\033[0m" ) {
|
||||
@@ -194,10 +190,7 @@ void Display::put_cell( bool initialized, FrameState &frame, const Framebuffer &
|
||||
}
|
||||
|
||||
if ( (frame.x != frame.cursor_x) || (frame.y != frame.cursor_y) ) {
|
||||
snprintf( tmp, 64, "\033[%d;%dH", frame.y + 1, frame.x + 1 );
|
||||
frame.append( tmp );
|
||||
frame.cursor_x = frame.x;
|
||||
frame.cursor_y = frame.y;
|
||||
frame.append_silent_move( frame.y, frame.x );
|
||||
}
|
||||
|
||||
std::string rendition_str = cell->renditions.sgr();
|
||||
@@ -243,3 +236,19 @@ void Display::put_cell( bool initialized, FrameState &frame, const Framebuffer &
|
||||
frame.x += cell->width;
|
||||
frame.cursor_x += cell->width;
|
||||
}
|
||||
|
||||
void FrameState::append_silent_move( int y, int x )
|
||||
{
|
||||
char tmp[ 64 ];
|
||||
|
||||
/* turn off cursor if necessary before moving cursor */
|
||||
if ( last_frame.ds.cursor_visible ) {
|
||||
append( "\033[?25l" );
|
||||
last_frame.ds.cursor_visible = false;
|
||||
}
|
||||
|
||||
snprintf( tmp, 64, "\033[%d;%dH", y + 1, x + 1 );
|
||||
append( tmp );
|
||||
cursor_x = x;
|
||||
cursor_y = y;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@ namespace Terminal {
|
||||
|
||||
FrameState( const Framebuffer &s_last ) : x(0), y(0), str(), cursor_x(0), cursor_y(0), current_rendition_string(), last_frame( s_last ) {}
|
||||
void append( std::string s ) { str.append( s ); }
|
||||
|
||||
void append_silent_move( int y, int x );
|
||||
};
|
||||
|
||||
class Display {
|
||||
|
||||
@@ -0,0 +1,234 @@
|
||||
#include <algorithm>
|
||||
#include <wchar.h>
|
||||
#include <list>
|
||||
|
||||
#include "terminaloverlay.hpp"
|
||||
|
||||
using namespace Overlay;
|
||||
|
||||
Validity OverlayElement::get_validity( const Framebuffer & ) const
|
||||
{
|
||||
return (timestamp() < expiration_time) ? Pending : IncorrectOrExpired;
|
||||
}
|
||||
|
||||
void OverlayCell::apply( Framebuffer &fb ) const
|
||||
{
|
||||
if ( (row >= fb.ds.get_height())
|
||||
|| (col >= fb.ds.get_width()) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
*(fb.get_mutable_cell( row, col )) = replacement;
|
||||
}
|
||||
|
||||
Validity ConditionalOverlayCell::get_validity( const Framebuffer &fb ) const
|
||||
{
|
||||
if ( (row >= fb.ds.get_height())
|
||||
|| (col >= fb.ds.get_width()) ) {
|
||||
return IncorrectOrExpired;
|
||||
}
|
||||
|
||||
const Cell ¤t = *( fb.get_cell( row, col ) );
|
||||
|
||||
if ( (timestamp() < expiration_time) && (current == original_contents) ) {
|
||||
return Pending;
|
||||
}
|
||||
|
||||
if ( current == replacement ) {
|
||||
return Correct;
|
||||
} else {
|
||||
return IncorrectOrExpired;
|
||||
}
|
||||
}
|
||||
|
||||
void CursorMove::apply( Framebuffer &fb ) const
|
||||
{
|
||||
assert( new_row < fb.ds.get_height() );
|
||||
assert( new_col < fb.ds.get_width() );
|
||||
assert( !fb.ds.origin_mode );
|
||||
|
||||
fb.ds.move_row( new_row, false );
|
||||
fb.ds.move_col( new_col, false, false );
|
||||
}
|
||||
|
||||
Validity ConditionalCursorMove::get_validity( const Framebuffer &fb ) const
|
||||
{
|
||||
if ( timestamp() < expiration_time ) {
|
||||
return Pending;
|
||||
}
|
||||
|
||||
if ( (fb.ds.get_cursor_col() == new_col)
|
||||
&& (fb.ds.get_cursor_row() == new_row) ) {
|
||||
return Correct;
|
||||
} else {
|
||||
return IncorrectOrExpired;
|
||||
}
|
||||
}
|
||||
|
||||
void OverlayEngine::clear( void )
|
||||
{
|
||||
for_each( elements.begin(), elements.end(), []( OverlayElement *x ){ delete x; } );
|
||||
elements.clear();
|
||||
}
|
||||
|
||||
OverlayEngine::~OverlayEngine()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
void OverlayEngine::apply( Framebuffer &fb ) const
|
||||
{
|
||||
for_each( elements.begin(), elements.end(),
|
||||
[&fb]( OverlayElement *x ) { x->apply( fb ); } );
|
||||
}
|
||||
|
||||
void OverlayEngine::cull( const Framebuffer &fb )
|
||||
{
|
||||
elements.remove_if( [fb]( OverlayElement *x ) { return IncorrectOrExpired == x->get_validity( fb ); } );
|
||||
}
|
||||
|
||||
OverlayCell::OverlayCell( uint64_t expiration_time, int s_row, int s_col, int background_color )
|
||||
: OverlayElement( expiration_time ), row( s_row ), col( s_col ), replacement( background_color )
|
||||
{}
|
||||
|
||||
NotificationEngine::NotificationEngine()
|
||||
: needs_render( true ),
|
||||
last_word( timestamp() ),
|
||||
last_render( 0 ),
|
||||
message(),
|
||||
message_expiration( 0 )
|
||||
{}
|
||||
|
||||
void NotificationEngine::server_ping( uint64_t s_last_word )
|
||||
{
|
||||
if ( s_last_word - last_word > 4000 ) {
|
||||
needs_render = true;
|
||||
}
|
||||
|
||||
last_word = s_last_word;
|
||||
}
|
||||
|
||||
void NotificationEngine::set_notification_string( const wstring s_message )
|
||||
{
|
||||
message = s_message;
|
||||
message_expiration = timestamp() + 1100;
|
||||
needs_render = true;
|
||||
}
|
||||
|
||||
void NotificationEngine::render_notification( void )
|
||||
{
|
||||
uint64_t now = timestamp();
|
||||
|
||||
if ( (now - last_render < 250) && (!needs_render) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
needs_render = false;
|
||||
last_render = now;
|
||||
|
||||
clear();
|
||||
|
||||
/* determine string to draw */
|
||||
if ( now >= message_expiration ) {
|
||||
message.clear();
|
||||
}
|
||||
|
||||
bool time_expired = now - last_word > 5000;
|
||||
|
||||
wchar_t tmp[ 128 ];
|
||||
|
||||
if ( message.empty() && (!time_expired) ) {
|
||||
return;
|
||||
} else if ( message.empty() && time_expired ) {
|
||||
swprintf( tmp, 128, L"[stm] No contact for %.0f seconds.", (double)(now - last_word) / 1000.0 );
|
||||
} else if ( (!message.empty()) && (!time_expired) ) {
|
||||
swprintf( tmp, 128, L"[stm] %ls", message.c_str() );
|
||||
} else {
|
||||
swprintf( tmp, 128, L"[stm] %ls (No contact for %.0f seconds.)", message.c_str(),
|
||||
(double)(now - last_word) / 1000.0 );
|
||||
}
|
||||
|
||||
wstring string_to_draw( tmp );
|
||||
|
||||
int overlay_col = 0;
|
||||
bool dirty = false;
|
||||
OverlayCell template_cell( now + 1100, 0 /* row */, -1 /* col */, 0 /* background_color */ );
|
||||
|
||||
template_cell.replacement.renditions.inverse = true;
|
||||
|
||||
OverlayCell current( template_cell );
|
||||
|
||||
for ( wstring::const_iterator i = string_to_draw.begin(); i != string_to_draw.end(); i++ ) {
|
||||
wchar_t ch = *i;
|
||||
int chwidth = ch == L'\0' ? -1 : wcwidth( ch );
|
||||
|
||||
switch ( chwidth ) {
|
||||
case 1: /* normal character */
|
||||
case 2: /* wide character */
|
||||
/* finish current cell */
|
||||
if ( dirty ) {
|
||||
elements.push_back( new OverlayCell( current ) );
|
||||
dirty = false;
|
||||
}
|
||||
|
||||
/* initialize new cell */
|
||||
current = template_cell;
|
||||
current.col = overlay_col;
|
||||
current.replacement.contents.push_back( ch );
|
||||
current.replacement.width = chwidth;
|
||||
overlay_col += chwidth;
|
||||
dirty = true;
|
||||
break;
|
||||
|
||||
case 0: /* combining character */
|
||||
if ( current.replacement.contents.empty() ) {
|
||||
/* string starts with combining character?? */
|
||||
/* emulate fallback rendering */
|
||||
current = template_cell;
|
||||
current.col = overlay_col;
|
||||
current.replacement.contents.push_back( 0xA0 ); /* no-break space */
|
||||
current.replacement.width = 1;
|
||||
overlay_col++;
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
current.replacement.contents.push_back( ch );
|
||||
break;
|
||||
|
||||
case -1:
|
||||
break;
|
||||
|
||||
default:
|
||||
assert( false );
|
||||
}
|
||||
}
|
||||
|
||||
if ( dirty ) {
|
||||
elements.push_back( new OverlayCell( current ) );
|
||||
}
|
||||
}
|
||||
|
||||
void NotificationEngine::apply( Framebuffer &fb ) const
|
||||
{
|
||||
if ( elements.empty() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert( fb.ds.get_width() > 0 );
|
||||
assert( fb.ds.get_height() > 0 );
|
||||
|
||||
Cell notification_bar( 0 );
|
||||
notification_bar.renditions.inverse = true;
|
||||
notification_bar.contents.push_back( 0x20 );
|
||||
|
||||
for ( int i = 0; i < fb.ds.get_width(); i++ ) {
|
||||
*(fb.get_mutable_cell( 0, i )) = notification_bar;
|
||||
}
|
||||
|
||||
OverlayEngine::apply( fb );
|
||||
}
|
||||
|
||||
void OverlayManager::apply( Framebuffer &fb ) const
|
||||
{
|
||||
notifications.apply( fb );
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
#ifndef TERMINAL_OVERLAY_HPP
|
||||
#define TERMINAL_OVERLAY_HPP
|
||||
|
||||
#include "terminalframebuffer.hpp"
|
||||
#include "network.hpp"
|
||||
|
||||
#include <list>
|
||||
|
||||
namespace Overlay {
|
||||
using namespace Terminal;
|
||||
using namespace Network;
|
||||
using namespace std;
|
||||
|
||||
enum Validity {
|
||||
Pending,
|
||||
Correct,
|
||||
IncorrectOrExpired
|
||||
};
|
||||
|
||||
/* The individual elements of an overlay -- cursor movements and replaced cells */
|
||||
class OverlayElement {
|
||||
public:
|
||||
uint64_t expiration_time;
|
||||
|
||||
virtual void apply( Framebuffer &fb ) const = 0;
|
||||
virtual Validity get_validity( const Framebuffer & ) const;
|
||||
|
||||
OverlayElement( uint64_t s_expiration_time ) : expiration_time( s_expiration_time ) {}
|
||||
virtual ~OverlayElement() {}
|
||||
};
|
||||
|
||||
class OverlayCell : public OverlayElement {
|
||||
public:
|
||||
int row, col;
|
||||
Cell replacement;
|
||||
|
||||
OverlayCell( uint64_t expiration_time, int s_row, int s_col, int background_color );
|
||||
void apply( Framebuffer &fb ) const;
|
||||
};
|
||||
|
||||
class ConditionalOverlayCell : public OverlayCell {
|
||||
public:
|
||||
Cell original_contents;
|
||||
|
||||
Validity get_validity( const Framebuffer &fb ) const;
|
||||
};
|
||||
|
||||
class CursorMove : public OverlayElement {
|
||||
public:
|
||||
int new_row, new_col;
|
||||
|
||||
void apply( Framebuffer &fb ) const;
|
||||
};
|
||||
|
||||
class ConditionalCursorMove : public CursorMove {
|
||||
public:
|
||||
Validity get_validity( const Framebuffer &fb ) const;
|
||||
};
|
||||
|
||||
/* the various overlays -- some predictive and some for local notifications */
|
||||
class OverlayEngine {
|
||||
protected:
|
||||
list<OverlayElement *> elements;
|
||||
|
||||
public:
|
||||
void cull( const Framebuffer &fb );
|
||||
virtual void apply( Framebuffer &fb ) const;
|
||||
void clear( void );
|
||||
|
||||
OverlayEngine() : elements() {}
|
||||
virtual ~OverlayEngine();
|
||||
};
|
||||
|
||||
class NotificationEngine : public OverlayEngine {
|
||||
private:
|
||||
bool needs_render;
|
||||
|
||||
uint64_t last_word;
|
||||
uint64_t last_render;
|
||||
|
||||
wstring message;
|
||||
uint64_t message_expiration;
|
||||
|
||||
public:
|
||||
void apply( Framebuffer &fb ) const;
|
||||
void set_notification_string( const wstring s_message );
|
||||
void server_ping( uint64_t s_last_word );
|
||||
void render_notification( void );
|
||||
|
||||
NotificationEngine();
|
||||
};
|
||||
|
||||
/* the overlay manager */
|
||||
class OverlayManager {
|
||||
private:
|
||||
NotificationEngine notifications;
|
||||
|
||||
public:
|
||||
void apply( Framebuffer &fb ) const;
|
||||
|
||||
NotificationEngine & get_notification_engine( void ) { return notifications; }
|
||||
|
||||
OverlayManager() : notifications() {}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <algorithm>
|
||||
#include <list>
|
||||
|
||||
#include "transportsender.hpp"
|
||||
#include "transportfragment.hpp"
|
||||
|
||||
Reference in New Issue
Block a user