+ SetWindowPos(hwnd, NULL, 0, 0, width, height,
+ SWP_NOACTIVATE | SWP_NOCOPYBITS |
+ SWP_NOMOVE | SWP_NOZORDER);
+ } else
+ reset_window(0);
+
+ InvalidateRect(hwnd, NULL, TRUE);
+}
+
+static void reset_window(int reinit) {
+ /*
+ * This function decides how to resize or redraw when the
+ * user changes something.
+ *
+ * This function doesn't like to change the terminal size but if the
+ * font size is locked that may be it's only soluion.
+ */
+ int win_width, win_height;
+ RECT cr, wr;
+
+#ifdef RDB_DEBUG_PATCH
+ debug((27, "reset_window()"));
+#endif
+
+ /* Current window sizes ... */
+ GetWindowRect(hwnd, &wr);
+ GetClientRect(hwnd, &cr);
+
+ win_width = cr.right - cr.left;
+ win_height = cr.bottom - cr.top;
+
+ if (cfg.resize_action == RESIZE_DISABLED) reinit = 2;
+
+ /* Are we being forced to reload the fonts ? */
+ if (reinit>1) {
+#ifdef RDB_DEBUG_PATCH
+ debug((27, "reset_window() -- Forced deinit"));
+#endif
+ deinit_fonts();
+ init_fonts(0,0);
+ }
+
+ /* Oh, looks like we're minimised */
+ if (win_width == 0 || win_height == 0)
+ return;
+
+ /* Is the window out of position ? */
+ if ( !reinit &&
+ (offset_width != (win_width-font_width*term->cols)/2 ||
+ offset_height != (win_height-font_height*term->rows)/2) ){
+ offset_width = (win_width-font_width*term->cols)/2;
+ offset_height = (win_height-font_height*term->rows)/2;
+ InvalidateRect(hwnd, NULL, TRUE);
+#ifdef RDB_DEBUG_PATCH
+ debug((27, "reset_window() -> Reposition terminal"));
+#endif
+ }
+
+ if (IsZoomed(hwnd)) {
+ /* We're fullscreen, this means we must not change the size of
+ * the window so it's the font size or the terminal itself.
+ */
+
+ extra_width = wr.right - wr.left - cr.right + cr.left;
+ extra_height = wr.bottom - wr.top - cr.bottom + cr.top;
+
+ if (cfg.resize_action != RESIZE_TERM) {
+ if ( font_width != win_width/term->cols ||
+ font_height != win_height/term->rows) {
+ deinit_fonts();
+ init_fonts(win_width/term->cols, win_height/term->rows);
+ offset_width = (win_width-font_width*term->cols)/2;
+ offset_height = (win_height-font_height*term->rows)/2;
+ InvalidateRect(hwnd, NULL, TRUE);
+#ifdef RDB_DEBUG_PATCH
+ debug((25, "reset_window() -> Z font resize to (%d, %d)",
+ font_width, font_height));
+#endif
+ }
+ } else {
+ if ( font_width != win_width/term->cols ||
+ font_height != win_height/term->rows) {
+ /* Our only choice at this point is to change the
+ * size of the terminal; Oh well.
+ */
+ term_size(term, win_height/font_height, win_width/font_width,
+ cfg.savelines);
+ offset_width = (win_width-font_width*term->cols)/2;
+ offset_height = (win_height-font_height*term->rows)/2;
+ InvalidateRect(hwnd, NULL, TRUE);
+#ifdef RDB_DEBUG_PATCH
+ debug((27, "reset_window() -> Zoomed term_size"));
+#endif
+ }
+ }
+ return;
+ }
+
+ /* Hmm, a force re-init means we should ignore the current window
+ * so we resize to the default font size.
+ */
+ if (reinit>0) {
+#ifdef RDB_DEBUG_PATCH
+ debug((27, "reset_window() -> Forced re-init"));
+#endif
+
+ 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;
+
+ if (win_width != font_width*term->cols + offset_width*2 ||
+ win_height != font_height*term->rows + offset_height*2) {
+
+ /* If this is too large windows will resize it to the maximum
+ * allowed window size, we will then be back in here and resize
+ * the font or terminal to fit.
+ */
+ SetWindowPos(hwnd, NULL, 0, 0,
+ font_width*term->cols + extra_width,
+ font_height*term->rows + extra_height,
+ SWP_NOMOVE | SWP_NOZORDER);
+ }
+
+ InvalidateRect(hwnd, NULL, TRUE);
+ return;
+ }
+
+ /* Okay the user doesn't want us to change the font so we try the
+ * window. But that may be too big for the screen which forces us
+ * to change the terminal.
+ */
+ if ((cfg.resize_action == RESIZE_TERM && reinit<=0) ||
+ (cfg.resize_action == RESIZE_EITHER && 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;
+
+ if (win_width != font_width*term->cols + offset_width*2 ||
+ win_height != font_height*term->rows + offset_height*2) {
+
+ static RECT ss;
+ int width, height;
+
+ get_fullscreen_rect(&ss);
+
+ width = (ss.right - ss.left - extra_width) / font_width;
+ height = (ss.bottom - ss.top - extra_height) / font_height;
+
+ /* Grrr too big */
+ if ( term->rows > height || term->cols > width ) {
+ if (cfg.resize_action == RESIZE_EITHER) {
+ /* Make the font the biggest we can */
+ if (term->cols > width)
+ font_width = (ss.right - ss.left - extra_width)
+ / term->cols;
+ if (term->rows > height)
+ font_height = (ss.bottom - ss.top - extra_height)
+ / term->rows;
+
+ deinit_fonts();
+ init_fonts(font_width, font_height);
+
+ width = (ss.right - ss.left - extra_width) / font_width;
+ height = (ss.bottom - ss.top - extra_height) / font_height;
+ } else {
+ if ( height > term->rows ) height = term->rows;
+ if ( width > term->cols ) width = term->cols;
+ term_size(term, height, width, cfg.savelines);
+#ifdef RDB_DEBUG_PATCH
+ debug((27, "reset_window() -> term resize to (%d,%d)",
+ height, width));
+#endif
+ }
+ }
+
+ SetWindowPos(hwnd, NULL, 0, 0,
+ font_width*term->cols + extra_width,
+ font_height*term->rows + extra_height,
+ SWP_NOMOVE | SWP_NOZORDER);
+
+ InvalidateRect(hwnd, NULL, TRUE);
+#ifdef RDB_DEBUG_PATCH
+ debug((27, "reset_window() -> window resize to (%d,%d)",
+ font_width*term->cols + extra_width,
+ font_height*term->rows + extra_height));
+#endif
+ }
+ return;
+ }
+
+ /* We're allowed to or must change the font but do we want to ? */
+
+ if (font_width != (win_width-cfg.window_border*2)/term->cols ||
+ font_height != (win_height-cfg.window_border*2)/term->rows) {
+
+ deinit_fonts();
+ init_fonts((win_width-cfg.window_border*2)/term->cols,
+ (win_height-cfg.window_border*2)/term->rows);
+ offset_width = (win_width-font_width*term->cols)/2;
+ offset_height = (win_height-font_height*term->rows)/2;
+
+ 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;
+
+ InvalidateRect(hwnd, NULL, TRUE);
+#ifdef RDB_DEBUG_PATCH
+ debug((25, "reset_window() -> font resize to (%d,%d)",
+ font_width, font_height));
+#endif
+ }
+}
+
+static void set_input_locale(HKL kl)
+{
+ char lbuf[20];
+
+ GetLocaleInfo(LOWORD(kl), LOCALE_IDEFAULTANSICODEPAGE,
+ lbuf, sizeof(lbuf));
+
+ kbd_codepage = atoi(lbuf);
+}
+
+static void click(Mouse_Button b, int x, int y, int shift, int ctrl, int alt)
+{
+ int thistime = GetMessageTime();
+
+ if (send_raw_mouse && !(cfg.mouse_override && shift)) {
+ lastbtn = MBT_NOTHING;
+ term_mouse(term, b, translate_button(b), MA_CLICK,
+ x, y, shift, ctrl, alt);
+ return;
+ }
+
+ if (lastbtn == b && thistime - lasttime < dbltime) {
+ lastact = (lastact == MA_CLICK ? MA_2CLK :
+ lastact == MA_2CLK ? MA_3CLK :
+ lastact == MA_3CLK ? MA_CLICK : MA_NOTHING);
+ } else {
+ lastbtn = b;
+ lastact = MA_CLICK;
+ }
+ if (lastact != MA_NOTHING)
+ term_mouse(term, b, translate_button(b), lastact,
+ x, y, shift, ctrl, alt);
+ lasttime = thistime;
+}
+
+/*
+ * Translate a raw mouse button designation (LEFT, MIDDLE, RIGHT)
+ * into a cooked one (SELECT, EXTEND, PASTE).
+ */
+static Mouse_Button translate_button(Mouse_Button button)
+{
+ if (button == MBT_LEFT)
+ return MBT_SELECT;
+ if (button == MBT_MIDDLE)
+ return cfg.mouse_is_xterm == 1 ? MBT_PASTE : MBT_EXTEND;
+ if (button == MBT_RIGHT)
+ return cfg.mouse_is_xterm == 1 ? MBT_EXTEND : MBT_PASTE;
+ return 0; /* shouldn't happen */
+}
+
+static void show_mouseptr(int show)
+{
+ static int cursor_visible = 1;
+ if (!cfg.hide_mouseptr) /* override if this feature disabled */
+ show = 1;
+ if (cursor_visible && !show)
+ ShowCursor(FALSE);
+ else if (!cursor_visible && show)
+ ShowCursor(TRUE);
+ cursor_visible = show;
+}
+
+static int is_alt_pressed(void)
+{
+ BYTE keystate[256];
+ int r = GetKeyboardState(keystate);
+ if (!r)
+ return FALSE;
+ if (keystate[VK_MENU] & 0x80)
+ return TRUE;
+ if (keystate[VK_RMENU] & 0x80)
+ return TRUE;
+ return FALSE;
+}
+
+static int is_shift_pressed(void)
+{
+ BYTE keystate[256];
+ int r = GetKeyboardState(keystate);
+ if (!r)
+ return FALSE;
+ if (keystate[VK_SHIFT] & 0x80)
+ return TRUE;
+ return FALSE;
+}
+
+static int resizing;
+
+static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
+ WPARAM wParam, LPARAM lParam)
+{
+ HDC hdc;
+ static int ignore_clip = FALSE;
+ static int need_backend_resize = FALSE;
+ static int fullscr_on_max = FALSE;
+ static UINT last_mousemove = 0;
+
+ switch (message) {
+ case WM_TIMER:
+ if (pending_netevent)
+ enact_pending_netevent();
+ if (GetCapture() != hwnd ||
+ (send_raw_mouse && !(cfg.mouse_override && is_shift_pressed())))
+ term_out(term);
+ noise_regular();
+ HideCaret(hwnd);
+ term_update(term);
+ ShowCaret(hwnd);
+ if (cfg.ping_interval > 0) {
+ time_t now;
+ time(&now);
+ if (now - last_movement > cfg.ping_interval) {
+ if (back)
+ back->special(backhandle, TS_PING);
+ last_movement = now;
+ }
+ }
+ net_pending_errors();
+ return 0;
+ case WM_CREATE:
+ break;
+ case WM_CLOSE:
+ {
+ char *str;
+ show_mouseptr(1);
+ str = dupprintf("%s Exit Confirmation", appname);
+ if (!cfg.warn_on_close || session_closed ||
+ MessageBox(hwnd,
+ "Are you sure you want to close this session?",
+ str, MB_ICONWARNING | MB_OKCANCEL) == IDOK)
+ DestroyWindow(hwnd);
+ sfree(str);
+ }
+ return 0;
+ case WM_DESTROY:
+ show_mouseptr(1);
+ PostQuitMessage(0);
+ return 0;
+ case WM_COMMAND:
+ case WM_SYSCOMMAND:
+ switch (wParam & ~0xF) { /* low 4 bits reserved to Windows */
+ case IDM_SHOWLOG:
+ showeventlog(hwnd);
+ break;
+ case IDM_NEWSESS:
+ case IDM_DUPSESS:
+ case IDM_SAVEDSESS:
+ {
+ char b[2048];
+ char c[30], *cl;
+ int freecl = FALSE;
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+ HANDLE filemap = NULL;
+
+ if (wParam == IDM_DUPSESS) {
+ /*
+ * Allocate a file-mapping memory chunk for the
+ * config structure.
+ */
+ SECURITY_ATTRIBUTES sa;
+ Config *p;
+
+ sa.nLength = sizeof(sa);
+ sa.lpSecurityDescriptor = NULL;
+ sa.bInheritHandle = TRUE;
+ filemap = CreateFileMapping((HANDLE) 0xFFFFFFFF,
+ &sa,
+ PAGE_READWRITE,
+ 0, sizeof(Config), NULL);
+ if (filemap) {
+ p = (Config *) MapViewOfFile(filemap,
+ FILE_MAP_WRITE,
+ 0, 0, sizeof(Config));
+ if (p) {
+ *p = cfg; /* structure copy */
+ UnmapViewOfFile(p);
+ }
+ }
+ sprintf(c, "putty &%p", filemap);
+ cl = c;
+ } else if (wParam == IDM_SAVEDSESS) {
+ if ((lParam - IDM_SAVED_MIN) / 16 < sesslist.nsessions) {
+ char *session =
+ sesslist.sessions[(lParam - IDM_SAVED_MIN) / 16];
+ cl = snewn(16 + strlen(session), char);
+ /* 8, but play safe */
+ if (!cl)
+ cl = NULL;
+ /* not a very important failure mode */
+ else {
+ sprintf(cl, "putty @%s", session);
+ freecl = TRUE;
+ }
+ } else
+ break;
+ } else
+ cl = NULL;
+
+ GetModuleFileName(NULL, b, sizeof(b) - 1);
+ si.cb = sizeof(si);
+ si.lpReserved = NULL;
+ si.lpDesktop = NULL;
+ si.lpTitle = NULL;
+ si.dwFlags = 0;
+ si.cbReserved2 = 0;
+ si.lpReserved2 = NULL;
+ CreateProcess(b, cl, NULL, NULL, TRUE,
+ NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi);
+
+ if (filemap)
+ CloseHandle(filemap);
+ if (freecl)
+ sfree(cl);
+ }
+ break;
+ case IDM_RESTART:
+ if (!back) {
+ logevent(NULL, "----- Session restarted -----");
+ start_backend();
+ }
+
+ break;
+ case IDM_RECONF:
+ {
+ Config prev_cfg;
+ int init_lvl = 1;
+
+ GetWindowText(hwnd, cfg.wintitle, sizeof(cfg.wintitle));
+ prev_cfg = cfg;
+
+ if (!do_reconfig(hwnd))
+ break;
+
+ {
+ /* Disable full-screen if resizing forbidden */
+ HMENU m = GetSystemMenu (hwnd, FALSE);
+ EnableMenuItem(m, IDM_FULLSCREEN, MF_BYCOMMAND |
+ (cfg.resize_action == RESIZE_DISABLED)
+ ? MF_GRAYED : MF_ENABLED);
+ /* Gracefully unzoom if necessary */
+ if (IsZoomed(hwnd) &&
+ (cfg.resize_action == RESIZE_DISABLED)) {
+ ShowWindow(hwnd, SW_RESTORE);
+ }
+ }
+
+ /* Pass new config data to the logging module */
+ log_reconfig(logctx, &cfg);
+
+ sfree(logpal);
+ /*
+ * Flush the line discipline's edit buffer in the
+ * case where local editing has just been disabled.
+ */
+ if (ldisc)
+ ldisc_send(ldisc, NULL, 0, 0);
+ if (pal)
+ DeleteObject(pal);
+ logpal = NULL;
+ pal = NULL;
+ cfgtopalette();
+ init_palette();
+
+ /* Pass new config data to the terminal */
+ term_reconfig(term, &cfg);
+
+ /* Pass new config data to the back end */
+ if (back)
+ back->reconfig(backhandle, &cfg);
+
+ /* Screen size changed ? */
+ if (cfg.height != prev_cfg.height ||
+ cfg.width != prev_cfg.width ||
+ cfg.savelines != prev_cfg.savelines ||
+ cfg.resize_action == RESIZE_FONT ||
+ (cfg.resize_action == RESIZE_EITHER && IsZoomed(hwnd)) ||
+ cfg.resize_action == RESIZE_DISABLED)
+ term_size(term, cfg.height, cfg.width, cfg.savelines);
+
+ /* Enable or disable the scroll bar, etc */
+ {
+ LONG nflg, flag = GetWindowLong(hwnd, GWL_STYLE);
+ LONG nexflag, exflag =
+ GetWindowLong(hwnd, GWL_EXSTYLE);
+
+ nexflag = exflag;
+ if (cfg.alwaysontop != prev_cfg.alwaysontop) {
+ if (cfg.alwaysontop) {
+ nexflag |= WS_EX_TOPMOST;
+ SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0,
+ SWP_NOMOVE | SWP_NOSIZE);
+ } else {
+ nexflag &= ~(WS_EX_TOPMOST);
+ SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0,
+ SWP_NOMOVE | SWP_NOSIZE);
+ }
+ }
+ if (cfg.sunken_edge)
+ nexflag |= WS_EX_CLIENTEDGE;
+ else
+ nexflag &= ~(WS_EX_CLIENTEDGE);
+
+ nflg = flag;
+ if (is_full_screen() ?
+ cfg.scrollbar_in_fullscreen : cfg.scrollbar)
+ nflg |= WS_VSCROLL;
+ else
+ nflg &= ~WS_VSCROLL;
+
+ if (cfg.resize_action == RESIZE_DISABLED ||
+ is_full_screen())
+ nflg &= ~WS_THICKFRAME;
+ else
+ nflg |= WS_THICKFRAME;
+
+ if (cfg.resize_action == RESIZE_DISABLED)
+ nflg &= ~WS_MAXIMIZEBOX;
+ else
+ nflg |= WS_MAXIMIZEBOX;
+
+ if (nflg != flag || nexflag != exflag) {
+ if (nflg != flag)
+ SetWindowLong(hwnd, GWL_STYLE, nflg);
+ if (nexflag != exflag)
+ SetWindowLong(hwnd, GWL_EXSTYLE, nexflag);
+
+ SetWindowPos(hwnd, NULL, 0, 0, 0, 0,
+ SWP_NOACTIVATE | SWP_NOCOPYBITS |
+ SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
+ SWP_FRAMECHANGED);
+
+ init_lvl = 2;
+ }
+ }
+
+ /* Oops */
+ if (cfg.resize_action == RESIZE_DISABLED && IsZoomed(hwnd)) {
+ force_normal(hwnd);
+ init_lvl = 2;
+ }
+
+ set_title(NULL, cfg.wintitle);
+ if (IsIconic(hwnd)) {
+ SetWindowText(hwnd,
+ cfg.win_name_always ? window_name :
+ icon_name);
+ }
+
+ if (strcmp(cfg.font.name, prev_cfg.font.name) != 0 ||
+ strcmp(cfg.line_codepage, prev_cfg.line_codepage) != 0 ||
+ cfg.font.isbold != prev_cfg.font.isbold ||
+ cfg.font.height != prev_cfg.font.height ||
+ cfg.font.charset != prev_cfg.font.charset ||
+ cfg.vtmode != prev_cfg.vtmode ||
+ cfg.bold_colour != prev_cfg.bold_colour ||
+ cfg.resize_action == RESIZE_DISABLED ||
+ cfg.resize_action == RESIZE_EITHER ||
+ (cfg.resize_action != prev_cfg.resize_action))
+ init_lvl = 2;
+
+ InvalidateRect(hwnd, NULL, TRUE);
+ reset_window(init_lvl);
+ net_pending_errors();
+ }
+ break;
+ case IDM_COPYALL:
+ term_copyall(term);
+ break;
+ case IDM_PASTE:
+ term_do_paste(term);
+ break;
+ case IDM_CLRSB:
+ term_clrsb(term);
+ break;
+ case IDM_RESET:
+ term_pwron(term);
+ if (ldisc)
+ ldisc_send(ldisc, NULL, 0, 0);
+ break;
+ case IDM_ABOUT:
+ showabout(hwnd);
+ break;
+ case IDM_HELP:
+ WinHelp(hwnd, help_path,
+ help_has_contents ? HELP_FINDER : HELP_CONTENTS, 0);
+ break;
+ case SC_MOUSEMENU:
+ /*
+ * We get this if the System menu has been activated
+ * using the mouse.
+ */
+ show_mouseptr(1);
+ break;
+ case SC_KEYMENU:
+ /*
+ * We get this if the System menu has been activated
+ * using the keyboard. This might happen from within
+ * TranslateKey, in which case it really wants to be
+ * followed by a `space' character to actually _bring
+ * the menu up_ rather than just sitting there in
+ * `ready to appear' state.
+ */
+ show_mouseptr(1); /* make sure pointer is visible */
+ 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);
+ }
+ if (wParam >= IDM_SPECIAL_MIN && wParam <= IDM_SPECIAL_MAX) {
+ int i = (wParam - IDM_SPECIAL_MIN) / 0x10;
+ /*
+ * Ensure we haven't been sent a bogus SYSCOMMAND
+ * which would cause us to reference invalid memory
+ * and crash. Perhaps I'm just too paranoid here.
+ */
+ if (i >= n_specials)
+ break;
+ if (back)
+ back->special(backhandle, specials[i].code);
+ net_pending_errors();
+ }
+ }
+ break;
+
+#define X_POS(l) ((int)(short)LOWORD(l))
+#define Y_POS(l) ((int)(short)HIWORD(l))
+
+#define TO_CHR_X(x) ((((x)<0 ? (x)-font_width+1 : (x))-offset_width) / font_width)
+#define TO_CHR_Y(y) ((((y)<0 ? (y)-font_height+1: (y))-offset_height) / font_height)
+ case WM_LBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ case WM_LBUTTONUP:
+ case WM_MBUTTONUP:
+ case WM_RBUTTONUP:
+ if (message == WM_RBUTTONDOWN &&
+ ((wParam & MK_CONTROL) || (cfg.mouse_is_xterm == 2))) {
+ POINT cursorpos;
+
+ show_mouseptr(1); /* make sure pointer is visible */
+ GetCursorPos(&cursorpos);
+ TrackPopupMenu(popup_menus[CTXMENU].menu,
+ TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RIGHTBUTTON,
+ cursorpos.x, cursorpos.y,
+ 0, hwnd, NULL);
+ break;
+ }
+ {
+ int button, press;
+
+ switch (message) {
+ case WM_LBUTTONDOWN:
+ button = MBT_LEFT;
+ press = 1;
+ break;
+ case WM_MBUTTONDOWN:
+ button = MBT_MIDDLE;
+ press = 1;
+ break;
+ case WM_RBUTTONDOWN:
+ button = MBT_RIGHT;
+ press = 1;
+ break;
+ case WM_LBUTTONUP:
+ button = MBT_LEFT;
+ press = 0;
+ break;
+ case WM_MBUTTONUP:
+ button = MBT_MIDDLE;
+ press = 0;
+ break;
+ case WM_RBUTTONUP:
+ button = MBT_RIGHT;
+ press = 0;
+ break;
+ default:
+ button = press = 0; /* shouldn't happen */
+ }
+ show_mouseptr(1);
+ /*
+ * Special case: in full-screen mode, if the left
+ * button is clicked in the very top left corner of the
+ * window, we put up the System menu instead of doing
+ * selection.
+ */
+ {
+ char mouse_on_hotspot = 0;
+ POINT pt;
+
+ GetCursorPos(&pt);
+#ifndef NO_MULTIMON
+ {
+ HMONITOR mon;
+ MONITORINFO mi;
+
+ mon = MonitorFromPoint(pt, MONITOR_DEFAULTTONULL);
+
+ if (mon != NULL) {
+ mi.cbSize = sizeof(MONITORINFO);
+ GetMonitorInfo(mon, &mi);
+
+ if (mi.rcMonitor.left == pt.x &&
+ mi.rcMonitor.top == pt.y) {
+ mouse_on_hotspot = 1;
+ }
+ }
+ }
+#else
+ if (pt.x == 0 && pt.y == 0) {
+ mouse_on_hotspot = 1;
+ }
+#endif
+ if (is_full_screen() && press &&
+ button == MBT_LEFT && mouse_on_hotspot) {
+ SendMessage(hwnd, WM_SYSCOMMAND, SC_MOUSEMENU,
+ MAKELPARAM(pt.x, pt.y));
+ return 0;
+ }
+ }
+
+ if (press) {
+ click(button,
+ TO_CHR_X(X_POS(lParam)), TO_CHR_Y(Y_POS(lParam)),
+ wParam & MK_SHIFT, wParam & MK_CONTROL,
+ is_alt_pressed());
+ SetCapture(hwnd);
+ } else {
+ term_mouse(term, button, translate_button(button), MA_RELEASE,
+ TO_CHR_X(X_POS(lParam)),
+ TO_CHR_Y(Y_POS(lParam)), wParam & MK_SHIFT,
+ wParam & MK_CONTROL, is_alt_pressed());
+ ReleaseCapture();
+ }
+ }
+ return 0;
+ case WM_MOUSEMOVE:
+ {
+ /*
+ * Windows seems to like to occasionally send MOUSEMOVE
+ * events even if the mouse hasn't moved. Don't unhide
+ * the mouse pointer in this case.
+ */
+ static WPARAM wp = 0;
+ static LPARAM lp = 0;
+ if (wParam != wp || lParam != lp ||
+ last_mousemove != WM_MOUSEMOVE) {
+ show_mouseptr(1);
+ wp = wParam; lp = lParam;
+ last_mousemove = WM_MOUSEMOVE;
+ }
+ }
+ /*
+ * Add the mouse position and message time to the random
+ * number noise.
+ */
+ noise_ultralight(lParam);
+
+ if (wParam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON) &&
+ GetCapture() == hwnd) {
+ Mouse_Button b;
+ if (wParam & MK_LBUTTON)
+ b = MBT_LEFT;
+ else if (wParam & MK_MBUTTON)
+ b = MBT_MIDDLE;
+ else
+ b = MBT_RIGHT;
+ term_mouse(term, b, translate_button(b), MA_DRAG,
+ TO_CHR_X(X_POS(lParam)),
+ TO_CHR_Y(Y_POS(lParam)), wParam & MK_SHIFT,
+ wParam & MK_CONTROL, is_alt_pressed());
+ }
+ return 0;
+ case WM_NCMOUSEMOVE:
+ {
+ static WPARAM wp = 0;
+ static LPARAM lp = 0;
+ if (wParam != wp || lParam != lp ||
+ last_mousemove != WM_NCMOUSEMOVE) {
+ show_mouseptr(1);
+ wp = wParam; lp = lParam;
+ last_mousemove = WM_NCMOUSEMOVE;
+ }
+ }
+ noise_ultralight(lParam);
+ break;
+ case WM_IGNORE_CLIP:
+ ignore_clip = wParam; /* don't panic on DESTROYCLIPBOARD */
+ break;
+ case WM_DESTROYCLIPBOARD:
+ if (!ignore_clip)
+ term_deselect(term);
+ ignore_clip = FALSE;
+ return 0;
+ case WM_PAINT:
+ {
+ PAINTSTRUCT p;
+ HideCaret(hwnd);
+ hdc = BeginPaint(hwnd, &p);
+ if (pal) {
+ SelectPalette(hdc, pal, TRUE);
+ RealizePalette(hdc);
+ }
+ 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,
+ is_alt_pressed());
+
+ if (p.fErase ||
+ p.rcPaint.left < offset_width ||
+ p.rcPaint.top < offset_height ||
+ p.rcPaint.right >= offset_width + font_width*term->cols ||
+ p.rcPaint.bottom>= offset_height + font_height*term->rows)
+ {
+ HBRUSH fillcolour, oldbrush;
+ HPEN edge, oldpen;
+ fillcolour = CreateSolidBrush (
+ colours[(ATTR_DEFBG>>ATTR_BGSHIFT)*2]);
+ oldbrush = SelectObject(hdc, fillcolour);
+ edge = CreatePen(PS_SOLID, 0,
+ colours[(ATTR_DEFBG>>ATTR_BGSHIFT)*2]);
+ oldpen = SelectObject(hdc, edge);
+
+ /*
+ * Jordan Russell reports that this apparently
+ * ineffectual IntersectClipRect() call masks a
+ * Windows NT/2K bug causing strange display
+ * problems when the PuTTY window is taller than
+ * the primary monitor. It seems harmless enough...
+ */
+ IntersectClipRect(hdc,
+ p.rcPaint.left, p.rcPaint.top,
+ p.rcPaint.right, p.rcPaint.bottom);
+
+ ExcludeClipRect(hdc,
+ offset_width, offset_height,
+ offset_width+font_width*term->cols,
+ offset_height+font_height*term->rows);
+
+ Rectangle(hdc, p.rcPaint.left, p.rcPaint.top,
+ p.rcPaint.right, p.rcPaint.bottom);
+
+ // SelectClipRgn(hdc, NULL);
+
+ SelectObject(hdc, oldbrush);
+ DeleteObject(fillcolour);
+ SelectObject(hdc, oldpen);
+ DeleteObject(edge);
+ }
+ SelectObject(hdc, GetStockObject(SYSTEM_FONT));
+ SelectObject(hdc, GetStockObject(WHITE_PEN));
+ EndPaint(hwnd, &p);
+ ShowCaret(hwnd);
+ }
+ return 0;
+ case WM_NETEVENT:
+ /* Notice we can get multiple netevents, FD_READ, FD_WRITE etc
+ * but the only one that's likely to try to overload us is FD_READ.
+ * This means buffering just one is fine.
+ */
+ if (pending_netevent)
+ enact_pending_netevent();
+
+ pending_netevent = TRUE;
+ pend_netevent_wParam = wParam;
+ pend_netevent_lParam = lParam;
+ if (WSAGETSELECTEVENT(lParam) != FD_READ)
+ enact_pending_netevent();
+
+ time(&last_movement);
+ return 0;
+ case WM_SETFOCUS:
+ term->has_focus = TRUE;
+ CreateCaret(hwnd, caretbm, font_width, font_height);
+ ShowCaret(hwnd);
+ flash_window(0); /* stop */
+ compose_state = 0;
+ term_out(term);
+ term_update(term);
+ break;
+ case WM_KILLFOCUS:
+ show_mouseptr(1);
+ term->has_focus = FALSE;
+ DestroyCaret();
+ caret_x = caret_y = -1; /* ensure caret is replaced next time */
+ term_out(term);
+ term_update(term);
+ break;
+ case WM_ENTERSIZEMOVE:
+#ifdef RDB_DEBUG_PATCH
+ debug((27, "WM_ENTERSIZEMOVE"));
+#endif
+ EnableSizeTip(1);
+ resizing = TRUE;
+ need_backend_resize = FALSE;
+ break;
+ case WM_EXITSIZEMOVE:
+ EnableSizeTip(0);
+ resizing = FALSE;
+#ifdef RDB_DEBUG_PATCH
+ debug((27, "WM_EXITSIZEMOVE"));
+#endif
+ if (need_backend_resize) {
+ term_size(term, cfg.height, cfg.width, cfg.savelines);
+ InvalidateRect(hwnd, NULL, TRUE);
+ }
+ break;
+ case WM_SIZING:
+ /*
+ * This does two jobs:
+ * 1) Keep the sizetip uptodate
+ * 2) Make sure the window size is _stepped_ in units of the font size.
+ */
+ if (cfg.resize_action != RESIZE_FONT && !is_alt_pressed()) {
+ int width, height, w, h, ew, eh;
+ LPRECT r = (LPRECT) lParam;
+
+ if ( !need_backend_resize && cfg.resize_action == RESIZE_EITHER &&
+ (cfg.height != term->rows || cfg.width != term->cols )) {
+ /*
+ * Great! It seems that both the terminal size and the
+ * font size have been changed and the user is now dragging.
+ *
+ * It will now be difficult to get back to the configured
+ * font size!
+ *
+ * This would be easier but it seems to be too confusing.
+
+ term_size(term, cfg.height, cfg.width, cfg.savelines);
+ reset_window(2);
+ */
+ cfg.height=term->rows; cfg.width=term->cols;
+
+ InvalidateRect(hwnd, NULL, TRUE);
+ need_backend_resize = TRUE;
+ }
+
+ width = r->right - r->left - extra_width;
+ height = r->bottom - r->top - extra_height;
+ w = (width + font_width / 2) / font_width;
+ if (w < 1)
+ w = 1;
+ h = (height + font_height / 2) / font_height;
+ if (h < 1)
+ h = 1;
+ UpdateSizeTip(hwnd, w, h);
+ ew = width - w * font_width;
+ eh = height - h * font_height;
+ if (ew != 0) {
+ if (wParam == WMSZ_LEFT ||
+ wParam == WMSZ_BOTTOMLEFT || wParam == WMSZ_TOPLEFT)
+ r->left += ew;
+ else
+ r->right -= ew;
+ }
+ if (eh != 0) {
+ if (wParam == WMSZ_TOP ||
+ wParam == WMSZ_TOPRIGHT || wParam == WMSZ_TOPLEFT)
+ r->top += eh;
+ else
+ r->bottom -= eh;
+ }
+ if (ew || eh)
+ return 1;
+ else
+ return 0;
+ } else {
+ int width, height, w, h, rv = 0;
+ int ex_width = extra_width + (cfg.window_border - offset_width) * 2;
+ int ex_height = extra_height + (cfg.window_border - offset_height) * 2;
+ LPRECT r = (LPRECT) lParam;
+
+ width = r->right - r->left - ex_width;
+ height = r->bottom - r->top - ex_height;
+
+ w = (width + term->cols/2)/term->cols;
+ h = (height + term->rows/2)/term->rows;
+ if ( r->right != r->left + w*term->cols + ex_width)
+ rv = 1;
+
+ if (wParam == WMSZ_LEFT ||
+ wParam == WMSZ_BOTTOMLEFT || wParam == WMSZ_TOPLEFT)
+ r->left = r->right - w*term->cols - ex_width;
+ else
+ r->right = r->left + w*term->cols + ex_width;
+
+ if (r->bottom != r->top + h*term->rows + ex_height)
+ rv = 1;
+
+ if (wParam == WMSZ_TOP ||
+ wParam == WMSZ_TOPRIGHT || wParam == WMSZ_TOPLEFT)
+ r->top = r->bottom - h*term->rows - ex_height;
+ else
+ r->bottom = r->top + h*term->rows + ex_height;
+
+ return rv;
+ }
+ /* break; (never reached) */
+ case WM_FULLSCR_ON_MAX:
+ fullscr_on_max = TRUE;
+ break;
+ case WM_MOVE:
+ sys_cursor_update();
+ break;
+ case WM_SIZE:
+#ifdef RDB_DEBUG_PATCH
+ debug((27, "WM_SIZE %s (%d,%d)",
+ (wParam == SIZE_MINIMIZED) ? "SIZE_MINIMIZED":
+ (wParam == SIZE_MAXIMIZED) ? "SIZE_MAXIMIZED":
+ (wParam == SIZE_RESTORED && resizing) ? "to":
+ (wParam == SIZE_RESTORED) ? "SIZE_RESTORED":
+ "...",
+ LOWORD(lParam), HIWORD(lParam)));
+#endif
+ if (wParam == SIZE_MINIMIZED)
+ SetWindowText(hwnd,
+ cfg.win_name_always ? window_name : icon_name);
+ if (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED)
+ SetWindowText(hwnd, window_name);
+ if (wParam == SIZE_RESTORED)
+ clear_full_screen();
+ if (wParam == SIZE_MAXIMIZED && fullscr_on_max) {
+ fullscr_on_max = FALSE;
+ make_full_screen();
+ }
+
+ if (cfg.resize_action == RESIZE_DISABLED) {
+ /* A resize, well it better be a minimize. */
+ reset_window(-1);
+ } else {
+
+ int width, height, w, h;
+
+ width = LOWORD(lParam);
+ height = HIWORD(lParam);
+
+ if (!resizing) {
+ if (wParam == SIZE_MAXIMIZED && !was_zoomed) {
+ was_zoomed = 1;
+ prev_rows = term->rows;
+ prev_cols = term->cols;
+ if (cfg.resize_action == RESIZE_TERM) {
+ w = width / font_width;
+ if (w < 1) w = 1;
+ h = height / font_height;
+ if (h < 1) h = 1;
+
+ term_size(term, h, w, cfg.savelines);
+ }
+ reset_window(0);
+ } else if (wParam == SIZE_RESTORED && was_zoomed) {
+ was_zoomed = 0;
+ if (cfg.resize_action == RESIZE_TERM)
+ term_size(term, prev_rows, prev_cols, cfg.savelines);
+ if (cfg.resize_action != RESIZE_FONT)
+ reset_window(2);
+ else
+ reset_window(0);
+ }
+ /* This is an unexpected resize, these will normally happen
+ * if the window is too large. Probably either the user
+ * selected a huge font or the screen size has changed.
+ *
+ * This is also called with minimize.
+ */
+ else reset_window(-1);
+ }
+
+ /*
+ * Don't call back->size in mid-resize. (To prevent
+ * massive numbers of resize events getting sent
+ * down the connection during an NT opaque drag.)
+ */
+ if (resizing) {
+ if (cfg.resize_action != RESIZE_FONT && !is_alt_pressed()) {
+ need_backend_resize = TRUE;
+ w = (width-cfg.window_border*2) / font_width;
+ if (w < 1) w = 1;
+ h = (height-cfg.window_border*2) / font_height;
+ if (h < 1) h = 1;
+
+ cfg.height = h;
+ cfg.width = w;
+ } else
+ reset_window(0);
+ }
+ }
+ sys_cursor_update();
+ return 0;
+ case WM_VSCROLL:
+ switch (LOWORD(wParam)) {
+ case SB_BOTTOM:
+ term_scroll(term, -1, 0);
+ break;
+ case SB_TOP:
+ term_scroll(term, +1, 0);
+ break;
+ case SB_LINEDOWN:
+ term_scroll(term, 0, +1);
+ break;
+ case SB_LINEUP:
+ term_scroll(term, 0, -1);
+ break;
+ case SB_PAGEDOWN:
+ term_scroll(term, 0, +term->rows / 2);
+ break;
+ case SB_PAGEUP:
+ term_scroll(term, 0, -term->rows / 2);
+ break;
+ case SB_THUMBPOSITION:
+ case SB_THUMBTRACK:
+ term_scroll(term, 1, HIWORD(wParam));
+ break;
+ }
+ break;
+ case WM_PALETTECHANGED:
+ if ((HWND) wParam != hwnd && pal != NULL) {
+ HDC hdc = get_ctx(NULL);
+ if (hdc) {
+ if (RealizePalette(hdc) > 0)
+ UpdateColors(hdc);
+ free_ctx(hdc);
+ }
+ }
+ break;
+ case WM_QUERYNEWPALETTE:
+ if (pal != NULL) {
+ HDC hdc = get_ctx(NULL);
+ if (hdc) {
+ if (RealizePalette(hdc) > 0)
+ UpdateColors(hdc);
+ free_ctx(hdc);
+ return TRUE;
+ }
+ }
+ return FALSE;
+ case WM_KEYDOWN:
+ case WM_SYSKEYDOWN:
+ case WM_KEYUP:
+ case WM_SYSKEYUP:
+ /*
+ * Add the scan code and keypress timing to the random
+ * number noise.
+ */
+ noise_ultralight(lParam);