Add a couple more FAQs (`where's the Tunnels panel' and `how do I do
[sgt/putty] / window.c
index cd5f703..006e5ff 100644 (file)
--- a/window.c
+++ b/window.c
@@ -9,6 +9,12 @@
 #include <winsock.h>
 #endif
 #endif
+
+#if (WINVER < 0x0500) && !defined(NO_MULTIMON)
+#define COMPILE_MULTIMON_STUBS
+#include <multimon.h>
+#endif
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <ctype.h>
@@ -42,6 +48,7 @@
 #define IDM_ABOUT     0x0140
 #define IDM_SAVEDSESS 0x0150
 #define IDM_COPYALL   0x0160
+#define IDM_FULLSCREEN 0x0170
 
 #define IDM_SESSLGP   0x0250          /* log type printable */
 #define IDM_SESSLGA   0x0260          /* log type all chars */
@@ -72,11 +79,14 @@ static void deinit_fonts(void);
 
 /* Window layout information */
 static void reset_window(int);
-static int full_screen = 0, extra_width, extra_height;
+static int full_screen = 0, want_full_screen = 0;
+static int extra_width, extra_height;
 static int font_width, font_height, font_dualwidth;
 static int offset_width, offset_height;
 static int was_zoomed = 0;
+static int was_full_screen = 0;
 static int prev_rows, prev_cols;
+static int pre_fs_rows, pre_fs_cols;
   
 static LONG old_wind_style;
 static WINDOWPLACEMENT old_wind_placement;
@@ -429,7 +439,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
        int exwinmode = 0;
        if (!cfg.scrollbar)
            winmode &= ~(WS_VSCROLL);
-       if (cfg.locksize && cfg.lockfont)
+       if (cfg.resize_action == RESIZE_DISABLED)
            winmode &= ~(WS_THICKFRAME | WS_MAXIMIZEBOX);
        if (cfg.alwaysontop)
            exwinmode |= WS_EX_TOPMOST;
@@ -526,12 +536,6 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
     session_closed = FALSE;
 
     /*
-     * Set up the input and output buffers.
-     */
-    inbuf_head = 0;
-    outbuf_reap = outbuf_head = 0;
-
-    /*
      * Prepare the mouse handler.
      */
     lastact = MA_NOTHING;
@@ -585,6 +589,8 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
        AppendMenu(m, MF_ENABLED, IDM_CLRSB, "C&lear Scrollback");
        AppendMenu(m, MF_ENABLED, IDM_RESET, "Rese&t Terminal");
        AppendMenu(m, MF_SEPARATOR, 0, 0);
+       AppendMenu(m, MF_ENABLED, IDM_FULLSCREEN, "&Full Screen");
+       AppendMenu(m, MF_SEPARATOR, 0, 0);
        AppendMenu(m, MF_ENABLED, IDM_ABOUT, "&About PuTTY");
     }
 
@@ -660,8 +666,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
                timer_id = 0;
            }
            HideCaret(hwnd);
-           if (inbuf_head)
-               term_out();
+           term_out();
            term_update();
            ShowCaret(hwnd);
 
@@ -1099,11 +1104,11 @@ void request_resize(int w, int h)
 
     /* If the window is maximized supress resizing attempts */
     if (IsZoomed(hwnd)) {
-       if (cfg.lockfont)
+       if (cfg.resize_action != RESIZE_FONT)
            return;
     }
 
-    if (cfg.lockfont && cfg.locksize) return;
+    if (cfg.resize_action == RESIZE_DISABLED) return;
     if (h == rows && w == cols) return;
 
     /* Sanity checks ... */
@@ -1136,7 +1141,7 @@ void request_resize(int w, int h)
 
     term_size(h, w, cfg.savelines);
 
