#include <limits.h>
#include <assert.h>
+#ifndef NO_MULTIMON
+#define COMPILE_MULTIMON_STUBS
+#endif
+
#define PUTTY_DO_GLOBALS /* actually _define_ globals */
#include "putty.h"
#include "terminal.h"
#include "win_res.h"
#ifndef NO_MULTIMON
-#if WINVER < 0x0500
-#define COMPILE_MULTIMON_STUBS
#include <multimon.h>
#endif
-#endif
#include <imm.h>
#include <commctrl.h>
static void deinit_fonts(void);
static void set_input_locale(HKL);
static void update_savedsess_menu(void);
+static void init_flashwindow(void);
static int is_full_screen(void);
static void make_full_screen(void);
static int was_zoomed = 0;
static int prev_rows, prev_cols;
-static void enact_netevent(WPARAM, LPARAM);
+static int pending_netevent = 0;
+static WPARAM pend_netevent_wParam = 0;
+static LPARAM pend_netevent_lParam = 0;
+static void enact_pending_netevent(void);
static void flash_window(int mode);
static void sys_cursor_update(void);
static int is_shift_pressed(void);
* Select protocol. This is farmed out into a table in a
* separate file to enable an ssh-free variant.
*/
- back = NULL;
- for (i = 0; backends[i].backend != NULL; i++)
- if (backends[i].protocol == cfg.protocol) {
- back = backends[i].backend;
- break;
- }
+ back = backend_from_proto(cfg.protocol);
if (back == NULL) {
char *str = dupprintf("%s Internal Error", appname);
MessageBox(NULL, "Unsupported protocol number found",
back->free(backhandle);
backhandle = NULL;
back = NULL;
+ term_provide_resize_fn(term, NULL, NULL);
update_specials_menu(NULL);
}
init_help();
+ init_flashwindow();
+
/*
* Process the command line.
*/
{
char *p;
int got_host = 0;
+ /* By default, we bring up the config dialog, rather than launching
+ * a session. This gets set to TRUE if something happens to change
+ * that (e.g., a hostname is specified on the command-line). */
+ int allow_launch = FALSE;
default_protocol = be_default_protocol;
/* Find the appropriate default port. */
{
- int i;
+ Backend *b = backend_from_proto(default_protocol);
default_port = 0; /* illegal */
- for (i = 0; backends[i].backend != NULL; i++)
- if (backends[i].protocol == default_protocol) {
- default_port = backends[i].backend->default_port;
- break;
- }
+ if (b)
+ default_port = b->default_port;
}
cfg.logtype = LGTYP_NONE;
if (!cfg_launchable(&cfg) && !do_config()) {
cleanup_exit(0);
}
+ allow_launch = TRUE; /* allow it to be launched directly */
} else if (*p == '&') {
/*
* An initial & means we've been given a command line
} else if (!do_config()) {
cleanup_exit(0);
}
+ allow_launch = TRUE;
} else {
/*
* Otherwise, break up the command line and deal with
cmdline_run_saved(&cfg);
- if (!cfg_launchable(&cfg) && !do_config()) {
+ if (loaded_session || got_host)
+ allow_launch = TRUE;
+
+ if ((!allow_launch || !cfg_launchable(&cfg)) && !do_config()) {
cleanup_exit(0);
}
}
}
- /* Check for invalid Port number (i.e. zero) */
- if (cfg.port == 0) {
- char *str = dupprintf("%s Internal Error", appname);
- MessageBox(NULL, "Invalid Port Number",
- str, MB_OK | MB_ICONEXCLAMATION);
- sfree(str);
- cleanup_exit(1);
- }
-
if (!prev) {
wndclass.style = 0;
wndclass.lpfnWndProc = WndProc;
sfree(handles);
if (must_close_session)
close_session();
- continue;
- }
-
- sfree(handles);
+ } else
+ sfree(handles);
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT)
/* The messages seem unreliable; especially if we're being tricky */
term_set_focus(term, GetForegroundWindow() == hwnd);
+ if (pending_netevent)
+ enact_pending_netevent();
+
net_pending_errors();
}
for (j = 0; j < lenof(popup_menus); j++) {
if (specials_menu) {
/* XXX does this free up all submenus? */
- DeleteMenu(popup_menus[j].menu, specials_menu, MF_BYCOMMAND);
+ DeleteMenu(popup_menus[j].menu, (UINT)specials_menu, MF_BYCOMMAND);
DeleteMenu(popup_menus[j].menu, IDM_SPECIALSEP, MF_BYCOMMAND);
}
if (new_menu) {
/*
* Actually do the job requested by a WM_NETEVENT
*/
-static void enact_netevent(WPARAM wParam, LPARAM lParam)
+static void enact_pending_netevent(void)
{
static int reentering = 0;
extern int select_result(WPARAM, LPARAM);
if (reentering)
return; /* don't unpend the pending */
+ pending_netevent = FALSE;
+
reentering = 1;
- select_result(wParam, lParam);
+ select_result(pend_netevent_wParam, pend_netevent_lParam);
reentering = 0;
}
gcpr.lStructSize = sizeof(gcpr);
gcpr.lpGlyphs = (void *)buffer;
- gcpr.lpClass = classbuffer;
+ gcpr.lpClass = (void *)classbuffer;
gcpr.nGlyphs = cbCount;
GetCharacterPlacementW(hdc, lpString, cbCount, 0, &gcpr,
xp = xn = x;
- for (i = 0; i < cbCount ;) {
+ for (i = 0; i < (int)cbCount ;) {
int rtl = is_rtl(lpString[i]);
xn += lpDx[i];
- for (j = i+1; j < cbCount; j++) {
+ for (j = i+1; j < (int)cbCount; j++) {
if (rtl != is_rtl(lpString[j]))
break;
xn += lpDx[j];
} else if (wParam == IDM_SAVEDSESS) {
unsigned int sessno = ((lParam - IDM_SAVED_MIN)
/ MENU_SAVED_STEP) + 1;
- if (sessno < sesslist.nsessions) {
+ if (sessno < (unsigned)sesslist.nsessions) {
char *session = sesslist.sessions[sessno];
/* XXX spaces? quotes? "-load"? */
cl = dupprintf("putty @%s", session);
}
return 0;
case WM_NETEVENT:
- enact_netevent(wParam, lParam);
+ /* 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();
+
net_pending_errors();
return 0;
case WM_SETFOCUS:
/*
* Translate a WM_(SYS)?KEY(UP|DOWN) message into a string of ASCII
- * codes. Returns number of bytes used or zero to drop the message
- * or -1 to forward the message to windows.
+ * codes. Returns number of bytes used, zero to drop the message,
+ * -1 to forward the message to Windows, or another negative number
+ * to indicate a NUL-terminated "special" string.
*/
static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
unsigned char *output)
return p - output;
}
if (wParam == VK_CANCEL && shift_state == 2) { /* Ctrl-Break */
- *p++ = 3;
- *p++ = 0;
- return -2;
+ if (back)
+ back->special(backhandle, TS_BRK);
+ return 0;
}
if (wParam == VK_PAUSE) { /* Break/Pause */
*p++ = 26;
*p++ = 0x1F;
return p - output;
}
- if (shift_state == 2 && wParam == 0xDF) {
+ if (shift_state == 2 && (wParam == 0xDF || wParam == 0xDC)) {
*p++ = 0x1C;
return p - output;
}
cleanup_exit(1);
}
+typedef BOOL (WINAPI *p_FlashWindowEx_t)(PFLASHWINFO);
+static p_FlashWindowEx_t p_FlashWindowEx = NULL;
+
+static void init_flashwindow(void)
+{
+ HMODULE user32_module = LoadLibrary("USER32.DLL");
+ if (user32_module) {
+ p_FlashWindowEx = (p_FlashWindowEx_t)
+ GetProcAddress(user32_module, "FlashWindowEx");
+ }
+}
+
+static BOOL flash_window_ex(DWORD dwFlags, UINT uCount, DWORD dwTimeout)
+{
+ if (p_FlashWindowEx) {
+ FLASHWINFO fi;
+ fi.cbSize = sizeof(fi);
+ fi.hwnd = hwnd;
+ fi.dwFlags = dwFlags;
+ fi.uCount = uCount;
+ fi.dwTimeout = dwTimeout;
+ return (*p_FlashWindowEx)(&fi);
+ }
+ else
+ return FALSE; /* shrug */
+}
+
static void flash_window(int mode);
static long next_flash;
static int flashing = 0;
+/*
+ * Timer for platforms where we must maintain window flashing manually
+ * (e.g., Win95).
+ */
static void flash_window_timer(void *ctx, long now)
{
if (flashing && now - next_flash >= 0) {
if ((mode == 0) || (cfg.beep_ind == B_IND_DISABLED)) {
/* stop */
if (flashing) {
- FlashWindow(hwnd, FALSE);
flashing = 0;
+ if (p_FlashWindowEx)
+ flash_window_ex(FLASHW_STOP, 0, 0);
+ else
+ FlashWindow(hwnd, FALSE);
}
} else if (mode == 2) {
/* start */
if (!flashing) {
flashing = 1;
- FlashWindow(hwnd, TRUE);
- next_flash = schedule_timer(450, flash_window_timer, hwnd);
+ if (p_FlashWindowEx) {
+ /* For so-called "steady" mode, we use uCount=2, which
+ * seems to be the traditional number of flashes used
+ * by user notifications (e.g., by Explorer).
+ * uCount=0 appears to enable continuous flashing, per
+ * "flashing" mode, although I haven't seen this
+ * documented. */
+ flash_window_ex(FLASHW_ALL | FLASHW_TIMER,
+ (cfg.beep_ind == B_IND_FLASH ? 0 : 2),
+ 0 /* system cursor blink rate */);
+ /* No need to schedule timer */
+ } else {
+ FlashWindow(hwnd, TRUE);
+ next_flash = schedule_timer(450, flash_window_timer, hwnd);
+ }
}
} else if ((mode == 1) && (cfg.beep_ind == B_IND_FLASH)) {
/* maintain */
- if (flashing) {
+ if (flashing && !p_FlashWindowEx) {
FlashWindow(hwnd, TRUE); /* toggle */
next_flash = schedule_timer(450, flash_window_timer, hwnd);
}