Bring implementation of XTSAVE and XTRESTORE into line with xterm

Now a stack of depth 1 is used to save/restore private mode values. And
saving/restoring individual modes is supported. This latter is used by
midnight commander.
This commit is contained in:
Kovid Goyal 2021-09-14 21:59:41 +05:30
parent 4c25ceff29
commit 2a8fd278c1
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
4 changed files with 89 additions and 26 deletions

View File

@ -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))

View File

@ -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);

View File

@ -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

View File

@ -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*/);