📄 window.c
字号:
"\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) {
/*
* If we already have a host name, treat
* this argument as a port number. NB we
* have to treat this as a saved -P
* argument, so that it will be deferred
* until it's a good moment to run it.
*/
int ret = cmdline_process_param("-P", p, 1, &cfg);
assert(ret == 2);
} else if (!strncmp(q, "telnet:", 7)) {
/*
* If the hostname starts with "telnet:",
* set the protocol to Telnet and process
* the string as a Telnet URL.
*/
char c;
q += 7;
if (q[0] == '/' && q[1] == '/')
q += 2;
cfg.protocol = PROT_TELNET;
p = q;
while (*p && *p != ':' && *p != '/')
p++;
c = *p;
if (*p)
*p++ = '\0';
if (c == ':')
cfg.port = atoi(p);
else
cfg.port = -1;
strncpy(cfg.host, q, sizeof(cfg.host) - 1);
cfg.host[sizeof(cfg.host) - 1] = '\0';
got_host = 1;
} else {
/*
* Otherwise, treat this argument as a host
* name.
*/
while (*p && !isspace(*p))
p++;
if (*p)
*p++ = '\0';
strncpy(cfg.host, q, sizeof(cfg.host) - 1);
cfg.host[sizeof(cfg.host) - 1] = '\0';
got_host = 1;
}
} else {
cmdline_error("unknown option \"%s\"", p);
}
}
}
cmdline_run_saved(&cfg);
if (loaded_session || got_host)
allow_launch = TRUE;
if ((!allow_launch || !cfg_launchable(&cfg)) && !do_config()) {
cleanup_exit(0);
}
/*
* Trim leading whitespace off the hostname if it's there.
*/
{
int space = strspn(cfg.host, " \t");
memmove(cfg.host, cfg.host+space, 1+strlen(cfg.host)-space);
}
/* See if host is of the form user@host */
if (cfg.host[0] != '\0') {
char *atsign = strrchr(cfg.host, '@');
/* Make sure we're not overflowing the user field */
if (atsign) {
if (atsign - cfg.host < sizeof cfg.username) {
strncpy(cfg.username, cfg.host, atsign - cfg.host);
cfg.username[atsign - cfg.host] = '\0';
}
memmove(cfg.host, atsign + 1, 1 + strlen(atsign + 1));
}
}
/*
* Trim a colon suffix off the hostname if it's there. In
* order to protect IPv6 address literals against this
* treatment, we do not do this if there's _more_ than one
* colon.
*/
{
char *c = strchr(cfg.host, ':');
if (c) {
char *d = strchr(c+1, ':');
if (!d)
*c = '\0';
}
}
/*
* Remove any remaining whitespace from the hostname.
*/
{
int p1 = 0, p2 = 0;
while (cfg.host[p2] != '\0') {
if (cfg.host[p2] != ' ' && cfg.host[p2] != '\t') {
cfg.host[p1] = cfg.host[p2];
p1++;
}
p2++;
}
cfg.host[p1] = '\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;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = inst;
wndclass.hIcon = LoadIcon(inst, MAKEINTRESOURCE(IDI_MAINICON));
wndclass.hCursor = LoadCursor(NULL, IDC_IBEAM);
wndclass.hbrBackground = NULL;
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = appname;
RegisterClass(&wndclass);
}
memset(&ucsdata, 0, sizeof(ucsdata));
cfgtopalette();
/*
* Guess some defaults for the window size. This all gets
* updated later, so we don't really care too much. However, we
* do want the font width/height guesses to correspond to a
* large font rather than a small one...
*/
font_width = 10;
font_height = 20;
extra_width = 25;
extra_height = 28;
guess_width = extra_width + font_width * cfg.width;
guess_height = extra_height + font_height * cfg.height;
{
RECT r;
get_fullscreen_rect(&r);
if (guess_width > r.right - r.left)
guess_width = r.right - r.left;
if (guess_height > r.bottom - r.top)
guess_height = r.bottom - r.top;
}
{
int winmode = WS_OVERLAPPEDWINDOW | WS_VSCROLL;
int exwinmode = 0;
if (!cfg.scrollbar)
winmode &= ~(WS_VSCROLL);
if (cfg.resize_action == RESIZE_DISABLED)
winmode &= ~(WS_THICKFRAME | WS_MAXIMIZEBOX);
if (cfg.alwaysontop)
exwinmode |= WS_EX_TOPMOST;
if (cfg.sunken_edge)
exwinmode |= WS_EX_CLIENTEDGE;
hwnd = CreateWindowEx(exwinmode, appname, appname,
winmode, CW_USEDEFAULT, CW_USEDEFAULT,
guess_width, guess_height,
NULL, NULL, inst, NULL);
}
/*
* Initialise the terminal. (We have to do this _after_
* creating the window, since the terminal is the first thing
* which will call schedule_timer(), which will in turn call
* timer_change_notify() which will expect hwnd to exist.)
*/
term = term_init(&cfg, &ucsdata, NULL);
logctx = log_init(NULL, &cfg);
term_provide_logctx(term, logctx);
term_size(term, cfg.height, cfg.width, cfg.savelines);
/*
* Initialise the fonts, simultaneously correcting the guesses
* for font_{width,height}.
*/
init_fonts(0,0);
/*
* Correct the guesses for extra_{width,height}.
*/
{
RECT cr, wr;
GetWindowRect(hwnd, &wr);
GetClientRect(hwnd, &cr);
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;
}
/*
* Resize the window, now we know what size we _really_ want it
* to be.
*/
guess_width = extra_width + font_width * term->cols;
guess_height = extra_height + font_height * term->rows;
SetWindowPos(hwnd, NULL, 0, 0, guess_width, guess_height,
SWP_NOMOVE | SWP_NOREDRAW | SWP_NOZORDER);
/*
* Set up a caret bitmap, with no content.
*/
{
char *bits;
int size = (font_width + 15) / 16 * 2 * font_height;
bits = snewn(size, char);
memset(bits, 0, size);
caretbm = CreateBitmap(font_width, font_height, 1, 1, bits);
sfree(bits);
}
CreateCaret(hwnd, caretbm, font_width, font_height);
/*
* Initialise the scroll bar.
*/
{
SCROLLINFO si;
si.cbSize = sizeof(si);
si.fMask = SIF_ALL | SIF_DISABLENOSCROLL;
si.nMin = 0;
si.nMax = term->rows - 1;
si.nPage = term->rows;
si.nPos = 0;
SetScrollInfo(hwnd, SB_VERT, &si, FALSE);
}
/*
* Prepare the mouse handler.
*/
lastact = MA_NOTHING;
lastbtn = MBT_NOTHING;
dbltime = GetDoubleClickTime();
/*
* Set up the session-control options on the system menu.
*/
{
HMENU m;
int j;
char *str;
popup_menus[SYSMENU].menu = GetSystemMenu(hwnd, FALSE);
popup_menus[CTXMENU].menu = CreatePopupMenu();
AppendMenu(popup_menus[CTXMENU].menu, MF_ENABLED, IDM_PASTE, "&Paste");
savedsess_menu = CreateMenu();
get_sesslist(&sesslist, TRUE);
update_savedsess_menu();
for (j = 0; j < lenof(popup_menus); j++) {
m = popup_menus[j].menu;
AppendMenu(m, MF_SEPARATOR, 0, 0);
AppendMenu(m, MF_ENABLED, IDM_SHOWLOG, "&Event Log");
AppendMenu(m, MF_SEPARATOR, 0, 0);
AppendMenu(m, MF_ENABLED, IDM_NEWSESS, "Ne&w Session...");
AppendMenu(m, MF_ENABLED, IDM_DUPSESS, "&Duplicate Session");
AppendMenu(m, MF_POPUP | MF_ENABLED, (UINT) savedsess_menu,
"Sa&ved Sessions");
AppendMenu(m, MF_ENABLED, IDM_RECONF, "Chan&ge Settings...");
AppendMenu(m, MF_SEPARATOR, 0, 0);
AppendMenu(m, MF_ENABLED, IDM_COPYALL, "C&opy All to Clipboard");
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, (cfg.resize_action == RESIZE_DISABLED) ?
MF_GRAYED : MF_ENABLED, IDM_FULLSCREEN, "&Full Screen");
AppendMenu(m, MF_SEPARATOR, 0, 0);
if (has_help())
AppendMenu(m, MF_ENABLED, IDM_HELP, "&Help");
str = dupprintf("&About %s", appname);
AppendMenu(m, MF_ENABLED, IDM_ABOUT, str);
sfree(str);
}
}
start_backend();
/*
* Set up the initial input locale.
*/
set_input_locale(GetKeyboardLayout(0));
/*
* Finally show the window!
*/
ShowWindow(hwnd, show);
SetForegroundWindow(hwnd);
/*
* Set the palette up.
*/
pal = NULL;
logpal = NULL;
init_palette();
term_set_focus(term, GetForegroundWindow() == hwnd);
UpdateWindow(hwnd);
while (1) {
HANDLE *handles;
int nhandles, n;
handles = handle_get_events(&nhandles);
n = MsgWaitForMultipleObjects(nhandles, handles, FALSE, INFINITE,
QS_ALLINPUT);
if ((unsigned)(n - WAIT_OBJECT_0) < (unsigned)nhandles) {
handle_got_event(handles[n - WAIT_OBJECT_0]);
sfree(handles);
if (must_close_session)
close_session();
} else
sfree(handles);
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT)
goto finished; /* two-level break */
if (!(IsWindow(logbox) && IsDialogMessage(logbox, &msg)))
DispatchMessage(&msg);
/* Send the paste buffer if there's anything to send */
term_paste(term);
/* If there's nothing new in the queue then we can do everything
* we've delayed, reading the socket, writing, and repainting
* the window.
*/
if (must_close_session)
close_session();
}
/* 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();
}
finished:
cleanup_exit(msg.wParam); /* this doesn't return... */
return msg.wParam; /* ... but optimiser doesn't know */
}
/*
* Clean up and exit.
*/
void cleanup_exit(int code)
{
/*
* Clean up.
*/
deinit_fonts();
sfree(logpal);
if (pal)
DeleteObject(pal);
sk_cleanup();
if (cfg.protocol == PROT_SSH) {
random_save_seed();
#ifdef MSCRYPTOAPI
crypto_wrapup();
#endif
}
shutdown_help();
exit(code);
}
/*
* Set up, or shut down, an AsyncSelect. Called from winnet.c.
*/
char *do_select(SOCKET skt, int startup)
{
int msg, events;
if (startup) {
msg = WM_NETEVENT;
events = (FD_CONNECT | FD_READ | FD_WRITE |
FD_OOB | FD_CLOSE | FD_ACCEPT);
} else {
msg = events = 0;
}
if (!hwnd)
return "do_select(): internal error (hwnd==NULL)";
if (p_WSAAsyncSelect(skt, hwnd, msg, events) == SOCKET_ERROR) {
switch (p_WSAGetLastError()) {
case WSAENETDOWN:
return "Network is down";
default:
return "WSAAsyncSelect(): unknown error";
}
}
return NULL;
}
/*
* Refresh the saved-session submenu from `sesslist'.
*/
static void update_savedsess_menu(void)
{
int i;
while (DeleteMenu(savedsess_menu, 0, MF_BYPOSITION)) ;
/* skip sesslist.sessions[0] == Default Settings */
for (i = 1;
i < ((sesslist.nsessions <= MENU_SAVED_MAX+1) ? sesslist.nsessions
: MENU_SAVED_MAX+1);
i++)
AppendMenu(savedsess_menu, MF_ENABLED,
IDM_SAVED_MIN + (i-1)*MENU_SAVED_STEP,
sesslist.sessions[i]);
}
/*
* Update the Special Commands submenu.
*/
void update_specials_menu(void *frontend)
{
HMENU new_menu;
int i, j;
if (back)
specials = back->get_specials(backhandle);
else
specials = NULL;
if (specials) {
/* We can't use Windows to provide a stack for submenus, so
* here's a lame "stack" that will do for now. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -