Patch from Robert de Bath to substantially simplify timing.c.
[u/mdw/putty] / windows / window.c
index d558cc9..a0a5268 100644 (file)
@@ -206,6 +206,12 @@ static int compose_state = 0;
 
 static UINT wm_mousewheel = WM_MOUSEWHEEL;
 
+#define IS_HIGH_VARSEL(wch1, wch2) \
+    ((wch1) == 0xDB40 && ((wch2) >= 0xDD00 && (wch2) <= 0xDDEF))
+#define IS_LOW_VARSEL(wch) \
+    (((wch) >= 0x180B && (wch) <= 0x180D) || /* MONGOLIAN FREE VARIATION SELECTOR */ \
+     ((wch) >= 0xFE00 && (wch) <= 0xFE0F)) /* VARIATION SELECTOR 1-16 */
+
 /* Dummy routine, only required in plink. */
 void ldisc_update(void *frontend, int echo, int edit)
 {
@@ -693,6 +699,12 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
     }
 
     /*
+     * Initialise the fonts, simultaneously correcting the guesses
+     * for font_{width,height}.
+     */
+    init_fonts(0,0);
+
+    /*
      * Initialise the terminal. (We have to do this _after_
      * creating the window, since the terminal is the first thing
      * which will call schedule_timer(), which will in turn call
@@ -706,12 +718,6 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
              conf_get_int(conf, CONF_savelines));
 
     /*
-     * Initialise the fonts, simultaneously correcting the guesses
-     * for font_{width,height}.
-     */
-    init_fonts(0,0);
-
-    /*
      * Correct the guesses for extra_{width,height}.
      */
     {
@@ -2315,7 +2321,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                {
                    FontSpec *font = conf_get_fontspec(conf, CONF_font);
                    FontSpec *prev_font = conf_get_fontspec(prev_conf,
-                                                           CONF_font);
+                                                             CONF_font);
 
                    if (!strcmp(font->name, prev_font->name) ||
                        !strcmp(conf_get_str(conf, CONF_line_codepage),
@@ -2899,7 +2905,21 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                     h = height / font_height;
                     if (h < 1) h = 1;
 
-                    term_size(term, h, w, conf_get_int(conf, CONF_savelines));
+                    if (resizing) {
+                        /*
+                         * As below, if we're in the middle of an
+                         * interactive resize we don't call
+                         * back->size. In Windows 7, this case can
+                         * arise in maximisation as well via the Aero
+                         * snap UI.
+                         */
+                        need_backend_resize = TRUE;
+                        conf_set_int(conf, CONF_height, h);
+                        conf_set_int(conf, CONF_width, w);
+                    } else {
+                        term_size(term, h, w,
+                                  conf_get_int(conf, CONF_savelines));
+                    }
                 }
                 reset_window(0);
             } else if (wParam == SIZE_RESTORED && was_zoomed) {
@@ -3091,9 +3111,20 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                 * instead we luni_send the characters one by one.
                 */
                term_seen_key_event(term);
-               for (i = 0; i < n; i += 2) {
-                   if (ldisc)
+               /* don't divide SURROGATE PAIR */
+               if (ldisc) {
+                    for (i = 0; i < n; i += 2) {
+                       WCHAR hs = *(unsigned short *)(buff+i);
+                       if (IS_HIGH_SURROGATE(hs) && i+2 < n) {
+                           WCHAR ls = *(unsigned short *)(buff+i+2);
+                           if (IS_LOW_SURROGATE(ls)) {
+                               luni_send(ldisc, (unsigned short *)(buff+i), 2, 1);
+                               i += 2;
+                               continue;
+                           }
+                       }
                        luni_send(ldisc, (unsigned short *)(buff+i), 1, 1);
+                    }
                }
                free(buff);
            }
@@ -3295,6 +3326,7 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len,
     static int *lpDx = NULL;
     static int lpDx_len = 0;
     int *lpDx_maybe;
+    int len2; /* for SURROGATE PAIR */
 
     lattr &= LATTR_MODE;
 
@@ -3339,6 +3371,7 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len,
     if (attr & ATTR_NARROW)
        nfont |= FONT_NARROW;
 
+#ifdef USES_VTLINE_HACK
     /* Special hack for the VT100 linedraw glyphs. */
     if (text[0] >= 0x23BA && text[0] <= 0x23BD) {
        switch ((unsigned char) (text[0])) {
@@ -3363,9 +3396,11 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len,
            force_manual_underline = 1;
        }
     }
+#endif
 
     /* Anything left as an original character set is unprintable. */
-    if (DIRECT_CHAR(text[0])) {
+    if (DIRECT_CHAR(text[0]) &&
+        (len < 2 || !IS_SURROGATE_PAIR(text[0], text[1]))) {
        int i;
        for (i = 0; i < len; i++)
            text[i] = 0xFFFD;
@@ -3418,6 +3453,24 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len,
     line_box.top = y;
     line_box.right = x + char_width * len;
     line_box.bottom = y + font_height;
+    /* adjust line_box.right for SURROGATE PAIR & VARIATION SELECTOR */
+    {
+       int i;
+       int rc_width = 0;
+       for (i = 0; i < len ; i++) {
+           if (i+1 < len && IS_HIGH_VARSEL(text[i], text[i+1])) {
+               i++;
+           } else if (i+1 < len && IS_SURROGATE_PAIR(text[i], text[i+1])) {
+               rc_width += char_width;
+               i++;
+           } else if (IS_LOW_VARSEL(text[i])) {
+               /* do nothing */
+            } else {
+               rc_width += char_width;
+            }
+       }
+       line_box.right = line_box.left + rc_width;
+    }
 
     /* Only want the left half of double width lines */
     if (line_box.right > font_width*term->cols+offset_width)
@@ -3448,19 +3501,47 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len,
 
     opaque = TRUE;                     /* start by erasing the rectangle */
     for (remaining = len; remaining > 0;
-         text += len, remaining -= len, x += char_width * len) {
+         text += len, remaining -= len, x += char_width * len2) {
         len = (maxlen < remaining ? maxlen : remaining);
-
-        if (len > lpDx_len) {
-            if (len > lpDx_len) {
-                lpDx_len = len * 9 / 8 + 16;
-                lpDx = sresize(lpDx, lpDx_len, int);
-            }
+        /* don't divide SURROGATE PAIR and VARIATION SELECTOR */
+        len2 = len;
+        if (maxlen == 1) {
+            if (remaining >= 1 && IS_SURROGATE_PAIR(text[0], text[1]))
+                len++;
+            if (remaining-len >= 1 && IS_LOW_VARSEL(text[len]))
+                len++;
+            else if (remaining-len >= 2 &&
+                     IS_HIGH_VARSEL(text[len], text[len+1]))
+                len += 2;
         }
+
+       if (len > lpDx_len) {
+           lpDx_len = len * 9 / 8 + 16;
+           lpDx = sresize(lpDx, lpDx_len, int);
+
+           if (lpDx_maybe) lpDx_maybe = lpDx;
+       }
+
         {
             int i;
-            for (i = 0; i < len; i++)
+            /* only last char has dx width in SURROGATE PAIR and
+             * VARIATION sequence */
+            for (i = 0; i < len; i++) {
                 lpDx[i] = char_width;
+                if (i+1 < len && IS_HIGH_VARSEL(text[i], text[i+1])) {
+                    if (i > 0) lpDx[i-1] = 0;
+                    lpDx[i] = 0;
+                    i++;
+                    lpDx[i] = char_width;
+                } else if (i+1 < len && IS_SURROGATE_PAIR(text[i],text[i+1])) {
+                    lpDx[i] = 0;
+                    i++;
+                    lpDx[i] = char_width;
+                } else if (IS_LOW_VARSEL(text[i])) {
+                    if (i > 0) lpDx[i-1] = 0;
+                    lpDx[i] = char_width;
+                }
+            }
         }
 
         /* We're using a private area for direct to font. (512 chars.) */
@@ -3609,9 +3690,35 @@ void do_text(Context ctx, int x, int y, wchar_t *text, int len,
 {
     if (attr & TATTR_COMBINING) {
        unsigned long a = 0;
-       attr &= ~TATTR_COMBINING;
+       int len0 = 1;
+        /* don't divide SURROGATE PAIR and VARIATION SELECTOR */
+       if (len >= 2 && IS_SURROGATE_PAIR(text[0], text[1]))
+           len0 = 2;
+       if (len-len0 >= 1 && IS_LOW_VARSEL(text[len0])) {
+           attr &= ~TATTR_COMBINING;
+           do_text_internal(ctx, x, y, text, len0+1, attr, lattr);
+           text += len0+1;
+           len -= len0+1;
+           a = TATTR_COMBINING;
+       } else if (len-len0 >= 2 && IS_HIGH_VARSEL(text[len0], text[len0+1])) {
+           attr &= ~TATTR_COMBINING;
+           do_text_internal(ctx, x, y, text, len0+2, attr, lattr);
+           text += len0+2;
+           len -= len0+2;
+           a = TATTR_COMBINING;
+       } else {
+            attr &= ~TATTR_COMBINING;
+        }
+
        while (len--) {
-           do_text_internal(ctx, x, y, text, 1, attr | a, lattr);
+           if (len >= 1 && IS_SURROGATE_PAIR(text[0], text[1])) {
+               do_text_internal(ctx, x, y, text, 2, attr | a, lattr);
+               len--;
+               text++;
+           } else {
+                do_text_internal(ctx, x, y, text, 1, attr | a, lattr);
+            }
+
            text++;
            a = TATTR_COMBINING;
        }
@@ -5612,6 +5719,11 @@ int from_backend_untrusted(void *frontend, const char *data, int len)
     return term_data_untrusted(term, data, len);
 }
 
+int from_backend_eof(void *frontend)
+{
+    return TRUE;   /* do respond to incoming EOF with outgoing */
+}
+
 int get_userpass_input(prompts_t *p, unsigned char *in, int inlen)
 {
     int ret;