From 755e0524eb217ebed9f649405fa2624b26f0fb29 Mon Sep 17 00:00:00 2001 From: jacob Date: Tue, 15 Feb 2005 17:05:58 +0000 Subject: [PATCH] The terminal window can now indicate that PuTTY is busy in various ways, by changing its mouse pointer. Currently this is only used in the (slightly- arbitrarily-defined) "heavy" bits of SSH-2 key exchange. We override pointer hiding while PuTTY is busy, but preserve pointer-hiding state. Not yet implemented on the Mac. Also switch to frobbing window-class cursor in Windows rather than relying on SetCursor(). git-svn-id: svn://svn.tartarus.org/sgt/putty@5303 cda61777-01e9-0310-a592-d414129be87e --- mac/macterm.c | 8 ++++++++ putty.h | 10 ++++++++++ ssh.c | 7 +++++++ unix/gtkwin.c | 45 ++++++++++++++++++++++++++++++++++---------- unix/uxcons.c | 4 ++++ windows/wincons.c | 4 ++++ windows/window.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++------- 7 files changed, 117 insertions(+), 17 deletions(-) diff --git a/mac/macterm.c b/mac/macterm.c index f4b8f4df..d0307f58 100644 --- a/mac/macterm.c +++ b/mac/macterm.c @@ -1500,6 +1500,14 @@ void set_title(void *frontend, char *title) } /* + * Used by backend to indicate busy-ness + */ +void set_busy_status(void *frontend, int status) +{ + /* FIXME do something */ +} + +/* * set or clear the "raw mouse message" mode */ void set_raw_mouse_mode(void *frontend, int activate) diff --git a/putty.h b/putty.h index c2a7c453..0b49dfa8 100644 --- a/putty.h +++ b/putty.h @@ -647,6 +647,16 @@ int is_iconic(void *frontend); void get_window_pos(void *frontend, int *x, int *y); void get_window_pixels(void *frontend, int *x, int *y); char *get_window_title(void *frontend, int icon); +/* Hint from backend to frontend about time-consuming operations. + * Initial state is assumed to be BUSY_NOT. */ +enum { + BUSY_NOT, /* Not busy, all user interaction OK */ + BUSY_WAITING, /* Waiting for something; local event loops still running + so some local interaction (e.g. menus) OK, but network + stuff is suspended */ + BUSY_CPU /* Locally busy (e.g. crypto); user interaction suspended */ +}; +void set_busy_status(void *frontend, int status); void cleanup_exit(int); diff --git a/ssh.c b/ssh.c index 25c236ec..20be6985 100644 --- a/ssh.c +++ b/ssh.c @@ -5142,16 +5142,19 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen, /* * Now generate and send e for Diffie-Hellman. */ + set_busy_status(ssh->frontend, BUSY_CPU); /* this can take a while */ s->e = dh_create_e(ssh->kex_ctx, s->nbits * 2); s->pktout = ssh2_pkt_init(s->kex_init_value); ssh2_pkt_addmp(s->pktout, s->e); ssh2_pkt_send_noqueue(ssh, s->pktout); + set_busy_status(ssh->frontend, BUSY_WAITING); /* wait for server */ crWaitUntil(pktin); if (pktin->type != s->kex_reply_value) { bombout(("expected key exchange reply packet from server")); crStop(0); } + set_busy_status(ssh->frontend, BUSY_CPU); /* cogitate */ ssh_pkt_getstring(pktin, &s->hostkeydata, &s->hostkeylen); s->f = ssh2_pkt_getmp(pktin); if (!s->f) { @@ -5162,6 +5165,10 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen, s->K = dh_find_K(ssh->kex_ctx, s->f); + /* We assume everything from now on will be quick, and it might + * involve user interaction. */ + set_busy_status(ssh->frontend, BUSY_NOT); + sha_string(&ssh->exhash, s->hostkeydata, s->hostkeylen); if (ssh->kex == &ssh_diffiehellman_gex) { sha_uint32(&ssh->exhash, s->pbits); diff --git a/unix/gtkwin.c b/unix/gtkwin.c index 1b0ba4a1..043f519f 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -64,7 +64,7 @@ struct gui_data { int is_wide; } fontinfo[4]; int xpos, ypos, gotpos, gravity; - GdkCursor *rawcursor, *textcursor, *blankcursor, *currcursor; + GdkCursor *rawcursor, *textcursor, *blankcursor, *waitcursor, *currcursor; GdkColor cols[NALLCOLOURS]; GdkColormap *colmap; wchar_t *pastein_data; @@ -76,6 +76,7 @@ struct gui_data { int width, height; int ignore_sbar; int mouseptr_visible; + int busy_status; guint term_paste_idle_id; int alt_keycode; int alt_digits; @@ -372,15 +373,34 @@ gint delete_window(GtkWidget *widget, GdkEvent *event, gpointer data) return FALSE; } +static void update_mouseptr(struct gui_data *inst) +{ + switch (inst->busy_status) { + case BUSY_NOT: + if (!inst->mouseptr_visible) { + gdk_window_set_cursor(inst->area->window, inst->blankcursor); + } else if (send_raw_mouse) { + gdk_window_set_cursor(inst->area->window, inst->rawcursor); + } else { + gdk_window_set_cursor(inst->area->window, inst->textcursor); + } + break; + case BUSY_WAITING: /* XXX can we do better? */ + case BUSY_CPU: + /* We always display these cursors. */ + gdk_window_set_cursor(inst->area->window, inst->waitcursor); + break; + default: + assert(0); + } +} + static void show_mouseptr(struct gui_data *inst, int show) { if (!inst->cfg.hide_mouseptr) show = 1; - if (show) - gdk_window_set_cursor(inst->area->window, inst->currcursor); - else - gdk_window_set_cursor(inst->area->window, inst->blankcursor); inst->mouseptr_visible = show; + update_mouseptr(inst); } void draw_backing_rect(struct gui_data *inst) @@ -1227,6 +1247,13 @@ gint focus_event(GtkWidget *widget, GdkEventFocus *event, gpointer data) return FALSE; } +void set_busy_status(void *frontend, int status) +{ + struct gui_data *inst = (struct gui_data *)frontend; + inst->busy_status = status; + update_mouseptr(inst); +} + /* * set or clear the "raw mouse message" mode */ @@ -1235,11 +1262,7 @@ void set_raw_mouse_mode(void *frontend, int activate) struct gui_data *inst = (struct gui_data *)frontend; activate = activate && !inst->cfg.no_mouse_rep; send_raw_mouse = activate; - if (send_raw_mouse) - inst->currcursor = inst->rawcursor; - else - inst->currcursor = inst->textcursor; - show_mouseptr(inst, inst->mouseptr_visible); + update_mouseptr(inst); } void request_resize(void *frontend, int w, int h) @@ -3310,6 +3333,7 @@ int pt_main(int argc, char **argv) inst = snew(struct gui_data); memset(inst, 0, sizeof(*inst)); inst->alt_keycode = -1; /* this one needs _not_ to be zero */ + inst->busy_status = BUSY_NOT; /* defer any child exit handling until we're ready to deal with * it */ @@ -3520,6 +3544,7 @@ int pt_main(int argc, char **argv) inst->textcursor = make_mouse_ptr(inst, GDK_XTERM); inst->rawcursor = make_mouse_ptr(inst, GDK_LEFT_PTR); + inst->waitcursor = make_mouse_ptr(inst, GDK_WATCH); inst->blankcursor = make_mouse_ptr(inst, -1); make_mouse_ptr(inst, -2); /* clean up cursor font */ inst->currcursor = inst->textcursor; diff --git a/unix/uxcons.c b/unix/uxcons.c index b5bf840b..7f05d1fa 100644 --- a/unix/uxcons.c +++ b/unix/uxcons.c @@ -31,6 +31,10 @@ void cleanup_exit(int code) exit(code); } +void set_busy_status(void *frontend, int status) +{ +} + void update_specials_menu(void *frontend) { } diff --git a/windows/wincons.c b/windows/wincons.c index 38b46fad..3417720a 100644 --- a/windows/wincons.c +++ b/windows/wincons.c @@ -33,6 +33,10 @@ void cleanup_exit(int code) exit(code); } +void set_busy_status(void *frontend, int status) +{ +} + void notify_remote_exit(void *frontend) { } diff --git a/windows/window.c b/windows/window.c index 17aaf1ae..1f4220e4 100644 --- a/windows/window.c +++ b/windows/window.c @@ -177,6 +177,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; @@ -949,6 +951,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 */ @@ -956,7 +1002,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(); } /* @@ -1736,6 +1782,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; @@ -2751,12 +2799,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. */ -- 2.11.0