Fix double-keystrokes by wrapping CreateDialog
[u/mdw/putty] / terminal.c
index 362d8b5..68363c0 100644 (file)
@@ -56,6 +56,8 @@
 
 #define has_compat(x) ( ((CL_##x)&term->compatibility_level) != 0 )
 
+const char sco2ansicolour[] = { 0, 4, 2, 6, 1, 5, 3, 7 };
+
 #define sel_nl_sz  (sizeof(sel_nl)/sizeof(wchar_t))
 const wchar_t sel_nl[] = SEL_NL;
 
@@ -321,8 +323,15 @@ void term_reconfig(Terminal *term, Config *cfg)
        term->alt_wrap = term->wrap = term->cfg.wrap_mode;
     if (reset_decom)
        term->alt_om = term->dec_om = term->cfg.dec_om;
-    if (reset_bce)
+    if (reset_bce) {
        term->use_bce = term->cfg.bce;
+       if (term->use_bce)
+           term->erase_char = (' ' | ATTR_ASCII |
+                               (term->curr_attr &
+                                (ATTR_FGMASK | ATTR_BGMASK)));
+       else
+           term->erase_char = ERASE_CHAR;
+    }
     if (reset_blink)
        term->blink_is_real = term->cfg.blinktext;
     if (reset_charclass)
@@ -418,6 +427,7 @@ Terminal *term_init(Config *mycfg, struct unicode_data *ucsdata,
     term->attr_mask = 0xffffffff;
     term->resize_fn = NULL;
     term->resize_ctx = NULL;
+    term->in_term_out = FALSE;
 
     return term;
 }
@@ -1255,17 +1265,18 @@ static void toggle_mode(Terminal *term, int mode, int query, int state)
            term->disptop = 0;
            break;
          case 1048:                   /* save/restore cursor */
-           save_cursor(term, state);
+           if (!term->cfg.no_alt_screen)
+                save_cursor(term, state);
            if (!state) term->seen_disp_event = TRUE;
            break;
          case 1049:                   /* cursor & alternate screen */
-           if (state)
+           if (state && !term->cfg.no_alt_screen)
                save_cursor(term, state);
            if (!state) term->seen_disp_event = TRUE;
            compatibility(OTHER);
            deselect(term);
            swap_screen(term, term->cfg.no_alt_screen ? 0 : state, TRUE, FALSE);
-           if (!state)
+           if (!state && !term->cfg.no_alt_screen)
                save_cursor(term, state);
            term->disptop = 0;
            break;
@@ -2381,6 +2392,11 @@ void term_out(Terminal *term)
                                    compatibility(VT100AVO);
                                    term->curr_attr |= ATTR_BLINK;
                                    break;
+                                 case 6:       /* SCO light bkgrd */
+                                   compatibility(SCOANSI);
+                                   term->blink_is_real = FALSE;
+                                   term->curr_attr |= ATTR_BLINK;
+                                   break;
                                  case 7:       /* enable reverse video */
                                    term->curr_attr |= ATTR_REVERSE;
                                    break;
@@ -2603,7 +2619,8 @@ void term_out(Terminal *term)
                                 */
                                break;
                              case 20:
