]> asedeno.scripts.mit.edu Git - PuTTY.git/blobdiff - terminal.c
The edit menu is now mostly functional. I'm not sure about paste, since I
[PuTTY.git] / terminal.c
index a935be7dff73992bb96848a836a35bc5c8b9c6f2..aa5a9a6354ff8fff9d60a65ceed38160e913522e 100644 (file)
@@ -1,8 +1,10 @@
+#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 */
@@ -57,8 +59,6 @@ static unsigned char *tabs;
 #define MAXNL 5
 static int nl_count;
 
-static int scroll_heuristic;
-
 static enum {
     TOPLEVEL, IGNORE_NEXT,
     SEEN_ESC, SEEN_CSI, SET_GL, SET_GR,
@@ -95,6 +95,7 @@ static void erase_lots (int, int, int);
 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.
@@ -144,7 +145,6 @@ void term_update(void) {
        do_paint (ctx, TRUE);
        free_ctx (ctx);
        nl_count = 0;
-       scroll_heuristic = 0;
     }
 }
 
@@ -325,7 +325,7 @@ static void update_sbar(void) {
 
 /*
  * 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)
@@ -398,9 +398,33 @@ static void scroll (int topline, int botline, int lines, int sb) {
                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
@@ -614,7 +638,7 @@ void term_out(void) {
                termstate = SEEN_OSC;
                esc_args[0] = 0;
                break;
-             case '\r':
+             case '\015':
                curs_x = 0;
                wrapnext = FALSE;
                fix_cpos;
@@ -623,11 +647,13 @@ void term_out(void) {
                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;
@@ -694,8 +720,8 @@ void term_out(void) {
            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? */
@@ -784,8 +810,8 @@ void term_out(void) {
            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':
@@ -932,7 +958,7 @@ void term_out(void) {
                    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;
@@ -1054,8 +1080,8 @@ void term_out(void) {
            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 */
@@ -1132,8 +1158,8 @@ void term_out(void) {
          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':
@@ -1161,8 +1187,10 @@ void term_out(void) {
        check_selection (cpos, cpos+1);
     }
        
-    if (must_update || nl_count > MAXNL)
+    if (must_update || nl_count > MAXNL) {
+       update_sbar();
        term_update();
+    }
 }
 
 /*
@@ -1216,7 +1244,7 @@ static void do_paint (Context ctx, int may_optimise){
            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);
@@ -1225,7 +1253,7 @@ static void do_paint (Context ctx, int may_optimise){
            if (needs_update) {
                if (start == -1) {
                    start = j;
-                   attr = t & ATTR_MASK;
+                   attr = t & attr_mask;
                }
                ch[j-start] = (char) (t & CHAR_MASK);
            }
@@ -1270,6 +1298,10 @@ void term_paint (Context ctx, int l, int t, int r, int b) {
  */
 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;
@@ -1278,6 +1310,11 @@ void term_scroll (int rel, int where) {
     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();
 }
 
@@ -1341,12 +1378,18 @@ static void sel_spread (void) {
 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();
@@ -1382,65 +1425,80 @@ void term_mouse (Mouse_Button b, Mouse_Action a, int x, int y) {
            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) {