X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/putty/blobdiff_plain/70887be9ad821c22faf52c87597a707a8320a8cf..2784cd098cc201db40725bb11c888791cba0ee0f:/window.c diff --git a/window.c b/window.c index 6c67b592..fe9d2e91 100644 --- a/window.c +++ b/window.c @@ -1,12 +1,19 @@ #include #include +#ifndef AUTO_WINSOCK +#ifdef WINSOCK_TWO +#include +#else #include +#endif +#endif #include #include #include #define PUTTY_DO_GLOBALS /* actually _define_ globals */ #include "putty.h" +#include "storage.h" #include "win_res.h" #define IDM_SHOWLOG 0x0010 @@ -59,6 +66,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; @@ -75,11 +83,19 @@ static RGBTRIPLE defpal[NCOLOURS]; static HWND hwnd; +static HBITMAP caretbm; + static int dbltime, lasttime, lastact; static Mouse_Button lastbtn; static char *window_name, *icon_name; +static Ldisc *real_ldisc; + +void begin_session(void) { + ldisc = real_ldisc; +} + int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { static char appname[] = "PuTTY"; WORD winsock_ver; @@ -89,6 +105,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)) { @@ -139,6 +156,32 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { tolower(p[1]) == 'o' && tolower(p[2]) == 'g') { logfile = "putty.log"; + } else if (q == p + 7 && + tolower(p[0]) == 'c' && + tolower(p[1]) == 'l' && + tolower(p[2]) == 'e' && + tolower(p[3]) == 'a' && + tolower(p[4]) == 'n' && + tolower(p[5]) == 'u' && + tolower(p[6]) == 'p') { + /* + * `putty -cleanup'. Remove all registry entries + * associated with PuTTY, and also find and delete + * the random seed file. + */ + if (MessageBox(NULL, + "This procedure will remove ALL Registry\n" + "entries associated with PuTTY, and will\n" + "also remove the PuTTY random seed file.\n" + "\n" + "THIS PROCESS WILL DESTROY YOUR SAVED\n" + "SESSIONS. Are you really sure you want\n" + "to continue?", + "PuTTY Warning", + MB_YESNO | MB_ICONWARNING) == IDYES) { + cleanup_all(); + } + exit(0); } p = q + strspn(q, " \t"); } @@ -214,6 +257,19 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { return 0; } } + + /* See if host is of the form user@host */ + if (cfg.host[0] != '\0') { + char *atsign = strchr(cfg.host, '@'); + /* Make sure we're not overflowing the user field */ + if (atsign) { + if (atsign-cfg.host < sizeof cfg.username) { + strncpy (cfg.username, cfg.host, atsign-cfg.host); + cfg.username[atsign-cfg.host] = '\0'; + } + memmove(cfg.host, atsign+1, 1+strlen(atsign+1)); + } + } } /* @@ -236,7 +292,10 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { } } - ldisc = (cfg.ldisc_term ? &ldisc_term : &ldisc_simple); + real_ldisc = (cfg.ldisc_term ? &ldisc_term : &ldisc_simple); + /* To start with, we use the simple line discipline, so we can + * type passwords etc without fear of them being echoed... */ + ldisc = &ldisc_simple; if (!prev) { wndclass.style = 0; @@ -326,6 +385,17 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { SWP_NOMOVE | SWP_NOREDRAW | SWP_NOZORDER); /* + * Set up a caret bitmap, with no content. + */ + { + char *bits; + int size = (font_width+15)/16 * 2 * font_height; + bits = calloc(size, 1); + caretbm = CreateBitmap(font_width, font_height, 1, 1, bits); + free(bits); + } + + /* * Initialise the scroll bar. */ { @@ -345,7 +415,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { */ { char *error; - char msg[1024]; + char msg[1024], *title; char *realhost; error = back->init (hwnd, cfg.host, cfg.port, &realhost); @@ -355,9 +425,14 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { return 0; } window_name = icon_name = NULL; - sprintf(msg, "%s - PuTTY", realhost); - set_title (msg); - set_icon (msg); + if (*cfg.wintitle) { + title = cfg.wintitle; + } else { + sprintf(msg, "%s - PuTTY", realhost); + title = msg; + } + set_title (title); + set_icon (title); } session_closed = FALSE; @@ -479,9 +554,11 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { KillTimer(hwnd, timer_id); timer_id = 0; } + HideCaret(hwnd); if (inbuf_head) term_out(); term_update(); + ShowCaret(hwnd); if (!has_focus) timer_id = SetTimer(hwnd, 1, 2000, NULL); else if (cfg.blinktext) @@ -518,12 +595,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]; @@ -535,10 +639,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 { @@ -669,6 +772,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); @@ -855,6 +1002,7 @@ static LRESULT CALLBACK WndProc (HWND hwnd, UINT message, static int ignore_size = FALSE; static int ignore_clip = FALSE; static int just_reconfigged = FALSE; + static int resizing = FALSE; switch (message) { case WM_TIMER: @@ -862,7 +1010,9 @@ static LRESULT CALLBACK WndProc (HWND hwnd, UINT message, enact_pending_netevent(); if (inbuf_head) term_out(); + HideCaret(hwnd); term_update(); + ShowCaret(hwnd); return 0; case WM_CREATE: break; @@ -1115,6 +1265,7 @@ static LRESULT CALLBACK WndProc (HWND hwnd, UINT message, case WM_PAINT: { PAINTSTRUCT p; + HideCaret(hwnd); hdc = BeginPaint (hwnd, &p); if (pal) { SelectPalette (hdc, pal, TRUE); @@ -1125,6 +1276,7 @@ static LRESULT CALLBACK WndProc (HWND hwnd, UINT message, SelectObject (hdc, GetStockObject(SYSTEM_FONT)); SelectObject (hdc, GetStockObject(WHITE_PEN)); EndPaint (hwnd, &p); + ShowCaret(hwnd); } return 0; case WM_NETEVENT: @@ -1141,11 +1293,14 @@ static LRESULT CALLBACK WndProc (HWND hwnd, UINT message, return 0; case WM_SETFOCUS: has_focus = TRUE; + CreateCaret(hwnd, caretbm, 0, 0); + ShowCaret(hwnd); term_out(); term_update(); break; case WM_KILLFOCUS: has_focus = FALSE; + DestroyCaret(); term_out(); term_update(); break; @@ -1154,9 +1309,12 @@ static LRESULT CALLBACK WndProc (HWND hwnd, UINT message, break; case WM_ENTERSIZEMOVE: EnableSizeTip(1); + resizing = TRUE; break; case WM_EXITSIZEMOVE: EnableSizeTip(0); + resizing = FALSE; + back->size(); break; case WM_SIZING: { @@ -1225,7 +1383,13 @@ static LRESULT CALLBACK WndProc (HWND hwnd, UINT message, if (w != cols || h != rows || just_reconfigged) { term_invalidate(); term_size (h, w, cfg.savelines); - back->size(); + /* + * Don't call back->size in mid-resize. (To prevent + * massive numbers of resize events getting sent + * down the connection during an NT opaque drag.) + */ + if (!resizing) + back->size(); just_reconfigged = FALSE; } } @@ -1311,6 +1475,16 @@ static LRESULT CALLBACK WndProc (HWND hwnd, UINT message, } /* + * Move the system caret. (We maintain one, even though it's + * invisible, for the benefit of blind people: apparently some + * helper software tracks the system caret, so we should arrange to + * have one.) + */ +void sys_cursor(int x, int y) { + SetCaretPos(x * font_width, y * font_height); +} + +/* * Draw a line of text in the window, at given character * coordinates, in given attributes. * @@ -1324,7 +1498,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; @@ -1467,6 +1641,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; } @@ -1694,19 +1870,25 @@ 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 (wParam == VK_INSERT && shift_state == 1) { + term_mouse (MB_PASTE, MA_CLICK, 0, 0); + term_mouse (MB_PASTE, MA_RELEASE, 0, 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_SYSCOMMAND, SC_KEYMENU, 0); + return -1; } /* Nethack keypad */ @@ -1730,7 +1912,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; @@ -1948,13 +2130,11 @@ static WPARAM compose_key = 0; } /* This stops ALT press-release doing a 'COMMAND MENU' function */ -#if 0 if (message == WM_SYSKEYUP && wParam == VK_MENU) { keystate[VK_MENU] = 0; return 0; } -#endif return -1; }