From 592c0d89f865c44e6909e0ca1e9d0c550be890b4 Mon Sep 17 00:00:00 2001
From: George Hazan <ghazan@miranda.im>
Date: Sun, 26 Mar 2017 20:45:13 +0300
Subject: context menu moved to mir_app, part II :)

---
 src/core/stdmsg/res/resource.rc     |  16 ----
 src/core/stdmsg/src/chat_window.cpp | 130 +--------------------------
 src/core/stdmsg/src/tabs.cpp        |   2 +-
 src/mir_app/res/resource.rc         |  28 ++++++
 src/mir_app/src/chat.h              |   1 +
 src/mir_app/src/chat_svc.cpp        |   7 ++
 src/mir_app/src/mir_app64.def       |   1 +
 src/mir_app/src/resource.h          |   9 ++
 src/mir_app/src/srmm_base.cpp       | 174 +++++++++++++++++++++++++++++++++++-
 9 files changed, 223 insertions(+), 145 deletions(-)

(limited to 'src')

diff --git a/src/core/stdmsg/res/resource.rc b/src/core/stdmsg/res/resource.rc
index 7893ed2b21..6ac278411b 100644
--- a/src/core/stdmsg/res/resource.rc
+++ b/src/core/stdmsg/res/resource.rc
@@ -527,22 +527,6 @@ IDC_DROPUSER            CURSOR                  "dropuser.cur"
 
 IDR_MENU MENU
 BEGIN
-    POPUP "List"
-    BEGIN
-        MENUITEM "&Message",                    ID_MESS
-    END
-    POPUP "Log"
-    BEGIN
-        MENUITEM "Clear lo&g",                  ID_CLEARLOG
-        MENUITEM SEPARATOR
-        MENUITEM "Co&py all",                   ID_COPYALL
-        MENUITEM SEPARATOR
-        POPUP "Word lookup", GRAYED
-        BEGIN
-            MENUITEM "Google",                      ID_SEARCH_GOOGLE
-            MENUITEM "Wikipedia",                   ID_SEARCH_WIKIPEDIA
-        END
-    END
     POPUP "Message"
     BEGIN
         MENUITEM "Undo",                        ID_MESSAGE_UNDO, GRAYED
diff --git a/src/core/stdmsg/src/chat_window.cpp b/src/core/stdmsg/src/chat_window.cpp
index cbb246e241..725a92e71b 100644
--- a/src/core/stdmsg/src/chat_window.cpp
+++ b/src/core/stdmsg/src/chat_window.cpp
@@ -873,7 +873,7 @@ LRESULT CChatRoomDlg::WndProc_Message(UINT msg, WPARAM wParam, LPARAM lParam)
 
 	case WM_RBUTTONDOWN:
 		{
-			HMENU hSubMenu = GetSubMenu(g_hMenu, 2);
+			HMENU hSubMenu = GetSubMenu(g_hMenu, 0);
 			TranslateMenu(hSubMenu);
 			m_message.SendMsg(EM_EXGETSEL, 0, (LPARAM)&sel);
 
@@ -977,50 +977,6 @@ LRESULT CChatRoomDlg::WndProc_Nicklist(UINT msg, WPARAM wParam, LPARAM lParam)
 			return TRUE;
 		}
 		break;
