diff --git a/Recipe b/Recipe index 1a34bb86eeb0c1db517ac6082b9a1017013997e5..0f558ea289e7a75ddb19401d9c798ba813b9f4a7 100644 --- a/Recipe +++ b/Recipe @@ -250,6 +250,7 @@ TERMINAL = terminal wcwidth ldiscucs logging tree234 minibidi # GUI front end and terminal emulator (putty, puttytel). GUITERM = TERMINAL window windlg winctrls sizetip winucs winprint + winutils wincfg sercfg winhelp winjump + + pickicondialog # Same thing on Unix. UXTERM = TERMINAL uxcfg sercfg uxucs uxprint timing @@ -321,6 +322,7 @@ puttygen : [G] winpgen sshrsag sshdssg sshprime sshdes sshbn sshmd5 version + sshrand winnoise sshsha winstore misc winctrls sshrsa sshdss winmisc + sshpubk sshaes sshsh256 sshsh512 import winutils puttygen.res + tree234 notiming winhelp winnojmp LIBS wintime + + pickicondialog pterm : [X] GTKTERM uxmisc misc ldisc settings uxpty uxsel BE_NONE uxstore + uxsignal CHARSET cmdline uxpterm version time xpmpterm xpmptcfg diff --git a/config.c b/config.c index 99ff1b4d70dca44d80d833a938ab975bd0d587e4..00e620a4767464a9c747e491c31e783f24875e19 100644 --- a/config.c +++ b/config.c @@ -1831,7 +1831,7 @@ void setup_config_box(struct controlbox *b, int midsession, s = ctrl_getset(b, "Connection", "tcp", "Low-level TCP connection options"); ctrl_checkbox(s, "Disable Nagle's algorithm (TCP_NODELAY option)", - 'n', HELPCTX(connection_nodelay), + 'l', HELPCTX(connection_nodelay), dlg_stdcheckbox_handler, I(offsetof(Config,tcp_nodelay))); ctrl_checkbox(s, "Enable TCP keepalives (SO_KEEPALIVE option)", diff --git a/dialog.c b/dialog.c index 53b642980a8d640fe13613d1b17e6d6a54d46194..ebd3cb3ad2317f96c32d6285f72c6687609af5f6 100644 --- a/dialog.c +++ b/dialog.c @@ -271,6 +271,15 @@ union control *ctrl_combobox(struct controlset *s, char *label, char shortcut, return c; } +/* + * HACK: PuttyTray / Session Icon + */ +union control *ctrl_icon(struct controlset *s, intorptr helpctx, intorptr context) +{ + union control *c = ctrl_new(s, CTRL_ICON, helpctx, NULL, context); + return c; +}; + /* * `ncolumns' is followed by (alternately) radio button titles and * intorptrs, until a NULL in place of a title string is seen. Each diff --git a/dialog.h b/dialog.h index 0cabb3d39dadf6104c9c3b84f04eddfc80c599d2..9e41df4b11bb83fbe2c1b9eaa4f01c3aef626408 100644 --- a/dialog.h +++ b/dialog.h @@ -35,7 +35,13 @@ enum { CTRL_COLUMNS, /* divide window into columns */ CTRL_FILESELECT, /* label plus filename selector */ CTRL_FONTSELECT, /* label plus font selector */ - CTRL_TABDELAY /* see `tabdelay' below */ + CTRL_TABDELAY, /* see `tabdelay' below */ + + /* + * HACK: PuttyTray / Session Icon + * Add ctrl_icon, ctrl_path, ctrl_sessionlistbox + */ + CTRL_ICON /* static icon without label */ }; /* @@ -404,6 +410,15 @@ union control { STANDARD_PREFIX; char shortcut; } fontselect; + + /* + * HACK: PuttyTray / Session Icon + */ + struct { + STANDARD_PREFIX; + intorptr handle; + } icon; + //-------------- }; #undef STANDARD_PREFIX @@ -521,6 +536,16 @@ union control *ctrl_checkbox(struct controlset *, char *label, char shortcut, handler_fn handler, intorptr context); union control *ctrl_tabdelay(struct controlset *, union control *); +/* + * HACK: PuttyTray / Session Icon + */ +union control *ctrl_icon(struct controlset *, intorptr helpctx, intorptr context); + +// Should be somewhere below, but this is easier +void dlg_icon_set(union control *ctrl, void *dlg, char const *icon); +int dlg_pick_icon(void *dlg, char **iname, int inamesize, int *iindex); +//------------------------------------ + /* * Standard handler routines to cover most of the common cases in * the config box. diff --git a/putty.h b/putty.h index 1a895f3dd8997ee44dacb8c680220a7f9ada7485..048592da21e544e6afa5482403b90a84cb595628 100644 --- a/putty.h +++ b/putty.h @@ -137,6 +137,30 @@ typedef struct terminal_tag Terminal; #define ATTR_DEFBG (258 << ATTR_BGSHIFT) #define ATTR_DEFAULT (ATTR_DEFFG | ATTR_DEFBG) +/* + * HACK: PuttyTray / Nutty + * Hyperlink stuff: define + */ +#define CHAR_MASK 0x000000FFUL + +/* + * HACK: PuttyTray / Nutty + * Hyperlink stuff: Underline settings + */ +enum { + URLHACK_UNDERLINE_ALWAYS, + URLHACK_UNDERLINE_HOVER, + URLHACK_UNDERLINE_NEVER +}; + +/* + * HACK: PuttyTray + * Tray options + */ +enum { + TRAY_NEVER, TRAY_NORMAL, TRAY_START, TRAY_ALWAYS +}; + struct sesslist { int nsessions; char **sessions; @@ -683,6 +707,17 @@ struct config_tag { * HACK: PuttyTray / PuTTY File */ int session_storagetype; + /* + * HACK: PuttyTray + */ + int tray; + int start_tray; + int tray_restore; + + /* + * HACK: PuttyTray / Session Icon + */ + char win_icon[256]; }; /* diff --git a/settings.c b/settings.c index 4e7ff6353e347f7d8ecef78215eaf8aba0de6578..1375a230d36fbdf2adb1a9c764e3aa53ef8b58f3 100644 --- a/settings.c +++ b/settings.c @@ -450,6 +450,20 @@ void save_open_settings(void *sesskey, Config *cfg) */ write_setting_i(sesskey, "StorageType", cfg->session_storagetype); + /* + * HACK: PuttyTray + * Save tray settings + */ + write_setting_i(sesskey, "Tray", cfg->tray); + write_setting_i(sesskey, "StartTray", cfg->start_tray); + write_setting_i(sesskey, "TrayRestore", cfg->tray_restore); + + + /* + * HACK: PuttyTray / Session Icon + */ + write_setting_s(sesskey, "WindowIcon", cfg->win_icon); + write_setting_i(sesskey, "AltF4", cfg->alt_f4); write_setting_i(sesskey, "AltSpace", cfg->alt_space); write_setting_i(sesskey, "AltOnly", cfg->alt_only); @@ -789,6 +803,20 @@ void load_open_settings(void *sesskey, Config *cfg) */ gppi(sesskey, "StorageType", 0, &cfg->session_storagetype); + /* + * HACK: PuttyTray + * Save tray settings + */ + gppi(sesskey, "Tray", TRAY_NEVER, &cfg->tray); + gppi(sesskey, "StartTray", 0, &cfg->start_tray); + gppi(sesskey, "TrayRestore", 0, &cfg->tray_restore); + + + /* + * HACK: PuttyTray / Session Icon + */ + gpps(sesskey, "WindowIcon", "", cfg->win_icon, sizeof(cfg->win_icon)); + gppi(sesskey, "AltF4", 1, &cfg->alt_f4); gppi(sesskey, "AltSpace", 0, &cfg->alt_space); gppi(sesskey, "AltOnly", 0, &cfg->alt_only); diff --git a/windows/pickicondialog.c b/windows/pickicondialog.c new file mode 100644 index 0000000000000000000000000000000000000000..8953d5ed641500fb3a1d2d9023457e9eb04359f0 --- /dev/null +++ b/windows/pickicondialog.c @@ -0,0 +1,59 @@ +/* + * HACK: PuttyTray / Session Icon + * Added this file + */ +#include <windows.h> +typedef WINSHELLAPI BOOL(WINAPI * fnPickIconDlg) (HWND hWndParent, LPTSTR pszFilename, LPDWORD pdwBufferSize, LPDWORD pdwIndex); + +BOOL SelectIconA(HWND hWndParent, LPSTR lpszFilename, DWORD dwBufferSize, DWORD * pdwIndex) { + BOOL result = FALSE; + OSVERSIONINFO versioninfo; + HMODULE hShell32 = LoadLibrary("shell32.dll"); + versioninfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&versioninfo); + + if (hShell32) { + fnPickIconDlg PickIconDlg = (fnPickIconDlg) GetProcAddress(hShell32, (LPCSTR) 62); + if (PickIconDlg) { + if (versioninfo.dwPlatformId == VER_PLATFORM_WIN32_NT) { + LPWSTR pszWideName = (LPWSTR) malloc(dwBufferSize); + MultiByteToWideChar(CP_ACP, 0, lpszFilename, -1, pszWideName, dwBufferSize); + result = PickIconDlg(hWndParent, (LPTSTR) pszWideName, &dwBufferSize, pdwIndex); + WideCharToMultiByte(CP_ACP, 0, pszWideName, -1, lpszFilename, dwBufferSize, NULL, NULL); + free(pszWideName); + } else { + result = PickIconDlg(hWndParent, (LPTSTR) lpszFilename, &dwBufferSize, pdwIndex); + } + } + FreeLibrary(hShell32); + } + + return result; +} + + +BOOL SelectIconW(HWND hWndParent, LPWSTR lpszFilename, DWORD dwBufferSize, DWORD * pdwIndex) { + BOOL result = FALSE; + OSVERSIONINFO versioninfo; + HMODULE hShell32 = LoadLibrary("shell32.dll"); + versioninfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&versioninfo); + + if (hShell32) { + fnPickIconDlg PickIconDlg = (fnPickIconDlg) GetProcAddress(hShell32, (LPCSTR) 62); + if (PickIconDlg) { + if (versioninfo.dwPlatformId != VER_PLATFORM_WIN32_NT) { + LPSTR pszMBName = (LPSTR) malloc(dwBufferSize); + WideCharToMultiByte(CP_ACP, 0, lpszFilename, -1, pszMBName, dwBufferSize, NULL, NULL); + result = PickIconDlg(hWndParent, (LPTSTR) pszMBName, &dwBufferSize, pdwIndex); + MultiByteToWideChar(CP_ACP, 0, pszMBName, -1, lpszFilename, dwBufferSize); + free(pszMBName); + } else { + result = PickIconDlg(hWndParent, (LPTSTR) lpszFilename, &dwBufferSize, pdwIndex); + } + } + FreeLibrary(hShell32); + } + + return result; +} diff --git a/windows/pickicondialog.h b/windows/pickicondialog.h new file mode 100644 index 0000000000000000000000000000000000000000..aef90096ec5ef49e237b7cae1cfb6bd339a28927 --- /dev/null +++ b/windows/pickicondialog.h @@ -0,0 +1,19 @@ +/* + * HACK: PuttyTray / Session Icon + * Added this file + */ + +#ifndef _SELECTICON_H_ +#define _SELECTICON_H_ + +BOOL SelectIconW(HWND hWndParent, LPWSTR lpszFilename, DWORD dwBufferSize, DWORD * pdwIndex); +BOOL SelectIconA(HWND hWndParent, LPSTR lpszFilename, DWORD dwBufferSize, DWORD * pdwIndex); + +#ifdef _UNICODE +#define SelectIcon SelectIconW +#else +#define SelectIcon SelectIconA +#endif + + +#endif diff --git a/windows/wincfg.c b/windows/wincfg.c index cb8f1ece9e166e78f36265017054daae1818aec1..179038cc0707bc22abaa1e453290cf3f2a69ec94 100644 --- a/windows/wincfg.c +++ b/windows/wincfg.c @@ -40,6 +40,33 @@ static void variable_pitch_handler(union control *ctrl, void *dlg, } } +/* + * HACK: PuttyTray / Session Icon + */ +static void window_icon_handler(union control *ctrl, void *dlg, void *data, int event) +{ + Config *cfg = (Config *) data; + + if (event == EVENT_ACTION) { + char buf[512], iname[512], *ipointer; + int iindex; + + memset(&iname, 0, sizeof(iname)); + memset(&buf, 0, sizeof(buf)); + iindex = 0; + ipointer = iname; + if (dlg_pick_icon(dlg, &ipointer, sizeof(iname), &iindex) /*&& iname[0]*/) { + if (iname[0]) { + sprintf(buf, "%s,%d", iname, iindex); + } else { + sprintf(buf, "%s", iname); + } + dlg_icon_set((union control *) ctrl->button.context.p, dlg, buf); + strcpy(cfg->win_icon, buf); + }; + }; +}; + void win_setup_config_box(struct controlbox *b, HWND *hwndp, int has_help, int midsession, int protocol) { @@ -332,7 +359,7 @@ void win_setup_config_box(struct controlbox *b, HWND *hwndp, int has_help, ctrl_checkbox(s, "Window closes on ALT-F4", '4', HELPCTX(behaviour_altf4), dlg_stdcheckbox_handler, I(offsetof(Config,alt_f4))); - ctrl_checkbox(s, "System menu appears on ALT-Space", 'y', + ctrl_checkbox(s, "System menu appears on ALT-Space", 'm', HELPCTX(behaviour_altspace), dlg_stdcheckbox_handler, I(offsetof(Config,alt_space))); ctrl_checkbox(s, "System menu appears on ALT alone", 'l', @@ -359,6 +386,36 @@ void win_setup_config_box(struct controlbox *b, HWND *hwndp, int has_help, ctrl_checkbox(s, "Attempt to reconnect on system wakeup", 'w', HELPCTX(no_help), dlg_stdcheckbox_handler, I(offsetof(Config,wakeup_reconnect))); ctrl_checkbox(s, "Attempt to reconnect on connection failure", 'f', HELPCTX(no_help), dlg_stdcheckbox_handler, I(offsetof(Config,failure_reconnect))); + /* + * HACK: PuttyTray + */ + ctrl_radiobuttons(s, "Show tray icon:", NO_SHORTCUT, 4, + HELPCTX(no_help), + dlg_stdradiobutton_handler, + I(offsetof(Config, tray)), + "Normal", 'n', I(TRAY_NORMAL), + "Always", 'y', I(TRAY_ALWAYS), + "Never", 'r', I(TRAY_NEVER), + "On start", 's', I(TRAY_START), NULL); + ctrl_checkbox(s, "Accept single-click to restore from tray", 't', + HELPCTX(no_help), + dlg_stdcheckbox_handler, I(offsetof(Config,tray_restore))); + + /* + * HACK: PuttyTray / Session Icon + */ + s = ctrl_getset(b, "Window/Behaviour", "icon", "Adjust the icon"); + ctrl_columns(s, 3, 40, 20, 40); + c = ctrl_text(s, "Window / tray icon:", HELPCTX(appearance_title)); + c->generic.column = 0; + c = ctrl_icon(s, HELPCTX(appearance_title), + I(offsetof(Config, win_icon))); + c->generic.column = 1; + c = ctrl_pushbutton(s, "Change Icon...", 'h', HELPCTX(appearance_title), + window_icon_handler, P(c)); + c->generic.column = 2; + ctrl_columns(s, 1, 100); + /* * Windows supports a local-command proxy. This also means we * must adjust the text on the `Telnet command' control. diff --git a/windows/winctrls.c b/windows/winctrls.c index 7c6bf8db3f9b98f1611e9a0ed59113a1f1fe8b4c..b3868e7c626d5b6cea8cf36ed55f8ce7198b5b2e 100644 --- a/windows/winctrls.c +++ b/windows/winctrls.c @@ -22,6 +22,12 @@ #include <commctrl.h> +/* + * HACK: PuttyTray / Session Icon + */ +#include "pickicondialog.h" +#define ICONHEIGHT 20 + #define GAPBETWEEN 3 #define GAPWITHIN 1 #define GAPXBOX 7 @@ -953,6 +959,26 @@ void prefslist(struct prefslist *hdl, struct ctlpos *cp, int lines, } +/* + * HACK: PuttyTray / Session Icon + */ +void staticicon(struct ctlpos *cp, char *stext, char *iname, int id) +{ + RECT r; + HWND hcontrol; + HICON hicon; + + r.left = GAPBETWEEN; + r.top = cp->ypos; + r.right = cp->width; + r.bottom = ICONHEIGHT; + cp->ypos += r.bottom + GAPBETWEEN; + hcontrol = doctl(cp, r, "STATIC", + WS_CHILD | WS_VISIBLE | SS_ICON, 0, NULL, id); + hicon = extract_icon(iname, FALSE); + SendMessage(hcontrol, STM_SETICON, (WPARAM) hicon, 0); +} + /* * Helper function for prefslist: move item in list box. */ @@ -1518,6 +1544,18 @@ void winctrl_layout(struct dlgparam *dp, struct winctrls *wc, } sfree(escaped); break; + + /* + * HACK: PuttyTray / Session Icon + */ + case CTRL_ICON: { + Config *cfg = (Config *)dp->data; + num_ids = 1; + staticicon(&pos, ctrl->icon.label, (char *) ATOFFSET(&cfg, ctrl->icon.context.i), base_id); + break; + } + //----------------------------------------------------- + case CTRL_RADIO: num_ids = ctrl->radio.nbuttons + 1; /* label as well */ { @@ -2239,6 +2277,21 @@ void dlg_text_set(union control *ctrl, void *dlg, char const *text) SetDlgItemText(dp->hwnd, c->base_id, text); } +/* + * HACK: PuttyTray / Session Icon + */ +void dlg_icon_set(union control *ctrl, void *dlg, char const *icon) +{ + HICON hicon; + + struct dlgparam *dp = (struct dlgparam *) dlg; + struct winctrl *c = dlg_findbyctrl(dp, ctrl); + assert(c && c->ctrl->generic.type == CTRL_ICON); + hicon = extract_icon((char *) icon, FALSE); + SendDlgItemMessage(dp->hwnd, c->base_id, STM_SETICON, (WPARAM) hicon, 0); +}; +//-------------------------------- + void dlg_label_change(union control *ctrl, void *dlg, char const *text) { struct dlgparam *dp = (struct dlgparam *)dlg; @@ -2621,3 +2674,13 @@ void *dlg_alloc_privdata(union control *ctrl, void *dlg, size_t size) p->data = smalloc(size); return p->data; } + +/* + * HACK: PuttyTray / Session Icon + */ +int dlg_pick_icon(void *dlg, char **iname, int inamesize, int *iindex) +{ + struct dlgparam *dp = (struct dlgparam *) dlg; + int ret = SelectIcon(dp->hwnd, *iname, inamesize, iindex); + return ret == IDOK ? TRUE : FALSE; +}; diff --git a/windows/windlg.c b/windows/windlg.c index f2f853b259e576d8d10d91e0ca4d04189f303548..ad32900ff18c7428a02b117980118a22cfb4b9be 100644 --- a/windows/windlg.c +++ b/windows/windlg.c @@ -234,24 +234,26 @@ static int SaneDialogBox(HINSTANCE hinst, HWND hwndparent, DLGPROC lpDialogFunc) { - WNDCLASS wc; + WNDCLASSEX wc; //HACK: PuTTYTray / Icon Fix HWND hwnd; MSG msg; int flags; int ret; int gm; - wc.style = CS_DBLCLKS | CS_SAVEBITS | CS_BYTEALIGNWINDOW; + wc.cbSize = sizeof(WNDCLASSEX); //HACK: PuTTYTray / Icon Fix + 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.hIcon = LoadImage(hinst, MAKEINTRESOURCE(IDI_CFGICON), IMAGE_ICON, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), LR_DEFAULTCOLOR|LR_SHARED); //HACK: PuTTYTray / Icon Fix + wc.hIconSm = LoadImage(hinst, MAKEINTRESOURCE(IDI_CFGICON), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR|LR_SHARED); //HACK: PuTTYTray / Icon Fix wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH) (COLOR_BACKGROUND +1); wc.lpszMenuName = NULL; wc.lpszClassName = "PuTTYConfigBox"; - RegisterClass(&wc); + RegisterClassEx(&wc); //HACK: PuTTYTray / Icon Fix hwnd = CreateDialog(hinst, tmpl, hwndparent, lpDialogFunc); @@ -389,8 +391,10 @@ static int CALLBACK GenericMainDlgProc(HWND hwnd, UINT msg, if (item) DestroyWindow(item); } - SendMessage(hwnd, WM_SETICON, (WPARAM) ICON_BIG, - (LPARAM) LoadIcon(hinst, MAKEINTRESOURCE(IDI_CFGICON))); + + // HACK: DISABLES LINE + //SendMessage(hwnd, WM_SETICON, (WPARAM) ICON_BIG, (LPARAM) LoadImage(hinst, MAKEINTRESOURCE(IDI_CFGICON), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR|LR_SHARED)); //HACK: PuTTYTray / Icon Fix + /* * Centre the window. */ diff --git a/windows/window.c b/windows/window.c index bd813e1f14600d3d0202a4138872ede8e7746c04..00142895ca8662c93b43c83c0bdc4031be2febf5 100644 --- a/windows/window.c +++ b/windows/window.c @@ -49,12 +49,23 @@ #define IDM_PASTE 0x0190 #define IDM_SPECIALSEP 0x0200 +/* + * HACK: PuttyTray + * Trayicon Menu addons + */ +#define IDM_VISIBLE 0x0240 + +#define IDM_TRAYSEP 0x0210 +#define IDM_TRAYCLOSE 0x0220 +#define IDM_TRAYRESTORE 0x0230 + #define IDM_SPECIAL_MIN 0x0400 #define IDM_SPECIAL_MAX 0x0800 #define IDM_SAVED_MIN 0x1000 #define IDM_SAVED_MAX 0x5000 #define MENU_SAVED_STEP 16 + /* Maximum number of sessions on saved-session submenu */ #define MENU_SAVED_MAX ((IDM_SAVED_MAX-IDM_SAVED_MIN) / MENU_SAVED_STEP) @@ -76,6 +87,22 @@ #define WHEEL_DELTA 120 #endif +#ifndef GCL_HCURSOR +#define GCL_HCURSOR -12 +#endif + +#ifndef GCL_HICON +#define GCL_HICON -14 +#endif + +#ifndef GCL_HICONSM +#define GCL_HICONSM -34 +#endif + +#ifndef GWL_HINSTANCE +#define GWL_HINSTANCE -6 +#endif + static Mouse_Button translate_button(Mouse_Button button); static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, @@ -230,6 +257,19 @@ static BOOL initialized = FALSE; #define LWA_ALPHA 0x00000002 #endif +/* + * HACK: PuttyTray + * Trayicon struct, Message ID and functions + */ +static NOTIFYICONDATA puttyTray; +static BOOL puttyTrayVisible; +static BOOL puttyTrayFlash; +static HICON puttyTrayFlashIcon; +static BOOL windowMinimized = FALSE; +BOOL taskbar_addicon(LPSTR lpszTip, BOOL showIcon); +void tray_updatemenu(BOOL disableMenuItems); +#define WM_NOTIFY_PUTTYTRAY (WM_USER + 1983) + /* Dummy routine, only required in plink. */ void ldisc_update(void *frontend, int echo, int edit) { @@ -352,7 +392,7 @@ static void close_session(void) int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { - WNDCLASS wndclass; + WNDCLASSEX wndclass; //HACK: PuttyTray / Session Icon MSG msg; HRESULT hr; int guess_width, guess_height; @@ -658,19 +698,42 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) } } + /* 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); + } + + /* + * HACK: PuttyTray / Session Icon + * + * Changes below: wndclassEX and some additions for the 2 icon sizes + */ 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); + wndclass.cbSize = sizeof(WNDCLASSEX); + wndclass.style = 0; + wndclass.lpfnWndProc = WndProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = 0; + wndclass.hInstance = inst; + + if (cfg.win_icon[0]) { + wndclass.hIcon = extract_icon(cfg.win_icon, FALSE); + wndclass.hIconSm = extract_icon(cfg.win_icon, TRUE); + } else { + wndclass.hIcon = LoadImage(inst, MAKEINTRESOURCE(IDI_MAINICON), IMAGE_ICON, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), LR_DEFAULTCOLOR|LR_SHARED); + wndclass.hIconSm = LoadImage(inst, MAKEINTRESOURCE(IDI_MAINICON), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR|LR_SHARED); + } + + wndclass.hCursor = LoadCursor(NULL, IDC_IBEAM); + wndclass.hbrBackground = NULL; + wndclass.lpszMenuName = NULL; + wndclass.lpszClassName = appname; + + RegisterClassEx(&wndclass); } memset(&ucsdata, 0, sizeof(ucsdata)); @@ -751,10 +814,9 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) */ 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); + SetWindowPos(hwnd, NULL, 0, 0, guess_width, guess_height, SWP_NOMOVE | SWP_NOREDRAW | SWP_NOZORDER); - /* + /* * Set up a caret bitmap, with no content. */ { @@ -848,6 +910,42 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) start_backend(); + /* + * HACK: PuttyTray + * Init TrayIcon + */ + puttyTray.cbSize = sizeof(NOTIFYICONDATA); + puttyTray.hWnd = hwnd; + puttyTray.uID = 1983; + puttyTray.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; + puttyTray.uCallbackMessage = WM_NOTIFY_PUTTYTRAY; + if (cfg.win_icon[0]) { + puttyTray.hIcon = wndclass.hIconSm; + } else { + puttyTray.hIcon = LoadImage(inst, MAKEINTRESOURCE(IDI_MAINICON), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR|LR_SHARED); + } + + /* + * HACK: PuttyTray + * Set trayicon menu properties + */ + { + MENUINFO mi; + memset(&mi, 0, sizeof(MENUINFO)); + mi.cbSize = sizeof(MENUINFO); + mi.fMask = MIM_STYLE; + mi.dwStyle = MNS_NOCHECK | MNS_AUTODISMISS; + SetMenuInfo(popup_menus[CTXMENU].menu, &mi); + } + + /* + * HACK: PuttyTray / Nutty + * Hyperlink stuff: Set the regular expression + */ + if (term->cfg.url_defregex == 0) { + urlhack_set_regular_expression(term->cfg.url_regex); + } + /* * Set up the initial input locale. */ @@ -866,8 +964,25 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) logpal = NULL; init_palette(); - term_set_focus(term, GetForegroundWindow() == hwnd); - UpdateWindow(hwnd); + + /* + * HACK: PuttyTray + * Finally show the window (or the trayicon)! + */ + puttyTrayVisible = FALSE; + + if (cfg.tray == TRAY_START || cfg.tray == TRAY_ALWAYS) { + taskbar_addicon(cfg.win_name_always ? window_name : icon_name, TRUE); + } + if (cfg.tray == TRAY_START) { + ShowWindow(hwnd, SW_HIDE); + windowMinimized = TRUE; + } else { + ShowWindow(hwnd, show); + SetForegroundWindow(hwnd); + term_set_focus(term, GetForegroundWindow() == hwnd); + UpdateWindow(hwnd); + } /* * HACK: PuttyTray / Transparency @@ -928,6 +1043,12 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) */ void cleanup_exit(int code) { + /* HACK: PuttyTray + * Remove trayicon on close + */ + taskbar_addicon("", FALSE); + DestroyIcon(puttyTray.hIcon); + /* * Clean up. */ @@ -2061,6 +2182,11 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, static int processed_resize = FALSE; static UINT last_mousemove = 0; + /* + * HACK: PuttyTray / Nutty + */ + POINT cursor_pt; + switch (message) { case WM_TIMER: if ((UINT_PTR)wParam == TIMING_TIMER_ID) { @@ -2198,6 +2324,12 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, int init_lvl = 1; int reconfig_result; + /* + * HACK: PuttyTray / Session Icon + */ + HINSTANCE inst; + HICON hIcon; + if (reconfiguring) break; else @@ -2263,6 +2395,43 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, } } else { MakeWindowTransparent(hwnd, 255); + + /* + * HACK: PuttyTray / Session Icon + * Reconfigure + */ + if (cfg.win_icon[0]) { + hIcon = extract_icon(cfg.win_icon, TRUE); + DestroyIcon(puttyTray.hIcon); + puttyTray.hIcon = hIcon; + SetClassLong(hwnd, GCL_HICON, extract_icon(cfg.win_icon, FALSE)); + SetClassLong(hwnd, GCL_HICONSM, (LONG)hIcon); + } else { + inst = (HINSTANCE) GetWindowLong(hwnd, GWL_HINSTANCE); + DestroyIcon(puttyTray.hIcon); + puttyTray.hIcon = LoadImage(inst, MAKEINTRESOURCE(IDI_MAINICON), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR|LR_SHARED); + SetClassLong(hwnd, GCL_HICON, (LONG)LoadImage(inst, MAKEINTRESOURCE(IDI_MAINICON), IMAGE_ICON, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), LR_DEFAULTCOLOR|LR_SHARED)); + SetClassLong(hwnd, GCL_HICONSM, (LONG)LoadImage(inst, MAKEINTRESOURCE(IDI_MAINICON), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR|LR_SHARED)); + } + if (puttyTrayVisible) { + taskbar_addicon(cfg.win_name_always ? window_name : icon_name, TRUE); + } + + /* + * HACK: PuttyTray + * Reconfigure + */ + if (cfg.tray == TRAY_NORMAL || cfg.tray == TRAY_START) { + if (windowMinimized) { + ShowWindow(hwnd, SW_HIDE); + taskbar_addicon(cfg.win_name_always ? window_name : icon_name, TRUE); + } else { + taskbar_addicon("", FALSE); + } + } else if (cfg.tray == TRAY_ALWAYS) { + taskbar_addicon(cfg.win_name_always ? window_name : icon_name, TRUE); + } else { + taskbar_addicon("", FALSE); } /* Screen size changed ? */ @@ -2390,8 +2559,25 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, * HACK: PuttyTray / Always on top */ case IDM_VISIBLE: - MakeWindowOnTop(hwnd); + MakeWindowOnTop(hwnd); break ; + /* + * HACK: PuttyTray + * Trayicon Menu addon click handlers + */ + case IDM_TRAYRESTORE: + ShowWindow(hwnd, SW_RESTORE); + SetForegroundWindow(hwnd); + windowMinimized = FALSE; + + // Remove icon + if (cfg.tray != TRAY_ALWAYS) { + taskbar_addicon(cfg.win_name_always ? window_name : icon_name, FALSE); + } + break; + case IDM_TRAYCLOSE: + SendMessage(hwnd, WM_CLOSE, NULL, NULL); + break; case SC_MOUSEMENU: /* @@ -2867,9 +3053,30 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, "...", LOWORD(lParam), HIWORD(lParam))); #endif - if (wParam == SIZE_MINIMIZED) - SetWindowText(hwnd, - cfg.win_name_always ? window_name : icon_name); + + /* + * HACK: PuttyTray + * Addon to SIZE_MINIMIZED for adding/removing the trayicon + */ + if (wParam == SIZE_MINIMIZED) { + + BYTE keys[256]; + int control_pressed; + if (GetKeyboardState(keys)!=0) { + control_pressed=keys[VK_CONTROL]&0x80; + } + + SetWindowText(hwnd, cfg.win_name_always ? window_name : icon_name); + + if (cfg.tray == TRAY_NORMAL || cfg.tray == TRAY_START || control_pressed > 0) { + taskbar_addicon(cfg.win_name_always ? window_name : icon_name, TRUE); + ShowWindow(hwnd, SW_HIDE); + } + windowMinimized = TRUE; + } else { + windowMinimized = FALSE; + } + if (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED) SetWindowText(hwnd, window_name); if (wParam == SIZE_RESTORED) { @@ -3176,6 +3383,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, if (process_clipdata((HGLOBAL)lParam, wParam)) term_do_paste(term); return 0; + /* * HACK: PuttyTray / Reconnect */ @@ -3208,6 +3416,54 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, } } break; + + /* + * HACK: PuttyTray + * Trayicon click handler + */ + case WM_NOTIFY_PUTTYTRAY: + { + UINT uID; + UINT uMouseMsg; + + uID = (UINT)wParam; + uMouseMsg = (UINT)lParam; + + if (uID = 1983) { + if (uMouseMsg == WM_LBUTTONDBLCLK || (cfg.tray_restore == TRUE && uMouseMsg == WM_LBUTTONUP)) { + // Remove icon + if (cfg.tray != TRAY_ALWAYS) { + taskbar_addicon(cfg.win_name_always ? window_name : icon_name, FALSE); + } + + // Sleep a little while, otherwise the click event is sent to, for example, the Outlook 2003 Tray Icon, and it will also pop its menu. + Sleep(100); + + // If trayicon is always visible, the icon should also be able to hide the window + if (windowMinimized) { + ShowWindow(hwnd, SW_RESTORE); + SetForegroundWindow(hwnd); + windowMinimized = FALSE; + } else { + ShowWindow(hwnd, SW_MINIMIZE); + windowMinimized = TRUE; + } + } else if (uMouseMsg == WM_RBUTTONUP) { + POINT cursorpos; + + // Fix disappear bug + SetForegroundWindow(hwnd); + + // Show popup + show_mouseptr(1); /* make sure pointer is visible */ + GetCursorPos(&cursorpos); + TrackPopupMenu(popup_menus[CTXMENU].menu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RIGHTBUTTON, cursorpos.x, cursorpos.y, 0, hwnd, NULL); + PostMessage(hwnd, WM_NULL, 0, 0); + } + } + } + break; + /* * END HACKS: PuttyTray / Trayicon & Reconnect */ @@ -4665,6 +4921,12 @@ void set_title(void *frontend, char *title) strcpy(window_name, title); if (cfg.win_name_always || !IsIconic(hwnd)) SetWindowText(hwnd, title); + + /* + * HACK: Putty Tray + * Change Trayicon Tooltip to window title + */ + taskbar_addicon(cfg.win_name_always ? window_name : icon_name, puttyTrayVisible); } void set_icon(void *frontend, char *title) @@ -5311,49 +5573,82 @@ static void flash_window_timer(void *ctx, long now) } /* - * Manage window caption / taskbar flashing, if enabled. - * 0 = stop, 1 = maintain, 2 = start +* Manage window caption / taskbar flashing, if enabled. +* 0 = stop, 1 = maintain, 2 = start +*/ +/* + * HACK: PuttyTray + * REPLACED flash_window with flash_window from PuTTY 0.58. + * The new version with FlashWindowEx is nice but where do I trigger the icon flash if I use it? */ static void flash_window(int mode) { - if ((mode == 0) || (cfg.beep_ind == B_IND_DISABLED)) { - /* stop */ - if (flashing) { - flashing = 0; - if (p_FlashWindowEx) - flash_window_ex(FLASHW_STOP, 0, 0); - else - FlashWindow(hwnd, FALSE); - } + HINSTANCE inst; - } else if (mode == 2) { - /* start */ - if (!flashing) { - flashing = 1; - 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); - } - } + if ((mode == 0) || (cfg.beep_ind == B_IND_DISABLED)) { + /* stop */ + if (flashing) { + FlashWindow(hwnd, FALSE); + flashing = 0; + + /* + * HACK: PuttyTray + * Reset trayicon + */ + if (puttyTrayVisible) { + inst = (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE); + + puttyTrayFlash = FALSE; + puttyTray.hIcon = puttyTrayFlashIcon; + taskbar_addicon(cfg.win_name_always ? window_name : icon_name, TRUE); + } + + return; + } - } else if ((mode == 1) && (cfg.beep_ind == B_IND_FLASH)) { - /* maintain */ - if (flashing && !p_FlashWindowEx) { - FlashWindow(hwnd, TRUE); /* toggle */ - next_flash = schedule_timer(450, flash_window_timer, hwnd); + } else if (mode == 2) { + /* start */ + if (!flashing) { + flashing = 1; + FlashWindow(hwnd, TRUE); + next_flash = schedule_timer(450, flash_window_timer, hwnd); + + /* + * HACK: PuttyTray + * Start flashing trayicon + */ + if (puttyTrayVisible) { + puttyTrayFlash = FALSE; + } + } + + } else if ((mode == 1) && (cfg.beep_ind == B_IND_FLASH)) { + /* maintain */ + if (flashing) { + FlashWindow(hwnd, TRUE); /* toggle */ + next_flash = schedule_timer(450, flash_window_timer, hwnd); + + /* + * HACK: PuttyTray + * Make trayicon blink + */ + if (puttyTrayVisible) { + if (!puttyTrayFlash) { + puttyTrayFlash = TRUE; + + puttyTrayFlashIcon = puttyTray.hIcon; + puttyTray.hIcon = NULL; + taskbar_addicon(cfg.win_name_always ? window_name : icon_name, TRUE); + } else { + inst = (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE); + puttyTrayFlash = FALSE; + + puttyTray.hIcon = puttyTrayFlashIcon; + taskbar_addicon(cfg.win_name_always ? window_name : icon_name, TRUE); + } + } + } } - } } /* @@ -5423,11 +5718,15 @@ void do_beep(void *frontend, int mode) void set_iconic(void *frontend, int iconic) { if (IsIconic(hwnd)) { - if (!iconic) - ShowWindow(hwnd, SW_RESTORE); + if (!iconic) { // HACK: PuttyTray / added { to if structure + ShowWindow(hwnd, SW_RESTORE); + windowMinimized = FALSE; // HACK: PuttyTray + } } else { - if (iconic) - ShowWindow(hwnd, SW_MINIMIZE); + if (iconic){ + ShowWindow(hwnd, SW_MINIMIZE); + windowMinimized = TRUE; // HACK: PuTTYTray + } } } @@ -5743,3 +6042,84 @@ void MakeWindowOnTop(HWND hwnd) { } } } + +/* + * HACK: PuttyTray + * Function to add icon to the taskbar's system tray + */ +BOOL taskbar_addicon(LPSTR lpszTip, BOOL showIcon) +{ + BOOL icon_result; + + if (showIcon) { + // Set Tooltip + if (lpszTip) { + strncpy(puttyTray.szTip, lpszTip, sizeof(puttyTray.szTip)); + } else { + puttyTray.szTip[0] = (TCHAR)'\0'; + } + + // Set icon visibility + if (!puttyTrayVisible) { + tray_updatemenu(TRUE); + icon_result = Shell_NotifyIcon(NIM_ADD, &puttyTray); + puttyTrayVisible = TRUE; + return icon_result; + } else { + icon_result = Shell_NotifyIcon(NIM_MODIFY, &puttyTray); + return icon_result; + } + } else { + if (puttyTrayVisible) { + tray_updatemenu(FALSE); + icon_result = Shell_NotifyIcon(NIM_DELETE, &puttyTray); + puttyTrayVisible = FALSE; + return icon_result; + } + } + + return TRUE; +} + +void tray_updatemenu(BOOL disableMenuItems) +{ + MENUITEMINFO mii; + memset(&mii, 0, sizeof(MENUITEMINFO)); + mii.cbSize = sizeof(MENUITEMINFO); + + if (disableMenuItems) { + DeleteMenu(popup_menus[CTXMENU].menu, IDM_TRAYSEP, MF_BYCOMMAND); + DeleteMenu(popup_menus[CTXMENU].menu, IDM_TRAYRESTORE, MF_BYCOMMAND); + DeleteMenu(popup_menus[CTXMENU].menu, IDM_TRAYCLOSE, MF_BYCOMMAND); + InsertMenu(popup_menus[CTXMENU].menu, -1, MF_BYPOSITION | MF_SEPARATOR, IDM_TRAYSEP, 0); + InsertMenu(popup_menus[CTXMENU].menu, -1, MF_BYPOSITION | MF_ENABLED, IDM_TRAYRESTORE, "&Restore Window"); + InsertMenu(popup_menus[CTXMENU].menu, -1, MF_BYPOSITION | MF_ENABLED, IDM_TRAYCLOSE, "&Exit"); + + // Set X bitmap on close window menuitem + mii.fMask = MIIM_BITMAP; + mii.hbmpItem = HBMMENU_POPUP_CLOSE; + SetMenuItemInfo(popup_menus[CTXMENU].menu, IDM_TRAYCLOSE, FALSE, &mii); + + // Set restore icon on restore menuitem + mii.hbmpItem = HBMMENU_POPUP_RESTORE; + SetMenuItemInfo(popup_menus[CTXMENU].menu, IDM_TRAYRESTORE, FALSE, &mii); + + mii.fMask = MIIM_STATE; + mii.fState = MFS_GRAYED; + } else { + DeleteMenu(popup_menus[CTXMENU].menu, IDM_TRAYSEP, MF_BYCOMMAND); + DeleteMenu(popup_menus[CTXMENU].menu, IDM_TRAYRESTORE, MF_BYCOMMAND); + DeleteMenu(popup_menus[CTXMENU].menu, IDM_TRAYCLOSE, MF_BYCOMMAND); + + mii.fMask = MIIM_STATE; + mii.fState = MFS_ENABLED; + } + + SetMenuItemInfo(popup_menus[CTXMENU].menu, specials_menu, FALSE, &mii); + SetMenuItemInfo(popup_menus[CTXMENU].menu, IDM_PASTE, FALSE, &mii); + SetMenuItemInfo(popup_menus[CTXMENU].menu, IDM_FULLSCREEN, FALSE, &mii); + SetMenuItemInfo(popup_menus[CTXMENU].menu, IDM_RESET, FALSE, &mii); + SetMenuItemInfo(popup_menus[CTXMENU].menu, IDM_CLRSB, FALSE, &mii); + SetMenuItemInfo(popup_menus[CTXMENU].menu, IDM_COPYALL, FALSE, &mii); +} + diff --git a/windows/winmisc.c b/windows/winmisc.c index d05a07ab5e6e6fe872f07c1c5fac68f08dda4d54..6eb9bd474c41d58530019da4a4f2df60fed0734c 100644 --- a/windows/winmisc.c +++ b/windows/winmisc.c @@ -7,6 +7,13 @@ #include "putty.h" #include <security.h> +/* + * HACK: PuttyTray / Session Icon + * Otherwise it will not know IDI_MAINICON + */ +#include "win_res.h" +//-------------------------- + OSVERSIONINFO osVersion; char *platform_get_x_display(void) { @@ -379,3 +386,46 @@ void *minefield_c_realloc(void *p, size_t size) } #endif /* MINEFIELD */ + +/* + * HACK: PuttyTray / Session Icon + */ +HICON extract_icon(char *iconpath, int smallicon) +{ + char *iname, *comma; + int iindex; + HICON hiconLarge, hiconSmall; + + hiconLarge = NULL; + hiconSmall = NULL; + + // Get icon + if (iconpath && iconpath[0]) { + iname = dupstr(iconpath); + comma = strrchr(iname, ','); + + if (comma) { + *comma = '\0'; + *comma++; + iindex = atoi(comma); + + ExtractIconEx(iname, iindex, &hiconLarge, &hiconSmall, 1); + }; + sfree(iname); + }; + + // Fix if no icon found + if (!hiconLarge && !smallicon) { + hiconLarge = LoadImage(hinst, MAKEINTRESOURCE(IDI_MAINICON), IMAGE_ICON, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), LR_DEFAULTCOLOR|LR_SHARED); + } + if (!hiconSmall && smallicon) { + hiconSmall = LoadImage(hinst, MAKEINTRESOURCE(IDI_MAINICON), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR|LR_SHARED); + } + + // Return the right icon + if (smallicon) { + return hiconSmall; + } else { + return hiconLarge; + } +};