Try to make our PGP signing more useful:
[u/mdw/putty] / windows / window.c
index 17aaf1a..05f0c61 100644 (file)
@@ -108,6 +108,7 @@ 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;
@@ -166,8 +167,6 @@ static HPALETTE pal;
 static LPLOGPALETTE logpal;
 static RGBTRIPLE defpal[NALLCOLOURS];
 
-static HWND hwnd;
-
 static HBITMAP caretbm;
 
 static int dbltime, lasttime, lastact;
@@ -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) {
@@ -597,8 +621,6 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
        RegisterClass(&wndclass);
     }
 
-    hwnd = NULL;
-
     memset(&ucsdata, 0, sizeof(ucsdata));
 
     cfgtopalette();
@@ -949,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
  */
@@ -956,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();
 }
 
 /*
@@ -1736,6 +1802,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;
@@ -1814,7 +1882,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);
        }
@@ -1836,6 +1905,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;
@@ -1864,6 +1934,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) {
@@ -1873,11 +1944,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);
@@ -1887,7 +1961,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)
@@ -1908,6 +1982,11 @@ 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;
 
@@ -2044,6 +2123,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:
@@ -2290,12 +2370,44 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                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,
-                      TRUE);
+                      !term->window_update_pending);
 
            if (p.fErase ||
                p.rcPaint.left  < offset_width  ||
@@ -2751,12 +2863,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. */