-
-	case WM_CONTEXTMENU:
-		TVHITTESTINFO hti;
-		{
-			int height = 0;
-			hti.pt.x = GET_X_LPARAM(lParam);
-			hti.pt.y = GET_Y_LPARAM(lParam);
-			if (hti.pt.x == -1 && hti.pt.y == -1) {
-				int index = m_nickList.SendMsg(LB_GETCURSEL, 0, 0);
-				int top = m_nickList.SendMsg(LB_GETTOPINDEX, 0, 0);
-				height = m_nickList.SendMsg(LB_GETITEMHEIGHT, 0, 0);
-				hti.pt.x = 4;
-				hti.pt.y = (index - top)*height + 1;
-			}
-			else ScreenToClient(m_nickList.GetHwnd(), &hti.pt);
-
-			int item = LOWORD(m_nickList.SendMsg(LB_ITEMFROMPOINT, 0, MAKELPARAM(hti.pt.x, hti.pt.y)));
-			USERINFO *ui = pci->SM_GetUserFromIndex(m_si->ptszID, m_si->pszModule, item);
-			if (ui) {
-				USERINFO uinew;
-				memcpy(&uinew, ui, sizeof(USERINFO));
-				if (hti.pt.x == -1 && hti.pt.y == -1)
-					hti.pt.y += height - 4;
-				ClientToScreen(m_nickList.GetHwnd(), &hti.pt);
-
-				HMENU hMenu = GetSubMenu(g_hMenu, 0);
-				UINT uID = Chat_CreateGCMenu(m_nickList.GetHwnd(), hMenu, hti.pt, m_si, uinew.pszUID, uinew.pszNick);
-				switch (uID) {
-				case 0:
-					break;
-
-				case ID_MESS:
-					DoEventHook(GC_USER_PRIVMESS, ui, nullptr, 0);
-					break;
-
-				default:
-					DoEventHook(GC_USER_NICKLISTMENU, ui, nullptr, uID);
-					break;
-				}
-				Chat_DestroyGCMenu(hMenu, 1);
-				return TRUE;
-			}
-		}
-		break;
 	}
 
 	return CSuper::WndProc_Nicklist(msg, wParam, lParam);
