diff --git a/kitty/client.py b/kitty/client.py index f5ca134e4..c0c51ffc5 100644 --- a/kitty/client.py +++ b/kitty/client.py @@ -92,10 +92,18 @@ def screen_set_mode(x: int, private: bool) -> None: write(CSI + ('?' if private else '') + str(x) + 'h') +def screen_save_mode(x: int, private: bool) -> None: + write(CSI + ('?' if private else '') + str(x) + 's') + + def screen_reset_mode(x: int, private: bool) -> None: write(CSI + ('?' if private else '') + str(x) + 'l') +def screen_restore_mode(x: int, private: bool) -> None: + write(CSI + ('?' if private else '') + str(x) + 'r') + + def screen_set_margins(t: int, b: int) -> None: write(CSI + '%d;%dr' % (t, b)) diff --git a/kitty/parser.c b/kitty/parser.c index 7a21a8831..0652d0b72 100644 --- a/kitty/parser.c +++ b/kitty/parser.c @@ -885,9 +885,11 @@ dispatch_csi(Screen *screen, PyObject DUMP_UNUSED *dump_callback) { REPORT_COMMAND(screen_save_cursor); screen_save_cursor(screen); break; - } else if (start_modifier == '?' && !end_modifier && !num_params) { - REPORT_COMMAND(screen_save_modes); - screen_save_modes(screen); + } else if (start_modifier == '?' && !end_modifier) { + if (!num_params) { + REPORT_COMMAND(screen_save_modes); + screen_save_modes(screen); + } else { SET_MODE(screen_save_mode); } break; } REPORT_ERROR("Unknown CSI s sequence with start and end modifiers: '%c' '%c' and %u parameters", start_modifier, end_modifier, num_params); @@ -949,9 +951,11 @@ dispatch_csi(Screen *screen, PyObject DUMP_UNUSED *dump_callback) { if (!start_modifier && !end_modifier) { // DECSTBM CALL_CSI_HANDLER2(screen_set_margins, 0, 0); - } else if (start_modifier == '?' && !end_modifier && !num_params) { - REPORT_COMMAND(screen_restore_modes); - screen_restore_modes(screen); + } else if (start_modifier == '?' && !end_modifier) { + if (!num_params) { + REPORT_COMMAND(screen_restore_modes); + screen_restore_modes(screen); + } else { SET_MODE(screen_restore_mode); } break; } REPORT_ERROR("Unknown CSI r sequence with start and end modifiers: '%c' '%c' and %u parameters", start_modifier, end_modifier, num_params); diff --git a/kitty/screen.c b/kitty/screen.c index e58bc0ca8..9ed6852ca 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -105,6 +105,7 @@ new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) { if (self->write_buf == NULL) { Py_CLEAR(self); return PyErr_NoMemory(); } self->write_buf_sz = BUFSIZ; self->modes = empty_modes; + self->saved_modes = empty_modes; self->is_dirty = true; self->scroll_changed = false; self->margin_top = 0; self->margin_bottom = self->lines - 1; @@ -163,6 +164,7 @@ screen_reset(Screen *self) { clear_hyperlink_pool(self->hyperlink_pool); grman_clear(self->grman, false, self->cell_size); self->modes = empty_modes; + self->saved_modes = empty_modes; self->active_hyperlink_id = 0; #define R(name) self->color_profile->overridden.name = 0 R(default_fg); R(default_bg); R(cursor_color); R(highlight_fg); R(highlight_bg); @@ -912,7 +914,7 @@ set_mode_from_const(Screen *self, unsigned int mode, bool val) { case DECOM: self->modes.mDECOM = val; // According to `vttest`, DECOM should also home the cursor, see - // vttest/main.c:303. + // vttest/main.c:369. screen_cursor_position(self, 1, 1); break; case DECAWM: @@ -1295,11 +1297,71 @@ screen_save_cursor(Screen *self) { sp->is_valid = true; } +static void +copy_specific_mode(Screen *self, unsigned int mode, const ScreenModes *src, ScreenModes *dest) { +#define SIMPLE_MODE(name) case name: dest->m##name = src->m##name; break; +#define SIDE_EFFECTS(name) case name: if (do_side_effects) set_mode_from_const(self, name, src->m##name); else dest->m##name = src->m##name; break; + + const bool do_side_effects = dest == &self->modes; + + switch(mode) { + SIMPLE_MODE(LNM) // kitty extension + SIMPLE_MODE(IRM) // kitty extension + SIMPLE_MODE(DECARM) + SIMPLE_MODE(BRACKETED_PASTE) + SIMPLE_MODE(FOCUS_TRACKING) + SIMPLE_MODE(DECCKM) + SIMPLE_MODE(DECTCEM) + SIMPLE_MODE(DECAWM) + case MOUSE_BUTTON_TRACKING: case MOUSE_MOTION_TRACKING: case MOUSE_MOVE_TRACKING: + dest->mouse_tracking_mode = src->mouse_tracking_mode; break; + case MOUSE_UTF8_MODE: case MOUSE_SGR_MODE: case MOUSE_URXVT_MODE: + dest->mouse_tracking_protocol = src->mouse_tracking_protocol; break; + case DECSCLM: + case DECNRCM: + break; // we ignore these modes + case DECSCNM: + if (dest->mDECSCNM != src->mDECSCNM) { + dest->mDECSCNM = src->mDECSCNM; + if (do_side_effects) self->is_dirty = true; + } + break; + SIDE_EFFECTS(DECOM) + SIDE_EFFECTS(DECCOLM) + } +#undef SIMPLE_MODE +#undef SIDE_EFFECTS +} + +void +screen_save_mode(Screen *self, unsigned int mode) { // XTSAVE + copy_specific_mode(self, mode, &self->modes, &self->saved_modes); +} + +void +screen_restore_mode(Screen *self, unsigned int mode) { // XTRESTORE + copy_specific_mode(self, mode, &self->saved_modes, &self->modes); +} + +static void +copy_specific_modes(Screen *self, const ScreenModes *src, ScreenModes *dest) { + copy_specific_mode(self, LNM, src, dest); + copy_specific_mode(self, IRM, src, dest); + copy_specific_mode(self, DECARM, src, dest); + copy_specific_mode(self, BRACKETED_PASTE, src, dest); + copy_specific_mode(self, FOCUS_TRACKING, src, dest); + copy_specific_mode(self, DECCKM, src, dest); + copy_specific_mode(self, DECTCEM, src, dest); + copy_specific_mode(self, DECAWM, src, dest); + copy_specific_mode(self, MOUSE_BUTTON_TRACKING, src, dest); + copy_specific_mode(self, MOUSE_UTF8_MODE, src, dest); + copy_specific_mode(self, DECSCNM, src, dest); +} + void screen_save_modes(Screen *self) { - ScreenModes *m; - buffer_push(&self->modes_savepoints, m); - *m = self->modes; + // kitty extension to XTSAVE that saves a bunch of no side-effect modes + copy_specific_modes(self, &self->modes, &self->saved_modes); } void @@ -1323,15 +1385,8 @@ screen_restore_cursor(Screen *self) { void screen_restore_modes(Screen *self) { - const ScreenModes *m; - buffer_pop(&self->modes_savepoints, m); - if (m == NULL) m = &empty_modes; -#define S(name) set_mode_from_const(self, name, m->m##name) - S(DECTCEM); S(DECSCNM); S(DECSCNM); S(DECOM); S(DECAWM); S(DECARM); S(DECCKM); - S(BRACKETED_PASTE); S(FOCUS_TRACKING); - self->modes.mouse_tracking_mode = m->mouse_tracking_mode; - self->modes.mouse_tracking_protocol = m->mouse_tracking_protocol; -#undef S + // kitty extension to XTRESTORE that saves a bunch of no side-effect modes + copy_specific_modes(self, &self->saved_modes, &self->modes); } void diff --git a/kitty/screen.h b/kitty/screen.h index b9cce1131..7acd59e6e 100644 --- a/kitty/screen.h +++ b/kitty/screen.h @@ -67,11 +67,6 @@ typedef struct { } Savepoint; -typedef struct { - ScreenModes buf[SAVEPOINTS_SZ]; - index_type start_of_data, count; -} SavemodesBuffer; - typedef struct { CPUCell *cpu_cells; GPUCell *gpu_cells; @@ -98,14 +93,13 @@ typedef struct { bool use_latin1, is_dirty, scroll_changed, reload_all_gpu_data; Cursor *cursor; Savepoint main_savepoint, alt_savepoint; - SavemodesBuffer modes_savepoints; PyObject *callbacks, *test_child; LineBuf *linebuf, *main_linebuf, *alt_linebuf; GraphicsManager *grman, *main_grman, *alt_grman; HistoryBuf *historybuf; unsigned int history_line_added_count; bool *tabstops, *main_tabstops, *alt_tabstops; - ScreenModes modes; + ScreenModes modes, saved_modes; ColorProfile *color_profile; monotonic_t start_visual_bell_at; @@ -143,7 +137,9 @@ void screen_align(Screen*); void screen_restore_cursor(Screen *); void screen_save_cursor(Screen *); void screen_restore_modes(Screen *); +void screen_restore_mode(Screen *, unsigned int); void screen_save_modes(Screen *); +void screen_save_mode(Screen *, unsigned int); bool write_escape_code_to_child(Screen *self, unsigned char which, const char *data); void screen_cursor_position(Screen*, unsigned int, unsigned int); void screen_cursor_back(Screen *self, unsigned int count/*=1*/, int move_direction/*=-1*/);