diff --git a/user/apars_csi.c b/user/apars_csi.c index 8fb738d..193b79b 100644 --- a/user/apars_csi.c +++ b/user/apars_csi.c @@ -672,12 +672,7 @@ do_csi_set_private_option(CSI_Data *opts) } else if (n == 1048) { // same as DECSC - save/restore cursor with attributes - if (yn) { - screen_cursor_save(true); - } - else { - screen_cursor_restore(true); - } + screen_cursor_save(yn); } else if (n == 1049) { // save/restore cursor and screen and clear it diff --git a/user/screen.c b/user/screen.c index f5811bc..9cf94ee 100644 --- a/user/screen.c +++ b/user/screen.c @@ -7,7 +7,6 @@ #include "apars_logging.h" #include "jstring.h" #include "character_sets.h" -#include "uart_driver.h" TerminalConfigBundle * const termconf = &persist.current.termconf; TerminalConfigBundle termconf_scratch; @@ -41,12 +40,8 @@ typedef struct __attribute__((packed)){ static Cell screen[MAX_SCREEN_SIZE]; -#define TABSTOP_WORDS 5 -/** - * Tab stops bitmap - */ -static u32 tab_stops[TABSTOP_WORDS]; +#define TABSTOP_WORDS 5 /** * Screen state structure */ @@ -63,6 +58,8 @@ static struct { // Vertical margin bounds (inclusive start/end of scrolling region) int vm0; int vm1; + + u32 tab_stops[TABSTOP_WORDS]; // tab stops bitmap } scr; #define R0 scr.vm0 @@ -107,6 +104,19 @@ static CursorTypeDef cursor; static CursorTypeDef cursor_sav; bool cursor_saved = false; +/** This structure holds old state when switching to an alternate buffer */ +static struct { + bool alternate_active; + char title[TERM_TITLE_LEN]; + char btn[TERM_BTN_COUNT][TERM_BTN_LEN]; + char btn_msg[TERM_BTN_COUNT][TERM_BTN_MSG_LEN]; + u32 width; + u32 height; + int vm0; + int vm1; + u32 tab_stops[TABSTOP_WORDS]; +} state_backup; + /** * This is used to prevent premature change notifications * (from nested calls) @@ -282,12 +292,35 @@ screen_reset_sgr(void) cursor.inverse = false; } +/** + * Reset the screen - called by ESC c + */ +static void ICACHE_FLASH_ATTR +screen_reset_on_resize(void) +{ + dbg("Screen partial reset due to resize"); + NOTIFY_LOCK(); + + cursor.x = 0; + cursor.y = 0; + cursor.hanging = false; + + scr.vm0 = 0; + scr.vm1 = H-1; + + // size is left unchanged + screen_clear(CLEAR_ALL); + + NOTIFY_DONE(); +} + /** * Reset the screen - called by ESC c */ void ICACHE_FLASH_ATTR screen_reset(void) { + dbg("Screen reset."); NOTIFY_LOCK(); cursor_reset(); @@ -301,6 +334,8 @@ screen_reset(void) scr.vm0 = 0; scr.vm1 = H-1; + state_backup.alternate_active = false; + mouse_tracking.encoding = MTE_SIMPLE; mouse_tracking.focus_tracking = false; mouse_tracking.mode = MTM_NONE; @@ -312,7 +347,7 @@ screen_reset(void) // Set initial tabstops for (int i = 0; i < TABSTOP_WORDS; i++) { - tab_stops[i] = 0x80808080; + scr.tab_stops[i] = 0x80808080; } NOTIFY_DONE(); @@ -326,7 +361,42 @@ screen_reset(void) void ICACHE_FLASH_ATTR screen_swap_state(bool alternate) { - // TODO impl - backup/restore title, size, global attributes (not SGR) + if (alternate == state_backup.alternate_active) { + warn("No swap, already alternate = %d", alternate); + return; // nothing to do + } + + if (alternate) { + dbg("Swap to alternate"); + // store old state + memcpy(state_backup.title, termconf_scratch.title, TERM_TITLE_LEN); + memcpy(state_backup.btn, termconf_scratch.btn, sizeof(termconf_scratch.btn)); + memcpy(state_backup.btn_msg, termconf_scratch.btn_msg, sizeof(termconf_scratch.btn_msg)); + memcpy(state_backup.tab_stops, scr.tab_stops, sizeof(scr.tab_stops)); + state_backup.vm0 = scr.vm0; + state_backup.vm1 = scr.vm1; + // remember old size. may have to resize when returning + state_backup.width = W; + state_backup.height = H; + // TODO backup screen content (if this is ever possible) + } + else { + dbg("Unswap from alternate"); + NOTIFY_LOCK(); + memcpy(termconf_scratch.title, state_backup.title, TERM_TITLE_LEN); + memcpy(termconf_scratch.btn, state_backup.btn, sizeof(termconf_scratch.btn)); + memcpy(termconf_scratch.btn_msg, state_backup.btn_msg, sizeof(termconf_scratch.btn_msg)); + memcpy(scr.tab_stops, state_backup.tab_stops, sizeof(scr.tab_stops)); + scr.vm0 = state_backup.vm0; + scr.vm1 = state_backup.vm1; + // this may clear the screen as a side effect if size changed + screen_resize(state_backup.height, state_backup.width); + // TODO restore screen content (if this is ever possible) + NOTIFY_DONE(); + screen_notifyChange(CHANGE_LABELS); + } + + state_backup.alternate_active = alternate; } //endregion @@ -336,19 +406,19 @@ screen_swap_state(bool alternate) void ICACHE_FLASH_ATTR screen_clear_all_tabs(void) { - memset(tab_stops, 0, sizeof(tab_stops)); + memset(scr.tab_stops, 0, sizeof(scr.tab_stops)); } void ICACHE_FLASH_ATTR screen_set_tab(void) { - tab_stops[cursor.x/32] |= (1<<(cursor.x%32)); + scr.tab_stops[cursor.x/32] |= (1<<(cursor.x%32)); } void ICACHE_FLASH_ATTR screen_clear_tab(void) { - tab_stops[cursor.x/32] &= ~(1<<(cursor.x%32)); + scr.tab_stops[cursor.x/32] &= ~(1<<(cursor.x%32)); } /** @@ -366,7 +436,7 @@ next_tab_stop(void) int offs = (cursor.x+1)%32; int cp = cursor.x; while (idx < TABSTOP_WORDS) { - u32 w = tab_stops[idx]; + u32 w = scr.tab_stops[idx]; w >>= offs; for(;offs<32;offs++) { cp++; @@ -396,7 +466,7 @@ prev_tab_stop(void) int offs = (cursor.x-1)%32; int cp = cursor.x; while (idx >= 0) { - u32 w = tab_stops[idx]; + u32 w = scr.tab_stops[idx]; w <<= 31-offs; if (w == 0) { cp -= cp%32; @@ -651,22 +721,23 @@ screen_fill_with_E(void) void ICACHE_FLASH_ATTR screen_resize(int rows, int cols) { - NOTIFY_LOCK(); // sanitize if (cols < 1 || rows < 1) { - error("Screen size must be positive"); - goto done; + error("Screen size must be positive, ignoring command: %d x %d", cols, rows); + return; } if (cols * rows > MAX_SCREEN_SIZE) { - error("Max screen size exceeded"); - goto done; + error("Max screen size exceeded, ignoring command: %d x %d", cols, rows); + return; } + if (W == cols && H == rows) return; // Do nothing + + NOTIFY_LOCK(); W = cols; H = rows; - screen_reset(); - done: + screen_reset_on_resize(); NOTIFY_DONE(); } @@ -1289,12 +1360,6 @@ screenSerializeToBuffer(char *buffer, size_t buf_len, void **data) size_t remain = buf_len; char *bb = buffer; - // Ideally we'd use snprintf here! -#define bufprint(fmt, ...) do { \ - used = sprintf(bb, fmt, ##__VA_ARGS__); \ - if(used>0) { bb += used; remain -= used; } \ - } while(0) - #define bufput_c(c) do { \ *bb = (char)c; bb++; \ remain--; \ diff --git a/user/wifimgr.c b/user/wifimgr.c index 942f5f4..486be36 100644 --- a/user/wifimgr.c +++ b/user/wifimgr.c @@ -52,7 +52,7 @@ configure_station(void) struct station_config conf; strcpy((char *) conf.ssid, (char *) wificonf->sta_ssid); strcpy((char *) conf.password, (char *) wificonf->sta_password); - dbg("[WiFi] Connecting to \"%s\", password \"%s\"", conf.ssid, conf.password); + dbg("[WiFi] Connecting to \"%s\"%s password", conf.ssid, conf.password[0]!=0?" using saved":", no"); conf.bssid_set = 0; conf.bssid[0] = 0; wifi_station_disconnect();