new message format
This commit is contained in:
+2
-2
@@ -757,11 +757,11 @@ do_csi_set_private_option(CSI_Data *opts)
|
||||
}
|
||||
else if (n == 800) { // ESPTerm: Toggle display of buttons
|
||||
termconf_live.show_buttons = yn;
|
||||
screen_notifyChange(CHANGE_CONTENT); // this info is included in the screen preamble
|
||||
screen_notifyChange(TOPIC_CHANGE_SCREEN_OPTS); // this info is included in the screen preamble
|
||||
}
|
||||
else if (n == 801) { // ESPTerm: Toggle display of config links
|
||||
termconf_live.show_config_links = yn;
|
||||
screen_notifyChange(CHANGE_CONTENT); // this info is included in the screen preamble
|
||||
screen_notifyChange(TOPIC_CHANGE_SCREEN_OPTS); // this info is included in the screen preamble
|
||||
}
|
||||
else {
|
||||
ansi_noimpl("?OPTION %d", n);
|
||||
|
||||
+1
-5
@@ -25,11 +25,7 @@ httpd_cgi_state ICACHE_FLASH_ATTR tplScreen(HttpdConnData *connData, char *token
|
||||
|
||||
char buff[150];
|
||||
|
||||
if (streq(token, "labels_seq")) {
|
||||
screenSerializeLabelsToBuffer(buff, 150);
|
||||
tplSend(connData, buff, -1);
|
||||
}
|
||||
else if (streq(token, "theme")) {
|
||||
if (streq(token, "theme")) {
|
||||
sprintf(buff, "%d", termconf->theme);
|
||||
tplSend(connData, buff, -1);
|
||||
}
|
||||
|
||||
+40
-65
@@ -16,6 +16,8 @@
|
||||
// Must be less than httpd sendbuf
|
||||
#define SOCK_BUF_LEN 2000
|
||||
|
||||
volatile ScreenNotifyTopics pendingBroadcastTopics = 0;
|
||||
|
||||
// flags for screen update timeouts
|
||||
volatile bool notify_available = true;
|
||||
volatile bool notify_cooldown = false;
|
||||
@@ -24,12 +26,11 @@ volatile bool notify_cooldown = false;
|
||||
* and we have to tell it we're ready again */
|
||||
volatile bool browser_wants_xon = false;
|
||||
|
||||
static ETSTimer notifyContentTim;
|
||||
static ETSTimer notifyLabelsTim;
|
||||
static ETSTimer updateNotifyTim;
|
||||
static ETSTimer notifyCooldownTim;
|
||||
static ETSTimer heartbeatTim;
|
||||
|
||||
volatile int active_clients = 0;
|
||||
volatile int term_active_clients = 0;
|
||||
|
||||
// we're trying to do a kind of mutex here, without the actual primitives
|
||||
// this might glitch, very rarely.
|
||||
@@ -52,25 +53,21 @@ notifyCooldownTimCb(void *arg)
|
||||
* @param arg
|
||||
*/
|
||||
static void ICACHE_FLASH_ATTR
|
||||
notifyContentTimCb(void *arg)
|
||||
updateNotify_do(Websock *ws, ScreenNotifyTopics topics)
|
||||
{
|
||||
Websock *ws = arg;
|
||||
void *data = NULL;
|
||||
int max_bl, total_bl;
|
||||
char sock_buff[SOCK_BUF_LEN];
|
||||
|
||||
cgiWebsockMeasureBacklog(URL_WS_UPDATE, &max_bl, &total_bl);
|
||||
|
||||
if (!notify_available || notify_cooldown || (max_bl > 2048)) { // do not send if we have anything significant backlogged
|
||||
// postpone a little
|
||||
TIMER_START(¬ifyContentTim, notifyContentTimCb, 4, 0);
|
||||
inp_dbg("postpone notify content");
|
||||
return;
|
||||
}
|
||||
notify_available = false;
|
||||
|
||||
for (int i = 0; i < 20; i++) {
|
||||
httpd_cgi_state cont = screenSerializeToBuffer(sock_buff, SOCK_BUF_LEN, &data);
|
||||
if (! ws) {
|
||||
// broadcast
|
||||
topics = pendingBroadcastTopics;
|
||||
pendingBroadcastTopics = 0;
|
||||
}
|
||||
httpd_cgi_state cont = screenSerializeToBuffer(sock_buff, SOCK_BUF_LEN, topics, &data);
|
||||
|
||||
int flg = 0;
|
||||
if (cont == HTTPD_CGI_MORE) flg |= WEBSOCK_FLAG_MORE;
|
||||
if (i > 0) flg |= WEBSOCK_FLAG_CONT;
|
||||
@@ -86,56 +83,42 @@ notifyContentTimCb(void *arg)
|
||||
}
|
||||
|
||||
// cleanup
|
||||
screenSerializeToBuffer(NULL, SOCK_BUF_LEN, &data);
|
||||
screenSerializeToBuffer(NULL, 0, 0, &data);
|
||||
|
||||
notify_cooldown = true;
|
||||
notify_available = true;
|
||||
|
||||
TIMER_START(¬ifyCooldownTim, notifyCooldownTimCb, termconf->display_cooldown_ms, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell browsers about the new text labels
|
||||
* Tell browser we have new content
|
||||
* @param arg
|
||||
*/
|
||||
static void ICACHE_FLASH_ATTR
|
||||
notifyLabelsTimCb(void *arg)
|
||||
updateNotifyCb(void *arg)
|
||||
{
|
||||
Websock *ws = arg;
|
||||
char sock_buff[SOCK_BUF_LEN];
|
||||
int max_bl, total_bl;
|
||||
cgiWebsockMeasureBacklog(URL_WS_UPDATE, &max_bl, &total_bl);
|
||||
|
||||
if (!notify_available || notify_cooldown) {
|
||||
if (!notify_available || notify_cooldown || (max_bl > 2048)) { // do not send if we have anything significant backlogged
|
||||
// postpone a little
|
||||
TIMER_START(¬ifyLabelsTim, notifyLabelsTimCb, 7, 0);
|
||||
inp_dbg("postpone notify labels");
|
||||
TIMER_START(&updateNotifyTim, updateNotifyCb, 4, 0);
|
||||
inp_dbg("postpone notify content");
|
||||
return;
|
||||
}
|
||||
notify_available = false;
|
||||
|
||||
screenSerializeLabelsToBuffer(sock_buff, SOCK_BUF_LEN);
|
||||
|
||||
if (ws) {
|
||||
cgiWebsocketSend(ws, sock_buff, (int) strlen(sock_buff), 0);
|
||||
} else {
|
||||
cgiWebsockBroadcast(URL_WS_UPDATE, sock_buff, (int) strlen(sock_buff), 0);
|
||||
resetHeartbeatTimer();
|
||||
}
|
||||
updateNotify_do(arg, 0);
|
||||
|
||||
notify_cooldown = true;
|
||||
notify_available = true;
|
||||
|
||||
TIMER_START(¬ifyCooldownTim, notifyCooldownTimCb, termconf->display_cooldown_ms, 0);
|
||||
}
|
||||
|
||||
|
||||
/** Beep */
|
||||
void ICACHE_FLASH_ATTR
|
||||
send_beep(void)
|
||||
{
|
||||
if (active_clients == 0) return;
|
||||
|
||||
// here's some potential for a race error with the other broadcast functions :C
|
||||
cgiWebsockBroadcast(URL_WS_UPDATE, "B", 1, 0);
|
||||
resetHeartbeatTimer();
|
||||
if (term_active_clients == 0) return;
|
||||
screen_notifyChange(TOPIC_BELL); // XXX has latency, maybe better to send directly
|
||||
}
|
||||
|
||||
|
||||
@@ -143,10 +126,10 @@ send_beep(void)
|
||||
void ICACHE_FLASH_ATTR
|
||||
notify_growl(char *msg)
|
||||
{
|
||||
if (active_clients == 0) return;
|
||||
if (term_active_clients == 0) return;
|
||||
|
||||
// TODO via timer...
|
||||
// here's some potential for a race error with the other broadcast functions :C
|
||||
// here's some potential for a race error with the other broadcast functions
|
||||
// - we assume app won't send notifications in the middle of updating content
|
||||
cgiWebsockBroadcast(URL_WS_UPDATE, msg, (int) strlen(msg), 0);
|
||||
resetHeartbeatTimer();
|
||||
}
|
||||
@@ -157,24 +140,17 @@ notify_growl(char *msg)
|
||||
* This is a callback for the Screen module,
|
||||
* called after each visible screen modification.
|
||||
*/
|
||||
void ICACHE_FLASH_ATTR screen_notifyChange(ScreenNotifyChangeTopic topic)
|
||||
void ICACHE_FLASH_ATTR screen_notifyChange(ScreenNotifyTopics topics)
|
||||
{
|
||||
if (active_clients == 0) return;
|
||||
if (term_active_clients == 0) return;
|
||||
|
||||
// this is probably not needed here - ensure timeout is not 0
|
||||
if (termconf->display_tout_ms == 0)
|
||||
if (termconf->display_tout_ms == 0) {
|
||||
termconf->display_tout_ms = SCR_DEF_DISPLAY_TOUT_MS;
|
||||
|
||||
// NOTE: the timers are restarted if already running
|
||||
|
||||
if (topic == CHANGE_LABELS) {
|
||||
// separate timer from content change timer, to avoid losing that update
|
||||
TIMER_START(¬ifyLabelsTim, notifyLabelsTimCb, termconf->display_tout_ms+2, 0); // this delay is useful when both are fired at once on screen reset
|
||||
}
|
||||
else if (topic == CHANGE_CONTENT) {
|
||||
// throttle delay
|
||||
TIMER_START(¬ifyContentTim, notifyContentTimCb, termconf->display_tout_ms, 0);
|
||||
}
|
||||
|
||||
// NOTE: the timer is restarted if already running
|
||||
TIMER_START(&updateNotifyTim, updateNotifyCb, termconf->display_tout_ms, 0); // note - this adds latency to beep
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -296,8 +272,7 @@ static void ICACHE_FLASH_ATTR updateSockRx(Websock *ws, char *data, int len, int
|
||||
case 'i':
|
||||
// requests initial load
|
||||
inp_dbg("Client requests initial load");
|
||||
notifyContentTimCb(ws); // delay??
|
||||
notifyLabelsTimCb(ws);
|
||||
updateNotify_do(ws, TOPIC_INITIAL);
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
@@ -322,7 +297,7 @@ static void ICACHE_FLASH_ATTR updateSockRx(Websock *ws, char *data, int len, int
|
||||
/** Send a heartbeat msg */
|
||||
static void ICACHE_FLASH_ATTR heartbeatTimCb(void *unused)
|
||||
{
|
||||
if (active_clients > 0) {
|
||||
if (term_active_clients > 0) {
|
||||
if (notify_available) {
|
||||
inp_dbg(".");
|
||||
|
||||
@@ -348,9 +323,9 @@ static void ICACHE_FLASH_ATTR resetHeartbeatTimer(void)
|
||||
|
||||
static void ICACHE_FLASH_ATTR closeSockCb(Websock *ws)
|
||||
{
|
||||
active_clients--;
|
||||
if (active_clients <= 0) {
|
||||
active_clients = 0;
|
||||
term_active_clients--;
|
||||
if (term_active_clients <= 0) {
|
||||
term_active_clients = 0;
|
||||
|
||||
if (mouse_tracking.focus_tracking) {
|
||||
UART_SendAsync("\x1b[O", 3);
|
||||
@@ -368,7 +343,7 @@ void ICACHE_FLASH_ATTR updateSockConnect(Websock *ws)
|
||||
ws->recvCb = updateSockRx;
|
||||
ws->closeCb = closeSockCb;
|
||||
|
||||
if (active_clients == 0) {
|
||||
if (term_active_clients == 0) {
|
||||
if (mouse_tracking.focus_tracking) {
|
||||
UART_SendAsync("\x1b[I", 3);
|
||||
}
|
||||
@@ -376,7 +351,7 @@ void ICACHE_FLASH_ATTR updateSockConnect(Websock *ws)
|
||||
resetHeartbeatTimer();
|
||||
}
|
||||
|
||||
active_clients++;
|
||||
term_active_clients++;
|
||||
}
|
||||
|
||||
ETSTimer xonTim;
|
||||
|
||||
@@ -15,6 +15,8 @@ void send_beep(void);
|
||||
/** open pop-up notification */
|
||||
void notify_growl(char *msg);
|
||||
|
||||
extern volatile int term_active_clients;
|
||||
|
||||
// defined in the makefile
|
||||
#if DEBUG_INPUT
|
||||
#define inp_warn warn
|
||||
|
||||
+26
-16
@@ -40,7 +40,7 @@ cgiTermCfgSetParams(HttpdConnData *connData)
|
||||
char buff[50];
|
||||
char redir_url_buf[100];
|
||||
int32 n, w, h;
|
||||
bool notify_screen_content = 0, notify_screen_labels = 0;
|
||||
ScreenNotifyTopics topics = 0;
|
||||
|
||||
bool shall_clear_screen = false;
|
||||
bool shall_init_uart = false;
|
||||
@@ -94,7 +94,8 @@ cgiTermCfgSetParams(HttpdConnData *connData)
|
||||
if (termconf->width != w || termconf->height != h) {
|
||||
termconf->width = w;
|
||||
termconf->height = h;
|
||||
shall_clear_screen = true; // this causes a notify
|
||||
shall_clear_screen = true;
|
||||
topics |= TOPIC_CHANGE_SCREEN_OPTS | TOPIC_CHANGE_CONTENT_ALL;
|
||||
}
|
||||
} while (0);
|
||||
}
|
||||
@@ -112,6 +113,7 @@ cgiTermCfgSetParams(HttpdConnData *connData)
|
||||
|
||||
if (termconf->default_bg != n) {
|
||||
termconf->default_bg = n; // this is current not sent through socket, no use to notify
|
||||
topics |= TOPIC_CHANGE_SCREEN_OPTS;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,6 +130,7 @@ cgiTermCfgSetParams(HttpdConnData *connData)
|
||||
|
||||
if (termconf->default_fg != n) {
|
||||
termconf->default_fg = n; // this is current not sent through socket, no use to notify
|
||||
topics |= TOPIC_CHANGE_SCREEN_OPTS;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,40 +171,49 @@ cgiTermCfgSetParams(HttpdConnData *connData)
|
||||
cgi_dbg("FN alt mode: %s", buff);
|
||||
n = atoi(buff);
|
||||
termconf->fn_alt_mode = (bool)n;
|
||||
notify_screen_content = true;
|
||||
topics |= TOPIC_CHANGE_SCREEN_OPTS;
|
||||
}
|
||||
|
||||
if (GET_ARG("want_all_fn")) {
|
||||
cgi_dbg("AllFN mode: %s", buff);
|
||||
n = atoi(buff);
|
||||
termconf->want_all_fn = (bool)n;
|
||||
topics |= TOPIC_CHANGE_SCREEN_OPTS;
|
||||
}
|
||||
|
||||
if (GET_ARG("crlf_mode")) {
|
||||
cgi_dbg("CRLF mode: %s", buff);
|
||||
n = atoi(buff);
|
||||
termconf->crlf_mode = (bool)n;
|
||||
notify_screen_content = true;
|
||||
topics |= TOPIC_CHANGE_SCREEN_OPTS;
|
||||
}
|
||||
|
||||
if (GET_ARG("show_buttons")) {
|
||||
cgi_dbg("Show buttons: %s", buff);
|
||||
n = atoi(buff);
|
||||
termconf->show_buttons = (bool)n;
|
||||
notify_screen_content = true;
|
||||
topics |= TOPIC_CHANGE_SCREEN_OPTS;
|
||||
}
|
||||
|
||||
if (GET_ARG("show_config_links")) {
|
||||
cgi_dbg("Show config links: %s", buff);
|
||||
n = atoi(buff);
|
||||
termconf->show_config_links = (bool)n;
|
||||
notify_screen_content = true;
|
||||
topics |= TOPIC_CHANGE_SCREEN_OPTS;
|
||||
}
|
||||
|
||||
if (GET_ARG("loopback")) {
|
||||
cgi_dbg("Loopback: %s", buff);
|
||||
n = atoi(buff);
|
||||
termconf->loopback = (bool)n;
|
||||
topics |= TOPIC_CHANGE_SCREEN_OPTS;
|
||||
}
|
||||
|
||||
if (GET_ARG("debugbar")) {
|
||||
cgi_dbg("Debugbar: %s", buff);
|
||||
n = atoi(buff);
|
||||
termconf->debugbar = (bool)n;
|
||||
topics |= TOPIC_CHANGE_SCREEN_OPTS;
|
||||
}
|
||||
|
||||
if (GET_ARG("theme")) {
|
||||
@@ -213,6 +225,7 @@ cgiTermCfgSetParams(HttpdConnData *connData)
|
||||
} else {
|
||||
cgi_warn("Bad theme num: %s", buff);
|
||||
redir_url += sprintf(redir_url, "theme,");
|
||||
topics |= TOPIC_CHANGE_SCREEN_OPTS;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,7 +234,7 @@ cgiTermCfgSetParams(HttpdConnData *connData)
|
||||
n = atoi(buff);
|
||||
if (n >= 0 && n <= 6 && n != 1) {
|
||||
termconf->cursor_shape = (enum CursorShape) n;
|
||||
notify_screen_content = true;
|
||||
topics |= TOPIC_CHANGE_SCREEN_OPTS;
|
||||
} else {
|
||||
cgi_warn("Bad cursor_shape num: %s", buff);
|
||||
redir_url += sprintf(redir_url, "cursor_shape,");
|
||||
@@ -231,7 +244,7 @@ cgiTermCfgSetParams(HttpdConnData *connData)
|
||||
if (GET_ARG("term_title")) {
|
||||
cgi_dbg("Terminal title default text: \"%s\"", buff);
|
||||
strncpy_safe(termconf->title, buff, 64); // ATTN those must match the values in
|
||||
notify_screen_labels = true;
|
||||
topics |= TOPIC_CHANGE_TITLE;
|
||||
}
|
||||
|
||||
for (int btn_i = 1; btn_i <= TERM_BTN_COUNT; btn_i++) {
|
||||
@@ -239,7 +252,7 @@ cgiTermCfgSetParams(HttpdConnData *connData)
|
||||
if (GET_ARG(buff)) {
|
||||
cgi_dbg("Button%d default text: \"%s\"", btn_i, buff);
|
||||
strncpy_safe(termconf->btn[btn_i-1], buff, TERM_BTN_LEN);
|
||||
notify_screen_labels = true;
|
||||
topics |= TOPIC_CHANGE_BUTTONS;
|
||||
}
|
||||
|
||||
sprintf(buff, "bm%d", btn_i);
|
||||
@@ -368,13 +381,7 @@ cgiTermCfgSetParams(HttpdConnData *connData)
|
||||
serialInit();
|
||||
}
|
||||
|
||||
if (notify_screen_content) {
|
||||
screen_notifyChange(CHANGE_CONTENT);
|
||||
}
|
||||
|
||||
if (notify_screen_labels) {
|
||||
screen_notifyChange(CHANGE_LABELS);
|
||||
}
|
||||
if (topics) screen_notifyChange(topics);
|
||||
|
||||
httpdRedirect(connData, SET_REDIR_SUC "?msg=Settings%20saved%20and%20applied.");
|
||||
} else {
|
||||
@@ -440,6 +447,9 @@ tplTermCfg(HttpdConnData *connData, char *token, void **arg)
|
||||
else if (streq(token, "loopback")) {
|
||||
sprintf(buff, "%d", (int)termconf->loopback);
|
||||
}
|
||||
else if (streq(token, "debugbar")) {
|
||||
sprintf(buff, "%d", (int)termconf->debugbar);
|
||||
}
|
||||
else if (streq(token, "theme")) {
|
||||
sprintf(buff, "%d", termconf->theme);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,4 @@
|
||||
|
||||
extern const HttpdBuiltInUrl routes[];
|
||||
|
||||
/** Broadcast screen state to sockets */
|
||||
void screen_notifyChange();
|
||||
|
||||
#endif //ROUTES_H
|
||||
|
||||
+285
-102
@@ -5,10 +5,9 @@
|
||||
#include "sgr.h"
|
||||
#include "ascii.h"
|
||||
#include "apars_logging.h"
|
||||
#include "jstring.h"
|
||||
#include "character_sets.h"
|
||||
#include "utf8.h"
|
||||
#include "uart_buffer.h"
|
||||
#include "cgi_sockets.h"
|
||||
|
||||
TerminalConfigBundle * const termconf = &persist.current.termconf;
|
||||
TerminalConfigBundle termconf_live;
|
||||
@@ -74,7 +73,6 @@ typedef struct {
|
||||
bool hanging; //!< xenl state - cursor half-wrapped
|
||||
|
||||
/* SGR */
|
||||
bool inverse; //!< not in attrs bc it's applied immediately when writing the cell
|
||||
bool conceal; //!< similar to inverse, causes all to be replaced by SP
|
||||
u16 attrs;
|
||||
Color fg; //!< Foreground color for writing
|
||||
@@ -139,14 +137,19 @@ static struct {
|
||||
* (from nested calls)
|
||||
*/
|
||||
static volatile int notifyLock = 0;
|
||||
static volatile ScreenNotifyTopics lockTopics = 0;
|
||||
|
||||
#define NOTIFY_LOCK() do { \
|
||||
notifyLock++; \
|
||||
} while(0)
|
||||
|
||||
#define NOTIFY_DONE() do { \
|
||||
#define NOTIFY_DONE(updateTopics) do { \
|
||||
lockTopics |= (updateTopics); \
|
||||
if (notifyLock > 0) notifyLock--; \
|
||||
if (notifyLock == 0) screen_notifyChange(CHANGE_CONTENT); \
|
||||
if (notifyLock == 0) { \
|
||||
screen_notifyChange(lockTopics); \
|
||||
lockTopics = 0;\
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
/** Clear the hanging attribute if the cursor is no longer >= W */
|
||||
@@ -185,6 +188,7 @@ terminal_restore_defaults(void)
|
||||
termconf->cursor_shape = SCR_DEF_CURSOR_SHAPE;
|
||||
termconf->crlf_mode = SCR_DEF_CRLF;
|
||||
termconf->want_all_fn = SCR_DEF_ALLFN;
|
||||
termconf->debugbar = SCR_DEF_DEBUGBAR;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -203,12 +207,12 @@ terminal_apply_settings_noclear(void)
|
||||
{
|
||||
bool changed = false;
|
||||
|
||||
// // Migrate to v1
|
||||
// if (termconf->config_version < 1) {
|
||||
// persist_dbg("termconf: Updating to version %d", 1);
|
||||
// termconf->display_cooldown_ms = SCR_DEF_DISPLAY_COOLDOWN_MS;
|
||||
// changed = 1;
|
||||
// }
|
||||
// Migrate to v1
|
||||
if (termconf->config_version < 1) {
|
||||
persist_dbg("termconf: Updating to version %d", 1);
|
||||
termconf->debugbar = SCR_DEF_DEBUGBAR;
|
||||
changed = 1;
|
||||
}
|
||||
|
||||
termconf->config_version = TERMCONF_VERSION;
|
||||
|
||||
@@ -257,6 +261,8 @@ screen_init(void)
|
||||
static void ICACHE_FLASH_ATTR
|
||||
cursor_reset(void)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
|
||||
cursor.x = 0;
|
||||
cursor.y = 0;
|
||||
cursor.hanging = false;
|
||||
@@ -266,6 +272,8 @@ cursor_reset(void)
|
||||
cursor.charset1 = CS_0_DEC_SUPPLEMENTAL;
|
||||
|
||||
screen_reset_sgr();
|
||||
|
||||
NOTIFY_DONE(TOPIC_CHANGE_CURSOR);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -285,7 +293,7 @@ screen_reset_on_resize(void)
|
||||
// size is left unchanged
|
||||
screen_clear(CLEAR_ALL); // also clears utf cache
|
||||
|
||||
NOTIFY_DONE();
|
||||
NOTIFY_DONE(TOPIC_INTERNAL);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -294,15 +302,20 @@ screen_reset_on_resize(void)
|
||||
void ICACHE_FLASH_ATTR
|
||||
screen_reset_sgr(void)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
|
||||
cursor.fg = 0;
|
||||
cursor.bg = 0;
|
||||
cursor.attrs = 0;
|
||||
cursor.conceal = false;
|
||||
|
||||
NOTIFY_DONE(TOPIC_INTERNAL);
|
||||
}
|
||||
|
||||
static void ICACHE_FLASH_ATTR
|
||||
screen_reset_do(bool size, bool labels)
|
||||
{
|
||||
ScreenNotifyTopics topics = TOPIC_CHANGE_SCREEN_OPTS | TOPIC_CHANGE_CURSOR | TOPIC_CHANGE_CONTENT_ALL;
|
||||
NOTIFY_LOCK();
|
||||
|
||||
// DECopts
|
||||
@@ -350,7 +363,7 @@ screen_reset_do(bool size, bool labels)
|
||||
termconf_live.show_buttons = termconf->show_buttons;
|
||||
termconf_live.show_config_links = termconf->show_config_links;
|
||||
|
||||
screen_notifyChange(CHANGE_LABELS);
|
||||
topics |= TOPIC_CHANGE_TITLE | TOPIC_CHANGE_BUTTONS;
|
||||
}
|
||||
|
||||
// initial values in the save buffer in case of receiving restore without storing first
|
||||
@@ -368,7 +381,7 @@ screen_reset_do(bool size, bool labels)
|
||||
opt_backup.show_buttons = termconf_live.show_buttons;
|
||||
opt_backup.show_config_links = termconf_live.show_config_links;
|
||||
|
||||
NOTIFY_DONE();
|
||||
NOTIFY_DONE(topics);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -395,8 +408,11 @@ screen_swap_state(bool alternate)
|
||||
return; // nothing to do
|
||||
}
|
||||
|
||||
NOTIFY_LOCK();
|
||||
|
||||
if (alternate) {
|
||||
ansi_dbg("Swap to alternate");
|
||||
NOTIFY_LOCK();
|
||||
// store old state
|
||||
memcpy(state_backup.title, termconf_live.title, TERM_TITLE_LEN);
|
||||
memcpy(state_backup.btn, termconf_live.btn, sizeof(termconf_live.btn));
|
||||
@@ -411,7 +427,6 @@ screen_swap_state(bool alternate)
|
||||
}
|
||||
else {
|
||||
ansi_dbg("Unswap from alternate");
|
||||
NOTIFY_LOCK();
|
||||
memcpy(termconf_live.title, state_backup.title, TERM_TITLE_LEN);
|
||||
memcpy(termconf_live.btn, state_backup.btn, sizeof(termconf_live.btn));
|
||||
memcpy(termconf_live.btn_msg, state_backup.btn_msg, sizeof(termconf_live.btn_msg));
|
||||
@@ -421,11 +436,10 @@ screen_swap_state(bool alternate)
|
||||
// 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;
|
||||
NOTIFY_DONE(TOPIC_INITIAL);
|
||||
}
|
||||
|
||||
//endregion
|
||||
@@ -435,19 +449,25 @@ screen_swap_state(bool alternate)
|
||||
void ICACHE_FLASH_ATTR
|
||||
screen_clear_all_tabs(void)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
memset(scr.tab_stops, 0, sizeof(scr.tab_stops));
|
||||
NOTIFY_DONE(TOPIC_INTERNAL);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
screen_set_tab(void)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
scr.tab_stops[cursor.x/32] |= (1<<(cursor.x%32));
|
||||
NOTIFY_DONE(TOPIC_INTERNAL);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
screen_clear_tab(void)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
scr.tab_stops[cursor.x/32] &= ~(1<<(cursor.x%32));
|
||||
NOTIFY_DONE(TOPIC_INTERNAL);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -529,7 +549,7 @@ screen_tab_forward(int count)
|
||||
cursor.x = W - 1;
|
||||
}
|
||||
}
|
||||
NOTIFY_DONE();
|
||||
NOTIFY_DONE(TOPIC_CHANGE_CURSOR);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
@@ -544,7 +564,7 @@ screen_tab_reverse(int count)
|
||||
cursor.x = 0;
|
||||
}
|
||||
}
|
||||
NOTIFY_DONE();
|
||||
NOTIFY_DONE(TOPIC_CHANGE_CURSOR);
|
||||
}
|
||||
|
||||
//endregion
|
||||
@@ -733,7 +753,7 @@ screen_clear(ClearMode mode)
|
||||
clear_range_utf(0, (cursor.y * W) + cursor.x);
|
||||
break;
|
||||
}
|
||||
NOTIFY_DONE();
|
||||
NOTIFY_DONE(mode == CLEAR_ALL ? TOPIC_CHANGE_CONTENT_ALL : TOPIC_CHANGE_CONTENT_PART);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -756,7 +776,7 @@ screen_clear_line(ClearMode mode)
|
||||
clear_range_utf(cursor.y * W, cursor.y * W + cursor.x);
|
||||
break;
|
||||
}
|
||||
NOTIFY_DONE();
|
||||
NOTIFY_DONE(TOPIC_CHANGE_CONTENT_PART);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
@@ -768,7 +788,7 @@ screen_clear_in_line(unsigned int count)
|
||||
} else {
|
||||
clear_range_utf(cursor.y * W + cursor.x, cursor.y * W + cursor.x + count - 1);
|
||||
}
|
||||
NOTIFY_DONE();
|
||||
NOTIFY_DONE(TOPIC_CHANGE_CONTENT_PART);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
@@ -796,7 +816,7 @@ screen_insert_lines(unsigned int lines)
|
||||
copy_row(i, cursor.y);
|
||||
}
|
||||
}
|
||||
NOTIFY_DONE();
|
||||
NOTIFY_DONE(TOPIC_CHANGE_CONTENT_PART);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
@@ -821,7 +841,7 @@ screen_delete_lines(unsigned int lines)
|
||||
clear_range_noutf((movedBlockEnd+1)*W, (BTM+1)*W-1);
|
||||
}
|
||||
|
||||
NOTIFY_DONE();
|
||||
NOTIFY_DONE(TOPIC_CHANGE_CONTENT_PART);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
@@ -844,7 +864,7 @@ screen_insert_characters(unsigned int count)
|
||||
}
|
||||
clear_range_utf(cursor.y * W + cursor.x, cursor.y * W + targetStart - 1);
|
||||
}
|
||||
NOTIFY_DONE();
|
||||
NOTIFY_DONE(TOPIC_CHANGE_CONTENT_PART);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
@@ -870,7 +890,7 @@ screen_delete_characters(unsigned int count)
|
||||
screen_clear_line(CLEAR_FROM_CURSOR);
|
||||
}
|
||||
|
||||
NOTIFY_DONE();
|
||||
NOTIFY_DONE(TOPIC_CHANGE_CONTENT_PART);
|
||||
}
|
||||
//endregion
|
||||
|
||||
@@ -891,7 +911,7 @@ screen_fill_with_E(void)
|
||||
for (unsigned int i = 0; i <= W*H-1; i++) {
|
||||
memcpy(&screen[i], &sample, sizeof(Cell));
|
||||
}
|
||||
NOTIFY_DONE();
|
||||
NOTIFY_DONE(TOPIC_CHANGE_CONTENT_ALL);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -920,14 +940,15 @@ screen_resize(int rows, int cols)
|
||||
W = cols;
|
||||
H = rows;
|
||||
screen_reset_on_resize();
|
||||
NOTIFY_DONE();
|
||||
NOTIFY_DONE(TOPIC_CHANGE_SCREEN_OPTS|TOPIC_CHANGE_CONTENT_ALL|TOPIC_CHANGE_CURSOR);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
screen_set_title(const char *title)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
strncpy(termconf_live.title, title, TERM_TITLE_LEN);
|
||||
screen_notifyChange(CHANGE_LABELS);
|
||||
NOTIFY_DONE(TOPIC_CHANGE_TITLE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -938,8 +959,9 @@ screen_set_title(const char *title)
|
||||
void ICACHE_FLASH_ATTR
|
||||
screen_set_button_text(int num, const char *text)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
strncpy(termconf_live.btn[num-1], text, TERM_BTN_LEN);
|
||||
screen_notifyChange(CHANGE_LABELS);
|
||||
NOTIFY_DONE(TOPIC_CHANGE_BUTTONS);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -970,7 +992,7 @@ screen_scroll_up(unsigned int lines)
|
||||
clear_range_noutf(y * W, (BTM + 1) * W - 1);
|
||||
|
||||
done:
|
||||
NOTIFY_DONE();
|
||||
NOTIFY_DONE(TOPIC_CHANGE_CONTENT_PART);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1000,13 +1022,14 @@ screen_scroll_down(unsigned int lines)
|
||||
|
||||
clear_range_noutf(TOP * W, TOP * W + lines * W - 1);
|
||||
done:
|
||||
NOTIFY_DONE();
|
||||
NOTIFY_DONE(TOPIC_CHANGE_CONTENT_PART);
|
||||
}
|
||||
|
||||
/** Set scrolling region */
|
||||
void ICACHE_FLASH_ATTR
|
||||
screen_set_scrolling_region(int from, int to)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
if (from <= 0 && to <= 0) {
|
||||
scr.vm0 = 0;
|
||||
scr.vm1 = H-1;
|
||||
@@ -1020,6 +1043,7 @@ screen_set_scrolling_region(int from, int to)
|
||||
|
||||
// Always move cursor home (may be translated due to DECOM)
|
||||
screen_cursor_set(0, 0);
|
||||
NOTIFY_DONE(TOPIC_INTERNAL);
|
||||
}
|
||||
|
||||
//endregion
|
||||
@@ -1033,7 +1057,7 @@ screen_cursor_shape(enum CursorShape shape)
|
||||
NOTIFY_LOCK();
|
||||
if (shape == CURSOR_DEFAULT) shape = termconf->cursor_shape;
|
||||
termconf_live.cursor_shape = shape;
|
||||
NOTIFY_DONE();
|
||||
NOTIFY_DONE(TOPIC_CHANGE_SCREEN_OPTS);
|
||||
}
|
||||
|
||||
/** set cursor blink option */
|
||||
@@ -1050,7 +1074,7 @@ screen_cursor_blink(bool blink)
|
||||
if (termconf_live.cursor_shape == CURSOR_BAR_BL) termconf_live.cursor_shape = CURSOR_BAR;
|
||||
if (termconf_live.cursor_shape == CURSOR_UNDERLINE_BL) termconf_live.cursor_shape = CURSOR_UNDERLINE;
|
||||
}
|
||||
NOTIFY_DONE();
|
||||
NOTIFY_DONE(TOPIC_CHANGE_SCREEN_OPTS);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1062,7 +1086,7 @@ screen_cursor_set(int y, int x)
|
||||
NOTIFY_LOCK();
|
||||
screen_cursor_set_x(x);
|
||||
screen_cursor_set_y(y);
|
||||
NOTIFY_DONE();
|
||||
NOTIFY_DONE(TOPIC_CHANGE_CURSOR);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1093,7 +1117,7 @@ screen_cursor_set_x(int x)
|
||||
// hanging happens when the cursor is virtually at col=81, which
|
||||
// cannot be set using the cursor-set commands.
|
||||
cursor.hanging = false;
|
||||
NOTIFY_DONE();
|
||||
NOTIFY_DONE(TOPIC_CHANGE_CURSOR);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1112,7 +1136,7 @@ screen_cursor_set_y(int y)
|
||||
if (y < 0) y = 0;
|
||||
}
|
||||
cursor.y = y;
|
||||
NOTIFY_DONE();
|
||||
NOTIFY_DONE(TOPIC_CHANGE_CURSOR);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1195,7 +1219,7 @@ screen_cursor_move(int dy, int dx, bool scroll)
|
||||
}
|
||||
}
|
||||
|
||||
NOTIFY_DONE();
|
||||
NOTIFY_DONE(TOPIC_CHANGE_CURSOR | (scroll*TOPIC_CHANGE_CONTENT_PART));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1232,21 +1256,23 @@ screen_cursor_restore(bool withAttrs)
|
||||
}
|
||||
}
|
||||
|
||||
NOTIFY_DONE();
|
||||
NOTIFY_DONE(TOPIC_CHANGE_CURSOR);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
screen_back_index(int count)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
ScreenNotifyTopics topics = TOPIC_CHANGE_CURSOR;
|
||||
int new_x = cursor.x - count;
|
||||
if (new_x >= 0) {
|
||||
cursor.x = new_x;
|
||||
} else {
|
||||
cursor.x = 0;
|
||||
screen_insert_characters(-new_x);
|
||||
topics |= TOPIC_CHANGE_CONTENT_PART;
|
||||
}
|
||||
NOTIFY_DONE();
|
||||
NOTIFY_DONE(topics);
|
||||
}
|
||||
|
||||
//endregion
|
||||
@@ -1261,7 +1287,7 @@ screen_set_cursor_visible(bool visible)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
scr.cursor_visible = visible;
|
||||
NOTIFY_DONE();
|
||||
NOTIFY_DONE(TOPIC_CHANGE_SCREEN_OPTS);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1270,7 +1296,9 @@ screen_set_cursor_visible(bool visible)
|
||||
void ICACHE_FLASH_ATTR
|
||||
screen_wrap_enable(bool enable)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
cursor.auto_wrap = enable;
|
||||
NOTIFY_DONE(TOPIC_INTERNAL);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1279,7 +1307,9 @@ screen_wrap_enable(bool enable)
|
||||
void ICACHE_FLASH_ATTR
|
||||
screen_reverse_wrap_enable(bool enable)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
cursor.reverse_wrap = enable;
|
||||
NOTIFY_DONE(TOPIC_INTERNAL);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1288,8 +1318,10 @@ screen_reverse_wrap_enable(bool enable)
|
||||
void ICACHE_FLASH_ATTR
|
||||
screen_set_fg(Color color)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
cursor.fg = color;
|
||||
cursor.attrs |= ATTR_FG;
|
||||
NOTIFY_DONE(TOPIC_INTERNAL);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1298,8 +1330,10 @@ screen_set_fg(Color color)
|
||||
void ICACHE_FLASH_ATTR
|
||||
screen_set_bg(Color color)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
cursor.bg = color;
|
||||
cursor.attrs |= ATTR_BG;
|
||||
NOTIFY_DONE(TOPIC_INTERNAL);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1308,8 +1342,10 @@ screen_set_bg(Color color)
|
||||
void ICACHE_FLASH_ATTR
|
||||
screen_set_default_fg(void)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
cursor.fg = 0;
|
||||
cursor.attrs &= ~ATTR_FG;
|
||||
NOTIFY_DONE(TOPIC_INTERNAL);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1318,45 +1354,57 @@ screen_set_default_fg(void)
|
||||
void ICACHE_FLASH_ATTR
|
||||
screen_set_default_bg(void)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
cursor.bg = 0;
|
||||
cursor.attrs &= ~ATTR_BG;
|
||||
NOTIFY_DONE(TOPIC_INTERNAL);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
screen_set_sgr(CellAttrs attrs, bool ena)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
if (ena) {
|
||||
cursor.attrs |= attrs;
|
||||
}
|
||||
else {
|
||||
cursor.attrs &= ~attrs;
|
||||
}
|
||||
NOTIFY_DONE(TOPIC_INTERNAL);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
screen_set_sgr_conceal(bool ena)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
cursor.conceal = ena;
|
||||
NOTIFY_DONE(TOPIC_INTERNAL);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
screen_set_charset_n(int Gx)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
if (Gx < 0 || Gx > 1) return; // bad n
|
||||
cursor.charsetN = Gx;
|
||||
NOTIFY_DONE(TOPIC_INTERNAL);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
screen_set_charset(int Gx, char charset)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
if (Gx == 0) cursor.charset0 = charset;
|
||||
else if (Gx == 1) cursor.charset1 = charset;
|
||||
NOTIFY_DONE(TOPIC_INTERNAL);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
screen_set_insert_mode(bool insert)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
scr.insert_mode = insert;
|
||||
NOTIFY_DONE(TOPIC_INTERNAL);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
@@ -1364,7 +1412,7 @@ screen_set_numpad_alt_mode(bool alt_mode)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
scr.numpad_alt_mode = alt_mode;
|
||||
NOTIFY_DONE();
|
||||
NOTIFY_DONE(TOPIC_CHANGE_SCREEN_OPTS);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
@@ -1372,7 +1420,7 @@ screen_set_cursors_alt_mode(bool alt_mode)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
scr.cursors_alt_mode = alt_mode;
|
||||
NOTIFY_DONE();
|
||||
NOTIFY_DONE(TOPIC_CHANGE_SCREEN_OPTS);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
@@ -1380,7 +1428,7 @@ screen_set_reverse_video(bool reverse)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
scr.reverse_video = reverse;
|
||||
NOTIFY_DONE();
|
||||
NOTIFY_DONE(TOPIC_CHANGE_SCREEN_OPTS);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
@@ -1388,7 +1436,7 @@ screen_set_bracketed_paste(bool ena)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
scr.bracketed_paste = ena;
|
||||
NOTIFY_DONE();
|
||||
NOTIFY_DONE(TOPIC_CHANGE_SCREEN_OPTS);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
@@ -1396,29 +1444,34 @@ screen_set_newline_mode(bool nlm)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
termconf_live.crlf_mode = nlm;
|
||||
NOTIFY_DONE();
|
||||
NOTIFY_DONE(TOPIC_CHANGE_SCREEN_OPTS);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
screen_set_origin_mode(bool region_origin)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
cursor.origin_mode = region_origin;
|
||||
screen_cursor_set(0, 0);
|
||||
NOTIFY_DONE(TOPIC_INTERNAL);
|
||||
}
|
||||
|
||||
static void ICACHE_FLASH_ATTR
|
||||
do_save_private_opt(int n, bool save)
|
||||
{
|
||||
ScreenNotifyTopics topics = TOPIC_INTERNAL;
|
||||
if (!save) NOTIFY_LOCK();
|
||||
#define SAVE_RESTORE(sf, of) do { if (save) sf=(of); else of=(sf); } while(0)
|
||||
switch (n) {
|
||||
case 1:
|
||||
SAVE_RESTORE(opt_backup.cursors_alt_mode, scr.cursors_alt_mode);
|
||||
topics |= TOPIC_CHANGE_SCREEN_OPTS;
|
||||
break;
|
||||
case 5:
|
||||
SAVE_RESTORE(opt_backup.reverse_video, scr.reverse_video);
|
||||
break;
|
||||
case 6:
|
||||
SAVE_RESTORE(opt_backup.origin_mode, cursor.origin_mode);
|
||||
SAVE_RESTORE(opt_backup.origin_mode, cursor.origin_mode); // XXX maybe we should move cursor to 1,1 if it's restored to True
|
||||
break;
|
||||
case 7:
|
||||
SAVE_RESTORE(opt_backup.auto_wrap, cursor.auto_wrap);
|
||||
@@ -1429,14 +1482,17 @@ do_save_private_opt(int n, bool save)
|
||||
case 1002:
|
||||
case 1003:
|
||||
SAVE_RESTORE(opt_backup.mouse_tracking, mouse_tracking.mode);
|
||||
topics |= TOPIC_CHANGE_SCREEN_OPTS;
|
||||
break;
|
||||
case 1004:
|
||||
SAVE_RESTORE(opt_backup.focus_tracking, mouse_tracking.focus_tracking);
|
||||
topics |= TOPIC_CHANGE_SCREEN_OPTS;
|
||||
break;
|
||||
case 1005:
|
||||
case 1006:
|
||||
case 1015:
|
||||
SAVE_RESTORE(opt_backup.mouse_encoding, mouse_tracking.encoding);
|
||||
topics |= TOPIC_CHANGE_SCREEN_OPTS;
|
||||
break;
|
||||
case 12: // cursor blink
|
||||
if (save) {
|
||||
@@ -1444,9 +1500,11 @@ do_save_private_opt(int n, bool save)
|
||||
} else {
|
||||
screen_cursor_blink(opt_backup.cursor_blink);
|
||||
}
|
||||
topics |= TOPIC_CHANGE_SCREEN_OPTS;
|
||||
break;
|
||||
case 25:
|
||||
SAVE_RESTORE(opt_backup.cursor_visible, scr.cursor_visible);
|
||||
topics |= TOPIC_CHANGE_SCREEN_OPTS;
|
||||
break;
|
||||
case 45:
|
||||
SAVE_RESTORE(opt_backup.reverse_wrap, cursor.reverse_wrap);
|
||||
@@ -1456,19 +1514,24 @@ do_save_private_opt(int n, bool save)
|
||||
break;
|
||||
case 800:
|
||||
SAVE_RESTORE(opt_backup.show_buttons, termconf_live.show_buttons);
|
||||
topics |= TOPIC_CHANGE_SCREEN_OPTS;
|
||||
break;
|
||||
case 801:
|
||||
SAVE_RESTORE(opt_backup.show_config_links, termconf_live.show_config_links);
|
||||
topics |= TOPIC_CHANGE_SCREEN_OPTS;
|
||||
break;
|
||||
default:
|
||||
ansi_warn("Cannot store ?%d", n);
|
||||
}
|
||||
if (!save) NOTIFY_DONE(topics);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
screen_save_private_opt(int n)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
do_save_private_opt(n, true);
|
||||
NOTIFY_DONE(TOPIC_INTERNAL);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
@@ -1476,7 +1539,7 @@ screen_restore_private_opt(int n)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
do_save_private_opt(n, false);
|
||||
NOTIFY_DONE();
|
||||
NOTIFY_DONE(TOPIC_INTERNAL);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
@@ -1599,7 +1662,7 @@ screen_putchar(const char *ch)
|
||||
strncpy(scr.last_char, result, 4);
|
||||
|
||||
done:
|
||||
NOTIFY_DONE();
|
||||
NOTIFY_DONE(TOPIC_WRITE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1621,7 +1684,7 @@ screen_repeat_last_character(int count)
|
||||
putchar_graphic(scr.last_char);
|
||||
count--;
|
||||
}
|
||||
NOTIFY_DONE();
|
||||
NOTIFY_DONE(TOPIC_WRITE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1674,29 +1737,12 @@ struct ScreenSerializeState {
|
||||
UnicodeCacheRef lastSymbol;
|
||||
char lastChar[4];
|
||||
u8 lastCharLen;
|
||||
int index;
|
||||
int index; // index in the screen buffer
|
||||
ScreenNotifyTopics topics;
|
||||
ScreenNotifyTopics last_topic;
|
||||
ScreenNotifyTopics current_topic;
|
||||
};
|
||||
|
||||
/**
|
||||
* buffer should be at least 64+5*10+6 long (title + buttons + 6), ie. 120
|
||||
* @param buffer
|
||||
* @param buf_len
|
||||
*/
|
||||
void ICACHE_FLASH_ATTR
|
||||
screenSerializeLabelsToBuffer(char *buffer, size_t buf_len)
|
||||
{
|
||||
(void)buf_len;
|
||||
// let's just assume it's long enough - called with the huge websocket buffer
|
||||
sprintf(buffer, "T%s\x01%s\x01%s\x01%s\x01%s\x01%s", // use 0x01 as separator
|
||||
termconf_live.title,
|
||||
termconf_live.btn[0],
|
||||
termconf_live.btn[1],
|
||||
termconf_live.btn[2],
|
||||
termconf_live.btn[3],
|
||||
termconf_live.btn[4]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the screen to a data buffer. May need multiple calls if the buffer is insufficient in size.
|
||||
*
|
||||
@@ -1705,12 +1751,14 @@ screenSerializeLabelsToBuffer(char *buffer, size_t buf_len)
|
||||
*
|
||||
* @param buffer - buffer array of limited size. If NULL, indicates this is the last call.
|
||||
* @param buf_len - buffer array size
|
||||
* @param topics - what should be included in the message (ignored after the first call)
|
||||
* @param data - opaque pointer to internal data structure for storing state between repeated calls
|
||||
* if NULL, indicates this is the first call.
|
||||
* @return HTTPD_CGI_DONE or HTTPD_CGI_MORE. If more, repeat with the same DATA.
|
||||
* if NULL, indicates this is the first call; the structure will be allocated.
|
||||
*
|
||||
* @return HTTPD_CGI_DONE or HTTPD_CGI_MORE. If more, repeat with the same `data` pointer.
|
||||
*/
|
||||
httpd_cgi_state ICACHE_FLASH_ATTR
|
||||
screenSerializeToBuffer(char *buffer, size_t buf_len, void **data)
|
||||
screenSerializeToBuffer(char *buffer, size_t buf_len, ScreenNotifyTopics topics, void **data)
|
||||
{
|
||||
struct ScreenSerializeState *ss = *data;
|
||||
|
||||
@@ -1719,11 +1767,11 @@ screenSerializeToBuffer(char *buffer, size_t buf_len, void **data)
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
|
||||
Cell *cell, *cell0;
|
||||
Cell *cell, *cell0; // temporary cell pointers for finding repetitions
|
||||
|
||||
u8 nbytes;
|
||||
size_t remain = buf_len;
|
||||
char *bb = buffer;
|
||||
u8 nbytes; // temporary variable for utf writing utilities
|
||||
size_t remain = buf_len; // remaining space in the output buffer
|
||||
char *bb = buffer; // write pointer
|
||||
|
||||
#define bufput_c(c) do { \
|
||||
*bb = (char)(c); \
|
||||
@@ -1742,26 +1790,78 @@ screenSerializeToBuffer(char *buffer, size_t buf_len, void **data)
|
||||
bufput_utf8((num)); \
|
||||
} while(0)
|
||||
|
||||
// tags for screen serialization
|
||||
#define SEQ_TAG_REPEAT '\x02'
|
||||
#define SEQ_TAG_COLORS '\x03'
|
||||
#define SEQ_TAG_ATTRS '\x04'
|
||||
#define SEQ_TAG_FG '\x05'
|
||||
#define SEQ_TAG_BG '\x06'
|
||||
|
||||
#define TOPICMARK_SCREEN_OPTS 'O'
|
||||
#define TOPICMARK_TITLE 'T'
|
||||
#define TOPICMARK_BUTTONS 'B'
|
||||
#define TOPICMARK_DEBUG 'D'
|
||||
#define TOPICMARK_BELL '!'
|
||||
#define TOPICMARK_CURSOR 'C'
|
||||
#define TOPICMARK_SCREEN_ALL 'S'
|
||||
#define TOPICMARK_SCREEN_PART 's'
|
||||
|
||||
if (ss == NULL) {
|
||||
// START!
|
||||
|
||||
*data = ss = malloc(sizeof(struct ScreenSerializeState));
|
||||
|
||||
if (topics == 0 || termconf_live.debugbar) {
|
||||
topics |= TOPIC_INTERNAL;
|
||||
}
|
||||
|
||||
ss->index = 0;
|
||||
ss->lastBg = 0xFF;
|
||||
ss->lastFg = 0xFF;
|
||||
ss->lastAttrs = 0xFFFF;
|
||||
ss->lastCharLen = 0;
|
||||
ss->lastSymbol = 0;
|
||||
|
||||
ss->topics = topics;
|
||||
ss->last_topic = 0; // to be filled
|
||||
ss->current_topic = 0; // to be filled
|
||||
strncpy(ss->lastChar, " ", 4);
|
||||
|
||||
bufput_c('S');
|
||||
// H W X Y Attribs
|
||||
dbg("NOTIFY -> %02X", topics);
|
||||
|
||||
bufput_c('U'); // - stands for "update"
|
||||
|
||||
bufput_utf8(topics & ~TOPIC_INTERNAL);
|
||||
}
|
||||
|
||||
int begun_topic = 0;
|
||||
int prev_topic = 0;
|
||||
|
||||
#define BEGIN_TOPIC(topic, size) \
|
||||
if (ss->last_topic == prev_topic) { \
|
||||
begun_topic = (topic); \
|
||||
if (ss->topics & (topic)) { \
|
||||
if (remain < (size)) return HTTPD_CGI_MORE;
|
||||
|
||||
#define END_TOPIC \
|
||||
} \
|
||||
ss->last_topic = begun_topic; \
|
||||
ss->current_topic = 0; \
|
||||
} \
|
||||
prev_topic = begun_topic;
|
||||
|
||||
if (ss->current_topic == 0) {
|
||||
BEGIN_TOPIC(TOPIC_CHANGE_SCREEN_OPTS, 32+1)
|
||||
bufput_c(TOPICMARK_SCREEN_OPTS);
|
||||
|
||||
bufput_utf8(H);
|
||||
bufput_utf8(W);
|
||||
bufput_utf8(cursor.y);
|
||||
bufput_utf8(cursor.x);
|
||||
// 3B has 18 free bits
|
||||
bufput_utf8(termconf_live.theme);
|
||||
|
||||
bufput_utf8(termconf_live.default_fg & 0x000FFF);
|
||||
bufput_utf8((termconf_live.default_fg & 0xFFF000) >> 12);
|
||||
|
||||
bufput_utf8(termconf_live.default_bg & 0x000FFF);
|
||||
bufput_utf8((termconf_live.default_bg & 0xFFF000) >> 12);
|
||||
|
||||
bufput_utf8(
|
||||
(scr.cursor_visible << 0) |
|
||||
(cursor.hanging << 1) |
|
||||
(termconf_live.debugbar << 1) | // debugbar - this was previously "hanging"
|
||||
(scr.cursors_alt_mode << 2) |
|
||||
(scr.numpad_alt_mode << 3) |
|
||||
(termconf_live.fn_alt_mode << 4) |
|
||||
@@ -1774,15 +1874,96 @@ screenSerializeToBuffer(char *buffer, size_t buf_len, void **data)
|
||||
(scr.bracketed_paste << 13) |
|
||||
(scr.reverse_video << 14)
|
||||
);
|
||||
END_TOPIC
|
||||
|
||||
BEGIN_TOPIC(TOPIC_CHANGE_TITLE, TERM_TITLE_LEN+4+1)
|
||||
bufput_c(TOPICMARK_TITLE);
|
||||
|
||||
int len = (int) strlen(termconf_live.title);
|
||||
bufput_utf8(len);
|
||||
memcpy(bb, termconf_live.title, len);
|
||||
bb += len;
|
||||
remain -= len;
|
||||
END_TOPIC
|
||||
|
||||
BEGIN_TOPIC(TOPIC_CHANGE_BUTTONS, (TERM_BTN_LEN+4)*TERM_BTN_COUNT+1+4)
|
||||
bufput_c(TOPICMARK_BUTTONS);
|
||||
|
||||
bufput_utf8(TERM_BTN_COUNT);
|
||||
|
||||
for (int i = 0; i < TERM_BTN_COUNT; i++) {
|
||||
int len = (int) strlen(termconf_live.btn[i]);
|
||||
bufput_utf8(len);
|
||||
memcpy(bb, termconf_live.btn[i], len);
|
||||
bb += len;
|
||||
remain -= len;
|
||||
}
|
||||
END_TOPIC
|
||||
|
||||
BEGIN_TOPIC(TOPIC_INTERNAL, 45)
|
||||
bufput_c(TOPICMARK_DEBUG);
|
||||
// General flags
|
||||
bufput_utf8(
|
||||
(scr.insert_mode << 0) |
|
||||
(cursor.conceal << 1) |
|
||||
(cursor.auto_wrap << 2) |
|
||||
(cursor.reverse_wrap << 3) |
|
||||
(cursor.origin_mode << 4) |
|
||||
(cursor_saved << 5) |
|
||||
(state_backup.alternate_active << 6)
|
||||
);
|
||||
bufput_utf8(cursor.attrs);
|
||||
bufput_utf8(scr.vm0);
|
||||
bufput_utf8(scr.vm1);
|
||||
bufput_utf8(cursor.charsetN);
|
||||
bufput_c(cursor.charset0);
|
||||
bufput_c(cursor.charset1);
|
||||
bufput_utf8(system_get_free_heap_size());
|
||||
bufput_utf8(term_active_clients);
|
||||
END_TOPIC
|
||||
|
||||
BEGIN_TOPIC(TOPIC_BELL, 1)
|
||||
bufput_c(TOPICMARK_BELL);
|
||||
END_TOPIC
|
||||
|
||||
BEGIN_TOPIC(TOPIC_CHANGE_CURSOR, 13)
|
||||
bufput_c(TOPICMARK_CURSOR);
|
||||
bufput_utf8(cursor.y);
|
||||
bufput_utf8(cursor.x);
|
||||
bufput_utf8(
|
||||
(cursor.hanging << 0)
|
||||
);
|
||||
END_TOPIC
|
||||
|
||||
if (ss->last_topic == TOPIC_CHANGE_CURSOR) {
|
||||
// now we can begin any of the two screen sequences
|
||||
|
||||
if (ss->topics & TOPIC_CHANGE_CONTENT_ALL) {
|
||||
ss->current_topic = TOPIC_CHANGE_CONTENT_ALL;
|
||||
}
|
||||
if (ss->topics & TOPIC_CHANGE_CONTENT_PART) {
|
||||
ss->current_topic = TOPIC_CHANGE_CONTENT_PART;
|
||||
}
|
||||
|
||||
#define SEQ_TAG_REPEAT '\x02'
|
||||
#define SEQ_TAG_COLORS '\x03'
|
||||
#define SEQ_TAG_ATTRS '\x04'
|
||||
#define SEQ_TAG_FG '\x05'
|
||||
#define SEQ_TAG_BG '\x06'
|
||||
if (ss->current_topic == 0) {
|
||||
// no screen mode - wrap it up
|
||||
goto ser_done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// screen contents - TODO implement partial update
|
||||
int i = ss->index;
|
||||
if (i == 0) {
|
||||
bufput_c(TOPICMARK_SCREEN_ALL); // desired update mode is in `ss->current_topic`
|
||||
|
||||
ss->index = 0;
|
||||
ss->lastBg = 0xFF;
|
||||
ss->lastFg = 0xFF;
|
||||
ss->lastAttrs = 0xFFFF;
|
||||
ss->lastCharLen = 0;
|
||||
ss->lastSymbol = 0;
|
||||
}
|
||||
while(i < W*H && remain > 12) {
|
||||
cell = cell0 = &screen[i];
|
||||
|
||||
@@ -1848,7 +2029,17 @@ screenSerializeToBuffer(char *buffer, size_t buf_len, void **data)
|
||||
}
|
||||
|
||||
ss->index = i;
|
||||
if (i >= W*H-1) goto ser_done;
|
||||
|
||||
// MORE TO WRITE...
|
||||
bufput_c('\0'); // terminate the string
|
||||
return HTTPD_CGI_MORE;
|
||||
|
||||
ser_done:
|
||||
bufput_c('\0'); // terminate the string
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
//endregion
|
||||
|
||||
#if 0
|
||||
printf("MSG: ");
|
||||
@@ -1857,11 +2048,3 @@ screenSerializeToBuffer(char *buffer, size_t buf_len, void **data)
|
||||
}
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
if (i < W*H-1) {
|
||||
return HTTPD_CGI_MORE;
|
||||
}
|
||||
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
//endregion
|
||||
|
||||
+30
-15
@@ -34,11 +34,6 @@
|
||||
*
|
||||
*/
|
||||
|
||||
// Size designed for the terminal config structure
|
||||
// Must be constant to avoid corrupting user config after upgrade
|
||||
#define TERMCONF_SIZE 300
|
||||
#define TERMCONF_VERSION 0
|
||||
|
||||
#define TERM_BTN_LEN 10
|
||||
#define TERM_BTN_MSG_LEN 10
|
||||
#define TERM_TITLE_LEN 64
|
||||
@@ -70,10 +65,16 @@ enum CursorShape {
|
||||
#define SCR_DEF_CURSOR_SHAPE CURSOR_BLOCK_BL
|
||||
#define SCR_DEF_CRLF 0 // enter sends CRLF
|
||||
#define SCR_DEF_ALLFN 0 // capture F5 etc
|
||||
#define SCR_DEF_DEBUGBAR 0
|
||||
|
||||
// --- Persistent Settings ---
|
||||
#define CURSOR_BLINKS(shape) ((shape)==CURSOR_BLOCK_BL||(shape)==CURSOR_UNDERLINE_BL||(shape)==CURSOR_BAR_BL)
|
||||
|
||||
// Size designed for the terminal config structure
|
||||
// Must be constant to avoid corrupting user config after upgrade
|
||||
#define TERMCONF_SIZE 300
|
||||
#define TERMCONF_VERSION 1
|
||||
|
||||
typedef struct {
|
||||
u32 width;
|
||||
u32 height;
|
||||
@@ -94,6 +95,7 @@ typedef struct {
|
||||
enum CursorShape cursor_shape;
|
||||
bool crlf_mode;
|
||||
bool want_all_fn;
|
||||
bool debugbar;
|
||||
} TerminalConfigBundle;
|
||||
|
||||
// Live config
|
||||
@@ -152,9 +154,29 @@ typedef enum {
|
||||
CS_1_DOS_437 = '1',
|
||||
} CHARSET;
|
||||
|
||||
httpd_cgi_state screenSerializeToBuffer(char *buffer, size_t buf_len, void **data);
|
||||
enum ScreenSerializeTopic {
|
||||
TOPIC_CHANGE_SCREEN_OPTS = (1<<0),
|
||||
TOPIC_CHANGE_TITLE = (1<<1),
|
||||
TOPIC_CHANGE_BUTTONS = (1<<2),
|
||||
TOPIC_BELL = (1<<3), // beep
|
||||
TOPIC_CHANGE_CURSOR = (1<<4),
|
||||
TOPIC_CHANGE_CONTENT_ALL = (1<<5),
|
||||
TOPIC_CHANGE_CONTENT_PART = (1<<6),
|
||||
TOPIC_INTERNAL = (1<<7), // debugging internal state
|
||||
// combos
|
||||
TOPIC_INITIAL =
|
||||
TOPIC_CHANGE_SCREEN_OPTS |
|
||||
TOPIC_CHANGE_CONTENT_ALL |
|
||||
TOPIC_CHANGE_CURSOR |
|
||||
TOPIC_CHANGE_TITLE |
|
||||
TOPIC_CHANGE_BUTTONS,
|
||||
|
||||
void screenSerializeLabelsToBuffer(char *buffer, size_t buf_len);
|
||||
TOPIC_WRITE = TOPIC_CHANGE_CURSOR | TOPIC_CHANGE_CONTENT_PART,
|
||||
};
|
||||
|
||||
typedef u16 ScreenNotifyTopics;
|
||||
|
||||
httpd_cgi_state screenSerializeToBuffer(char *buffer, size_t buf_len, ScreenNotifyTopics topics, void **data);
|
||||
|
||||
// --- Clearing ---
|
||||
|
||||
@@ -323,18 +345,11 @@ void screen_repeat_last_character(int count);
|
||||
/** Report current SGR as num;num;... for DAC query */
|
||||
void screen_report_sgr(char *buffer);
|
||||
|
||||
// --- Notify ---
|
||||
|
||||
typedef enum {
|
||||
CHANGE_CONTENT = 0,
|
||||
CHANGE_LABELS = 1,
|
||||
} ScreenNotifyChangeTopic;
|
||||
|
||||
/**
|
||||
* Called when the screen content or settings change
|
||||
* and the front-end should redraw / update.
|
||||
* @param topic - what kind of change this is (chooses what message to send)
|
||||
*/
|
||||
extern void screen_notifyChange(ScreenNotifyChangeTopic topic);
|
||||
extern void screen_notifyChange(ScreenNotifyTopics topics);
|
||||
|
||||
#endif // SCREEN_H
|
||||
|
||||
Reference in New Issue
Block a user