Add a nonfatal() function everywhere, to be used for reporting things
[u/mdw/putty] / windows / window.c
index a1d99ba..38270e6 100644 (file)
@@ -174,8 +174,9 @@ static HFONT fonts[FONT_MAXNO];
 static LOGFONT lfont;
 static int fontflag[FONT_MAXNO];
 static enum {
-    BOLD_COLOURS, BOLD_SHADOW, BOLD_FONT
-} bold_mode;
+    BOLD_NONE, BOLD_SHADOW, BOLD_FONT
+} bold_font_mode;
+static int bold_colours;
 static enum {
     UND_LINE, UND_FONT
 } und_mode;
@@ -206,6 +207,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 +700,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 +719,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}.
      */
     {
@@ -1403,8 +1410,9 @@ static void init_fonts(int pick_width, int pick_height)
     for (i = 0; i < FONT_MAXNO; i++)
        fonts[i] = NULL;
 
-    bold_mode = conf_get_int(conf, CONF_bold_colour) ?
-       BOLD_COLOURS : BOLD_FONT;
+    bold_font_mode = conf_get_int(conf, CONF_bold_style) & 1 ?
+       BOLD_FONT : BOLD_NONE;
+    bold_colours = conf_get_int(conf, CONF_bold_style) & 2 ? TRUE : FALSE;
     und_mode = UND_FONT;
 
     font = conf_get_fontspec(conf, CONF_font);
@@ -1529,7 +1537,7 @@ static void init_fonts(int pick_width, int pick_height)
        }
     }
 
-    if (bold_mode == BOLD_FONT) {
+    if (bold_font_mode == BOLD_FONT) {
        f(FONT_BOLD, font->charset, fw_bold, FALSE);
     }
 #undef f
@@ -1556,9 +1564,9 @@ static void init_fonts(int pick_width, int pick_height)
        fonts[FONT_UNDERLINE] = 0;
     }
 
-    if (bold_mode == BOLD_FONT &&
+    if (bold_font_mode == BOLD_FONT &&
        fontsize[FONT_BOLD] != fontsize[FONT_NORMAL]) {
-       bold_mode = BOLD_SHADOW;
+       bold_font_mode = BOLD_SHADOW;
        DeleteObject(fonts[FONT_BOLD]);
        fonts[FONT_BOLD] = 0;
     }
@@ -2004,10 +2012,14 @@ void notify_remote_exit(void *fe)
     }
 }
 
-void timer_change_notify(long next)
+void timer_change_notify(unsigned long next)
 {
-    long ticks = next - GETTICKCOUNT();
-    if (ticks <= 0) ticks = 1;        /* just in case */
+    unsigned long now = GETTICKCOUNT();
+    long ticks;
+    if (now - next < INT_MAX)
+       ticks = 0;
+    else
+       ticks = next - now;
     KillTimer(hwnd, TIMING_TIMER_ID);
     SetTimer(hwnd, TIMING_TIMER_ID, ticks, NULL);
     timing_next_time = next;
@@ -2034,7 +2046,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
     switch (message) {
       case WM_TIMER:
        if ((UINT_PTR)wParam == TIMING_TIMER_ID) {
-           long next;
+           unsigned long next;
 
            KillTimer(hwnd, TIMING_TIMER_ID);
            if (run_timers(timing_next_time, &next)) {
@@ -2144,6 +2156,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                si.lpReserved2 = NULL;
                CreateProcess(b, cl, NULL, NULL, inherit_handles,
                              NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi);
+                CloseHandle(pi.hProcess);
+                CloseHandle(pi.hThread);
 
                if (filemap)
                    CloseHandle(filemap);
@@ -2327,8 +2341,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                        conf_get_int(prev_conf, CONF_font_quality) ||
                        conf_get_int(conf, CONF_vtmode) !=
                        conf_get_int(prev_conf, CONF_vtmode) ||
-                       conf_get_int(conf, CONF_bold_colour) !=
-                       conf_get_int(prev_conf, CONF_bold_colour) ||
+                       conf_get_int(conf, CONF_bold_style) !=
+                       conf_get_int(prev_conf, CONF_bold_style) ||
                        resize_action == RESIZE_DISABLED ||
                        resize_action == RESIZE_EITHER ||
                        resize_action != conf_get_int(prev_conf,
@@ -2980,7 +2994,19 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
            break;
          case SB_THUMBPOSITION:
          case SB_THUMBTRACK:
-           term_scroll(term, 1, HIWORD(wParam));
+           /*
+            * Use GetScrollInfo instead of HIWORD(wParam) to get
+            * 32-bit scroll position.
+            */
+           {
+               SCROLLINFO si;
+
+               si.cbSize = sizeof(si);
+               si.fMask = SIF_TRACKPOS;
+               if (GetScrollInfo(hwnd, SB_VERT, &si) == 0)
+                   si.nTrackPos = HIWORD(wParam);
+               term_scroll(term, 1, si.nTrackPos);
+           }
            break;
        }
        break;
@@ -3105,9 +3131,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);
            }
@@ -3198,8 +3235,9 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                } else
                    break;
 
-               if (send_raw_mouse && shift_pressed &&
-                   !(conf_get_int(conf, CONF_mouse_override))) {
+               if (send_raw_mouse &&
+                   !(conf_get_int(conf, CONF_mouse_override) &&
+                      shift_pressed)) {
                    /* Mouse wheel position is in screen coordinates for
                     * some reason */
                    POINT p;
@@ -3306,9 +3344,11 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len,
     int text_adjust = 0;
     int xoffset = 0;
     int maxlen, remaining, opaque;
+    int is_cursor = FALSE;
     static int *lpDx = NULL;
     static int lpDx_len = 0;
     int *lpDx_maybe;
+    int len2; /* for SURROGATE PAIR */
 
     lattr &= LATTR_MODE;
 
@@ -3328,11 +3368,9 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len,
 
     if ((attr & TATTR_ACTCURS) && (cursor_type == 0 || term->big_cursor)) {
        attr &= ~(ATTR_REVERSE|ATTR_BLINK|ATTR_COLOURS);
-       if (bold_mode == BOLD_COLOURS)
-           attr &= ~ATTR_BOLD;
-
        /* cursor fg and bg */
        attr |= (260 << ATTR_FGSHIFT) | (261 << ATTR_BGSHIFT);
+        is_cursor = TRUE;
     }
 
     nfont = 0;
@@ -3353,6 +3391,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])) {
@@ -3377,9 +3416,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;
@@ -3391,7 +3432,7 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len,
 
     nfg = ((attr & ATTR_FGMASK) >> ATTR_FGSHIFT);
     nbg = ((attr & ATTR_BGMASK) >> ATTR_BGSHIFT);
-    if (bold_mode == BOLD_FONT && (attr & ATTR_BOLD))
+    if (bold_font_mode == BOLD_FONT && (attr & ATTR_BOLD))
        nfont |= FONT_BOLD;
     if (und_mode == UND_FONT && (attr & ATTR_UNDER))
        nfont |= FONT_UNDERLINE;
@@ -3411,11 +3452,11 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len,
        nfg = nbg;
        nbg = t;
     }
-    if (bold_mode == BOLD_COLOURS && (attr & ATTR_BOLD)) {
+    if (bold_colours && (attr & ATTR_BOLD) && !is_cursor) {
        if (nfg < 16) nfg |= 8;
        else if (nfg >= 256) nfg |= 1;
     }
-    if (bold_mode == BOLD_COLOURS && (attr & ATTR_BLINK)) {
+    if (bold_colours && (attr & ATTR_BLINK)) {
        if (nbg < 16) nbg |= 8;
        else if (nbg >= 256) nbg |= 1;
     }
@@ -3432,6 +3473,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)
@@ -3462,19 +3521,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.) */
@@ -3519,7 +3606,7 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len,
                         ETO_CLIPPED | (opaque ? ETO_OPAQUE : 0),
                         &line_box, uni_buf, nlen,
                         lpDx_maybe);
-            if (bold_mode == BOLD_SHADOW && (attr & ATTR_BOLD)) {
+            if (bold_font_mode == BOLD_SHADOW && (attr & ATTR_BOLD)) {
                 SetBkMode(hdc, TRANSPARENT);
                 ExtTextOutW(hdc, x + xoffset - 1,
                             y - font_height * (lattr ==
@@ -3544,7 +3631,7 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len,
                        y - font_height * (lattr == LATTR_BOT) + text_adjust,
                        ETO_CLIPPED | (opaque ? ETO_OPAQUE : 0),
                        &line_box, directbuf, len, lpDx_maybe);
-            if (bold_mode == BOLD_SHADOW && (attr & ATTR_BOLD)) {
+            if (bold_font_mode == BOLD_SHADOW && (attr & ATTR_BOLD)) {
                 SetBkMode(hdc, TRANSPARENT);
 
                 /* GRR: This draws the character outside its box and
@@ -3583,7 +3670,7 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len,
                             opaque && !(attr & TATTR_COMBINING));
 
             /* And the shadow bold hack. */
-            if (bold_mode == BOLD_SHADOW && (attr & ATTR_BOLD)) {
+            if (bold_font_mode == BOLD_SHADOW && (attr & ATTR_BOLD)) {
                 SetBkMode(hdc, TRANSPARENT);
                 ExtTextOutW(hdc, x + xoffset - 1,
                             y - font_height * (lattr ==
@@ -3623,9 +3710,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;
        }
@@ -4837,7 +4950,7 @@ void write_clip(void *frontend, wchar_t * data, int *attr, int len, int must_des
                    bgcolour = tmpcolour;
                }
 
-               if (bold_mode == BOLD_COLOURS && (attr[i] & ATTR_BOLD)) {
+               if (bold_colours && (attr[i] & ATTR_BOLD)) {
                    if (fgcolour  <   8)        /* ANSI colours */
                        fgcolour +=   8;
                    else if (fgcolour >= 256)   /* Default colours */
@@ -4928,7 +5041,7 @@ void write_clip(void *frontend, wchar_t * data, int *attr, int len, int must_des
                    bgcolour = tmpcolour;
                }
 
-               if (bold_mode == BOLD_COLOURS && (attr[tindex] & ATTR_BOLD)) {
+               if (bold_colours && (attr[tindex] & ATTR_BOLD)) {
                    if (fgcolour  <   8)            /* ANSI colours */
                        fgcolour +=   8;
                    else if (fgcolour >= 256)       /* Default colours */
@@ -4945,7 +5058,7 @@ void write_clip(void *frontend, wchar_t * data, int *attr, int len, int must_des
                 /*
                  * Collect other attributes
                  */
-               if (bold_mode != BOLD_COLOURS)
+               if (bold_font_mode != BOLD_NONE)
                    attrBold  = attr[tindex] & ATTR_BOLD;
                else
                    attrBold  = 0;
@@ -4964,7 +5077,7 @@ void write_clip(void *frontend, wchar_t * data, int *attr, int len, int must_des
                        bgcolour  = -1;             /* No coloring */
 
                    if (fgcolour >= 256) {          /* Default colour */
-                       if (bold_mode == BOLD_COLOURS && (fgcolour & 1) && bgcolour == -1)
+                       if (bold_colours && (fgcolour & 1) && bgcolour == -1)
                            attrBold = ATTR_BOLD;   /* Emphasize text with bold attribute */
 
                        fgcolour  = -1;             /* No coloring */
@@ -5229,6 +5342,22 @@ void modalfatalbox(char *fmt, ...)
     cleanup_exit(1);
 }
 
+/*
+ * Print a message box and don't close the connection.
+ */
+void nonfatal(char *fmt, ...)
+{
+    va_list ap;
+    char *stuff, morestuff[100];
+
+    va_start(ap, fmt);
+    stuff = dupvprintf(fmt, ap);
+    va_end(ap);
+    sprintf(morestuff, "%.70s Error", appname);
+    MessageBox(hwnd, stuff, morestuff, MB_ICONERROR | MB_OK);
+    sfree(stuff);
+}
+
 DECL_WINDOWS_FUNCTION(static, BOOL, FlashWindowEx, (PFLASHWINFO));
 
 static void init_flashwindow(void)
@@ -5260,9 +5389,9 @@ static int flashing = 0;
  * Timer for platforms where we must maintain window flashing manually
  * (e.g., Win95).
  */
-static void flash_window_timer(void *ctx, long now)
+static void flash_window_timer(void *ctx, unsigned long now)
 {
-    if (flashing && now - next_flash >= 0) {
+    if (flashing && now == next_flash) {
        flash_window(1);
     }
 }