-                               if (term->ldisc) {
+                               if (term->ldisc &&
+                                   !term->cfg.no_remote_qtitle) {
                                    p = get_window_title(term->frontend, TRUE);
                                    len = strlen(p);
                                    ldisc_send(term->ldisc, "\033]L", 3, 0);
@@ -2612,7 +2629,8 @@ void term_out(Terminal *term)
                                }
                                break;
                              case 21:
-                               if (term->ldisc) {
+                               if (term->ldisc &&
+                                   !term->cfg.no_remote_qtitle) {
                                    p = get_window_title(term->frontend,FALSE);
                                    len = strlen(p);
                                    ldisc_send(term->ldisc, "\033]l", 3, 0);
@@ -2715,8 +2733,71 @@ void term_out(Terminal *term)
                            check_selection(term, old_curs, term->curs);
                        }
                        break;
+                     case ANSI('c', '='):      /* Hide or Show Cursor */
+                       compatibility(SCOANSI);
+                       switch(term->esc_args[0]) {
+                         case 0:  /* hide cursor */
+                           term->cursor_on = FALSE;
+                           break;
+                         case 1:  /* restore cursor */
+                           term->big_cursor = FALSE;
+                           term->cursor_on = TRUE;
+                           break;
+                         case 2:  /* block cursor */
+                           term->big_cursor = TRUE;
+                           term->cursor_on = TRUE;
+                           break;
+                       }
+                       break;
+                     case ANSI('C', '='):
+                       /*
+                        * set cursor start on scanline esc_args[0] and
+                        * end on scanline esc_args[1].If you set
+                        * the bottom scan line to a value less than
+                        * the top scan line, the cursor will disappear.
+                        */
+                       compatibility(SCOANSI);
+                       if (term->esc_nargs >= 2) {
+                           if (term->esc_args[0] > term->esc_args[1])
+                               term->cursor_on = FALSE;
+                           else
+                               term->cursor_on = TRUE;
+                       }
+                       break;
+                     case ANSI('D', '='):
+                       compatibility(SCOANSI);
+                       term->blink_is_real = FALSE;
+                       if (term->esc_args[0]>=1)
+                           term->curr_attr |= ATTR_BLINK;
+                       else
+                           term->curr_attr &= ~ATTR_BLINK;
+                       break;
+                     case ANSI('E', '='):
+                       compatibility(SCOANSI);
+                       term->blink_is_real = (term->esc_args[0] >= 1);
+                       break;
+                     case ANSI('F', '='):      /* set normal foreground */
+                       compatibility(SCOANSI);
+                       if (term->esc_args[0] >= 0 && term->esc_args[0] < 16) {
+                           term->curr_attr &= ~ATTR_FGMASK;
+                           term->curr_attr |=
+                               (sco2ansicolour[term->esc_args[0] & 0x7] |
+                                ((term->esc_args[0] & 0x8) << 1)) <<
+                               ATTR_FGSHIFT;
+                       }
+                       break;
+                     case ANSI('G', '='):      /* set normal background */
+                       compatibility(SCOANSI);
+                       if (term->esc_args[0] >= 0 && term->esc_args[0] < 16) {
+                           term->curr_attr &= ~ATTR_BGMASK;
+                           term->curr_attr |=
+                               (sco2ansicolour[term->esc_args[0] & 0x7] |
+                                ((term->esc_args[0] & 0x8) << 1)) <<
+                               ATTR_BGSHIFT;
+                       }
+                       break;
                      case ANSI('L', '='):
-                       compatibility(OTHER);
+                       compatibility(SCOANSI);
                        term->use_bce = (term->esc_args[0] <= 0);
                        term->erase_char = ERASE_CHAR;
                        if (term->use_bce)
@@ -2724,10 +2805,6 @@ void term_out(Terminal *term)
                                                (term->curr_attr & 
                                                 (ATTR_FGMASK | ATTR_BGMASK)));
                        break;
-                     case ANSI('E', '='):
-                       compatibility(OTHER);
-                       term->blink_is_real = (term->esc_args[0] >= 1);
-                       break;
                      case ANSI('p', '"'):
                        /*
                         * Allow the host to make this emulator a
@@ -3554,7 +3631,7 @@ void term_scroll(Terminal *term, int rel, int where)
     term_update(term);
 }
 
-static void clipme(Terminal *term, pos top, pos bottom, int rect)
+static void clipme(Terminal *term, pos top, pos bottom, int rect, int desel)
 {
     wchar_t *workbuf;
     wchar_t *wbptr;                   /* where next char goes within workbuf */
@@ -3702,7 +3779,7 @@ static void clipme(Terminal *term, pos top, pos bottom, int rect)
     wblen++;
     *wbptr++ = 0;
 #endif
-    write_clip(term->frontend, workbuf, wblen, FALSE); /* transfer to clipbd */
+    write_clip(term->frontend, workbuf, wblen, desel); /* transfer to clipbd */
     if (buflen > 0)                   /* indicates we allocated this buffer */
        sfree(workbuf);
 }
@@ -3712,7 +3789,7 @@ void term_copyall(Terminal *term)
     pos top;
     top.y = -sblines(term);
     top.x = 0;
-    clipme(term, top, term->curs, 0);
+    clipme(term, top, term->curs, 0, TRUE);
 }
 
 /*
@@ -4177,7 +4254,7 @@ void term_mouse(Terminal *term, Mouse_Button braw, Mouse_Button bcooked,
             * data to the clipboard.
             */
            clipme(term, term->selstart, term->selend,
-                  (term->seltype == RECTANGULAR));
+                  (term->seltype == RECTANGULAR), FALSE);
            term->selstate = SELECTED;
        } else
            term->selstate = NO_SELECTION;
@@ -4510,7 +4587,7 @@ void term_key(Terminal *term, Key_Sym keysym, wchar_t *text, size_t tlen,
              case PK_END:      xkey = 'E'; break;
              case PK_PAGEUP:   xkey = 'I'; break;
              case PK_PAGEDOWN: xkey = 'G'; break;
-             default: break; /* else gcc warns `enum value not used' */
+             default: xkey=0; break; /* else gcc warns `enum value not used'*/
            }
            p += sprintf((char *) p, "\x1B%c", xkey);
            goto done;
@@ -4523,7 +4600,7 @@ void term_key(Terminal *term, Key_Sym keysym, wchar_t *text, size_t tlen,
          case PK_END:      code = 4; break;
          case PK_PAGEUP:   code = 5; break;
          case PK_PAGEDOWN: code = 6; break;
-         default: break; /* else gcc warns `enum value not used' */
+         default: code = 0; break; /* else gcc warns `enum value not used' */
        }
        p += sprintf((char *) p, "\x1B[%d~", code);
        goto done;
@@ -4567,7 +4644,7 @@ void term_key(Terminal *term, Key_Sym keysym, wchar_t *text, size_t tlen,
          case PK_RIGHT: xkey = 'C'; break;
          case PK_LEFT:  xkey = 'D'; break;
          case PK_REST:  xkey = 'G'; break; /* centre key on number pad */
-         default: break; /* else gcc warns `enum value not used' */
+         default: xkey = 0; break; /* else gcc warns `enum value not used' */
        }
        if (term->vt52_mode)
            p += sprintf((char *) p, "\x1B%c", xkey);
@@ -4704,17 +4781,19 @@ int term_ldisc(Terminal *term, int option)
     return FALSE;
 }
 
-/*
- * from_backend(), to get data from the backend for the terminal.
- */
-int from_backend(void *vterm, int is_stderr, const char *data, int len)
+int term_data(Terminal *term, int is_stderr, const char *data, int len)
 {
-    Terminal *term = (Terminal *)vterm;
-
     assert(len > 0);
 
     bufchain_add(&term->inbuf, data, len);
 
+    if (!term->in_term_out) {
+       term->in_term_out = TRUE;
+       term_blink(term, 1);
+       term_out(term);
+       term->in_term_out = FALSE;
+    }
+
     /*
      * term_out() always completely empties inbuf. Therefore,
      * there's no reason at all to return anything other than zero