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;
+	}
+};