Prevent network errors from summarily closing the window when CoE is off
[u/mdw/putty] / window.c
index 5acddc7..b497123 100644 (file)
--- a/window.c
+++ b/window.c
@@ -36,6 +36,7 @@
 
 #define WM_IGNORE_SIZE (WM_XUSER + 1)
 #define WM_IGNORE_CLIP (WM_XUSER + 2)
+#define WM_IGNORE_KEYMENU (WM_XUSER + 3)
 
 static LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
 static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, unsigned char *output);
@@ -59,6 +60,7 @@ static void enact_pending_netevent(void);
 #define FONT_OEMBOLDUND 6
 #define FONT_OEMUND 7
 static HFONT fonts[8];
+static int font_needs_hand_underlining;
 static enum {
     BOLD_COLOURS, BOLD_SHADOW, BOLD_FONT
 } bold_mode;
@@ -89,6 +91,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) {
     int guess_width, guess_height;
 
     putty_inst = inst;
+    flags = FLAG_VERBOSE | FLAG_INTERACTIVE;
 
     winsock_ver = MAKEWORD(1, 1);
     if (WSAStartup(winsock_ver, &wsadata)) {
@@ -174,14 +177,16 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) {
        } else if (*p) {
            char *q = p;
             /*
-             * If the hostname starts with "telnet://", set the
+             * If the hostname starts with "telnet:", set the
              * protocol to Telnet and process the string as a
              * Telnet URL.
              */
-            if (!strncmp(q, "telnet://", 9)) {
+            if (!strncmp(q, "telnet:", 7)) {
                 char c;
 
-                q += 9;
+                q += 7;
+               if (q[0] == '/' && q[1] == '/')
+                   q += 2;
                 cfg.protocol = PROT_TELNET;
                 p = q;
                 while (*p && *p != ':' && *p != '/') p++;
@@ -516,12 +521,39 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) {
 }
 
 /*
+ * Print a message box and close the connection.
+ */
+void connection_fatal(char *fmt, ...) {
+    va_list ap;
+    char stuff[200];
+
+    va_start(ap, fmt);
+    vsprintf(stuff, fmt, ap);
+    va_end(ap);
+    MessageBox(hwnd, stuff, "PuTTY Fatal Error", MB_ICONERROR | MB_OK);
+    if (cfg.close_on_exit)
+        PostQuitMessage(1);
+    else {
+        session_closed = TRUE;
+        SetWindowText (hwnd, "PuTTY (inactive)");
+    }
+}
+
+/*
  * Actually do the job requested by a WM_NETEVENT
  */
 static void enact_pending_netevent(void) {
     int i;
+    static int reentering = 0;
+
+    if (reentering)
+        return;                        /* don't unpend the pending */
+
     pending_netevent = FALSE;
+
+    reentering = 1;
     i = back->msg (pend_netevent_wParam, pend_netevent_lParam);
+    reentering = 0;
 
     if (i < 0) {
        char buf[1024];
@@ -533,10 +565,9 @@ static void enact_pending_netevent(void) {
            sprintf(buf, "Unexpected network error %d", -i);
            break;
        }
-       MessageBox(hwnd, buf, "PuTTY Fatal Error",
-                  MB_ICONERROR | MB_OK);
-       PostQuitMessage(1);
-    } else if (i == 0) {
+        connection_fatal(buf);
+    }
+    if (i <= 0) {
        if (cfg.close_on_exit)
            PostQuitMessage(0);
        else {
@@ -667,6 +698,50 @@ font_messup:
 
        f(FONT_UNDERLINE, cfg.fontcharset, fw_dontcare, TRUE);
 
+        /*
+         * Some fonts, e.g. 9-pt Courier, draw their underlines
+         * outside their character cell. We successfully prevent
+         * screen corruption by clipping the text output, but then
+         * we lose the underline completely. Here we try to work
+         * out whether this is such a font, and if it is, we set a
+         * flag that causes underlines to be drawn by hand.
+         *
+         * Having tried other more sophisticated approaches (such
+         * as examining the TEXTMETRIC structure or requesting the
+         * height of a string), I think we'll do this the brute
+         * force way: we create a small bitmap, draw an underlined
+         * space on it, and test to see whether any pixels are
+         * foreground-coloured. (Since we expect the underline to
+         * go all the way across the character cell, we only search
+         * down a single column of the bitmap, half way across.)
+         */
+        {
+            HDC und_dc;
+            HBITMAP und_bm, und_oldbm;
+            int i, gotit;
+            COLORREF c;
+
+            und_dc = CreateCompatibleDC(hdc);
+            und_bm = CreateCompatibleBitmap(hdc, font_width, font_height);
+            und_oldbm = SelectObject(und_dc, und_bm);
+            SelectObject(und_dc, fonts[FONT_UNDERLINE]);
+            SetTextAlign(und_dc, TA_TOP | TA_LEFT | TA_NOUPDATECP);
+            SetTextColor (und_dc, RGB(255,255,255));
+            SetBkColor (und_dc, RGB(0,0,0));
+            SetBkMode (und_dc, OPAQUE);
+            ExtTextOut (und_dc, 0, 0, ETO_OPAQUE, NULL, " ", 1, NULL);
+            gotit = FALSE;
+            for (i = 0; i < font_height; i++) {
+                c = GetPixel(und_dc, font_width/2, i);
+                if (c != RGB(0,0,0))
+                    gotit = TRUE;
+            }
+            SelectObject(und_dc, und_oldbm);
+            DeleteObject(und_bm);
+            DeleteDC(und_dc);
+            font_needs_hand_underlining = !gotit;
+        }
+
         if (bold_mode == BOLD_FONT) {
            f(FONT_BOLD, cfg.fontcharset, fw_bold, FALSE);
            f(FONT_BOLDUND, cfg.fontcharset, fw_bold, TRUE);
@@ -852,6 +927,7 @@ static LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
     HDC hdc;
     static int ignore_size = FALSE;
     static int ignore_clip = FALSE;
+    static int ignore_keymenu = TRUE;
     static int just_reconfigged = FALSE;
 
     switch (message) {
@@ -876,6 +952,10 @@ static LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
        return 0;
       case WM_SYSCOMMAND:
        switch (wParam & ~0xF) {       /* low 4 bits reserved to Windows */
+          case SC_KEYMENU:
+            if (ignore_keymenu)
+                return 0;              /* don't put up system menu on Alt */
+            break;
          case IDM_SHOWLOG:
            showeventlog(hwnd);
            break;
@@ -1105,6 +1185,9 @@ static LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
       case WM_IGNORE_CLIP:
        ignore_clip = wParam;          /* don't panic on DESTROYCLIPBOARD */
        break;
+      case WM_IGNORE_KEYMENU:
+       ignore_keymenu = wParam;       /* do or don't ignore SC_KEYMENU */
+       break;
       case WM_DESTROYCLIPBOARD:
        if (!ignore_clip)
            term_deselect();
@@ -1322,7 +1405,7 @@ void do_text (Context ctx, int x, int y, char *text, int len,
     RECT line_box;
     int force_manual_underline = 0;
     int fnt_width = font_width*(1+(lattr!=LATTR_NORM));
-static int *IpDx = 0, IpDxLEN = 0;;
+    static int *IpDx = 0, IpDxLEN = 0;;
 
     if (len>IpDxLEN || IpDx[0] != fnt_width) {
        int i;
@@ -1465,6 +1548,8 @@ static int *IpDx = 0, IpDxLEN = 0;;
 
        nfont &= ~(FONT_BOLD|FONT_UNDERLINE);
     }
+    if (font_needs_hand_underlining && (attr & ATTR_UNDER))
+        force_manual_underline = 1;
     if (attr & ATTR_REVERSE) {
        t = nfg; nfg = nbg; nbg = t;
     }
@@ -1692,19 +1777,22 @@ static WPARAM compose_key = 0;
 
        /* Lets see if it's a pattern we know all about ... */
        if (wParam == VK_PRIOR && shift_state == 1) {
-          SendMessage (hwnd, WM_VSCROLL, SB_PAGEUP, 0);
-          return 0;
+            SendMessage (hwnd, WM_VSCROLL, SB_PAGEUP, 0);
+            return 0;
        }
        if (wParam == VK_NEXT && shift_state == 1) {
-          SendMessage (hwnd, WM_VSCROLL, SB_PAGEDOWN, 0);
-          return 0;
+            SendMessage (hwnd, WM_VSCROLL, SB_PAGEDOWN, 0);
+            return 0;
        }
        if (left_alt && wParam == VK_F4 && cfg.alt_f4) {
-          return -1;
+            return -1;
        }
        if (left_alt && wParam == VK_SPACE && cfg.alt_space) {
-          SendMessage (hwnd, WM_SYSCOMMAND, SC_KEYMENU, 0);
-          return -1;
+            
+            SendMessage (hwnd, WM_IGNORE_KEYMENU, FALSE, 0);
+            SendMessage (hwnd, WM_SYSCOMMAND, SC_KEYMENU, 0);
+            SendMessage (hwnd, WM_IGNORE_KEYMENU, TRUE, 0);
+            return -1;
        }
 
        /* Nethack keypad */
@@ -1728,7 +1816,7 @@ static WPARAM compose_key = 0;
 
           if ( cfg.funky_type == 0 ||
              ( cfg.funky_type == 1 && app_keypad_keys)) switch(wParam) {
-              case VK_EXECUTE: xkey = 'P'; break;
+              case VK_EXECUTE: if (app_keypad_keys) xkey = 'P'; break;
               case VK_DIVIDE:  xkey = 'Q'; break;
               case VK_MULTIPLY:xkey = 'R'; break;
               case VK_SUBTRACT:xkey = 'S'; break;