📄 windlg.c
字号:
/*
* windlg.c - dialogs for PuTTY(tel), including the configuration dialog.
*/
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <assert.h>
#include <ctype.h>
#include <time.h>
#include "putty.h"
#include "ssh.h"
#include "win_res.h"
#include "storage.h"
#include "dialog.h"
#include <commctrl.h>
#include <commdlg.h>
#include <shellapi.h>
#ifdef MSVC4
#define TVINSERTSTRUCT TV_INSERTSTRUCT
#define TVITEM TV_ITEM
#define ICON_BIG 1
#endif
/*
* These are the various bits of data required to handle the
* portable-dialog stuff in the config box. Having them at file
* scope in here isn't too bad a place to put them; if we were ever
* to need more than one config box per process we could always
* shift them to a per-config-box structure stored in GWL_USERDATA.
*/
static struct controlbox *ctrlbox;
/*
* ctrls_base holds the OK and Cancel buttons: the controls which
* are present in all dialog panels. ctrls_panel holds the ones
* which change from panel to panel.
*/
static struct winctrls ctrls_base, ctrls_panel;
static struct dlgparam dp;
static char **events = NULL;
static int nevents = 0, negsize = 0;
extern Config cfg; /* defined in window.c */
#define PRINTER_DISABLED_STRING "None (printing disabled)"
void force_normal(HWND hwnd)
{
static int recurse = 0;
WINDOWPLACEMENT wp;
if (recurse)
return;
recurse = 1;
wp.length = sizeof(wp);
if (GetWindowPlacement(hwnd, &wp) && wp.showCmd == SW_SHOWMAXIMIZED) {
wp.showCmd = SW_SHOWNORMAL;
SetWindowPlacement(hwnd, &wp);
}
recurse = 0;
}
static int CALLBACK LogProc(HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam)
{
int i;
switch (msg) {
case WM_INITDIALOG:
{
char *str = dupprintf("%s Event Log", appname);
SetWindowText(hwnd, str);
sfree(str);
}
{
static int tabs[4] = { 78, 108 };
SendDlgItemMessage(hwnd, IDN_LIST, LB_SETTABSTOPS, 2,
(LPARAM) tabs);
}
for (i = 0; i < nevents; i++)
SendDlgItemMessage(hwnd, IDN_LIST, LB_ADDSTRING,
0, (LPARAM) events[i]);
return 1;
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDOK:
case IDCANCEL:
logbox = NULL;
SetActiveWindow(GetParent(hwnd));
DestroyWindow(hwnd);
return 0;
case IDN_COPY:
if (HIWORD(wParam) == BN_CLICKED ||
HIWORD(wParam) == BN_DOUBLECLICKED) {
int selcount;
int *selitems;
selcount = SendDlgItemMessage(hwnd, IDN_LIST,
LB_GETSELCOUNT, 0, 0);
if (selcount == 0) { /* don't even try to copy zero items */
MessageBeep(0);
break;
}
selitems = snewn(selcount, int);
if (selitems) {
int count = SendDlgItemMessage(hwnd, IDN_LIST,
LB_GETSELITEMS,
selcount,
(LPARAM) selitems);
int i;
int size;
char *clipdata;
static unsigned char sel_nl[] = SEL_NL;
if (count == 0) { /* can't copy zero stuff */
MessageBeep(0);
break;
}
size = 0;
for (i = 0; i < count; i++)
size +=
strlen(events[selitems[i]]) + sizeof(sel_nl);
clipdata = snewn(size, char);
if (clipdata) {
char *p = clipdata;
for (i = 0; i < count; i++) {
char *q = events[selitems[i]];
int qlen = strlen(q);
memcpy(p, q, qlen);
p += qlen;
memcpy(p, sel_nl, sizeof(sel_nl));
p += sizeof(sel_nl);
}
write_aclip(NULL, clipdata, size, TRUE);
sfree(clipdata);
}
sfree(selitems);
for (i = 0; i < nevents; i++)
SendDlgItemMessage(hwnd, IDN_LIST, LB_SETSEL,
FALSE, i);
}
}
return 0;
}
return 0;
case WM_CLOSE:
logbox = NULL;
SetActiveWindow(GetParent(hwnd));
DestroyWindow(hwnd);
return 0;
}
return 0;
}
static int CALLBACK LicenceProc(HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam)
{
switch (msg) {
case WM_INITDIALOG:
{
char *str = dupprintf("%s Licence", appname);
SetWindowText(hwnd, str);
sfree(str);
}
return 1;
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDOK:
case IDCANCEL:
EndDialog(hwnd, 1);
return 0;
}
return 0;
case WM_CLOSE:
EndDialog(hwnd, 1);
return 0;
}
return 0;
}
static int CALLBACK AboutProc(HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam)
{
char *str;
switch (msg) {
case WM_INITDIALOG:
str = dupprintf("About %s", appname);
SetWindowText(hwnd, str);
sfree(str);
SetDlgItemText(hwnd, IDA_TEXT1, appname);
SetDlgItemText(hwnd, IDA_VERSION, ver);
return 1;
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDOK:
case IDCANCEL:
EndDialog(hwnd, TRUE);
return 0;
case IDA_LICENCE:
EnableWindow(hwnd, 0);
DialogBox(hinst, MAKEINTRESOURCE(IDD_LICENCEBOX),
hwnd, LicenceProc);
EnableWindow(hwnd, 1);
SetActiveWindow(hwnd);
return 0;
case IDA_WEB:
/* Load web browser */
ShellExecute(hwnd, "open",
"http://www.chiark.greenend.org.uk/~sgtatham/putty/",
0, 0, SW_SHOWDEFAULT);
return 0;
}
return 0;
case WM_CLOSE:
EndDialog(hwnd, TRUE);
return 0;
}
return 0;
}
static int SaneDialogBox(HINSTANCE hinst,
LPCTSTR tmpl,
HWND hwndparent,
DLGPROC lpDialogFunc)
{
WNDCLASS wc;
HWND hwnd;
MSG msg;
int flags;
int ret;
int gm;
wc.style = CS_DBLCLKS | CS_SAVEBITS | CS_BYTEALIGNWINDOW;
wc.lpfnWndProc = DefDlgProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = DLGWINDOWEXTRA + 2*sizeof(LONG_PTR);
wc.hInstance = hinst;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH) (COLOR_BACKGROUND +1);
wc.lpszMenuName = NULL;
wc.lpszClassName = "PuTTYConfigBox";
RegisterClass(&wc);
hwnd = CreateDialog(hinst, tmpl, hwndparent, lpDialogFunc);
SetWindowLongPtr(hwnd, BOXFLAGS, 0); /* flags */
SetWindowLongPtr(hwnd, BOXRESULT, 0); /* result from SaneEndDialog */
while ((gm=GetMessage(&msg, NULL, 0, 0)) > 0) {
flags=GetWindowLongPtr(hwnd, BOXFLAGS);
if (!(flags & DF_END) && !IsDialogMessage(hwnd, &msg))
DispatchMessage(&msg);
if (flags & DF_END)
break;
}
if (gm == 0)
PostQuitMessage(msg.wParam); /* We got a WM_QUIT, pass it on */
ret=GetWindowLongPtr(hwnd, BOXRESULT);
DestroyWindow(hwnd);
return ret;
}
static void SaneEndDialog(HWND hwnd, int ret)
{
SetWindowLongPtr(hwnd, BOXRESULT, ret);
SetWindowLongPtr(hwnd, BOXFLAGS, DF_END);
}
/*
* Null dialog procedure.
*/
static int CALLBACK NullDlgProc(HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam)
{
return 0;
}
enum {
IDCX_ABOUT = IDC_ABOUT,
IDCX_TVSTATIC,
IDCX_TREEVIEW,
IDCX_STDBASE,
IDCX_PANELBASE = IDCX_STDBASE + 32
};
struct treeview_faff {
HWND treeview;
HTREEITEM lastat[4];
};
static HTREEITEM treeview_insert(struct treeview_faff *faff,
int level, char *text, char *path)
{
TVINSERTSTRUCT ins;
int i;
HTREEITEM newitem;
ins.hParent = (level > 0 ? faff->lastat[level - 1] : TVI_ROOT);
ins.hInsertAfter = faff->lastat[level];
#if _WIN32_IE >= 0x0400 && defined NONAMELESSUNION
#define INSITEM DUMMYUNIONNAME.item
#else
#define INSITEM item
#endif
ins.INSITEM.mask = TVIF_TEXT | TVIF_PARAM;
ins.INSITEM.pszText = text;
ins.INSITEM.cchTextMax = strlen(text)+1;
ins.INSITEM.lParam = (LPARAM)path;
newitem = TreeView_InsertItem(faff->treeview, &ins);
if (level > 0)
TreeView_Expand(faff->treeview, faff->lastat[level - 1],
(level > 1 ? TVE_COLLAPSE : TVE_EXPAND));
faff->lastat[level] = newitem;
for (i = level + 1; i < 4; i++)
faff->lastat[i] = NULL;
return newitem;
}
/*
* Create the panelfuls of controls in the configuration box.
*/
static void create_controls(HWND hwnd, char *path)
{
struct ctlpos cp;
int index;
int base_id;
struct winctrls *wc;
if (!path[0]) {
/*
* Here we must create the basic standard controls.
*/
ctlposinit(&cp, hwnd, 3, 3, 235);
wc = &ctrls_base;
base_id = IDCX_STDBASE;
} else {
/*
* Otherwise, we're creating the controls for a particular
* panel.
*/
ctlposinit(&cp, hwnd, 100, 3, 13);
wc = &ctrls_panel;
base_id = IDCX_PANELBASE;
}
for (index=-1; (index = ctrl_find_path(ctrlbox, path, index)) >= 0 ;) {
struct controlset *s = ctrlbox->ctrlsets[index];
winctrl_layout(&dp, wc, &cp, s, &base_id);
}
}
/*
* This function is the configuration box.
* (Being a dialog procedure, in general it returns 0 if the default
* dialog processing should be performed, and 1 if it should not.)
*/
static int CALLBACK GenericMainDlgProc(HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam)
{
HWND hw, treeview;
struct treeview_faff tvfaff;
int ret;
switch (msg) {
case WM_INITDIALOG:
dp.hwnd = hwnd;
create_controls(hwnd, ""); /* Open and Cancel buttons etc */
SetWindowText(hwnd, dp.wintitle);
SetWindowLongPtr(hwnd, GWLP_USERDATA, 0);
if (has_help())
SetWindowLongPtr(hwnd, GWL_EXSTYLE,
GetWindowLongPtr(hwnd, GWL_EXSTYLE) |
WS_EX_CONTEXTHELP);
else {
HWND item = GetDlgItem(hwnd, IDC_HELPBTN);
if (item)
DestroyWindow(item);
}
SendMessage(hwnd, WM_SETICON, (WPARAM) ICON_BIG,
(LPARAM) LoadIcon(hinst, MAKEINTRESOURCE(IDI_CFGICON)));
/*
* Centre the window.
*/
{ /* centre the window */
RECT rs, rd;
hw = GetDesktopWindow();
if (GetWindowRect(hw, &rs) && GetWindowRect(hwnd, &rd))
MoveWindow(hwnd,
(rs.right + rs.left + rd.left - rd.right) / 2,
(rs.bottom + rs.top + rd.top - rd.bottom) / 2,
rd.right - rd.left, rd.bottom - rd.top, TRUE);
}
/*
* Create the tree view.
*/
{
RECT r;
WPARAM font;
HWND tvstatic;
r.left = 3;
r.right = r.left + 95;
r.top = 3;
r.bottom = r.top + 10;
MapDialogRect(hwnd, &r);
tvstatic = CreateWindowEx(0, "STATIC", "Cate&gory:",
WS_CHILD | WS_VISIBLE,
r.left, r.top,
r.right - r.left, r.bottom - r.top,
hwnd, (HMENU) IDCX_TVSTATIC, hinst,
NULL);
font = SendMessage(hwnd, WM_GETFONT, 0, 0);
SendMessage(tvstatic, WM_SETFONT, font, MAKELPARAM(TRUE, 0));
r.left = 3;
r.right = r.left + 95;
r.top = 13;
r.bottom = r.top + 219;
MapDialogRect(hwnd, &r);
treeview = CreateWindowEx(WS_EX_CLIENTEDGE, WC_TREEVIEW, "",
WS_CHILD | WS_VISIBLE |
WS_TABSTOP | TVS_HASLINES |
TVS_DISABLEDRAGDROP | TVS_HASBUTTONS
| TVS_LINESATROOT |
TVS_SHOWSELALWAYS, r.left, r.top,
r.right - r.left, r.bottom - r.top,
hwnd, (HMENU) IDCX_TREEVIEW, hinst,
NULL);
font = SendMessage(hwnd, WM_GETFONT, 0, 0);
SendMessage(treeview, WM_SETFONT, font, MAKELPARAM(TRUE, 0));
tvfaff.treeview = treeview;
memset(tvfaff.lastat, 0, sizeof(tvfaff.lastat));
}
/*
* Set up the tree view contents.
*/
{
HTREEITEM hfirst = NULL;
int i;
char *path = NULL;
for (i = 0; i < ctrlbox->nctrlsets; i++) {
struct controlset *s = ctrlbox->ctrlsets[i];
HTREEITEM item;
int j;
char *c;
if (!s->pathname[0])
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -