📄 window.c
字号:
* 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 (!*cfg.host && !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. */ cfg.host[strcspn(cfg.host, ":")] = '\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); } hwnd = NULL; memset(&ucsdata, 0, sizeof(ucsdata)); term = term_init(&cfg, &ucsdata, NULL); logctx = log_init(NULL, &cfg); term_provide_logctx(term, logctx); 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; term_size(term, cfg.height, cfg.width, cfg.savelines); guess_width = extra_width + font_width * term->cols; guess_height = extra_height + font_height * term->rows; { 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 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 s, m; int i, 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"); s = CreateMenu(); get_sesslist(&sesslist, TRUE); for (i = 1; i < ((sesslist.nsessions < 256) ? sesslist.nsessions : 256); i++) AppendMenu(s, MF_ENABLED, IDM_SAVED_MIN + (16 * i), sesslist.sessions[i]); for (j = 0; j < lenof(popup_menus); j++) { m = popup_menus[j].menu; AppendMenu(m, MF_SEPARATOR, 0, 0); popup_menus[j].specials_submenu_pos = GetMenuItemCount(m); 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) s, "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 (help_path) 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)); /* * Open the initial log file if there is one. */ logfopen(logctx); /* * Finally show the window! */ ShowWindow(hwnd, show); SetForegroundWindow(hwnd); /* * Set the palette up. */ pal = NULL; logpal = NULL; init_palette(); term->has_focus = (GetForegroundWindow() == hwnd); UpdateWindow(hwnd); if (GetMessage(&msg, NULL, 0, 0) == 1) { int timer_id = 0, long_timer = 0; while (msg.message != WM_QUIT) { /* Sometimes DispatchMessage calls routines that use their own * GetMessage loop, setup this timer so we get some control back. * * Also call term_update() from the timer so that if the host * is sending data flat out we still do redraws. */ if (timer_id && long_timer) { KillTimer(hwnd, timer_id); long_timer = timer_id = 0; } if (!timer_id) timer_id = SetTimer(hwnd, 1, 20, NULL); if (!(IsWindow(logbox) && IsDialogMessage(logbox, &msg))) DispatchMessage(&msg); /* Make sure we blink everything that needs it. */ term_blink(term, 0); /* 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 (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) continue; if (pending_netevent) { enact_pending_netevent(); if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) continue; } /* Okay there is now nothing to do so we make sure the screen is * completely up to date then tell windows to call us in a little * while. */ if (timer_id) { KillTimer(hwnd, timer_id); timer_id = 0; } HideCaret(hwnd); if (GetCapture() != hwnd || (send_raw_mouse && !(cfg.mouse_override && is_shift_pressed()))) term_out(term); term_update(term); ShowCaret(hwnd); flash_window(1); /* maintain */ /* The messages seem unreliable; especially if we're being tricky */ term->has_focus = (GetForegroundWindow() == hwnd); if (term->in_vbell) /* Hmm, term_update didn't want to do an update too soon ... */ timer_id = SetTimer(hwnd, 1, 50, NULL); else if (!term->has_focus) timer_id = SetTimer(hwnd, 1, 500, NULL); else timer_id = SetTimer(hwnd, 1, 100, NULL); long_timer = 1; /* There's no point rescanning everything in the message queue * so we do an apparently unnecessary wait here */ WaitMessage(); if (GetMessage(&msg, NULL, 0, 0) != 1) break; } } 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 } 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;}/* * Update the Special Commands submenu. */void update_specials_menu(void *frontend){ HMENU p; int menu_already_exists = (specials != NULL); 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. */ HMENU saved_menu = NULL; int nesting = 1; p = CreatePopupMenu(); for (i = 0; nesting > 0; i++) { assert(IDM_SPECIAL_MIN + 0x10 * i < IDM_SPECIAL_MAX); switch (specials[i].code) { case TS_SEP: AppendMenu(p, MF_SEPARATOR, 0, 0); break; case TS_SUBMENU: assert(nesting < 2); nesting++; saved_menu = p; /* XXX lame stacking */ p = CreatePopupMenu(); AppendMenu(saved_menu, MF_POPUP | MF_ENABLED, (UINT) p, specials[i].name); break; case TS_EXITMENU: nesting--; if (nesting) { p = saved_menu; /* XXX lame stacking */ saved_menu = NULL; } break; default: AppendMenu(p, MF_ENABLED, IDM_SPECIAL_MIN + 0x10 * i, specials[i].name); break; } } /* Squirrel the highest special. */ n_specials = i - 1; } else { p = NULL; n_specials = 0; } for (j = 0; j < lenof(popup_menus); j++) { if (menu_already_exists) { /* XXX does this free up all submenus? */ DeleteMenu(popup_menus[j].menu, popup_menus[j].specials_submenu_pos, MF_BYPOSITION); DeleteMenu(popup_menus[j].menu, popup_menus[j].specials_submenu_pos, MF_BYPOSITION); } if (specials) { InsertMenu(popup_menus[j].menu, popup_menus[j].specials_submenu_pos, MF_BYPOSITION | MF_SEPARATOR, 0, 0); InsertMenu(popup_menus[j].menu, popup_menus[j].specials_submenu_pos, MF_BYPOSITION | MF_POPUP | MF_ENABLED, (UINT) p, "S&pecial Command"); } }}/* * set or clear the "raw mouse message" mode */void set_raw_mouse_mode(void *frontend, int activate){ activate = activate && !cfg.no_mouse_rep; send_raw_mouse = activate; SetCursor(LoadCursor(NULL, activate ? IDC_ARROW : IDC_IBEAM));}/* * Print a message box and close the connection. */void connection_fatal(void *frontend, char *fmt, ...)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -