X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/073e9f42f40b00c570bacb92c54cd7b83b13fa31..5fd70d0768f86274b22e73f3cd8f59fec0325e36:/windows/window.c diff --git a/windows/window.c b/windows/window.c index 7cd306da..8d13ff91 100644 --- a/windows/window.c +++ b/windows/window.c @@ -80,7 +80,7 @@ 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); -static void cfgtopalette(void); +static void conftopalette(void); static void systopalette(void); static void init_palette(void); static void init_fonts(int, int); @@ -99,7 +99,7 @@ static int process_clipdata(HGLOBAL clipdata, int unicode); /* Window layout information */ static void reset_window(int); static int extra_width, extra_height; -static int font_width, font_height, font_dualwidth; +static int font_width, font_height, font_dualwidth, font_varpitch; static int offset_width, offset_height; static int was_zoomed = 0; static int prev_rows, prev_cols; @@ -140,7 +140,11 @@ static struct { enum { SYSMENU, CTXMENU }; static HMENU savedsess_menu; -Config cfg; /* exported to windlg.c */ +Conf *conf; /* exported to windlg.c */ + +static void conf_cache_data(void); +int cursor_type; +int vtmode; static struct sesslist sesslist; /* for saved-session menu */ @@ -164,14 +168,15 @@ struct agent_callback { #define FONT_OEMUND 0x22 #define FONT_OEMBOLDUND 0x23 -#define FONT_MAXNO 0x2F +#define FONT_MAXNO 0x40 #define FONT_SHIFT 5 static HFONT fonts[FONT_MAXNO]; static LOGFONT lfont; static int fontflag[FONT_MAXNO]; static enum { - BOLD_COLOURS, BOLD_SHADOW, BOLD_FONT -} bold_mode; + BOLD_NONE, BOLD_SHADOW, BOLD_FONT +} bold_font_mode; +static int bold_colours; static enum { UND_LINE, UND_FONT } und_mode; @@ -202,6 +207,12 @@ static int compose_state = 0; static UINT wm_mousewheel = WM_MOUSEWHEEL; +#define IS_HIGH_VARSEL(wch1, wch2) \ + ((wch1) == 0xDB40 && ((wch2) >= 0xDD00 && (wch2) <= 0xDDEF)) +#define IS_LOW_VARSEL(wch) \ + (((wch) >= 0x180B && (wch) <= 0x180D) || /* MONGOLIAN FREE VARIATION SELECTOR */ \ + ((wch) >= 0xFE00 && (wch) <= 0xFE0F)) /* VARIATION SELECTOR 1-16 */ + /* Dummy routine, only required in plink. */ void ldisc_update(void *frontend, int echo, int edit) { @@ -223,7 +234,7 @@ static void start_backend(void) * Select protocol. This is farmed out into a table in a * separate file to enable an ssh-free variant. */ - back = backend_from_proto(cfg.protocol); + back = backend_from_proto(conf_get_int(conf, CONF_protocol)); if (back == NULL) { char *str = dupprintf("%s Internal Error", appname); MessageBox(NULL, "Unsupported protocol number found", @@ -232,22 +243,24 @@ static void start_backend(void) cleanup_exit(1); } - error = back->init(NULL, &backhandle, &cfg, - cfg.host, cfg.port, &realhost, cfg.tcp_nodelay, - cfg.tcp_keepalives); + error = back->init(NULL, &backhandle, conf, + conf_get_str(conf, CONF_host), + conf_get_int(conf, CONF_port), + &realhost, + conf_get_int(conf, CONF_tcp_nodelay), + conf_get_int(conf, CONF_tcp_keepalives)); 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_dest(&cfg), error); + "%.800s\n" "%s", conf_dest(conf), error); MessageBox(NULL, msg, str, MB_ICONERROR | MB_OK); sfree(str); exit(0); } window_name = icon_name = NULL; - if (*cfg.wintitle) { - title = cfg.wintitle; - } else { + title = conf_get_str(conf, CONF_wintitle); + if (!*title) { sprintf(msg, "%s - %s", realhost, appname); title = msg; } @@ -263,7 +276,7 @@ static void start_backend(void) /* * Set up a line discipline. */ - ldisc = ldisc_create(&cfg, term, back, backhandle, NULL); + ldisc = ldisc_create(conf, term, back, backhandle, NULL); /* * Destroy the Restart Session menu item. (This will return @@ -311,6 +324,15 @@ static void close_session(void) InsertMenu(popup_menus[i].menu, IDM_DUPSESS, MF_BYCOMMAND | MF_ENABLED, IDM_RESTART, "&Restart Session"); } + + /* + * Unset the 'must_close_session' flag, or else we'll come + * straight back here the next time we go round the main message + * loop - which, worse still, will be immediately (without + * blocking) because we've just triggered a WM_SETTEXT by the + * window title change above. + */ + must_close_session = FALSE; } int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) @@ -355,6 +377,8 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) init_flashwindow(); + conf = conf_new(); + /* * Initialize COM. */ @@ -386,9 +410,9 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) if (b) default_port = b->default_port; } - cfg.logtype = LGTYP_NONE; + conf_set_int(conf, CONF_logtype, LGTYP_NONE); - do_defaults(NULL, &cfg); + do_defaults(NULL, conf); p = cmdline; @@ -413,8 +437,8 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) while (i > 1 && isspace(p[i - 1])) i--; p[i] = '\0'; - do_defaults(p + 1, &cfg); - if (!cfg_launchable(&cfg) && !do_config()) { + do_defaults(p + 1, conf); + if (!conf_launchable(conf) && !do_config()) { cleanup_exit(0); } allow_launch = TRUE; /* allow it to be launched directly */ @@ -422,15 +446,16 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) /* * An initial & means we've been given a command line * containing the hex value of a HANDLE for a file - * mapping object, which we must then extract as a - * config. + * mapping object, which we must then interpret as a + * serialised Conf. */ HANDLE filemap; - Config *cp; - if (sscanf(p + 1, "%p", &filemap) == 1 && + void *cp; + unsigned cpsize; + if (sscanf(p + 1, "%p:%u", &filemap, &cpsize) == 2 && (cp = MapViewOfFile(filemap, FILE_MAP_READ, - 0, 0, sizeof(Config))) != NULL) { - cfg = *cp; + 0, 0, cpsize)) != NULL) { + conf_deserialise(conf, cp, cpsize); UnmapViewOfFile(cp); CloseHandle(filemap); } else if (!do_config()) { @@ -452,7 +477,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) int ret; ret = cmdline_process_param(p, i+1left, lprc->top, lprc->right, lprc->bottom)); -debug(("\n")); -#endif + int bkmode = 0, got_bkmode = FALSE; xp = xn = x; @@ -1312,44 +1338,56 @@ debug(("\n")); * function. */ if (rtl) { - newrc.left = lprc->left + xp - x; - newrc.right = lprc->left + xn - x; - newrc.top = lprc->top; - newrc.bottom = lprc->bottom; -#ifdef FIXME_REMOVE_BEFORE_CHECKIN -{ -int k; -debug((" exact_textout: %d,%d", xp, y)); -for(k=0;kleft + xp - x; - newrc.right = lprc->left + xn - x; - newrc.top = lprc->top; - newrc.bottom = lprc->bottom; ExtTextOutW(hdc, xp, y, ETO_CLIPPED | (opaque ? ETO_OPAQUE : 0), - &newrc, lpString+i, j-i, lpDx+i); + lprc, lpString+i, j-i, + font_varpitch ? NULL : lpDx+i); } i = j; xp = xn; + + bkmode = GetBkMode(hdc); + got_bkmode = TRUE; + SetBkMode(hdc, TRANSPARENT); + opaque = FALSE; } -#ifdef FIXME_REMOVE_BEFORE_CHECKIN -debug(("general_textout: done, xn=%d\n", xn)); -#endif - assert(xn - x >= lprc->right - lprc->left); + if (got_bkmode) + SetBkMode(hdc, bkmode); +} + +static int get_font_width(HDC hdc, const TEXTMETRIC *tm) +{ + int ret; + /* Note that the TMPF_FIXED_PITCH bit is defined upside down :-( */ + if (!(tm->tmPitchAndFamily & TMPF_FIXED_PITCH)) { + ret = tm->tmAveCharWidth; + } else { +#define FIRST '0' +#define LAST '9' + ABCFLOAT widths[LAST-FIRST + 1]; + int j; + + font_varpitch = TRUE; + font_dualwidth = TRUE; + if (GetCharABCWidthsFloat(hdc, FIRST, LAST, widths)) { + ret = 0; + for (j = 0; j < lenof(widths); j++) { + int width = (int)(0.5 + widths[j].abcfA + + widths[j].abcfB + widths[j].abcfC); + if (ret < width) + ret = width; + } + } else { + ret = tm->tmMaxCharWidth; + } +#undef FIRST +#undef LAST + } + return ret; } /* @@ -1373,18 +1411,23 @@ static void init_fonts(int pick_width, int pick_height) { TEXTMETRIC tm; CPINFO cpinfo; + FontSpec *font; int fontsize[3]; int i; + int quality; HDC hdc; int fw_dontcare, fw_bold; for (i = 0; i < FONT_MAXNO; i++) fonts[i] = NULL; - bold_mode = cfg.bold_colour ? BOLD_COLOURS : BOLD_FONT; + bold_font_mode = conf_get_int(conf, CONF_bold_style) & 1 ? + BOLD_FONT : BOLD_NONE; + bold_colours = conf_get_int(conf, CONF_bold_style) & 2 ? TRUE : FALSE; und_mode = UND_FONT; - if (cfg.font.isbold) { + font = conf_get_fontspec(conf, CONF_font); + if (font->isbold) { fw_dontcare = FW_BOLD; fw_bold = FW_HEAVY; } else { @@ -1397,7 +1440,7 @@ static void init_fonts(int pick_width, int pick_height) if (pick_height) font_height = pick_height; else { - font_height = cfg.font.height; + font_height = font->height; if (font_height > 0) { font_height = -MulDiv(font_height, GetDeviceCaps(hdc, LOGPIXELSY), 72); @@ -1405,24 +1448,32 @@ static void init_fonts(int pick_width, int pick_height) } font_width = pick_width; + quality = conf_get_int(conf, CONF_font_quality); #define f(i,c,w,u) \ fonts[i] = CreateFont (font_height, font_width, 0, 0, w, FALSE, u, FALSE, \ c, OUT_DEFAULT_PRECIS, \ - CLIP_DEFAULT_PRECIS, FONT_QUALITY(cfg.font_quality), \ - FIXED_PITCH | FF_DONTCARE, cfg.font.name) + CLIP_DEFAULT_PRECIS, FONT_QUALITY(quality), \ + FIXED_PITCH | FF_DONTCARE, font->name) - f(FONT_NORMAL, cfg.font.charset, fw_dontcare, FALSE); + f(FONT_NORMAL, font->charset, fw_dontcare, FALSE); SelectObject(hdc, fonts[FONT_NORMAL]); GetTextMetrics(hdc, &tm); GetObject(fonts[FONT_NORMAL], sizeof(LOGFONT), &lfont); + /* Note that the TMPF_FIXED_PITCH bit is defined upside down :-( */ + if (!(tm.tmPitchAndFamily & TMPF_FIXED_PITCH)) { + font_varpitch = FALSE; + font_dualwidth = (tm.tmAveCharWidth != tm.tmMaxCharWidth); + } else { + font_varpitch = TRUE; + font_dualwidth = TRUE; + } if (pick_width == 0 || pick_height == 0) { font_height = tm.tmHeight; - font_width = tm.tmAveCharWidth; + font_width = get_font_width(hdc, &tm); } - font_dualwidth = (tm.tmAveCharWidth != tm.tmMaxCharWidth); #ifdef RDB_DEBUG_PATCH debug(23, "Primary font H=%d, AW=%d, MW=%d", @@ -1447,7 +1498,7 @@ static void init_fonts(int pick_width, int pick_height) ucsdata.dbcs_screenfont = (cpinfo.MaxCharSize > 1); } - f(FONT_UNDERLINE, cfg.font.charset, fw_dontcare, TRUE); + f(FONT_UNDERLINE, font->charset, fw_dontcare, TRUE); /* * Some fonts, e.g. 9-pt Courier, draw their underlines @@ -1497,8 +1548,8 @@ static void init_fonts(int pick_width, int pick_height) } } - if (bold_mode == BOLD_FONT) { - f(FONT_BOLD, cfg.font.charset, fw_bold, FALSE); + if (bold_font_mode == BOLD_FONT) { + f(FONT_BOLD, font->charset, fw_bold, FALSE); } #undef f @@ -1509,7 +1560,7 @@ static void init_fonts(int pick_width, int pick_height) for (i = 0; i < 3; i++) { if (fonts[i]) { if (SelectObject(hdc, fonts[i]) && GetTextMetrics(hdc, &tm)) - fontsize[i] = tm.tmAveCharWidth + 256 * tm.tmHeight; + fontsize[i] = get_font_width(hdc, &tm) + 256 * tm.tmHeight; else fontsize[i] = -i; } else @@ -1524,23 +1575,24 @@ static void init_fonts(int pick_width, int pick_height) fonts[FONT_UNDERLINE] = 0; } - if (bold_mode == BOLD_FONT && + if (bold_font_mode == BOLD_FONT && fontsize[FONT_BOLD] != fontsize[FONT_NORMAL]) { - bold_mode = BOLD_SHADOW; + bold_font_mode = BOLD_SHADOW; DeleteObject(fonts[FONT_BOLD]); fonts[FONT_BOLD] = 0; } fontflag[0] = fontflag[1] = fontflag[2] = 1; - init_ucs(&cfg, &ucsdata); + init_ucs(conf, &ucsdata); } static void another_font(int fontno) { int basefont; - int fw_dontcare, fw_bold; + int fw_dontcare, fw_bold, quality; int c, u, w, x; char *s; + FontSpec *font; if (fontno < 0 || fontno >= FONT_MAXNO || fontflag[fontno]) return; @@ -1549,7 +1601,9 @@ static void another_font(int fontno) if (basefont != fontno && !fontflag[basefont]) another_font(basefont); - if (cfg.font.isbold) { + font = conf_get_fontspec(conf, CONF_font); + + if (font->isbold) { fw_dontcare = FW_BOLD; fw_bold = FW_HEAVY; } else { @@ -1557,10 +1611,10 @@ static void another_font(int fontno) fw_bold = FW_BOLD; } - c = cfg.font.charset; + c = font->charset; w = fw_dontcare; u = FALSE; - s = cfg.font.name; + s = font->name; x = font_width; if (fontno & FONT_WIDE) @@ -1574,11 +1628,13 @@ static void another_font(int fontno) if (fontno & FONT_UNDERLINE) u = TRUE; + quality = conf_get_int(conf, CONF_font_quality); + fonts[fontno] = CreateFont(font_height * (1 + !!(fontno & FONT_HIGH)), x, 0, 0, w, FALSE, u, FALSE, c, OUT_DEFAULT_PRECIS, - CLIP_DEFAULT_PRECIS, FONT_QUALITY(cfg.font_quality), - FIXED_PITCH | FF_DONTCARE, s); + CLIP_DEFAULT_PRECIS, FONT_QUALITY(quality), + DEFAULT_PITCH | FF_DONTCARE, s); fontflag[fontno] = 1; } @@ -1600,11 +1656,11 @@ void request_resize(void *frontend, int w, int h) /* If the window is maximized supress resizing attempts */ if (IsZoomed(hwnd)) { - if (cfg.resize_action == RESIZE_TERM) + if (conf_get_int(conf, CONF_resize_action) == RESIZE_TERM) return; } - if (cfg.resize_action == RESIZE_DISABLED) return; + if (conf_get_int(conf, CONF_resize_action) == RESIZE_DISABLED) return; if (h == term->rows && w == term->cols) return; /* Sanity checks ... */ @@ -1635,9 +1691,10 @@ void request_resize(void *frontend, int w, int h) } } - term_size(term, h, w, cfg.savelines); + term_size(term, h, w, conf_get_int(conf, CONF_savelines)); - if (cfg.resize_action != RESIZE_FONT && !IsZoomed(hwnd)) { + if (conf_get_int(conf, CONF_resize_action) != RESIZE_FONT && + !IsZoomed(hwnd)) { width = extra_width + font_width * w; height = extra_height + font_height * h; @@ -1658,7 +1715,7 @@ static void reset_window(int reinit) { * This function doesn't like to change the terminal size but if the * font size is locked that may be it's only soluion. */ - int win_width, win_height; + int win_width, win_height, resize_action, window_border; RECT cr, wr; #ifdef RDB_DEBUG_PATCH @@ -1672,7 +1729,11 @@ static void reset_window(int reinit) { win_width = cr.right - cr.left; win_height = cr.bottom - cr.top; - if (cfg.resize_action == RESIZE_DISABLED) reinit = 2; + resize_action = conf_get_int(conf, CONF_resize_action); + window_border = conf_get_int(conf, CONF_window_border); + + if (resize_action == RESIZE_DISABLED) + reinit = 2; /* Are we being forced to reload the fonts ? */ if (reinit>1) { @@ -1707,9 +1768,9 @@ static void reset_window(int reinit) { extra_width = wr.right - wr.left - cr.right + cr.left; extra_height = wr.bottom - wr.top - cr.bottom + cr.top; - if (cfg.resize_action != RESIZE_TERM) { - if ( font_width != win_width/term->cols || - font_height != win_height/term->rows) { + if (resize_action != RESIZE_TERM) { + if (font_width != win_width/term->cols || + font_height != win_height/term->rows) { deinit_fonts(); init_fonts(win_width/term->cols, win_height/term->rows); offset_width = (win_width-font_width*term->cols)/2; @@ -1721,13 +1782,13 @@ static void reset_window(int reinit) { #endif } } else { - if ( font_width * term->cols != win_width || - font_height * term->rows != win_height) { + if (font_width * term->cols != win_width || + font_height * term->rows != win_height) { /* Our only choice at this point is to change the * size of the terminal; Oh well. */ term_size(term, win_height/font_height, win_width/font_width, - cfg.savelines); + conf_get_int(conf, CONF_savelines)); offset_width = (win_width-font_width*term->cols)/2; offset_height = (win_height-font_height*term->rows)/2; InvalidateRect(hwnd, NULL, TRUE); @@ -1747,7 +1808,7 @@ static void reset_window(int reinit) { debug((27, "reset_window() -> Forced re-init")); #endif - offset_width = offset_height = cfg.window_border; + offset_width = offset_height = window_border; 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; @@ -1772,10 +1833,10 @@ static void reset_window(int reinit) { * window. But that may be too big for the screen which forces us * to change the terminal. */ - if ((cfg.resize_action == RESIZE_TERM && reinit<=0) || - (cfg.resize_action == RESIZE_EITHER && reinit<0) || + if ((resize_action == RESIZE_TERM && reinit<=0) || + (resize_action == RESIZE_EITHER && reinit<0) || reinit>0) { - offset_width = offset_height = cfg.window_border; + offset_width = offset_height = window_border; 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; @@ -1792,7 +1853,7 @@ static void reset_window(int reinit) { /* Grrr too big */ if ( term->rows > height || term->cols > width ) { - if (cfg.resize_action == RESIZE_EITHER) { + if (resize_action == RESIZE_EITHER) { /* Make the font the biggest we can */ if (term->cols > width) font_width = (ss.right - ss.left - extra_width) @@ -1809,7 +1870,8 @@ static void reset_window(int reinit) { } else { if ( height > term->rows ) height = term->rows; if ( width > term->cols ) width = term->cols; - term_size(term, height, width, cfg.savelines); + term_size(term, height, width, + conf_get_int(conf, CONF_savelines)); #ifdef RDB_DEBUG_PATCH debug((27, "reset_window() -> term resize to (%d,%d)", height, width)); @@ -1834,12 +1896,12 @@ 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)/term->cols || - font_height != (win_height-cfg.window_border*2)/term->rows) { + if (font_width != (win_width-window_border*2)/term->cols || + font_height != (win_height-window_border*2)/term->rows) { deinit_fonts(); - init_fonts((win_width-cfg.window_border*2)/term->cols, - (win_height-cfg.window_border*2)/term->rows); + init_fonts((win_width-window_border*2)/term->cols, + (win_height-window_border*2)/term->rows); offset_width = (win_width-font_width*term->cols)/2; offset_height = (win_height-font_height*term->rows)/2; @@ -1868,7 +1930,8 @@ static void click(Mouse_Button b, int x, int y, int shift, int ctrl, int alt) { int thistime = GetMessageTime(); - if (send_raw_mouse && !(cfg.mouse_override && shift)) { + if (send_raw_mouse && + !(shift && conf_get_int(conf, CONF_mouse_override))) { lastbtn = MBT_NOTHING; term_mouse(term, b, translate_button(b), MA_CLICK, x, y, shift, ctrl, alt); @@ -1898,9 +1961,11 @@ static Mouse_Button translate_button(Mouse_Button button) if (button == MBT_LEFT) return MBT_SELECT; if (button == MBT_MIDDLE) - return cfg.mouse_is_xterm == 1 ? MBT_PASTE : MBT_EXTEND; + return conf_get_int(conf, CONF_mouse_is_xterm) == 1 ? + MBT_PASTE : MBT_EXTEND; if (button == MBT_RIGHT) - return cfg.mouse_is_xterm == 1 ? MBT_EXTEND : MBT_PASTE; + return conf_get_int(conf, CONF_mouse_is_xterm) == 1 ? + MBT_EXTEND : MBT_PASTE; return 0; /* shouldn't happen */ } @@ -1909,8 +1974,8 @@ static void show_mouseptr(int show) /* NB that the counter in ShowCursor() is also frobbed by * update_mouse_pointer() */ static int cursor_visible = 1; - if (!cfg.hide_mouseptr) /* override if this feature disabled */ - show = 1; + if (!conf_get_int(conf, CONF_hide_mouseptr)) + show = 1; /* override if this feature disabled */ if (cursor_visible && !show) ShowCursor(FALSE); else if (!cursor_visible && show) @@ -1935,14 +2000,15 @@ static int resizing; void notify_remote_exit(void *fe) { - int exitcode; + int exitcode, close_on_exit; if (!session_closed && (exitcode = back->exitcode(backhandle)) >= 0) { + close_on_exit = conf_get_int(conf, CONF_close_on_exit); /* Abnormal exits will already have set session_closed and taken * appropriate action. */ - if (cfg.close_on_exit == FORCE_ON || - (cfg.close_on_exit == AUTO && exitcode != INT_MAX)) { + if (close_on_exit == FORCE_ON || + (close_on_exit == AUTO && exitcode != INT_MAX)) { PostQuitMessage(0); } else { must_close_session = TRUE; @@ -1957,15 +2023,26 @@ void notify_remote_exit(void *fe) } } -void timer_change_notify(long next) +void timer_change_notify(unsigned long next) { - long ticks = next - GETTICKCOUNT(); - if (ticks <= 0) ticks = 1; /* just in case */ + unsigned long now = GETTICKCOUNT(); + long ticks; + if (now - next < INT_MAX) + ticks = 0; + else + ticks = next - now; KillTimer(hwnd, TIMING_TIMER_ID); SetTimer(hwnd, TIMING_TIMER_ID, ticks, NULL); timing_next_time = next; } +static void conf_cache_data(void) +{ + /* Cache some items from conf to speed lookups in very hot code */ + cursor_type = conf_get_int(conf, CONF_cursor_type); + vtmode = conf_get_int(conf, CONF_vtmode); +} + static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { @@ -1973,12 +2050,14 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, static int ignore_clip = FALSE; static int need_backend_resize = FALSE; static int fullscr_on_max = FALSE; + static int processed_resize = FALSE; static UINT last_mousemove = 0; + int resize_action; switch (message) { case WM_TIMER: if ((UINT_PTR)wParam == TIMING_TIMER_ID) { - long next; + unsigned long next; KillTimer(hwnd, TIMING_TIMER_ID); if (run_timers(timing_next_time, &next)) { @@ -1994,7 +2073,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, char *str; show_mouseptr(1); str = dupprintf("%s Exit Confirmation", appname); - if (!cfg.warn_on_close || session_closed || + if (session_closed || !conf_get_int(conf, CONF_warn_on_close) || MessageBox(hwnd, "Are you sure you want to close this session?", str, MB_ICONWARNING | MB_OKCANCEL | MB_DEFBUTTON1) @@ -2041,7 +2120,10 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, * config structure. */ SECURITY_ATTRIBUTES sa; - Config *p; + void *p; + int size; + + size = conf_serialised_size(conf); sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = NULL; @@ -2049,18 +2131,16 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, filemap = CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, - 0, sizeof(Config), NULL); + 0, size, NULL); if (filemap && filemap != INVALID_HANDLE_VALUE) { - p = (Config *) MapViewOfFile(filemap, - FILE_MAP_WRITE, - 0, 0, sizeof(Config)); + p = MapViewOfFile(filemap, FILE_MAP_WRITE, 0, 0, size); if (p) { - *p = cfg; /* structure copy */ + conf_serialise(conf, p); UnmapViewOfFile(p); } } inherit_handles = TRUE; - sprintf(c, "putty &%p", filemap); + sprintf(c, "putty &%p:%u", filemap, (unsigned)size); cl = c; } else if (wParam == IDM_SAVEDSESS) { unsigned int sessno = ((lParam - IDM_SAVED_MIN) @@ -2087,6 +2167,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, si.lpReserved2 = NULL; CreateProcess(b, cl, NULL, NULL, inherit_handles, NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); if (filemap) CloseHandle(filemap); @@ -2104,7 +2186,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, break; case IDM_RECONF: { - Config prev_cfg; + Conf *prev_conf; int init_lvl = 1; int reconfig_result; @@ -2113,62 +2195,78 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, else reconfiguring = TRUE; - GetWindowText(hwnd, cfg.wintitle, sizeof(cfg.wintitle)); - prev_cfg = cfg; + /* + * Copy the current window title into the stored + * previous configuration, so that doing nothing to + * the window title field in the config box doesn't + * reset the title to its startup state. + */ + conf_set_str(conf, CONF_wintitle, window_name); + + prev_conf = conf_copy(conf); reconfig_result = do_reconfig(hwnd, back ? back->cfg_info(backhandle) : 0); reconfiguring = FALSE; - if (!reconfig_result) + if (!reconfig_result) { + conf_free(prev_conf); break; + } + conf_cache_data(); + + resize_action = conf_get_int(conf, CONF_resize_action); { /* Disable full-screen if resizing forbidden */ int i; for (i = 0; i < lenof(popup_menus); i++) EnableMenuItem(popup_menus[i].menu, IDM_FULLSCREEN, MF_BYCOMMAND | - (cfg.resize_action == RESIZE_DISABLED) + (resize_action == RESIZE_DISABLED) ? MF_GRAYED : MF_ENABLED); /* Gracefully unzoom if necessary */ - if (IsZoomed(hwnd) && - (cfg.resize_action == RESIZE_DISABLED)) { + if (IsZoomed(hwnd) && (resize_action == RESIZE_DISABLED)) ShowWindow(hwnd, SW_RESTORE); - } } /* Pass new config data to the logging module */ - log_reconfig(logctx, &cfg); + log_reconfig(logctx, conf); sfree(logpal); /* * Flush the line discipline's edit buffer in the * case where local editing has just been disabled. */ + ldisc_configure(ldisc, conf); if (ldisc) ldisc_send(ldisc, NULL, 0, 0); if (pal) DeleteObject(pal); logpal = NULL; pal = NULL; - cfgtopalette(); + conftopalette(); init_palette(); /* Pass new config data to the terminal */ - term_reconfig(term, &cfg); + term_reconfig(term, conf); /* Pass new config data to the back end */ if (back) - back->reconfig(backhandle, &cfg); + back->reconfig(backhandle, conf); /* Screen size changed ? */ - if (cfg.height != prev_cfg.height || - cfg.width != prev_cfg.width || - cfg.savelines != prev_cfg.savelines || - cfg.resize_action == RESIZE_FONT || - (cfg.resize_action == RESIZE_EITHER && IsZoomed(hwnd)) || - cfg.resize_action == RESIZE_DISABLED) - term_size(term, cfg.height, cfg.width, cfg.savelines); + if (conf_get_int(conf, CONF_height) != + conf_get_int(prev_conf, CONF_height) || + conf_get_int(conf, CONF_width) != + conf_get_int(prev_conf, CONF_width) || + conf_get_int(conf, CONF_savelines) != + conf_get_int(prev_conf, CONF_savelines) || + resize_action == RESIZE_FONT || + (resize_action == RESIZE_EITHER && IsZoomed(hwnd)) || + resize_action == RESIZE_DISABLED) + term_size(term, conf_get_int(conf, CONF_height), + conf_get_int(conf, CONF_width), + conf_get_int(conf, CONF_savelines)); /* Enable or disable the scroll bar, etc */ { @@ -2177,8 +2275,9 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, GetWindowLongPtr(hwnd, GWL_EXSTYLE); nexflag = exflag; - if (cfg.alwaysontop != prev_cfg.alwaysontop) { - if (cfg.alwaysontop) { + if (conf_get_int(conf, CONF_alwaysontop) != + conf_get_int(prev_conf, CONF_alwaysontop)) { + if (conf_get_int(conf, CONF_alwaysontop)) { nexflag |= WS_EX_TOPMOST; SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); @@ -2188,25 +2287,26 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, SWP_NOMOVE | SWP_NOSIZE); } } - if (cfg.sunken_edge) + if (conf_get_int(conf, CONF_sunken_edge)) nexflag |= WS_EX_CLIENTEDGE; else nexflag &= ~(WS_EX_CLIENTEDGE); nflg = flag; - if (is_full_screen() ? - cfg.scrollbar_in_fullscreen : cfg.scrollbar) + if (conf_get_int(conf, is_full_screen() ? + CONF_scrollbar_in_fullscreen : + CONF_scrollbar)) nflg |= WS_VSCROLL; else nflg &= ~WS_VSCROLL; - if (cfg.resize_action == RESIZE_DISABLED || + if (resize_action == RESIZE_DISABLED || is_full_screen()) nflg &= ~WS_THICKFRAME; else nflg |= WS_THICKFRAME; - if (cfg.resize_action == RESIZE_DISABLED) + if (resize_action == RESIZE_DISABLED) nflg &= ~WS_MAXIMIZEBOX; else nflg |= WS_MAXIMIZEBOX; @@ -2227,34 +2327,47 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, } /* Oops */ - if (cfg.resize_action == RESIZE_DISABLED && IsZoomed(hwnd)) { + if (resize_action == RESIZE_DISABLED && IsZoomed(hwnd)) { force_normal(hwnd); init_lvl = 2; } - set_title(NULL, cfg.wintitle); + set_title(NULL, conf_get_str(conf, CONF_wintitle)); if (IsIconic(hwnd)) { SetWindowText(hwnd, - cfg.win_name_always ? window_name : - icon_name); + conf_get_int(conf, CONF_win_name_always) ? + window_name : icon_name); } - if (strcmp(cfg.font.name, prev_cfg.font.name) != 0 || - strcmp(cfg.line_codepage, prev_cfg.line_codepage) != 0 || - cfg.font.isbold != prev_cfg.font.isbold || - cfg.font.height != prev_cfg.font.height || - cfg.font.charset != prev_cfg.font.charset || - cfg.font_quality != prev_cfg.font_quality || - cfg.vtmode != prev_cfg.vtmode || - cfg.bold_colour != prev_cfg.bold_colour || - cfg.resize_action == RESIZE_DISABLED || - cfg.resize_action == RESIZE_EITHER || - (cfg.resize_action != prev_cfg.resize_action)) - init_lvl = 2; + { + FontSpec *font = conf_get_fontspec(conf, CONF_font); + FontSpec *prev_font = conf_get_fontspec(prev_conf, + CONF_font); + + if (!strcmp(font->name, prev_font->name) || + !strcmp(conf_get_str(conf, CONF_line_codepage), + conf_get_str(prev_conf, CONF_line_codepage)) || + font->isbold != prev_font->isbold || + font->height != prev_font->height || + font->charset != prev_font->charset || + conf_get_int(conf, CONF_font_quality) != + conf_get_int(prev_conf, CONF_font_quality) || + conf_get_int(conf, CONF_vtmode) != + conf_get_int(prev_conf, CONF_vtmode) || + conf_get_int(conf, CONF_bold_style) != + conf_get_int(prev_conf, CONF_bold_style) || + resize_action == RESIZE_DISABLED || + resize_action == RESIZE_EITHER || + resize_action != conf_get_int(prev_conf, + CONF_resize_action)) + init_lvl = 2; + } InvalidateRect(hwnd, NULL, TRUE); reset_window(init_lvl); net_pending_errors(); + + conf_free(prev_conf); } break; case IDM_COPYALL: @@ -2332,7 +2445,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, case WM_MBUTTONUP: case WM_RBUTTONUP: if (message == WM_RBUTTONDOWN && - ((wParam & MK_CONTROL) || (cfg.mouse_is_xterm == 2))) { + ((wParam & MK_CONTROL) || + (conf_get_int(conf, CONF_mouse_is_xterm) == 2))) { POINT cursorpos; show_mouseptr(1); /* make sure pointer is visible */ @@ -2639,7 +2753,9 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, debug((27, "WM_EXITSIZEMOVE")); #endif if (need_backend_resize) { - term_size(term, cfg.height, cfg.width, cfg.savelines); + term_size(term, conf_get_int(conf, CONF_height), + conf_get_int(conf, CONF_width), + conf_get_int(conf, CONF_savelines)); InvalidateRect(hwnd, NULL, TRUE); } break; @@ -2649,13 +2765,15 @@ 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_TERM || - (cfg.resize_action == RESIZE_EITHER && !is_alt_pressed())) { + resize_action = conf_get_int(conf, CONF_resize_action); + if (resize_action == RESIZE_TERM || + (resize_action == RESIZE_EITHER && !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 != term->rows || cfg.width != term->cols )) { + if (!need_backend_resize && resize_action == RESIZE_EITHER && + (conf_get_int(conf, CONF_height) != term->rows || + conf_get_int(conf, CONF_width) != term->cols)) { /* * Great! It seems that both the terminal size and the * font size have been changed and the user is now dragging. @@ -2664,11 +2782,9 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, * font size! * * This would be easier but it seems to be too confusing. - - term_size(term, cfg.height, cfg.width, cfg.savelines); - reset_window(2); */ - cfg.height=term->rows; cfg.width=term->cols; + conf_set_int(conf, CONF_height, term->rows); + conf_set_int(conf, CONF_width, term->cols); InvalidateRect(hwnd, NULL, TRUE); need_backend_resize = TRUE; @@ -2705,8 +2821,9 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, return 0; } else { int width, height, w, h, rv = 0; - int ex_width = extra_width + (cfg.window_border - offset_width) * 2; - int ex_height = extra_height + (cfg.window_border - offset_height) * 2; + int window_border = conf_get_int(conf, CONF_window_border); + int ex_width = extra_width + (window_border - offset_width) * 2; + int ex_height = extra_height + (window_border - offset_height) * 2; LPRECT r = (LPRECT) lParam; width = r->right - r->left - ex_width; @@ -2742,6 +2859,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, sys_cursor_update(); break; case WM_SIZE: + resize_action = conf_get_int(conf, CONF_resize_action); #ifdef RDB_DEBUG_PATCH debug((27, "WM_SIZE %s (%d,%d)", (wParam == SIZE_MINIMIZED) ? "SIZE_MINIMIZED": @@ -2753,22 +2871,47 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, #endif if (wParam == SIZE_MINIMIZED) SetWindowText(hwnd, - cfg.win_name_always ? window_name : icon_name); + conf_get_int(conf, CONF_win_name_always) ? + window_name : icon_name); if (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED) SetWindowText(hwnd, window_name); - if (wParam == SIZE_RESTORED) + if (wParam == SIZE_RESTORED) { + processed_resize = FALSE; clear_full_screen(); + if (processed_resize) { + /* + * Inhibit normal processing of this WM_SIZE; a + * secondary one was triggered just now by + * clear_full_screen which contained the correct + * client area size. + */ + return 0; + } + } if (wParam == SIZE_MAXIMIZED && fullscr_on_max) { fullscr_on_max = FALSE; + processed_resize = FALSE; make_full_screen(); + if (processed_resize) { + /* + * Inhibit normal processing of this WM_SIZE; a + * secondary one was triggered just now by + * make_full_screen which contained the correct client + * area size. + */ + return 0; + } } - if (cfg.resize_action == RESIZE_DISABLED) { + processed_resize = TRUE; + + if (resize_action == RESIZE_DISABLED) { /* A resize, well it better be a minimize. */ reset_window(-1); } else { int width, height, w, h; + int window_border = conf_get_int(conf, CONF_window_border); width = LOWORD(lParam); height = HIWORD(lParam); @@ -2777,36 +2920,50 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, was_zoomed = 1; prev_rows = term->rows; prev_cols = term->cols; - if (cfg.resize_action == RESIZE_TERM) { + if (resize_action == RESIZE_TERM) { w = width / font_width; if (w < 1) w = 1; h = height / font_height; if (h < 1) h = 1; - term_size(term, h, w, cfg.savelines); + if (resizing) { + /* + * As below, if we're in the middle of an + * interactive resize we don't call + * back->size. In Windows 7, this case can + * arise in maximisation as well via the Aero + * snap UI. + */ + need_backend_resize = TRUE; + conf_set_int(conf, CONF_height, h); + conf_set_int(conf, CONF_width, w); + } else { + term_size(term, h, w, + conf_get_int(conf, CONF_savelines)); + } } reset_window(0); } else if (wParam == SIZE_RESTORED && was_zoomed) { was_zoomed = 0; - if (cfg.resize_action == RESIZE_TERM) { - w = (width-cfg.window_border*2) / font_width; + if (resize_action == RESIZE_TERM) { + w = (width-window_border*2) / font_width; if (w < 1) w = 1; - h = (height-cfg.window_border*2) / font_height; + h = (height-window_border*2) / font_height; if (h < 1) h = 1; - term_size(term, h, w, cfg.savelines); + term_size(term, h, w, conf_get_int(conf, CONF_savelines)); reset_window(2); - } else if (cfg.resize_action != RESIZE_FONT) + } else if (resize_action != RESIZE_FONT) reset_window(2); else reset_window(0); } else if (wParam == SIZE_MINIMIZED) { /* do nothing */ - } else if (cfg.resize_action == RESIZE_TERM || - (cfg.resize_action == RESIZE_EITHER && + } else if (resize_action == RESIZE_TERM || + (resize_action == RESIZE_EITHER && !is_alt_pressed())) { - w = (width-cfg.window_border*2) / font_width; + w = (width-window_border*2) / font_width; if (w < 1) w = 1; - h = (height-cfg.window_border*2) / font_height; + h = (height-window_border*2) / font_height; if (h < 1) h = 1; if (resizing) { @@ -2817,10 +2974,10 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, * opaque drag.) */ need_backend_resize = TRUE; - cfg.height = h; - cfg.width = w; + conf_set_int(conf, CONF_height, h); + conf_set_int(conf, CONF_width, w); } else { - term_size(term, h, w, cfg.savelines); + term_size(term, h, w, conf_get_int(conf, CONF_savelines)); } } else { reset_window(0); @@ -2850,7 +3007,19 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, break; case SB_THUMBPOSITION: case SB_THUMBTRACK: - term_scroll(term, 1, HIWORD(wParam)); + /* + * Use GetScrollInfo instead of HIWORD(wParam) to get + * 32-bit scroll position. + */ + { + SCROLLINFO si; + + si.cbSize = sizeof(si); + si.fMask = SIF_TRACKPOS; + if (GetScrollInfo(hwnd, SB_VERT, &si) == 0) + si.nTrackPos = HIWORD(wParam); + term_scroll(term, 1, si.nTrackPos); + } break; } break; @@ -2975,9 +3144,20 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, * instead we luni_send the characters one by one. */ term_seen_key_event(term); - for (i = 0; i < n; i += 2) { - if (ldisc) + /* don't divide SURROGATE PAIR */ + if (ldisc) { + for (i = 0; i < n; i += 2) { + WCHAR hs = *(unsigned short *)(buff+i); + if (IS_HIGH_SURROGATE(hs) && i+2 < n) { + WCHAR ls = *(unsigned short *)(buff+i+2); + if (IS_LOW_SURROGATE(ls)) { + luni_send(ldisc, (unsigned short *)(buff+i), 2, 1); + i += 2; + continue; + } + } luni_send(ldisc, (unsigned short *)(buff+i), 1, 1); + } } free(buff); } @@ -3017,7 +3197,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, } return 0; case WM_SYSCOLORCHANGE: - if (cfg.system_colour) { + if (conf_get_int(conf, CONF_system_colour)) { /* Refresh palette from system colours. */ /* XXX actually this zaps the entire palette. */ systopalette(); @@ -3069,7 +3249,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, break; if (send_raw_mouse && - !(cfg.mouse_override && shift_pressed)) { + !(conf_get_int(conf, CONF_mouse_override) && + shift_pressed)) { /* Mouse wheel position is in screen coordinates for * some reason */ POINT p; @@ -3174,7 +3355,13 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, int force_manual_underline = 0; int fnt_width, char_width; int text_adjust = 0; - static int *IpDx = 0, IpDxLEN = 0; + int xoffset = 0; + int maxlen, remaining, opaque; + int is_cursor = FALSE; + static int *lpDx = NULL; + static int lpDx_len = 0; + int *lpDx_maybe; + int len2; /* for SURROGATE PAIR */ lattr &= LATTR_MODE; @@ -3183,17 +3370,6 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, if (attr & ATTR_WIDE) char_width *= 2; - if (len > IpDxLEN || IpDx[0] != char_width) { - int i; - if (len > IpDxLEN) { - sfree(IpDx); - IpDx = snewn(len + 16, int); - IpDxLEN = (len + 16); - } - for (i = 0; i < IpDxLEN; i++) - IpDx[i] = char_width; - } - /* Only want the left half of double width lines */ if (lattr != LATTR_NORM && x*2 >= term->cols) return; @@ -3203,17 +3379,15 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, x += offset_width; y += offset_height; - if ((attr & TATTR_ACTCURS) && (cfg.cursor_type == 0 || term->big_cursor)) { + if ((attr & TATTR_ACTCURS) && (cursor_type == 0 || term->big_cursor)) { attr &= ~(ATTR_REVERSE|ATTR_BLINK|ATTR_COLOURS); - if (bold_mode == BOLD_COLOURS) - attr &= ~ATTR_BOLD; - /* cursor fg and bg */ attr |= (260 << ATTR_FGSHIFT) | (261 << ATTR_BGSHIFT); + is_cursor = TRUE; } nfont = 0; - if (cfg.vtmode == VT_POORMAN && lattr != LATTR_NORM) { + if (vtmode == VT_POORMAN && lattr != LATTR_NORM) { /* Assume a poorman font is borken in other ways too. */ lattr = LATTR_WIDE; } else @@ -3230,6 +3404,7 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, if (attr & ATTR_NARROW) nfont |= FONT_NARROW; +#ifdef USES_VTLINE_HACK /* Special hack for the VT100 linedraw glyphs. */ if (text[0] >= 0x23BA && text[0] <= 0x23BD) { switch ((unsigned char) (text[0])) { @@ -3254,9 +3429,11 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, force_manual_underline = 1; } } +#endif /* Anything left as an original character set is unprintable. */ - if (DIRECT_CHAR(text[0])) { + if (DIRECT_CHAR(text[0]) && + (len < 2 || !IS_SURROGATE_PAIR(text[0], text[1]))) { int i; for (i = 0; i < len; i++) text[i] = 0xFFFD; @@ -3268,7 +3445,7 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, nfg = ((attr & ATTR_FGMASK) >> ATTR_FGSHIFT); nbg = ((attr & ATTR_BGMASK) >> ATTR_BGSHIFT); - if (bold_mode == BOLD_FONT && (attr & ATTR_BOLD)) + if (bold_font_mode == BOLD_FONT && (attr & ATTR_BOLD)) nfont |= FONT_BOLD; if (und_mode == UND_FONT && (attr & ATTR_UNDER)) nfont |= FONT_UNDERLINE; @@ -3288,11 +3465,11 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, nfg = nbg; nbg = t; } - if (bold_mode == BOLD_COLOURS && (attr & ATTR_BOLD)) { + if (bold_colours && (attr & ATTR_BOLD) && !is_cursor) { if (nfg < 16) nfg |= 8; else if (nfg >= 256) nfg |= 1; } - if (bold_mode == BOLD_COLOURS && (attr & ATTR_BLINK)) { + if (bold_colours && (attr & ATTR_BLINK)) { if (nbg < 16) nbg |= 8; else if (nbg >= 256) nbg |= 1; } @@ -3309,116 +3486,218 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, line_box.top = y; line_box.right = x + char_width * len; line_box.bottom = y + font_height; + /* adjust line_box.right for SURROGATE PAIR & VARIATION SELECTOR */ + { + int i; + int rc_width = 0; + for (i = 0; i < len ; i++) { + if (i+1 < len && IS_HIGH_VARSEL(text[i], text[i+1])) { + i++; + } else if (i+1 < len && IS_SURROGATE_PAIR(text[i], text[i+1])) { + rc_width += char_width; + i++; + } else if (IS_LOW_VARSEL(text[i])) { + /* do nothing */ + } else { + rc_width += char_width; + } + } + line_box.right = line_box.left + rc_width; + } /* Only want the left half of double width lines */ if (line_box.right > font_width*term->cols+offset_width) line_box.right = font_width*term->cols+offset_width; - /* We're using a private area for direct to font. (512 chars.) */ - if (ucsdata.dbcs_screenfont && (text[0] & CSET_MASK) == CSET_ACP) { - /* Ho Hum, dbcs fonts are a PITA! */ - /* To display on W9x I have to convert to UCS */ - static wchar_t *uni_buf = 0; - static int uni_len = 0; - int nlen, mptr; - if (len > uni_len) { - sfree(uni_buf); - uni_len = len; - uni_buf = snewn(uni_len, wchar_t); - } + if (font_varpitch) { + /* + * If we're using a variable-pitch font, we unconditionally + * draw the glyphs one at a time and centre them in their + * character cells (which means in particular that we must + * disable the lpDx mechanism). This gives slightly odd but + * generally reasonable results. + */ + xoffset = char_width / 2; + SetTextAlign(hdc, TA_TOP | TA_CENTER | TA_NOUPDATECP); + lpDx_maybe = NULL; + maxlen = 1; + } else { + /* + * In a fixed-pitch font, we draw the whole string in one go + * in the normal way. + */ + xoffset = 0; + SetTextAlign(hdc, TA_TOP | TA_LEFT | TA_NOUPDATECP); + lpDx_maybe = lpDx; + maxlen = len; + } - for(nlen = mptr = 0; mptr 0; + text += len, remaining -= len, x += char_width * len2) { + len = (maxlen < remaining ? maxlen : remaining); + /* don't divide SURROGATE PAIR and VARIATION SELECTOR */ + len2 = len; + if (maxlen == 1) { + if (remaining >= 1 && IS_SURROGATE_PAIR(text[0], text[1])) + len++; + if (remaining-len >= 1 && IS_LOW_VARSEL(text[len])) + len++; + else if (remaining-len >= 2 && + IS_HIGH_VARSEL(text[len], text[len+1])) + len += 2; + } - IpDx[0] = -1; - } else if (DIRECT_FONT(text[0])) { - static char *directbuf = NULL; - static int directlen = 0; - int i; - if (len > directlen) { - directlen = len; - directbuf = sresize(directbuf, directlen, char); + if (len > lpDx_len) { + lpDx_len = len * 9 / 8 + 16; + lpDx = sresize(lpDx, lpDx_len, int); + + if (lpDx_maybe) lpDx_maybe = lpDx; } - for (i = 0; i < len; i++) - directbuf[i] = text[i] & 0xFF; + { + int i; + /* only last char has dx width in SURROGATE PAIR and + * VARIATION sequence */ + for (i = 0; i < len; i++) { + lpDx[i] = char_width; + if (i+1 < len && IS_HIGH_VARSEL(text[i], text[i+1])) { + if (i > 0) lpDx[i-1] = 0; + lpDx[i] = 0; + i++; + lpDx[i] = char_width; + } else if (i+1 < len && IS_SURROGATE_PAIR(text[i],text[i+1])) { + lpDx[i] = 0; + i++; + lpDx[i] = char_width; + } else if (IS_LOW_VARSEL(text[i])) { + if (i > 0) lpDx[i-1] = 0; + lpDx[i] = char_width; + } + } + } - ExtTextOut(hdc, x, - y - font_height * (lattr == LATTR_BOT) + text_adjust, - ETO_CLIPPED | ETO_OPAQUE, &line_box, directbuf, len, IpDx); - if (bold_mode == BOLD_SHADOW && (attr & ATTR_BOLD)) { - SetBkMode(hdc, TRANSPARENT); + /* We're using a private area for direct to font. (512 chars.) */ + if (ucsdata.dbcs_screenfont && (text[0] & CSET_MASK) == CSET_ACP) { + /* Ho Hum, dbcs fonts are a PITA! */ + /* To display on W9x I have to convert to UCS */ + static wchar_t *uni_buf = 0; + static int uni_len = 0; + int nlen, mptr; + if (len > uni_len) { + sfree(uni_buf); + uni_len = len; + uni_buf = snewn(uni_len, wchar_t); + } - /* GRR: This draws the character outside it's box and can leave - * 'droppings' even with the clip box! I suppose I could loop it - * one character at a time ... yuk. - * - * Or ... I could do a test print with "W", and use +1 or -1 for this - * shift depending on if the leftmost column is blank... - */ - ExtTextOut(hdc, x - 1, - y - font_height * (lattr == - LATTR_BOT) + text_adjust, - ETO_CLIPPED, &line_box, directbuf, len, IpDx); - } - } else { - /* And 'normal' unicode characters */ - static WCHAR *wbuf = NULL; - static int wlen = 0; - int i; + for(nlen = mptr = 0; mptr directlen) { + directlen = len; + directbuf = sresize(directbuf, directlen, char); + } - for (i = 0; i < len; i++) - wbuf[i] = text[i]; - - /* print Glyphs as they are, without Windows' Shaping*/ - general_textout(hdc, x, y - font_height * (lattr == LATTR_BOT) + text_adjust, - &line_box, wbuf, len, IpDx, !(attr & TATTR_COMBINING)); - - /* And the shadow bold hack. */ - if (bold_mode == BOLD_SHADOW && (attr & ATTR_BOLD)) { - SetBkMode(hdc, TRANSPARENT); - ExtTextOutW(hdc, x - 1, - y - font_height * (lattr == - LATTR_BOT) + text_adjust, - ETO_CLIPPED, &line_box, wbuf, len, IpDx); - } + for (i = 0; i < len; i++) + directbuf[i] = text[i] & 0xFF; + + ExtTextOut(hdc, x + xoffset, + y - font_height * (lattr == LATTR_BOT) + text_adjust, + ETO_CLIPPED | (opaque ? ETO_OPAQUE : 0), + &line_box, directbuf, len, lpDx_maybe); + if (bold_font_mode == BOLD_SHADOW && (attr & ATTR_BOLD)) { + SetBkMode(hdc, TRANSPARENT); + + /* GRR: This draws the character outside its box and + * can leave 'droppings' even with the clip box! I + * suppose I could loop it one character at a time ... + * yuk. + * + * Or ... I could do a test print with "W", and use +1 + * or -1 for this shift depending on if the leftmost + * column is blank... + */ + ExtTextOut(hdc, x + xoffset - 1, + y - font_height * (lattr == + LATTR_BOT) + text_adjust, + ETO_CLIPPED, &line_box, directbuf, len, lpDx_maybe); + } + } else { + /* And 'normal' unicode characters */ + static WCHAR *wbuf = NULL; + static int wlen = 0; + int i; + + if (wlen < len) { + sfree(wbuf); + wlen = len; + wbuf = snewn(wlen, WCHAR); + } + + for (i = 0; i < len; i++) + wbuf[i] = text[i]; + + /* print Glyphs as they are, without Windows' Shaping*/ + general_textout(hdc, x + xoffset, + y - font_height * (lattr==LATTR_BOT) + text_adjust, + &line_box, wbuf, len, lpDx, + opaque && !(attr & TATTR_COMBINING)); + + /* And the shadow bold hack. */ + if (bold_font_mode == BOLD_SHADOW && (attr & ATTR_BOLD)) { + SetBkMode(hdc, TRANSPARENT); + ExtTextOutW(hdc, x + xoffset - 1, + y - font_height * (lattr == + LATTR_BOT) + text_adjust, + ETO_CLIPPED, &line_box, wbuf, len, lpDx_maybe); + } + } + + /* + * If we're looping round again, stop erasing the background + * rectangle. + */ + SetBkMode(hdc, TRANSPARENT); + opaque = FALSE; } if (lattr != LATTR_TOP && (force_manual_underline || (und_mode == UND_LINE @@ -3429,8 +3708,8 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, dec = dec * 2 - font_height; oldpen = SelectObject(hdc, CreatePen(PS_SOLID, 0, fg)); - MoveToEx(hdc, x, y + dec, NULL); - LineTo(hdc, x + len * char_width, y + dec); + MoveToEx(hdc, line_box.left, line_box.top + dec, NULL); + LineTo(hdc, line_box.right, line_box.top + dec); oldpen = SelectObject(hdc, oldpen); DeleteObject(oldpen); } @@ -3444,9 +3723,35 @@ void do_text(Context ctx, int x, int y, wchar_t *text, int len, { if (attr & TATTR_COMBINING) { unsigned long a = 0; - attr &= ~TATTR_COMBINING; + int len0 = 1; + /* don't divide SURROGATE PAIR and VARIATION SELECTOR */ + if (len >= 2 && IS_SURROGATE_PAIR(text[0], text[1])) + len0 = 2; + if (len-len0 >= 1 && IS_LOW_VARSEL(text[len0])) { + attr &= ~TATTR_COMBINING; + do_text_internal(ctx, x, y, text, len0+1, attr, lattr); + text += len0+1; + len -= len0+1; + a = TATTR_COMBINING; + } else if (len-len0 >= 2 && IS_HIGH_VARSEL(text[len0], text[len0+1])) { + attr &= ~TATTR_COMBINING; + do_text_internal(ctx, x, y, text, len0+2, attr, lattr); + text += len0+2; + len -= len0+2; + a = TATTR_COMBINING; + } else { + attr &= ~TATTR_COMBINING; + } + while (len--) { - do_text_internal(ctx, x, y, text, 1, attr | a, lattr); + if (len >= 1 && IS_SURROGATE_PAIR(text[0], text[1])) { + do_text_internal(ctx, x, y, text, 2, attr | a, lattr); + len--; + text++; + } else { + do_text_internal(ctx, x, y, text, 1, attr | a, lattr); + } + text++; a = TATTR_COMBINING; } @@ -3461,7 +3766,7 @@ void do_cursor(Context ctx, int x, int y, wchar_t *text, int len, int fnt_width; int char_width; HDC hdc = ctx; - int ctype = cfg.cursor_type; + int ctype = cursor_type; lattr &= LATTR_MODE; @@ -3606,13 +3911,16 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, int r, i, code; unsigned char *p = output; static int alt_sum = 0; + int funky_type = conf_get_int(conf, CONF_funky_type); + int no_applic_k = conf_get_int(conf, CONF_no_applic_k); + int ctrlaltkeys = conf_get_int(conf, CONF_ctrlaltkeys); + int nethack_keypad = conf_get_int(conf, CONF_nethack_keypad); HKL kbd_layout = GetKeyboardLayout(0); - /* keys is for ToAsciiEx. There's some ick here, see below. */ - static WORD keys[3]; + static wchar_t keys_unicode[3]; static int compose_char = 0; - static WPARAM compose_key = 0; + static WPARAM compose_keycode = 0; r = GetKeyboardState(keystate); if (!r) @@ -3662,12 +3970,12 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, else if (ch) debug((", $%02x", ch)); - if (keys[0]) - debug((", KB0=%02x", keys[0])); - if (keys[1]) - debug((", KB1=%02x", keys[1])); - if (keys[2]) - debug((", KB2=%02x", keys[2])); + if (keys_unicode[0]) + debug((", KB0=%04x", keys_unicode[0])); + if (keys_unicode[1]) + debug((", KB1=%04x", keys_unicode[1])); + if (keys_unicode[2]) + debug((", KB2=%04x", keys_unicode[2])); if ((keystate[VK_SHIFT] & 0x80) != 0) debug((", S")); @@ -3699,9 +4007,9 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, /* Nastyness with NUMLock - Shift-NUMLock is left alone though */ - if ((cfg.funky_type == FUNKY_VT400 || - (cfg.funky_type <= FUNKY_LINUX && term->app_keypad_keys && - !cfg.no_applic_k)) + if ((funky_type == FUNKY_VT400 || + (funky_type <= FUNKY_LINUX && term->app_keypad_keys && + !no_applic_k)) && wParam == VK_NUMLOCK && !(keystate[VK_SHIFT] & 0x80)) { wParam = VK_EXECUTE; @@ -3727,7 +4035,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, /* Make sure Ctrl-ALT is not the same as AltGr for ToAscii unless told. */ if (left_alt && (keystate[VK_CONTROL] & 0x80)) { - if (cfg.ctrlaltkeys) + if (ctrlaltkeys) keystate[VK_MENU] = 0; else { keystate[VK_RMENU] = 0x80; @@ -3741,16 +4049,16 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, /* Note if AltGr was pressed and if it was used as a compose key */ if (!compose_state) { - compose_key = 0x100; - if (cfg.compose_key) { + compose_keycode = 0x100; + if (conf_get_int(conf, CONF_compose_key)) { if (wParam == VK_MENU && (HIWORD(lParam) & KF_EXTENDED)) - compose_key = wParam; + compose_keycode = wParam; } if (wParam == VK_APPS) - compose_key = wParam; + compose_keycode = wParam; } - if (wParam == compose_key) { + if (wParam == compose_keycode) { if (compose_state == 0 && (HIWORD(lParam) & (KF_UP | KF_REPEAT)) == 0) compose_state = 1; @@ -3765,9 +4073,9 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, compose_state = 0; /* Sanitize the number pad if not using a PC NumPad */ - if (left_alt || (term->app_keypad_keys && !cfg.no_applic_k - && cfg.funky_type != FUNKY_XTERM) - || cfg.funky_type == FUNKY_VT400 || cfg.nethack_keypad || compose_state) { + if (left_alt || (term->app_keypad_keys && !no_applic_k + && funky_type != FUNKY_XTERM) + || funky_type == FUNKY_VT400 || nethack_keypad || compose_state) { if ((HIWORD(lParam) & KF_EXTENDED) == 0) { int nParam = 0; switch (wParam) { @@ -3844,15 +4152,17 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, request_paste(NULL); return 0; } - if (left_alt && wParam == VK_F4 && cfg.alt_f4) { + if (left_alt && wParam == VK_F4 && conf_get_int(conf, CONF_alt_f4)) { return -1; } - if (left_alt && wParam == VK_SPACE && cfg.alt_space) { + if (left_alt && wParam == VK_SPACE && conf_get_int(conf, + CONF_alt_space)) { SendMessage(hwnd, WM_SYSCOMMAND, SC_KEYMENU, 0); return -1; } - if (left_alt && wParam == VK_RETURN && cfg.fullscreenonaltenter && - (cfg.resize_action != RESIZE_DISABLED)) { + if (left_alt && wParam == VK_RETURN && + conf_get_int(conf, CONF_fullscreenonaltenter) && + (conf_get_int(conf, CONF_resize_action) != RESIZE_DISABLED)) { if ((HIWORD(lParam) & (KF_UP | KF_REPEAT)) != KF_REPEAT) flip_full_screen(); return -1; @@ -3864,7 +4174,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, } /* Nethack keypad */ - if (cfg.nethack_keypad && !left_alt) { + if (nethack_keypad && !left_alt) { switch (wParam) { case VK_NUMPAD1: *p++ = "bB\002\002"[shift_state & 3]; @@ -3900,9 +4210,9 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, if (!left_alt) { int xkey = 0; - if (cfg.funky_type == FUNKY_VT400 || - (cfg.funky_type <= FUNKY_LINUX && - term->app_keypad_keys && !cfg.no_applic_k)) switch (wParam) { + if (funky_type == FUNKY_VT400 || + (funky_type <= FUNKY_LINUX && + term->app_keypad_keys && !no_applic_k)) switch (wParam) { case VK_EXECUTE: xkey = 'P'; break; @@ -3916,7 +4226,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, xkey = 'S'; break; } - if (term->app_keypad_keys && !cfg.no_applic_k) + if (term->app_keypad_keys && !no_applic_k) switch (wParam) { case VK_NUMPAD0: xkey = 'p'; @@ -3953,7 +4263,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, xkey = 'n'; break; case VK_ADD: - if (cfg.funky_type == FUNKY_XTERM) { + if (funky_type == FUNKY_XTERM) { if (shift_state) xkey = 'l'; else @@ -3965,15 +4275,15 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, break; case VK_DIVIDE: - if (cfg.funky_type == FUNKY_XTERM) + if (funky_type == FUNKY_XTERM) xkey = 'o'; break; case VK_MULTIPLY: - if (cfg.funky_type == FUNKY_XTERM) + if (funky_type == FUNKY_XTERM) xkey = 'j'; break; case VK_SUBTRACT: - if (cfg.funky_type == FUNKY_XTERM) + if (funky_type == FUNKY_XTERM) xkey = 'm'; break; @@ -3995,13 +4305,13 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, } if (wParam == VK_BACK && shift_state == 0) { /* Backspace */ - *p++ = (cfg.bksp_is_delete ? 0x7F : 0x08); + *p++ = (conf_get_int(conf, CONF_bksp_is_delete) ? 0x7F : 0x08); *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++ = (conf_get_int(conf, CONF_bksp_is_delete) ? 0x08 : 0x7F); *p++ = 0; return -2; } @@ -4145,7 +4455,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, break; } /* Reorder edit keys to physical order */ - if (cfg.funky_type == FUNKY_VT400 && code <= 6) + if (funky_type == FUNKY_VT400 && code <= 6) code = "\0\2\1\4\5\3\6"[code]; if (term->vt52_mode && code > 0 && code <= 6) { @@ -4153,8 +4463,8 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, return p - output; } - if (cfg.funky_type == FUNKY_SCO && /* SCO function keys */ - code >= 11 && code <= 34) { + if (funky_type == FUNKY_SCO && code >= 11 && code <= 34) { + /* SCO function keys */ char codes[] = "MNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@[\\]^_`{"; int index = 0; switch (wParam) { @@ -4176,7 +4486,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, p += sprintf((char *) p, "\x1B[%c", codes[index]); return p - output; } - if (cfg.funky_type == FUNKY_SCO && /* SCO small keypad */ + if (funky_type == FUNKY_SCO && /* SCO small keypad */ code >= 1 && code <= 6) { char codes[] = "HL.FIG"; if (code == 3) { @@ -4186,7 +4496,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, } return p - output; } - if ((term->vt52_mode || cfg.funky_type == FUNKY_VT100P) && code >= 11 && code <= 24) { + if ((term->vt52_mode || funky_type == FUNKY_VT100P) && code >= 11 && code <= 24) { int offt = 0; if (code > 15) offt++; @@ -4199,18 +4509,19 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, sprintf((char *) p, "\x1BO%c", code + 'P' - 11 - offt); return p - output; } - if (cfg.funky_type == FUNKY_LINUX && code >= 11 && code <= 15) { + if (funky_type == FUNKY_LINUX && code >= 11 && code <= 15) { p += sprintf((char *) p, "\x1B[[%c", code + 'A' - 11); return p - output; } - if (cfg.funky_type == FUNKY_XTERM && code >= 11 && code <= 14) { + if (funky_type == FUNKY_XTERM && code >= 11 && code <= 14) { if (term->vt52_mode) p += sprintf((char *) p, "\x1B%c", code + 'P' - 11); else p += sprintf((char *) p, "\x1BO%c", code + 'P' - 11); return p - output; } - if (cfg.rxvt_homeend && (code == 1 || code == 4)) { + if ((code == 1 || code == 4) && + conf_get_int(conf, CONF_rxvt_homeend)) { p += sprintf((char *) p, code == 1 ? "\x1B[H" : "\x1BOw"); return p - output; } @@ -4270,7 +4581,8 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, BOOL capsOn=0; /* helg: clear CAPS LOCK state if caps lock switches to cyrillic */ - if(cfg.xlat_capslockcyr && keystate[VK_CAPITAL] != 0) { + if(keystate[VK_CAPITAL] != 0 && + conf_get_int(conf, CONF_xlat_capslockcyr)) { capsOn= !left_alt; keystate[VK_CAPITAL] = 0; } @@ -4279,6 +4591,9 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, * be is? There's indication on MS' website of an Inquire/InquireEx * functioning returning a KBINFO structure which tells us. */ if (osVersion.dwPlatformId == VER_PLATFORM_WIN32_NT) { + r = ToUnicodeEx(wParam, scan, keystate, keys_unicode, + lenof(keys_unicode), 0, kbd_layout); + } else { /* XXX 'keys' parameter is declared in MSDN documentation as * 'LPWORD lpChar'. * The experience of a French user indicates that on @@ -4289,12 +4604,17 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, * Win9x/NT split, but I suspect it's worse than that. * See wishlist item `win-dead-keys' for more horrible detail * and speculations. */ - BYTE keybs[3]; int i; - r = ToAsciiEx(wParam, scan, keystate, (LPWORD)keybs, 0, kbd_layout); - for (i=0; i<3; i++) keys[i] = keybs[i]; - } else { + static WORD keys[3]; + static BYTE keysb[3]; r = ToAsciiEx(wParam, scan, keystate, keys, 0, kbd_layout); + if (r > 0) { + for (i = 0; i < r; i++) { + keysb[i] = (BYTE)keys[i]; + } + MultiByteToWideChar(CP_ACP, 0, (LPCSTR)keysb, r, + keys_unicode, lenof(keys_unicode)); + } } #ifdef SHOW_TOASCII_RESULT if (r == 1 && !key_down) { @@ -4304,13 +4624,13 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, else debug((", LCH(%d)", alt_sum)); } else { - debug((", ACH(%d)", keys[0])); + debug((", ACH(%d)", keys_unicode[0])); } } else if (r > 0) { int r1; debug((", ASC(")); for (r1 = 0; r1 < r; r1++) { - debug(("%s%d", r1 ? "," : "", keys[r1])); + debug(("%s%d", r1 ? "," : "", keys_unicode[r1])); } debug((")")); } @@ -4327,18 +4647,18 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, p = output; for (i = 0; i < r; i++) { - unsigned char ch = (unsigned char) keys[i]; + wchar_t wch = keys_unicode[i]; - if (compose_state == 2 && (ch & 0x80) == 0 && ch > ' ') { - compose_char = ch; + if (compose_state == 2 && wch >= ' ' && wch < 0x80) { + compose_char = wch; compose_state++; continue; } - if (compose_state == 3 && (ch & 0x80) == 0 && ch > ' ') { + if (compose_state == 3 && wch >= ' ' && wch < 0x80) { int nc; compose_state = 0; - if ((nc = check_compose(compose_char, ch)) == -1) { + if ((nc = check_compose(compose_char, wch)) == -1) { MessageBeep(MB_ICONHAND); return 0; } @@ -4359,7 +4679,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, if (ldisc) luni_send(ldisc, &keybuf, 1, 1); } else { - ch = (char) alt_sum; + char ch = (char) alt_sum; /* * We need not bother about stdin * backlogs here, because in GUI PuTTY @@ -4377,40 +4697,39 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, } else { term_seen_key_event(term); if (ldisc) - lpage_send(ldisc, kbd_codepage, &ch, 1, 1); + luni_send(ldisc, &wch, 1, 1); } } else { - if(capsOn && ch < 0x80) { + if(capsOn && wch < 0x80) { WCHAR cbuf[2]; cbuf[0] = 27; - cbuf[1] = xlat_uskbd2cyrllic(ch); + cbuf[1] = xlat_uskbd2cyrllic(wch); term_seen_key_event(term); if (ldisc) luni_send(ldisc, cbuf+!left_alt, 1+!!left_alt, 1); } else { - char cbuf[2]; + WCHAR cbuf[2]; cbuf[0] = '\033'; - cbuf[1] = ch; + cbuf[1] = wch; term_seen_key_event(term); if (ldisc) - lpage_send(ldisc, kbd_codepage, - cbuf+!left_alt, 1+!!left_alt, 1); + luni_send(ldisc, cbuf +!left_alt, 1+!!left_alt, 1); } } show_mouseptr(0); } /* This is so the ALT-Numpad and dead keys work correctly. */ - keys[0] = 0; + keys_unicode[0] = 0; return p - output; } /* If we're definitly not building up an ALT-54321 then clear it */ if (!left_alt) - keys[0] = 0; + keys_unicode[0] = 0; /* If we will be using alt_sum fix the 256s */ - else if (keys[0] && (in_utf(term) || ucsdata.dbcs_screenfont)) - keys[0] = 10; + else if (keys_unicode[0] && (in_utf(term) || ucsdata.dbcs_screenfont)) + keys_unicode[0] = 10; } /* @@ -4420,7 +4739,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, * we return -1, which means Windows will give the keystroke * its default handling (i.e. bring up the System menu). */ - if (wParam == VK_MENU && !cfg.alt_only) + if (wParam == VK_MENU && !conf_get_int(conf, CONF_alt_only)) return 0; return -1; @@ -4431,7 +4750,7 @@ void set_title(void *frontend, char *title) sfree(window_name); window_name = snewn(1 + strlen(title), char); strcpy(window_name, title); - if (cfg.win_name_always || !IsIconic(hwnd)) + if (conf_get_int(conf, CONF_win_name_always) || !IsIconic(hwnd)) SetWindowText(hwnd, title); } @@ -4440,7 +4759,7 @@ void set_icon(void *frontend, char *title) sfree(icon_name); icon_name = snewn(1 + strlen(title), char); strcpy(icon_name, title); - if (!cfg.win_name_always && IsIconic(hwnd)) + if (!conf_get_int(conf, CONF_win_name_always) && IsIconic(hwnd)) SetWindowText(hwnd, title); } @@ -4448,7 +4767,8 @@ void set_sbar(void *frontend, int total, int start, int page) { SCROLLINFO si; - if (is_full_screen() ? !cfg.scrollbar_in_fullscreen : !cfg.scrollbar) + if (!conf_get_int(conf, is_full_screen() ? + CONF_scrollbar_in_fullscreen : CONF_scrollbar)) return; si.cbSize = sizeof(si); @@ -4496,7 +4816,7 @@ void palette_set(void *frontend, int n, int r, int g, int b) { if (n >= 16) n += 256 - 16; - if (n > NALLCOLOURS) + if (n >= NALLCOLOURS) return; real_palette_set(n, r, g, b); if (pal) { @@ -4596,15 +4916,22 @@ void write_clip(void *frontend, wchar_t * data, int *attr, int len, int must_des GlobalFree(clipdata2); return; } - if (!(lock = GlobalLock(clipdata))) + if (!(lock = GlobalLock(clipdata))) { + GlobalFree(clipdata); + GlobalFree(clipdata2); return; - if (!(lock2 = GlobalLock(clipdata2))) + } + if (!(lock2 = GlobalLock(clipdata2))) { + GlobalUnlock(clipdata); + GlobalFree(clipdata); + GlobalFree(clipdata2); return; + } memcpy(lock, data, len * sizeof(wchar_t)); WideCharToMultiByte(CP_ACP, 0, data, len, lock2, len2, NULL, NULL); - if (cfg.rtf_paste) { + if (conf_get_int(conf, CONF_rtf_paste)) { wchar_t unitab[256]; char *rtf = NULL; unsigned char *tdata = (unsigned char *)lock2; @@ -4619,13 +4946,14 @@ void write_clip(void *frontend, wchar_t * data, int *attr, int len, int must_des int attrUnder, lastAttrUnder = 0; int palette[NALLCOLOURS]; int numcolours; + FontSpec *font = conf_get_fontspec(conf, CONF_font); get_unitab(CP_ACP, unitab, 0); - rtfsize = 100 + strlen(cfg.font.name); + rtfsize = 100 + strlen(font->name); rtf = snewn(rtfsize, char); rtflen = sprintf(rtf, "{\\rtf1\\ansi\\deff0{\\fonttbl\\f0\\fmodern %s;}\\f0\\fs%d", - cfg.font.name, cfg.font.height*2); + font->name, font->height*2); /* * Add colour palette @@ -4648,7 +4976,7 @@ void write_clip(void *frontend, wchar_t * data, int *attr, int len, int must_des bgcolour = tmpcolour; } - if (bold_mode == BOLD_COLOURS && (attr[i] & ATTR_BOLD)) { + if (bold_colours && (attr[i] & ATTR_BOLD)) { if (fgcolour < 8) /* ANSI colours */ fgcolour += 8; else if (fgcolour >= 256) /* Default colours */ @@ -4739,7 +5067,7 @@ void write_clip(void *frontend, wchar_t * data, int *attr, int len, int must_des bgcolour = tmpcolour; } - if (bold_mode == BOLD_COLOURS && (attr[tindex] & ATTR_BOLD)) { + if (bold_colours && (attr[tindex] & ATTR_BOLD)) { if (fgcolour < 8) /* ANSI colours */ fgcolour += 8; else if (fgcolour >= 256) /* Default colours */ @@ -4756,7 +5084,7 @@ void write_clip(void *frontend, wchar_t * data, int *attr, int len, int must_des /* * Collect other attributes */ - if (bold_mode != BOLD_COLOURS) + if (bold_font_mode != BOLD_NONE) attrBold = attr[tindex] & ATTR_BOLD; else attrBold = 0; @@ -4775,7 +5103,7 @@ void write_clip(void *frontend, wchar_t * data, int *attr, int len, int must_des bgcolour = -1; /* No coloring */ if (fgcolour >= 256) { /* Default colour */ - if (bold_mode == BOLD_COLOURS && (fgcolour & 1) && bgcolour == -1) + if (bold_colours && (fgcolour & 1) && bgcolour == -1) attrBold = ATTR_BOLD; /* Emphasize text with bold attribute */ fgcolour = -1; /* No coloring */ @@ -5040,6 +5368,22 @@ void modalfatalbox(char *fmt, ...) cleanup_exit(1); } +/* + * Print a message box and don't close the connection. + */ +void nonfatal(char *fmt, ...) +{ + va_list ap; + char *stuff, morestuff[100]; + + va_start(ap, fmt); + stuff = dupvprintf(fmt, ap); + va_end(ap); + sprintf(morestuff, "%.70s Error", appname); + MessageBox(hwnd, stuff, morestuff, MB_ICONERROR | MB_OK); + sfree(stuff); +} + DECL_WINDOWS_FUNCTION(static, BOOL, FlashWindowEx, (PFLASHWINFO)); static void init_flashwindow(void) @@ -5071,9 +5415,9 @@ static int flashing = 0; * Timer for platforms where we must maintain window flashing manually * (e.g., Win95). */ -static void flash_window_timer(void *ctx, long now) +static void flash_window_timer(void *ctx, unsigned long now) { - if (flashing && now - next_flash >= 0) { + if (flashing && now == next_flash) { flash_window(1); } } @@ -5084,7 +5428,8 @@ static void flash_window_timer(void *ctx, long now) */ static void flash_window(int mode) { - if ((mode == 0) || (cfg.beep_ind == B_IND_DISABLED)) { + int beep_ind = conf_get_int(conf, CONF_beep_ind); + if ((mode == 0) || (beep_ind == B_IND_DISABLED)) { /* stop */ if (flashing) { flashing = 0; @@ -5106,7 +5451,7 @@ static void flash_window(int mode) * "flashing" mode, although I haven't seen this * documented. */ flash_window_ex(FLASHW_ALL | FLASHW_TIMER, - (cfg.beep_ind == B_IND_FLASH ? 0 : 2), + (beep_ind == B_IND_FLASH ? 0 : 2), 0 /* system cursor blink rate */); /* No need to schedule timer */ } else { @@ -5115,7 +5460,7 @@ static void flash_window(int mode) } } - } else if ((mode == 1) && (cfg.beep_ind == B_IND_FLASH)) { + } else if ((mode == 1) && (beep_ind == B_IND_FLASH)) { /* maintain */ if (flashing && !p_FlashWindowEx) { FlashWindow(hwnd, TRUE); /* toggle */ @@ -5149,16 +5494,17 @@ void do_beep(void *frontend, int mode) */ lastbeep = GetTickCount(); } else if (mode == BELL_WAVEFILE) { - if (!PlaySound(cfg.bell_wavefile.path, NULL, + Filename *bell_wavefile = conf_get_filename(conf, CONF_bell_wavefile); + if (!PlaySound(bell_wavefile->path, NULL, SND_ASYNC | SND_FILENAME)) { - char buf[sizeof(cfg.bell_wavefile.path) + 80]; + char buf[sizeof(bell_wavefile->path) + 80]; char otherbuf[100]; sprintf(buf, "Unable to play sound file\n%s\n" - "Using default sound instead", cfg.bell_wavefile.path); + "Using default sound instead", bell_wavefile->path); sprintf(otherbuf, "%.70s Sound Error", appname); MessageBox(hwnd, buf, otherbuf, MB_OK | MB_ICONEXCLAMATION); - cfg.beep = BELL_DEFAULT; + conf_set_int(conf, CONF_beep, BELL_DEFAULT); } } else if (mode == BELL_PCSPEAKER) { static long lastbeep = 0; @@ -5204,8 +5550,9 @@ void set_iconic(void *frontend, int iconic) */ void move_window(void *frontend, int x, int y) { - if (cfg.resize_action == RESIZE_DISABLED || - cfg.resize_action == RESIZE_FONT || + int resize_action = conf_get_int(conf, CONF_resize_action); + if (resize_action == RESIZE_DISABLED || + resize_action == RESIZE_FONT || IsZoomed(hwnd)) return; @@ -5218,7 +5565,7 @@ void move_window(void *frontend, int x, int y) */ void set_zorder(void *frontend, int top) { - if (cfg.alwaysontop) + if (conf_get_int(conf, CONF_alwaysontop)) return; /* ignore */ SetWindowPos(hwnd, top ? HWND_TOP : HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); @@ -5340,7 +5687,7 @@ static void make_full_screen() /* Remove the window furniture. */ style = GetWindowLongPtr(hwnd, GWL_STYLE); style &= ~(WS_CAPTION | WS_BORDER | WS_THICKFRAME); - if (cfg.scrollbar_in_fullscreen) + if (conf_get_int(conf, CONF_scrollbar_in_fullscreen)) style |= WS_VSCROLL; else style &= ~WS_VSCROLL; @@ -5375,11 +5722,11 @@ static void clear_full_screen() /* Reinstate the window furniture. */ style = oldstyle = GetWindowLongPtr(hwnd, GWL_STYLE); style |= WS_CAPTION | WS_BORDER; - if (cfg.resize_action == RESIZE_DISABLED) + if (conf_get_int(conf, CONF_resize_action) == RESIZE_DISABLED) style &= ~WS_THICKFRAME; else style |= WS_THICKFRAME; - if (cfg.scrollbar) + if (conf_get_int(conf, CONF_scrollbar)) style |= WS_VSCROLL; else style &= ~WS_VSCROLL; @@ -5434,6 +5781,11 @@ int from_backend_untrusted(void *frontend, const char *data, int len) return term_data_untrusted(term, data, len); } +int from_backend_eof(void *frontend) +{ + return TRUE; /* do respond to incoming EOF with outgoing */ +} + int get_userpass_input(prompts_t *p, unsigned char *in, int inlen) { int ret;