diff --git a/ChangeLog b/ChangeLog index 93bdf171..da336605 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2017-11-18 Markus Gans + * Improved command line paramenter handling + * New command line paramenter --no-terminal-detection + * New command line paramenter --no-color-change + 2017-11-11 Markus Gans * Improved code coverage tests diff --git a/examples/mouse.cpp b/examples/mouse.cpp index 86d868c8..b2795250 100644 --- a/examples/mouse.cpp +++ b/examples/mouse.cpp @@ -411,7 +411,7 @@ void MouseDraw::draw() int y_max = getHeight(); FDialog::draw(); setColor(); - + if ( isNewFont() ) { for (int y = 2; y < y_max; y++) diff --git a/include/final/fapplication.h b/include/final/fapplication.h index 6dd9c469..6dcf7572 100644 --- a/include/final/fapplication.h +++ b/include/final/fapplication.h @@ -110,7 +110,8 @@ class FApplication : public FWidget static void sendQueuedEvents (); static bool eventInQueue(); static bool removeQueuedEvent (const FObject*); - static FWidget* showParameterUsage (const int&, char*[]); + static FWidget* processParameters (const int&, char*[]); + static void showParameterUsage (); static void closeConfirmationDialog (FWidget*, FCloseEvent*); // Callback method @@ -148,8 +149,7 @@ class FApplication : public FWidget // Methods void init(); - void setExitMessage (std::string); - void cmd_options(); + static void cmd_options (const int&, char*[]); #ifdef F_HAVE_LIBGPM int gpmEvent (bool = true); diff --git a/include/final/fc.h b/include/final/fc.h index dd6f0b0b..d57cc239 100644 --- a/include/final/fc.h +++ b/include/final/fc.h @@ -112,7 +112,8 @@ class fc VT100, PC, ASCII, - NUM_OF_ENCODINGS // number of items + NUM_OF_ENCODINGS, // number of items + UNKNOWN }; // VT100 line graphic keys diff --git a/include/final/fterm.h b/include/final/fterm.h index 90c7c067..5d16454a 100644 --- a/include/final/fterm.h +++ b/include/final/fterm.h @@ -260,8 +260,9 @@ class FTerm static void resetBeep(); static void beep(); - static void setEncoding (std::string); - static std::string getEncoding(); + static void setEncoding (fc::encoding); + static fc::encoding getEncoding(); + static std::string getEncodingString(); static bool scrollTermForward(); static bool scrollTermReverse(); @@ -300,9 +301,6 @@ class FTerm static void initFreeBSDConsoleCharMap(); #endif - static void initCygwinCharMap(); - static void initTeraTermCharMap(); - static bool charEncodable (uInt); static uInt charEncode (uInt); static uInt charEncode (uInt, fc::encoding); @@ -324,6 +322,7 @@ class FTerm static FPoint& getMousePos(); static void setMousePos (const FPoint&); static void setMousePos (short, short); + static void exitWithMessage (std::string); // Data Members static int stdin_no; @@ -340,9 +339,33 @@ class FTerm static bool cursor_optimisation; static bool xterm_default_colors; static bool use_alternate_screen; - static fc::encoding Encoding; + static fc::encoding term_encoding; static char exit_message[8192]; + static struct initializationValues + { + public: + initializationValues() + : terminal_detection(true) + , cursor_optimisation(true) + , color_change(true) + , vgafont(false) + , newfont(false) + , encoding(fc::UNKNOWN) + { } + + ~initializationValues() + { } + + uInt8 terminal_detection : 1; + uInt8 cursor_optimisation : 1; + uInt8 color_change : 1; + uInt8 vgafont : 1; + uInt8 newfont : 1; + uInt8 : 3; // padding bits + fc::encoding encoding; + } init_values; + private: // Typedefs typedef FTermcap::tcap_map termcap_map; @@ -418,6 +441,9 @@ class FTerm #endif static uInt getBaudRate (const struct termios*); + static void init_global_values(); + static void detectTerminal(); + static void termtypeAnalysis(); static char* init_256colorTerminal(); static char* parseAnswerbackMsg (char*&); static char* parseSecDA (char*&); @@ -425,11 +451,18 @@ class FTerm static void oscPostfix(); static void init_alt_charset(); static void init_pc_charset(); + static void init_cygwin_charmap(); + static void init_teraterm_charmap(); static void init_termcaps(); + static void init_locale(); static void init_encoding(); + static void redefineColorPalette(); + static void restoreColorPalette(); void init(); void finish(); static uInt cp437_to_unicode (uChar); + static void setSignalHandler(); + static void resetSignalHandler(); static void signal_handler (int); // Data Members diff --git a/src/fapplication.cpp b/src/fapplication.cpp index 4d05ee40..4f71f4dc 100644 --- a/src/fapplication.cpp +++ b/src/fapplication.cpp @@ -58,7 +58,7 @@ FApplication::eventQueue* FApplication::event_queue = 0; FApplication::FApplication ( const int& _argc , char* _argv[] , bool disable_alt_screen ) - : FWidget(showParameterUsage(_argc,_argv), disable_alt_screen) + : FWidget(processParameters(_argc,_argv), disable_alt_screen) , app_argc(_argc) , app_argv(_argv) , key(0) @@ -310,33 +310,44 @@ bool FApplication::removeQueuedEvent (const FObject* receiver) } //---------------------------------------------------------------------- -FWidget* FApplication::showParameterUsage (const int& argc, char* argv[]) +FWidget* FApplication::processParameters (const int& argc, char* argv[]) { if ( argc > 0 && argv[1] && ( std::strcmp(argv[1], "--help") == 0 || std::strcmp(argv[1], "-h") == 0 ) ) { - std::cout \ - << "Generic options:" << std::endl - << " -h, --help " - << " Display this help and exit" << std::endl - << std::endl - << "FinalCut Options:" << std::endl - << " --encoding " - << " Sets the character encoding mode" << std::endl - << " " - << " {UTF8, VT100, PC, ASCII}" << std::endl - << " --no-optimized-cursor" - << " No cursor optimisation" << std::endl - << " --vgafont " - << " Set the standard vga 8x16 font" << std::endl - << " --newfont " - << " Enables the graphical font" << std::endl; - std::exit(EXIT_SUCCESS); + showParameterUsage(); } + cmd_options (argc, argv); return 0; } +//---------------------------------------------------------------------- +void FApplication::showParameterUsage() +{ + std::cout \ + << "Generic options:" << std::endl + << " -h, --help " + << " Display this help and exit" << std::endl + << std::endl + << "FinalCut Options:" << std::endl + << " --encoding " + << " Sets the character encoding mode" << std::endl + << " " + << " {UTF8, VT100, PC, ASCII}" << std::endl + << " --no-optimized-cursor " + << " Disable cursor optimization" << std::endl + << " --no-terminal-detection" + << " Disable terminal detection" << std::endl + << " --no-color-change " + << " Do not redefine the color palette" << std::endl + << " --vgafont " + << " Set the standard vga 8x16 font" << std::endl + << " --newfont " + << " Enables the graphical font" << std::endl; + std::exit(EXIT_SUCCESS); +} + //---------------------------------------------------------------------- void FApplication::closeConfirmationDialog (FWidget* w, FCloseEvent* ev) { @@ -385,40 +396,31 @@ void FApplication::init() std::fill_n (urxvt_mouse, sizeof(urxvt_mouse), '\0'); // init bit field with 0 std::memset(&b_state, 0x00, sizeof(b_state)); +} +//---------------------------------------------------------------------- +void FApplication::cmd_options (const int& argc, char* argv[]) +{ // interpret the command line options - cmd_options(); -} -//---------------------------------------------------------------------- -void FApplication::setExitMessage (std::string message) -{ - quit_now = true; - snprintf ( FTerm::exit_message - , sizeof(FTerm::exit_message) - , "%s" - , message.c_str() ); -} - -//---------------------------------------------------------------------- -void FApplication::cmd_options () -{ while ( true ) { int c, idx = 0; static struct option long_options[] = { - {"encoding", required_argument, 0, 0 }, - {"no-optimized-cursor", no_argument, 0, 0 }, - {"vgafont", no_argument, 0, 0 }, - {"newfont", no_argument, 0, 0 }, - {0, 0, 0, 0 } + {"encoding", required_argument, 0, 0 }, + {"no-optimized-cursor", no_argument, 0, 0 }, + {"no-terminal-detection", no_argument, 0, 0 }, + {"no-color-change", no_argument, 0, 0 }, + {"vgafont", no_argument, 0, 0 }, + {"newfont", no_argument, 0, 0 }, + {0, 0, 0, 0 } }; opterr = 0; - c = getopt_long ( app_argc - , app_argv + c = getopt_long ( argc + , argv , "" , long_options , &idx ); @@ -432,36 +434,35 @@ void FApplication::cmd_options () FString encoding(optarg); encoding = encoding.toUpper(); - if ( encoding.includes("UTF8") - || encoding.includes("VT100") - || encoding.includes("PC") - || encoding.includes("ASCII") ) - { - setEncoding(encoding.c_str()); - } + if ( encoding.includes("UTF8") ) + init_values.encoding = fc::UTF8; + else if ( encoding.includes("VT100") ) + init_values.encoding = fc::VT100; + else if ( encoding.includes("PC") ) + init_values.encoding = fc::PC; + else if ( encoding.includes("ASCII") ) + init_values.encoding = fc::ASCII; + else if ( encoding.includes("HELP") ) + showParameterUsage(); else - setExitMessage ( "Unknown encoding " - + std::string(encoding.c_str()) ); + exitWithMessage ( "Unknown encoding " + + std::string(encoding.c_str()) ); } if ( std::strcmp(long_options[idx].name, "no-optimized-cursor") == 0 ) - setCursorOptimisation (false); + init_values.cursor_optimisation = false; + + if ( std::strcmp(long_options[idx].name, "no-terminal-detection") == 0 ) + init_values.terminal_detection = false; + + if ( std::strcmp(long_options[idx].name, "no-color-change") == 0 ) + init_values.color_change = false; if ( std::strcmp(long_options[idx].name, "vgafont") == 0 ) - { - bool ret = setVGAFont(); - - if ( ! ret ) - setExitMessage ("VGAfont is not supported by this terminal"); - } + init_values.vgafont = true; if ( std::strcmp(long_options[idx].name, "newfont") == 0 ) - { - bool ret = setNewFont(); - - if ( ! ret ) - setExitMessage ("Newfont is not supported by this terminal"); - } + init_values.newfont = true; } } } diff --git a/src/fbutton.cpp b/src/fbutton.cpp index 6fa15fe8..a97e3478 100644 --- a/src/fbutton.cpp +++ b/src/fbutton.cpp @@ -206,8 +206,8 @@ bool FButton::setFlat (bool on) bool FButton::setShadow (bool on) { if ( on - && Encoding != fc::VT100 - && Encoding != fc::ASCII ) + && term_encoding != fc::VT100 + && term_encoding != fc::ASCII ) { flags |= fc::shadow; setShadowSize(1,1); diff --git a/src/flineedit.cpp b/src/flineedit.cpp index e34c67d1..748923fd 100644 --- a/src/flineedit.cpp +++ b/src/flineedit.cpp @@ -234,8 +234,8 @@ bool FLineEdit::setFocus (bool on) bool FLineEdit::setShadow (bool on) { if ( on - && Encoding != fc::VT100 - && Encoding != fc::ASCII ) + && term_encoding != fc::VT100 + && term_encoding != fc::ASCII ) { flags |= fc::shadow; setShadowSize(1,1); diff --git a/src/fmenu.cpp b/src/fmenu.cpp index a2f159f8..0edba4bc 100644 --- a/src/fmenu.cpp +++ b/src/fmenu.cpp @@ -1344,7 +1344,7 @@ void FMenu::drawItems() { setColor (wc.menu_inactive_fg, getBackgroundColor()); - if ( getEncoding() == "ASCII" ) + if ( getEncoding() == fc::ASCII ) print ('-'); else print (fc::SmallBullet); // · diff --git a/src/fprogressbar.cpp b/src/fprogressbar.cpp index f9cd95d6..36e23f5c 100644 --- a/src/fprogressbar.cpp +++ b/src/fprogressbar.cpp @@ -79,8 +79,8 @@ void FProgressbar::setGeometry (int x, int y, int w, int h, bool adjust) bool FProgressbar::setShadow (bool on) { if ( on - && Encoding != fc::VT100 - && Encoding != fc::ASCII ) + && term_encoding != fc::VT100 + && term_encoding != fc::ASCII ) { flags |= fc::shadow; setShadowSize(1,1); diff --git a/src/fterm.cpp b/src/fterm.cpp index 56322254..19bb8b26 100644 --- a/src/fterm.cpp +++ b/src/fterm.cpp @@ -114,7 +114,7 @@ FPoint* FTerm::mouse = 0; FRect* FTerm::term = 0; char FTerm::exit_message[8192] = ""; -fc::encoding FTerm::Encoding; +fc::encoding FTerm::term_encoding; const FString* FTerm::xterm_font = 0; const FString* FTerm::xterm_title = 0; const FString* FTerm::answer_back = 0; @@ -136,6 +136,7 @@ bool FTermcap::no_utf8_acs_chars = false; int FTermcap::max_color = 1; int FTermcap::tabstop = 8; int FTermcap::attr_without_color = 0; +FTerm::initializationValues FTerm::init_values; fc::linuxConsoleCursorStyle FTerm::linux_console_cursor_style; fc::freebsdConsoleCursorStyle FTerm::freebsd_console_cursor_style; @@ -175,12 +176,7 @@ FTerm::FTerm (bool disable_alt_screen) FTerm::~FTerm() // destructor { if ( init_term_object == this ) - { finish(); - - if ( exit_message[0] ) - std::fprintf (stderr, "Warning: %s\n", exit_message); - } } @@ -607,7 +603,7 @@ bool FTerm::setVGAFont() std::fflush(stdout); NewFont = false; pc_charset_console = true; - Encoding = fc::PC; + term_encoding = fc::PC; if ( xterm_terminal && utf8_console ) Fputchar = &FTerm::putchar_UTF8; @@ -644,7 +640,7 @@ bool FTerm::setVGAFont() VGAFont = false; pc_charset_console = true; - Encoding = fc::PC; + term_encoding = fc::PC; Fputchar = &FTerm::putchar_ASCII; } #endif @@ -678,7 +674,7 @@ bool FTerm::setNewFont() oscPostfix(); std::fflush(stdout); pc_charset_console = true; - Encoding = fc::PC; + term_encoding = fc::PC; if ( xterm_terminal && utf8_console ) Fputchar = &FTerm::putchar_UTF8; @@ -715,7 +711,7 @@ bool FTerm::setNewFont() } pc_charset_console = true; - Encoding = fc::PC; + term_encoding = fc::PC; Fputchar = &FTerm::putchar_ASCII; // function pointer } #endif @@ -1370,6 +1366,8 @@ void FTerm::resetColorMap() //---------------------------------------------------------------------- void FTerm::setPalette (short index, int r, int g, int b) { + // Redefine the color palette + char*& Ic = TCAP(fc::t_initialize_color); char*& Ip = TCAP(fc::t_initialize_pair); @@ -1451,28 +1449,20 @@ void FTerm::beep() } //---------------------------------------------------------------------- -void FTerm::setEncoding (std::string enc) +void FTerm::setEncoding (fc::encoding enc) { - std::map::const_iterator it; + if ( FTermcap::no_utf8_acs_chars && isUTF8() && enc == fc::VT100 ) + enc = fc::UTF8; - if ( FTermcap::no_utf8_acs_chars && isUTF8() && enc == "VT100" ) - enc = "UTF8"; + term_encoding = enc; - // available encodings: "UTF8", "VT100", "PC" and "ASCII" - it = encoding_set->find(enc); - - if ( it == encoding_set->end() ) // not found - return; - - Encoding = it->second; - - assert ( Encoding == fc::UTF8 - || Encoding == fc::VT100 - || Encoding == fc::PC - || Encoding == fc::ASCII ); + assert ( term_encoding == fc::UTF8 + || term_encoding == fc::VT100 + || term_encoding == fc::PC + || term_encoding == fc::ASCII ); // set the new Fputchar function pointer - switch ( int(Encoding) ) + switch ( term_encoding ) { case fc::UTF8: Fputchar = &FTerm::putchar_UTF8; @@ -1493,7 +1483,7 @@ void FTerm::setEncoding (std::string enc) if ( linux_terminal ) { - if ( Encoding == fc::VT100 || Encoding == fc::PC ) + if ( term_encoding == fc::VT100 || term_encoding == fc::PC ) { char* empty = 0; opti_move->set_tabular (empty); @@ -1504,13 +1494,19 @@ void FTerm::setEncoding (std::string enc) } //---------------------------------------------------------------------- -std::string FTerm::getEncoding() +fc::encoding FTerm::getEncoding() +{ + return term_encoding; +} + +//---------------------------------------------------------------------- +std::string FTerm::getEncodingString() { std::map::const_iterator it, end; end = encoding_set->end(); for (it = encoding_set->begin(); it != end; ++it ) - if ( it->second == Encoding ) + if ( it->second == term_encoding ) return it->first; return ""; @@ -1775,36 +1771,6 @@ void FTerm::initFreeBSDConsoleCharMap() } #endif -//---------------------------------------------------------------------- -void FTerm::initCygwinCharMap() -{ - // Replace don't printable characters in a Cygwin terminal - - if ( ! cygwin_terminal ) - return; - - for (int i = 0; i <= lastCharItem; i++ ) - { - if ( character[i][fc::UTF8] == fc::BlackUpPointingTriangle // ▲ - || character[i][fc::UTF8] == fc::BlackDownPointingTriangle // ▼ - || character[i][fc::UTF8] == fc::SquareRoot ) // SquareRoot √ - character[i][fc::PC] = character[i][fc::ASCII]; - } -} - -//---------------------------------------------------------------------- -void FTerm::initTeraTermCharMap() -{ - // Tera Term can't print ascii characters < 0x20 - - if ( ! tera_terminal ) - return; - - for (int i = 0; i <= lastCharItem; i++ ) - if ( character[i][fc::PC] < 0x20 ) - character[i][fc::PC] = character[i][fc::ASCII]; -} - //---------------------------------------------------------------------- bool FTerm::charEncodable (uInt c) { @@ -1815,7 +1781,7 @@ bool FTerm::charEncodable (uInt c) //---------------------------------------------------------------------- uInt FTerm::charEncode (uInt c) { - return charEncode (c, Encoding); + return charEncode (c, term_encoding); } //---------------------------------------------------------------------- @@ -1925,6 +1891,28 @@ bool FTerm::gpmMouse (bool on) } #endif // F_HAVE_LIBGPM +//---------------------------------------------------------------------- +void FTerm::exitWithMessage (std::string message) +{ + // Set the exit_message for the atexit-handler + snprintf ( exit_message + , sizeof(exit_message) + , "%s" + , message.c_str() ); + + // Exit the programm + if ( init_term_object ) + init_term_object->finish(); + + std::fflush (stderr); + std::fflush (stdout); + + if ( exit_message[0] ) + std::fprintf (stderr, "Warning: %s\n", exit_message); + + exit (EXIT_FAILURE); +} + // private methods of FTerm //---------------------------------------------------------------------- @@ -2435,7 +2423,6 @@ void FTerm::initLinuxConsole() { // initialize Linux console - fd_tty = -1; screen_unicode_map.entries = 0; screen_font.data = 0; @@ -2606,6 +2593,208 @@ uInt FTerm::getBaudRate (const struct termios* termios_p) return outspeed[cfgetospeed(termios_p)]; } +//---------------------------------------------------------------------- +void FTerm::init_global_values() +{ + // Initialize global values + + // Teletype (tty) file descriptor is still undefined + fd_tty = -1; + + // Preset to false + utf8_console = \ + utf8_input = \ + utf8_state = \ + utf8_linux_terminal = \ + pc_charset_console = \ + vt100_console = \ + NewFont = \ + VGAFont = \ + no_shadow_character = \ + no_half_block_character = \ + ascii_console = \ + mouse_support = \ + decscusr_support = \ + force_vt100 = \ + tera_terminal = \ + kterm_terminal = \ + gnome_terminal = \ + kde_konsole = \ + ansi_terminal = \ + rxvt_terminal = \ + urxvt_terminal = \ + mlterm_terminal = \ + mintty_terminal = \ + openbsd_terminal = \ + screen_terminal = \ + tmux_terminal = \ + xterm_default_colors = false; + + // Preset to true + cursor_optimisation = \ + terminal_detection = true; + + // assertion: programm start in cooked mode + raw_mode = \ + input_data_pending = \ + non_blocking_stdin = false; + + // init arrays with '\0' + std::fill_n (exit_message, sizeof(exit_message), '\0'); +} + +//---------------------------------------------------------------------- +void FTerm::detectTerminal() +{ + // Terminal detection + + char* new_termtype = 0; + + if ( ! terminal_detection ) + { + struct termios t; + tcgetattr (stdin_no, &t); + t.c_cc[VTIME] = 1; // Timeout in deciseconds + t.c_cc[VMIN] = 0; // Minimum number of characters + tcsetattr (stdin_no, TCSANOW, &t); + } + else + { + struct termios t; + tcgetattr (stdin_no, &t); + t.c_lflag &= uInt(~(ICANON | ECHO)); + t.c_cc[VTIME] = 1; // Timeout in deciseconds + t.c_cc[VMIN] = 0; // Minimum number of characters + tcsetattr (stdin_no, TCSANOW, &t); + + // Initialize 256 colors terminals + new_termtype = init_256colorTerminal(); + + // Identify the terminal via the answerback-message + new_termtype = parseAnswerbackMsg (new_termtype); + + // Identify the terminal via the secondary device attributes (SEC_DA) + new_termtype = parseSecDA (new_termtype); + + // Determine xterm maximum number of colors via OSC 4 + if ( ! color256 + && ! cygwin_terminal + && ! tera_terminal + && ! linux_terminal + && ! netbsd_terminal + && ! getXTermColorName(0).isEmpty() ) + { + if ( ! getXTermColorName(256).isEmpty() ) + { + if ( putty_terminal ) + new_termtype = const_cast("putty-256color"); + else + new_termtype = const_cast("xterm-256color"); + } + else if ( ! getXTermColorName(87).isEmpty() ) + { + new_termtype = const_cast("xterm-88color"); + } + else if ( ! getXTermColorName(15).isEmpty() ) + { + new_termtype = const_cast("xterm-16color"); + } + } + + if ( cygwin_terminal + || putty_terminal + || tera_terminal + || rxvt_terminal ) + { + FTermcap::max_color = 16; + } + + #if defined(__linux__) + if ( linux_terminal && openConsole() == 0 ) + { + if ( isLinuxConsole() ) + { + if ( setBlinkAsIntensity(true) == 0 ) + FTermcap::max_color = 16; + else + FTermcap::max_color = 8; + } + + closeConsole(); + setLinuxConsoleCursorStyle (fc::underscore_cursor, true); + } + + if ( linux_terminal && getFramebuffer_bpp() >= 4 ) + FTermcap::max_color = 16; + #endif + + #if defined(__FreeBSD__) || defined(__DragonFly__) + setFreeBSDConsoleCursorStyle (fc::destructive_cursor, true); + #endif + + t.c_lflag |= uInt(ICANON | ECHO); + tcsetattr(stdin_no, TCSADRAIN, &t); + } + + // + // Additional termtype analysis + // + + // Test if the terminal is a xterm + if ( std::strncmp(termtype, const_cast("xterm"), 5) == 0 + || std::strncmp(termtype, const_cast("Eterm"), 5) == 0 ) + { + xterm_terminal = true; + + // Each xterm should be able to use at least 16 colors + if ( ! new_termtype && std::strlen(termtype) == 5 ) + new_termtype = const_cast("xterm-16color"); + } + else + xterm_terminal = false; + + // set the new environment variable TERM + if ( new_termtype ) + { + setenv(const_cast("TERM"), new_termtype, 1); + std::strncpy (termtype, new_termtype, std::strlen(new_termtype) + 1); + } +} + +//---------------------------------------------------------------------- +void FTerm::termtypeAnalysis() +{ + // Cygwin console + if ( std::strncmp(termtype, "cygwin", 6) == 0 ) + cygwin_terminal = true; + else + cygwin_terminal = false; + + // rxvt terminal emulator (native MS Window System port) on cygwin + if ( std::strncmp(termtype, "rxvt-cygwin-native", 18) == 0 ) + rxvt_terminal = true; + + // Ansi terminal + if ( std::strncmp(termtype, "ansi", 4) == 0 ) + { + terminal_detection = false; + ansi_terminal = true; + } + + // Linux console + if ( std::strncmp(termtype, const_cast("linux"), 5) == 0 + || std::strncmp(termtype, const_cast("con"), 3) == 0 ) + linux_terminal = true; + else + linux_terminal = false; + + // NetBSD workstation console + if ( std::strncmp(termtype, const_cast("wsvt25"), 6) == 0 ) + netbsd_terminal = true; + else + netbsd_terminal = false; +} + //---------------------------------------------------------------------- char* FTerm::init_256colorTerminal() { @@ -3049,6 +3238,36 @@ void FTerm::init_pc_charset() opti_attr->init(); } +//---------------------------------------------------------------------- +void FTerm::init_cygwin_charmap() +{ + // Replace don't printable characters in a Cygwin terminal + + if ( ! cygwin_terminal ) + return; + + for (int i = 0; i <= lastCharItem; i++ ) + { + if ( character[i][fc::UTF8] == fc::BlackUpPointingTriangle // ▲ + || character[i][fc::UTF8] == fc::BlackDownPointingTriangle // ▼ + || character[i][fc::UTF8] == fc::SquareRoot ) // SquareRoot √ + character[i][fc::PC] = character[i][fc::ASCII]; + } +} + +//---------------------------------------------------------------------- +void FTerm::init_teraterm_charmap() +{ + // Tera Term can't print ascii characters < 0x20 + + if ( ! tera_terminal ) + return; + + for (int i = 0; i <= lastCharItem; i++ ) + if ( character[i][fc::PC] < 0x20 ) + character[i][fc::PC] = character[i][fc::ASCII]; +} + //---------------------------------------------------------------------- void FTerm::init_termcaps() { @@ -3620,19 +3839,65 @@ void FTerm::init_termcaps() opti_attr->init(); } +//---------------------------------------------------------------------- +void FTerm::init_locale() +{ + // Init current locale + locale_name = std::setlocale (LC_ALL, ""); + locale_name = std::setlocale (LC_NUMERIC, ""); + + // Get XTERM_LOCALE + locale_xterm = std::getenv("XTERM_LOCALE"); + + // set LC_ALL to XTERM_LOCALE + if ( locale_xterm ) + locale_name = std::setlocale (LC_ALL, locale_xterm); + + // TeraTerm can not show UTF-8 character + if ( tera_terminal && ! std::strcmp(nl_langinfo(CODESET), "UTF-8") ) + locale_name = std::setlocale (LC_ALL, "C"); + + // Try to found a meaningful content for locale_name + if ( locale_name ) + locale_name = std::setlocale (LC_CTYPE, 0); + else + { + locale_name = std::getenv("LC_ALL"); + + if ( ! locale_name ) + { + locale_name = std::getenv("LC_CTYPE"); + + if ( ! locale_name ) + locale_name = std::getenv("LANG"); + } + } + + // Fallback to C + if ( ! locale_name ) + locale_name = const_cast("C"); +} + //---------------------------------------------------------------------- void FTerm::init_encoding() { // detect encoding and set the Fputchar function pointer + // Define the encoding set + (*encoding_set)["UTF8"] = fc::UTF8; + (*encoding_set)["UTF-8"] = fc::UTF8; + (*encoding_set)["VT100"] = fc::VT100; + (*encoding_set)["PC"] = fc::PC; + (*encoding_set)["ASCII"] = fc::ASCII; + if ( isatty(stdout_no) && ! std::strcmp(nl_langinfo(CODESET), "UTF-8") ) { - utf8_console = true; - Encoding = fc::UTF8; - Fputchar = &FTerm::putchar_UTF8; // function pointer - utf8_state = true; - utf8_input = true; + utf8_console = true; + term_encoding = fc::UTF8; + Fputchar = &FTerm::putchar_UTF8; // function pointer + utf8_state = true; + utf8_input = true; setUTF8(true); } else if ( isatty(stdout_no) @@ -3640,14 +3905,14 @@ void FTerm::init_encoding() && (TCAP(fc::t_exit_alt_charset_mode) != 0) ) { vt100_console = true; - Encoding = fc::VT100; - Fputchar = &FTerm::putchar_ASCII; // function pointer + term_encoding = fc::VT100; + Fputchar = &FTerm::putchar_ASCII; // function pointer } else { ascii_console = true; - Encoding = fc::ASCII; - Fputchar = &FTerm::putchar_ASCII; // function pointer + term_encoding = fc::ASCII; + Fputchar = &FTerm::putchar_ASCII; // function pointer } init_pc_charset(); @@ -3659,8 +3924,8 @@ void FTerm::init_encoding() || (tera_terminal && ! utf8_state) ) { pc_charset_console = true; - Encoding = fc::PC; - Fputchar = &FTerm::putchar_ASCII; // function pointer + term_encoding = fc::PC; + Fputchar = &FTerm::putchar_ASCII; // function pointer if ( linux_terminal && utf8_console ) { @@ -3676,27 +3941,73 @@ void FTerm::init_encoding() if ( force_vt100 ) { vt100_console = true; - Encoding = fc::VT100; - Fputchar = &FTerm::putchar_ASCII; // function pointer + term_encoding = fc::VT100; + Fputchar = &FTerm::putchar_ASCII; // function pointer } // In some alternative character sets, a tab character prints a '○' // on the terminal and does not move the cursor to the next tab stop // position - if ( Encoding == fc::VT100 || Encoding == fc::PC ) + if ( term_encoding == fc::VT100 || term_encoding == fc::PC ) { char* empty = 0; opti_move->set_tabular (empty); } } +//---------------------------------------------------------------------- +void FTerm::redefineColorPalette() +{ + if ( FTermcap::max_color >= 16 + && ! cygwin_terminal + && ! kde_konsole + && ! tera_terminal + && ! ansi_terminal ) + { + resetColorMap(); + saveColorMap(); + + setPalette (fc::Black, 0x00, 0x00, 0x00); + setPalette (fc::Blue, 0x22, 0x22, 0xb2); + setPalette (fc::Green, 0x18, 0x78, 0x18); + setPalette (fc::Cyan, 0x4a, 0x4a, 0xe4); + setPalette (fc::Red, 0xb2, 0x18, 0x18); + setPalette (fc::Magenta, 0xb2, 0x18, 0xb2); + setPalette (fc::Brown, 0xe8, 0x87, 0x1f); + setPalette (fc::LightGray, 0xbc, 0xbc, 0xbc); + setPalette (fc::DarkGray, 0x50, 0x50, 0x50); + setPalette (fc::LightBlue, 0x80, 0xa4, 0xec); + setPalette (fc::LightGreen, 0x5e, 0xeb, 0x5c); + setPalette (fc::LightCyan, 0x62, 0xbf, 0xf8); + setPalette (fc::LightRed, 0xed, 0x57, 0x31); + setPalette (fc::LightMagenta, 0xe9, 0xad, 0xff); + setPalette (fc::Yellow, 0xfb, 0xe8, 0x67); + setPalette (fc::White, 0xff, 0xff, 0xff); + } +} + +//---------------------------------------------------------------------- +void FTerm::restoreColorPalette() +{ + if ( FTermcap::max_color >= 16 + && ! (kde_konsole || tera_terminal || ansi_terminal) ) + { + // Reset screen settings + setPalette (fc::Cyan, 0x18, 0xb2, 0xb2); + setPalette (fc::LightGray, 0xb2, 0xb2, 0xb2); + setPalette (fc::DarkGray, 0x68, 0x68, 0x68); + setPalette (fc::LightBlue, 0x54, 0x54, 0xff); + setPalette (fc::LightGreen, 0x54, 0xff, 0x54); + + resetXTermColors(); + resetColorMap(); + } +} + //---------------------------------------------------------------------- void FTerm::init() { - char* new_termtype = 0; - term_initialized = true; init_term_object = this; - fd_tty = -1; try { @@ -3713,56 +4024,17 @@ void FTerm::init() std::abort(); } - // Define the encoding set - (*encoding_set)["UTF8"] = fc::UTF8; - (*encoding_set)["UTF-8"] = fc::UTF8; - (*encoding_set)["VT100"] = fc::VT100; - (*encoding_set)["PC"] = fc::PC; - (*encoding_set)["ASCII"] = fc::ASCII; + // Initialize global values for all objects + init_global_values(); - // Preset to false - utf8_console = \ - utf8_input = \ - utf8_state = \ - utf8_linux_terminal = \ - pc_charset_console = \ - vt100_console = \ - NewFont = \ - VGAFont = \ - no_shadow_character = \ - no_half_block_character = \ - ascii_console = \ - mouse_support = \ - decscusr_support = \ - force_vt100 = \ - tera_terminal = \ - kterm_terminal = \ - gnome_terminal = \ - kde_konsole = \ - ansi_terminal = \ - rxvt_terminal = \ - urxvt_terminal = \ - mlterm_terminal = \ - mintty_terminal = \ - openbsd_terminal = \ - screen_terminal = \ - tmux_terminal = \ - xterm_default_colors = false; - - // Preset to true - cursor_optimisation = \ - terminal_detection = true; - - // assertion: programm start in cooked mode - raw_mode = \ - input_data_pending = \ - non_blocking_stdin = false; - - // init arrays with '\0' - std::fill_n (exit_message, sizeof(exit_message), '\0'); + if ( ! init_values.terminal_detection ) + terminal_detection = false; + // Get file descriptor for standard input and standard output stdin_no = fileno(stdin); stdout_no = fileno(stdout); + + // Get the stdin file status flags stdin_status_flags = fcntl(stdin_no, F_GETFL); if ( stdin_status_flags == -1 ) @@ -3799,174 +4071,25 @@ void FTerm::init() // Set the variable 'termtype' to the predefined type of the terminal getSystemTermType(); - if ( std::strncmp(termtype, "cygwin", 6) == 0 ) - cygwin_terminal = true; - else - cygwin_terminal = false; - - if ( std::strncmp(termtype, "rxvt-cygwin-native", 18) == 0 ) - rxvt_terminal = true; - - if ( std::strncmp(termtype, "ansi", 4) == 0 ) - { - terminal_detection = false; - ansi_terminal = true; - } - - // Test for Linux console - if ( std::strncmp(termtype, const_cast("linux"), 5) == 0 - || std::strncmp(termtype, const_cast("con"), 3) == 0 ) - linux_terminal = true; - else - linux_terminal = false; - - // Test for NetBSD workstation console - if ( std::strncmp(termtype, const_cast("wsvt25"), 6) == 0 ) - netbsd_terminal = true; - else - netbsd_terminal = false; + // Analysis the termtype + termtypeAnalysis(); // Terminal detection - if ( terminal_detection ) - { - struct termios t; - tcgetattr (stdin_no, &t); - t.c_lflag &= uInt(~(ICANON | ECHO)); - t.c_cc[VTIME] = 1; // Timeout in deciseconds - t.c_cc[VMIN] = 0; // Minimum number of characters - tcsetattr (stdin_no, TCSANOW, &t); - - // Initialize 256 colors terminals - new_termtype = init_256colorTerminal(); - - // Identify the terminal via the answerback-message - new_termtype = parseAnswerbackMsg (new_termtype); - - // Identify the terminal via the secondary device attributes (SEC_DA) - new_termtype = parseSecDA (new_termtype); - - // Determine xterm maximum number of colors via OSC 4 - if ( ! color256 - && ! cygwin_terminal - && ! tera_terminal - && ! linux_terminal - && ! netbsd_terminal - && ! getXTermColorName(0).isEmpty() ) - { - if ( ! getXTermColorName(256).isEmpty() ) - { - if ( putty_terminal ) - new_termtype = const_cast("putty-256color"); - else - new_termtype = const_cast("xterm-256color"); - } - else if ( ! getXTermColorName(87).isEmpty() ) - { - new_termtype = const_cast("xterm-88color"); - } - else if ( ! getXTermColorName(15).isEmpty() ) - { - new_termtype = const_cast("xterm-16color"); - } - } - - if ( cygwin_terminal - || putty_terminal - || tera_terminal - || rxvt_terminal ) - { - FTermcap::max_color = 16; - } - -#if defined(__linux__) - if ( linux_terminal && openConsole() == 0 ) - { - if ( isLinuxConsole() ) - { - if ( setBlinkAsIntensity(true) == 0 ) - FTermcap::max_color = 16; - else - FTermcap::max_color = 8; - } - - closeConsole(); - setLinuxConsoleCursorStyle (fc::underscore_cursor, true); - } - - if ( linux_terminal && getFramebuffer_bpp() >= 4 ) - FTermcap::max_color = 16; -#endif - -#if defined(__FreeBSD__) || defined(__DragonFly__) - setFreeBSDConsoleCursorStyle (fc::destructive_cursor, true); -#endif - - t.c_lflag |= uInt(ICANON | ECHO); - tcsetattr(stdin_no, TCSADRAIN, &t); - } - - // Test if the terminal is a xterm - if ( std::strncmp(termtype, const_cast("xterm"), 5) == 0 - || std::strncmp(termtype, const_cast("Eterm"), 5) == 0 ) - { - xterm_terminal = true; - - // Each xterm should be able to use at least 16 colors - if ( ! new_termtype && std::strlen(termtype) == 5 ) - new_termtype = const_cast("xterm-16color"); - } - else - xterm_terminal = false; - - // set the new environment variable TERM - if ( new_termtype ) - { - setenv(const_cast("TERM"), new_termtype, 1); - std::strncpy (termtype, new_termtype, std::strlen(new_termtype) + 1); - } + detectTerminal(); // Initializes variables for the current terminal init_termcaps(); init_alt_charset(); - // init current locale - locale_name = std::setlocale (LC_ALL, ""); - locale_name = std::setlocale (LC_NUMERIC, ""); - - // get XTERM_LOCALE - locale_xterm = std::getenv("XTERM_LOCALE"); - - // set LC_ALL to XTERM_LOCALE - if ( locale_xterm ) - locale_name = std::setlocale (LC_ALL, locale_xterm); - - // TeraTerm can not show UTF-8 character - if ( tera_terminal && ! std::strcmp(nl_langinfo(CODESET), "UTF-8") ) - locale_name = std::setlocale (LC_ALL, "C"); - - // try to found a meaningful content for locale_name - if ( locale_name ) - locale_name = std::setlocale (LC_CTYPE, 0); - else - { - locale_name = std::getenv("LC_ALL"); - - if ( ! locale_name ) - { - locale_name = std::getenv("LC_CTYPE"); - - if ( ! locale_name ) - locale_name = std::getenv("LANG"); - } - } - - // Fallback to C - if ( ! locale_name ) - locale_name = const_cast("C"); + // Initializes locale information + init_locale(); // Detect environment and set encoding init_encoding(); + if ( init_values.encoding != fc::UNKNOWN ) + setEncoding(init_values.encoding); + #ifdef F_HAVE_LIBGPM // Enable the linux general purpose mouse (gpm) server @@ -4031,111 +4154,89 @@ void FTerm::init() setKDECursor(fc::UnderlineCursor); if ( cygwin_terminal ) - initCygwinCharMap(); + init_cygwin_charmap(); if ( tera_terminal ) - initTeraTermCharMap(); + init_teraterm_charmap(); - if ( FTermcap::max_color >= 16 - && ! cygwin_terminal - && ! kde_konsole - && ! tera_terminal - && ! ansi_terminal ) - { - resetColorMap(); - saveColorMap(); - - setPalette (fc::Black, 0x00, 0x00, 0x00); - setPalette (fc::Blue, 0x22, 0x22, 0xb2); - setPalette (fc::Green, 0x18, 0x78, 0x18); - setPalette (fc::Cyan, 0x4a, 0x4a, 0xe4); - setPalette (fc::Red, 0xb2, 0x18, 0x18); - setPalette (fc::Magenta, 0xb2, 0x18, 0xb2); - setPalette (fc::Brown, 0xe8, 0x87, 0x1f); - setPalette (fc::LightGray, 0xbc, 0xbc, 0xbc); - setPalette (fc::DarkGray, 0x50, 0x50, 0x50); - setPalette (fc::LightBlue, 0x80, 0xa4, 0xec); - setPalette (fc::LightGreen, 0x5e, 0xeb, 0x5c); - setPalette (fc::LightCyan, 0x62, 0xbf, 0xf8); - setPalette (fc::LightRed, 0xed, 0x57, 0x31); - setPalette (fc::LightMagenta, 0xe9, 0xad, 0xff); - setPalette (fc::Yellow, 0xfb, 0xe8, 0x67); - setPalette (fc::White, 0xff, 0xff, 0xff); - } + // Redefine the color palette + if ( init_values.color_change ) + redefineColorPalette(); // set 200 Hz beep (100 ms) setBeep(200, 100); - signal(SIGTERM, FTerm::signal_handler); // Termination signal - signal(SIGQUIT, FTerm::signal_handler); // Quit from keyboard (Ctrl-\) - signal(SIGINT, FTerm::signal_handler); // Keyboard interrupt (Ctrl-C) - signal(SIGABRT, FTerm::signal_handler); // Abort signal from abort(3) - signal(SIGILL, FTerm::signal_handler); // Illegal Instruction - signal(SIGSEGV, FTerm::signal_handler); // Invalid memory reference - signal(SIGWINCH, FTerm::signal_handler); // Window resize signal + // Set FTerm signal handler + setSignalHandler(); + + if ( ! init_values.cursor_optimisation ) + setCursorOptimisation (false); + + if ( init_values.vgafont ) + { + bool ret = setVGAFont(); + + if ( ! ret ) + exitWithMessage ("VGAfont is not supported by this terminal"); + } + + if ( init_values.newfont ) + { + bool ret = setNewFont(); + + if ( ! ret ) + exitWithMessage ("Newfont is not supported by this terminal"); + } // turn off hardware echo noHardwareEcho(); // switch to the raw mode setRawMode(); + + // The terminal is now initialized + term_initialized = true; } //---------------------------------------------------------------------- void FTerm::finish() { - // set default signal handler - signal(SIGWINCH, SIG_DFL); // Window resize signal - signal(SIGSEGV, SIG_DFL); // Invalid memory reference - signal(SIGILL, SIG_DFL); // Illegal Instruction - signal(SIGABRT, SIG_DFL); // Abort signal from abort(3) - signal(SIGINT, SIG_DFL); // Keyboard interrupt (Ctrl-C) - signal(SIGQUIT, SIG_DFL); // Quit from keyboard (Ctrl-\) - signal(SIGTERM, SIG_DFL); // Termination signal + // Set default signal handler + resetSignalHandler(); if ( xterm_title && xterm_terminal && ! rxvt_terminal ) setXTermTitle (*xterm_title); - // restore the saved termios settings + // Restore the saved termios settings restoreTTYsettings(); - // turn off all attributes + // Turn off all attributes if ( TCAP(fc::t_exit_attribute_mode) ) { putstring (TCAP(fc::t_exit_attribute_mode)); std::fflush(stdout); } - // turn off pc charset mode + // Turn off pc charset mode if ( TCAP(fc::t_exit_pc_charset_mode) ) { putstring (TCAP(fc::t_exit_pc_charset_mode)); std::fflush(stdout); } - // reset xterm color settings to default values + // Reset xterm color settings to default values resetXTermDefaults(); - // set xterm full block cursor + // Set xterm full block cursor setXTermCursorStyle(fc::steady_block); - if ( FTermcap::max_color >= 16 - && ! (kde_konsole || tera_terminal || ansi_terminal) ) - { - // reset screen settings - setPalette (fc::Cyan, 0x18, 0xb2, 0xb2); - setPalette (fc::LightGray, 0xb2, 0xb2, 0xb2); - setPalette (fc::DarkGray, 0x68, 0x68, 0x68); - setPalette (fc::LightBlue, 0x54, 0x54, 0xff); - setPalette (fc::LightGreen, 0x54, 0xff, 0x54); - - resetXTermColors(); - resetColorMap(); - } + // Restore the color palette + if ( init_values.color_change ) + restoreColorPalette(); if ( mintty_terminal ) { - // switch to normal escape key mode + // Switch to normal escape key mode putstring (CSI "?7727l"); std::fflush(stdout); } @@ -4162,11 +4263,11 @@ void FTerm::finish() resetBeep(); - // disable xterm mouse support + // Disable xterm mouse support if ( mouse_support ) disableXTermMouse(); - // deactivate meta key sends escape + // Deactivate meta key sends escape if ( xterm_terminal ) xtermMetaSendsESC(false); @@ -4262,6 +4363,30 @@ uInt FTerm::cp437_to_unicode (uChar c) return ucs; } +//---------------------------------------------------------------------- +void FTerm::setSignalHandler() +{ + signal(SIGTERM, FTerm::signal_handler); // Termination signal + signal(SIGQUIT, FTerm::signal_handler); // Quit from keyboard (Ctrl-\) + signal(SIGINT, FTerm::signal_handler); // Keyboard interrupt (Ctrl-C) + signal(SIGABRT, FTerm::signal_handler); // Abort signal from abort(3) + signal(SIGILL, FTerm::signal_handler); // Illegal Instruction + signal(SIGSEGV, FTerm::signal_handler); // Invalid memory reference + signal(SIGWINCH, FTerm::signal_handler); // Window resize signal +} + +//---------------------------------------------------------------------- +void FTerm::resetSignalHandler() +{ + signal(SIGWINCH, SIG_DFL); // Window resize signal + signal(SIGSEGV, SIG_DFL); // Invalid memory reference + signal(SIGILL, SIG_DFL); // Illegal Instruction + signal(SIGABRT, SIG_DFL); // Abort signal from abort(3) + signal(SIGINT, SIG_DFL); // Keyboard interrupt (Ctrl-C) + signal(SIGQUIT, SIG_DFL); // Quit from keyboard (Ctrl-\) + signal(SIGTERM, SIG_DFL); // Termination signal +} + //---------------------------------------------------------------------- void FTerm::signal_handler (int signum) { diff --git a/src/ftextview.cpp b/src/ftextview.cpp index 1494164a..e3a681eb 100644 --- a/src/ftextview.cpp +++ b/src/ftextview.cpp @@ -791,7 +791,7 @@ void FTextView::drawText() for (i = 0; i < len; i++) { wchar_t ch = line_str[i]; - bool utf8 = ( Encoding == fc::UTF8 ) ? true : false; + bool utf8 = ( term_encoding == fc::UTF8 ) ? true : false; // only printable and 1 column per character if ( ( (utf8 && std::iswprint(wint_t(ch))) diff --git a/src/fvterm.cpp b/src/fvterm.cpp index 8c4e9cc4..f6df2f14 100644 --- a/src/fvterm.cpp +++ b/src/fvterm.cpp @@ -2717,7 +2717,7 @@ inline void FVTerm::newFontChanges (char_data*& next_char) //---------------------------------------------------------------------- inline void FVTerm::charsetChanges (char_data*& next_char) { - if ( Encoding == fc::UTF8 ) + if ( term_encoding == fc::UTF8 ) return; uInt code = uInt(next_char->code); @@ -2733,9 +2733,9 @@ inline void FVTerm::charsetChanges (char_data*& next_char) next_char->code = int(ch_enc); - if ( Encoding == fc::VT100 ) + if ( term_encoding == fc::VT100 ) next_char->attr.bit.alt_charset = true; - else if ( Encoding == fc::PC ) + else if ( term_encoding == fc::PC ) { next_char->attr.bit.pc_charset = true; diff --git a/src/fwidget.cpp b/src/fwidget.cpp index 60343e75..82f7c2ee 100644 --- a/src/fwidget.cpp +++ b/src/fwidget.cpp @@ -1411,8 +1411,8 @@ void FWidget::drawShadow() if ( isMonochron() && ! trans_shadow ) return; - if ( (Encoding == fc::VT100 && ! trans_shadow) - || (Encoding == fc::ASCII && ! trans_shadow) ) + if ( (term_encoding == fc::VT100 && ! trans_shadow) + || (term_encoding == fc::ASCII && ! trans_shadow) ) { clearShadow(); return;