From 6d30b376e908fe678fc35c79d58314367f3d44fe Mon Sep 17 00:00:00 2001 From: Siarzhuk Zharski Date: Tue, 5 Mar 2013 20:17:40 +0100 Subject: [PATCH] Support for underline and ibeam terminal cursor styles * Add support for underline and i-beam cursor shapes. No corresponding UI configuration in preferences view ATM because preferences are waiting for refactoring and we need some eggs for this Easters. ;-) * Add handling of VT520/xterm specific DECSCUSR control sequences allowing applications to modify the style and blinking state of the cursor. May be utilized, for example, by console version of vim; * Implement cursor blinking/hiding on DECSET/DECRST commands. --- src/apps/terminal/PrefHandler.cpp | 16 +++++- src/apps/terminal/PrefHandler.h | 6 +++ src/apps/terminal/TermConst.h | 11 ++++ src/apps/terminal/TermParse.cpp | 42 +++++++++++++-- src/apps/terminal/TermView.cpp | 78 ++++++++++++++++++++++------ src/apps/terminal/TermView.h | 5 +- src/apps/terminal/TerminalBuffer.cpp | 34 ++++++++++++ src/apps/terminal/TerminalBuffer.h | 4 ++ src/apps/terminal/VTPrsTbl.c | 4 +- src/apps/terminal/VTparse.h | 2 + 10 files changed, 179 insertions(+), 23 deletions(-) diff --git a/src/apps/terminal/PrefHandler.cpp b/src/apps/terminal/PrefHandler.cpp index a83ba77c87..4013e56c76 100644 --- a/src/apps/terminal/PrefHandler.cpp +++ b/src/apps/terminal/PrefHandler.cpp @@ -27,7 +27,6 @@ #include #include -#include "PrefHandler.h" #include "TermConst.h" @@ -81,6 +80,7 @@ static const pref_defaults kTermDefaults[] = { { PREF_WINDOW_TITLE, "%T %i: %t" }, { PREF_BLINK_CURSOR, PREF_TRUE }, { PREF_WARN_ON_EXIT, PREF_TRUE }, + { PREF_CURSOR_STYLE, PREF_BLOCK_CURSOR }, { NULL, NULL}, }; @@ -262,6 +262,20 @@ PrefHandler::getBool(const char *key) } +int +PrefHandler::getCursor(const char *key) +{ + const char *value = fContainer.FindString(key); + if (value != NULL && strcmp(value, PREF_BLOCK_CURSOR) != 0) { + if (strcmp(value, PREF_UNDERLINE_CURSOR) == 0) + return UNDERLINE_CURSOR; + if (strcmp(value, PREF_IBEAM_CURSOR) == 0) + return IBEAM_CURSOR; + } + return BLOCK_CURSOR; +} + + #undef B_TRANSLATION_CONTEXT #define B_TRANSLATION_CONTEXT "Terminal getRGB" diff --git a/src/apps/terminal/PrefHandler.h b/src/apps/terminal/PrefHandler.h index 6420a40fc2..466638cb6a 100644 --- a/src/apps/terminal/PrefHandler.h +++ b/src/apps/terminal/PrefHandler.h @@ -26,6 +26,11 @@ struct pref_defaults { #define PREF_TRUE "true" #define PREF_FALSE "false" +#define PREF_BLOCK_CURSOR "block" +#define PREF_IBEAM_CURSOR "ibeam" +#define PREF_UNDERLINE_CURSOR "underline" + + class BMessage; class BEntry; @@ -49,6 +54,7 @@ class PrefHandler { const char* getString(const char *key); bool getBool(const char *key); rgb_color getRGB(const char *key); + int getCursor(const char *key); void setInt32(const char *key, int32 data); void setFloat(const char *key, float data); diff --git a/src/apps/terminal/TermConst.h b/src/apps/terminal/TermConst.h index 89ec6dc0f8..22e4a54cc0 100644 --- a/src/apps/terminal/TermConst.h +++ b/src/apps/terminal/TermConst.h @@ -105,6 +105,7 @@ static const uint32 MSG_SAVE_WINDOW_POSITION = 'swps'; static const uint32 MSG_MOVE_TAB_LEFT = 'mvtl'; static const uint32 MSG_MOVE_TAB_RIGHT = 'mvtr'; static const uint32 MSG_ACTIVATE_TERM = 'msat'; +static const uint32 MSG_SET_CURSOR_STYLE = 'mscs'; // Preference Read/Write Keys @@ -153,6 +154,7 @@ static const char* const PREF_TEXT_ENCODING = "Text encoding"; static const char* const PREF_BLINK_CURSOR = "Blinking cursor"; static const char* const PREF_WARN_ON_EXIT = "Warn on exit"; +static const char* const PREF_CURSOR_STYLE = "Cursor style"; static const char* const PREF_TAB_TITLE = "Tab title"; static const char* const PREF_WINDOW_TITLE = "Window title"; @@ -169,6 +171,15 @@ enum { SELECTION_BACKGROUND_COLOR }; + +// Cursor shape +enum { + BLOCK_CURSOR, + UNDERLINE_CURSOR, + IBEAM_CURSOR +}; + + // Preference Folder and setting path static const int32 DEFAULT = -1; diff --git a/src/apps/terminal/TermParse.cpp b/src/apps/terminal/TermParse.cpp index 4078679138..92fb5e3c45 100644 --- a/src/apps/terminal/TermParse.cpp +++ b/src/apps/terminal/TermParse.cpp @@ -694,6 +694,12 @@ TermParse::EscParse() param[nparam++] = DEFAULT; break; + case CASE_CSI_SP: // ESC [N q + // part of change cursor style DECSCUSR + if (nparam < NPARAM) + param[nparam++] = ' '; + break; + case CASE_DEC_STATE: /* enter dec mode */ parsestate = gDecTable; @@ -988,6 +994,34 @@ TermParse::EscParse() parsestate = groundtable; break; + case CASE_DECSCUSR_ETC: + // DECSCUSR - set cursor style VT520 + if (nparam == 2 && param[1] == ' ') { + bool blinking = (param[0] & 0x01) != 0; + int style = -1; + switch (param[0]) { + case 0: + blinking = true; + case 1: + case 2: + style = BLOCK_CURSOR; + break; + case 3: + case 4: + style = UNDERLINE_CURSOR; + break; + case 5: + case 6: + style = IBEAM_CURSOR; + break; + } + + if (style != -1) + fBuffer->SetCursorStyle(style, blinking); + } + parsestate = groundtable; + break; + case CASE_DECREQTPARM: // DEXREQTPARM - request terminal parameters _DecReqTermParms(param[0]); @@ -1344,11 +1378,11 @@ TermParse::_DecPrivateModeSet(int value) break; case 12: // Start Blinking Cursor. - // Not supported yet. + fBuffer->SetCursorBlinking(true); break; case 25: // Show Cursor. - // Not supported yet. + fBuffer->SetCursorHidden(false); break; case 47: // Use Alternate Screen Buffer. @@ -1419,11 +1453,11 @@ TermParse::_DecPrivateModeReset(int value) break; case 12: // Stop Blinking Cursor. - // Not supported yet. + fBuffer->SetCursorBlinking(false); break; case 25: // Hide Cursor - // Not supported yet. + fBuffer->SetCursorHidden(true); break; case 47: // Use Normal Screen Buffer. diff --git a/src/apps/terminal/TermView.cpp b/src/apps/terminal/TermView.cpp index 160b5c985b..5c9d37d55d 100644 --- a/src/apps/terminal/TermView.cpp +++ b/src/apps/terminal/TermView.cpp @@ -300,7 +300,9 @@ TermView::_InitObject(const ShellParameters& shellParameters) fResizeViewDisableCount = 0; fLastActivityTime = 0; fCursorState = 0; - fCursorHeight = 0; + fCursorStyle = BLOCK_CURSOR; + fCursorBlinking = true; + fCursorHidden = false; fCursor = TermPos(0, 0); fTextBuffer = NULL; fVisibleTextBuffer = NULL; @@ -748,7 +750,9 @@ TermView::SetTermFont(const BFont *font) fFontAscent = font_ascent; fFontHeight = font_ascent + font_descent + font_leading + 1; - fCursorHeight = fFontHeight; + fCursorStyle = PrefHandler::Default() == NULL ? BLOCK_CURSOR + : PrefHandler::Default()->getCursor(PREF_CURSOR_STYLE); + fCursorBlinking = PrefHandler::Default()->getBool(PREF_BLINK_CURSOR); _ScrollTo(0, false); if (fScrollBar != NULL) @@ -881,18 +885,30 @@ TermView::_DetachShell() } +void +TermView::_SwitchCursorBlinking(bool blinkingOn) +{ + if (blinkingOn) { + if (fCursorBlinkRunner == NULL) { + BMessage blinkMessage(kBlinkCursor); + fCursorBlinkRunner = new (std::nothrow) BMessageRunner( + BMessenger(this), &blinkMessage, kCursorBlinkInterval); + } + } else { + // make sure the cursor becomes visible + fCursorState = 0; + _InvalidateTextRect(fCursor.x, fCursor.y, fCursor.x, fCursor.y); + delete fCursorBlinkRunner; + fCursorBlinkRunner = NULL; + } +} + + void TermView::_Activate() { - bool blinkCursor = PrefHandler::Default()->getBool(PREF_BLINK_CURSOR); - fActive = true; - - if (fCursorBlinkRunner == NULL && blinkCursor) { - BMessage blinkMessage(kBlinkCursor); - fCursorBlinkRunner = new (std::nothrow) BMessageRunner( - BMessenger(this), &blinkMessage, kCursorBlinkInterval); - } + _SwitchCursorBlinking(fCursorBlinking); } @@ -902,8 +918,8 @@ TermView::_Deactivate() // make sure the cursor becomes visible fCursorState = 0; _InvalidateTextRect(fCursor.x, fCursor.y, fCursor.x, fCursor.y); - delete fCursorBlinkRunner; - fCursorBlinkRunner = NULL; + + _SwitchCursorBlinking(false); fActive = false; } @@ -987,7 +1003,7 @@ TermView::_DrawCursor() { BRect rect(fFontWidth * fCursor.x, _LineOffset(fCursor.y), 0, 0); rect.right = rect.left + fFontWidth - 1; - rect.bottom = rect.top + fCursorHeight - 1; + rect.bottom = rect.top + fFontHeight - 1; int32 firstVisible = _LineAt(0); UTF8Char character; @@ -995,9 +1011,24 @@ TermView::_DrawCursor() bool cursorVisible = _IsCursorVisible(); + if (cursorVisible) { + switch (fCursorStyle) { + case UNDERLINE_CURSOR: + rect.top = rect.bottom - 2; + break; + case IBEAM_CURSOR: + rect.right = rect.left + 1; + break; + case BLOCK_CURSOR: + default: + break; + } + } + bool selected = _CheckSelectedRegion(TermPos(fCursor.x, fCursor.y)); if (fVisibleTextBuffer->GetChar(fCursor.y - firstVisible, fCursor.x, - character, attr) == A_CHAR) { + character, attr) == A_CHAR + && (fCursorStyle == BLOCK_CURSOR || !cursorVisible)) { int32 width; if (IS_WIDTH(attr)) width = 2; @@ -1042,7 +1073,7 @@ TermView::_DrawCursor() bool TermView::_IsCursorVisible() const { - return fCursorState < kCursorVisibleIntervals; + return !fCursorHidden && fCursorState < kCursorVisibleIntervals; } @@ -1863,6 +1894,23 @@ TermView::MessageReceived(BMessage *msg) break; } + case MSG_SET_CURSOR_STYLE: + { + int32 style = BLOCK_CURSOR; + if (msg->FindInt32("style", &style) == B_OK) + fCursorStyle = style; + + bool blinking = fCursorBlinking; + if (msg->FindBool("blinking", &blinking) == B_OK) { + fCursorBlinking = blinking; + _SwitchCursorBlinking(fCursorBlinking); + } + + bool hidden = fCursorHidden; + if (msg->FindBool("hidden", &hidden) == B_OK) + fCursorHidden = hidden; + break; + } case MSG_REPORT_MOUSE_EVENT: { bool report; diff --git a/src/apps/terminal/TermView.h b/src/apps/terminal/TermView.h index a22a74dabf..f0707e3888 100644 --- a/src/apps/terminal/TermView.h +++ b/src/apps/terminal/TermView.h @@ -160,6 +160,7 @@ private: void _Activate(); void _Deactivate(); + void _SwitchCursorBlinking(bool blinkingOn); void _DrawLinePart(int32 x1, int32 y1, uint32 attr, char* buffer, int32 width, bool mouse, @@ -241,7 +242,9 @@ private: // Cursor Blinking, draw flag. bigtime_t fLastActivityTime; int32 fCursorState; - int fCursorHeight; + int fCursorStyle; + bool fCursorBlinking; + bool fCursorHidden; // Cursor position. TermPos fCursor; diff --git a/src/apps/terminal/TerminalBuffer.cpp b/src/apps/terminal/TerminalBuffer.cpp index 49d9812ad8..3f6e456758 100644 --- a/src/apps/terminal/TerminalBuffer.cpp +++ b/src/apps/terminal/TerminalBuffer.cpp @@ -177,6 +177,40 @@ TerminalBuffer::ResetColors(uint8* indexes, int32 count, bool dynamic) } +void +TerminalBuffer::SetCursorStyle(int32 style, bool blinking) +{ + if (fListenerValid) { + BMessage message(MSG_SET_CURSOR_STYLE); + message.AddInt32("style", style); + message.AddBool("blinking", blinking); + fListener.SendMessage(&message); + } +} + + +void +TerminalBuffer::SetCursorBlinking(bool blinking) +{ + if (fListenerValid) { + BMessage message(MSG_SET_CURSOR_STYLE); + message.AddBool("blinking", blinking); + fListener.SendMessage(&message); + } +} + + +void +TerminalBuffer::SetCursorHidden(bool hidden) +{ + if (fListenerValid) { + BMessage message(MSG_SET_CURSOR_STYLE); + message.AddBool("hidden", hidden); + fListener.SendMessage(&message); + } +} + + void TerminalBuffer::NotifyQuit(int32 reason) { diff --git a/src/apps/terminal/TerminalBuffer.h b/src/apps/terminal/TerminalBuffer.h index 96f1b13baa..a505350f89 100644 --- a/src/apps/terminal/TerminalBuffer.h +++ b/src/apps/terminal/TerminalBuffer.h @@ -31,6 +31,10 @@ public: int32 count = 1, bool dynamic = false); void ResetColors(uint8* indexes, int32 count = 1, bool dynamic = false); + void SetCursorStyle(int32 style, bool blinking); + void SetCursorBlinking(bool blinking); + void SetCursorHidden(bool hidden); + void NotifyQuit(int32 reason); virtual status_t ResizeTo(int32 width, int32 height); diff --git a/src/apps/terminal/VTPrsTbl.c b/src/apps/terminal/VTPrsTbl.c index 1747432064..6d09b304d5 100644 --- a/src/apps/terminal/VTPrsTbl.c +++ b/src/apps/terminal/VTPrsTbl.c @@ -1377,7 +1377,7 @@ CASE_IGNORE, CASE_IGNORE, CASE_IGNORE, /* SP ! " # */ -CASE_ESC_IGNORE, +CASE_CSI_SP, CASE_ESC_IGNORE, CASE_ESC_IGNORE, CASE_ESC_IGNORE, @@ -1478,7 +1478,7 @@ CASE_CPR, CASE_GROUND_STATE, /* p q r s */ CASE_GROUND_STATE, -CASE_GROUND_STATE, +CASE_DECSCUSR_ETC, CASE_DECSTBM, CASE_GROUND_STATE, /* t u v w */ diff --git a/src/apps/terminal/VTparse.h b/src/apps/terminal/VTparse.h index 2ec8b8184c..0fefe3bd4c 100644 --- a/src/apps/terminal/VTparse.h +++ b/src/apps/terminal/VTparse.h @@ -125,3 +125,5 @@ #define CASE_ECH 91 /* erase characters */ #define CASE_PRINT_GRA 92 +#define CASE_DECSCUSR_ETC 93 +#define CASE_CSI_SP 94