From c71cc50e52aca439185c09ada7788c3f226d17a4 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 24 Apr 2025 11:30:52 +0100 Subject: [PATCH] Windows: cope if caret blinking is disabled. On Windows, when a blinking cursor is enabled, PuTTY uses the system default blink time from GetCaretBlinkTime(), which can be configured in Control Panel. Control Panel allows caret blinking to be disabled entirely, in which case GetCaretBlinkTime() returns INFINITE. PuTTY wasn't handling this case; if cursor blinking was enabled in PuTTY but disabled at the system level, the terminal window would hang, blinking the cursor madly. --- doc/config.but | 4 +++- terminal/terminal.c | 5 +++-- windows/CMakeLists.txt | 1 + windows/platform.h | 4 +++- windows/utils/blink_time.c | 21 +++++++++++++++++++++ 5 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 windows/utils/blink_time.c diff --git a/doc/config.but b/doc/config.but index 56641b5b..ae714db3 100644 --- a/doc/config.but +++ b/doc/config.but @@ -1091,7 +1091,9 @@ empty box when the window loses focus; an underline or a vertical line becomes dotted. The \q{\ii{Cursor blinks}} option makes the cursor blink on and off. This -works in any of the cursor modes. +works in any of the cursor modes. (On Windows, the blink rate matches +that configured in Control Panel; so this setting will have no effect +if cursor blinking has been disabled system-wide.) \S{config-font} Controlling the \i{font} used in the terminal window diff --git a/terminal/terminal.c b/terminal/terminal.c index 0fad9eb8..574e8261 100644 --- a/terminal/terminal.c +++ b/terminal/terminal.c @@ -1381,9 +1381,10 @@ static void term_schedule_tblink(Terminal *term) */ static void term_schedule_cblink(Terminal *term) { - if (term->blink_cur && term->has_focus) { + int delay = CBLINK_DELAY; + if (term->blink_cur && term->has_focus && delay > 0) { if (!term->cblink_pending) - term->next_cblink = schedule_timer(CBLINK_DELAY, term_timer, term); + term->next_cblink = schedule_timer(delay, term_timer, term); term->cblink_pending = true; } else { term->cblinker = true; /* reset when not in use */ diff --git a/windows/CMakeLists.txt b/windows/CMakeLists.txt index 960a440d..1b5c6162 100644 --- a/windows/CMakeLists.txt +++ b/windows/CMakeLists.txt @@ -5,6 +5,7 @@ add_sources_from_current_dir(utils utils/agent_named_pipe_name.c utils/arm_arch_queries.c utils/aux_match_opt.c + utils/blink_time.c utils/centre_window.c utils/cmdline_arg.c utils/cryptoapi.c diff --git a/windows/platform.h b/windows/platform.h index 10551e87..0932e02a 100644 --- a/windows/platform.h +++ b/windows/platform.h @@ -203,8 +203,10 @@ void centre_window(HWND hwnd); #define PUTTY_CHM_FILE "putty.chm" +int get_caret_blink_time(void); + #define GETTICKCOUNT GetTickCount -#define CURSORBLINK GetCaretBlinkTime() +#define CURSORBLINK get_caret_blink_time() #define TICKSPERSEC 1000 /* GetTickCount returns milliseconds */ #define DEFAULT_CODEPAGE CP_ACP diff --git a/windows/utils/blink_time.c b/windows/utils/blink_time.c new file mode 100644 index 00000000..3a7ac400 --- /dev/null +++ b/windows/utils/blink_time.c @@ -0,0 +1,21 @@ +/* + * Wrapper for GetCaretBlinkTime() which turns it into a signed integer, + * with 0 meaning "no blinking". + */ + +#include "putty.h" +#include + +int get_caret_blink_time(void) +{ + UINT blinktime = GetCaretBlinkTime(); + if (blinktime == INFINITE) + /* Windows' registry representation for 'no caret blinking' + * is the string "-1", but we may as well use 0 as the sentinel + * value, as it'd be bad to attempt blinking with period 0 + * in any case. */ + return 0; + else + /* assume this won't be so big that casting is a problem */ + return (int) blinktime; +}