The terminal window can now indicate that PuTTY is busy in various ways, by
authorjacob <jacob@cda61777-01e9-0310-a592-d414129be87e>
Tue, 15 Feb 2005 17:05:58 +0000 (17:05 +0000)
committerjacob <jacob@cda61777-01e9-0310-a592-d414129be87e>
Tue, 15 Feb 2005 17:05:58 +0000 (17:05 +0000)
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
putty.h
ssh.c
unix/gtkwin.c
unix/uxcons.c
windows/wincons.c
windows/window.c

index f4b8f4d..d0307f5 100644 (file)
@@ -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 c2a7c45..0b49dfa 100644 (file)
--- 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 25c236e..20be698 100644 (file)
--- 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);
index 1b0ba4a..043f519 100644 (file)
@@ -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;
index b5bf840..7f05d1f 100644 (file)
@@ -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)
 {
 }
index 38b46fa..3417720 100644 (file)
@@ -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)
 {
 }
index 17aaf1a..1f4220e 100644 (file)
@@ -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. */