Re-engineering of terminal emulator, phase 1.
[u/mdw/putty] / window.c
index 4cb6003..5a36973 100644 (file)
--- a/window.c
+++ b/window.c
@@ -525,7 +525,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
 
        /* See if host is of the form user@host */
        if (cfg.host[0] != '\0') {
-           char *atsign = strchr(cfg.host, '@');
+           char *atsign = strrchr(cfg.host, '@');
            /* Make sure we're not overflowing the user field */
            if (atsign) {
                if (atsign - cfg.host < sizeof cfg.username) {
@@ -945,7 +945,7 @@ void update_specials_menu(void *frontend)
            InsertMenu(popup_menus[j].menu,
                       popup_menus[j].specials_submenu_pos,
                       MF_BYPOSITION | MF_POPUP | MF_ENABLED,
-                      (UINT) p, "Special Command");
+                      (UINT) p, "S&pecial Command");
        }
     }
 }
@@ -2767,6 +2767,16 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
            return TRUE;
        }
        break;
+      case WM_SYSCOLORCHANGE:
+       if (cfg.system_colour) {
+           /* Refresh palette from system colours. */
+           /* XXX actually this zaps the entire palette. */
+           systopalette();
+           init_palette();
+           /* Force a repaint of the terminal window. */
+           term_invalidate(term);
+       }
+       break;
       case WM_AGENT_CALLBACK:
        {
            struct agent_callback *c = (struct agent_callback *)lParam;
@@ -2891,7 +2901,7 @@ static void sys_cursor_update(void)
  *
  * We are allowed to fiddle with the contents of `text'.
  */
-void do_text(Context ctx, int x, int y, char *text, int len,
+void do_text(Context ctx, int x, int y, wchar_t *text, int len,
             unsigned long attr, int lattr)
 {
     COLORREF fg, bg, t;
@@ -2899,11 +2909,14 @@ void do_text(Context ctx, int x, int y, char *text, int len,
     HDC hdc = ctx;
     RECT line_box;
     int force_manual_underline = 0;
-    int fnt_width = font_width * (1 + (lattr != LATTR_NORM));
-    int char_width = fnt_width;
+    int fnt_width, char_width;
     int text_adjust = 0;
     static int *IpDx = 0, IpDxLEN = 0;
 
+    lattr &= LATTR_MODE;
+
+    char_width = fnt_width = font_width * (1 + (lattr != LATTR_NORM));
+
     if (attr & ATTR_WIDE)
        char_width *= 2;
 
@@ -2951,43 +2964,39 @@ void do_text(Context ctx, int x, int y, char *text, int len,
        nfont |= FONT_NARROW;
 
     /* Special hack for the VT100 linedraw glyphs. */
-    if ((attr & CSET_MASK) == 0x2300) {
-       if (text[0] >= (char) 0xBA && text[0] <= (char) 0xBD) {
-           switch ((unsigned char) (text[0])) {
-             case 0xBA:
-               text_adjust = -2 * font_height / 5;
-               break;
-             case 0xBB:
-               text_adjust = -1 * font_height / 5;
-               break;
-             case 0xBC:
-               text_adjust = font_height / 5;
-               break;
-             case 0xBD:
-               text_adjust = 2 * font_height / 5;
-               break;
-           }
-           if (lattr == LATTR_TOP || lattr == LATTR_BOT)
-               text_adjust *= 2;
-           attr &= ~CSET_MASK;
-           text[0] = (char) (ucsdata.unitab_xterm['q'] & CHAR_MASK);
-           attr |= (ucsdata.unitab_xterm['q'] & CSET_MASK);
-           if (attr & ATTR_UNDER) {
-               attr &= ~ATTR_UNDER;
-               force_manual_underline = 1;
-           }
+    if (text[0] >= 0x23BA && text[0] <= 0x23BD) {
+       switch ((unsigned char) (text[0])) {
+         case 0xBA:
+           text_adjust = -2 * font_height / 5;
+           break;
+         case 0xBB:
+           text_adjust = -1 * font_height / 5;
+           break;
+         case 0xBC:
+           text_adjust = font_height / 5;
+           break;
+         case 0xBD:
+           text_adjust = 2 * font_height / 5;
+           break;
+       }
+       if (lattr == LATTR_TOP || lattr == LATTR_BOT)
+           text_adjust *= 2;
+       text[0] = ucsdata.unitab_xterm['q'];
+       if (attr & ATTR_UNDER) {
+           attr &= ~ATTR_UNDER;
+           force_manual_underline = 1;
        }
     }
 
     /* Anything left as an original character set is unprintable. */
-    if (DIRECT_CHAR(attr)) {
-       attr &= ~CSET_MASK;
-       attr |= 0xFF00;
-       memset(text, 0xFD, len);
+    if (DIRECT_CHAR(text[0])) {
+       int i;
+       for (i = 0; i < len; i++)
+           text[i] = 0xFFFD;
     }
 
     /* OEM CP */
-    if ((attr & CSET_MASK) == ATTR_OEMCP)
+    if ((text[0] & CSET_MASK) == CSET_OEMCP)
        nfont |= FONT_OEM;
 
     nfg = ((attr & ATTR_FGMASK) >> ATTR_FGSHIFT);
@@ -3034,7 +3043,7 @@ void do_text(Context ctx, int x, int y, char *text, int len,
        line_box.right = font_width*term->cols+offset_width;
 
     /* We're using a private area for direct to font. (512 chars.) */
-    if (ucsdata.dbcs_screenfont && (attr & CSET_MASK) == ATTR_ACP) {
+    if (ucsdata.dbcs_screenfont && (text[0] & CSET_MASK) == CSET_ACP) {
        /* Ho Hum, dbcs fonts are a PITA! */
        /* To display on W9x I have to convert to UCS */
        static wchar_t *uni_buf = 0;
@@ -3049,15 +3058,20 @@ void do_text(Context ctx, int x, int y, char *text, int len,
        for(nlen = mptr = 0; mptr<len; mptr++) {
            uni_buf[nlen] = 0xFFFD;
            if (IsDBCSLeadByteEx(ucsdata.font_codepage, (BYTE) text[mptr])) {
+               char dbcstext[2];
+               dbcstext[0] = text[mptr] & 0xFF;
+               dbcstext[1] = text[mptr+1] & 0xFF;
                IpDx[nlen] += char_width;
                MultiByteToWideChar(ucsdata.font_codepage, MB_USEGLYPHCHARS,
-                                  text+mptr, 2, uni_buf+nlen, 1);
+                                   dbcstext, 2, uni_buf+nlen, 1);
                mptr++;
            }
            else
            {
+               char dbcstext[1];
+               dbcstext[0] = text[mptr] & 0xFF;
                MultiByteToWideChar(ucsdata.font_codepage, MB_USEGLYPHCHARS,
-                                  text+mptr, 1, uni_buf+nlen, 1);
+                                   dbcstext, 1, uni_buf+nlen, 1);
            }
            nlen++;
        }
@@ -3076,10 +3090,21 @@ void do_text(Context ctx, int x, int y, char *text, int len,
        }
 
        IpDx[0] = -1;
-    } else if (DIRECT_FONT(attr)) {
+    } else if (DIRECT_FONT(text[0])) {
+       static char *directbuf = NULL;
+       static int directlen = 0;
+       int i;
+       if (len > directlen) {
+           directlen = len;
+           directbuf = sresize(directbuf, directlen, char);
+       }
+
+       for (i = 0; i < len; i++)
+           directbuf[i] = text[i] & 0xFF;
+
        ExtTextOut(hdc, x,
                   y - font_height * (lattr == LATTR_BOT) + text_adjust,
-                  ETO_CLIPPED | ETO_OPAQUE, &line_box, text, len, IpDx);
+                  ETO_CLIPPED | ETO_OPAQUE, &line_box, directbuf, len, IpDx);
        if (bold_mode == BOLD_SHADOW && (attr & ATTR_BOLD)) {
            SetBkMode(hdc, TRANSPARENT);
 
@@ -3093,7 +3118,7 @@ void do_text(Context ctx, int x, int y, char *text, int len,
            ExtTextOut(hdc, x - 1,
                       y - font_height * (lattr ==
                                          LATTR_BOT) + text_adjust,
-                      ETO_CLIPPED, &line_box, text, len, IpDx);
+                      ETO_CLIPPED, &line_box, directbuf, len, IpDx);
        }
     } else {
        /* And 'normal' unicode characters */
@@ -3106,7 +3131,7 @@ void do_text(Context ctx, int x, int y, char *text, int len,
            wbuf = snewn(wlen, WCHAR);
        }
        for (i = 0; i < len; i++)
-           wbuf[i] = (WCHAR) ((attr & CSET_MASK) + (text[i] & CHAR_MASK));
+           wbuf[i] = text[i];
 
        /* print Glyphs as they are, without Windows' Shaping*/
        exact_textout(hdc, x, y - font_height * (lattr == LATTR_BOT) + text_adjust,
@@ -3141,7 +3166,7 @@ void do_text(Context ctx, int x, int y, char *text, int len,
     }
 }
 
-void do_cursor(Context ctx, int x, int y, char *text, int len,
+void do_cursor(Context ctx, int x, int y, wchar_t *text, int len,
               unsigned long attr, int lattr)
 {
 
@@ -3151,7 +3176,7 @@ void do_cursor(Context ctx, int x, int y, char *text, int len,
     int ctype = cfg.cursor_type;
 
     if ((attr & TATTR_ACTCURS) && (ctype == 0 || term->big_cursor)) {
-       if (((attr & CSET_MASK) | (unsigned char) *text) != UCSWIDE) {
+       if (*text != UCSWIDE) {
            do_text(ctx, x, y, text, len, attr, lattr);
            return;
        }
@@ -3228,13 +3253,13 @@ int char_width(Context ctx, int uc) {
     if (!font_dualwidth) return 1;
 
     switch (uc & CSET_MASK) {
-      case ATTR_ASCII:
+      case CSET_ASCII:
        uc = ucsdata.unitab_line[uc & 0xFF];
        break;
-      case ATTR_LINEDRW:
+      case CSET_LINEDRW:
        uc = ucsdata.unitab_xterm[uc & 0xFF];
        break;
-      case ATTR_SCOACS:
+      case CSET_SCOACS:
        uc = ucsdata.unitab_scoacs[uc & 0xFF];
        break;
     }
@@ -3242,12 +3267,12 @@ int char_width(Context ctx, int uc) {
        if (ucsdata.dbcs_screenfont) return 1;
 
        /* Speedup, I know of no font where ascii is the wrong width */
-       if ((uc&CHAR_MASK) >= ' ' && (uc&CHAR_MASK)<= '~') 
+       if ((uc&~CSET_MASK) >= ' ' && (uc&~CSET_MASK)<= '~')
            return 1;
 
-       if ( (uc & CSET_MASK) == ATTR_ACP ) {
+       if ( (uc & CSET_MASK) == CSET_ACP ) {
            SelectObject(hdc, fonts[FONT_NORMAL]);
-       } else if ( (uc & CSET_MASK) == ATTR_OEMCP ) {
+       } else if ( (uc & CSET_MASK) == CSET_OEMCP ) {
            another_font(FONT_OEM);
            if (!fonts[FONT_OEM]) return 0;
 
@@ -3255,8 +3280,8 @@ int char_width(Context ctx, int uc) {
        } else
            return 0;
 
-       if ( GetCharWidth32(hdc, uc&CHAR_MASK, uc&CHAR_MASK, &ibuf) != 1 && 
-            GetCharWidth(hdc, uc&CHAR_MASK, uc&CHAR_MASK, &ibuf) != 1)
+       if ( GetCharWidth32(hdc, uc&~CSET_MASK, uc&~CSET_MASK, &ibuf) != 1 &&
+            GetCharWidth(hdc, uc&~CSET_MASK, uc&~CSET_MASK, &ibuf) != 1)
            return 0;
     } else {
        /* Speedup, I know of no font where ascii is the wrong width */
@@ -3383,8 +3408,8 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
 
 
        /* Nastyness with NUMLock - Shift-NUMLock is left alone though */
-       if ((cfg.funky_type == 3 ||
-            (cfg.funky_type <= 1 && term->app_keypad_keys &&
+       if ((cfg.funky_type == FUNKY_VT400 ||
+            (cfg.funky_type <= FUNKY_LINUX && term->app_keypad_keys &&
              !cfg.no_applic_k))
            && wParam == VK_NUMLOCK && !(keystate[VK_SHIFT] & 0x80)) {
 
@@ -3450,8 +3475,8 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
 
     /* Sanitize the number pad if not using a PC NumPad */
     if (left_alt || (term->app_keypad_keys && !cfg.no_applic_k
-                    && cfg.funky_type != 2)
-       || cfg.funky_type == 3 || cfg.nethack_keypad || compose_state) {
+                    && cfg.funky_type != FUNKY_XTERM)
+       || cfg.funky_type == FUNKY_VT400 || cfg.nethack_keypad || compose_state) {
        if ((HIWORD(lParam) & KF_EXTENDED) == 0) {
            int nParam = 0;
            switch (wParam) {
@@ -3580,8 +3605,8 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
        if (!left_alt) {
            int xkey = 0;
 
-           if (cfg.funky_type == 3 ||
-               (cfg.funky_type <= 1 &&
+           if (cfg.funky_type == FUNKY_VT400 ||
+               (cfg.funky_type <= FUNKY_LINUX &&
                 term->app_keypad_keys && !cfg.no_applic_k)) switch (wParam) {
                  case VK_EXECUTE:
                    xkey = 'P';
@@ -3633,7 +3658,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
                    xkey = 'n';
                    break;
                  case VK_ADD:
-                   if (cfg.funky_type == 2) {
+                   if (cfg.funky_type == FUNKY_XTERM) {
                        if (shift_state)
                            xkey = 'l';
                        else
@@ -3645,15 +3670,15 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
                    break;
 
                  case VK_DIVIDE:
-                   if (cfg.funky_type == 2)
+                   if (cfg.funky_type == FUNKY_XTERM)
                        xkey = 'o';
                    break;
                  case VK_MULTIPLY:
-                   if (cfg.funky_type == 2)
+                   if (cfg.funky_type == FUNKY_XTERM)
                        xkey = 'j';
                    break;
                  case VK_SUBTRACT:
-                   if (cfg.funky_type == 2)
+                   if (cfg.funky_type == FUNKY_XTERM)
                        xkey = 'm';
                    break;
 
@@ -3825,7 +3850,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
            break;
        }
        /* Reorder edit keys to physical order */
-       if (cfg.funky_type == 3 && code <= 6)
+       if (cfg.funky_type == FUNKY_VT400 && code <= 6)
            code = "\0\2\1\4\5\3\6"[code];
 
        if (term->vt52_mode && code > 0 && code <= 6) {
@@ -3833,7 +3858,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
            return p - output;
        }
 
-       if (cfg.funky_type == 5 &&     /* SCO function keys */
+       if (cfg.funky_type == FUNKY_SCO &&     /* SCO function keys */
            code >= 11 && code <= 34) {
            char codes[] = "MNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@[\\]^_`{";
            int index = 0;
@@ -3856,7 +3881,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
            p += sprintf((char *) p, "\x1B[%c", codes[index]);
            return p - output;
        }
-       if (cfg.funky_type == 5 &&     /* SCO small keypad */
+       if (cfg.funky_type == FUNKY_SCO &&     /* SCO small keypad */
            code >= 1 && code <= 6) {
            char codes[] = "HL.FIG";
            if (code == 3) {
@@ -3866,7 +3891,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
            }
            return p - output;
        }
-       if ((term->vt52_mode || cfg.funky_type == 4) && code >= 11 && code <= 24) {
+       if ((term->vt52_mode || cfg.funky_type == FUNKY_VT100P) && code >= 11 && code <= 24) {
            int offt = 0;
            if (code > 15)
                offt++;
@@ -3879,11 +3904,11 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
                    sprintf((char *) p, "\x1BO%c", code + 'P' - 11 - offt);
            return p - output;
        }
-       if (cfg.funky_type == 1 && code >= 11 && code <= 15) {
+       if (cfg.funky_type == FUNKY_LINUX && code >= 11 && code <= 15) {
            p += sprintf((char *) p, "\x1B[[%c", code + 'A' - 11);
            return p - output;
        }
-       if (cfg.funky_type == 2 && code >= 11 && code <= 14) {
+       if (cfg.funky_type == FUNKY_XTERM && code >= 11 && code <= 14) {
            if (term->vt52_mode)
                p += sprintf((char *) p, "\x1B%c", code + 'P' - 11);
            else