From 4f5daa94d01d4e7a98c13b2aa619d98d1a77bc33 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 24 Nov 2016 21:18:04 +0530 Subject: [PATCH] Clean up the mode handling code --- kitty/data-types.h | 4 +- kitty/modes.h | 37 +++++----- kitty/screen.c | 154 +++++++++++++++++++----------------------- kitty_tests/parser.py | 4 +- 4 files changed, 96 insertions(+), 103 deletions(-) diff --git a/kitty/data-types.h b/kitty/data-types.h index 6dd1d82e9..2bdea1663 100644 --- a/kitty/data-types.h +++ b/kitty/data-types.h @@ -224,7 +224,9 @@ PyTypeObject ChangeTracker_Type; typedef struct { - bool mLNM, mIRM, mDECTCEM, mDECSCNM, mDECOM, mDECAWM, mDECCOLM, mBRACKETED_PASTE, mFOCUS_TRACKING; + bool mLNM, mIRM, mDECTCEM, mDECSCNM, mDECOM, mDECAWM, mDECCOLM, + mBRACKETED_PASTE, mFOCUS_TRACKING, mMOUSE_BUTTON_TRACKING, + mMOUSE_MOTION_TRACKING, mMOUSE_SGR_MODE; } ScreenModes; PyTypeObject ScreenModes_Type; diff --git a/kitty/modes.h b/kitty/modes.h index 5e172642e..fcb01de11 100644 --- a/kitty/modes.h +++ b/kitty/modes.h @@ -23,8 +23,13 @@ // Private modes. -// *Text Cursor Enable Mode*: determines if the text cursor is visible. -#define DECTCEM (25 << 5) +// Arrow keys send application sequences or cursor movement commands +#define DECCKM (1 << 5) + +// *Column Mode*: selects the number of columns per line (80 or 132) +// on the screen. +#define DECCOLM (3 << 5) + // *Screen Mode*: toggles screen-wide reverse-video mode. #define DECSCNM (5 << 5) @@ -39,23 +44,23 @@ // when the cursor is at the right margin. #define DECAWM (7 << 5) -// *Column Mode*: selects the number of columns per line (80 or 132) -// on the screen. -#define DECCOLM (3 << 5) +// Toggle cursor blinking +#define CONTROL_CURSOR_BLINK (12 << 5) + +// *Text Cursor Enable Mode*: determines if the text cursor is visible. +#define DECTCEM (25 << 5) + +// Xterm mouse protocol +#define MOUSE_BUTTON_TRACKING (1000 << 5) +#define MOUSE_MOTION_TRACKING (1002 << 5) +#define FOCUS_TRACKING (1004 << 5) +#define MOUSE_SGR_MODE (1006 << 6) + +// Alternate screen buffer +#define ALTERNATE_SCREEN (1049 << 5) // Bracketed paste mode // http://cirw.in/blog/bracketed-paste #define BRACKETED_PASTE (2004 << 5) #define BRACKETED_PASTE_START "\033[200~" #define BRACKETED_PASTE_END "\033[201~" - -// Alternate screen buffer -#define ALTERNATE_SCREEN (1049 << 5) - -// Xterm mouse protocol -#define SEND_MOUSE_ON_PRESS_AND_RELEASE (1000 << 5) -#define HILITE_MOUSE_TRACKING (1001 << 5) -#define CELL_MOTION_MOUSE_TRACKING (1002 << 5) -#define FOCUS_TRACKING (1004 << 5) -#define SGR_MOUSE_MODE (1006 << 6) - diff --git a/kitty/screen.c b/kitty/screen.c index 1132c0cf9..16793fb6d 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -294,105 +294,78 @@ void screen_toggle_screen_buffer(Screen *self) { void screen_normal_keypad_mode(Screen UNUSED *self) {} // Not implemented as this is handled by the GUI void screen_alternate_keypad_mode(Screen UNUSED *self) {} // Not implemented as this is handled by the GUI -static inline void set_mode_from_const(Screen *self, unsigned int mode, bool val) { +static inline void +set_mode_from_const(Screen *self, unsigned int mode, bool val) { +#define SIMPLE_MODE(name) \ + case name: \ + self->modes.m##name = val; break; + + bool private; switch(mode) { - case LNM: - self->modes.mLNM = val; break; - case IRM: - self->modes.mIRM = val; break; + SIMPLE_MODE(LNM) + SIMPLE_MODE(IRM) + SIMPLE_MODE(BRACKETED_PASTE) + SIMPLE_MODE(MOUSE_BUTTON_TRACKING) + SIMPLE_MODE(MOUSE_MOTION_TRACKING) + SIMPLE_MODE(MOUSE_SGR_MODE) + SIMPLE_MODE(FOCUS_TRACKING) + + case DECCKM: + break; // we ignore this mode case DECTCEM: - self->modes.mDECTCEM = val; break; + self->modes.mDECTCEM = val; + if ((val && self->cursor->hidden) || (!val && !self->cursor->hidden)) { + self->cursor->hidden = !val; + tracker_cursor_changed(self->change_tracker); + } + break; case DECSCNM: - self->modes.mDECSCNM = val; break; + // Mark all displayed characters as reverse. + self->modes.mDECSCNM = val; + linebuf_set_attribute(self->linebuf, REVERSE_SHIFT, 0); + tracker_update_screen(self->change_tracker); + self->cursor->reverse = val; + tracker_cursor_changed(self->change_tracker); + break; case DECOM: - self->modes.mDECOM = val; break; + self->modes.mDECOM = val; + // According to `vttest`, DECOM should also home the cursor, see + // vttest/main.c:303. + screen_cursor_position(self, 1, 1); + break; case DECAWM: self->modes.mDECAWM = val; break; case DECCOLM: - self->modes.mDECCOLM = val; break; - case BRACKETED_PASTE: - self->modes.mBRACKETED_PASTE = val; break; - case FOCUS_TRACKING: - self->modes.mFOCUS_TRACKING = val; break; + // When DECCOLM mode is set, the screen is erased and the cursor + // moves to the home position. + self->modes.mDECCOLM = val; + screen_erase_in_display(self, 2, false); + screen_cursor_position(self, 1, 1); + break; + case CONTROL_CURSOR_BLINK: + self->cursor->blink = val; + tracker_cursor_changed(self->change_tracker); + break; + case ALTERNATE_SCREEN: + if (val && self->linebuf == self->main_linebuf) screen_toggle_screen_buffer(self); + else if (!val && self->linebuf != self->main_linebuf) screen_toggle_screen_buffer(self); + break; + default: + private = mode >= 1 << 5; + if (private) mode >>= 5; + fprintf(stderr, "%s %s %u %s\n", ERROR_PREFIX, "Unsupported screen mode: ", mode, private ? "(private)" : ""); } +#undef SIMPLE_MODE } void screen_set_mode(Screen *self, unsigned int mode) { - if (mode == DECCOLM) { - // When DECCOLM mode is set, the screen is erased and the cursor - // moves to the home position. - screen_erase_in_display(self, 2, false); - screen_cursor_position(self, 1, 1); - } - // According to `vttest`, DECOM should also home the cursor, see - // vttest/main.c:303. - if (mode == DECOM) screen_cursor_position(self, 1, 1); - - if (mode == DECSCNM) { - // Mark all displayed characters as reverse. - linebuf_set_attribute(self->linebuf, REVERSE_SHIFT, 1); - tracker_update_screen(self->change_tracker); - self->cursor->reverse = true; - tracker_cursor_changed(self->change_tracker); - } - - if (mode == DECTCEM && self->cursor->hidden) { - self->cursor->hidden = false; - tracker_cursor_changed(self->change_tracker); - } - - if (mode == ALTERNATE_SCREEN && self->linebuf == self->main_linebuf) { - screen_toggle_screen_buffer(self); - } set_mode_from_const(self, mode, true); } -static PyObject* -in_bracketed_paste_mode(Screen *self) { -#define in_bracketed_paste_mode_doc "" - PyObject *ans = self->modes.mBRACKETED_PASTE ? Py_True : Py_False; - Py_INCREF(ans); - return ans; -} - -static PyObject* -focus_tracking_enabled(Screen *self) { -#define focus_tracking_enabled_doc "" - PyObject *ans = self->modes.mFOCUS_TRACKING ? Py_True : Py_False; - Py_INCREF(ans); - return ans; -} - void screen_reset_mode(Screen *self, unsigned int mode) { - if (mode == DECCOLM) { - // When DECCOLM mode is set, the screen is erased and the cursor - // moves to the home position. - screen_erase_in_display(self, 2, false); - screen_cursor_position(self, 1, 1); - } - // According to `vttest`, DECOM should also home the cursor, see - // vttest/main.c:303. - if (mode == DECOM) screen_cursor_position(self, 1, 1); - - if (mode == DECSCNM) { - // Mark all displayed characters as reverse. - linebuf_set_attribute(self->linebuf, REVERSE_SHIFT, 0); - tracker_update_screen(self->change_tracker); - self->cursor->reverse = false; - tracker_cursor_changed(self->change_tracker); - } - - if (mode == DECTCEM && !self->cursor->hidden) { - self->cursor->hidden = true; - tracker_cursor_changed(self->change_tracker); - } - - if (mode == ALTERNATE_SCREEN && self->linebuf != self->main_linebuf) { - screen_toggle_screen_buffer(self); - } - set_mode_from_const(self, mode, false); } + // }}} // Cursor {{{ @@ -934,6 +907,16 @@ erase_in_display(Screen *self, PyObject *args) { Py_RETURN_NONE; } +#define MODE_GETTER(name, uname) \ + static PyObject* name(Screen *self) { PyObject *ans = self->modes.m##uname ? Py_True : Py_False; Py_INCREF(ans); return ans; } + +MODE_GETTER(in_bracketed_paste, BRACKETED_PASTE) +MODE_GETTER(focus_tracking_enabled, FOCUS_TRACKING) +MODE_GETTER(mouse_button_tracking_enabled, MOUSE_BUTTON_TRACKING) +MODE_GETTER(mouse_motion_tracking_enabled, MOUSE_MOTION_TRACKING) +MODE_GETTER(mouse_in_sgr_mode, MOUSE_SGR_MODE) + + static PyObject* cursor_up(Screen *self, PyObject *args) { unsigned int count = 1; @@ -1059,8 +1042,6 @@ static PyMethodDef methods[] = { METHOD(draw, METH_O) METHOD(set_mode, METH_VARARGS) METHOD(reset_mode, METH_VARARGS) - METHOD(focus_tracking_enabled, METH_NOARGS) - METHOD(in_bracketed_paste_mode, METH_NOARGS) METHOD(reset, METH_NOARGS) METHOD(reset_dirty, METH_NOARGS) METHOD(consolidate_changes, METH_NOARGS) @@ -1085,6 +1066,11 @@ static PyMethodDef methods[] = { MND(mark_as_dirty, METH_NOARGS) MND(resize, METH_VARARGS) MND(set_scroll_cell_data, METH_VARARGS) + MND(in_bracketed_paste, METH_NOARGS) + MND(focus_tracking_enabled, METH_NOARGS) + MND(mouse_button_tracking_enabled, METH_NOARGS) + MND(mouse_motion_tracking_enabled, METH_NOARGS) + MND(mouse_in_sgr_mode, METH_NOARGS) {"update_cell_data", (PyCFunction)screen_update_cell_data, METH_VARARGS, ""}, {NULL} /* Sentinel */ diff --git a/kitty_tests/parser.py b/kitty_tests/parser.py index 0f3997540..84dde1671 100644 --- a/kitty_tests/parser.py +++ b/kitty_tests/parser.py @@ -91,8 +91,8 @@ class TestParser(BaseTest): pb('\033[?2J', ('screen_erase_in_display', 2, 1)) pb('\033[h') pb('\033[20;4h', ('screen_set_mode', 20), ('screen_set_mode', 4)) - pb('\033[?20;5h', ('screen_set_mode', 20 << 5), ('screen_set_mode', 5 << 5)) - pb('\033[20;4;145l', ('screen_reset_mode', 20), ('screen_reset_mode', 4), ('screen_reset_mode', 145)) + pb('\033[?1000;1004h', ('screen_set_mode', 1000 << 5), ('screen_set_mode', 1004 << 5)) + pb('\033[20;4;20l', ('screen_reset_mode', 20), ('screen_reset_mode', 4), ('screen_reset_mode', 20)) s.reset() pb('\033[1;3;4;7;9;34;44m', ('select_graphic_rendition', 7)) for attr in 'bold italic reverse strikethrough'.split():