#endif
#endif
+#if WINVER < 0x0500
+#define COMPILE_MULTIMON_STUBS
+#include <multimon.h>
+#endif
+
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define IDM_TEL_SUSP 0x0110
#define IDM_TEL_EOR 0x0120
#define IDM_TEL_EOF 0x0130
-#define IDM_ABOUT 0x0140
-#define IDM_SAVEDSESS 0x0150
-#define IDM_COPYALL 0x0160
-#define IDM_FULLSCREEN 0x0170
+#define IDM_HELP 0x0140
+#define IDM_ABOUT 0x0150
+#define IDM_SAVEDSESS 0x0160
+#define IDM_COPYALL 0x0170
+#define IDM_FULLSCREEN 0x0180
#define IDM_SESSLGP 0x0250 /* log type printable */
#define IDM_SESSLGA 0x0260 /* log type all chars */
#define IDM_SAVED_MAX 0x2000
#define WM_IGNORE_CLIP (WM_XUSER + 2)
+#define WM_FULLSCR_ON_MAX (WM_XUSER + 3)
/* Needed for Chinese support and apparently not always defined. */
#ifndef VK_PROCESSKEY
#define VK_PROCESSKEY 0xE5
#endif
-/* Needed for mouse wheel support and not defined in earlier SDKs. */
+/* Mouse wheel support. */
#ifndef WM_MOUSEWHEEL
-#define WM_MOUSEWHEEL 0x020A
+#define WM_MOUSEWHEEL 0x020A /* not defined in earlier SDKs */
+#endif
+#ifndef WHEEL_DELTA
+#define WHEEL_DELTA 120
#endif
static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
static void another_font(int);
static void deinit_fonts(void);
static void set_input_locale(HKL);
+static int do_mouse_wheel_msg(UINT message, WPARAM wParam, LPARAM lParam);
+
+static int is_full_screen(void);
+static void make_full_screen(void);
+static void clear_full_screen(void);
+static void flip_full_screen(void);
/* Window layout information */
static void reset_window(int);
-static int full_screen = 0;
static int extra_width, extra_height;
static int font_width, font_height, font_dualwidth;
static int offset_width, offset_height;
static LPARAM pend_netevent_lParam = 0;
static void enact_pending_netevent(void);
static void flash_window(int mode);
-static void flip_full_screen(void);
static time_t last_movement = 0;
static OSVERSIONINFO osVersion;
+static UINT wm_mousewheel = WM_MOUSEWHEEL;
+
/* Dummy routine, only required in plink. */
void ldisc_update(int echo, int edit)
{
}
/*
+ * If we're running a version of Windows that doesn't support
+ * WM_MOUSEWHEEL, find out what message number we should be
+ * using instead.
+ */
+ if (osVersion.dwMajorVersion < 4 ||
+ (osVersion.dwMajorVersion == 4 &&
+ osVersion.dwPlatformId != VER_PLATFORM_WIN32_NT))
+ wm_mousewheel = RegisterWindowMessage("MSWHEEL_ROLLMSG");
+
+ /*
+ * See if we can find our Help file.
+ */
+ {
+ char b[2048], *p, *q, *r;
+ FILE *fp;
+ GetModuleFileName(NULL, b, sizeof(b) - 1);
+ r = b;
+ p = strrchr(b, '\\');
+ if (p && p >= r) r = p+1;
+ q = strrchr(b, ':');
+ if (q && q >= r) r = q+1;
+ strcpy(r, "putty.hlp");
+ if ( (fp = fopen(b, "r")) != NULL) {
+ help_path = dupstr(b);
+ fclose(fp);
+ } else
+ help_path = NULL;
+ strcpy(r, "putty.cnt");
+ if ( (fp = fopen(b, "r")) != NULL) {
+ help_has_contents = TRUE;
+ fclose(fp);
+ } else
+ help_has_contents = FALSE;
+ }
+
+ /*
* Process the command line.
*/
{
AppendMenu(m, (cfg.resize_action == RESIZE_DISABLED) ?
MF_GRAYED : MF_ENABLED, IDM_FULLSCREEN, "&Full Screen");
AppendMenu(m, MF_SEPARATOR, 0, 0);
+ if (help_path)
+ AppendMenu(m, MF_ENABLED, IDM_HELP, "&Help");
AppendMenu(m, MF_ENABLED, IDM_ABOUT, "&About PuTTY");
}
set_input_locale(GetKeyboardLayout(0));
/*
- * Finally show the window!
+ * Open the initial log file if there is one.
*/
- ShowWindow(hwnd, show);
- SetForegroundWindow(hwnd);
+ logfopen();
/*
- * Open the initial log file if there is one.
+ * Finally show the window!
*/
- logfopen();
+ ShowWindow(hwnd, show);
+ SetForegroundWindow(hwnd);
/*
* Set the palette up.
HDC hdc;
static int ignore_clip = FALSE;
static int need_backend_resize = FALSE;
+ static int fullscr_on_max = FALSE;
switch (message) {
case WM_TIMER:
sprintf(c, "putty &%p", filemap);
cl = c;
} else if (wParam == IDM_SAVEDSESS) {
- char *session =
- sessions[(lParam - IDM_SAVED_MIN) / 16];
- cl = smalloc(16 + strlen(session)); /* 8, but play safe */
- if (!cl)
- cl = NULL; /* not a very important failure mode */
- else {
- sprintf(cl, "putty @%s", session);
- freecl = TRUE;
- }
+ if ((lParam - IDM_SAVED_MIN) / 16 < nsessions) {
+ char *session =
+ sessions[(lParam - IDM_SAVED_MIN) / 16];
+ cl = smalloc(16 + strlen(session));
+ /* 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;
(cfg.resize_action == RESIZE_DISABLED)
? MF_GRAYED : MF_ENABLED);
/* Gracefully unzoom if necessary */
- if (full_screen &&
+ if (IsZoomed(hwnd) &&
(cfg.resize_action == RESIZE_DISABLED)) {
- flip_full_screen();
+ ShowWindow(hwnd, SW_RESTORE);
}
}
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(cfg.height, cfg.width, cfg.savelines);
nexflag &= ~(WS_EX_CLIENTEDGE);
nflg = flag;
- if (full_screen ?
+ 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_THICKFRAME | WS_MAXIMIZEBOX);
+ nflg &= ~WS_MAXIMIZEBOX;
else
- nflg |= (WS_THICKFRAME | WS_MAXIMIZEBOX);
+ nflg |= WS_MAXIMIZEBOX;
if (nflg != flag || nexflag != exflag) {
if (nflg != flag)
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
PostMessage(hwnd, WM_CHAR, ' ', 0);
break;
case IDM_FULLSCREEN:
- flip_full_screen();
- break;
+ flip_full_screen();
+ break;
default:
if (wParam >= IDM_SAVED_MIN && wParam <= IDM_SAVED_MAX) {
SendMessage(hwnd, WM_SYSCOMMAND, IDM_SAVEDSESS, wParam);
#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)
-#define WHEEL_DELTA 120
- case WM_MOUSEWHEEL:
- {
- wheel_accumulator += (short) HIWORD(wParam);
- wParam = LOWORD(wParam);
-
- /* process events when the threshold is reached */
- while (abs(wheel_accumulator) >= WHEEL_DELTA) {
- int b;
-
- /* reduce amount for next time */
- if (wheel_accumulator > 0) {
- b = MBT_WHEEL_UP;
- wheel_accumulator -= WHEEL_DELTA;
- } else if (wheel_accumulator < 0) {
- b = MBT_WHEEL_DOWN;
- wheel_accumulator += WHEEL_DELTA;
- } else
- break;
-
- if (send_raw_mouse) {
- /* send a mouse-down followed by a mouse up */
-
- term_mouse(b,
- MA_CLICK,
- TO_CHR_X(X_POS(lParam)),
- TO_CHR_Y(Y_POS(lParam)), wParam & MK_SHIFT,
- wParam & MK_CONTROL, is_alt_pressed());
- term_mouse(b, MA_RELEASE, TO_CHR_X(X_POS(lParam)),
- TO_CHR_Y(Y_POS(lParam)), wParam & MK_SHIFT,
- wParam & MK_CONTROL, is_alt_pressed());
- } else {
- /* trigger a scroll */
- term_scroll(0,
- b == MBT_WHEEL_UP ? -rows / 2 : rows / 2);
- }
- }
- return 0;
- }
case WM_LBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_RBUTTONDOWN:
* window, we put up the System menu instead of doing
* selection.
*/
- if (full_screen && press && button == MBT_LEFT &&
+ if (is_full_screen() && press && button == MBT_LEFT &&
X_POS(lParam) == 0 && Y_POS(lParam) == 0) {
SendMessage(hwnd, WM_SYSCOMMAND, SC_MOUSEMENU, 0);
return 0;
term_update();
break;
case WM_KILLFOCUS:
- if (full_screen) flip_full_screen();
show_mouseptr(1);
has_focus = FALSE;
DestroyCaret();
return rv;
}
/* break; (never reached) */
+ case WM_FULLSCR_ON_MAX:
+ fullscr_on_max = TRUE;
+ break;
case WM_SIZE:
#ifdef RDB_DEBUG_PATCH
debug((27, "WM_SIZE %s (%d,%d)",
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) {
+ make_full_screen();
+ fullscr_on_max = FALSE;
+ }
if (cfg.resize_action == RESIZE_DISABLED) {
/* A resize, well it better be a minimize. */
HIMC hIMC;
int n;
char *buff;
-
+
if(osVersion.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS ||
osVersion.dwPlatformId == VER_PLATFORM_WIN32s) break; /* no Unicode */
n = ImmGetCompositionStringW(hIMC, GCS_RESULTSTR, NULL, 0);
if (n > 0) {
+ int i;
buff = (char*) smalloc(n);
ImmGetCompositionStringW(hIMC, GCS_RESULTSTR, buff, n);
- luni_send((unsigned short *)buff, n / 2, 1);
+ /*
+ * Jaeyoun Chung reports that Korean character
+ * input doesn't work correctly if we do a single
+ * luni_send() covering the whole of buff. So
+ * instead we luni_send the characters one by one.
+ */
+ for (i = 0; i < n; i += 2)
+ luni_send((unsigned short *)(buff+i), 1, 1);
free(buff);
}
ImmReleaseContext(hwnd, hIMC);
SetCursor(LoadCursor(NULL, IDC_ARROW));
return TRUE;
}
+ default:
+ if (message == wm_mousewheel) {
+ int shift_pressed=0, control_pressed=0, alt_pressed=0;
+
+ if (message == WM_MOUSEWHEEL) {
+ wheel_accumulator += (short)HIWORD(wParam);
+ shift_pressed=LOWORD(wParam) & MK_SHIFT;
+ control_pressed=LOWORD(wParam) & MK_CONTROL;
+ } else {
+ BYTE keys[256];
+ wheel_accumulator += (int)wParam;
+ if (GetKeyboardState(keys)!=0) {
+ shift_pressed=keys[VK_SHIFT]&0x80;
+ control_pressed=keys[VK_CONTROL]&0x80;
+ }
+ }
+
+ /* process events when the threshold is reached */
+ while (abs(wheel_accumulator) >= WHEEL_DELTA) {
+ int b;
+
+ /* reduce amount for next time */
+ if (wheel_accumulator > 0) {
+ b = MBT_WHEEL_UP;
+ wheel_accumulator -= WHEEL_DELTA;
+ } else if (wheel_accumulator < 0) {
+ b = MBT_WHEEL_DOWN;
+ wheel_accumulator += WHEEL_DELTA;
+ } else
+ break;
+
+ if (send_raw_mouse &&
+ !(cfg.mouse_override && shift_pressed)) {
+ /* send a mouse-down followed by a mouse up */
+ term_mouse(b,
+ MA_CLICK,
+ TO_CHR_X(X_POS(lParam)),
+ TO_CHR_Y(Y_POS(lParam)), shift_pressed,
+ control_pressed, is_alt_pressed());
+ term_mouse(b, MA_RELEASE, TO_CHR_X(X_POS(lParam)),
+ TO_CHR_Y(Y_POS(lParam)), shift_pressed,
+ control_pressed, is_alt_pressed());
+ } else {
+ /* trigger a scroll */
+ term_scroll(0,
+ b == MBT_WHEEL_UP ? -rows / 2 : rows / 2);
+ }
+ }
+ return 0;
+ }
}
return DefWindowProc(hwnd, message, wParam, lParam);
p += sprintf((char *) p, "\x1B%c", xkey);
else {
int app_flg = (app_cursor_keys && !cfg.no_applic_c);
- /* VT100 & VT102 manuals both state the app cursor keys
- * only work if the app keypad is on.
+#if 0
+ /*
+ * RDB: VT100 & VT102 manuals both state the
+ * app cursor keys only work if the app keypad
+ * is on.
+ *
+ * SGT: That may well be true, but xterm
+ * disagrees and so does at least one
+ * application, so I've #if'ed this out and the
+ * behaviour is back to PuTTY's original: app
+ * cursor and app keypad are independently
+ * switchable modes. If anyone complains about
+ * _this_ I'll have to put in a configurable
+ * option.
*/
if (!app_keypad_keys)
app_flg = 0;
+#endif
/* Useful mapping of Ctrl-arrows */
if (shift_state == 2)
app_flg = !app_flg;
{
SCROLLINFO si;
- if ((full_screen && !cfg.scrollbar_in_fullscreen) ||
- (!full_screen && !cfg.scrollbar))
+ if (is_full_screen() ? !cfg.scrollbar_in_fullscreen : !cfg.scrollbar)
return;
si.cbSize = sizeof(si);
len * sizeof(wchar_t));
clipdata2 = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, len2);
- if (!clipdata || !clipdata2 || !clipdata3) {
+ if (!clipdata || !clipdata2) {
if (clipdata)
GlobalFree(clipdata);
if (clipdata2)
GlobalFree(clipdata2);
- if (clipdata3)
- GlobalFree(clipdata3);
return;
}
if (!(lock = GlobalLock(clipdata)))
}
/*
- * Toggle full screen mode. Thanks to cwis@nerim.fr for the
- * implementation.
- * Revised by <wez@thebrainroom.com>
- */
-static void flip_full_screen(void)
-{
- WINDOWPLACEMENT wp;
- LONG style;
-
- wp.length = sizeof(wp);
- GetWindowPlacement(hwnd, &wp);
-
- full_screen = !full_screen;
-
- if (full_screen) {
- if (wp.showCmd == SW_SHOWMAXIMIZED) {
- /* Ooops it was already 'zoomed' we have to unzoom it before
- * everything will work right.
- */
- wp.showCmd = SW_SHOWNORMAL;
- SetWindowPlacement(hwnd, &wp);
- }
-
- style = GetWindowLong(hwnd, GWL_STYLE) & ~(WS_CAPTION|WS_THICKFRAME);
- style &= ~WS_VSCROLL;
- if (cfg.scrollbar_in_fullscreen)
- style |= WS_VSCROLL;
- SetWindowLong(hwnd, GWL_STYLE, style);
-
- /* Some versions of explorer get confused and don't take
- * notice of us going fullscreen, so go topmost too.
- */
- SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0,
- SWP_NOACTIVATE | SWP_NOCOPYBITS |
- SWP_NOMOVE | SWP_NOSIZE |
- SWP_FRAMECHANGED);
-
- wp.showCmd = SW_SHOWMAXIMIZED;
- SetWindowPlacement(hwnd, &wp);
- } else {
- style = GetWindowLong(hwnd, GWL_STYLE) | WS_CAPTION;
- if (cfg.resize_action != RESIZE_DISABLED)
- style |= WS_THICKFRAME;
- style &= ~WS_VSCROLL;
- if (cfg.scrollbar)
- style |= WS_VSCROLL;
- SetWindowLong(hwnd, GWL_STYLE, style);
-
- SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0,
- SWP_NOACTIVATE | SWP_NOCOPYBITS |
- SWP_NOMOVE | SWP_NOSIZE |
- SWP_FRAMECHANGED);
-
- wp.showCmd = SW_SHOWNORMAL;
- SetWindowPlacement(hwnd, &wp);
- }
-
- CheckMenuItem(GetSystemMenu(hwnd, FALSE), IDM_FULLSCREEN,
- MF_BYCOMMAND| full_screen ? MF_CHECKED : MF_UNCHECKED);
-}
-
-/*
* Minimise or restore the window in response to a server-side
* request.
*/
*/
void set_zorder(int top)
{
- if (cfg.alwaysontop || full_screen)
+ if (cfg.alwaysontop)
return; /* ignore */
SetWindowPos(hwnd, top ? HWND_TOP : HWND_BOTTOM, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE);
*/
void set_zoomed(int zoomed)
{
- if (IsZoomed(hwnd) || full_screen) {
- if (!zoomed) {
- if (full_screen)
- flip_full_screen();
- else
- ShowWindow(hwnd, SW_RESTORE);
- }
+ if (IsZoomed(hwnd)) {
+ if (!zoomed)
+ ShowWindow(hwnd, SW_RESTORE);
} else {
if (zoomed)
ShowWindow(hwnd, SW_MAXIMIZE);
{
return icon ? icon_name : window_name;
}
+
+/*
+ * See if we're in full-screen mode.
+ */
+int is_full_screen()
+{
+ if (!IsZoomed(hwnd))
+ return FALSE;
+ if (GetWindowLong(hwnd, GWL_STYLE) & WS_CAPTION)
+ return FALSE;
+ return TRUE;
+}
+
+/*
+ * Go full-screen. This should only be called when we are already
+ * maximised.
+ */
+void make_full_screen()
+{
+ DWORD style;
+ int x, y, w, h;
+
+ assert(IsZoomed(hwnd));
+
+ /* Remove the window furniture. */
+ style = GetWindowLong(hwnd, GWL_STYLE);
+ style &= ~(WS_CAPTION | WS_BORDER | WS_THICKFRAME);
+ if (cfg.scrollbar_in_fullscreen)
+ style |= WS_VSCROLL;
+ else
+ style &= ~WS_VSCROLL;
+ SetWindowLong(hwnd, GWL_STYLE, style);
+
+ /* Resize ourselves to exactly cover the nearest monitor. */
+#ifdef MONITOR_DEFAULTTONEAREST
+ {
+ HMONITOR mon;
+ MONITORINFO mi;
+ mon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
+ mi.cbSize = sizeof(mi);
+ GetMonitorInfo(mon, &mi);
+ x = mi.rcMonitor.left;
+ y = mi.rcMonitor.top;
+ w = mi.rcMonitor.right;
+ h = mi.rcMonitor.bottom;
+ }
+#else
+ x = y = 0;
+ w = GetSystemMetrics(SM_CXSCREEN);
+ h = GetSystemMetrics(SM_CYSCREEN);
+#endif
+ SetWindowPos(hwnd, HWND_TOP, x, y, w, h, SWP_FRAMECHANGED);
+
+ /* Tick the menu item in the System menu. */
+ CheckMenuItem(GetSystemMenu(hwnd, FALSE), IDM_FULLSCREEN,
+ MF_CHECKED);
+}
+
+/*
+ * Clear the full-screen attributes.
+ */
+void clear_full_screen()
+{
+ DWORD oldstyle, style;
+
+ /* Reinstate the window furniture. */
+ style = oldstyle = GetWindowLong(hwnd, GWL_STYLE);
+ style |= WS_CAPTION | WS_BORDER;
+ if (cfg.resize_action == RESIZE_DISABLED)
+ style &= ~WS_THICKFRAME;
+ else
+ style |= WS_THICKFRAME;
+ if (cfg.scrollbar)
+ style |= WS_VSCROLL;
+ else
+ style &= ~WS_VSCROLL;
+ if (style != oldstyle) {
+ SetWindowLong(hwnd, GWL_STYLE, style);
+ SetWindowPos(hwnd, NULL, 0, 0, 0, 0,
+ SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
+ SWP_FRAMECHANGED);
+ }
+
+ /* Untick the menu item in the System menu. */
+ CheckMenuItem(GetSystemMenu(hwnd, FALSE), IDM_FULLSCREEN,
+ MF_UNCHECKED);
+}
+
+/*
+ * Toggle full-screen mode.
+ */
+void flip_full_screen()
+{
+ if (is_full_screen()) {
+ ShowWindow(hwnd, SW_RESTORE);
+ } else if (IsZoomed(hwnd)) {
+ make_full_screen();
+ } else {
+ SendMessage(hwnd, WM_FULLSCR_ON_MAX, 0, 0);
+ ShowWindow(hwnd, SW_MAXIMIZE);
+ }
+}