diff --git a/kitty/data-types.h b/kitty/data-types.h index 46ce2a447..6385a5654 100644 --- a/kitty/data-types.h +++ b/kitty/data-types.h @@ -330,6 +330,7 @@ void screen_insert_lines(Screen *self, unsigned int count/*=1*/); void screen_delete_lines(Screen *self, unsigned int count/*=1*/); void screen_delete_characters(Screen *self, unsigned int count); void screen_erase_characters(Screen *self, unsigned int count); +void screen_set_margins(Screen *self, unsigned int top, unsigned int bottom); void report_device_attributes(Screen *self, unsigned int UNUSED mode, bool UNUSED secondary); void select_graphic_rendition(Screen *self, unsigned int *params, unsigned int count); void report_device_status(Screen *self, unsigned int which, bool UNUSED); diff --git a/kitty/parser.c b/kitty/parser.c index b8649e29a..afb5fe6c5 100644 --- a/kitty/parser.c +++ b/kitty/parser.c @@ -344,6 +344,8 @@ HANDLER(csi) { CSI_HANDLER_MULTIPLE(select_graphic_rendition); \ case DSR: \ CALL_CSI_HANDLER1P(report_device_status, 0, '?'); \ + case DECSTBM: \ + CALL_CSI_HANDLER2(screen_set_margins, 0, 0); \ uint8_t ch = buf[(*pos)++]; unsigned int params[MAX_PARAMS], p1, p2, count, i; diff --git a/kitty/screen.c b/kitty/screen.c index ca533dcb7..883020704 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -775,6 +775,23 @@ void report_device_status(Screen *self, unsigned int which, bool UNUSED private) } } +void screen_set_margins(Screen *self, unsigned int top, unsigned int bottom) { + if (!top) top = 1; + if (!bottom) bottom = self->lines; + top = MIN(self->lines, top); + bottom = MIN(self->lines, bottom); + top--; bottom--; // 1 based indexing + if (bottom > top) { + // Even though VT102 and VT220 require DECSTBM to ignore regions + // of width less than 2, some programs (like aptitude for example) + // rely on it. Practicality beats purity. + self->margin_top = top; self->margin_bottom = bottom; + // The cursor moves to the home position when the top and + // bottom margins of the scrolling region (DECSTBM) changes. + screen_cursor_position(self, 1, 1); + } +} + // }}} // Python interface {{{ @@ -942,6 +959,8 @@ static PyMemberDef members[] = { {"linebuf", T_OBJECT_EX, offsetof(Screen, linebuf), 0, "linebuf"}, {"lines", T_UINT, offsetof(Screen, lines), 0, "lines"}, {"columns", T_UINT, offsetof(Screen, columns), 0, "columns"}, + {"margin_top", T_UINT, offsetof(Screen, margin_top), 0, "margin_top"}, + {"margin_bottom", T_UINT, offsetof(Screen, margin_bottom), 0, "margin_bottom"}, {"current_charset", T_UINT, offsetof(Screen, current_charset), 0, "current_charset"}, {NULL} }; diff --git a/kitty_tests/parser.py b/kitty_tests/parser.py index aff2060c8..1d4db4374 100644 --- a/kitty_tests/parser.py +++ b/kitty_tests/parser.py @@ -116,3 +116,7 @@ class TestScreen(BaseTest): c.clear() pb('\033[6n', ('report_device_status', 6, 0)) self.ae(c.wtcbuf, b'\033[2;1R') + pb('\033[2;4r', ('screen_set_margins', 2, 4)) + self.ae(s.margin_top, 1), self.ae(s.margin_bottom, 3) + pb('\033[r', ('screen_set_margins', 0, 0)) + self.ae(s.margin_top, 0), self.ae(s.margin_bottom, 4)