X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/359fd192c362f17ee28ca9019bf5d90c21669c6b..edd0cb8aef57080ae884e06731a7892ca8cdba44:/windows/window.c diff --git a/windows/window.c b/windows/window.c index 9b810278..43a5e24c 100644 --- a/windows/window.c +++ b/windows/window.c @@ -50,9 +50,9 @@ /* Maximum number of sessions on saved-session submenu */ #define MENU_SAVED_MAX ((IDM_SAVED_MAX-IDM_SAVED_MIN) / MENU_SAVED_STEP) -#define WM_IGNORE_CLIP (WM_XUSER + 2) -#define WM_FULLSCR_ON_MAX (WM_XUSER + 3) -#define WM_AGENT_CALLBACK (WM_XUSER + 4) +#define WM_IGNORE_CLIP (WM_APP + 2) +#define WM_FULLSCR_ON_MAX (WM_APP + 3) +#define WM_AGENT_CALLBACK (WM_APP + 4) /* Needed for Chinese support and apparently not always defined. */ #ifndef VK_PROCESSKEY @@ -78,6 +78,7 @@ static void init_fonts(int, int); static void another_font(int); static void deinit_fonts(void); static void set_input_locale(HKL); +static void update_savedsess_menu(void); static int is_full_screen(void); static void make_full_screen(void); @@ -108,7 +109,7 @@ static void *backhandle; static struct unicode_data ucsdata; static int session_closed; -static int reconfiguring; +static int reconfiguring = FALSE; static const struct telnet_special *specials; static int n_specials; @@ -121,10 +122,11 @@ static struct { int specials_submenu_pos; } popup_menus[2]; enum { SYSMENU, CTXMENU }; +static HMENU savedsess_menu; Config cfg; /* exported to windlg.c */ -extern struct sesslist sesslist; /* imported from windlg.c */ +static struct sesslist sesslist; /* for saved-session menu */ struct agent_callback { void (*callback)(void *, void *, int); @@ -189,6 +191,11 @@ void ldisc_update(void *frontend, int echo, int edit) { } +char *get_ttymode(void *frontend, const char *mode) +{ + return term_get_ttymode(term, mode); +} + static void start_backend(void) { const char *error; @@ -479,6 +486,9 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) sfree(s1); sfree(s2); exit(0); + } else if (!strcmp(p, "-pgpfp")) { + pgp_fingerprints(); + exit(1); } else if (*p != '-') { char *q = p; if (got_host) { @@ -738,23 +748,17 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) * Set up the session-control options on the system menu. */ { - HMENU s, m; - int i, j; + HMENU m; + int j; char *str; popup_menus[SYSMENU].menu = GetSystemMenu(hwnd, FALSE); popup_menus[CTXMENU].menu = CreatePopupMenu(); AppendMenu(popup_menus[CTXMENU].menu, MF_ENABLED, IDM_PASTE, "&Paste"); - s = CreateMenu(); + savedsess_menu = CreateMenu(); get_sesslist(&sesslist, TRUE); - /* skip sesslist.sessions[0] == Default Settings */ - for (i = 1; - i < ((sesslist.nsessions <= MENU_SAVED_MAX+1) ? sesslist.nsessions - : MENU_SAVED_MAX+1); - i++) - AppendMenu(s, MF_ENABLED, IDM_SAVED_MIN + (i-1)*MENU_SAVED_STEP, - sesslist.sessions[i]); + update_savedsess_menu(); for (j = 0; j < lenof(popup_menus); j++) { m = popup_menus[j].menu; @@ -765,7 +769,8 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) AppendMenu(m, MF_SEPARATOR, 0, 0); AppendMenu(m, MF_ENABLED, IDM_NEWSESS, "Ne&w Session..."); AppendMenu(m, MF_ENABLED, IDM_DUPSESS, "&Duplicate Session"); - AppendMenu(m, MF_POPUP | MF_ENABLED, (UINT) s, "Sa&ved Sessions"); + AppendMenu(m, MF_POPUP | MF_ENABLED, (UINT) savedsess_menu, + "Sa&ved Sessions"); AppendMenu(m, MF_ENABLED, IDM_RECONF, "Chan&ge Settings..."); AppendMenu(m, MF_SEPARATOR, 0, 0); AppendMenu(m, MF_ENABLED, IDM_COPYALL, "C&opy All to Clipboard"); @@ -893,6 +898,23 @@ char *do_select(SOCKET skt, int startup) } /* + * Refresh the saved-session submenu from `sesslist'. + */ +static void update_savedsess_menu(void) +{ + int i; + while (DeleteMenu(savedsess_menu, 0, MF_BYPOSITION)) ; + /* skip sesslist.sessions[0] == Default Settings */ + for (i = 1; + i < ((sesslist.nsessions <= MENU_SAVED_MAX+1) ? sesslist.nsessions + : MENU_SAVED_MAX+1); + i++) + AppendMenu(savedsess_menu, MF_ENABLED, + IDM_SAVED_MIN + (i-1)*MENU_SAVED_STEP, + sesslist.sessions[i]); +} + +/* * Update the Special Commands submenu. */ void update_specials_menu(void *frontend) @@ -1113,12 +1135,12 @@ static void cfgtopalette(void) for (i = 0; i < NEXTCOLOURS; i++) { if (i < 216) { int r = i / 36, g = (i / 6) % 6, b = i % 6; - defpal[i+16].rgbtRed = r * 0x33; - defpal[i+16].rgbtGreen = g * 0x33; - defpal[i+16].rgbtBlue = b * 0x33; + defpal[i+16].rgbtRed = r ? r * 40 + 55 : 0; + defpal[i+16].rgbtGreen = g ? g * 40 + 55 : 0; + defpal[i+16].rgbtBlue = b ? b * 40 + 55 : 0; } else { int shade = i - 216; - shade = (shade + 1) * 0xFF / (NEXTCOLOURS - 216 + 1); + shade = shade * 10 + 8; defpal[i+16].rgbtRed = defpal[i+16].rgbtGreen = defpal[i+16].rgbtBlue = shade; } @@ -1211,8 +1233,17 @@ static void exact_textout(HDC hdc, int x, int y, CONST RECT *lprc, unsigned short *lpString, UINT cbCount, CONST INT *lpDx, int opaque) { - +#ifdef __LCC__ + /* + * The LCC include files apparently don't supply the + * GCP_RESULTSW type, but we can make do with GCP_RESULTS + * proper: the differences aren't important to us (the only + * variable-width string parameter is one we don't use anyway). + */ + GCP_RESULTS gcpr; +#else GCP_RESULTSW gcpr; +#endif char *buffer = snewn(cbCount*2+2, char); char *classbuffer = snewn(cbCount, char); memset(&gcpr, 0, sizeof(gcpr)); @@ -1293,24 +1324,11 @@ static void init_fonts(int pick_width, int pick_height) f(FONT_NORMAL, cfg.font.charset, fw_dontcare, FALSE); - lfont.lfHeight = font_height; - lfont.lfWidth = font_width; - lfont.lfEscapement = 0; - lfont.lfOrientation = 0; - lfont.lfWeight = fw_dontcare; - lfont.lfItalic = FALSE; - lfont.lfUnderline = FALSE; - lfont.lfStrikeOut = FALSE; - lfont.lfCharSet = cfg.font.charset; - lfont.lfOutPrecision = OUT_DEFAULT_PRECIS; - lfont.lfClipPrecision = CLIP_DEFAULT_PRECIS; - lfont.lfQuality = DEFAULT_QUALITY; - lfont.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE; - strncpy(lfont.lfFaceName, cfg.font.name, LF_FACESIZE); - SelectObject(hdc, fonts[FONT_NORMAL]); GetTextMetrics(hdc, &tm); + GetObject(fonts[FONT_NORMAL], sizeof(LOGFONT), &lfont); + if (pick_width == 0 || pick_height == 0) { font_height = tm.tmHeight; font_width = tm.tmAveCharWidth; @@ -1889,6 +1907,16 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, show_mouseptr(1); PostQuitMessage(0); return 0; + case WM_INITMENUPOPUP: + if ((HMENU)wParam == savedsess_menu) { + /* About to pop up Saved Sessions sub-menu. + * Refresh the session list. */ + get_sesslist(&sesslist, FALSE); /* free */ + get_sesslist(&sesslist, TRUE); + update_savedsess_menu(); + return 0; + } + break; case WM_COMMAND: case WM_SYSCOMMAND: switch (wParam & ~0xF) { /* low 4 bits reserved to Windows */ @@ -1978,16 +2006,20 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, { Config prev_cfg; int init_lvl = 1; + int reconfig_result; if (reconfiguring) - break; + break; else - reconfiguring = TRUE; + reconfiguring = TRUE; GetWindowText(hwnd, cfg.wintitle, sizeof(cfg.wintitle)); prev_cfg = cfg; - if (!do_reconfig(hwnd, back ? back->cfg_info(backhandle) : 0)) + reconfig_result = + do_reconfig(hwnd, back ? back->cfg_info(backhandle) : 0); + reconfiguring = FALSE; + if (!reconfig_result) break; { @@ -2038,9 +2070,9 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, /* Enable or disable the scroll bar, etc */ { - LONG nflg, flag = GetWindowLong(hwnd, GWL_STYLE); + LONG nflg, flag = GetWindowLongPtr(hwnd, GWL_STYLE); LONG nexflag, exflag = - GetWindowLong(hwnd, GWL_EXSTYLE); + GetWindowLongPtr(hwnd, GWL_EXSTYLE); nexflag = exflag; if (cfg.alwaysontop != prev_cfg.alwaysontop) { @@ -2079,9 +2111,9 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, if (nflg != flag || nexflag != exflag) { if (nflg != flag) - SetWindowLong(hwnd, GWL_STYLE, nflg); + SetWindowLongPtr(hwnd, GWL_STYLE, nflg); if (nexflag != exflag) - SetWindowLong(hwnd, GWL_EXSTYLE, nexflag); + SetWindowLongPtr(hwnd, GWL_EXSTYLE, nexflag); SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOCOPYBITS | @@ -2120,7 +2152,6 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, InvalidateRect(hwnd, NULL, TRUE); reset_window(init_lvl); net_pending_errors(); - reconfiguring = FALSE; } break; case IDM_COPYALL: @@ -2367,12 +2398,44 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, RealizePalette(hdc); } + /* + * We have to be careful about term_paint(). It will + * set a bunch of character cells to INVALID and then + * call do_paint(), which will redraw those cells and + * _then mark them as done_. This may not be accurate: + * when painting in WM_PAINT context we are restricted + * to the rectangle which has just been exposed - so if + * that only covers _part_ of a character cell and the + * rest of it was already visible, that remainder will + * not be redrawn at all. Accordingly, we must not + * paint any character cell in a WM_PAINT context which + * already has a pending update due to terminal output. + * The simplest solution to this - and many, many + * thanks to Hung-Te Lin for working all this out - is + * not to do any actual painting at _all_ if there's a + * pending terminal update: just mark the relevant + * character cells as INVALID and wait for the + * scheduled full update to sort it out. + * + * I have a suspicion this isn't the _right_ solution. + * An alternative approach would be to have terminal.c + * separately track what _should_ be on the terminal + * screen and what _is_ on the terminal screen, and + * have two completely different types of redraw (one + * for full updates, which syncs the former with the + * terminal itself, and one for WM_PAINT which syncs + * the latter with the former); yet another possibility + * would be to have the Windows front end do what the + * GTK one already does, and maintain a bitmap of the + * current terminal appearance so that WM_PAINT becomes + * completely trivial. However, this should do for now. + */ term_paint(term, hdc, (p.rcPaint.left-offset_width)/font_width, (p.rcPaint.top-offset_height)/font_height, (p.rcPaint.right-offset_width-1)/font_width, (p.rcPaint.bottom-offset_height-1)/font_height, - TRUE); + !term->window_update_pending); if (p.fErase || p.rcPaint.left < offset_width || @@ -2709,13 +2772,15 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, unsigned char buf[20]; int len; - if (wParam == VK_PROCESSKEY) { - MSG m; - m.hwnd = hwnd; - m.message = WM_KEYDOWN; - m.wParam = wParam; - m.lParam = lParam & 0xdfff; - TranslateMessage(&m); + if (wParam == VK_PROCESSKEY) { /* IME PROCESS key */ + if (message == WM_KEYDOWN) { + MSG m; + m.hwnd = hwnd; + m.message = WM_KEYDOWN; + m.wParam = wParam; + m.lParam = lParam & 0xdfff; + TranslateMessage(&m); + } else break; /* pass to Windows for default processing */ } else { len = TranslateKey(message, wParam, lParam, buf); if (len == -1) @@ -2753,12 +2818,11 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, set_input_locale((HKL)lParam); sys_cursor_update(); break; - case WM_IME_NOTIFY: - if(wParam == IMN_SETOPENSTATUS) { + case WM_IME_STARTCOMPOSITION: + { HIMC hImc = ImmGetContext(hwnd); ImmSetCompositionFont(hImc, &lfont); ImmReleaseContext(hwnd, hImc); - return 0; } break; case WM_IME_COMPOSITION: @@ -2899,6 +2963,10 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, } } + /* + * Any messages we don't process completely above are passed through to + * DefWindowProc() for default processing. + */ return DefWindowProc(hwnd, message, wParam, lParam); } @@ -4445,7 +4513,7 @@ void write_clip(void *frontend, wchar_t * data, int len, int must_deselect) rtfsize = 100 + strlen(cfg.font.name); rtf = snewn(rtfsize, char); - sprintf(rtf, "{\\rtf1\\ansi%d{\\fonttbl\\f0\\fmodern %s;}\\f0", + sprintf(rtf, "{\\rtf1\\ansi%d{\\fonttbl\\f0\\fmodern %s;}\\f0 ", GetACP(), cfg.font.name); rtflen = strlen(rtf); @@ -4874,7 +4942,7 @@ static int is_full_screen() { if (!IsZoomed(hwnd)) return FALSE; - if (GetWindowLong(hwnd, GWL_STYLE) & WS_CAPTION) + if (GetWindowLongPtr(hwnd, GWL_STYLE) & WS_CAPTION) return FALSE; return TRUE; } @@ -4920,13 +4988,13 @@ static void make_full_screen() return; /* Remove the window furniture. */ - style = GetWindowLong(hwnd, GWL_STYLE); + style = GetWindowLongPtr(hwnd, GWL_STYLE); style &= ~(WS_CAPTION | WS_BORDER | WS_THICKFRAME); if (cfg.scrollbar_in_fullscreen) style |= WS_VSCROLL; else style &= ~WS_VSCROLL; - SetWindowLong(hwnd, GWL_STYLE, style); + SetWindowLongPtr(hwnd, GWL_STYLE, style); /* Resize ourselves to exactly cover the nearest monitor. */ get_fullscreen_rect(&ss); @@ -4948,7 +5016,7 @@ static void clear_full_screen() DWORD oldstyle, style; /* Reinstate the window furniture. */ - style = oldstyle = GetWindowLong(hwnd, GWL_STYLE); + style = oldstyle = GetWindowLongPtr(hwnd, GWL_STYLE); style |= WS_CAPTION | WS_BORDER; if (cfg.resize_action == RESIZE_DISABLED) style &= ~WS_THICKFRAME; @@ -4959,7 +5027,7 @@ static void clear_full_screen() else style &= ~WS_VSCROLL; if (style != oldstyle) { - SetWindowLong(hwnd, GWL_STYLE, style); + SetWindowLongPtr(hwnd, GWL_STYLE, style); SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); @@ -5001,6 +5069,20 @@ int from_backend(void *frontend, int is_stderr, const char *data, int len) return term_data(term, is_stderr, data, len); } +int from_backend_untrusted(void *frontend, const char *data, int len) +{ + return term_data_untrusted(term, data, len); +} + +int get_userpass_input(prompts_t *p, unsigned char *in, int inlen) +{ + int ret; + ret = cmdline_get_passwd_input(p, in, inlen); + if (ret == -1) + ret = term_get_userpass_input(term, p, in, inlen); + return ret; +} + void agent_schedule_callback(void (*callback)(void *, void *, int), void *callback_ctx, void *data, int len) {