From 04a483526f856399c03ab871836494bd80f1543c Mon Sep 17 00:00:00 2001 From: Markus Gans Date: Sat, 12 Nov 2016 22:59:48 +0100 Subject: [PATCH] Optimized input cursor positioning for terminals without hidden cursor --- ChangeLog | 8 ++- src/fbutton.cpp | 1 + src/fmenu.cpp | 3 +- src/fmenubar.cpp | 68 +++++++++---------- src/fmenuitem.cpp | 1 + src/fstring.cpp | 8 +-- src/fterm.cpp | 135 ++++++++++++++++++++----------------- src/fterm.h | 3 +- src/fwidget.cpp | 14 +++- src/fwidget.h | 5 +- test/string-operations.cpp | 2 +- 11 files changed, 141 insertions(+), 107 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4dd02b49..ac01de7c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ +2016-11-12 Markus Gans + * Better support for Linux terminals with 8 colors + * Optimized input cursor positioning for terminals without hidden cursor + * Switch locale name from "en_US" to "C" + * Fix FString toLong() + 2016-11-06 Markus Gans - * The use of xterm default colors now is configurable + * The adjustment of xterm default colors now is configurable 2016-11-05 Markus Gans * Determine xterm maximum number of colors via OSC 4 diff --git a/src/fbutton.cpp b/src/fbutton.cpp index e35463d8..cf0c5064 100644 --- a/src/fbutton.cpp +++ b/src/fbutton.cpp @@ -79,6 +79,7 @@ void FButton::setHotkeyForegroundColor (short color) button_hotkey_fg = color; } +//---------------------------------------------------------------------- void FButton::setFocusForegroundColor (short color) { // valid colors -1..254 diff --git a/src/fmenu.cpp b/src/fmenu.cpp index 3a58cc87..d024cd64 100644 --- a/src/fmenu.cpp +++ b/src/fmenu.cpp @@ -592,6 +592,7 @@ void FMenu::onMouseMove (FMouseEvent* ev) { // Unselect selected item without mouse focus (*iter)->unsetSelected(); + (*iter)->unsetFocus(); if ( getSelectedItem() == *iter ) setSelectedItem(0); @@ -1055,12 +1056,12 @@ bool FMenu::selectNextItem() unselectItem(); next->setSelected(); setSelectedItem(next); - redraw(); next->setFocus(); if ( getStatusBar() ) getStatusBar()->drawMessage(); + redraw(); updateTerminal(); flush_out(); break; diff --git a/src/fmenubar.cpp b/src/fmenubar.cpp index e0baa079..d023cf4c 100644 --- a/src/fmenubar.cpp +++ b/src/fmenubar.cpp @@ -256,47 +256,30 @@ void FMenuBar::onMouseUp (FMouseEvent* ev) x1 = (*iter)->getX(); x2 = (*iter)->getX() + (*iter)->getWidth(); - if ( mouse_y == 1 ) + if ( mouse_y == 1 && (*iter)->isEnabled() && (*iter)->isSelected() ) { - if ( (*iter)->isEnabled() && (*iter)->isSelected() ) + if ( mouse_x >= x1 && mouse_x < x2 ) { - if ( mouse_x >= x1 && mouse_x < x2 ) + // Mouse pointer over item + if ( (*iter)->hasMenu() ) { - // Mouse pointer over item - if ( (*iter)->hasMenu() ) + FMenu* menu = (*iter)->getMenu(); + + if ( ! menu->hasSelectedItem() ) { - FMenu* menu = (*iter)->getMenu(); + FMenuItem* first_item; + menu->selectFirstItem(); + first_item = menu->getSelectedItem(); - if ( ! menu->hasSelectedItem() ) - { - FMenuItem* first_item; - menu->selectFirstItem(); - first_item = menu->getSelectedItem(); + if ( first_item ) + first_item->setFocus(); - if ( first_item ) - first_item->setFocus(); + if ( getStatusBar() ) + getStatusBar()->drawMessage(); - menu->redraw(); - - if ( getStatusBar() ) - getStatusBar()->drawMessage(); - - redraw(); - drop_down = true; - } - } - else - { - (*iter)->unsetSelected(); - - if ( getSelectedItem() == *iter ) - { - setSelectedItem(0); - leaveMenuBar(); - drop_down = false; - (*iter)->processClicked(); - return; - } + redraw(); + menu->redraw(); + drop_down = true; } } else @@ -304,11 +287,24 @@ void FMenuBar::onMouseUp (FMouseEvent* ev) (*iter)->unsetSelected(); if ( getSelectedItem() == *iter ) + { setSelectedItem(0); - - redraw(); + leaveMenuBar(); + drop_down = false; + (*iter)->processClicked(); + return; + } } } + else + { + (*iter)->unsetSelected(); + + if ( getSelectedItem() == *iter ) + setSelectedItem(0); + + redraw(); + } } ++iter; diff --git a/src/fmenuitem.cpp b/src/fmenuitem.cpp index b662c890..707fb575 100644 --- a/src/fmenuitem.cpp +++ b/src/fmenuitem.cpp @@ -271,6 +271,7 @@ void FMenuItem::setSelected() void FMenuItem::unsetSelected() { selected = false; + unsetCursorPos(); processDeactivate(); } diff --git a/src/fstring.cpp b/src/fstring.cpp index 4208c6dc..86dbc4ef 100644 --- a/src/fstring.cpp +++ b/src/fstring.cpp @@ -690,7 +690,7 @@ long FString::toLong() const p++; } - while ( std::isdigit(*p) ) + while ( std::iswdigit(*p) ) { register uChar d = uChar((*p) - L'0'); @@ -704,7 +704,7 @@ long FString::toLong() const p++; } - if ( ! std::isdigit(*p) ) + if ( *p != L'\0' && ! std::iswdigit(*p) ) throw std::invalid_argument ("no valid number"); return num; @@ -736,7 +736,7 @@ uLong FString::toULong() const p++; } - while ( std::isdigit(*p) ) + while ( std::iswdigit(*p) ) { register uChar d = uChar((*p) - L'0'); @@ -750,7 +750,7 @@ uLong FString::toULong() const p++; } - if ( ! std::isdigit(*p) ) + if ( *p != L'\0' && ! std::iswdigit(*p) ) throw std::invalid_argument ("no valid number"); return num; diff --git a/src/fterm.cpp b/src/fterm.cpp index 3b6c6c0a..e6b3097d 100644 --- a/src/fterm.cpp +++ b/src/fterm.cpp @@ -27,6 +27,7 @@ int FTerm::stdin_status_flags; uInt FTerm::baudrate; bool FTerm::resize_term; bool FTerm::mouse_support; +bool FTerm::terminal_detection; bool FTerm::raw_mode; bool FTerm::input_data_pending; bool FTerm::non_blocking_stdin; @@ -2265,7 +2266,6 @@ char* FTerm::parseSecDA (char*& current_termtype) { terminal_id_version = -1; } - switch ( terminal_id_type ) { case 0: // DEC VT100 @@ -2520,7 +2520,8 @@ void FTerm::init_termcaps() FTermcap::eat_nl_glitch = true; // maximum number of colors on screen - FTermcap::max_color = tgetnum(const_cast("Co")); + FTermcap::max_color = std::max( FTermcap::max_color + , tgetnum(const_cast("Co")) ); if ( FTermcap::max_color < 0 ) FTermcap::max_color = 1; @@ -2577,10 +2578,21 @@ void FTerm::init_termcaps() // set ansi foreground and background color if ( linux_terminal || cygwin_terminal ) { - tcap[fc::t_set_a_foreground].string = \ - const_cast(CSI "3%p1%{8}%m%d%?%p1%{7}%>%t;1%e;21%;m"); - tcap[fc::t_set_a_background].string = \ - const_cast(CSI "4%p1%{8}%m%d%?%p1%{7}%>%t;5%e;25%;m"); + if ( FTermcap::max_color > 8 ) + { + tcap[fc::t_set_a_foreground].string = \ + const_cast(CSI "3%p1%{8}%m%d%?%p1%{7}%>%t;1%e;21%;m"); + tcap[fc::t_set_a_background].string = \ + const_cast(CSI "4%p1%{8}%m%d%?%p1%{7}%>%t;5%e;25%;m"); + } + else + { + tcap[fc::t_set_a_foreground].string = \ + const_cast(CSI "3%p1%dm"); + tcap[fc::t_set_a_background].string = \ + const_cast(CSI "4%p1%dm"); + } + tcap[fc::t_orig_pair].string = \ const_cast(CSI "39;49;25m"); } @@ -2946,6 +2958,7 @@ void FTerm::init() VGAFont = \ ascii_console = \ mouse_support = \ + force_vt100 = \ tera_terminal = \ kterm_terminal = \ @@ -2960,7 +2973,8 @@ void FTerm::init() xterm_default_colors = false; // Preset to true - cursor_optimisation = true; + cursor_optimisation = \ + terminal_detection = true; // assertion: programm start in cooked mode raw_mode = \ @@ -3015,33 +3029,61 @@ void FTerm::init() else linux_terminal = false; - // start terminal detection... - setRawMode(); - - // 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); - - if ( ! color256 && getXTermColorName(0) != "" ) + // terminal detection + if ( terminal_detection ) { - if ( getXTermColorName(256) != "" ) - { - new_termtype = const_cast("xterm-256color"); - } - else if ( FTermcap::max_color < 88 && getXTermColorName(87) != "" ) - { - new_termtype = const_cast("xterm-88color"); - } - else if ( FTermcap::max_color < 16 && getXTermColorName(15) != "" ) - { - new_termtype = const_cast("xterm-16color"); - } - } + setRawMode(); - unsetRawMode(); - // ...end of terminal detection + // 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 && ! tera_terminal && getXTermColorName(0) != "" ) + { + if ( getXTermColorName(256) != "" ) + { + new_termtype = const_cast("xterm-256color"); + } + else if ( getXTermColorName(87) != "" ) + { + new_termtype = const_cast("xterm-88color"); + } + else if ( getXTermColorName(15) != "" ) + { + new_termtype = const_cast("xterm-16color"); + } + } + + if ( cygwin_terminal + || putty_terminal + || tera_terminal + || rxvt_terminal ) + { + FTermcap::max_color = 16; + } + + if ( linux_terminal && openConsole() == 0 ) + { + if ( isConsole() ) + { + if ( setBlinkAsIntensity(true) == 0 ) + FTermcap::max_color = 16; + else + FTermcap::max_color = 8; + } + + closeConsole(); + setConsoleCursor(fc::underscore_cursor, true); + } + + if ( linux_terminal && getFramebuffer_bpp() >= 4 ) + FTermcap::max_color = 16; + + unsetRawMode(); + } // stop non-blocking stdin unsetNonBlockingInput(); @@ -3083,11 +3125,7 @@ void FTerm::init() // TeraTerm can not show UTF-8 character if ( tera_terminal && ! std::strcmp(nl_langinfo(CODESET), "UTF-8") ) - locale_name = std::setlocale (LC_ALL, "en_US"); - - // if locale C => switch from 7bit ascii -> latin1 - if ( isatty(stdout_no) && ! std::strcmp(nl_langinfo(CODESET), "ANSI_X3.4-1968") ) - locale_name = std::setlocale (LC_ALL, "en_US"); + locale_name = std::setlocale (LC_ALL, "C"); // try to found a meaningful content for locale_name if ( locale_name ) @@ -3164,29 +3202,6 @@ void FTerm::init() unsetNonBlockingInput(); } - if ( (FTermcap::max_color == 8) - && ( linux_terminal - || cygwin_terminal - || putty_terminal - || tera_terminal - || rxvt_terminal) ) - { - FTermcap::max_color = 16; - } - - if ( linux_terminal && openConsole() == 0 ) - { - if ( isConsole() ) - if ( setBlinkAsIntensity(true) != 0 ) - FTermcap::max_color = 8; - - closeConsole(); - setConsoleCursor(fc::underscore_cursor, true); - } - - if ( linux_terminal && getFramebuffer_bpp() >= 4 ) - FTermcap::max_color = 16; - if ( kde_konsole ) setKDECursor(fc::UnderlineCursor); diff --git a/src/fterm.h b/src/fterm.h index 8264619b..dfccc306 100644 --- a/src/fterm.h +++ b/src/fterm.h @@ -205,7 +205,7 @@ class FTerm // function pointer -> static function static int (*Fputchar)(int); - + static void putstringf (const char*, ...) #if defined(__clang__) __attribute__((__format__ (__printf__, 1, 2))) @@ -313,6 +313,7 @@ class FTerm static FTermcap::tcap_map* tcap; static bool mouse_support; + static bool terminal_detection; static bool raw_mode; static bool input_data_pending; static bool non_blocking_stdin; diff --git a/src/fwidget.cpp b/src/fwidget.cpp index 8b60dc7b..d102bfaf 100644 --- a/src/fwidget.cpp +++ b/src/fwidget.cpp @@ -22,6 +22,8 @@ FWidget::widgetList* FWidget::dialog_list = 0; FWidget::widgetList* FWidget::always_on_top_list = 0; FWidget::widgetList* FWidget::close_widget = 0; FWidget::widget_colors FWidget::wc; +bool FWidget::hideable; + //---------------------------------------------------------------------- // class FWidget @@ -40,7 +42,7 @@ FWidget::FWidget (FWidget* parent) , shown(false) , focus(false) , focusable(true) - , visible_cursor(false) + , visible_cursor(true) , widget_cursor_position(-1,-1) , size_hints() , double_flatline_mask() @@ -72,6 +74,7 @@ FWidget::FWidget (FWidget* parent) } else { + visible_cursor = ! hideable; offset = parent->client_offset; double_flatline_mask.top.resize (uLong(getWidth()), false); double_flatline_mask.right.resize (uLong(getHeight()), false); @@ -2124,6 +2127,15 @@ void FWidget::init() always_on_top_list = new widgetList(); close_widget = new widgetList(); + char* cursor_off_str = disableCursor(); + + if ( cursor_off_str && std::strlen(cursor_off_str ) > 0 ) + hideable = true; + else + hideable = false; + + visible_cursor = ! hideable; + // determine width and height of the terminal detectTermSize(); wsize.setRect(1, 1, getColumnNumber(), getLineNumber()); diff --git a/src/fwidget.h b/src/fwidget.h index 32bddc6d..81678528 100644 --- a/src/fwidget.h +++ b/src/fwidget.h @@ -514,6 +514,7 @@ class FWidget : public FVTerm static FMenuBar* menubar; static FWidget* show_root_widget; static FWidget* redraw_root_widget; + static bool hideable; // Friend class friend class FToggleButton; @@ -683,7 +684,7 @@ inline bool FWidget::setDisable() //---------------------------------------------------------------------- inline bool FWidget::setVisibleCursor (bool on) -{ return visible_cursor = (on) ? true : false; } +{ return visible_cursor = (on) ? true : ((hideable) ? false : true); } //---------------------------------------------------------------------- inline bool FWidget::setVisibleCursor() @@ -776,7 +777,7 @@ inline bool FWidget::setCursorPos (const FPoint& pos) //---------------------------------------------------------------------- inline void FWidget::unsetCursorPos() -{ widget_cursor_position.setPoint(-1,-1); } +{ setCursorPos(-1,-1); } //---------------------------------------------------------------------- inline void FWidget::setPrintPos (const FPoint& pos) diff --git a/test/string-operations.cpp b/test/string-operations.cpp index 3cc5edf3..43bab425 100644 --- a/test/string-operations.cpp +++ b/test/string-operations.cpp @@ -19,7 +19,7 @@ int main (int, char**) if ( isatty(1) && ! std::strcmp(nl_langinfo(CODESET), "ANSI_X3.4-1968") ) { // locale C -> switch from 7bit ascii -> latin1 - std::setlocale(LC_ALL, "en_US"); + std::setlocale(LC_ALL, "C"); } printf (" Codeset: %s\n", nl_langinfo(CODESET));