@@ -1030,9 +986,6 @@ LRESULT CChatRoomDlg::WndProc_Nicklist(UINT msg, WPARAM wParam, LPARAM lParam)
 
 INT_PTR CChatRoomDlg::DlgProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
 {
-	SESSION_INFO *s;
-	CHARRANGE sel;
-
 	switch (uMsg) {
 	case WM_CBD_LOADICONS:
 		Srmm_UpdateToolbarIcons(m_hwnd);
@@ -1210,85 +1163,8 @@ INT_PTR CChatRoomDlg::DlgProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
 		switch (((LPNMHDR)lParam)->code) {
 		case EN_MSGFILTER:
 			if (((LPNMHDR)lParam)->idFrom == IDC_SRMM_LOG && ((MSGFILTER *)lParam)->msg == WM_RBUTTONUP) {
-				ENLINK *pLink = (ENLINK*)lParam;
-				POINT pt = { GET_X_LPARAM(pLink->lParam), GET_Y_LPARAM(pLink->lParam) };
-				ClientToScreen(((LPNMHDR)lParam)->hwndFrom, &pt);
-
-				// fixing stuff for searches
-				POINTL ptl = { (LONG)pt.x, (LONG)pt.y };
-				ScreenToClient(m_log.GetHwnd(), (LPPOINT)&ptl);
-				long iCharIndex = m_log.SendMsg(EM_CHARFROMPOS, 0, (LPARAM)&ptl);
-				if (iCharIndex < 0)
-					break;
-
-				long start = m_log.SendMsg(EM_FINDWORDBREAK, WB_LEFT, iCharIndex);//-iChars;
-				long end = m_log.SendMsg(EM_FINDWORDBREAK, WB_RIGHT, iCharIndex);//-iChars;
-
-				wchar_t pszWord[4096]; pszWord[0] = '\0';
-				if (end - start > 0) {
-					TEXTRANGE tr;
-					tr.lpstrText = pszWord;
-					tr.chrg.cpMin = start;
-					tr.chrg.cpMax = end;
-					long iRes = m_log.SendMsg(EM_GETTEXTRANGE, 0, (LPARAM)&tr);
-					if (pszWord[0] == 0)
-						break;
-					if (iRes > 0)
-						for (size_t iLen = mir_wstrlen(pszWord) - 1; wcschr(szTrimString, pszWord[iLen]); iLen--)
-							pszWord[iLen] = 0;
-				}
-
-				CHARRANGE all = { 0, -1 };
-				HMENU hMenu = GetSubMenu(g_hMenu, 1);
-				UINT uID = Chat_CreateGCMenu(m_log.GetHwnd(), hMenu, pt, m_si, nullptr, pszWord);
-				switch (uID) {
-				case 0:
-					PostMessage(m_hwnd, WM_MOUSEACTIVATE, 0, 0);
-					break;
-
-				case ID_COPYALL:
-					SendMessage(((LPNMHDR)lParam)->hwndFrom, EM_EXGETSEL, 0, (LPARAM)&sel);
-					SendMessage(((LPNMHDR)lParam)->hwndFrom, EM_EXSETSEL, 0, (LPARAM)&all);
-					SendMessage(((LPNMHDR)lParam)->hwndFrom, WM_COPY, 0, 0);
-					SendMessage(((LPNMHDR)lParam)->hwndFrom, EM_EXSETSEL, 0, (LPARAM)&sel);
-					PostMessage(m_hwnd, WM_MOUSEACTIVATE, 0, 0);
-					break;
-
-				case ID_CLEARLOG:
-					s = pci->SM_FindSession(m_si->ptszID, m_si->pszModule);
-					if (s) {
-						ClearLog();
-						pci->LM_RemoveAll(&s->pLog, &s->pLogEnd);
-						s->iEventCount = 0;
-						s->LastTime = 0;
-						m_si->iEventCount = 0;
-						m_si->LastTime = 0;
-						m_si->pLog = s->pLog;
-						m_si->pLogEnd = s->pLogEnd;
-						PostMessage(m_hwnd, WM_MOUSEACTIVATE, 0, 0);
-					}
-					break;
-
-				case ID_SEARCH_GOOGLE:
-					if (pszWord[0])
-						Utils_OpenUrlW(CMStringW(FORMAT, L"http://www.google.com/search?q=%s", pszWord));
-
-					PostMessage(m_hwnd, WM_MOUSEACTIVATE, 0, 0);
-					break;
-
-				case ID_SEARCH_WIKIPEDIA:
-					if (pszWord[0])
-						Utils_OpenUrlW(CMStringW(FORMAT, L"http://en.wikipedia.org/wiki/%s", pszWord));
-
-					PostMessage(m_hwnd, WM_MOUSEACTIVATE, 0, 0);
-					break;
-
-				default:
-					PostMessage(m_hwnd, WM_MOUSEACTIVATE, 0, 0);
-					DoEventHook(GC_USER_LOGMENU, nullptr, nullptr, uID);
-					break;
-				}
-				Chat_DestroyGCMenu(hMenu, 5);
+				SetWindowLongPtr(m_hwnd, DWLP_MSGRESULT, TRUE);
+				return TRUE;
 			}
 			break;
 
diff --git a/src/core/stdmsg/src/tabs.cpp b/src/core/stdmsg/src/tabs.cpp
index b3f9574f52..e12a1c2495 100644
--- a/src/core/stdmsg/src/tabs.cpp
+++ b/src/core/stdmsg/src/tabs.cpp
@@ -421,7 +421,7 @@ INT_PTR CTabbedWindow::DlgProc(UINT msg, WPARAM wParam, LPARAM lParam)
 				SESSION_INFO *si = ((CChatRoomDlg*)m_tab.GetNthPage(i))->m_si;
 
 				ClientToScreen(GetDlgItem(m_hwnd, IDC_TAB), &tci.pt);
-				HMENU hSubMenu = GetSubMenu(g_hMenu, 3);
+				HMENU hSubMenu = GetSubMenu(g_hMenu, 1);
 				TranslateMenu(hSubMenu);
 
 				if (si) {
diff --git a/src/mir_app/res/resource.rc b/src/mir_app/res/resource.rc
index 113bde9218..7b9ac32d40 100644
--- a/src/mir_app/res/resource.rc
+++ b/src/mir_app/res/resource.rc
@@ -1304,6 +1304,34 @@ BEGIN
     END
 END
 
+IDR_SRMM MENU
+BEGIN
+    POPUP "List"
+    BEGIN
+        MENUITEM "&Message",                    IDM_SENDMESSAGE
+    END
+    POPUP "Log"
+    BEGIN
+        MENUITEM "Clear lo&g",                  IDM_CLEAR
+        MENUITEM SEPARATOR
+        MENUITEM "Co&py all",                   IDM_COPYALL
+        MENUITEM SEPARATOR
+        POPUP "Word lookup", GRAYED
+        BEGIN
+            MENUITEM "Google",                      IDM_SEARCH_GOOGLE
+            MENUITEM "Bing",                        IDM_SEARCH_BING
+            MENUITEM "Yandex",                      IDM_SEARCH_YANDEX
+            MENUITEM "Wikipedia (en)",              IDM_SEARCH_WIKIPEDIA
+            MENUITEM SEPARATOR
+            MENUITEM "Google Maps",                 IDM_SEARCH_GOOGLE_MAPS
+            MENUITEM "Google Translate",            IDM_SEARCH_GOOGLE_TRANSLATE
+            MENUITEM SEPARATOR
+            MENUITEM "Yahoo",                       IDM_SEARCH_YAHOO
+            MENUITEM "Foodnetwork",                 IDM_SEARCH_FOODNETWORK
+        END
+    END
+END
+
 #endif    // English (United States) resources
 /////////////////////////////////////////////////////////////////////////////
 
diff --git a/src/mir_app/src/chat.h b/src/mir_app/src/chat.h
index cb7e26f97c..4a4b1acb14 100644
--- a/src/mir_app/src/chat.h
+++ b/src/mir_app/src/chat.h
@@ -38,6 +38,7 @@ extern int g_cbSession, g_cbModuleInfo, g_iFontMode, g_iChatLang;
 extern wchar_t *g_szFontGroup;
 extern mir_cs csChat;
 
+extern HMENU g_hMenu;
 extern HCURSOR g_hCurHyperlinkHand;
 extern char* pLogIconBmpBits[14];
 extern LIST<SESSION_INFO> g_arSessions;
diff --git a/src/mir_app/src/chat_svc.cpp b/src/mir_app/src/chat_svc.cpp
index 3dc5539ce0..9434faed20 100644
--- a/src/mir_app/src/chat_svc.cpp
+++ b/src/mir_app/src/chat_svc.cpp
@@ -25,7 +25,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 INT_PTR SvcGetChatManager(WPARAM, LPARAM);
 
 #include "chat.h"
+#include "resource.h"
 
+HMENU g_hMenu = nullptr;
 HGENMENU hJoinMenuItem, hLeaveMenuItem;
 mir_cs csChat;
 
@@ -783,6 +785,9 @@ int LoadChatModule(void)
 	HookEvent(ME_FONT_RELOAD, FontsChanged);
 	HookEvent(ME_SKIN2_ICONSCHANGED, IconsChanged);
 
+	g_hMenu = LoadMenu(g_hInst, MAKEINTRESOURCE(IDR_SRMM));
+	TranslateMenu(g_hMenu);
+
 	bInited = true;
 	return 0;
 }
@@ -803,4 +808,6 @@ void UnloadChatModule(void)
 	DestroyHookableEvent(chatApi.hSendEvent);
 	DestroyHookableEvent(chatApi.hBuildMenuEvent);
 	DestroyHookableEvent(hHookEvent);
+
+	DestroyMenu(g_hMenu);
 }
diff --git a/src/mir_app/src/mir_app64.def b/src/mir_app/src/mir_app64.def
index 01e2359241..bce854eeef 100644
--- a/src/mir_app/src/mir_app64.def
+++ b/src/mir_app/src/mir_app64.def
@@ -439,3 +439,4 @@ Chat_UpdateOptions @418 NONAME
 Chat_AddMenuItems @442 NONAME
 Chat_DestroyGCMenu @443 NONAME
 Chat_CreateGCMenu @444 NONAME
+?RunUserMenu@CSrmmBaseDialog@@IEAAXPEAUHWND__@@PEAUUSERINFO@@AEBUtagPOINT@@@Z @445 NONAME
diff --git a/src/mir_app/src/resource.h b/src/mir_app/src/resource.h
index a224363be6..5a56718d2d 100644
--- a/src/mir_app/src/resource.h
+++ b/src/mir_app/src/resource.h
@@ -34,6 +34,7 @@
 #define IDI_INVISIBLE                   130
 #define IDI_NA                          131
 #define IDI_LOAD                        132
+#define IDR_SRMM								 133
 #define IDD_OPT_SOUND                   134
 #define IDI_RECVMSG                     136
 #define IDI_URL                         138
@@ -601,6 +602,14 @@
 #define POPUP_DELETEGROUP               40053
 #define ID_GROUP                        40066
 #define ID_UNGROUP                      40067
+#define IDM_SEARCH_GOOGLE               40080
+#define IDM_SEARCH_BING                 40081
+#define IDM_SEARCH_YANDEX               40082
+#define IDM_SEARCH_WIKIPEDIA            40083
+#define IDM_SEARCH_GOOGLE_MAPS          40084
+#define IDM_SEARCH_GOOGLE_TRANSLATE     40085
+#define IDM_SEARCH_YAHOO                40086
+#define IDM_SEARCH_FOODNETWORK          40087
 
 // Next default values for new objects
 // 
diff --git a/src/mir_app/src/srmm_base.cpp b/src/mir_app/src/srmm_base.cpp
index d9e25d6c9d..d55a71ff53 100644
--- a/src/mir_app/src/srmm_base.cpp
+++ b/src/mir_app/src/srmm_base.cpp
@@ -24,6 +24,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #include "stdafx.h"
 
 #include "chat.h"
+#include "resource.h"
 #include <m_history.h>
 
 CSrmmBaseDialog::CSrmmBaseDialog(HINSTANCE hInst, int idDialog, SESSION_INFO *si)
@@ -92,6 +93,27 @@ CSrmmBaseDialog& CSrmmBaseDialog::operator=(const CSrmmBaseDialog&)
 	return *this;
 }
 
+void CSrmmBaseDialog::RunUserMenu(HWND hwndOwner, USERINFO *ui, const POINT &pt)
+{
+	USERINFO uinew;
+	memcpy(&uinew, ui, sizeof(USERINFO));
+	HMENU hMenu = GetSubMenu(g_hMenu, 0);
+	UINT uID = Chat_CreateGCMenu(hwndOwner, hMenu, pt, m_si, uinew.pszUID, uinew.pszNick);
+	switch (uID) {
+	case 0:
+		break;
+
+	case IDM_SENDMESSAGE:
+		DoEventHook(GC_USER_PRIVMESS, ui, nullptr, 0);
+		break;
+
+	default:
+		DoEventHook(GC_USER_NICKLISTMENU, ui, nullptr, uID);
+		break;
+	}
+	Chat_DestroyGCMenu(hMenu, 1);
+}
+
 /////////////////////////////////////////////////////////////////////////////////////////
 
 static LRESULT CALLBACK Srmm_ButtonSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
@@ -136,10 +158,11 @@ static LRESULT CALLBACK stubLogProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM l
 
 LRESULT CSrmmBaseDialog::WndProc_Log(UINT msg, WPARAM wParam, LPARAM lParam)
 {
+	CHARRANGE sel;
+
 	switch (msg) {
 	case WM_ACTIVATE:
 		if (LOWORD(wParam) == WA_INACTIVE) {
-			CHARRANGE sel;
 			m_log.SendMsg(EM_EXGETSEL, 0, (LPARAM)&sel);
 			if (sel.cpMin != sel.cpMax) {
 				sel.cpMin = sel.cpMax;
@@ -152,6 +175,127 @@ LRESULT CSrmmBaseDialog::WndProc_Log(UINT msg, WPARAM wParam, LPARAM lParam)
 		SetFocus(m_message.GetHwnd());
 		m_message.SendMsg(WM_CHAR, wParam, lParam);
 		break;
+
+	case WM_CONTEXTMENU:
+		if (m_si == nullptr)
+			break;
+
+		POINT pt, ptl;
+		m_message.SendMsg(EM_EXGETSEL, 0, (LPARAM)&sel);
+		if (lParam == 0xFFFFFFFF) {
+			m_message.SendMsg(EM_POSFROMCHAR, (WPARAM)&pt, (LPARAM)sel.cpMax);
+			ClientToScreen(m_log.GetHwnd(), &pt);
+		}
+		else {
+			pt.x = GET_X_LPARAM(lParam);
+			pt.y = GET_Y_LPARAM(lParam);
+		}
+		ptl = pt;
+		ScreenToClient(m_log.GetHwnd(), (LPPOINT)&ptl);
+		{
+			wchar_t *pszWord = (wchar_t*)_alloca(8192);
+			pszWord[0] = '\0';
+
+			int iCharIndex = m_log.SendMsg(EM_CHARFROMPOS, 0, (LPARAM)&ptl);
+			if (iCharIndex < 0)
+				break;
+
+			int start = m_log.SendMsg(EM_FINDWORDBREAK, WB_LEFT, iCharIndex);
+			int end = m_log.SendMsg(EM_FINDWORDBREAK, WB_RIGHT, iCharIndex);
+
+			if (end - start > 0) {
+				static wchar_t szTrimString[] = L":;,.!?\'\"><()[]- \r\n";
+
+				CHARRANGE cr;
+				cr.cpMin = start;
+				cr.cpMax = end;
+
+				TEXTRANGE tr = { 0 };
+				tr.chrg = cr;
+				tr.lpstrText = (wchar_t*)pszWord;
+				int iRes = m_log.SendMsg(EM_GETTEXTRANGE, 0, (LPARAM)&tr);
+				if (iRes > 0) {
+					size_t iLen = mir_wstrlen(pszWord) - 1;
+					while (wcschr(szTrimString, pszWord[iLen])) {
+						pszWord[iLen] = '\0';
+						iLen--;
+					}
+				}
+			}
+
+			CHARRANGE all = { 0, -1 };
+			HMENU hMenu = GetSubMenu(g_hMenu, 1);
+			UINT uID = Chat_CreateGCMenu(m_log.GetHwnd(), hMenu, pt, m_si, nullptr, pszWord);
+			switch (uID) {
+			case 0:
+				PostMessage(m_hwnd, WM_MOUSEACTIVATE, 0, 0);
+				break;
+
+			case IDM_COPYALL:
+				m_message.SendMsg(EM_EXGETSEL, 0, (LPARAM)&sel);
+				m_message.SendMsg(EM_EXSETSEL, 0, (LPARAM)&all);
+				m_message.SendMsg(WM_COPY, 0, 0);
+				m_message.SendMsg(EM_EXSETSEL, 0, (LPARAM)&sel);
+				PostMessage(m_hwnd, WM_MOUSEACTIVATE, 0, 0);
+				break;
+
+			case IDM_CLEAR:
+				m_log.SetText(L"");
+				chatApi.LM_RemoveAll(&m_si->pLog, &m_si->pLogEnd);
+				m_si->iEventCount = 0;
+				m_si->LastTime = 0;
+				PostMessage(m_hwnd, WM_MOUSEACTIVATE, 0, 0);
+				break;
+
+			case IDM_SEARCH_GOOGLE:
+			case IDM_SEARCH_BING:
+			case IDM_SEARCH_YANDEX:
+			case IDM_SEARCH_YAHOO:
+			case IDM_SEARCH_WIKIPEDIA:
+			case IDM_SEARCH_FOODNETWORK:
+			case IDM_SEARCH_GOOGLE_MAPS:
+			case IDM_SEARCH_GOOGLE_TRANSLATE:
+				{
+					CMStringW szURL;
+					switch (uID) {
+					case IDM_SEARCH_WIKIPEDIA:
+						szURL.Format(L"http://en.wikipedia.org/wiki/%s", pszWord);
+						break;
+					case IDM_SEARCH_YAHOO:
+						szURL.Format(L"http://search.yahoo.com/search?p=%s&ei=UTF-8", pszWord);
+						break;
+					case IDM_SEARCH_FOODNETWORK:
+						szURL.Format(L"http://search.foodnetwork.com/search/delegate.do?fnSearchString=%s", pszWord);
+						break;
+					case IDM_SEARCH_BING:
+						szURL.Format(L"http://www.bing.com/search?q=%s&form=OSDSRC", pszWord);
+						break;
+					case IDM_SEARCH_GOOGLE_MAPS:
+						szURL.Format(L"http://maps.google.com/maps?q=%s&ie=utf-8&oe=utf-8", pszWord);
+						break;
+					case IDM_SEARCH_GOOGLE_TRANSLATE:
+						szURL.Format(L"http://translate.google.com/?q=%s&ie=utf-8&oe=utf-8", pszWord);
+						break;
+					case IDM_SEARCH_YANDEX:
+						szURL.Format(L"http://yandex.ru/yandsearch?text=%s", pszWord);
+						break;
+					case IDM_SEARCH_GOOGLE:
+						szURL.Format(L"http://www.google.com/search?q=%s&ie=utf-8&oe=utf-8", pszWord);
+						break;
+					}
+					Utils_OpenUrlW(szURL);
+				}
+				PostMessage(m_hwnd, WM_MOUSEACTIVATE, 0, 0);
+				break;
+
+			default:
+				PostMessage(m_hwnd, WM_MOUSEACTIVATE, 0, 0);
+				DoEventHook(GC_USER_LOGMENU, nullptr, nullptr, uID);
+				break;
+			}
+			Chat_DestroyGCMenu(hMenu, 5);
+		}
+		break;
 	}
 
 	return mir_callNextSubclass(m_log.GetHwnd(), stubLogProc, msg, wParam, lParam);
@@ -390,6 +534,34 @@ LRESULT CSrmmBaseDialog::WndProc_Nicklist(UINT msg, WPARAM wParam, LPARAM lParam
 			}
 		}
 		return 1;
+
+	case WM_CONTEXTMENU:
+		POINT pt;
+		{
+			int height = 0;
+			pt.x = GET_X_LPARAM(lParam);
+			pt.y = GET_Y_LPARAM(lParam);
+			if (pt.x == -1 && pt.y == -1) {
+				int index = m_nickList.GetCurSel();
+				int top = m_nickList.SendMsg(LB_GETTOPINDEX, 0, 0);
+				height = m_nickList.SendMsg(LB_GETITEMHEIGHT, 0, 0);
+				pt.x = 4;
+				pt.y = (index - top)*height + 1;
+			}
+			else ScreenToClient(m_nickList.GetHwnd(), &pt);
+
+			int item = LOWORD(m_nickList.SendMsg(LB_ITEMFROMPOINT, 0, MAKELPARAM(pt.x, pt.y)));
+			USERINFO *ui = chatApi.SM_GetUserFromIndex(m_si->ptszID, m_si->pszModule, item);
+			if (ui != nullptr) {
+				if (pt.x == -1 && pt.y == -1)
+					pt.y += height - 4;
+				ClientToScreen(m_nickList.GetHwnd(), &pt);
+
+				RunUserMenu(m_nickList.GetHwnd(), ui, pt);
+				return TRUE;
+			}
+		}
+		break;
 	}
 
 	return mir_callNextSubclass(m_nickList.GetHwnd(), stubNicklistProc, msg, wParam, lParam);
-- 
cgit v1.2.3