X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/c264be083963de27ce917434c97d5b61822ff107..f80d4744684828c7b99f1dc25d4b21cf0b59c786:/window.c diff --git a/window.c b/window.c index fd977ed8..9f1dbe33 100644 --- a/window.c +++ b/window.c @@ -25,9 +25,10 @@ #define IDM_SHOWLOG 0x0010 #define IDM_NEWSESS 0x0020 #define IDM_DUPSESS 0x0030 -#define IDM_RECONF 0x0040 -#define IDM_CLRSB 0x0050 -#define IDM_RESET 0x0060 +#define IDM_RESTART 0x0040 +#define IDM_RECONF 0x0050 +#define IDM_CLRSB 0x0060 +#define IDM_RESET 0x0070 #define IDM_HELP 0x0140 #define IDM_ABOUT 0x0150 #define IDM_SAVEDSESS 0x0160 @@ -110,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; @@ -182,6 +184,110 @@ void ldisc_update(void *frontend, int echo, int edit) { } +static void start_backend(void) +{ + const char *error; + char msg[1024], *title; + char *realhost; + int i; + + /* + * Select protocol. This is farmed out into a table in a + * separate file to enable an ssh-free variant. + */ + back = NULL; + for (i = 0; backends[i].backend != NULL; i++) + if (backends[i].protocol == cfg.protocol) { + back = backends[i].backend; + break; + } + if (back == NULL) { + char *str = dupprintf("%s Internal Error", appname); + MessageBox(NULL, "Unsupported protocol number found", + str, MB_OK | MB_ICONEXCLAMATION); + sfree(str); + cleanup_exit(1); + } + + error = back->init(NULL, &backhandle, &cfg, + cfg.host, cfg.port, &realhost, cfg.tcp_nodelay, + cfg.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.host, 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 { + sprintf(msg, "%s - %s", realhost, appname); + title = msg; + } + sfree(realhost); + set_title(NULL, title); + set_icon(NULL, title); + + /* + * Connect the terminal to the backend for resize purposes. + */ + term_provide_resize_fn(term, back->size, backhandle); + + /* + * Set up a line discipline. + */ + ldisc = ldisc_create(&cfg, term, back, backhandle, NULL); + + /* + * Destroy the Restart Session menu item. (This will return + * failure if it's already absent, as it will be the very first + * time we call this function. We ignore that, because as long + * as the menu item ends up not being there, we don't care + * whether it was us who removed it or not!) + */ + for (i = 0; i < lenof(popup_menus); i++) { + DeleteMenu(popup_menus[i].menu, IDM_RESTART, MF_BYCOMMAND); + } + + session_closed = FALSE; +} + +static void close_session(void) +{ + char morestuff[100]; + int i; + + session_closed = TRUE; + sprintf(morestuff, "%.70s (inactive)", appname); + set_icon(NULL, morestuff); + set_title(NULL, morestuff); + + if (ldisc) { + ldisc_free(ldisc); + ldisc = NULL; + } + if (back) { + back->free(backhandle); + backhandle = NULL; + back = NULL; + update_specials_menu(NULL); + } + + /* + * Show the Restart Session menu item. Do a precautionary + * delete first to ensure we never end up with more than one. + */ + for (i = 0; i < lenof(popup_menus); i++) { + DeleteMenu(popup_menus[i].menu, IDM_RESTART, MF_BYCOMMAND); + InsertMenu(popup_menus[i].menu, IDM_DUPSESS, MF_BYCOMMAND | MF_ENABLED, + IDM_RESTART, "&Restart Session"); + } +} + int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { WNDCLASS wndclass; @@ -420,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) { @@ -452,27 +558,6 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) } } - /* - * Select protocol. This is farmed out into a table in a - * separate file to enable an ssh-free variant. - */ - { - int i; - back = NULL; - for (i = 0; backends[i].backend != NULL; i++) - if (backends[i].protocol == cfg.protocol) { - back = backends[i].backend; - break; - } - if (back == NULL) { - char *str = dupprintf("%s Internal Error", appname); - MessageBox(NULL, "Unsupported protocol number found", - str, MB_OK | MB_ICONEXCLAMATION); - sfree(str); - cleanup_exit(1); - } - } - /* Check for invalid Port number (i.e. zero) */ if (cfg.port == 0) { char *str = dupprintf("%s Internal Error", appname); @@ -603,49 +688,6 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) } /* - * Start up the telnet connection. - */ - { - const char *error; - char msg[1024], *title; - char *realhost; - - error = back->init(NULL, &backhandle, &cfg, - cfg.host, cfg.port, &realhost, cfg.tcp_nodelay); - back->provide_logctx(backhandle, logctx); - if (error) { - char *str = dupprintf("%s Error", appname); - sprintf(msg, "Unable to open connection to\n" - "%.800s\n" "%s", cfg.host, error); - MessageBox(NULL, msg, str, MB_ICONERROR | MB_OK); - sfree(str); - return 0; - } - window_name = icon_name = NULL; - if (*cfg.wintitle) { - title = cfg.wintitle; - } else { - sprintf(msg, "%s - %s", realhost, appname); - title = msg; - } - sfree(realhost); - set_title(NULL, title); - set_icon(NULL, title); - } - - /* - * Connect the terminal to the backend for resize purposes. - */ - term_provide_resize_fn(term, back->size, backhandle); - - /* - * Set up a line discipline. - */ - ldisc = ldisc_create(&cfg, term, back, backhandle, NULL); - - session_closed = FALSE; - - /* * Prepare the mouse handler. */ lastact = MA_NOTHING; @@ -699,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. @@ -864,34 +906,73 @@ char *do_select(SOCKET skt, int startup) */ void update_specials_menu(void *frontend) { - HMENU m = GetSystemMenu(hwnd, FALSE); + HMENU p; int menu_already_exists = (specials != NULL); int i, j; - specials = back->get_specials(backhandle); + if (back) + specials = back->get_specials(backhandle); + else + specials = NULL; + if (specials) { - HMENU 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; + } } - for (j = 0; j < lenof(popup_menus); j++) { - if (menu_already_exists) - DeleteMenu(popup_menus[j].menu, - popup_menus[j].specials_submenu_pos, - MF_BYPOSITION); - else - InsertMenu(popup_menus[j].menu, - popup_menus[j].specials_submenu_pos, - MF_BYPOSITION | MF_SEPARATOR, 0, 0); + /* 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); + DeleteMenu(popup_menus[j].menu, + popup_menus[j].specials_submenu_pos, + MF_BYPOSITION); + } + if (specials) { + InsertMenu(popup_menus[j].menu, + popup_menus[j].specials_submenu_pos, + MF_BYPOSITION | MF_SEPARATOR, 0, 0); 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"); } } } @@ -924,10 +1005,7 @@ void connection_fatal(void *frontend, char *fmt, ...) if (cfg.close_on_exit == FORCE_ON) PostQuitMessage(1); else { - session_closed = TRUE; - sprintf(morestuff, "%.70s (inactive)", appname); - set_icon(NULL, morestuff); - set_title(NULL, morestuff); + close_session(); } } @@ -972,11 +1050,8 @@ static void enact_pending_netevent(void) if (cfg.close_on_exit == FORCE_ON || cfg.close_on_exit == AUTO) PostQuitMessage(0); else { - char morestuff[100]; + close_session(); session_closed = TRUE; - sprintf(morestuff, "%.70s (inactive)", appname); - set_icon(NULL, morestuff); - set_title(NULL, morestuff); MessageBox(hwnd, "Connection closed by remote host", appname, MB_OK | MB_ICONINFORMATION); } @@ -1081,6 +1156,37 @@ static void init_palette(void) } /* + * This is a wrapper to ExtTextOut() to force Windows to display + * the precise glyphs we give it. Otherwise it would do its own + * bidi and Arabic shaping, and we would end up uncertain which + * characters it had put where. + */ +static void exact_textout(HDC hdc, int x, int y, CONST RECT *lprc, + unsigned short *lpString, UINT cbCount, + CONST INT *lpDx, int opaque) +{ + + GCP_RESULTSW gcpr; + char *buffer = snewn(cbCount*2+2, char); + char *classbuffer = snewn(cbCount, char); + memset(&gcpr, 0, sizeof(gcpr)); + memset(buffer, 0, cbCount*2+2); + memset(classbuffer, GCPCLASS_NEUTRAL, cbCount); + + gcpr.lStructSize = sizeof(gcpr); + gcpr.lpGlyphs = (void *)buffer; + gcpr.lpClass = classbuffer; + gcpr.nGlyphs = cbCount; + + GetCharacterPlacementW(hdc, lpString, cbCount, 0, &gcpr, + FLI_MASK | GCP_CLASSIN | GCP_DIACRITIC); + + ExtTextOut(hdc, x, y, + ETO_GLYPH_INDEX | ETO_CLIPPED | (opaque ? ETO_OPAQUE : 0), + lprc, buffer, cbCount, lpDx); +} + +/* * Initialise all the fonts we will need initially. There may be as many as * three or as few as one. The other (poentially) twentyone fonts are done * if/when they are needed. @@ -1690,6 +1796,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 UINT last_mousemove = 0; switch (message) { case WM_TIMER: @@ -1706,7 +1813,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, time_t now; time(&now); if (now - last_movement > cfg.ping_interval) { - back->special(backhandle, TS_PING); + if (back) + back->special(backhandle, TS_PING); last_movement = now; } } @@ -1809,6 +1917,13 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, sfree(cl); } break; + case IDM_RESTART: + if (!back) { + logevent(NULL, "----- Session restarted -----"); + start_backend(); + } + + break; case IDM_RECONF: { Config prev_cfg; @@ -1841,7 +1956,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, * Flush the line discipline's edit buffer in the * case where local editing has just been disabled. */ - ldisc_send(ldisc, NULL, 0, 0); + if (ldisc) + ldisc_send(ldisc, NULL, 0, 0); if (pal) DeleteObject(pal); logpal = NULL; @@ -1853,7 +1969,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, term_reconfig(term, &cfg); /* Pass new config data to the back end */ - back->reconfig(backhandle, &cfg); + if (back) + back->reconfig(backhandle, &cfg); /* Screen size changed ? */ if (cfg.height != prev_cfg.height || @@ -1961,7 +2078,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, break; case IDM_RESET: term_pwron(term); - ldisc_send(ldisc, NULL, 0, 0); + if (ldisc) + ldisc_send(ldisc, NULL, 0, 0); break; case IDM_ABOUT: showabout(hwnd); @@ -1999,19 +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 (i >= n_specials) + break; + if (back) back->special(backhandle, specials[i].code); - net_pending_errors(); - } + net_pending_errors(); } } break; @@ -2097,7 +2212,6 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, mi.rcMonitor.top == pt.y) { mouse_on_hotspot = 1; } - CloseHandle(mon); } } #else @@ -2129,7 +2243,21 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, } return 0; case WM_MOUSEMOVE: - show_mouseptr(1); + { + /* + * Windows seems to like to occasionally send MOUSEMOVE + * events even if the mouse hasn't moved. Don't unhide + * the mouse pointer in this case. + */ + static WPARAM wp = 0; + static LPARAM lp = 0; + if (wParam != wp || lParam != lp || + last_mousemove != WM_MOUSEMOVE) { + show_mouseptr(1); + wp = wParam; lp = lParam; + last_mousemove = WM_MOUSEMOVE; + } + } /* * Add the mouse position and message time to the random * number noise. @@ -2152,7 +2280,16 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, } return 0; case WM_NCMOUSEMOVE: - show_mouseptr(1); + { + static WPARAM wp = 0; + static LPARAM lp = 0; + if (wParam != wp || lParam != lp || + last_mousemove != WM_NCMOUSEMOVE) { + show_mouseptr(1); + wp = wParam; lp = lParam; + last_mousemove = WM_NCMOUSEMOVE; + } + } noise_ultralight(lParam); break; case WM_IGNORE_CLIP: @@ -2558,7 +2695,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, * we're sent. */ term_seen_key_event(term); - ldisc_send(ldisc, buf, len, 1); + if (ldisc) + ldisc_send(ldisc, buf, len, 1); show_mouseptr(0); } } @@ -2606,7 +2744,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, */ term_seen_key_event(term); for (i = 0; i < n; i += 2) { - luni_send(ldisc, (unsigned short *)(buff+i), 1, 1); + if (ldisc) + luni_send(ldisc, (unsigned short *)(buff+i), 1, 1); } free(buff); } @@ -2621,11 +2760,13 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, buf[1] = wParam; buf[0] = wParam >> 8; term_seen_key_event(term); - lpage_send(ldisc, kbd_codepage, buf, 2, 1); + if (ldisc) + lpage_send(ldisc, kbd_codepage, buf, 2, 1); } else { char c = (unsigned char) wParam; term_seen_key_event(term); - lpage_send(ldisc, kbd_codepage, &c, 1, 1); + if (ldisc) + lpage_send(ldisc, kbd_codepage, &c, 1, 1); } return (0); case WM_CHAR: @@ -2639,7 +2780,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, { char c = (unsigned char)wParam; term_seen_key_event(term); - lpage_send(ldisc, CP_ACP, &c, 1, 1); + if (ldisc) + lpage_send(ldisc, CP_ACP, &c, 1, 1); } return 0; case WM_SETCURSOR: @@ -2648,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; @@ -2772,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; @@ -2832,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); @@ -2904,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; @@ -2915,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; @@ -2930,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); @@ -2974,24 +3144,30 @@ 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]; - ExtTextOutW(hdc, x, + /* 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, !(attr & TATTR_COMBINING)); +/* ExtTextOutW(hdc, x, y - font_height * (lattr == LATTR_BOT) + text_adjust, ETO_CLIPPED | ETO_OPAQUE, &line_box, wbuf, len, IpDx); + */ /* And the shadow bold hack. */ if (bold_mode == BOLD_SHADOW && (attr & ATTR_BOLD)) { @@ -3018,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) { @@ -3028,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; } @@ -3105,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; } @@ -3119,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; @@ -3132,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 */ @@ -3260,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)) { @@ -3327,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) { @@ -3457,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'; @@ -3510,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 @@ -3522,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; @@ -3702,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) { @@ -3710,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; @@ -3733,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) { @@ -3743,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++; @@ -3756,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 @@ -3931,7 +4125,8 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, } keybuf = nc; term_seen_key_event(term); - luni_send(ldisc, &keybuf, 1, 1); + if (ldisc) + luni_send(ldisc, &keybuf, 1, 1); continue; } @@ -3942,7 +4137,8 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, if (in_utf(term) || ucsdata.dbcs_screenfont) { keybuf = alt_sum; term_seen_key_event(term); - luni_send(ldisc, &keybuf, 1, 1); + if (ldisc) + luni_send(ldisc, &keybuf, 1, 1); } else { ch = (char) alt_sum; /* @@ -3955,12 +4151,14 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, * everything we're sent. */ term_seen_key_event(term); - ldisc_send(ldisc, &ch, 1, 1); + if (ldisc) + ldisc_send(ldisc, &ch, 1, 1); } alt_sum = 0; } else { term_seen_key_event(term); - lpage_send(ldisc, kbd_codepage, &ch, 1, 1); + if (ldisc) + lpage_send(ldisc, kbd_codepage, &ch, 1, 1); } } else { if(capsOn && ch < 0x80) { @@ -3968,14 +4166,16 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, cbuf[0] = 27; cbuf[1] = xlat_uskbd2cyrllic(ch); term_seen_key_event(term); - luni_send(ldisc, cbuf+!left_alt, 1+!!left_alt, 1); + if (ldisc) + luni_send(ldisc, cbuf+!left_alt, 1+!!left_alt, 1); } else { char cbuf[2]; cbuf[0] = '\033'; cbuf[1] = ch; term_seen_key_event(term); - lpage_send(ldisc, kbd_codepage, - cbuf+!left_alt, 1+!!left_alt, 1); + if (ldisc) + lpage_send(ldisc, kbd_codepage, + cbuf+!left_alt, 1+!!left_alt, 1); } } show_mouseptr(0);