+#ifndef macintosh
#include <windows.h>
+#endif /* not macintosh */
#include <stdio.h>
#include <stdlib.h>
-
+#include <string.h>
#include "putty.h"
static unsigned long *text; /* buffer of text on terminal screen */
#define MAXNL 5
static int nl_count;
-static int scroll_heuristic;
-
static enum {
TOPLEVEL, IGNORE_NEXT,
SEEN_ESC, SEEN_CSI, SET_GL, SET_GR,
static void swap_screen (int);
static void update_sbar (void);
static void deselect (void);
+static void scroll_display(int, int, int);
/*
* Set up power-on settings for the terminal.
do_paint (ctx, TRUE);
free_ctx (ctx);
nl_count = 0;
- scroll_heuristic = 0;
}
}
/*
* Check whether the region bounded by the two pointers intersects
- * the scroll region, and de-select the on-screen selection if so.
+ * the selection, and de-select the on-screen selection if so.
*/
static void check_selection (unsigned long *from, unsigned long *to) {
if (from < selend && selstart < to)
selend = scroll_top + size + scroll_size;
}
}
+#ifdef OPTIMISE_SCROLL
+ scroll_display(topline, botline, lines);
+#endif
+}
+
+#ifdef OPTIMISE_SCROLL
+static void scroll_display(int topline, int botline, int lines) {
+ unsigned long *start, *end;
+ int distance, size, i;
- scroll_heuristic += lines;
+ start = disptext + topline * (cols + 1);
+ end = disptext + (botline + 1) * (cols + 1);
+ distance = (lines > 0 ? lines : -lines) * (cols + 1);
+ size = end - start - distance;
+ if (lines > 0) {
+ memmove(start, start + distance, size * TSIZE);
+ for (i = 0; i < distance; i++)
+ (start + size)[i] |= ATTR_INVALID;
+ } else {
+ memmove(start + distance, start, size * TSIZE);
+ for (i = 0; i < distance; i++)
+ start[i] |= ATTR_INVALID;
+ }
+ do_scroll(topline, botline, lines);
}
+#endif /* OPTIMISE_SCROLL */
+
/*
* Move the cursor to a given position, clipping at boundaries. We
termstate = SEEN_OSC;
esc_args[0] = 0;
break;
- case '\r':
+ case '\015':
curs_x = 0;
wrapnext = FALSE;
fix_cpos;
break;
case '\013':
case '\014':
- case '\n':
+ case '\012':
if (curs_y == marg_b)
scroll (marg_t, marg_b, 1, TRUE);
else if (curs_y < rows-1)
curs_y++;
+ if (cfg.lfhascr)
+ curs_x = 0;
fix_cpos;
wrapnext = FALSE;
disptop = scrtop;
termstate = TOPLEVEL;
switch (c) {
case '\005': case '\007': case '\b': case '\016': case '\017':
- case '\033': case 0233: case 0234: case 0235: case '\r':
- case '\013': case '\014': case '\n': case '\t':
+ case '\033': case 0233: case 0234: case 0235: case '\015':
+ case '\013': case '\014': case '\012': case '\t':
termstate = TOPLEVEL;
goto do_toplevel; /* hack... */
case ' ': /* some weird sequence? */
termstate = TOPLEVEL; /* default */
switch (c) {
case '\005': case '\007': case '\b': case '\016': case '\017':
- case '\033': case 0233: case 0234: case 0235: case '\r':
- case '\013': case '\014': case '\n': case '\t':
+ case '\033': case 0233: case 0234: case 0235: case '\015':
+ case '\013': case '\014': case '\012': case '\t':
termstate = TOPLEVEL;
goto do_toplevel; /* hack... */
case '0': case '1': case '2': case '3': case '4':
top = def(esc_args[0], 1) - 1;
if (top < 0)
top = 0;
- bot = (esc_nargs == 1 ? rows :
+ bot = (esc_nargs <= 1 || esc_args[1] == 0 ? rows :
def(esc_args[1], rows)) - 1;
if (bot >= rows)
bot = rows-1;
osc_w = FALSE;
switch (c) {
case '\005': case '\007': case '\b': case '\016': case '\017':
- case '\033': case 0233: case 0234: case 0235: case '\r':
- case '\013': case '\014': case '\n': case '\t':
+ case '\033': case 0233: case 0234: case 0235: case '\015':
+ case '\013': case '\014': case '\012': case '\t':
termstate = TOPLEVEL;
goto do_toplevel; /* hack... */
case 'P': /* Linux palette sequence */
case SEEN_OSC_W:
switch (c) {
case '\005': case '\007': case '\b': case '\016': case '\017':
- case '\033': case 0233: case 0234: case 0235: case '\r':
- case '\013': case '\014': case '\n': case '\t':
+ case '\033': case 0233: case 0234: case 0235: case '\015':
+ case '\013': case '\014': case '\012': case '\t':
termstate = TOPLEVEL;
goto do_toplevel; /* hack... */
case '0': case '1': case '2': case '3': case '4':
check_selection (cpos, cpos+1);
}
- if (must_update || nl_count > MAXNL)
+ if (must_update || nl_count > MAXNL) {
+ update_sbar();
term_update();
+ }
}
/*
unsigned long t = wanttext[idx];
int needs_update = (j < cols && t != disptext[idx]);
int keep_going = (start != -1 && needs_update &&
- (t & ATTR_MASK) == attr &&
+ (t & attr_mask) == attr &&
j-start < sizeof(ch));
if (start != -1 && !keep_going) {
do_text (ctx, start, i, ch, j-start, attr);
if (needs_update) {
if (start == -1) {
start = j;
- attr = t & ATTR_MASK;
+ attr = t & attr_mask;
}
ch[j-start] = (char) (t & CHAR_MASK);
}
right = (r - 1) / font_width;
top = t / font_height;
bottom = (b - 1) / font_height;
- for (i = top; i <= bottom && j<rows ; i++)
- for (j = left; j <= right && j<cols ; j++)
+ for (i = top; i <= bottom && i < rows ; i++)
+ for (j = left; j <= right && j < cols ; j++)
disptext[i*(cols+1)+j] = ATTR_INVALID;
do_paint (ctx, FALSE);
*/
void term_scroll (int rel, int where) {
int n = where * (cols+1);
+#ifdef OPTIMISE_SCROLL
+ unsigned long *olddisptop = disptop;
+ int shift;
+#endif /* OPTIMISE_SCROLL */
disptop = (rel < 0 ? scrtop :
rel > 0 ? sbtop : disptop) + n;
if (disptop > scrtop)
disptop = scrtop;
update_sbar();
+#ifdef OPTIMISE_SCROLL
+ shift = (disptop - olddisptop) / (cols + 1);
+ if (shift < rows && shift > -rows)
+ scroll_display(0, rows - 1, shift);
+#endif /* OPTIMISE_SCROLL */
term_update();
}
void term_mouse (Mouse_Button b, Mouse_Action a, int x, int y) {
unsigned long *selpoint;
- if (y<0) y = 0;
- if (y>=rows) y = rows-1;
- if (x<0) x = 0;
- if (x>=cols) x = cols-1;
-
- selpoint = disptop + y * (cols+1) + x;
+ if (x < 0) {
+ x = cols - 1;
+ y--;
+ } else if (x >= cols)
+ x = cols - 1;
+
+ selpoint = disptop + y * (cols + 1) + x;
+ if (selpoint < sbtop)
+ selpoint = sbtop;
+ else if (selpoint > scrtop + rows * (cols + 1) - 1)
+ /* XXX put this in a variable? */
+ selpoint = scrtop + rows * (cols + 1) - 1;
if (b == MB_SELECT && a == MA_CLICK) {
deselect();
selend = selpoint + 1;
}
sel_spread();
- } else if ((b == MB_SELECT || b == MB_EXTEND) && a == MA_RELEASE) {
+ } else if ((b == MB_SELECT || b == MB_EXTEND) && a == MA_RELEASE)
if (selstate == DRAGGING) {
- /*
- * We've completed a selection. We now transfer the
- * data to the clipboard.
- */
- unsigned char *p = selspace;
- unsigned long *q = selstart;
-
- while (q < selend) {
- int nl = FALSE;
- unsigned long *lineend = q - (q-text) % (cols+1) + cols;
- unsigned long *nlpos = lineend;
-
- if (!(*nlpos & ATTR_WRAPPED)) {
- while ((nlpos[-1] & CHAR_MASK) == 0x20 && nlpos > q)
- nlpos--;
- if (nlpos < selend)
- nl = TRUE;
- }
- while (q < nlpos && q < selend)
- *p++ = (unsigned char) (*q++ & CHAR_MASK);
- if (nl) {
- int i;
- for (i=0; i<sizeof(sel_nl); i++)
- *p++ = sel_nl[i];
- }
- q = lineend + 1; /* start of next line */
- }
- write_clip (selspace, p - selspace);
+ if (cfg.implicit_copy)
+ term_copy();
selstate = SELECTED;
} else
selstate = NO_SELECTION;
- } else if (b == MB_PASTE && (a==MA_CLICK || a==MA_2CLK || a==MA_3CLK)) {
- char *data;
- int len;
-
- get_clip((void **) &data, &len);
- if (data) {
- char *p, *q;
- p = q = data;
- while (p < data+len) {
- while (p < data+len &&
- !(p <= data+len-sizeof(sel_nl) &&
- !memcmp(p, sel_nl, sizeof(sel_nl))))
- p++;
- back->send (q, p-q);
- if (p <= data+len-sizeof(sel_nl) &&
- !memcmp(p, sel_nl, sizeof(sel_nl))) {
- back->send ("\r", 1);
- p += sizeof(sel_nl);
- }
- q = p;
+ else if (b == MB_PASTE && (a==MA_CLICK || a==MA_2CLK || a==MA_3CLK))
+ term_paste();
+ term_update();
+}
+
+/*
+ * We've completed a selection. We now transfer the
+ * data to the clipboard.
+ */
+void term_copy() {
+ unsigned char *p = selspace;
+ unsigned long *q = selstart;
+
+ while (q < selend) {
+ int nl = FALSE;
+ unsigned long *lineend = q - (q-text) % (cols+1) + cols;
+ unsigned long *nlpos = lineend;
+
+ if (!(*nlpos & ATTR_WRAPPED)) {
+ while ((nlpos[-1] & CHAR_MASK) == 0x20 && nlpos > q)
+ nlpos--;
+ if (nlpos < selend)
+ nl = TRUE;
+ }
+ while (q < nlpos && q < selend)
+ *p++ = (unsigned char) (*q++ & CHAR_MASK);
+ if (nl) {
+ int i;
+ for (i=0; i<sizeof(sel_nl); i++)
+ *p++ = sel_nl[i];
+ }
+ q = lineend + 1; /* start of next line */
+ }
+ write_clip (selspace, p - selspace);
+}
+
+void term_paste() {
+ char *data;
+ int len;
+
+ get_clip((void **) &data, &len);
+ if (data) {
+ char *p, *q;
+ p = q = data;
+ while (p < data+len) {
+ while (p < data+len &&
+ !(p <= data+len-sizeof(sel_nl) &&
+ !memcmp(p, sel_nl, sizeof(sel_nl))))
+ p++;
+ back->send (q, p-q);
+ if (p <= data+len-sizeof(sel_nl) &&
+ !memcmp(p, sel_nl, sizeof(sel_nl))) {
+ back->send ("\015", 1);
+ p += sizeof(sel_nl);
}
+ q = p;
}
- get_clip(NULL, NULL);
}
+ get_clip(NULL, NULL);
+}
- term_update();
+/*
+ * Find out if there's a selection.
+ */
+int term_hasselection(void) {
+
+ return selstate == SELECTED;
}
static void deselect (void) {