X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/bda368a515dc80afe90f2a35c3eb123b2489aa9f..53126a62c0456c53cabb6cb83741f60c02433044:/windows/window.c diff --git a/windows/window.c b/windows/window.c index 2b80430d..9060bd10 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; @@ -317,6 +317,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { WNDCLASS wndclass; MSG msg; + HRESULT hr; int guess_width, guess_height; hinst = inst; @@ -355,6 +356,18 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) init_flashwindow(); /* + * Initialize COM. + */ + hr = CoInitialize(NULL); + if (hr != S_OK && hr != S_FALSE) { + char *str = dupprintf("%s Fatal Error", appname); + MessageBox(NULL, "Failed to initialize COM subsystem", + str, MB_OK | MB_ICONEXCLAMATION); + sfree(str); + return 1; + } + + /* * Process the command line. */ { @@ -381,14 +394,21 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) /* * 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. + * easily dealt with before the line is broken up into words. + * These are the old-fashioned but convenient @sessionname and + * the internal-use-only &sharedmemoryhandle, neither of which + * are combined with anything else. */ while (*p && isspace(*p)) p++; if (*p == '@') { + /* + * An initial @ means that the whole of the rest of the + * command line should be treated as the name of a saved + * session, with _no quoting or escaping_. This makes it a + * very convenient means of automated saved-session + * launching, via IDM_SAVEDSESS or Windows 7 jump lists. + */ int i = strlen(p); while (i > 1 && isspace(p[i - 1])) i--; @@ -867,6 +887,9 @@ void cleanup_exit(int code) } shutdown_help(); + /* Clean up COM. */ + CoUninitialize(); + exit(code); } @@ -1237,7 +1260,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); @@ -1301,7 +1323,8 @@ for(k=0;ktop; newrc.bottom = lprc->bottom; ExtTextOutW(hdc, xp, y, ETO_CLIPPED | (opaque ? ETO_OPAQUE : 0), - &newrc, lpString+i, j-i, lpDx+i); + &newrc, lpString+i, j-i, + font_varpitch ? NULL : lpDx+i); } i = j; @@ -1329,6 +1353,37 @@ debug(("general_textout: done, xn=%d\n", xn)); assert(xn - x >= lprc->right - lprc->left); } +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; +} + /* * Initialise all the fonts we will need initially. There may be as many as * three or as few as one. The other (potentially) twenty-one fonts are done @@ -1395,11 +1450,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", @@ -1486,7 +1548,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 @@ -1555,7 +1617,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; } @@ -1950,6 +2012,7 @@ 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; switch (message) { @@ -2044,7 +2107,6 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, / MENU_SAVED_STEP) + 1; if (sessno < (unsigned)sesslist.nsessions) { char *session = sesslist.sessions[sessno]; - /* XXX spaces? quotes? "-load"? */ cl = dupprintf("putty @%s", session); inherit_handles = FALSE; freecl = TRUE; @@ -2627,7 +2689,8 @@ 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 && !is_alt_pressed()) { + if (cfg.resize_action == RESIZE_TERM || + (cfg.resize_action == RESIZE_EITHER && !is_alt_pressed())) { int width, height, w, h, ew, eh; LPRECT r = (LPRECT) lParam; @@ -2733,13 +2796,36 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, cfg.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; + } } + processed_resize = TRUE; + if (cfg.resize_action == RESIZE_DISABLED) { /* A resize, well it better be a minimize. */ reset_window(-1); @@ -2750,55 +2836,57 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, width = LOWORD(lParam); height = HIWORD(lParam); - if (!resizing) { - if (wParam == SIZE_MAXIMIZED && !was_zoomed) { - was_zoomed = 1; - 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(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(term, prev_rows, prev_cols, cfg.savelines); - if (cfg.resize_action != RESIZE_FONT) - reset_window(2); - else - reset_window(0); - } - /* This is an unexpected resize, these will normally happen - * if the window is too large. Probably either the user - * selected a huge font or the screen size has changed. - * - * This is also called with minimize. - */ - else reset_window(-1); - } - - /* - * Don't call back->size in mid-resize. (To prevent - * massive numbers of resize events getting sent - * down the connection during an NT opaque drag.) - */ - if (resizing) { - if (cfg.resize_action != RESIZE_FONT && !is_alt_pressed()) { + if (wParam == SIZE_MAXIMIZED && !was_zoomed) { + was_zoomed = 1; + 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(term, h, w, cfg.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 (w < 1) w = 1; + h = (height-cfg.window_border*2) / font_height; + if (h < 1) h = 1; + term_size(term, h, w, cfg.savelines); + reset_window(2); + } else if (cfg.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 && + !is_alt_pressed())) { + w = (width-cfg.window_border*2) / font_width; + if (w < 1) w = 1; + h = (height-cfg.window_border*2) / font_height; + if (h < 1) h = 1; + + if (resizing) { + /* + * Don't call back->size in mid-resize. (To + * prevent massive numbers of resize events + * getting sent down the connection during an NT + * opaque drag.) + */ need_backend_resize = TRUE; - w = (width-cfg.window_border*2) / font_width; - if (w < 1) w = 1; - h = (height-cfg.window_border*2) / font_height; - if (h < 1) h = 1; - cfg.height = h; cfg.width = w; - } else - reset_window(0); + } else { + term_size(term, h, w, cfg.savelines); + } + } else { + reset_window(0); } } sys_cursor_update(); @@ -3149,7 +3237,10 @@ 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; + int xoffset = 0; + int maxlen, remaining, opaque; static int *IpDx = 0, IpDxLEN = 0; + int *IpDxReal; lattr &= LATTR_MODE; @@ -3289,111 +3380,155 @@ 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); - } - - for(nlen = mptr = 0; mptr directlen) { - directlen = len; - directbuf = sresize(directbuf, directlen, char); - } + opaque = TRUE; /* start by erasing the rectangle */ + for (remaining = len; remaining > 0; + text += len, remaining -= len, x += char_width * len) { + len = (maxlen < remaining ? maxlen : remaining); + + /* 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 (i = 0; i < len; i++) - directbuf[i] = text[i] & 0xFF; + 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, IpDxReal); + 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, IpDxReal); + } + } 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, IpDx, + 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, IpDxReal); + } + } - 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