X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/e3be8de51cd988d07cba827ef3fc7bb17f2b2625..8df11cad382be13bc3250340039d2d07544b5995:/window.c diff --git a/window.c b/window.c index 4cb60030..9f1dbe33 100644 --- a/window.c +++ b/window.c @@ -111,6 +111,7 @@ static struct unicode_data ucsdata; static int session_closed; static const struct telnet_special *specials; +static int n_specials; static struct { HMENU menu; @@ -525,7 +526,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) /* See if host is of the form user@host */ if (cfg.host[0] != '\0') { - char *atsign = strchr(cfg.host, '@'); + char *atsign = strrchr(cfg.host, '@'); /* Make sure we're not overflowing the user field */ if (atsign) { if (atsign - cfg.host < sizeof cfg.username) { @@ -686,8 +687,6 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) SetScrollInfo(hwnd, SB_VERT, &si, FALSE); } - start_backend(); - /* * Prepare the mouse handler. */ @@ -742,7 +741,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) } } - update_specials_menu(NULL); + start_backend(); /* * Set up the initial input locale. @@ -917,20 +916,48 @@ void update_specials_menu(void *frontend) specials = NULL; if (specials) { - p = CreateMenu(); - for (i = 0; specials[i].name; i++) { + /* We can't use Windows to provide a stack for submenus, so + * here's a lame "stack" that will do for now. */ + HMENU saved_menu = NULL; + int nesting = 1; + p = CreatePopupMenu(); + for (i = 0; nesting > 0; i++) { assert(IDM_SPECIAL_MIN + 0x10 * i < IDM_SPECIAL_MAX); - if (*specials[i].name) + switch (specials[i].code) { + case TS_SEP: + AppendMenu(p, MF_SEPARATOR, 0, 0); + break; + case TS_SUBMENU: + assert(nesting < 2); + nesting++; + saved_menu = p; /* XXX lame stacking */ + p = CreatePopupMenu(); + AppendMenu(saved_menu, MF_POPUP | MF_ENABLED, + (UINT) p, specials[i].name); + break; + case TS_EXITMENU: + nesting--; + if (nesting) { + p = saved_menu; /* XXX lame stacking */ + saved_menu = NULL; + } + break; + default: AppendMenu(p, MF_ENABLED, IDM_SPECIAL_MIN + 0x10 * i, specials[i].name); - else - AppendMenu(p, MF_SEPARATOR, 0, 0); + break; + } } - } else + /* Squirrel the highest special. */ + n_specials = i - 1; + } else { p = NULL; + n_specials = 0; + } for (j = 0; j < lenof(popup_menus); j++) { if (menu_already_exists) { + /* XXX does this free up all submenus? */ DeleteMenu(popup_menus[j].menu, popup_menus[j].specials_submenu_pos, MF_BYPOSITION); @@ -945,7 +972,7 @@ void update_specials_menu(void *frontend) InsertMenu(popup_menus[j].menu, popup_menus[j].specials_submenu_pos, MF_BYPOSITION | MF_POPUP | MF_ENABLED, - (UINT) p, "Special Command"); + (UINT) p, "S&pecial Command"); } } } @@ -1136,7 +1163,7 @@ static void init_palette(void) */ static void exact_textout(HDC hdc, int x, int y, CONST RECT *lprc, unsigned short *lpString, UINT cbCount, - CONST INT *lpDx) + CONST INT *lpDx, int opaque) { GCP_RESULTSW gcpr; @@ -1152,10 +1179,11 @@ static void exact_textout(HDC hdc, int x, int y, CONST RECT *lprc, gcpr.nGlyphs = cbCount; GetCharacterPlacementW(hdc, lpString, cbCount, 0, &gcpr, - FLI_MASK | GCP_CLASSIN); + FLI_MASK | GCP_CLASSIN | GCP_DIACRITIC); - ExtTextOut(hdc, x, y, ETO_GLYPH_INDEX | ETO_CLIPPED | ETO_OPAQUE, lprc, - buffer, cbCount, lpDx); + ExtTextOut(hdc, x, y, + ETO_GLYPH_INDEX | ETO_CLIPPED | (opaque ? ETO_OPAQUE : 0), + lprc, buffer, cbCount, lpDx); } /* @@ -2089,20 +2117,16 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, } if (wParam >= IDM_SPECIAL_MIN && wParam <= IDM_SPECIAL_MAX) { int i = (wParam - IDM_SPECIAL_MIN) / 0x10; - int j; /* * Ensure we haven't been sent a bogus SYSCOMMAND * which would cause us to reference invalid memory * and crash. Perhaps I'm just too paranoid here. */ - for (j = 0; j < i; j++) - if (!specials || !specials[j].name) - break; - if (j == i) { - if (back) - back->special(backhandle, specials[i].code); - net_pending_errors(); - } + if (i >= n_specials) + break; + if (back) + back->special(backhandle, specials[i].code); + net_pending_errors(); } } break; @@ -2188,7 +2212,6 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, mi.rcMonitor.top == pt.y) { mouse_on_hotspot = 1; } - CloseHandle(mon); } } #else @@ -2767,6 +2790,16 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, return TRUE; } break; + case WM_SYSCOLORCHANGE: + if (cfg.system_colour) { + /* Refresh palette from system colours. */ + /* XXX actually this zaps the entire palette. */ + systopalette(); + init_palette(); + /* Force a repaint of the terminal window. */ + term_invalidate(term); + } + break; case WM_AGENT_CALLBACK: { struct agent_callback *c = (struct agent_callback *)lParam; @@ -2891,19 +2924,22 @@ static void sys_cursor_update(void) * * We are allowed to fiddle with the contents of `text'. */ -void do_text(Context ctx, int x, int y, char *text, int len, - unsigned long attr, int lattr) +void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, + unsigned long attr, int lattr) { COLORREF fg, bg, t; int nfg, nbg, nfont; HDC hdc = ctx; RECT line_box; int force_manual_underline = 0; - int fnt_width = font_width * (1 + (lattr != LATTR_NORM)); - int char_width = fnt_width; + int fnt_width, char_width; int text_adjust = 0; static int *IpDx = 0, IpDxLEN = 0; + lattr &= LATTR_MODE; + + char_width = fnt_width = font_width * (1 + (lattr != LATTR_NORM)); + if (attr & ATTR_WIDE) char_width *= 2; @@ -2951,43 +2987,39 @@ void do_text(Context ctx, int x, int y, char *text, int len, nfont |= FONT_NARROW; /* Special hack for the VT100 linedraw glyphs. */ - if ((attr & CSET_MASK) == 0x2300) { - if (text[0] >= (char) 0xBA && text[0] <= (char) 0xBD) { - switch ((unsigned char) (text[0])) { - case 0xBA: - text_adjust = -2 * font_height / 5; - break; - case 0xBB: - text_adjust = -1 * font_height / 5; - break; - case 0xBC: - text_adjust = font_height / 5; - break; - case 0xBD: - text_adjust = 2 * font_height / 5; - break; - } - if (lattr == LATTR_TOP || lattr == LATTR_BOT) - text_adjust *= 2; - attr &= ~CSET_MASK; - text[0] = (char) (ucsdata.unitab_xterm['q'] & CHAR_MASK); - attr |= (ucsdata.unitab_xterm['q'] & CSET_MASK); - if (attr & ATTR_UNDER) { - attr &= ~ATTR_UNDER; - force_manual_underline = 1; - } + if (text[0] >= 0x23BA && text[0] <= 0x23BD) { + switch ((unsigned char) (text[0])) { + case 0xBA: + text_adjust = -2 * font_height / 5; + break; + case 0xBB: + text_adjust = -1 * font_height / 5; + break; + case 0xBC: + text_adjust = font_height / 5; + break; + case 0xBD: + text_adjust = 2 * font_height / 5; + break; + } + if (lattr == LATTR_TOP || lattr == LATTR_BOT) + text_adjust *= 2; + text[0] = ucsdata.unitab_xterm['q']; + if (attr & ATTR_UNDER) { + attr &= ~ATTR_UNDER; + force_manual_underline = 1; } } /* Anything left as an original character set is unprintable. */ - if (DIRECT_CHAR(attr)) { - attr &= ~CSET_MASK; - attr |= 0xFF00; - memset(text, 0xFD, len); + if (DIRECT_CHAR(text[0])) { + int i; + for (i = 0; i < len; i++) + text[i] = 0xFFFD; } /* OEM CP */ - if ((attr & CSET_MASK) == ATTR_OEMCP) + if ((text[0] & CSET_MASK) == CSET_OEMCP) nfont |= FONT_OEM; nfg = ((attr & ATTR_FGMASK) >> ATTR_FGSHIFT); @@ -3023,7 +3055,10 @@ void do_text(Context ctx, int x, int y, char *text, int len, SelectObject(hdc, fonts[nfont]); SetTextColor(hdc, fg); SetBkColor(hdc, bg); - SetBkMode(hdc, OPAQUE); + if (attr & TATTR_COMBINING) + SetBkMode(hdc, TRANSPARENT); + else + SetBkMode(hdc, OPAQUE); line_box.left = x; line_box.top = y; line_box.right = x + char_width * len; @@ -3034,7 +3069,7 @@ void do_text(Context ctx, int x, int y, char *text, int len, 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 && (attr & CSET_MASK) == ATTR_ACP) { + 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; @@ -3049,15 +3084,20 @@ void do_text(Context ctx, int x, int y, char *text, int len, for(nlen = mptr = 0; mptr directlen) { + directlen = len; + directbuf = sresize(directbuf, directlen, char); + } + + for (i = 0; i < len; i++) + directbuf[i] = text[i] & 0xFF; + ExtTextOut(hdc, x, y - font_height * (lattr == LATTR_BOT) + text_adjust, - ETO_CLIPPED | ETO_OPAQUE, &line_box, text, len, IpDx); + ETO_CLIPPED | ETO_OPAQUE, &line_box, directbuf, len, IpDx); if (bold_mode == BOLD_SHADOW && (attr & ATTR_BOLD)) { SetBkMode(hdc, TRANSPARENT); @@ -3093,24 +3144,26 @@ void do_text(Context ctx, int x, int y, char *text, int len, ExtTextOut(hdc, x - 1, y - font_height * (lattr == LATTR_BOT) + text_adjust, - ETO_CLIPPED, &line_box, text, len, IpDx); + ETO_CLIPPED, &line_box, directbuf, len, IpDx); } } 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] = (WCHAR) ((attr & CSET_MASK) + (text[i] & CHAR_MASK)); + wbuf[i] = text[i]; /* print Glyphs as they are, without Windows' Shaping*/ exact_textout(hdc, x, y - font_height * (lattr == LATTR_BOT) + text_adjust, - &line_box, wbuf, len, IpDx); + &line_box, wbuf, len, IpDx, !(attr & TATTR_COMBINING)); /* ExtTextOutW(hdc, x, y - font_height * (lattr == LATTR_BOT) + text_adjust, ETO_CLIPPED | ETO_OPAQUE, &line_box, wbuf, len, IpDx); @@ -3141,7 +3194,25 @@ void do_text(Context ctx, int x, int y, char *text, int len, } } -void do_cursor(Context ctx, int x, int y, char *text, int len, +/* + * Wrapper that handles combining characters. + */ +void do_text(Context ctx, int x, int y, wchar_t *text, int len, + unsigned long attr, int lattr) +{ + if (attr & TATTR_COMBINING) { + unsigned long a = 0; + attr &= ~TATTR_COMBINING; + while (len--) { + do_text_internal(ctx, x, y, text, 1, attr | a, lattr); + text++; + a = TATTR_COMBINING; + } + } else + do_text_internal(ctx, x, y, text, len, attr, lattr); +} + +void do_cursor(Context ctx, int x, int y, wchar_t *text, int len, unsigned long attr, int lattr) { @@ -3151,7 +3222,7 @@ void do_cursor(Context ctx, int x, int y, char *text, int len, int ctype = cfg.cursor_type; if ((attr & TATTR_ACTCURS) && (ctype == 0 || term->big_cursor)) { - if (((attr & CSET_MASK) | (unsigned char) *text) != UCSWIDE) { + if (*text != UCSWIDE) { do_text(ctx, x, y, text, len, attr, lattr); return; } @@ -3228,13 +3299,13 @@ int char_width(Context ctx, int uc) { if (!font_dualwidth) return 1; switch (uc & CSET_MASK) { - case ATTR_ASCII: + case CSET_ASCII: uc = ucsdata.unitab_line[uc & 0xFF]; break; - case ATTR_LINEDRW: + case CSET_LINEDRW: uc = ucsdata.unitab_xterm[uc & 0xFF]; break; - case ATTR_SCOACS: + case CSET_SCOACS: uc = ucsdata.unitab_scoacs[uc & 0xFF]; break; } @@ -3242,12 +3313,12 @@ int char_width(Context ctx, int uc) { if (ucsdata.dbcs_screenfont) return 1; /* Speedup, I know of no font where ascii is the wrong width */ - if ((uc&CHAR_MASK) >= ' ' && (uc&CHAR_MASK)<= '~') + if ((uc&~CSET_MASK) >= ' ' && (uc&~CSET_MASK)<= '~') return 1; - if ( (uc & CSET_MASK) == ATTR_ACP ) { + if ( (uc & CSET_MASK) == CSET_ACP ) { SelectObject(hdc, fonts[FONT_NORMAL]); - } else if ( (uc & CSET_MASK) == ATTR_OEMCP ) { + } else if ( (uc & CSET_MASK) == CSET_OEMCP ) { another_font(FONT_OEM); if (!fonts[FONT_OEM]) return 0; @@ -3255,8 +3326,8 @@ int char_width(Context ctx, int uc) { } else return 0; - if ( GetCharWidth32(hdc, uc&CHAR_MASK, uc&CHAR_MASK, &ibuf) != 1 && - GetCharWidth(hdc, uc&CHAR_MASK, uc&CHAR_MASK, &ibuf) != 1) + if ( GetCharWidth32(hdc, uc&~CSET_MASK, uc&~CSET_MASK, &ibuf) != 1 && + GetCharWidth(hdc, uc&~CSET_MASK, uc&~CSET_MASK, &ibuf) != 1) return 0; } else { /* Speedup, I know of no font where ascii is the wrong width */ @@ -3383,8 +3454,8 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, /* Nastyness with NUMLock - Shift-NUMLock is left alone though */ - if ((cfg.funky_type == 3 || - (cfg.funky_type <= 1 && term->app_keypad_keys && + if ((cfg.funky_type == FUNKY_VT400 || + (cfg.funky_type <= FUNKY_LINUX && term->app_keypad_keys && !cfg.no_applic_k)) && wParam == VK_NUMLOCK && !(keystate[VK_SHIFT] & 0x80)) { @@ -3450,8 +3521,8 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, /* Sanitize the number pad if not using a PC NumPad */ if (left_alt || (term->app_keypad_keys && !cfg.no_applic_k - && cfg.funky_type != 2) - || cfg.funky_type == 3 || cfg.nethack_keypad || compose_state) { + && cfg.funky_type != FUNKY_XTERM) + || cfg.funky_type == FUNKY_VT400 || cfg.nethack_keypad || compose_state) { if ((HIWORD(lParam) & KF_EXTENDED) == 0) { int nParam = 0; switch (wParam) { @@ -3580,8 +3651,8 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, if (!left_alt) { int xkey = 0; - if (cfg.funky_type == 3 || - (cfg.funky_type <= 1 && + if (cfg.funky_type == FUNKY_VT400 || + (cfg.funky_type <= FUNKY_LINUX && term->app_keypad_keys && !cfg.no_applic_k)) switch (wParam) { case VK_EXECUTE: xkey = 'P'; @@ -3633,7 +3704,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, xkey = 'n'; break; case VK_ADD: - if (cfg.funky_type == 2) { + if (cfg.funky_type == FUNKY_XTERM) { if (shift_state) xkey = 'l'; else @@ -3645,15 +3716,15 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, break; case VK_DIVIDE: - if (cfg.funky_type == 2) + if (cfg.funky_type == FUNKY_XTERM) xkey = 'o'; break; case VK_MULTIPLY: - if (cfg.funky_type == 2) + if (cfg.funky_type == FUNKY_XTERM) xkey = 'j'; break; case VK_SUBTRACT: - if (cfg.funky_type == 2) + if (cfg.funky_type == FUNKY_XTERM) xkey = 'm'; break; @@ -3825,7 +3896,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, break; } /* Reorder edit keys to physical order */ - if (cfg.funky_type == 3 && code <= 6) + if (cfg.funky_type == FUNKY_VT400 && code <= 6) code = "\0\2\1\4\5\3\6"[code]; if (term->vt52_mode && code > 0 && code <= 6) { @@ -3833,7 +3904,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, return p - output; } - if (cfg.funky_type == 5 && /* SCO function keys */ + if (cfg.funky_type == FUNKY_SCO && /* SCO function keys */ code >= 11 && code <= 34) { char codes[] = "MNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@[\\]^_`{"; int index = 0; @@ -3856,7 +3927,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 == 5 && /* SCO small keypad */ + if (cfg.funky_type == FUNKY_SCO && /* SCO small keypad */ code >= 1 && code <= 6) { char codes[] = "HL.FIG"; if (code == 3) { @@ -3866,7 +3937,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, } return p - output; } - if ((term->vt52_mode || cfg.funky_type == 4) && code >= 11 && code <= 24) { + if ((term->vt52_mode || cfg.funky_type == FUNKY_VT100P) && code >= 11 && code <= 24) { int offt = 0; if (code > 15) offt++; @@ -3879,11 +3950,11 @@ 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 == 1 && code >= 11 && code <= 15) { + if (cfg.funky_type == FUNKY_LINUX && code >= 11 && code <= 15) { p += sprintf((char *) p, "\x1B[[%c", code + 'A' - 11); return p - output; } - if (cfg.funky_type == 2 && code >= 11 && code <= 14) { + if (cfg.funky_type == FUNKY_XTERM && code >= 11 && code <= 14) { if (term->vt52_mode) p += sprintf((char *) p, "\x1B%c", code + 'P' - 11); else