-#include <windows.h>
-
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
static unsigned long *dispcurs; /* location of cursor on real screen */
static unsigned long curstype; /* type of cursor on real screen */
-#define VBELL_TIMEOUT 100 /* millisecond len of visual bell */
+#define VBELL_TIMEOUT (TICKSPERSEC/10) /* visual bell lasts 1/10 sec */
struct beeptime {
struct beeptime *next;
static int utf_state; /* Is there a pending UTF-8 character */
static int utf_char; /* and what is it so far. */
static int utf_size; /* The size of the UTF character. */
+static int printing, only_printing; /* Are we doing ANSI printing? */
+static int print_state; /* state of print-end-sequence scan */
+static bufchain printer_buf; /* buffered data for printer */
+static printer_job *print_job;
static int xterm_mouse; /* send mouse messages to app */
*/
static void do_paint(Context, int);
static void erase_lots(int, int, int);
-static void swap_screen(int);
+static void swap_screen(int, int, int);
static void update_sbar(void);
static void deselect(void);
+static void term_print_finish(void);
/*
* Resize a line to make it `cols' columns wide.
blink_is_real = cfg.blinktext;
erase_char = ERASE_CHAR;
alt_which = 0;
+ term_print_finish();
{
int i;
for (i = 0; i < 256; i++)
wordness[i] = cfg.wordness[i];
}
if (screen) {
- swap_screen(1);
+ swap_screen(1, FALSE, FALSE);
erase_lots(FALSE, TRUE, TRUE);
- swap_screen(0);
+ swap_screen(0, FALSE, FALSE);
erase_lots(FALSE, TRUE, TRUE);
}
}
ctx = get_ctx();
if (ctx) {
int need_sbar_update = seen_disp_event;
- if ((seen_key_event && (cfg.scroll_on_key)) ||
- (seen_disp_event && (cfg.scroll_on_disp))) {
+ if (seen_disp_event && cfg.scroll_on_disp) {
disptop = 0; /* return to main screen */
- seen_disp_event = seen_key_event = 0;
+ seen_disp_event = 0;
need_sbar_update = TRUE;
}
if (need_sbar_update)
}
/*
+ * Called from front end when a keypress occurs, to trigger
+ * anything magical that needs to happen in that situation.
+ */
+void term_seen_key_event(void)
+{
+ /*
+ * On any keypress, clear the bell overload mechanism
+ * completely, on the grounds that large numbers of
+ * beeps coming from deliberate key action are likely
+ * to be intended (e.g. beeps from filename completion
+ * blocking repeatedly).
+ */
+ beep_overloaded = FALSE;
+ while (beephead) {
+ struct beeptime *tmp = beephead;
+ beephead = tmp->next;
+ sfree(tmp);
+ }
+ beeptail = NULL;
+ nbeeps = 0;
+
+ /*
+ * Reset the scrollback on keypress, if we're doing that.
+ */
+ if (cfg.scroll_on_key) {
+ disptop = 0; /* return to main screen */
+ seen_disp_event = 1;
+ }
+}
+
+/*
* Same as power_on(), but an external function.
*/
void term_pwron(void)
/*
* When the user reconfigures us, we need to check the forbidden-
- * alternate-screen config option.
+ * alternate-screen config option, disable raw mouse mode if the
+ * user has disabled mouse reporting, and abandon a print job if
+ * the user has disabled printing.
*/
void term_reconfig(void)
{
if (cfg.no_alt_screen)
- swap_screen(0);
+ swap_screen(0, FALSE, FALSE);
+ if (cfg.no_mouse_rep) {
+ xterm_mouse = 0;
+ set_raw_mouse_mode(0);
+ }
if (cfg.no_remote_charset) {
cset_attr[0] = cset_attr[1] = ATTR_ASCII;
sco_acs = alt_sco_acs = 0;
utf = 0;
}
+ if (!*cfg.printer) {
+ term_print_finish();
+ }
}
/*
return; /* nothing to do */
deselect();
- swap_screen(0);
+ swap_screen(0, FALSE, FALSE);
alt_t = marg_t = 0;
alt_b = marg_b = newrows - 1;
savelines = newsavelines;
fix_cpos;
- swap_screen(save_alt_which);
+ swap_screen(save_alt_which, FALSE, FALSE);
update_sbar();
term_update();
}
/*
- * Swap screens.
+ * Swap screens. If `reset' is TRUE and we have been asked to
+ * switch to the alternate screen, we must bring most of its
+ * configuration from the main screen and erase the contents of the
+ * alternate screen completely. (This is even true if we're already
+ * on it! Blame xterm.)
*/
-static void swap_screen(int which)
+static void swap_screen(int which, int reset, int keep_cur_pos)
{
int t;
tree234 *ttr;
- if (which == alt_which)
- return;
+ if (!which)
+ reset = FALSE; /* do no weird resetting if which==0 */
+
+ if (which != alt_which) {
+ alt_which = which;
+
+ ttr = alt_screen;
+ alt_screen = screen;
+ screen = ttr;
+ t = curs.x;
+ if (!reset && !keep_cur_pos)
+ curs.x = alt_x;
+ alt_x = t;
+ t = curs.y;
+ if (!reset && !keep_cur_pos)
+ curs.y = alt_y;
+ alt_y = t;
+ t = marg_t;
+ if (!reset) marg_t = alt_t;
+ alt_t = t;
+ t = marg_b;
+ if (!reset) marg_b = alt_b;
+ alt_b = t;
+ t = dec_om;
+ if (!reset) dec_om = alt_om;
+ alt_om = t;
+ t = wrap;
+ if (!reset) wrap = alt_wrap;
+ alt_wrap = t;
+ t = wrapnext;
+ if (!reset) wrapnext = alt_wnext;
+ alt_wnext = t;
+ t = insert;
+ if (!reset) insert = alt_ins;
+ alt_ins = t;
+ t = cset;
+ if (!reset) cset = alt_cset;
+ alt_cset = t;
+ t = utf;
+ if (!reset) utf = alt_utf;
+ alt_utf = t;
+ t = sco_acs;
+ if (!reset) sco_acs = alt_sco_acs;
+ alt_sco_acs = t;
+ }
- alt_which = which;
-
- ttr = alt_screen;
- alt_screen = screen;
- screen = ttr;
- t = curs.x;
- curs.x = alt_x;
- alt_x = t;
- t = curs.y;
- curs.y = alt_y;
- alt_y = t;
- t = marg_t;
- marg_t = alt_t;
- alt_t = t;
- t = marg_b;
- marg_b = alt_b;
- alt_b = t;
- t = dec_om;
- dec_om = alt_om;
- alt_om = t;
- t = wrap;
- wrap = alt_wrap;
- alt_wrap = t;
- t = wrapnext;
- wrapnext = alt_wnext;
- alt_wnext = t;
- t = insert;
- insert = alt_ins;
- alt_ins = t;
- t = cset;
- cset = alt_cset;
- alt_cset = t;
- t = utf;
- utf = alt_utf;
- alt_utf = t;
- t = sco_acs;
- sco_acs = alt_sco_acs;
- alt_sco_acs = t;
+ if (reset && screen) {
+ /*
+ * Yes, this _is_ supposed to honour background-colour-erase.
+ */
+ erase_lots(FALSE, TRUE, TRUE);
+ }
- fix_cpos;
+ /*
+ * This might not be possible if we're called during
+ * initialisation.
+ */
+ if (screen)
+ fix_cpos;
}
/*
* effective visual bell, so that ESC[?5hESC[?5l will
* always be an actually _visible_ visual bell.
*/
- ticks = GetTickCount();
+ ticks = GETTICKCOUNT();
/* turn off a previous vbell to avoid inconsistencies */
if (ticks - vbell_startpoint >= VBELL_TIMEOUT)
in_vbell = FALSE;
case 47: /* alternate screen */
compatibility(OTHER);
deselect();
- swap_screen(cfg.no_alt_screen ? 0 : state);
+ swap_screen(cfg.no_alt_screen ? 0 : state, FALSE, FALSE);
disptop = 0;
break;
case 1000: /* xterm mouse 1 */
xterm_mouse = state ? 2 : 0;
set_raw_mouse_mode(state);
break;
+ case 1047: /* alternate screen */
+ compatibility(OTHER);
+ deselect();
+ swap_screen(cfg.no_alt_screen ? 0 : state, TRUE, TRUE);
+ disptop = 0;
+ break;
+ case 1048: /* save/restore cursor */
+ save_cursor(state);
+ if (!state) seen_disp_event = TRUE;
+ break;
+ case 1049: /* cursor & alternate screen */
+ if (state)
+ save_cursor(state);
+ if (!state) seen_disp_event = TRUE;
+ compatibility(OTHER);
+ deselect();
+ swap_screen(cfg.no_alt_screen ? 0 : state, TRUE, FALSE);
+ if (!state)
+ save_cursor(state);
+ disptop = 0;
+ break;
} else
switch (mode) {
case 4: /* set insert mode */
}
/*
+ * ANSI printing routines.
+ */
+static void term_print_setup(void)
+{
+ bufchain_clear(&printer_buf);
+ print_job = printer_start_job(cfg.printer);
+}
+static void term_print_flush(void)
+{
+ void *data;
+ int len;
+ int size;
+ while ((size = bufchain_size(&printer_buf)) > 5) {
+ bufchain_prefix(&printer_buf, &data, &len);
+ if (len > size-5)
+ len = size-5;
+ printer_job_data(print_job, data, len);
+ bufchain_consume(&printer_buf, len);
+ }
+}
+static void term_print_finish(void)
+{
+ void *data;
+ int len, size;
+ char c;
+
+ if (!printing && !only_printing)
+ return; /* we need do nothing */
+
+ term_print_flush();
+ while ((size = bufchain_size(&printer_buf)) > 0) {
+ bufchain_prefix(&printer_buf, &data, &len);
+ c = *(char *)data;
+ if (c == '\033' || c == '\233') {
+ bufchain_consume(&printer_buf, size);
+ break;
+ } else {
+ printer_job_data(print_job, &c, 1);
+ bufchain_consume(&printer_buf, 1);
+ }
+ }
+ printer_finish_job(print_job);
+ print_job = NULL;
+ printing = only_printing = FALSE;
+}
+
+/*
* Remove everything currently in `inbuf' and stick it up on the
* in-memory display. There's a big state machine in here to
* process escape sequences...
unget = -1;
+ chars = NULL; /* placate compiler warnings */
while (nchars > 0 || bufchain_size(&inbuf) > 0) {
if (unget == -1) {
if (nchars == 0) {
* of i18n.
*/
+ /*
+ * If we're printing, add the character to the printer
+ * buffer.
+ */
+ if (printing) {
+ bufchain_add(&printer_buf, &c, 1);
+
+ /*
+ * If we're in print-only mode, we use a much simpler
+ * state machine designed only to recognise the ESC[4i
+ * termination sequence.
+ */
+ if (only_printing) {
+ if (c == '\033')
+ print_state = 1;
+ else if (c == (unsigned char)'\233')
+ print_state = 2;
+ else if (c == '[' && print_state == 1)
+ print_state = 2;
+ else if (c == '4' && print_state == 2)
+ print_state = 3;
+ else if (c == 'i' && print_state == 3)
+ print_state = 4;
+ else
+ print_state = 0;
+ if (print_state == 4) {
+ term_print_finish();
+ }
+ continue;
+ }
+ }
+
/* First see about all those translations. */
if (termstate == TOPLEVEL) {
if (in_utf)
} else
*d++ = *s;
}
- lpage_send(CP_ACP, abuf, d - abuf, 0);
+ lpage_send(DEFAULT_CODEPAGE, abuf, d - abuf, 0);
}
break;
case '\007':
struct beeptime *newbeep;
unsigned long ticks;
- ticks = GetTickCount();
+ ticks = GETTICKCOUNT();
if (!beep_overloaded) {
newbeep = smalloc(sizeof(struct beeptime));
* Perform an actual beep if we're not overloaded.
*/
if (!cfg.bellovl || !beep_overloaded) {
- beep(cfg.beep);
if (cfg.beep == BELL_VISUAL) {
in_vbell = TRUE;
vbell_startpoint = ticks;
term_update();
- }
+ } else
+ beep(cfg.beep);
}
disptop = 0;
}
toggle_mode(esc_args[i], esc_query, TRUE);
}
break;
+ case 'i':
+ case ANSI_QUE('i'):
+ compatibility(VT100);
+ {
+ if (esc_nargs != 1) break;
+ if (esc_args[0] == 5 && *cfg.printer) {
+ printing = TRUE;
+ only_printing = !esc_query;
+ print_state = 0;
+ term_print_setup();
+ } else if (esc_args[0] == 4 && printing) {
+ term_print_finish();
+ }
+ }
+ break;
case 'l': /* toggle modes to low */
case ANSI_QUE('l'):
compatibility(VT100);
check_selection(curs, cursplus);
}
}
+
+ term_print_flush();
}
#if 0
* Check the visual bell state.
*/
if (in_vbell) {
- ticks = GetTickCount();
+ ticks = GETTICKCOUNT();
if (ticks - vbell_startpoint >= VBELL_TIMEOUT)
in_vbell = FALSE;
}
static long last_tblink = 0;
long now, blink_diff;
- now = GetTickCount();
+ now = GETTICKCOUNT();
blink_diff = now - last_tblink;
- /* Make sure the text blinks no more than 2Hz */
- if (blink_diff < 0 || blink_diff > 450) {
+ /* Make sure the text blinks no more than 2Hz; we'll use 0.45 s period. */
+ if (blink_diff < 0 || blink_diff > (TICKSPERSEC * 9 / 20)) {
last_tblink = now;
tblinker = !tblinker;
}
blink_diff = now - last_blink;
- /* Make sure the cursor blinks no faster than GetCaretBlinkTime() */
- if (blink_diff >= 0 && blink_diff < (long) GetCaretBlinkTime())
+ /* Make sure the cursor blinks no faster than system blink rate */
+ if (blink_diff >= 0 && blink_diff < (long) CURSORBLINK)
return;
last_blink = now;
unsigned char buf[4];
WCHAR wbuf[4];
int rv;
- if (IsDBCSLeadByteEx(font_codepage, (BYTE) c)) {
+ if (is_dbcs_leadbyte(font_codepage, (BYTE) c)) {
buf[0] = c;
buf[1] = (unsigned char) ldata[top.x + 1];
- rv = MultiByteToWideChar(font_codepage,
- 0, buf, 2, wbuf, 4);
+ rv = mb_to_wc(font_codepage, 0, buf, 2, wbuf, 4);
top.x++;
} else {
buf[0] = c;
- rv = MultiByteToWideChar(font_codepage,
- 0, buf, 1, wbuf, 4);
+ rv = mb_to_wc(font_codepage, 0, buf, 1, wbuf, 4);
}
if (rv > 0) {
top.y++;
top.x = rect ? old_top_x : 0;
}
+#if SELECTION_NUL_TERMINATED
wblen++;
*wbptr++ = 0;
+#endif
write_clip(workbuf, wblen, FALSE); /* transfer to clipboard */
if (buflen > 0) /* indicates we allocated this buffer */
sfree(workbuf);
int len;
get_clip(&data, &len);
- if (data) {
+ if (data && len > 0) {
wchar_t *p, *q;
+ term_seen_key_event(); /* pasted data counts */
+
if (paste_buffer)
sfree(paste_buffer);
paste_pos = paste_hold = paste_len = 0;
{
pos selpoint;
unsigned long *ldata;
- int raw_mouse = xterm_mouse && !(cfg.mouse_override && shift);
+ int raw_mouse = (xterm_mouse &&
+ !cfg.no_mouse_rep &&
+ !(cfg.mouse_override && shift));
int default_seltype;
if (y < 0) {
} else
selstate = NO_SELECTION;
} else if (b == MBT_PASTE
- && (a == MA_CLICK || a == MA_2CLK || a == MA_3CLK)) {
- term_do_paste();
+ && (a == MA_CLICK
+#if MULTICLICK_ONLY_EVENT
+ || a == MA_2CLK || a == MA_3CLK
+#endif
+ )) {
+ request_paste();
}
term_update();
paste_len = 0;
}
+int term_paste_pending(void)
+{
+ return paste_len != 0;
+}
+
void term_paste()
{
static long last_paste = 0;
/* Don't wait forever to paste */
if (paste_hold) {
- now = GetTickCount();
+ now = GETTICKCOUNT();
paste_diff = now - last_paste;
if (paste_diff >= 0 && paste_diff < 450)
return;