X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/putty/blobdiff_plain/6da411554bfe4c2a8ddfbb0616b0030ea5e813f5..c8f5c5c8f0bd6f8221642c51deb285913df9944b:/windows/window.c diff --git a/windows/window.c b/windows/window.c index ccebea77..fedcc359 100644 --- a/windows/window.c +++ b/windows/window.c @@ -92,17 +92,12 @@ static int offset_width, offset_height; static int was_zoomed = 0; static int prev_rows, prev_cols; -static int pending_netevent = 0; -static WPARAM pend_netevent_wParam = 0; -static LPARAM pend_netevent_lParam = 0; -static void enact_pending_netevent(void); +static void enact_netevent(WPARAM, LPARAM); static void flash_window(int mode); static void sys_cursor_update(void); static int is_shift_pressed(void); static int get_fullscreen_rect(RECT * ss); -static time_t last_movement = 0; - static int caret_x = -1, caret_y = -1; static int kbd_codepage; @@ -113,10 +108,14 @@ static void *backhandle; static struct unicode_data ucsdata; static int session_closed; +static int reconfiguring; static const struct telnet_special *specials; static int n_specials; +#define TIMING_TIMER_ID 1234 +static long timing_next_time; + static struct { HMENU menu; int specials_submenu_pos; @@ -160,13 +159,13 @@ static enum { } und_mode; static int descent; -#define NCOLOURS 24 -static COLORREF colours[NCOLOURS]; +#define NCFGCOLOURS 22 +#define NEXTCOLOURS 240 +#define NALLCOLOURS (NCFGCOLOURS + NEXTCOLOURS) +static COLORREF colours[NALLCOLOURS]; static HPALETTE pal; static LPLOGPALETTE logpal; -static RGBTRIPLE defpal[NCOLOURS]; - -static HWND hwnd; +static RGBTRIPLE defpal[NALLCOLOURS]; static HBITMAP caretbm; @@ -177,6 +176,8 @@ static Mouse_Button lastbtn; static int send_raw_mouse = 0; static int wheel_accumulator = 0; +static int busy_status = BUSY_NOT; + static char *window_name, *icon_name; static int compose_state = 0; @@ -299,6 +300,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) int guess_width, guess_height; hinst = inst; + hwnd = NULL; flags = FLAG_VERBOSE | FLAG_INTERACTIVE; sk_init(); @@ -340,13 +342,13 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) if (p && p >= r) r = p+1; q = strrchr(b, ':'); if (q && q >= r) r = q+1; - strcpy(r, "putty.hlp"); + strcpy(r, PUTTY_HELP_FILE); if ( (fp = fopen(b, "r")) != NULL) { help_path = dupstr(b); fclose(fp); } else help_path = NULL; - strcpy(r, "putty.cnt"); + strcpy(r, PUTTY_HELP_CONTENTS); if ( (fp = fopen(b, "r")) != NULL) { help_has_contents = TRUE; fclose(fp); @@ -436,28 +438,50 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) i++; /* skip next argument */ } else if (ret == 1) { continue; /* nothing further needs doing */ - } else if (!strcmp(p, "-cleanup")) { + } else if (!strcmp(p, "-cleanup") || + !strcmp(p, "-cleanup-during-uninstall")) { /* * `putty -cleanup'. Remove all registry * entries associated with PuTTY, and also find * and delete the random seed file. */ char *s1, *s2; - s1 = dupprintf("This procedure will remove ALL Registry\n" - "entries associated with %s, and will\n" - "also remove the random seed file.\n" - "\n" - "THIS PROCESS WILL DESTROY YOUR SAVED\n" - "SESSIONS. Are you really sure you want\n" - "to continue?", appname); - s2 = dupprintf("%s Warning", appname); - if (MessageBox(NULL, s1, s2, - MB_YESNO | MB_ICONWARNING) == IDYES) { + /* Are we being invoked from an uninstaller? */ + if (!strcmp(p, "-cleanup-during-uninstall")) { + s1 = dupprintf("Remove saved sessions and random seed file?\n" + "\n" + "If you hit Yes, ALL Registry entries associated\n" + "with %s will be removed, as well as the\n" + "random seed file. THIS PROCESS WILL\n" + "DESTROY YOUR SAVED SESSIONS.\n" + "(This only affects the currently logged-in user.)\n" + "\n" + "If you hit No, uninstallation will proceed, but\n" + "saved sessions etc will be left on the machine.", + appname); + s2 = dupprintf("%s Uninstallation", appname); + } else { + s1 = dupprintf("This procedure will remove ALL Registry entries\n" + "associated with %s, and will also remove\n" + "the random seed file. (This only affects the\n" + "currently logged-in user.)\n" + "\n" + "THIS PROCESS WILL DESTROY YOUR SAVED SESSIONS.\n" + "Are you really sure you want to continue?", + appname); + s2 = dupprintf("%s Warning", appname); + } + if (message_box(s1, s2, + MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2, + HELPCTXID(option_cleanup)) == IDYES) { cleanup_all(); } sfree(s1); sfree(s2); exit(0); + } else if (!strcmp(p, "-pgpfp")) { + pgp_fingerprints(); + exit(1); } else if (*p != '-') { char *q = p; if (got_host) { @@ -542,9 +566,20 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) } /* - * Trim a colon suffix off the hostname if it's there. + * Trim a colon suffix off the hostname if it's there. In + * order to protect IPv6 address literals against this + * treatment, we do not do this if there's _more_ than one + * colon. */ - cfg.host[strcspn(cfg.host, ":")] = '\0'; + { + char *c = strchr(cfg.host, ':'); + + if (c) { + char *d = strchr(c+1, ':'); + if (!d) + *c = '\0'; + } + } /* * Remove any remaining whitespace from the hostname. @@ -586,14 +621,8 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) RegisterClass(&wndclass); } - hwnd = NULL; - memset(&ucsdata, 0, sizeof(ucsdata)); - term = term_init(&cfg, &ucsdata, NULL); - logctx = log_init(NULL, &cfg); - term_provide_logctx(term, logctx); - cfgtopalette(); /* @@ -607,9 +636,8 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) font_height = 20; extra_width = 25; extra_height = 28; - term_size(term, cfg.height, cfg.width, cfg.savelines); - guess_width = extra_width + font_width * term->cols; - guess_height = extra_height + font_height * term->rows; + guess_width = extra_width + font_width * cfg.width; + guess_height = extra_height + font_height * cfg.height; { RECT r; get_fullscreen_rect(&r); @@ -637,6 +665,17 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) } /* + * Initialise the terminal. (We have to do this _after_ + * creating the window, since the terminal is the first thing + * which will call schedule_timer(), which will in turn call + * timer_change_notify() which will expect hwnd to exist.) + */ + term = term_init(&cfg, &ucsdata, NULL); + logctx = log_init(NULL, &cfg); + term_provide_logctx(term, logctx); + term_size(term, cfg.height, cfg.width, cfg.savelines); + + /* * Initialise the fonts, simultaneously correcting the guesses * for font_{width,height}. */ @@ -772,34 +811,15 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) logpal = NULL; init_palette(); - term->has_focus = (GetForegroundWindow() == hwnd); + term_set_focus(term, GetForegroundWindow() == hwnd); UpdateWindow(hwnd); if (GetMessage(&msg, NULL, 0, 0) == 1) { - int timer_id = 0, long_timer = 0; - while (msg.message != WM_QUIT) { - /* Sometimes DispatchMessage calls routines that use their own - * GetMessage loop, setup this timer so we get some control back. - * - * Also call term_update() from the timer so that if the host - * is sending data flat out we still do redraws. - */ - if (timer_id && long_timer) { - KillTimer(hwnd, timer_id); - long_timer = timer_id = 0; - } - if (!timer_id) - timer_id = SetTimer(hwnd, 1, 20, NULL); if (!(IsWindow(logbox) && IsDialogMessage(logbox, &msg))) DispatchMessage(&msg); - - /* Make sure we blink everything that needs it. */ - term_blink(term, 0); - /* Send the paste buffer if there's anything to send */ term_paste(term); - /* If there's nothing new in the queue then we can do everything * we've delayed, reading the socket, writing, and repainting * the window. @@ -807,42 +827,10 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) continue; - if (pending_netevent) { - enact_pending_netevent(); - - if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) - continue; - } - - /* Okay there is now nothing to do so we make sure the screen is - * completely up to date then tell windows to call us in a little - * while. - */ - if (timer_id) { - KillTimer(hwnd, timer_id); - timer_id = 0; - } - HideCaret(hwnd); - if (GetCapture() != hwnd || - (send_raw_mouse && - !(cfg.mouse_override && is_shift_pressed()))) - term_out(term); - term_update(term); - ShowCaret(hwnd); - - flash_window(1); /* maintain */ - /* The messages seem unreliable; especially if we're being tricky */ - term->has_focus = (GetForegroundWindow() == hwnd); + term_set_focus(term, GetForegroundWindow() == hwnd); - if (term->in_vbell) - /* Hmm, term_update didn't want to do an update too soon ... */ - timer_id = SetTimer(hwnd, 1, 50, NULL); - else if (!term->has_focus) - timer_id = SetTimer(hwnd, 1, 500, NULL); - else - timer_id = SetTimer(hwnd, 1, 100, NULL); - long_timer = 1; + net_pending_errors(); /* There's no point rescanning everything in the message queue * so we do an apparently unnecessary wait here @@ -983,6 +971,50 @@ void update_specials_menu(void *frontend) } } +static void update_mouse_pointer(void) +{ + LPTSTR curstype; + int force_visible = FALSE; + static int forced_visible = FALSE; + switch (busy_status) { + case BUSY_NOT: + if (send_raw_mouse) + curstype = IDC_ARROW; + else + curstype = IDC_IBEAM; + break; + case BUSY_WAITING: + curstype = IDC_APPSTARTING; /* this may be an abuse */ + force_visible = TRUE; + break; + case BUSY_CPU: + curstype = IDC_WAIT; + force_visible = TRUE; + break; + default: + assert(0); + } + { + HCURSOR cursor = LoadCursor(NULL, curstype); + SetClassLong(hwnd, GCL_HCURSOR, (LONG)cursor); + SetCursor(cursor); /* force redraw of cursor at current posn */ + } + if (force_visible != forced_visible) { + /* We want some cursor shapes to be visible always. + * Along with show_mouseptr(), this manages the ShowCursor() + * counter such that if we switch back to a non-force_visible + * cursor, the previous visibility state is restored. */ + ShowCursor(force_visible); + forced_visible = force_visible; + } +} + +void set_busy_status(void *frontend, int status) +{ + busy_status = status; + update_mouse_pointer(); +} + /* * set or clear the "raw mouse message" mode */ @@ -990,7 +1022,7 @@ void set_raw_mouse_mode(void *frontend, int activate) { activate = activate && !cfg.no_mouse_rep; send_raw_mouse = activate; - SetCursor(LoadCursor(NULL, activate ? IDC_ARROW : IDC_IBEAM)); + update_mouse_pointer(); } /* @@ -1035,7 +1067,7 @@ void cmdline_error(char *fmt, ...) /* * Actually do the job requested by a WM_NETEVENT */ -static void enact_pending_netevent(void) +static void enact_netevent(WPARAM wParam, LPARAM lParam) { static int reentering = 0; extern int select_result(WPARAM, LPARAM); @@ -1044,10 +1076,8 @@ static void enact_pending_netevent(void) if (reentering) return; /* don't unpend the pending */ - pending_netevent = FALSE; - reentering = 1; - ret = select_result(pend_netevent_wParam, pend_netevent_lParam); + ret = select_result(wParam, lParam); reentering = 0; if (ret == 0 && !session_closed) { @@ -1072,16 +1102,29 @@ static void cfgtopalette(void) { int i; static const int ww[] = { - 6, 7, 8, 9, 10, 11, 12, 13, - 14, 15, 16, 17, 18, 19, 20, 21, - 0, 1, 2, 3, 4, 4, 5, 5 + 256, 257, 258, 259, 260, 261, + 0, 8, 1, 9, 2, 10, 3, 11, + 4, 12, 5, 13, 6, 14, 7, 15 }; - for (i = 0; i < 24; i++) { + for (i = 0; i < 22; i++) { int w = ww[i]; - defpal[i].rgbtRed = cfg.colours[w][0]; - defpal[i].rgbtGreen = cfg.colours[w][1]; - defpal[i].rgbtBlue = cfg.colours[w][2]; + defpal[w].rgbtRed = cfg.colours[i][0]; + defpal[w].rgbtGreen = cfg.colours[i][1]; + defpal[w].rgbtBlue = cfg.colours[i][2]; + } + for (i = 0; i < NEXTCOLOURS; i++) { + if (i < 216) { + int r = i / 36, g = (i / 6) % 6, b = i % 6; + defpal[i+16].rgbtRed = r * 0x33; + defpal[i+16].rgbtGreen = g * 0x33; + defpal[i+16].rgbtBlue = b * 0x33; + } else { + int shade = i - 216; + shade = (shade + 1) * 0xFF / (NEXTCOLOURS - 216 + 1); + defpal[i+16].rgbtRed = defpal[i+16].rgbtGreen = + defpal[i+16].rgbtBlue = shade; + } } /* Override with system colours if appropriate */ @@ -1100,10 +1143,10 @@ static void systopalette(void) int i; static const struct { int nIndex; int norm; int bold; } or[] = { - { COLOR_WINDOWTEXT, 16, 17 }, /* Default Foreground */ - { COLOR_WINDOW, 18, 19 }, /* Default Background */ - { COLOR_HIGHLIGHTTEXT, 20, 21 }, /* Cursor Text */ - { COLOR_HIGHLIGHT, 22, 23 }, /* Cursor Colour */ + { COLOR_WINDOWTEXT, 256, 257 }, /* Default Foreground */ + { COLOR_WINDOW, 258, 259 }, /* Default Background */ + { COLOR_HIGHLIGHTTEXT, 260, 260 }, /* Cursor Text */ + { COLOR_HIGHLIGHT, 261, 261 }, /* Cursor Colour */ }; for (i = 0; i < (sizeof(or)/sizeof(or[0])); i++) { @@ -1132,10 +1175,10 @@ static void init_palette(void) */ logpal = smalloc(sizeof(*logpal) - sizeof(logpal->palPalEntry) - + NCOLOURS * sizeof(PALETTEENTRY)); + + NALLCOLOURS * sizeof(PALETTEENTRY)); logpal->palVersion = 0x300; - logpal->palNumEntries = NCOLOURS; - for (i = 0; i < NCOLOURS; i++) { + logpal->palNumEntries = NALLCOLOURS; + for (i = 0; i < NALLCOLOURS; i++) { logpal->palPalEntry[i].peRed = defpal[i].rgbtRed; logpal->palPalEntry[i].peGreen = defpal[i].rgbtGreen; logpal->palPalEntry[i].peBlue = defpal[i].rgbtBlue; @@ -1151,12 +1194,12 @@ static void init_palette(void) ReleaseDC(hwnd, hdc); } if (pal) - for (i = 0; i < NCOLOURS; i++) + for (i = 0; i < NALLCOLOURS; i++) colours[i] = PALETTERGB(defpal[i].rgbtRed, defpal[i].rgbtGreen, defpal[i].rgbtBlue); else - for (i = 0; i < NCOLOURS; i++) + for (i = 0; i < NALLCOLOURS; i++) colours[i] = RGB(defpal[i].rgbtRed, defpal[i].rgbtGreen, defpal[i].rgbtBlue); } @@ -1253,24 +1296,11 @@ static void init_fonts(int pick_width, int pick_height) f(FONT_NORMAL, cfg.font.charset, fw_dontcare, FALSE); - lfont.lfHeight = font_height; - lfont.lfWidth = font_width; - lfont.lfEscapement = 0; - lfont.lfOrientation = 0; - lfont.lfWeight = fw_dontcare; - lfont.lfItalic = FALSE; - lfont.lfUnderline = FALSE; - lfont.lfStrikeOut = FALSE; - lfont.lfCharSet = cfg.font.charset; - lfont.lfOutPrecision = OUT_DEFAULT_PRECIS; - lfont.lfClipPrecision = CLIP_DEFAULT_PRECIS; - lfont.lfQuality = DEFAULT_QUALITY; - lfont.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE; - strncpy(lfont.lfFaceName, cfg.font.name, LF_FACESIZE); - SelectObject(hdc, fonts[FONT_NORMAL]); GetTextMetrics(hdc, &tm); + GetObject(fonts[FONT_NORMAL], sizeof(LOGFONT), &lfont); + if (pick_width == 0 || pick_height == 0) { font_height = tm.tmHeight; font_width = tm.tmAveCharWidth; @@ -1759,6 +1789,8 @@ static Mouse_Button translate_button(Mouse_Button button) 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; @@ -1795,6 +1827,17 @@ static int is_shift_pressed(void) static int resizing; +void notify_remote_exit(void *fe) { /* stub not needed in this frontend */ } + +void timer_change_notify(long next) +{ + long ticks = next - GETTICKCOUNT(); + if (ticks <= 0) ticks = 1; /* just in case */ + KillTimer(hwnd, TIMING_TIMER_ID); + SetTimer(hwnd, TIMING_TIMER_ID, ticks, NULL); + timing_next_time = next; +} + static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { @@ -1806,25 +1849,15 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, switch (message) { case WM_TIMER: - if (pending_netevent) - enact_pending_netevent(); - if (GetCapture() != hwnd || - (send_raw_mouse && !(cfg.mouse_override && is_shift_pressed()))) - term_out(term); - noise_regular(); - HideCaret(hwnd); - term_update(term); - ShowCaret(hwnd); - if (cfg.ping_interval > 0) { - time_t now; - time(&now); - if (now - last_movement > cfg.ping_interval) { - if (back) - back->special(backhandle, TS_PING); - last_movement = now; + if ((UINT_PTR)wParam == TIMING_TIMER_ID) { + long next; + + KillTimer(hwnd, TIMING_TIMER_ID); + if (run_timers(timing_next_time, &next)) { + timer_change_notify(next); + } else { } } - net_pending_errors(); return 0; case WM_CREATE: break; @@ -1836,7 +1869,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, if (!cfg.warn_on_close || session_closed || MessageBox(hwnd, "Are you sure you want to close this session?", - str, MB_ICONWARNING | MB_OKCANCEL) == IDOK) + str, MB_ICONWARNING | MB_OKCANCEL | MB_DEFBUTTON1) + == IDOK) DestroyWindow(hwnd); sfree(str); } @@ -1858,6 +1892,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, char b[2048]; char c[30], *cl; int freecl = FALSE; + BOOL inherit_handles; STARTUPINFO si; PROCESS_INFORMATION pi; HANDLE filemap = NULL; @@ -1886,6 +1921,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, UnmapViewOfFile(p); } } + inherit_handles = TRUE; sprintf(c, "putty &%p", filemap); cl = c; } else if (wParam == IDM_SAVEDSESS) { @@ -1895,11 +1931,14 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, char *session = sesslist.sessions[sessno]; /* XXX spaces? quotes? "-load"? */ cl = dupprintf("putty @%s", session); + inherit_handles = FALSE; freecl = TRUE; } else break; - } else + } else /* IDM_NEWSESS */ { cl = NULL; + inherit_handles = FALSE; + } GetModuleFileName(NULL, b, sizeof(b) - 1); si.cb = sizeof(si); @@ -1909,7 +1948,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, si.dwFlags = 0; si.cbReserved2 = 0; si.lpReserved2 = NULL; - CreateProcess(b, cl, NULL, NULL, TRUE, + CreateProcess(b, cl, NULL, NULL, inherit_handles, NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi); if (filemap) @@ -1930,10 +1969,15 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, Config prev_cfg; int init_lvl = 1; + if (reconfiguring) + break; + else + reconfiguring = TRUE; + GetWindowText(hwnd, cfg.wintitle, sizeof(cfg.wintitle)); prev_cfg = cfg; - if (!do_reconfig(hwnd)) + if (!do_reconfig(hwnd, back ? back->cfg_info(backhandle) : 0)) break; { @@ -2066,6 +2110,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, InvalidateRect(hwnd, NULL, TRUE); reset_window(init_lvl); net_pending_errors(); + reconfiguring = FALSE; } break; case IDM_COPYALL: @@ -2304,18 +2349,52 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, case WM_PAINT: { PAINTSTRUCT p; + HideCaret(hwnd); hdc = BeginPaint(hwnd, &p); if (pal) { SelectPalette(hdc, pal, TRUE); RealizePalette(hdc); } + + /* + * We have to be careful about term_paint(). It will + * set a bunch of character cells to INVALID and then + * call do_paint(), which will redraw those cells and + * _then mark them as done_. This may not be accurate: + * when painting in WM_PAINT context we are restricted + * to the rectangle which has just been exposed - so if + * that only covers _part_ of a character cell and the + * rest of it was already visible, that remainder will + * not be redrawn at all. Accordingly, we must not + * paint any character cell in a WM_PAINT context which + * already has a pending update due to terminal output. + * The simplest solution to this - and many, many + * thanks to Hung-Te Lin for working all this out - is + * not to do any actual painting at _all_ if there's a + * pending terminal update: just mark the relevant + * character cells as INVALID and wait for the + * scheduled full update to sort it out. + * + * I have a suspicion this isn't the _right_ solution. + * An alternative approach would be to have terminal.c + * separately track what _should_ be on the terminal + * screen and what _is_ on the terminal screen, and + * have two completely different types of redraw (one + * for full updates, which syncs the former with the + * terminal itself, and one for WM_PAINT which syncs + * the latter with the former); yet another possibility + * would be to have the Windows front end do what the + * GTK one already does, and maintain a bitmap of the + * current terminal appearance so that WM_PAINT becomes + * completely trivial. However, this should do for now. + */ term_paint(term, hdc, (p.rcPaint.left-offset_width)/font_width, (p.rcPaint.top-offset_height)/font_height, (p.rcPaint.right-offset_width-1)/font_width, (p.rcPaint.bottom-offset_height-1)/font_height, - is_alt_pressed()); + !term->window_update_pending); if (p.fErase || p.rcPaint.left < offset_width || @@ -2326,10 +2405,10 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, HBRUSH fillcolour, oldbrush; HPEN edge, oldpen; fillcolour = CreateSolidBrush ( - colours[(ATTR_DEFBG>>ATTR_BGSHIFT)*2]); + colours[ATTR_DEFBG>>ATTR_BGSHIFT]); oldbrush = SelectObject(hdc, fillcolour); edge = CreatePen(PS_SOLID, 0, - colours[(ATTR_DEFBG>>ATTR_BGSHIFT)*2]); + colours[ATTR_DEFBG>>ATTR_BGSHIFT]); oldpen = SelectObject(hdc, edge); /* @@ -2351,7 +2430,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, Rectangle(hdc, p.rcPaint.left, p.rcPaint.top, p.rcPaint.right, p.rcPaint.bottom); - // SelectClipRgn(hdc, NULL); + /* SelectClipRgn(hdc, NULL); */ SelectObject(hdc, oldbrush); DeleteObject(fillcolour); @@ -2365,36 +2444,22 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, } return 0; case WM_NETEVENT: - /* Notice we can get multiple netevents, FD_READ, FD_WRITE etc - * but the only one that's likely to try to overload us is FD_READ. - * This means buffering just one is fine. - */ - if (pending_netevent) - enact_pending_netevent(); - - pending_netevent = TRUE; - pend_netevent_wParam = wParam; - pend_netevent_lParam = lParam; - if (WSAGETSELECTEVENT(lParam) != FD_READ) - enact_pending_netevent(); - - time(&last_movement); + enact_netevent(wParam, lParam); + net_pending_errors(); return 0; case WM_SETFOCUS: - term->has_focus = TRUE; + term_set_focus(term, TRUE); CreateCaret(hwnd, caretbm, font_width, font_height); ShowCaret(hwnd); flash_window(0); /* stop */ compose_state = 0; - term_out(term); term_update(term); break; case WM_KILLFOCUS: show_mouseptr(1); - term->has_focus = FALSE; + term_set_focus(term, FALSE); DestroyCaret(); caret_x = caret_y = -1; /* ensure caret is replaced next time */ - term_out(term); term_update(term); break; case WM_ENTERSIZEMOVE: @@ -2710,12 +2775,11 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, set_input_locale((HKL)lParam); sys_cursor_update(); break; - case WM_IME_NOTIFY: - if(wParam == IMN_SETOPENSTATUS) { + case WM_IME_STARTCOMPOSITION: + { HIMC hImc = ImmGetContext(hwnd); ImmSetCompositionFont(hImc, &lfont); ImmReleaseContext(hwnd, hImc); - return 0; } break; case WM_IME_COMPOSITION: @@ -2785,12 +2849,6 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, lpage_send(ldisc, CP_ACP, &c, 1, 1); } return 0; - case WM_SETCURSOR: - if (send_raw_mouse && LOWORD(lParam) == HTCLIENT) { - SetCursor(LoadCursor(NULL, IDC_ARROW)); - return TRUE; - } - break; case WM_SYSCOLORCHANGE: if (cfg.system_colour) { /* Refresh palette from system colours. */ @@ -2862,6 +2920,10 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, } } + /* + * Any messages we don't process completely above are passed through to + * DefWindowProc() for default processing. + */ return DefWindowProc(hwnd, message, wParam, lParam); } @@ -2965,8 +3027,12 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, y += offset_height; if ((attr & TATTR_ACTCURS) && (cfg.cursor_type == 0 || term->big_cursor)) { - attr &= ATTR_CUR_AND | (bold_mode != BOLD_COLOURS ? ATTR_BOLD : 0); - attr ^= ATTR_CUR_XOR; + 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); } nfont = 0; @@ -3024,9 +3090,7 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, nfont |= FONT_OEM; nfg = ((attr & ATTR_FGMASK) >> ATTR_FGSHIFT); - nfg = 2 * (nfg & 0xF) + (nfg & 0x10 ? 1 : 0); nbg = ((attr & ATTR_BGMASK) >> ATTR_BGSHIFT); - nbg = 2 * (nbg & 0xF) + (nbg & 0x10 ? 1 : 0); if (bold_mode == BOLD_FONT && (attr & ATTR_BOLD)) nfont |= FONT_BOLD; if (und_mode == UND_FONT && (attr & ATTR_UNDER)) @@ -3047,10 +3111,14 @@ 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)) - nfg |= 1; - if (bold_mode == BOLD_COLOURS && (attr & ATTR_BLINK)) - nbg |= 1; + if (bold_mode == BOLD_COLOURS && (attr & ATTR_BOLD)) { + if (nfg < 16) nfg |= 8; + else if (nfg >= 256) nfg |= 1; + } + if (bold_mode == BOLD_COLOURS && (attr & ATTR_BLINK)) { + if (nbg < 16) nbg |= 8; + else if (nbg >= 256) nbg |= 1; + } fg = colours[nfg]; bg = colours[nbg]; SelectObject(hdc, fonts[nfont]); @@ -3248,7 +3316,7 @@ void do_cursor(Context ctx, int x, int y, wchar_t *text, int len, pts[2].x = pts[3].x = x + char_width - 1; pts[0].y = pts[3].y = pts[4].y = y; pts[1].y = pts[2].y = y + font_height - 1; - oldpen = SelectObject(hdc, CreatePen(PS_SOLID, 0, colours[23])); + oldpen = SelectObject(hdc, CreatePen(PS_SOLID, 0, colours[261])); Polyline(hdc, pts, 5); oldpen = SelectObject(hdc, oldpen); DeleteObject(oldpen); @@ -3273,7 +3341,7 @@ void do_cursor(Context ctx, int x, int y, wchar_t *text, int len, if (attr & TATTR_ACTCURS) { HPEN oldpen; oldpen = - SelectObject(hdc, CreatePen(PS_SOLID, 0, colours[23])); + SelectObject(hdc, CreatePen(PS_SOLID, 0, colours[261])); MoveToEx(hdc, startx, starty, NULL); LineTo(hdc, startx + dx * length, starty + dy * length); oldpen = SelectObject(hdc, oldpen); @@ -3281,7 +3349,7 @@ void do_cursor(Context ctx, int x, int y, wchar_t *text, int len, } else { for (i = 0; i < length; i++) { if (i % 2 == 0) { - SetPixel(hdc, startx, starty, colours[23]); + SetPixel(hdc, startx, starty, colours[261]); } startx += dx; starty += dy; @@ -4281,21 +4349,18 @@ static void real_palette_set(int n, int r, int g, int b) logpal->palPalEntry[n].peBlue = b; logpal->palPalEntry[n].peFlags = PC_NOCOLLAPSE; colours[n] = PALETTERGB(r, g, b); - SetPaletteEntries(pal, 0, NCOLOURS, logpal->palPalEntry); + SetPaletteEntries(pal, 0, NALLCOLOURS, logpal->palPalEntry); } else colours[n] = RGB(r, g, b); } void palette_set(void *frontend, int n, int r, int g, int b) { - static const int first[21] = { - 0, 2, 4, 6, 8, 10, 12, 14, - 1, 3, 5, 7, 9, 11, 13, 15, - 16, 17, 18, 20, 22 - }; - real_palette_set(first[n], r, g, b); - if (first[n] >= 18) - real_palette_set(first[n] + 1, r, g, b); + if (n >= 16) + n += 256 - 16; + if (n > NALLCOLOURS) + return; + real_palette_set(n, r, g, b); if (pal) { HDC hdc = get_ctx(frontend); UnrealizeObject(pal); @@ -4308,7 +4373,8 @@ void palette_reset(void *frontend) { int i; - for (i = 0; i < NCOLOURS; i++) { + /* And this */ + for (i = 0; i < NALLCOLOURS; i++) { if (pal) { logpal->palPalEntry[i].peRed = defpal[i].rgbtRed; logpal->palPalEntry[i].peGreen = defpal[i].rgbtGreen; @@ -4324,7 +4390,7 @@ void palette_reset(void *frontend) if (pal) { HDC hdc; - SetPaletteEntries(pal, 0, NCOLOURS, logpal->palPalEntry); + SetPaletteEntries(pal, 0, NALLCOLOURS, logpal->palPalEntry); hdc = get_ctx(frontend); RealizePalette(hdc); free_ctx(hdc); @@ -4624,14 +4690,23 @@ void modalfatalbox(char *fmt, ...) cleanup_exit(1); } +static void flash_window(int mode); +static long next_flash; +static int flashing = 0; + +static void flash_window_timer(void *ctx, long now) +{ + if (flashing && now - next_flash >= 0) { + flash_window(1); + } +} + /* * Manage window caption / taskbar flashing, if enabled. * 0 = stop, 1 = maintain, 2 = start */ static void flash_window(int mode) { - static long last_flash = 0; - static int flashing = 0; if ((mode == 0) || (cfg.beep_ind == B_IND_DISABLED)) { /* stop */ if (flashing) { @@ -4642,20 +4717,16 @@ static void flash_window(int mode) } else if (mode == 2) { /* start */ if (!flashing) { - last_flash = GetTickCount(); flashing = 1; FlashWindow(hwnd, TRUE); + next_flash = schedule_timer(450, flash_window_timer, hwnd); } } else if ((mode == 1) && (cfg.beep_ind == B_IND_FLASH)) { /* maintain */ if (flashing) { - long now = GetTickCount(); - long fdiff = now - last_flash; - if (fdiff < 0 || fdiff > 450) { - last_flash = now; - FlashWindow(hwnd, TRUE); /* toggle */ - } + FlashWindow(hwnd, TRUE); /* toggle */ + next_flash = schedule_timer(450, flash_window_timer, hwnd); } } }