-    if (cfg.lockfont) {
+    if (cfg.resize_action != RESIZE_FONT) {
        width = extra_width + font_width * w;
        height = extra_height + font_height * h;
 
@@ -1196,7 +1201,7 @@ static void reset_window(int reinit) {
 #endif
     }
 
-    if (IsZoomed(hwnd)) {
+    if (IsZoomed(hwnd) || full_screen) {
        /* We're fullscreen, this means we must not change the size of
         * the window so it's the font size or the terminal itself.
         */
@@ -1204,7 +1209,7 @@ static void reset_window(int reinit) {
        extra_width = wr.right - wr.left - cr.right + cr.left;
        extra_height = wr.bottom - wr.top - cr.bottom + cr.top;
 
-       if (!cfg.lockfont) {
+       if (cfg.resize_action == RESIZE_FONT) {
            if (  font_width != win_width/cols || 
                  font_height != win_height/rows) {
                deinit_fonts();
@@ -1267,7 +1272,7 @@ static void reset_window(int reinit) {
      * window. But that may be too big for the screen which forces us
      * to change the terminal.
      */
-    if ((cfg.lockfont && reinit==0) || reinit>0) {
+    if ((cfg.resize_action != RESIZE_FONT  && reinit==0) || reinit>0) {
        offset_width = offset_height = cfg.window_border;
        extra_width = wr.right - wr.left - cr.right + cr.left + offset_width*2;
        extra_height = wr.bottom - wr.top - cr.bottom + cr.top +offset_height*2;
@@ -1392,8 +1397,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
       case WM_TIMER:
        if (pending_netevent)
            enact_pending_netevent();
-       if (inbuf_head)
-           term_out();
+       term_out();
        noise_regular();
        HideCaret(hwnd);
        term_update();
@@ -1406,6 +1410,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                last_movement = now;
            }
        }
+       net_pending_errors();
        return 0;
       case WM_CREATE:
        break;
@@ -1505,6 +1510,11 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                if (!do_reconfig(hwnd))
                    break;
 
+               /* If user forcibly disables full-screen, gracefully unzoom */
+               if (full_screen && !cfg.fullscreenonaltenter) {
+                   flip_full_screen();
+               }
+
                if (strcmp(prev_cfg.logfilename, cfg.logfilename) ||
                    prev_cfg.logtype != cfg.logtype) {
                    logfclose();       /* reset logging */
@@ -1516,7 +1526,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                 * Flush the line discipline's edit buffer in the
                 * case where local editing has just been disabled.
                 */
-               ldisc_send(NULL, 0);
+               ldisc_send(NULL, 0, 0);
                if (pal)
                    DeleteObject(pal);
                logpal = NULL;
@@ -1528,7 +1538,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                if (cfg.height != prev_cfg.height ||
                    cfg.width != prev_cfg.width ||
                    cfg.savelines != prev_cfg.savelines ||
-                   cfg.locksize )
+                   cfg.resize_action != RESIZE_TERM)
                    term_size(cfg.height, cfg.width, cfg.savelines);
 
                /* Enable or disable the scroll bar, etc */
@@ -1559,7 +1569,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                        nflg |= WS_VSCROLL;
                    else
                        nflg &= ~WS_VSCROLL;
-                   if (cfg.locksize && cfg.lockfont)
+                   if (cfg.resize_action == RESIZE_DISABLED)
                        nflg &= ~(WS_THICKFRAME | WS_MAXIMIZEBOX);
                    else
                        nflg |= (WS_THICKFRAME | WS_MAXIMIZEBOX);
@@ -1580,7 +1590,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                }
 
                /* Oops */
-               if (cfg.locksize && cfg.lockfont && IsZoomed(hwnd)) {
+               if (cfg.resize_action == RESIZE_DISABLED && IsZoomed(hwnd)) {
                    force_normal(hwnd);
                    init_lvl = 2;
                }
@@ -1599,11 +1609,13 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                    cfg.fontcharset != prev_cfg.fontcharset ||
                    cfg.vtmode != prev_cfg.vtmode ||
                    cfg.bold_colour != prev_cfg.bold_colour ||
-                   (cfg.lockfont && !prev_cfg.lockfont))
+                   (cfg.resize_action != RESIZE_FONT &&
+                    prev_cfg.resize_action == RESIZE_FONT))
                    init_lvl = 2;
 
                InvalidateRect(hwnd, NULL, TRUE);
                reset_window(init_lvl);
+               net_pending_errors();
            }
            break;
          case IDM_COPYALL:
@@ -1617,42 +1629,55 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
            break;
          case IDM_TEL_AYT:
            back->special(TS_AYT);
+           net_pending_errors();
            break;
          case IDM_TEL_BRK:
            back->special(TS_BRK);
+           net_pending_errors();
            break;
          case IDM_TEL_SYNCH:
            back->special(TS_SYNCH);
+           net_pending_errors();
            break;
          case IDM_TEL_EC:
            back->special(TS_EC);
+           net_pending_errors();
            break;
          case IDM_TEL_EL:
            back->special(TS_EL);
+           net_pending_errors();
            break;
          case IDM_TEL_GA:
            back->special(TS_GA);
+           net_pending_errors();
            break;
          case IDM_TEL_NOP:
            back->special(TS_NOP);
+           net_pending_errors();
            break;
          case IDM_TEL_ABORT:
            back->special(TS_ABORT);
+           net_pending_errors();
            break;
          case IDM_TEL_AO:
            back->special(TS_AO);
+           net_pending_errors();
            break;
          case IDM_TEL_IP:
            back->special(TS_IP);
+           net_pending_errors();
            break;
          case IDM_TEL_SUSP:
            back->special(TS_SUSP);
+           net_pending_errors();
            break;
          case IDM_TEL_EOR:
            back->special(TS_EOR);
+           net_pending_errors();
            break;
          case IDM_TEL_EOF:
            back->special(TS_EOF);
+           net_pending_errors();
            break;
          case IDM_ABOUT:
            showabout(hwnd);
@@ -1668,6 +1693,9 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
            if( lParam == 0 )
                PostMessage(hwnd, WM_CHAR, ' ', 0);
            break;
+         case IDM_FULLSCREEN:
+               flip_full_screen();     
+               break;
          default:
            if (wParam >= IDM_SAVED_MIN && wParam <= IDM_SAVED_MAX) {
                SendMessage(hwnd, WM_SYSCOMMAND, IDM_SAVEDSESS, wParam);
@@ -1910,7 +1938,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
         * 1) Keep the sizetip uptodate
         * 2) Make sure the window size is _stepped_ in units of the font size.
         */
-       if (!cfg.locksize && !alt_pressed) {
+       if (cfg.resize_action == RESIZE_TERM && !alt_pressed) {
            int width, height, w, h, ew, eh;
            LPRECT r = (LPRECT) lParam;
 
@@ -1990,7 +2018,6 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
 
            return rv;
        }
-       break;
        /* break;  (never reached) */
       case WM_SIZE:
 #ifdef RDB_DEBUG_PATCH
@@ -2010,7 +2037,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
        if (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED)
            SetWindowText(hwnd, window_name);
 
-       if (cfg.lockfont && cfg.locksize) {
+       if (cfg.resize_action == RESIZE_DISABLED) {
            /* A resize, well it better be a minimize. */
            reset_window(-1);
        } else {
@@ -2025,7 +2052,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                    was_zoomed = 1;
                    prev_rows = rows;
                    prev_cols = cols;
-                   if (cfg.lockfont) {
+                   if (cfg.resize_action != RESIZE_FONT) {
                        w = width / font_width;
                        if (w < 1) w = 1;
                        h = height / font_height;
@@ -2036,9 +2063,14 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                    reset_window(0);
                } else if (wParam == SIZE_RESTORED && was_zoomed) {
                    was_zoomed = 0;
-                   if (cfg.lockfont)
+                   if (cfg.resize_action != RESIZE_FONT)
                        term_size(prev_rows, prev_cols, cfg.savelines);
                    reset_window(0);
+               } else if (was_full_screen) {
+                   was_full_screen = 0;
+                   if (cfg.resize_action != RESIZE_FONT)
+                       term_size(pre_fs_rows, pre_fs_cols, cfg.savelines);
+                   reset_window(0);
                }
                /* This is an unexpected resize, these will normally happen
                 * if the window is too large. Probably either the user
@@ -2055,7 +2087,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
             * down the connection during an NT opaque drag.)
             */
            if (resizing) {
-               if (!cfg.locksize && !alt_pressed) {
+               if (cfg.resize_action == RESIZE_TERM && !alt_pressed) {
                    need_backend_resize = TRUE;
                    w = (width-cfg.window_border*2) / font_width;
                    if (w < 1) w = 1;
@@ -2151,6 +2183,14 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
 
                if (len != 0) {
                    /*
+                    * Interrupt an ongoing paste. I'm not sure
+                    * this is sensible, but for the moment it's
+                    * preferable to having to faff about buffering
+                    * things.
+                    */
+                   term_nopaste();
+
+                   /*
                     * We need not bother about stdin backlogs
                     * here, because in GUI PuTTY we can't do
                     * anything about it anyway; there's no means
@@ -2158,11 +2198,12 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                     * messages. We _have_ to buffer everything
                     * we're sent.
                     */
-                   ldisc_send(buf, len);
+                   ldisc_send(buf, len, 1);
                    show_mouseptr(0);
                }
            }
        }
+       net_pending_errors();
        return 0;
       case WM_INPUTLANGCHANGE:
        {
@@ -2197,7 +2238,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
            if (n > 0) {
                buff = (char*) smalloc(n);
                ImmGetCompositionStringW(hIMC, GCS_RESULTSTR, buff, n);
-               luni_send((unsigned short *)buff, n / 2);
+               luni_send((unsigned short *)buff, n / 2, 1);
                free(buff);
            }
            ImmReleaseContext(hwnd, hIMC);
@@ -2210,10 +2251,10 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
 
            buf[1] = wParam;
            buf[0] = wParam >> 8;
-           lpage_send(kbd_codepage, buf, 2);
+           lpage_send(kbd_codepage, buf, 2, 1);
        } else {
            char c = (unsigned char) wParam;
-           lpage_send(kbd_codepage, &c, 1);
+           lpage_send(kbd_codepage, &c, 1, 1);
        }
        return (0);
       case WM_CHAR:
@@ -2226,7 +2267,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
         */
        {
            char c = (unsigned char)wParam;
-           lpage_send(CP_ACP, &c, 1);
+           lpage_send(CP_ACP, &c, 1, 1);
        }
        return 0;
       case WM_SETCURSOR:
@@ -2831,10 +2872,6 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
        seen_key_event = 1;
     }
 
-    /* Make sure we're not pasting */
-    if (key_down)
-       term_nopaste();
-
     if (compose_state > 1 && left_alt)
        compose_state = 0;
 
@@ -3364,6 +3401,14 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
 #endif
        if (r > 0) {
            WCHAR keybuf;
+
+           /*
+            * Interrupt an ongoing paste. I'm not sure this is
+            * sensible, but for the moment it's preferable to
+            * having to faff about buffering things.
+            */
+           term_nopaste();
+
            p = output;
            for (i = 0; i < r; i++) {
                unsigned char ch = (unsigned char) keys[i];
@@ -3382,7 +3427,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
                        return 0;
                    }
                    keybuf = nc;
-                   luni_send(&keybuf, 1);
+                   luni_send(&keybuf, 1, 1);
                    continue;
                }
 
@@ -3392,7 +3437,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
                    if (alt_sum) {
                        if (in_utf || dbcs_screenfont) {
                            keybuf = alt_sum;
-                           luni_send(&keybuf, 1);
+                           luni_send(&keybuf, 1, 1);
                        } else {
                            ch = (char) alt_sum;
                            /*
@@ -3404,22 +3449,22 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
                             * messages. We _have_ to buffer
                             * everything we're sent.
                             */
-                           ldisc_send(&ch, 1);
+                           ldisc_send(&ch, 1, 1);
                        }
                        alt_sum = 0;
                    } else
-                       lpage_send(kbd_codepage, &ch, 1);
+                       lpage_send(kbd_codepage, &ch, 1, 1);
                } else {
                    if(capsOn && ch < 0x80) {
                        WCHAR cbuf[2];
                        cbuf[0] = 27;
                        cbuf[1] = xlat_uskbd2cyrllic(ch);
-                       luni_send(cbuf+!left_alt, 1+!!left_alt);
+                       luni_send(cbuf+!left_alt, 1+!!left_alt, 1);
                    } else {
                        char cbuf[2];
                        cbuf[0] = '\033';
                        cbuf[1] = ch;
-                       lpage_send(kbd_codepage, cbuf+!left_alt, 1+!!left_alt);
+                       lpage_send(kbd_codepage, cbuf+!left_alt, 1+!!left_alt, 1);
                    }
                }
                show_mouseptr(0);
@@ -3799,23 +3844,62 @@ void beep(int mode)
 /*
  * Toggle full screen mode. Thanks to cwis@nerim.fr for the
  * implementation.
+ * Revised by <wez@thebrainroom.com>
  */
 static void flip_full_screen(void)
 {
-    if (!full_screen) {
-       int cx, cy;
+    want_full_screen = !want_full_screen;
+
+    if (full_screen == want_full_screen)
+       return;
 
+    full_screen = want_full_screen;
+
+    old_wind_placement.length = sizeof(old_wind_placement);
+
+    if (full_screen) {
+       int x, y, cx, cy;
+#if !defined(NO_MULTIMON) && defined(MONITOR_DEFAULTTONEAREST)
+       /* The multi-monitor safe way of doing things */
+       HMONITOR        mon;
+       MONITORINFO     mi;
+
+       mon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
+       mi.cbSize = sizeof(mi);
+       GetMonitorInfo(mon, &mi);
+       x = mi.rcMonitor.left;
+       y = mi.rcMonitor.top;
+       cx = mi.rcMonitor.right;
+       cy = mi.rcMonitor.bottom;
+#else
+       /* good old fashioned way of doing it */
+       x = 0;
+       y = 0;
        cx = GetSystemMetrics(SM_CXSCREEN);
        cy = GetSystemMetrics(SM_CYSCREEN);
+#endif
+
+       /* save rows for when we "restore" back down again */
+       pre_fs_rows = rows;
+       pre_fs_cols = cols;
+
        GetWindowPlacement(hwnd, &old_wind_placement);
-       old_wind_style = GetWindowLong(hwnd, GWL_STYLE);
        SetWindowLong(hwnd, GWL_STYLE,
-                     old_wind_style & ~(WS_CAPTION | WS_BORDER | WS_THICKFRAME));
-       SetWindowPos(hwnd, HWND_TOP, 0, 0, cx, cy, SWP_SHOWWINDOW);
-       full_screen = 1;
+                     GetWindowLong(hwnd, GWL_STYLE)
+                     & ~((cfg.scrollbar_in_fullscreen ? 0 : WS_VSCROLL)
+                         | WS_CAPTION | WS_BORDER | WS_THICKFRAME));
+       /* become topmost */
+       SetWindowPos(hwnd, HWND_TOP, x, y, cx, cy, SWP_FRAMECHANGED);
     } else {
-       SetWindowLong(hwnd, GWL_STYLE, old_wind_style);
+       was_full_screen = 1;
+       SetWindowLong(hwnd, GWL_STYLE,
+                     GetWindowLong(hwnd, GWL_STYLE)
+                     | (cfg.scrollbar ? WS_VSCROLL : 0)
+                     | WS_CAPTION | WS_BORDER | WS_THICKFRAME);
+       SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0,
+                    SWP_NOMOVE|SWP_NOSIZE|SWP_FRAMECHANGED);
        SetWindowPlacement(hwnd,&old_wind_placement);
-       full_screen = 0;
     }
+    CheckMenuItem(GetSystemMenu(hwnd, FALSE), IDM_FULLSCREEN,
+                 MF_BYCOMMAND| full_screen ? MF_CHECKED : MF_UNCHECKED);
 }