X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/4c472521e531fb420537806e1724c4a7a0041977..971bcc0afc69f7e754285167e88885c8893d0229:/window.c diff --git a/window.c b/window.c index 59901010..6d306f56 100644 --- a/window.c +++ b/window.c @@ -11,10 +11,12 @@ #endif #endif +#ifndef NO_MULTIMON #if WINVER < 0x0500 #define COMPILE_MULTIMON_STUBS #include #endif +#endif #include #include @@ -24,6 +26,7 @@ #define PUTTY_DO_GLOBALS /* actually _define_ globals */ #include "putty.h" +#include "terminal.h" #include "winstuff.h" #include "storage.h" #include "win_res.h" @@ -34,19 +37,6 @@ #define IDM_RECONF 0x0040 #define IDM_CLRSB 0x0050 #define IDM_RESET 0x0060 -#define IDM_TEL_AYT 0x0070 -#define IDM_TEL_BRK 0x0080 -#define IDM_TEL_SYNCH 0x0090 -#define IDM_TEL_EC 0x00a0 -#define IDM_TEL_EL 0x00b0 -#define IDM_TEL_GA 0x00c0 -#define IDM_TEL_NOP 0x00d0 -#define IDM_TEL_ABORT 0x00e0 -#define IDM_TEL_AO 0x00f0 -#define IDM_TEL_IP 0x0100 -#define IDM_TEL_SUSP 0x0110 -#define IDM_TEL_EOR 0x0120 -#define IDM_TEL_EOF 0x0130 #define IDM_HELP 0x0140 #define IDM_ABOUT 0x0150 #define IDM_SAVEDSESS 0x0160 @@ -56,11 +46,16 @@ #define IDM_SESSLGP 0x0250 /* log type printable */ #define IDM_SESSLGA 0x0260 /* log type all chars */ #define IDM_SESSLGE 0x0270 /* log end */ + +#define IDM_SPECIAL_MIN 0x0400 +#define IDM_SPECIAL_MAX 0x0800 + #define IDM_SAVED_MIN 0x1000 #define IDM_SAVED_MAX 0x2000 #define WM_IGNORE_CLIP (WM_XUSER + 2) #define WM_FULLSCR_ON_MAX (WM_XUSER + 3) +#define WM_AGENT_CALLBACK (WM_XUSER + 4) /* Needed for Chinese support and apparently not always defined. */ #ifndef VK_PROCESSKEY @@ -75,6 +70,7 @@ #define WHEEL_DELTA 120 #endif +static Mouse_Button translate_button(Mouse_Button button); static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, unsigned char *output); @@ -84,7 +80,6 @@ static void init_fonts(int, int); static void another_font(int); static void deinit_fonts(void); static void set_input_locale(HKL); -static int do_mouse_wheel_msg(UINT message, WPARAM wParam, LPARAM lParam); static int is_full_screen(void); static void make_full_screen(void); @@ -105,11 +100,36 @@ static LPARAM pend_netevent_lParam = 0; static void enact_pending_netevent(void); static void flash_window(int mode); static void sys_cursor_update(void); +static int is_shift_pressed(void); +static int get_fullscreen_rect(RECT * ss); static time_t last_movement = 0; static int caret_x = -1, caret_y = -1; +static int kbd_codepage; + +static void *ldisc; +static Backend *back; +static void *backhandle; + +static struct unicode_data ucsdata; +static int session_closed; + +static const struct telnet_special *specials; +static int specials_menu_position; + +Config cfg; /* exported to windlg.c */ + +extern struct sesslist sesslist; /* imported from windlg.c */ + +struct agent_callback { + void (*callback)(void *, void *, int); + void *callback_ctx; + void *data; + int len; +}; + #define FONT_NORMAL 0 #define FONT_BOLD 1 #define FONT_UNDERLINE 2 @@ -157,18 +177,19 @@ static char *window_name, *icon_name; static int compose_state = 0; +static int wsa_started = 0; + static OSVERSIONINFO osVersion; static UINT wm_mousewheel = WM_MOUSEWHEEL; /* Dummy routine, only required in plink. */ -void ldisc_update(int echo, int edit) +void ldisc_update(void *frontend, int echo, int edit) { } int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { - static char appname[] = "PuTTY"; WORD winsock_ver; WSADATA wsadata; WNDCLASS wndclass; @@ -190,6 +211,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) WSACleanup(); return 1; } + wsa_started = 1; /* WISHLIST: maybe allow config tweaking even if winsock not present? */ sk_init(); @@ -203,8 +225,10 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) ZeroMemory(&osVersion, sizeof(osVersion)); osVersion.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); if (!GetVersionEx ( (OSVERSIONINFO *) &osVersion)) { + char *str = dupprintf("%s Fatal Error", appname); MessageBox(NULL, "Windows refuses to report a version", - "PuTTY Fatal Error", MB_OK | MB_ICONEXCLAMATION); + str, MB_OK | MB_ICONEXCLAMATION); + sfree(str); return 1; } } @@ -250,62 +274,34 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) */ { char *p; + int got_host = 0; - default_protocol = DEFAULT_PROTOCOL; - default_port = DEFAULT_PORT; + default_protocol = be_default_protocol; + /* Find the appropriate default port. */ + { + int i; + default_port = 0; /* illegal */ + for (i = 0; backends[i].backend != NULL; i++) + if (backends[i].protocol == default_protocol) { + default_port = backends[i].backend->default_port; + break; + } + } cfg.logtype = LGTYP_NONE; do_defaults(NULL, &cfg); p = cmdline; - while (*p && isspace(*p)) - p++; /* - * Process command line options first. Yes, this can be - * done better, and it will be as soon as I have the - * energy... + * Process a couple of command-line options which are more + * easily dealt with before the line is broken up into + * words. These are the soon-to-be-defunct @sessionname and + * the internal-use-only &sharedmemoryhandle, neither of + * which are combined with anything else. */ - while (*p == '-') { - char *q = p + strcspn(p, " \t"); + while (*p && isspace(*p)) p++; - if (q == p + 3 && - tolower(p[0]) == 's' && - tolower(p[1]) == 's' && tolower(p[2]) == 'h') { - default_protocol = cfg.protocol = PROT_SSH; - default_port = cfg.port = 22; - } 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"); - } - - /* - * An initial @ means to activate a saved session. - */ if (*p == '@') { int i = strlen(p); while (i > 1 && isspace(p[i - 1])) @@ -335,53 +331,113 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) WSACleanup(); return 0; } - } else if (*p) { - char *q = p; + } else { /* - * If the hostname starts with "telnet:", set the - * protocol to Telnet and process the string as a - * Telnet URL. + * Otherwise, break up the command line and deal with + * it sensibly. */ - if (!strncmp(q, "telnet:", 7)) { - char c; - - q += 7; - if (q[0] == '/' && q[1] == '/') - q += 2; - cfg.protocol = PROT_TELNET; - p = q; - while (*p && *p != ':' && *p != '/') - p++; - c = *p; - if (*p) - *p++ = '\0'; - if (c == ':') - cfg.port = atoi(p); - else - cfg.port = -1; - strncpy(cfg.host, q, sizeof(cfg.host) - 1); - cfg.host[sizeof(cfg.host) - 1] = '\0'; - } else { - while (*p && !isspace(*p)) - p++; - if (*p) - *p++ = '\0'; - strncpy(cfg.host, q, sizeof(cfg.host) - 1); - cfg.host[sizeof(cfg.host) - 1] = '\0'; - while (*p && isspace(*p)) - p++; - if (*p) - cfg.port = atoi(p); - else - cfg.port = -1; - } - } else { - if (!do_config()) { - WSACleanup(); - return 0; + int argc, i; + char **argv; + + split_into_argv(cmdline, &argc, &argv, NULL); + + for (i = 0; i < argc; i++) { + char *p = argv[i]; + int ret; + + ret = cmdline_process_param(p, i+1cols; + guess_height = extra_height + font_height * term->rows; { RECT r; - HWND w = GetDesktopWindow(); - GetWindowRect(w, &r); + get_fullscreen_rect(&r); if (guess_width > r.right - r.left) guess_width = r.right - r.left; if (guess_height > r.bottom - r.top) @@ -522,8 +599,8 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) * Resize the window, now we know what size we _really_ want it * to be. */ - guess_width = extra_width + font_width * cols; - guess_height = extra_height + font_height * rows; + guess_width = extra_width + font_width * term->cols; + guess_height = extra_height + font_height * term->rows; SetWindowPos(hwnd, NULL, 0, 0, guess_width, guess_height, SWP_NOMOVE | SWP_NOREDRAW | SWP_NOZORDER); @@ -533,7 +610,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { char *bits; int size = (font_width + 15) / 16 * 2 * font_height; - bits = smalloc(size); + bits = snewn(size, char); memset(bits, 0, size); caretbm = CreateBitmap(font_width, font_height, 1, 1, bits); sfree(bits); @@ -549,8 +626,8 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) si.cbSize = sizeof(si); si.fMask = SIF_ALL | SIF_DISABLENOSCROLL; si.nMin = 0; - si.nMax = rows - 1; - si.nPage = rows; + si.nMax = term->rows - 1; + si.nPage = term->rows; si.nPos = 0; SetScrollInfo(hwnd, SB_VERT, &si, FALSE); } @@ -563,25 +640,39 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) char msg[1024], *title; char *realhost; - error = back->init(cfg.host, cfg.port, &realhost, cfg.tcp_nodelay); + error = back->init(NULL, &backhandle, &cfg, + cfg.host, cfg.port, &realhost, cfg.tcp_nodelay); + back->provide_logctx(backhandle, logctx); if (error) { + char *str = dupprintf("%s Error", appname); sprintf(msg, "Unable to open connection to\n" "%.800s\n" "%s", cfg.host, error); - MessageBox(NULL, msg, "PuTTY Error", MB_ICONERROR | MB_OK); + MessageBox(NULL, msg, str, MB_ICONERROR | MB_OK); + sfree(str); return 0; } window_name = icon_name = NULL; if (*cfg.wintitle) { title = cfg.wintitle; } else { - sprintf(msg, "%s - PuTTY", realhost); + sprintf(msg, "%s - %s", realhost, appname); title = msg; } sfree(realhost); - set_title(title); - set_icon(title); + set_title(NULL, title); + set_icon(NULL, title); } + /* + * Connect the terminal to the backend for resize purposes. + */ + term_provide_resize_fn(term, back->size, backhandle); + + /* + * Set up a line discipline. + */ + ldisc = ldisc_create(&cfg, term, back, backhandle, NULL); + session_closed = FALSE; /* @@ -596,41 +687,23 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) */ { HMENU m = GetSystemMenu(hwnd, FALSE); - HMENU p, s; + HMENU s; int i; + char *str; AppendMenu(m, MF_SEPARATOR, 0, 0); - if (cfg.protocol == PROT_TELNET) { - p = CreateMenu(); - AppendMenu(p, MF_ENABLED, IDM_TEL_AYT, "Are You There"); - AppendMenu(p, MF_ENABLED, IDM_TEL_BRK, "Break"); - AppendMenu(p, MF_ENABLED, IDM_TEL_SYNCH, "Synch"); - AppendMenu(p, MF_SEPARATOR, 0, 0); - AppendMenu(p, MF_ENABLED, IDM_TEL_EC, "Erase Character"); - AppendMenu(p, MF_ENABLED, IDM_TEL_EL, "Erase Line"); - AppendMenu(p, MF_ENABLED, IDM_TEL_GA, "Go Ahead"); - AppendMenu(p, MF_ENABLED, IDM_TEL_NOP, "No Operation"); - AppendMenu(p, MF_SEPARATOR, 0, 0); - AppendMenu(p, MF_ENABLED, IDM_TEL_ABORT, "Abort Process"); - AppendMenu(p, MF_ENABLED, IDM_TEL_AO, "Abort Output"); - AppendMenu(p, MF_ENABLED, IDM_TEL_IP, "Interrupt Process"); - AppendMenu(p, MF_ENABLED, IDM_TEL_SUSP, "Suspend Process"); - AppendMenu(p, MF_SEPARATOR, 0, 0); - AppendMenu(p, MF_ENABLED, IDM_TEL_EOR, "End Of Record"); - AppendMenu(p, MF_ENABLED, IDM_TEL_EOF, "End Of File"); - AppendMenu(m, MF_POPUP | MF_ENABLED, (UINT) p, - "Telnet Command"); - AppendMenu(m, MF_SEPARATOR, 0, 0); - } + specials_menu_position = GetMenuItemCount(m); AppendMenu(m, MF_ENABLED, IDM_SHOWLOG, "&Event Log"); AppendMenu(m, MF_SEPARATOR, 0, 0); AppendMenu(m, MF_ENABLED, IDM_NEWSESS, "Ne&w Session..."); AppendMenu(m, MF_ENABLED, IDM_DUPSESS, "&Duplicate Session"); s = CreateMenu(); - get_sesslist(TRUE); - for (i = 1; i < ((nsessions < 256) ? nsessions : 256); i++) + get_sesslist(&sesslist, TRUE); + for (i = 1; + i < ((sesslist.nsessions < 256) ? sesslist.nsessions : 256); + i++) AppendMenu(s, MF_ENABLED, IDM_SAVED_MIN + (16 * i), - sessions[i]); + sesslist.sessions[i]); AppendMenu(m, MF_POPUP | MF_ENABLED, (UINT) s, "Sa&ved Sessions"); AppendMenu(m, MF_ENABLED, IDM_RECONF, "Chan&ge Settings..."); AppendMenu(m, MF_SEPARATOR, 0, 0); @@ -643,9 +716,13 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) AppendMenu(m, MF_SEPARATOR, 0, 0); if (help_path) AppendMenu(m, MF_ENABLED, IDM_HELP, "&Help"); - AppendMenu(m, MF_ENABLED, IDM_ABOUT, "&About PuTTY"); + str = dupprintf("&About %s", appname); + AppendMenu(m, MF_ENABLED, IDM_ABOUT, str); + sfree(str); } + update_specials_menu(NULL); + /* * Set up the initial input locale. */ @@ -654,7 +731,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) /* * Open the initial log file if there is one. */ - logfopen(); + logfopen(logctx); /* * Finally show the window! @@ -669,7 +746,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) logpal = NULL; init_palette(); - has_focus = (GetForegroundWindow() == hwnd); + term->has_focus = (GetForegroundWindow() == hwnd); UpdateWindow(hwnd); if (GetMessage(&msg, NULL, 0, 0) == 1) { @@ -692,10 +769,10 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) DispatchMessage(&msg); /* Make sure we blink everything that needs it. */ - term_blink(0); + term_blink(term, 0); /* Send the paste buffer if there's anything to send */ - term_paste(); + term_paste(term); /* If there's nothing new in the queue then we can do everything * we've delayed, reading the socket, writing, and repainting @@ -707,9 +784,6 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) if (pending_netevent) { enact_pending_netevent(); - /* Force the cursor blink on */ - term_blink(1); - if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) continue; } @@ -723,20 +797,22 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) timer_id = 0; } HideCaret(hwnd); - if (GetCapture() != hwnd) - term_out(); - term_update(); + if (GetCapture() != hwnd || + (send_raw_mouse && + !(cfg.mouse_override && is_shift_pressed()))) + term_out(term); + term_update(term); ShowCaret(hwnd); flash_window(1); /* maintain */ /* The messages seem unreliable; especially if we're being tricky */ - has_focus = (GetForegroundWindow() == hwnd); + term->has_focus = (GetForegroundWindow() == hwnd); - if (in_vbell) + if (term->in_vbell) /* Hmm, term_update didn't want to do an update too soon ... */ timer_id = SetTimer(hwnd, 1, 50, NULL); - else if (!has_focus) + else if (!term->has_focus) timer_id = SetTimer(hwnd, 1, 500, NULL); else timer_id = SetTimer(hwnd, 1, 100, NULL); @@ -751,6 +827,15 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) } } + cleanup_exit(msg.wParam); /* this doesn't return... */ + return msg.wParam; /* ... but optimiser doesn't know */ +} + +/* + * Clean up and exit. + */ +void cleanup_exit(int code) +{ /* * Clean up. */ @@ -758,7 +843,9 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) sfree(logpal); if (pal) DeleteObject(pal); - WSACleanup(); + sk_cleanup(); + if (wsa_started) + WSACleanup(); if (cfg.protocol == PROT_SSH) { random_save_seed(); @@ -767,7 +854,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) #endif } - return msg.wParam; + exit(code); } /* @@ -797,10 +884,42 @@ char *do_select(SOCKET skt, int startup) } /* + * Update the Special Commands submenu. + */ +void update_specials_menu(void *frontend) +{ + HMENU m = GetSystemMenu(hwnd, FALSE); + int menu_already_exists = (specials != NULL); + int i; + + specials = back->get_specials(backhandle); + if (specials) { + HMENU p = CreateMenu(); + for (i = 0; specials[i].name; i++) { + assert(IDM_SPECIAL_MIN + 0x10 * i < IDM_SPECIAL_MAX); + if (*specials[i].name) + AppendMenu(p, MF_ENABLED, IDM_SPECIAL_MIN + 0x10 * i, + specials[i].name); + else + AppendMenu(p, MF_SEPARATOR, 0, 0); + } + if (menu_already_exists) + DeleteMenu(m, specials_menu_position, MF_BYPOSITION); + else + InsertMenu(m, specials_menu_position, + MF_BYPOSITION | MF_SEPARATOR, 0, 0); + InsertMenu(m, specials_menu_position, + MF_BYPOSITION | MF_POPUP | MF_ENABLED, + (UINT) p, "Special Command"); + } +} + +/* * set or clear the "raw mouse message" mode */ -void set_raw_mouse_mode(int activate) +void set_raw_mouse_mode(void *frontend, int activate) { + activate = activate && !cfg.no_mouse_rep; send_raw_mouse = activate; SetCursor(LoadCursor(NULL, activate ? IDC_ARROW : IDC_IBEAM)); } @@ -808,24 +927,46 @@ void set_raw_mouse_mode(int activate) /* * Print a message box and close the connection. */ -void connection_fatal(char *fmt, ...) +void connection_fatal(void *frontend, char *fmt, ...) { va_list ap; - char stuff[200]; + char *stuff, morestuff[100]; va_start(ap, fmt); - vsprintf(stuff, fmt, ap); + stuff = dupvprintf(fmt, ap); va_end(ap); - MessageBox(hwnd, stuff, "PuTTY Fatal Error", MB_ICONERROR | MB_OK); - if (cfg.close_on_exit == COE_ALWAYS) + sprintf(morestuff, "%.70s Fatal Error", appname); + MessageBox(hwnd, stuff, morestuff, MB_ICONERROR | MB_OK); + sfree(stuff); + + if (cfg.close_on_exit == FORCE_ON) PostQuitMessage(1); else { session_closed = TRUE; - SetWindowText(hwnd, "PuTTY (inactive)"); + sprintf(morestuff, "%.70s (inactive)", appname); + set_icon(NULL, morestuff); + set_title(NULL, morestuff); } } /* + * Report an error at the command-line parsing stage. + */ +void cmdline_error(char *fmt, ...) +{ + va_list ap; + char *stuff, morestuff[100]; + + va_start(ap, fmt); + stuff = dupvprintf(fmt, ap); + va_end(ap); + sprintf(morestuff, "%.70s Command Line Error", appname); + MessageBox(hwnd, stuff, morestuff, MB_ICONERROR | MB_OK); + sfree(stuff); + exit(1); +} + +/* * Actually do the job requested by a WM_NETEVENT */ static void enact_pending_netevent(void) @@ -846,13 +987,16 @@ static void enact_pending_netevent(void) if (ret == 0 && !session_closed) { /* Abnormal exits will already have set session_closed and taken * appropriate action. */ - if (cfg.close_on_exit == COE_ALWAYS || - cfg.close_on_exit == COE_NORMAL) PostQuitMessage(0); + if (cfg.close_on_exit == FORCE_ON || + cfg.close_on_exit == AUTO) PostQuitMessage(0); else { + char morestuff[100]; session_closed = TRUE; - SetWindowText(hwnd, "PuTTY (inactive)"); + sprintf(morestuff, "%.70s (inactive)", appname); + set_icon(NULL, morestuff); + set_title(NULL, morestuff); MessageBox(hwnd, "Connection closed by remote host", - "PuTTY", MB_OK | MB_ICONINFORMATION); + appname, MB_OK | MB_ICONINFORMATION); } } } @@ -887,6 +1031,10 @@ static void init_palette(void) HDC hdc = GetDC(hwnd); if (hdc) { if (cfg.try_palette && GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) { + /* + * This is a genuine case where we must use smalloc + * because the snew macros can't cope. + */ logpal = smalloc(sizeof(*logpal) - sizeof(logpal->palPalEntry) + NCOLOURS * sizeof(PALETTEENTRY)); @@ -950,7 +1098,7 @@ static void init_fonts(int pick_width, int pick_height) bold_mode = cfg.bold_colour ? BOLD_COLOURS : BOLD_FONT; und_mode = UND_FONT; - if (cfg.fontisbold) { + if (cfg.font.isbold) { fw_dontcare = FW_BOLD; fw_bold = FW_HEAVY; } else { @@ -963,7 +1111,7 @@ static void init_fonts(int pick_width, int pick_height) if (pick_height) font_height = pick_height; else { - font_height = cfg.fontheight; + font_height = cfg.font.height; if (font_height > 0) { font_height = -MulDiv(font_height, GetDeviceCaps(hdc, LOGPIXELSY), 72); @@ -975,9 +1123,9 @@ static void init_fonts(int pick_width, int pick_height) fonts[i] = CreateFont (font_height, font_width, 0, 0, w, FALSE, u, FALSE, \ c, OUT_DEFAULT_PRECIS, \ CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, \ - FIXED_PITCH | FF_DONTCARE, cfg.font) + FIXED_PITCH | FF_DONTCARE, cfg.font.name) - f(FONT_NORMAL, cfg.fontcharset, fw_dontcare, FALSE); + f(FONT_NORMAL, cfg.font.charset, fw_dontcare, FALSE); lfont.lfHeight = font_height; lfont.lfWidth = font_width; @@ -987,12 +1135,12 @@ static void init_fonts(int pick_width, int pick_height) lfont.lfItalic = FALSE; lfont.lfUnderline = FALSE; lfont.lfStrikeOut = FALSE; - lfont.lfCharSet = cfg.fontcharset; + 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, LF_FACESIZE); + strncpy(lfont.lfFaceName, cfg.font.name, LF_FACESIZE); SelectObject(hdc, fonts[FONT_NORMAL]); GetTextMetrics(hdc, &tm); @@ -1015,19 +1163,18 @@ static void init_fonts(int pick_width, int pick_height) /* !!! Yes the next line is right */ if (cset == OEM_CHARSET) - font_codepage = GetOEMCP(); + ucsdata.font_codepage = GetOEMCP(); else - if (TranslateCharsetInfo - ((DWORD *) cset, &info, TCI_SRCCHARSET)) font_codepage = - info.ciACP; + if (TranslateCharsetInfo ((DWORD *) cset, &info, TCI_SRCCHARSET)) + ucsdata.font_codepage = info.ciACP; else - font_codepage = -1; + ucsdata.font_codepage = -1; - GetCPInfo(font_codepage, &cpinfo); - dbcs_screenfont = (cpinfo.MaxCharSize > 1); + GetCPInfo(ucsdata.font_codepage, &cpinfo); + ucsdata.dbcs_screenfont = (cpinfo.MaxCharSize > 1); } - f(FONT_UNDERLINE, cfg.fontcharset, fw_dontcare, TRUE); + f(FONT_UNDERLINE, cfg.font.charset, fw_dontcare, TRUE); /* * Some fonts, e.g. 9-pt Courier, draw their underlines @@ -1078,7 +1225,7 @@ static void init_fonts(int pick_width, int pick_height) } if (bold_mode == BOLD_FONT) { - f(FONT_BOLD, cfg.fontcharset, fw_bold, FALSE); + f(FONT_BOLD, cfg.font.charset, fw_bold, FALSE); } #undef f @@ -1112,7 +1259,7 @@ static void init_fonts(int pick_width, int pick_height) } fontflag[0] = fontflag[1] = fontflag[2] = 1; - init_ucs_tables(); + init_ucs(&cfg, &ucsdata); } static void another_font(int fontno) @@ -1129,7 +1276,7 @@ static void another_font(int fontno) if (basefont != fontno && !fontflag[basefont]) another_font(basefont); - if (cfg.fontisbold) { + if (cfg.font.isbold) { fw_dontcare = FW_BOLD; fw_bold = FW_HEAVY; } else { @@ -1137,10 +1284,10 @@ static void another_font(int fontno) fw_bold = FW_BOLD; } - c = cfg.fontcharset; + c = cfg.font.charset; w = fw_dontcare; u = FALSE; - s = cfg.font; + s = cfg.font.name; x = font_width; if (fontno & FONT_WIDE) @@ -1174,7 +1321,7 @@ static void deinit_fonts(void) } } -void request_resize(int w, int h) +void request_resize(void *frontend, int w, int h) { int width, height; @@ -1185,7 +1332,7 @@ void request_resize(int w, int h) } if (cfg.resize_action == RESIZE_DISABLED) return; - if (h == rows && w == cols) return; + if (h == term->rows && w == term->cols) return; /* Sanity checks ... */ { @@ -1195,7 +1342,7 @@ void request_resize(int w, int h) switch (first_time) { case 1: /* Get the size of the screen */ - if (GetClientRect(GetDesktopWindow(), &ss)) + if (get_fullscreen_rect(&ss)) /* first_time = 0 */ ; else { first_time = 2; @@ -1215,7 +1362,7 @@ void request_resize(int w, int h) } } - term_size(h, w, cfg.savelines); + term_size(term, h, w, cfg.savelines); if (cfg.resize_action != RESIZE_FONT && !IsZoomed(hwnd)) { width = extra_width + font_width * w; @@ -1269,10 +1416,10 @@ static void reset_window(int reinit) { /* Is the window out of position ? */ if ( !reinit && - (offset_width != (win_width-font_width*cols)/2 || - offset_height != (win_height-font_height*rows)/2) ){ - offset_width = (win_width-font_width*cols)/2; - offset_height = (win_height-font_height*rows)/2; + (offset_width != (win_width-font_width*term->cols)/2 || + offset_height != (win_height-font_height*term->rows)/2) ){ + offset_width = (win_width-font_width*term->cols)/2; + offset_height = (win_height-font_height*term->rows)/2; InvalidateRect(hwnd, NULL, TRUE); #ifdef RDB_DEBUG_PATCH debug((27, "reset_window() -> Reposition terminal")); @@ -1288,12 +1435,12 @@ static void reset_window(int reinit) { extra_height = wr.bottom - wr.top - cr.bottom + cr.top; if (cfg.resize_action != RESIZE_TERM) { - if ( font_width != win_width/cols || - font_height != win_height/rows) { + if ( font_width != win_width/term->cols || + font_height != win_height/term->rows) { deinit_fonts(); - init_fonts(win_width/cols, win_height/rows); - offset_width = (win_width-font_width*cols)/2; - offset_height = (win_height-font_height*rows)/2; + init_fonts(win_width/term->cols, win_height/term->rows); + offset_width = (win_width-font_width*term->cols)/2; + offset_height = (win_height-font_height*term->rows)/2; InvalidateRect(hwnd, NULL, TRUE); #ifdef RDB_DEBUG_PATCH debug((25, "reset_window() -> Z font resize to (%d, %d)", @@ -1301,15 +1448,15 @@ static void reset_window(int reinit) { #endif } } else { - if ( font_width != win_width/cols || - font_height != win_height/rows) { + if ( font_width != win_width/term->cols || + font_height != win_height/term->rows) { /* Our only choice at this point is to change the * size of the terminal; Oh well. */ - term_size( win_height/font_height, win_width/font_width, - cfg.savelines); - offset_width = (win_width-font_width*cols)/2; - offset_height = (win_height-font_height*rows)/2; + term_size(term, win_height/font_height, win_width/font_width, + cfg.savelines); + offset_width = (win_width-font_width*term->cols)/2; + offset_height = (win_height-font_height*term->rows)/2; InvalidateRect(hwnd, NULL, TRUE); #ifdef RDB_DEBUG_PATCH debug((27, "reset_window() -> Zoomed term_size")); @@ -1331,16 +1478,16 @@ static void reset_window(int reinit) { extra_width = wr.right - wr.left - cr.right + cr.left + offset_width*2; extra_height = wr.bottom - wr.top - cr.bottom + cr.top +offset_height*2; - if (win_width != font_width*cols + offset_width*2 || - win_height != font_height*rows + offset_height*2) { + if (win_width != font_width*term->cols + offset_width*2 || + win_height != font_height*term->rows + offset_height*2) { /* If this is too large windows will resize it to the maximum * allowed window size, we will then be back in here and resize * the font or terminal to fit. */ SetWindowPos(hwnd, NULL, 0, 0, - font_width*cols + extra_width, - font_height*rows + extra_height, + font_width*term->cols + extra_width, + font_height*term->rows + extra_height, SWP_NOMOVE | SWP_NOZORDER); } @@ -1359,24 +1506,27 @@ static void reset_window(int reinit) { extra_width = wr.right - wr.left - cr.right + cr.left + offset_width*2; extra_height = wr.bottom - wr.top - cr.bottom + cr.top +offset_height*2; - if (win_width != font_width*cols + offset_width*2 || - win_height != font_height*rows + offset_height*2) { + if (win_width != font_width*term->cols + offset_width*2 || + win_height != font_height*term->rows + offset_height*2) { static RECT ss; int width, height; + + get_fullscreen_rect(&ss); - GetClientRect(GetDesktopWindow(), &ss); width = (ss.right - ss.left - extra_width) / font_width; height = (ss.bottom - ss.top - extra_height) / font_height; /* Grrr too big */ - if ( rows > height || cols > width ) { + if ( term->rows > height || term->cols > width ) { if (cfg.resize_action == RESIZE_EITHER) { /* Make the font the biggest we can */ - if (cols > width) - font_width = (ss.right - ss.left - extra_width)/cols; - if (rows > height) - font_height = (ss.bottom - ss.top - extra_height)/rows; + if (term->cols > width) + font_width = (ss.right - ss.left - extra_width) + / term->cols; + if (term->rows > height) + font_height = (ss.bottom - ss.top - extra_height) + / term->rows; deinit_fonts(); init_fonts(font_width, font_height); @@ -1384,9 +1534,9 @@ static void reset_window(int reinit) { width = (ss.right - ss.left - extra_width) / font_width; height = (ss.bottom - ss.top - extra_height) / font_height; } else { - if ( height > rows ) height = rows; - if ( width > cols ) width = cols; - term_size(height, width, cfg.savelines); + if ( height > term->rows ) height = term->rows; + if ( width > term->cols ) width = term->cols; + term_size(term, height, width, cfg.savelines); #ifdef RDB_DEBUG_PATCH debug((27, "reset_window() -> term resize to (%d,%d)", height, width)); @@ -1395,15 +1545,15 @@ static void reset_window(int reinit) { } SetWindowPos(hwnd, NULL, 0, 0, - font_width*cols + extra_width, - font_height*rows + extra_height, + font_width*term->cols + extra_width, + font_height*term->rows + extra_height, SWP_NOMOVE | SWP_NOZORDER); InvalidateRect(hwnd, NULL, TRUE); #ifdef RDB_DEBUG_PATCH debug((27, "reset_window() -> window resize to (%d,%d)", - font_width*cols + extra_width, - font_height*rows + extra_height)); + font_width*term->cols + extra_width, + font_height*term->rows + extra_height)); #endif } return; @@ -1411,14 +1561,14 @@ static void reset_window(int reinit) { /* We're allowed to or must change the font but do we want to ? */ - if (font_width != (win_width-cfg.window_border*2)/cols || - font_height != (win_height-cfg.window_border*2)/rows) { + if (font_width != (win_width-cfg.window_border*2)/term->cols || + font_height != (win_height-cfg.window_border*2)/term->rows) { deinit_fonts(); - init_fonts((win_width-cfg.window_border*2)/cols, - (win_height-cfg.window_border*2)/rows); - offset_width = (win_width-font_width*cols)/2; - offset_height = (win_height-font_height*rows)/2; + init_fonts((win_width-cfg.window_border*2)/term->cols, + (win_height-cfg.window_border*2)/term->rows); + offset_width = (win_width-font_width*term->cols)/2; + offset_height = (win_height-font_height*term->rows)/2; extra_width = wr.right - wr.left - cr.right + cr.left +offset_width*2; extra_height = wr.bottom - wr.top - cr.bottom + cr.top+offset_height*2; @@ -1447,7 +1597,8 @@ static void click(Mouse_Button b, int x, int y, int shift, int ctrl, int alt) if (send_raw_mouse && !(cfg.mouse_override && shift)) { lastbtn = MBT_NOTHING; - term_mouse(b, MA_CLICK, x, y, shift, ctrl, alt); + term_mouse(term, b, translate_button(b), MA_CLICK, + x, y, shift, ctrl, alt); return; } @@ -1460,7 +1611,8 @@ static void click(Mouse_Button b, int x, int y, int shift, int ctrl, int alt) lastact = MA_CLICK; } if (lastact != MA_NOTHING) - term_mouse(b, lastact, x, y, shift, ctrl, alt); + term_mouse(term, b, translate_button(b), lastact, + x, y, shift, ctrl, alt); lasttime = thistime; } @@ -1468,7 +1620,7 @@ static void click(Mouse_Button b, int x, int y, int shift, int ctrl, int alt) * Translate a raw mouse button designation (LEFT, MIDDLE, RIGHT) * into a cooked one (SELECT, EXTEND, PASTE). */ -Mouse_Button translate_button(Mouse_Button button) +static Mouse_Button translate_button(Mouse_Button button) { if (button == MBT_LEFT) return MBT_SELECT; @@ -1504,6 +1656,17 @@ static int is_alt_pressed(void) return FALSE; } +static int is_shift_pressed(void) +{ + BYTE keystate[256]; + int r = GetKeyboardState(keystate); + if (!r) + return FALSE; + if (keystate[VK_SHIFT] & 0x80) + return TRUE; + return FALSE; +} + static int resizing; static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, @@ -1518,17 +1681,18 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, case WM_TIMER: if (pending_netevent) enact_pending_netevent(); - if (GetCapture() != hwnd) - term_out(); + if (GetCapture() != hwnd || + (send_raw_mouse && !(cfg.mouse_override && is_shift_pressed()))) + term_out(term); noise_regular(); HideCaret(hwnd); - term_update(); + term_update(term); ShowCaret(hwnd); if (cfg.ping_interval > 0) { time_t now; time(&now); if (now - last_movement > cfg.ping_interval) { - back->special(TS_PING); + back->special(backhandle, TS_PING); last_movement = now; } } @@ -1537,13 +1701,17 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, case WM_CREATE: break; case WM_CLOSE: - show_mouseptr(1); - if (!cfg.warn_on_close || session_closed || - MessageBox(hwnd, - "Are you sure you want to close this session?", - "PuTTY Exit Confirmation", - MB_ICONWARNING | MB_OKCANCEL) == IDOK) - DestroyWindow(hwnd); + { + char *str; + show_mouseptr(1); + str = dupprintf("%s Exit Confirmation", appname); + if (!cfg.warn_on_close || session_closed || + MessageBox(hwnd, + "Are you sure you want to close this session?", + str, MB_ICONWARNING | MB_OKCANCEL) == IDOK) + DestroyWindow(hwnd); + sfree(str); + } return 0; case WM_DESTROY: show_mouseptr(1); @@ -1592,10 +1760,10 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, sprintf(c, "putty &%p", filemap); cl = c; } else if (wParam == IDM_SAVEDSESS) { - if ((lParam - IDM_SAVED_MIN) / 16 < nsessions) { + if ((lParam - IDM_SAVED_MIN) / 16 < sesslist.nsessions) { char *session = - sessions[(lParam - IDM_SAVED_MIN) / 16]; - cl = smalloc(16 + strlen(session)); + sesslist.sessions[(lParam - IDM_SAVED_MIN) / 16]; + cl = snewn(16 + strlen(session), char); /* 8, but play safe */ if (!cl) cl = NULL; @@ -1650,18 +1818,15 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, } } - if (strcmp(prev_cfg.logfilename, cfg.logfilename) || - prev_cfg.logtype != cfg.logtype) { - logfclose(); /* reset logging */ - logfopen(); - } + /* Pass new config data to the logging module */ + log_reconfig(logctx, &cfg); sfree(logpal); /* * Flush the line discipline's edit buffer in the * case where local editing has just been disabled. */ - ldisc_send(NULL, 0, 0); + ldisc_send(ldisc, NULL, 0, 0); if (pal) DeleteObject(pal); logpal = NULL; @@ -1669,6 +1834,12 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, cfgtopalette(); init_palette(); + /* Pass new config data to the terminal */ + term_reconfig(term, &cfg); + + /* Pass new config data to the back end */ + back->reconfig(backhandle, &cfg); + /* Screen size changed ? */ if (cfg.height != prev_cfg.height || cfg.width != prev_cfg.width || @@ -1676,7 +1847,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, cfg.resize_action == RESIZE_FONT || (cfg.resize_action == RESIZE_EITHER && IsZoomed(hwnd)) || cfg.resize_action == RESIZE_DISABLED) - term_size(cfg.height, cfg.width, cfg.savelines); + term_size(term, cfg.height, cfg.width, cfg.savelines); /* Enable or disable the scroll bar, etc */ { @@ -1740,18 +1911,18 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, init_lvl = 2; } - set_title(cfg.wintitle); + set_title(NULL, cfg.wintitle); if (IsIconic(hwnd)) { SetWindowText(hwnd, cfg.win_name_always ? window_name : icon_name); } - if (strcmp(cfg.font, prev_cfg.font) != 0 || + if (strcmp(cfg.font.name, prev_cfg.font.name) != 0 || strcmp(cfg.line_codepage, prev_cfg.line_codepage) != 0 || - cfg.fontisbold != prev_cfg.fontisbold || - cfg.fontheight != prev_cfg.fontheight || - cfg.fontcharset != prev_cfg.fontcharset || + cfg.font.isbold != prev_cfg.font.isbold || + cfg.font.height != prev_cfg.font.height || + cfg.font.charset != prev_cfg.font.charset || cfg.vtmode != prev_cfg.vtmode || cfg.bold_colour != prev_cfg.bold_colour || cfg.resize_action == RESIZE_DISABLED || @@ -1765,65 +1936,14 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, } break; case IDM_COPYALL: - term_copyall(); + term_copyall(term); break; case IDM_CLRSB: - term_clrsb(); + term_clrsb(term); break; case IDM_RESET: - term_pwron(); - break; - case IDM_TEL_AYT: - back->special(TS_AYT); - net_pending_errors(); - break; - case IDM_TEL_BRK: - back->special(TS_BRK); - net_pending_errors(); - break; - case IDM_TEL_SYNCH: - back->special(TS_SYNCH); - net_pending_errors(); - break; - case IDM_TEL_EC: - back->special(TS_EC); - net_pending_errors(); - break; - case IDM_TEL_EL: - back->special(TS_EL); - net_pending_errors(); - break; - case IDM_TEL_GA: - back->special(TS_GA); - net_pending_errors(); - break; - case IDM_TEL_NOP: - back->special(TS_NOP); - net_pending_errors(); - break; - case IDM_TEL_ABORT: - back->special(TS_ABORT); - net_pending_errors(); - break; - case IDM_TEL_AO: - back->special(TS_AO); - net_pending_errors(); - break; - case IDM_TEL_IP: - back->special(TS_IP); - net_pending_errors(); - break; - case IDM_TEL_SUSP: - back->special(TS_SUSP); - net_pending_errors(); - break; - case IDM_TEL_EOR: - back->special(TS_EOR); - net_pending_errors(); - break; - case IDM_TEL_EOF: - back->special(TS_EOF); - net_pending_errors(); + term_pwron(term); + ldisc_send(ldisc, NULL, 0, 0); break; case IDM_ABOUT: showabout(hwnd); @@ -1859,6 +1979,22 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, if (wParam >= IDM_SAVED_MIN && wParam <= IDM_SAVED_MAX) { SendMessage(hwnd, WM_SYSCOMMAND, IDM_SAVEDSESS, wParam); } + if (wParam >= IDM_SPECIAL_MIN && wParam <= IDM_SPECIAL_MAX) { + int i = (wParam - IDM_SPECIAL_MIN) / 0x10; + int j; + /* + * Ensure we haven't been sent a bogus SYSCOMMAND + * which would cause us to reference invalid memory + * and crash. Perhaps I'm just too paranoid here. + */ + for (j = 0; j < i; j++) + if (!specials || !specials[j].name) + break; + if (j == i) { + back->special(backhandle, specials[i].code); + net_pending_errors(); + } + } } break; @@ -1923,7 +2059,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, is_alt_pressed()); SetCapture(hwnd); } else { - term_mouse(button, MA_RELEASE, + term_mouse(term, button, translate_button(button), MA_RELEASE, TO_CHR_X(X_POS(lParam)), TO_CHR_Y(Y_POS(lParam)), wParam & MK_SHIFT, wParam & MK_CONTROL, is_alt_pressed()); @@ -1948,7 +2084,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, b = MBT_MIDDLE; else b = MBT_RIGHT; - term_mouse(b, MA_DRAG, TO_CHR_X(X_POS(lParam)), + term_mouse(term, b, translate_button(b), MA_DRAG, + TO_CHR_X(X_POS(lParam)), TO_CHR_Y(Y_POS(lParam)), wParam & MK_SHIFT, wParam & MK_CONTROL, is_alt_pressed()); } @@ -1962,7 +2099,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, break; case WM_DESTROYCLIPBOARD: if (!ignore_clip) - term_deselect(); + term_deselect(term); ignore_clip = FALSE; return 0; case WM_PAINT: @@ -1974,17 +2111,18 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, SelectPalette(hdc, pal, TRUE); RealizePalette(hdc); } - term_paint(hdc, + 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); + (p.rcPaint.bottom-offset_height-1)/font_height, + is_alt_pressed()); if (p.fErase || p.rcPaint.left < offset_width || p.rcPaint.top < offset_height || - p.rcPaint.right >= offset_width + font_width*cols || - p.rcPaint.bottom>= offset_height + font_height*rows) + p.rcPaint.right >= offset_width + font_width*term->cols || + p.rcPaint.bottom>= offset_height + font_height*term->rows) { HBRUSH fillcolour, oldbrush; HPEN edge, oldpen; @@ -1995,10 +2133,21 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, colours[(ATTR_DEFBG>>ATTR_BGSHIFT)*2]); oldpen = SelectObject(hdc, edge); + /* + * Jordan Russell reports that this apparently + * ineffectual IntersectClipRect() call masks a + * Windows NT/2K bug causing strange display + * problems when the PuTTY window is taller than + * the primary monitor. It seems harmless enough... + */ + IntersectClipRect(hdc, + p.rcPaint.left, p.rcPaint.top, + p.rcPaint.right, p.rcPaint.bottom); + ExcludeClipRect(hdc, offset_width, offset_height, - offset_width+font_width*cols, - offset_height+font_height*rows); + offset_width+font_width*term->cols, + offset_height+font_height*term->rows); Rectangle(hdc, p.rcPaint.left, p.rcPaint.top, p.rcPaint.right, p.rcPaint.bottom); @@ -2033,21 +2182,21 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, time(&last_movement); return 0; case WM_SETFOCUS: - has_focus = TRUE; + term->has_focus = TRUE; CreateCaret(hwnd, caretbm, font_width, font_height); ShowCaret(hwnd); flash_window(0); /* stop */ compose_state = 0; - term_out(); - term_update(); + term_out(term); + term_update(term); break; case WM_KILLFOCUS: show_mouseptr(1); - has_focus = FALSE; + term->has_focus = FALSE; DestroyCaret(); caret_x = caret_y = -1; /* ensure caret is replaced next time */ - term_out(); - term_update(); + term_out(term); + term_update(term); break; case WM_ENTERSIZEMOVE: #ifdef RDB_DEBUG_PATCH @@ -2064,7 +2213,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, debug((27, "WM_EXITSIZEMOVE")); #endif if (need_backend_resize) { - term_size(cfg.height, cfg.width, cfg.savelines); + term_size(term, cfg.height, cfg.width, cfg.savelines); InvalidateRect(hwnd, NULL, TRUE); } break; @@ -2074,12 +2223,12 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, * 1) Keep the sizetip uptodate * 2) Make sure the window size is _stepped_ in units of the font size. */ - if (cfg.resize_action != RESIZE_FONT && !alt_pressed) { + if (cfg.resize_action != RESIZE_FONT && !is_alt_pressed()) { int width, height, w, h, ew, eh; LPRECT r = (LPRECT) lParam; if ( !need_backend_resize && cfg.resize_action == RESIZE_EITHER && - (cfg.height != rows || cfg.width != cols )) { + (cfg.height != term->rows || cfg.width != term->cols )) { /* * Great! It seems that both the terminal size and the * font size have been changed and the user is now dragging. @@ -2089,10 +2238,10 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, * * This would be easier but it seems to be too confusing. - term_size(cfg.height, cfg.width, cfg.savelines); + term_size(term, cfg.height, cfg.width, cfg.savelines); reset_window(2); */ - cfg.height=rows; cfg.width=cols; + cfg.height=term->rows; cfg.width=term->cols; InvalidateRect(hwnd, NULL, TRUE); need_backend_resize = TRUE; @@ -2136,25 +2285,25 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, width = r->right - r->left - ex_width; height = r->bottom - r->top - ex_height; - w = (width + cols/2)/cols; - h = (height + rows/2)/rows; - if ( r->right != r->left + w*cols + ex_width) + w = (width + term->cols/2)/term->cols; + h = (height + term->rows/2)/term->rows; + if ( r->right != r->left + w*term->cols + ex_width) rv = 1; if (wParam == WMSZ_LEFT || wParam == WMSZ_BOTTOMLEFT || wParam == WMSZ_TOPLEFT) - r->left = r->right - w*cols - ex_width; + r->left = r->right - w*term->cols - ex_width; else - r->right = r->left + w*cols + ex_width; + r->right = r->left + w*term->cols + ex_width; - if (r->bottom != r->top + h*rows + ex_height) + if (r->bottom != r->top + h*term->rows + ex_height) rv = 1; if (wParam == WMSZ_TOP || wParam == WMSZ_TOPRIGHT || wParam == WMSZ_TOPLEFT) - r->top = r->bottom - h*rows - ex_height; + r->top = r->bottom - h*term->rows - ex_height; else - r->bottom = r->top + h*rows + ex_height; + r->bottom = r->top + h*term->rows + ex_height; return rv; } @@ -2183,8 +2332,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, if (wParam == SIZE_RESTORED) clear_full_screen(); if (wParam == SIZE_MAXIMIZED && fullscr_on_max) { - make_full_screen(); fullscr_on_max = FALSE; + make_full_screen(); } if (cfg.resize_action == RESIZE_DISABLED) { @@ -2200,21 +2349,21 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, if (!resizing) { if (wParam == SIZE_MAXIMIZED && !was_zoomed) { was_zoomed = 1; - prev_rows = rows; - prev_cols = cols; + prev_rows = term->rows; + prev_cols = term->cols; if (cfg.resize_action == RESIZE_TERM) { w = width / font_width; if (w < 1) w = 1; h = height / font_height; if (h < 1) h = 1; - term_size(h, w, cfg.savelines); + term_size(term, h, w, cfg.savelines); } reset_window(0); } else if (wParam == SIZE_RESTORED && was_zoomed) { was_zoomed = 0; if (cfg.resize_action == RESIZE_TERM) - term_size(prev_rows, prev_cols, cfg.savelines); + term_size(term, prev_rows, prev_cols, cfg.savelines); if (cfg.resize_action != RESIZE_FONT) reset_window(2); else @@ -2235,7 +2384,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, * down the connection during an NT opaque drag.) */ if (resizing) { - if (cfg.resize_action != RESIZE_FONT && !alt_pressed) { + if (cfg.resize_action != RESIZE_FONT && !is_alt_pressed()) { need_backend_resize = TRUE; w = (width-cfg.window_border*2) / font_width; if (w < 1) w = 1; @@ -2253,32 +2402,32 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, case WM_VSCROLL: switch (LOWORD(wParam)) { case SB_BOTTOM: - term_scroll(-1, 0); + term_scroll(term, -1, 0); break; case SB_TOP: - term_scroll(+1, 0); + term_scroll(term, +1, 0); break; case SB_LINEDOWN: - term_scroll(0, +1); + term_scroll(term, 0, +1); break; case SB_LINEUP: - term_scroll(0, -1); + term_scroll(term, 0, -1); break; case SB_PAGEDOWN: - term_scroll(0, +rows / 2); + term_scroll(term, 0, +term->rows / 2); break; case SB_PAGEUP: - term_scroll(0, -rows / 2); + term_scroll(term, 0, -term->rows / 2); break; case SB_THUMBPOSITION: case SB_THUMBTRACK: - term_scroll(1, HIWORD(wParam)); + term_scroll(term, 1, HIWORD(wParam)); break; } break; case WM_PALETTECHANGED: if ((HWND) wParam != hwnd && pal != NULL) { - HDC hdc = get_ctx(); + HDC hdc = get_ctx(NULL); if (hdc) { if (RealizePalette(hdc) > 0) UpdateColors(hdc); @@ -2288,7 +2437,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, break; case WM_QUERYNEWPALETTE: if (pal != NULL) { - HDC hdc = get_ctx(); + HDC hdc = get_ctx(NULL); if (hdc) { if (RealizePalette(hdc) > 0) UpdateColors(hdc); @@ -2337,7 +2486,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, * preferable to having to faff about buffering * things. */ - term_nopaste(); + term_nopaste(term); /* * We need not bother about stdin backlogs @@ -2347,7 +2496,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, * messages. We _have_ to buffer everything * we're sent. */ - ldisc_send(buf, len, 1); + term_seen_key_event(term); + ldisc_send(ldisc, buf, len, 1); show_mouseptr(0); } } @@ -2385,7 +2535,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, if (n > 0) { int i; - buff = (char*) smalloc(n); + buff = snewn(n, char); ImmGetCompositionStringW(hIMC, GCS_RESULTSTR, buff, n); /* * Jaeyoun Chung reports that Korean character @@ -2393,8 +2543,10 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, * luni_send() covering the whole of buff. So * instead we luni_send the characters one by one. */ - for (i = 0; i < n; i += 2) - luni_send((unsigned short *)(buff+i), 1, 1); + term_seen_key_event(term); + for (i = 0; i < n; i += 2) { + luni_send(ldisc, (unsigned short *)(buff+i), 1, 1); + } free(buff); } ImmReleaseContext(hwnd, hIMC); @@ -2407,10 +2559,12 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, buf[1] = wParam; buf[0] = wParam >> 8; - lpage_send(kbd_codepage, buf, 2, 1); + term_seen_key_event(term); + lpage_send(ldisc, kbd_codepage, buf, 2, 1); } else { char c = (unsigned char) wParam; - lpage_send(kbd_codepage, &c, 1, 1); + term_seen_key_event(term); + lpage_send(ldisc, kbd_codepage, &c, 1, 1); } return (0); case WM_CHAR: @@ -2423,7 +2577,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, */ { char c = (unsigned char)wParam; - lpage_send(CP_ACP, &c, 1, 1); + term_seen_key_event(term); + lpage_send(ldisc, CP_ACP, &c, 1, 1); } return 0; case WM_SETCURSOR: @@ -2431,9 +2586,17 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, SetCursor(LoadCursor(NULL, IDC_ARROW)); return TRUE; } + break; + case WM_AGENT_CALLBACK: + { + struct agent_callback *c = (struct agent_callback *)lParam; + c->callback(c->callback_ctx, c->data, c->len); + sfree(c); + } + return 0; default: - if (message == wm_mousewheel) { - int shift_pressed=0, control_pressed=0, alt_pressed=0; + if (message == wm_mousewheel || message == WM_MOUSEWHEEL) { + int shift_pressed=0, control_pressed=0; if (message == WM_MOUSEWHEEL) { wheel_accumulator += (short)HIWORD(wParam); @@ -2465,18 +2628,20 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, if (send_raw_mouse && !(cfg.mouse_override && shift_pressed)) { /* send a mouse-down followed by a mouse up */ - term_mouse(b, + term_mouse(term, b, translate_button(b), MA_CLICK, TO_CHR_X(X_POS(lParam)), TO_CHR_Y(Y_POS(lParam)), shift_pressed, control_pressed, is_alt_pressed()); - term_mouse(b, MA_RELEASE, TO_CHR_X(X_POS(lParam)), + term_mouse(term, b, translate_button(b), + MA_RELEASE, TO_CHR_X(X_POS(lParam)), TO_CHR_Y(Y_POS(lParam)), shift_pressed, control_pressed, is_alt_pressed()); } else { /* trigger a scroll */ - term_scroll(0, - b == MBT_WHEEL_UP ? -rows / 2 : rows / 2); + term_scroll(term, 0, + b == MBT_WHEEL_UP ? + -term->rows / 2 : term->rows / 2); } } return 0; @@ -2492,11 +2657,11 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, * helper software tracks the system caret, so we should arrange to * have one.) */ -void sys_cursor(int x, int y) +void sys_cursor(void *frontend, int x, int y) { int cx, cy; - if (!has_focus) return; + if (!term->has_focus) return; /* * Avoid gratuitously re-updating the cursor position and IMM @@ -2517,7 +2682,7 @@ static void sys_cursor_update(void) COMPOSITIONFORM cf; HIMC hIMC; - if (!has_focus) return; + if (!term->has_focus) return; if (caret_x < 0 || caret_y < 0) return; @@ -2566,7 +2731,7 @@ void do_text(Context ctx, int x, int y, char *text, int len, int i; if (len > IpDxLEN) { sfree(IpDx); - IpDx = smalloc((len + 16) * sizeof(int)); + IpDx = snewn(len + 16, int); IpDxLEN = (len + 16); } for (i = 0; i < IpDxLEN; i++) @@ -2574,7 +2739,7 @@ void do_text(Context ctx, int x, int y, char *text, int len, } /* Only want the left half of double width lines */ - if (lattr != LATTR_NORM && x*2 >= cols) + if (lattr != LATTR_NORM && x*2 >= term->cols) return; x *= fnt_width; @@ -2582,7 +2747,7 @@ void do_text(Context ctx, int x, int y, char *text, int len, x += offset_width; y += offset_height; - if ((attr & TATTR_ACTCURS) && (cfg.cursor_type == 0 || big_cursor)) { + if ((attr & TATTR_ACTCURS) && (cfg.cursor_type == 0 || term->big_cursor)) { attr &= ATTR_CUR_AND | (bold_mode != BOLD_COLOURS ? ATTR_BOLD : 0); attr ^= ATTR_CUR_XOR; } @@ -2625,8 +2790,8 @@ void do_text(Context ctx, int x, int y, char *text, int len, if (lattr == LATTR_TOP || lattr == LATTR_BOT) text_adjust *= 2; attr &= ~CSET_MASK; - text[0] = (char) (unitab_xterm['q'] & CHAR_MASK); - attr |= (unitab_xterm['q'] & CSET_MASK); + text[0] = (char) (ucsdata.unitab_xterm['q'] & CHAR_MASK); + attr |= (ucsdata.unitab_xterm['q'] & CSET_MASK); if (attr & ATTR_UNDER) { attr &= ~ATTR_UNDER; force_manual_underline = 1; @@ -2645,8 +2810,10 @@ void do_text(Context ctx, int x, int y, char *text, int len, if ((attr & CSET_MASK) == ATTR_OEMCP) nfont |= FONT_OEM; - nfg = 2 * ((attr & ATTR_FGMASK) >> ATTR_FGSHIFT); - nbg = 2 * ((attr & ATTR_BGMASK) >> ATTR_BGSHIFT); + nfg = ((attr & ATTR_FGMASK) >> ATTR_FGSHIFT); + nfg = 2 * (nfg & 0xF) + (nfg & 0x10 ? 1 : 0); + nbg = ((attr & ATTR_BGMASK) >> ATTR_BGSHIFT); + nbg = 2 * (nbg & 0xF) + (nbg & 0x10 ? 1 : 0); if (bold_mode == BOLD_FONT && (attr & ATTR_BOLD)) nfont |= FONT_BOLD; if (und_mode == UND_FONT && (attr & ATTR_UNDER)) @@ -2668,9 +2835,9 @@ void do_text(Context ctx, int x, int y, char *text, int len, nbg = t; } if (bold_mode == BOLD_COLOURS && (attr & ATTR_BOLD)) - nfg++; + nfg |= 1; if (bold_mode == BOLD_COLOURS && (attr & ATTR_BLINK)) - nbg++; + nbg |= 1; fg = colours[nfg]; bg = colours[nbg]; SelectObject(hdc, fonts[nfont]); @@ -2683,11 +2850,11 @@ void do_text(Context ctx, int x, int y, char *text, int len, line_box.bottom = y + font_height; /* Only want the left half of double width lines */ - if (line_box.right > font_width*cols+offset_width) - line_box.right = font_width*cols+offset_width; + if (line_box.right > font_width*term->cols+offset_width) + line_box.right = font_width*term->cols+offset_width; /* We're using a private area for direct to font. (512 chars.) */ - if (dbcs_screenfont && (attr & CSET_MASK) == ATTR_ACP) { + if (ucsdata.dbcs_screenfont && (attr & CSET_MASK) == ATTR_ACP) { /* Ho Hum, dbcs fonts are a PITA! */ /* To display on W9x I have to convert to UCS */ static wchar_t *uni_buf = 0; @@ -2695,20 +2862,21 @@ void do_text(Context ctx, int x, int y, char *text, int len, int nlen, mptr; if (len > uni_len) { sfree(uni_buf); - uni_buf = smalloc((uni_len = len) * sizeof(wchar_t)); + uni_len = len; + uni_buf = snewn(uni_len, wchar_t); } for(nlen = mptr = 0; mptrbig_cursor)) { if (((attr & CSET_MASK) | (unsigned char) *text) != UCSWIDE) { do_text(ctx, x, y, text, len, attr, lattr); return; @@ -2815,7 +2983,7 @@ void do_cursor(Context ctx, int x, int y, char *text, int len, x += offset_width; y += offset_height; - if ((attr & TATTR_PASCURS) && (ctype == 0 || big_cursor)) { + if ((attr & TATTR_PASCURS) && (ctype == 0 || term->big_cursor)) { POINT pts[5]; HPEN oldpen; pts[0].x = pts[1].x = pts[4].x = x; @@ -2866,7 +3034,7 @@ void do_cursor(Context ctx, int x, int y, char *text, int len, /* This function gets the actual width of a character in the normal font. */ -int CharWidth(Context ctx, int uc) { +int char_width(Context ctx, int uc) { HDC hdc = ctx; int ibuf = 0; @@ -2877,17 +3045,17 @@ int CharWidth(Context ctx, int uc) { switch (uc & CSET_MASK) { case ATTR_ASCII: - uc = unitab_line[uc & 0xFF]; + uc = ucsdata.unitab_line[uc & 0xFF]; break; case ATTR_LINEDRW: - uc = unitab_xterm[uc & 0xFF]; + uc = ucsdata.unitab_xterm[uc & 0xFF]; break; case ATTR_SCOACS: - uc = unitab_scoacs[uc & 0xFF]; + uc = ucsdata.unitab_scoacs[uc & 0xFF]; break; } if (DIRECT_FONT(uc)) { - if (dbcs_screenfont) return 1; + if (ucsdata.dbcs_screenfont) return 1; /* Speedup, I know of no font where ascii is the wrong width */ if ((uc&CHAR_MASK) >= ' ' && (uc&CHAR_MASK)<= '~') @@ -3031,7 +3199,8 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, /* Nastyness with NUMLock - Shift-NUMLock is left alone though */ if ((cfg.funky_type == 3 || - (cfg.funky_type <= 1 && app_keypad_keys && !cfg.no_applic_k)) + (cfg.funky_type <= 1 && term->app_keypad_keys && + !cfg.no_applic_k)) && wParam == VK_NUMLOCK && !(keystate[VK_SHIFT] & 0x80)) { wParam = VK_EXECUTE; @@ -3046,7 +3215,8 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, } /* Disable Auto repeat if required */ - if (repeat_off && (HIWORD(lParam) & (KF_UP | KF_REPEAT)) == KF_REPEAT) + if (term->repeat_off && + (HIWORD(lParam) & (KF_UP | KF_REPEAT)) == KF_REPEAT) return 0; if ((HIWORD(lParam) & KF_ALTDOWN) && (keystate[VK_RMENU] & 0x80) == 0) @@ -3064,8 +3234,6 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, } } - alt_pressed = (left_alt && key_down); - scan = (HIWORD(lParam) & (KF_UP | KF_EXTENDED | 0xFF)); shift_state = ((keystate[VK_SHIFT] & 0x80) != 0) + ((keystate[VK_CONTROL] & 0x80) != 0) * 2; @@ -3092,20 +3260,11 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, } else if (compose_state == 1 && wParam != VK_CONTROL) compose_state = 0; - /* - * Record that we pressed key so the scroll window can be reset, but - * be careful to avoid Shift-UP/Down - */ - if (wParam != VK_SHIFT && wParam != VK_PRIOR && wParam != VK_NEXT && - wParam != VK_MENU && wParam != VK_CONTROL) { - seen_key_event = 1; - } - if (compose_state > 1 && left_alt) compose_state = 0; /* Sanitize the number pad if not using a PC NumPad */ - if (left_alt || (app_keypad_keys && !cfg.no_applic_k + if (left_alt || (term->app_keypad_keys && !cfg.no_applic_k && cfg.funky_type != 2) || cfg.funky_type == 3 || cfg.nethack_keypad || compose_state) { if ((HIWORD(lParam) & KF_EXTENDED) == 0) { @@ -3164,12 +3323,20 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, SendMessage(hwnd, WM_VSCROLL, SB_PAGEUP, 0); return 0; } + if (wParam == VK_PRIOR && shift_state == 2) { + SendMessage(hwnd, WM_VSCROLL, SB_LINEUP, 0); + return 0; + } if (wParam == VK_NEXT && shift_state == 1) { SendMessage(hwnd, WM_VSCROLL, SB_PAGEDOWN, 0); return 0; } + if (wParam == VK_NEXT && shift_state == 2) { + SendMessage(hwnd, WM_VSCROLL, SB_LINEDOWN, 0); + return 0; + } if (wParam == VK_INSERT && shift_state == 1) { - term_do_paste(); + term_do_paste(term); return 0; } if (left_alt && wParam == VK_F4 && cfg.alt_f4) { @@ -3187,7 +3354,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, } /* Control-Numlock for app-keypad mode switch */ if (wParam == VK_PAUSE && shift_state == 2) { - app_keypad_keys ^= 1; + term->app_keypad_keys ^= 1; return 0; } @@ -3230,7 +3397,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, if (cfg.funky_type == 3 || (cfg.funky_type <= 1 && - app_keypad_keys && !cfg.no_applic_k)) switch (wParam) { + term->app_keypad_keys && !cfg.no_applic_k)) switch (wParam) { case VK_EXECUTE: xkey = 'P'; break; @@ -3244,7 +3411,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, xkey = 'S'; break; } - if (app_keypad_keys && !cfg.no_applic_k) + if (term->app_keypad_keys && !cfg.no_applic_k) switch (wParam) { case VK_NUMPAD0: xkey = 'p'; @@ -3311,7 +3478,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, break; } if (xkey) { - if (vt52_mode) { + if (term->vt52_mode) { if (xkey >= 'P' && xkey <= 'S') p += sprintf((char *) p, "\x1B%c", xkey); else @@ -3327,6 +3494,12 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, *p++ = 0; return -2; } + if (wParam == VK_BACK && shift_state == 1) { /* Shift Backspace */ + /* We do the opposite of what is configured */ + *p++ = (cfg.bksp_is_delete ? 0x08 : 0x7F); + *p++ = 0; + return -2; + } if (wParam == VK_TAB && shift_state == 1) { /* Shift tab */ *p++ = 0x1B; *p++ = '['; @@ -3356,7 +3529,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, *p++ = "\000\033\034\035\036\037\177"[wParam - '2']; return p - output; } - if (shift_state == 2 && wParam == 0xBD) { + if (shift_state == 2 && (wParam == 0xBD || wParam == 0xBF)) { *p++ = 0x1F; return p - output; } @@ -3364,7 +3537,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, *p++ = 0x1C; return p - output; } - if (shift_state == 0 && wParam == VK_RETURN && cr_lf_return) { + if (shift_state == 0 && wParam == VK_RETURN && term->cr_lf_return) { *p++ = '\r'; *p++ = '\n'; return p - output; @@ -3466,7 +3639,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, if (cfg.funky_type == 3 && code <= 6) code = "\0\2\1\4\5\3\6"[code]; - if (vt52_mode && code > 0 && code <= 6) { + if (term->vt52_mode && code > 0 && code <= 6) { p += sprintf((char *) p, "\x1B%c", " HLMEIG"[code]); return p - output; } @@ -3504,13 +3677,13 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, } return p - output; } - if ((vt52_mode || cfg.funky_type == 4) && code >= 11 && code <= 24) { + if ((term->vt52_mode || cfg.funky_type == 4) && code >= 11 && code <= 24) { int offt = 0; if (code > 15) offt++; if (code > 21) offt++; - if (vt52_mode) + if (term->vt52_mode) p += sprintf((char *) p, "\x1B%c", code + 'P' - 11 - offt); else p += @@ -3522,7 +3695,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, return p - output; } if (cfg.funky_type == 2 && code >= 11 && code <= 14) { - if (vt52_mode) + if (term->vt52_mode) p += sprintf((char *) p, "\x1B%c", code + 'P' - 11); else p += sprintf((char *) p, "\x1BO%c", code + 'P' - 11); @@ -3561,10 +3734,10 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, break; } if (xkey) { - if (vt52_mode) + if (term->vt52_mode) p += sprintf((char *) p, "\x1B%c", xkey); else { - int app_flg = (app_cursor_keys && !cfg.no_applic_c); + int app_flg = (term->app_cursor_keys && !cfg.no_applic_c); #if 0 /* * RDB: VT100 & VT102 manuals both state the @@ -3580,7 +3753,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, * _this_ I'll have to put in a configurable * option. */ - if (!app_keypad_keys) + if (!term->app_keypad_keys) app_flg = 0; #endif /* Useful mapping of Ctrl-arrows */ @@ -3627,7 +3800,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, #ifdef SHOW_TOASCII_RESULT if (r == 1 && !key_down) { if (alt_sum) { - if (in_utf || dbcs_screenfont) + if (in_utf(term) || ucsdata.dbcs_screenfont) debug((", (U+%04x)", alt_sum)); else debug((", LCH(%d)", alt_sum)); @@ -3651,7 +3824,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, * sensible, but for the moment it's preferable to * having to faff about buffering things. */ - term_nopaste(); + term_nopaste(term); p = output; for (i = 0; i < r; i++) { @@ -3671,7 +3844,8 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, return 0; } keybuf = nc; - luni_send(&keybuf, 1, 1); + term_seen_key_event(term); + luni_send(ldisc, &keybuf, 1, 1); continue; } @@ -3679,9 +3853,10 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, if (!key_down) { if (alt_sum) { - if (in_utf || dbcs_screenfont) { + if (in_utf(term) || ucsdata.dbcs_screenfont) { keybuf = alt_sum; - luni_send(&keybuf, 1, 1); + term_seen_key_event(term); + luni_send(ldisc, &keybuf, 1, 1); } else { ch = (char) alt_sum; /* @@ -3693,22 +3868,27 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, * messages. We _have_ to buffer * everything we're sent. */ - ldisc_send(&ch, 1, 1); + term_seen_key_event(term); + ldisc_send(ldisc, &ch, 1, 1); } alt_sum = 0; } else - lpage_send(kbd_codepage, &ch, 1, 1); + term_seen_key_event(term); + lpage_send(ldisc, kbd_codepage, &ch, 1, 1); } else { if(capsOn && ch < 0x80) { WCHAR cbuf[2]; cbuf[0] = 27; cbuf[1] = xlat_uskbd2cyrllic(ch); - luni_send(cbuf+!left_alt, 1+!!left_alt, 1); + term_seen_key_event(term); + luni_send(ldisc, cbuf+!left_alt, 1+!!left_alt, 1); } else { char cbuf[2]; cbuf[0] = '\033'; cbuf[1] = ch; - lpage_send(kbd_codepage, cbuf+!left_alt, 1+!!left_alt, 1); + term_seen_key_event(term); + lpage_send(ldisc, kbd_codepage, + cbuf+!left_alt, 1+!!left_alt, 1); } } show_mouseptr(0); @@ -3723,7 +3903,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, if (!left_alt) keys[0] = 0; /* If we will be using alt_sum fix the 256s */ - else if (keys[0] && (in_utf || dbcs_screenfont)) + else if (keys[0] && (in_utf(term) || ucsdata.dbcs_screenfont)) keys[0] = 10; } @@ -3740,25 +3920,35 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, return -1; } -void set_title(char *title) +void request_paste(void *frontend) +{ + /* + * In Windows, pasting is synchronous: we can read the + * clipboard with no difficulty, so request_paste() can just go + * ahead and paste. + */ + term_do_paste(term); +} + +void set_title(void *frontend, char *title) { sfree(window_name); - window_name = smalloc(1 + strlen(title)); + window_name = snewn(1 + strlen(title), char); strcpy(window_name, title); if (cfg.win_name_always || !IsIconic(hwnd)) SetWindowText(hwnd, title); } -void set_icon(char *title) +void set_icon(void *frontend, char *title) { sfree(icon_name); - icon_name = smalloc(1 + strlen(title)); + icon_name = snewn(1 + strlen(title), char); strcpy(icon_name, title); if (!cfg.win_name_always && IsIconic(hwnd)) SetWindowText(hwnd, title); } -void set_sbar(int total, int start, int page) +void set_sbar(void *frontend, int total, int start, int page) { SCROLLINFO si; @@ -3775,7 +3965,7 @@ void set_sbar(int total, int start, int page) SetScrollInfo(hwnd, SB_VERT, &si, TRUE); } -Context get_ctx(void) +Context get_ctx(void *frontend) { HDC hdc; if (hwnd) { @@ -3806,7 +3996,7 @@ static void real_palette_set(int n, int r, int g, int b) colours[n] = RGB(r, g, b); } -void palette_set(int n, int r, int g, int b) +void palette_set(void *frontend, int n, int r, int g, int b) { static const int first[21] = { 0, 2, 4, 6, 8, 10, 12, 14, @@ -3817,14 +4007,14 @@ void palette_set(int n, int r, int g, int b) if (first[n] >= 18) real_palette_set(first[n] + 1, r, g, b); if (pal) { - HDC hdc = get_ctx(); + HDC hdc = get_ctx(frontend); UnrealizeObject(pal); RealizePalette(hdc); free_ctx(hdc); } } -void palette_reset(void) +void palette_reset(void *frontend) { int i; @@ -3845,13 +4035,13 @@ void palette_reset(void) if (pal) { HDC hdc; SetPaletteEntries(pal, 0, NCOLOURS, logpal->palPalEntry); - hdc = get_ctx(); + hdc = get_ctx(frontend); RealizePalette(hdc); free_ctx(hdc); } } -void write_aclip(char *data, int len, int must_deselect) +void write_aclip(void *frontend, char *data, int len, int must_deselect) { HGLOBAL clipdata; void *lock; @@ -3883,7 +4073,7 @@ void write_aclip(char *data, int len, int must_deselect) /* * Note: unlike write_aclip() this will not append a nul. */ -void write_clip(wchar_t * data, int len, int must_deselect) +void write_clip(void *frontend, wchar_t * data, int len, int must_deselect) { HGLOBAL clipdata, clipdata2, clipdata3; int len2; @@ -3922,10 +4112,10 @@ void write_clip(wchar_t * data, int len, int must_deselect) get_unitab(CP_ACP, unitab, 0); - rtfsize = 100 + strlen(cfg.font); - rtf = smalloc(rtfsize); + rtfsize = 100 + strlen(cfg.font.name); + rtf = snewn(rtfsize, char); sprintf(rtf, "{\\rtf1\\ansi%d{\\fonttbl\\f0\\fmodern %s;}\\f0", - GetACP(), cfg.font); + GetACP(), cfg.font.name); rtflen = strlen(rtf); /* @@ -3988,7 +4178,7 @@ void write_clip(wchar_t * data, int len, int must_deselect) if (rtfsize < rtflen + totallen + 3) { rtfsize = rtflen + totallen + 512; - rtf = srealloc(rtf, rtfsize); + rtf = sresize(rtf, rtfsize, char); } strcpy(rtf + rtflen, before); rtflen += blen; @@ -4046,7 +4236,7 @@ void write_clip(wchar_t * data, int len, int must_deselect) SendMessage(hwnd, WM_IGNORE_CLIP, FALSE, 0); } -void get_clip(wchar_t ** p, int *len) +void get_clip(void *frontend, wchar_t ** p, int *len) { static HGLOBAL clipdata = NULL; static wchar_t *converted = 0; @@ -4076,7 +4266,7 @@ void get_clip(wchar_t ** p, int *len) CloseClipboard(); s = GlobalLock(clipdata); i = MultiByteToWideChar(CP_ACP, 0, s, strlen(s) + 1, 0, 0); - *p = converted = smalloc(i * sizeof(wchar_t)); + *p = converted = snewn(i, wchar_t); MultiByteToWideChar(CP_ACP, 0, s, strlen(s) + 1, converted, i); *len = i - 1; return; @@ -4093,7 +4283,7 @@ void get_clip(wchar_t ** p, int *len) * Move `lines' lines from position `from' to position `to' in the * window. */ -void optimised_move(int to, int from, int lines) +void optimised_move(void *frontend, int to, int from, int lines) { RECT r; int min, max; @@ -4102,7 +4292,7 @@ void optimised_move(int to, int from, int lines) max = to + from - min; r.left = offset_width; - r.right = offset_width + cols * font_width; + r.right = offset_width + term->cols * font_width; r.top = offset_height + min * font_height; r.bottom = offset_height + (max + lines) * font_height; ScrollWindow(hwnd, 0, (to - from) * font_height, &r, &r); @@ -4115,13 +4305,33 @@ void optimised_move(int to, int from, int lines) void fatalbox(char *fmt, ...) { va_list ap; - char stuff[200]; + char *stuff, morestuff[100]; va_start(ap, fmt); - vsprintf(stuff, fmt, ap); + stuff = dupvprintf(fmt, ap); va_end(ap); - MessageBox(hwnd, stuff, "PuTTY Fatal Error", MB_ICONERROR | MB_OK); - exit(1); + sprintf(morestuff, "%.70s Fatal Error", appname); + MessageBox(hwnd, stuff, morestuff, MB_ICONERROR | MB_OK); + sfree(stuff); + cleanup_exit(1); +} + +/* + * Print a modal (Really Bad) message box and perform a fatal exit. + */ +void modalfatalbox(char *fmt, ...) +{ + va_list ap; + char *stuff, morestuff[100]; + + va_start(ap, fmt); + stuff = dupvprintf(fmt, ap); + va_end(ap); + sprintf(morestuff, "%.70s Fatal Error", appname); + MessageBox(hwnd, stuff, morestuff, + MB_SYSTEMMODAL | MB_ICONERROR | MB_OK); + sfree(stuff); + cleanup_exit(1); } /* @@ -4163,7 +4373,7 @@ static void flash_window(int mode) /* * Beep. */ -void beep(int mode) +void beep(void *frontend, int mode) { if (mode == BELL_DEFAULT) { /* @@ -4185,17 +4395,20 @@ void beep(int mode) */ lastbeep = GetTickCount(); } else if (mode == BELL_WAVEFILE) { - if (!PlaySound(cfg.bell_wavefile, NULL, SND_ASYNC | SND_FILENAME)) { + if (!PlaySound(cfg.bell_wavefile.path, NULL, + SND_ASYNC | SND_FILENAME)) { char buf[sizeof(cfg.bell_wavefile) + 80]; + char otherbuf[100]; sprintf(buf, "Unable to play sound file\n%s\n" "Using default sound instead", cfg.bell_wavefile); - MessageBox(hwnd, buf, "PuTTY Sound Error", + sprintf(otherbuf, "%.70s Sound Error", appname); + MessageBox(hwnd, buf, otherbuf, MB_OK | MB_ICONEXCLAMATION); cfg.beep = BELL_DEFAULT; } } /* Otherwise, either visual bell or disabled; do nothing here */ - if (!has_focus) { + if (!term->has_focus) { flash_window(2); /* start */ } } @@ -4204,7 +4417,7 @@ void beep(int mode) * Minimise or restore the window in response to a server-side * request. */ -void set_iconic(int iconic) +void set_iconic(void *frontend, int iconic) { if (IsIconic(hwnd)) { if (!iconic) @@ -4218,8 +4431,13 @@ void set_iconic(int iconic) /* * Move the window in response to a server-side request. */ -void move_window(int x, int y) +void move_window(void *frontend, int x, int y) { + if (cfg.resize_action == RESIZE_DISABLED || + cfg.resize_action == RESIZE_FONT || + IsZoomed(hwnd)) + return; + SetWindowPos(hwnd, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); } @@ -4227,7 +4445,7 @@ void move_window(int x, int y) * Move the window to the top or bottom of the z-order in response * to a server-side request. */ -void set_zorder(int top) +void set_zorder(void *frontend, int top) { if (cfg.alwaysontop) return; /* ignore */ @@ -4238,7 +4456,7 @@ void set_zorder(int top) /* * Refresh the window in response to a server-side request. */ -void refresh_window(void) +void refresh_window(void *frontend) { InvalidateRect(hwnd, NULL, TRUE); } @@ -4247,7 +4465,7 @@ void refresh_window(void) * Maximise or restore the window in response to a server-side * request. */ -void set_zoomed(int zoomed) +void set_zoomed(void *frontend, int zoomed) { if (IsZoomed(hwnd)) { if (!zoomed) @@ -4261,7 +4479,7 @@ void set_zoomed(int zoomed) /* * Report whether the window is iconic, for terminal reports. */ -int is_iconic(void) +int is_iconic(void *frontend) { return IsIconic(hwnd); } @@ -4269,7 +4487,7 @@ int is_iconic(void) /* * Report the window's position, for terminal reports. */ -void get_window_pos(int *x, int *y) +void get_window_pos(void *frontend, int *x, int *y) { RECT r; GetWindowRect(hwnd, &r); @@ -4280,7 +4498,7 @@ void get_window_pos(int *x, int *y) /* * Report the window's pixel size, for terminal reports. */ -void get_window_pixels(int *x, int *y) +void get_window_pixels(void *frontend, int *x, int *y) { RECT r; GetWindowRect(hwnd, &r); @@ -4291,7 +4509,7 @@ void get_window_pixels(int *x, int *y) /* * Return the window or icon title. */ -char *get_window_title(int icon) +char *get_window_title(void *frontend, int icon) { return icon ? icon_name : window_name; } @@ -4308,6 +4526,32 @@ int is_full_screen() return TRUE; } +/* Get the rect/size of a full screen window using the nearest available + * monitor in multimon systems; default to something sensible if only + * one monitor is present. */ +static int get_fullscreen_rect(RECT * ss) +{ +#ifdef MONITOR_DEFAULTTONEAREST + HMONITOR mon; + MONITORINFO mi; + mon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST); + mi.cbSize = sizeof(mi); + GetMonitorInfo(mon, &mi); + + /* structure copy */ + *ss = mi.rcMonitor; + return TRUE; +#else +/* could also use code like this: + ss->left = ss->top = 0; + ss->right = GetSystemMetrics(SM_CXSCREEN); + ss->bottom = GetSystemMetrics(SM_CYSCREEN); +*/ + return GetClientRect(GetDesktopWindow(), ss); +#endif +} + + /* * Go full-screen. This should only be called when we are already * maximised. @@ -4315,10 +4559,13 @@ int is_full_screen() void make_full_screen() { DWORD style; - int x, y, w, h; + RECT ss; assert(IsZoomed(hwnd)); + if (is_full_screen()) + return; + /* Remove the window furniture. */ style = GetWindowLong(hwnd, GWL_STYLE); style &= ~(WS_CAPTION | WS_BORDER | WS_THICKFRAME); @@ -4329,24 +4576,11 @@ void make_full_screen() SetWindowLong(hwnd, GWL_STYLE, style); /* Resize ourselves to exactly cover the nearest monitor. */ -#ifdef MONITOR_DEFAULTTONEAREST - { - HMONITOR mon; - MONITORINFO mi; - mon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST); - mi.cbSize = sizeof(mi); - GetMonitorInfo(mon, &mi); - x = mi.rcMonitor.left; - y = mi.rcMonitor.top; - w = mi.rcMonitor.right; - h = mi.rcMonitor.bottom; - } -#else - x = y = 0; - w = GetSystemMetrics(SM_CXSCREEN); - h = GetSystemMetrics(SM_CYSCREEN); -#endif - SetWindowPos(hwnd, HWND_TOP, x, y, w, h, SWP_FRAMECHANGED); + get_fullscreen_rect(&ss); + SetWindowPos(hwnd, HWND_TOP, ss.left, ss.top, + ss.right - ss.left, + ss.bottom - ss.top, + SWP_FRAMECHANGED); /* Tick the menu item in the System menu. */ CheckMenuItem(GetSystemMenu(hwnd, FALSE), IDM_FULLSCREEN, @@ -4397,3 +4631,30 @@ void flip_full_screen() ShowWindow(hwnd, SW_MAXIMIZE); } } + +void frontend_keypress(void *handle) +{ + /* + * Keypress termination in non-Close-On-Exit mode is not + * currently supported in PuTTY proper, because the window + * always has a perfectly good Close button anyway. So we do + * nothing here. + */ + return; +} + +int from_backend(void *frontend, int is_stderr, const char *data, int len) +{ + return term_data(term, is_stderr, data, len); +} + +void agent_schedule_callback(void (*callback)(void *, void *, int), + void *callback_ctx, void *data, int len) +{ + struct agent_callback *c = snew(struct agent_callback); + c->callback = callback; + c->callback_ctx = callback_ctx; + c->data = data; + c->len = len; + PostMessage(hwnd, WM_AGENT_CALLBACK, 0, (LPARAM)c); +}