From e057ea65983545ed7ff4a3b0a6fb76e350bb11ed Mon Sep 17 00:00:00 2001 From: Keith Winstein Date: Tue, 1 Feb 2011 04:14:16 -0500 Subject: [PATCH] Support setting window title (as OS command) --- parseraction.cpp | 15 +++++++++++++++ parseraction.hpp | 12 +++++++++--- terminal.cpp | 18 ++++++++++++++++++ terminal.hpp | 14 ++++---------- terminaldispatcher.cpp | 20 +++++++++++++++++--- terminaldispatcher.hpp | 11 ++++++++++- terminalframebuffer.cpp | 3 ++- terminalframebuffer.hpp | 5 +++++ terminalfunctions.cpp | 17 +++++++++++++++++ 9 files changed, 97 insertions(+), 18 deletions(-) diff --git a/parseraction.cpp b/parseraction.cpp index b3374e7..ef7fb64 100644 --- a/parseraction.cpp +++ b/parseraction.cpp @@ -50,3 +50,18 @@ void Esc_Dispatch::act_on_terminal( Terminal::Emulator *emu ) { emu->Esc_dispatch( this ); } + +void OSC_Put::act_on_terminal( Terminal::Emulator *emu ) +{ + emu->dispatch.OSC_put( this ); +} + +void OSC_Start::act_on_terminal( Terminal::Emulator *emu ) +{ + emu->dispatch.OSC_start( this ); +} + +void OSC_End::act_on_terminal( Terminal::Emulator *emu ) +{ + emu->OSC_end( this ); +} diff --git a/parseraction.hpp b/parseraction.hpp index 9402a09..14743ae 100644 --- a/parseraction.hpp +++ b/parseraction.hpp @@ -73,13 +73,19 @@ namespace Parser { public: std::string name( void ) { return std::string( "Unhook" ); } }; class OSC_Start : public Action { - public: std::string name( void ) { return std::string( "OSC_Start" ); } + public: + std::string name( void ) { return std::string( "OSC_Start" ); } + void act_on_terminal( Terminal::Emulator *emu ); }; class OSC_Put : public Action { - public: std::string name( void ) { return std::string( "OSC_Put" ); } + public: + std::string name( void ) { return std::string( "OSC_Put" ); } + void act_on_terminal( Terminal::Emulator *emu ); }; class OSC_End : public Action { - public: std::string name( void ) { return std::string( "OSC_End" ); } + public: + std::string name( void ) { return std::string( "OSC_End" ); } + void act_on_terminal( Terminal::Emulator *emu ); }; } diff --git a/terminal.cpp b/terminal.cpp index f7623ad..aacd7d0 100644 --- a/terminal.cpp +++ b/terminal.cpp @@ -120,6 +120,12 @@ void Emulator::CSI_dispatch( Parser::CSI_Dispatch *act ) dispatch.dispatch( CSI, act, &fb ); } +void Emulator::OSC_end( Parser::OSC_End *act ) +{ + fb.ds.next_print_will_wrap = false; + dispatch.OSC_dispatch( act, &fb ); +} + void Emulator::Esc_dispatch( Parser::Esc_Dispatch *act ) { fb.ds.next_print_will_wrap = false; @@ -140,6 +146,18 @@ void Emulator::debug_printout( int fd ) std::string screen; screen.append( "\033[H" ); + /* set window title */ + screen.append( "\033]0;" ); + std::vector window_title = fb.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( "\x7" ); /* xterm's "OSC" string ends in BEL... */ + for ( int y = 0; y < fb.ds.get_height(); y++ ) { for ( int x = 0; x < fb.ds.get_width(); /* let charwidth handle advance */ ) { char curmove[ 32 ]; diff --git a/terminal.hpp b/terminal.hpp index c2ad8f4..20f8c8f 100644 --- a/terminal.hpp +++ b/terminal.hpp @@ -19,6 +19,9 @@ namespace Terminal { friend void Parser::Collect::act_on_terminal( Emulator * ); friend void Parser::CSI_Dispatch::act_on_terminal( Emulator * ); friend void Parser::Esc_Dispatch::act_on_terminal( Emulator * ); + friend void Parser::OSC_Start::act_on_terminal( Emulator * ); + friend void Parser::OSC_Put::act_on_terminal( Emulator * ); + friend void Parser::OSC_End::act_on_terminal( Emulator * ); private: Parser::UTF8Parser parser; @@ -28,18 +31,9 @@ namespace Terminal { /* action methods */ void print( Parser::Print *act ); void execute( Parser::Execute *act ); - void param( Parser::Param *act ); - void collect( Parser::Collect *act ); - void clear( Parser::Clear *act ); void CSI_dispatch( Parser::CSI_Dispatch *act ); void Esc_dispatch( Parser::Esc_Dispatch *act ); - - /* CSI and Escape methods */ - void CSI_EL( void ); - void CSI_ED( void ); - void CSI_cursormove( void ); - void CSI_DA( void ); - void Esc_DECALN( void ); + void OSC_end( Parser::OSC_End *act ); public: Emulator( size_t s_width, size_t s_height ); diff --git a/terminaldispatcher.cpp b/terminaldispatcher.cpp index d43b2ce..e72c26f 100644 --- a/terminaldispatcher.cpp +++ b/terminaldispatcher.cpp @@ -9,7 +9,7 @@ using namespace Terminal; Dispatcher::Dispatcher() : params(), parsed_params(), parsed( false ), dispatch_chars(), - terminal_to_host() + OSC_string(), terminal_to_host() {} void Dispatcher::newparamchar( Parser::Param *act ) @@ -146,8 +146,7 @@ Function::Function( Function_Type type, std::string dispatch_chars, void Dispatcher::dispatch( Function_Type type, Parser::Action *act, Framebuffer *fb ) { /* add final char to dispatch key */ - - if ( type != CONTROL ) { + if ( (type == ESCAPE) || (type == CSI) ) { assert( act->char_present ); Parser::Collect act2; act2.char_present = true; @@ -177,3 +176,18 @@ void Dispatcher::dispatch( Function_Type type, Parser::Action *act, Framebuffer return i->second.function( fb, this ); } } + +void Dispatcher::OSC_put( Parser::OSC_Put *act ) +{ + assert( act->char_present ); + if ( OSC_string.size() < 256 ) { /* should be a long enough window title */ + OSC_string.push_back( act->ch ); + act->handled = true; + } +} + +void Dispatcher::OSC_start( Parser::OSC_Start *act ) +{ + OSC_string.clear(); + act->handled = true; +} diff --git a/terminaldispatcher.hpp b/terminaldispatcher.hpp index 81294d1..37447f9 100644 --- a/terminaldispatcher.hpp +++ b/terminaldispatcher.hpp @@ -13,6 +13,9 @@ namespace Parser { class Esc_Dispatch; class CSI_Dispatch; class Execute; + class OSC_Start; + class OSC_Put; + class OSC_End; } namespace Terminal { @@ -49,6 +52,7 @@ namespace Terminal { bool parsed; std::string dispatch_chars; + std::vector OSC_string; /* only used to set the window title */ void parse_params( void ); @@ -66,7 +70,12 @@ namespace Terminal { std::string str( void ); void dispatch( Function_Type type, Parser::Action *act, Framebuffer *fb ); - const std::string get_dispatch_chars( void ) { return dispatch_chars; } + std::string get_dispatch_chars( void ) { return dispatch_chars; } + std::vector get_OSC_string( void ) { return OSC_string; } + + void OSC_put( Parser::OSC_Put *act ); + void OSC_start( Parser::OSC_Start *act ); + void OSC_dispatch( Parser::OSC_End *act, Framebuffer *fb ); }; } diff --git a/terminalframebuffer.cpp b/terminalframebuffer.cpp index 34cd14a..828162f 100644 --- a/terminalframebuffer.cpp +++ b/terminalframebuffer.cpp @@ -55,7 +55,7 @@ DrawState::DrawState( int s_width, int s_height ) } Framebuffer::Framebuffer( int s_width, int s_height ) - : rows( s_height, Row( s_width ) ), ds( s_width, s_height ) + : rows( s_height, Row( s_width ) ), window_title(), ds( s_width, s_height ) {} void Framebuffer::scroll( int N ) @@ -311,6 +311,7 @@ void Framebuffer::reset( void ) { int width = ds.get_width(), height = ds.get_height(); rows = std::deque( height, Row( width ) ); + window_title.clear(); ds = DrawState( width, height ); } diff --git a/terminalframebuffer.hpp b/terminalframebuffer.hpp index 3800c97..e141309 100644 --- a/terminalframebuffer.hpp +++ b/terminalframebuffer.hpp @@ -3,6 +3,7 @@ #include #include +#include /* Terminal framebuffer */ @@ -109,6 +110,7 @@ namespace Terminal { class Framebuffer { private: std::deque rows; + std::vector window_title; void scroll( int N ); @@ -132,6 +134,9 @@ namespace Terminal { void reset( void ); void soft_reset( void ); + + void set_window_title( std::vector s ) { window_title = s; } + std::vector get_window_title( void ) { return window_title; } }; } diff --git a/terminalfunctions.cpp b/terminalfunctions.cpp index 84d7709..2c59b25 100644 --- a/terminalfunctions.cpp +++ b/terminalfunctions.cpp @@ -1,7 +1,9 @@ #include +#include #include "terminaldispatcher.hpp" #include "terminalframebuffer.hpp" +#include "parseraction.hpp" using namespace Terminal; @@ -457,3 +459,18 @@ void CSI_DECSTR( Framebuffer *fb, Dispatcher *dispatch __attribute((unused)) ) } static Function func_CSI_DECSTR( CSI, "!p", CSI_DECSTR ); + +/* xterm uses an Operating System Command to set the window title */ +void Dispatcher::OSC_dispatch( Parser::OSC_End *act, Framebuffer *fb ) +{ + if ( OSC_string.size() >= 2 ) { + if ( (OSC_string[ 0 ] == L'0') + && (OSC_string[ 1 ] == L';') ) { + std::vector newtitle = OSC_string; + newtitle.erase( newtitle.begin() ); + newtitle.erase( newtitle.begin() ); + fb->set_window_title( newtitle ); + act->handled = true; + } + } +}