X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/putty/blobdiff_plain/19caf3185084d85a282e088cf6b7ca5cb81ce049..6475463f799b980dcc922bb113a8d6294beceba4:/windows/window.c diff --git a/windows/window.c b/windows/window.c index f0006f04..c8c2b56d 100644 --- a/windows/window.c +++ b/windows/window.c @@ -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; @@ -311,6 +311,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) @@ -1260,7 +1269,6 @@ static void exact_textout(HDC hdc, int x, int y, CONST RECT *lprc, gcpr.lpGlyphs = (void *)buffer; gcpr.lpClass = (void *)classbuffer; gcpr.nGlyphs = cbCount; - GetCharacterPlacementW(hdc, lpString, cbCount, 0, &gcpr, FLI_MASK | GCP_CLASSIN | GCP_DIACRITIC); @@ -1283,15 +1291,7 @@ static void general_textout(HDC hdc, int x, int y, CONST RECT *lprc, CONST INT *lpDx, int opaque) { int i, j, xp, xn; - RECT newrc; - -#ifdef FIXME_REMOVE_BEFORE_CHECKIN -int k; -debug(("general_textout: %d,%d", x, y)); -for(k=0;kleft, lprc->top, lprc->right, lprc->bottom)); -debug(("\n")); -#endif + int bkmode = 0, got_bkmode = FALSE; xp = xn = x; @@ -1312,44 +1312,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; } /* @@ -1418,11 +1430,18 @@ static void init_fonts(int pick_width, int pick_height) 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", @@ -1509,7 +1528,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 @@ -1578,7 +1597,7 @@ static void another_font(int 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); + DEFAULT_PITCH | FF_DONTCARE, s); fontflag[fontno] = 1; } @@ -3198,7 +3217,11 @@ 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; + static int *lpDx = NULL; + static int lpDx_len = 0; + int *lpDx_maybe; lattr &= LATTR_MODE; @@ -3207,17 +3230,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; @@ -3338,111 +3350,167 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, 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 * len) { + len = (maxlen < remaining ? maxlen : remaining); - 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) { + if (len > lpDx_len) { + lpDx_len = len * 9 / 8 + 16; + lpDx = sresize(lpDx, lpDx_len, int); + } + } + { + int i; + for (i = 0; i < len; i++) + lpDx[i] = char_width; + } - for (i = 0; i < len; i++) - directbuf[i] = text[i] & 0xFF; + /* 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); + } + + for(nlen = mptr = 0; mptr directlen) { + directlen = len; + directbuf = sresize(directbuf, directlen, char); + } - /* 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 (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_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); + } - 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_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); + } + } - 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); - } + /* + * 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